diff --git a/src/main/java/ru/serega6531/packmate/controller/StreamController.java b/src/main/java/ru/serega6531/packmate/controller/StreamController.java index 2dd089c..a4d7f84 100644 --- a/src/main/java/ru/serega6531/packmate/controller/StreamController.java +++ b/src/main/java/ru/serega6531/packmate/controller/StreamController.java @@ -2,27 +2,21 @@ package ru.serega6531.packmate.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.Pagination; import ru.serega6531.packmate.model.Stream; -import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.StreamService; -import java.util.Collections; import java.util.List; -import java.util.Optional; @RestController @RequestMapping("/api/stream/") public class StreamController { private final StreamService streamService; - private final ServicesService servicesService; @Autowired - public StreamController(StreamService streamService, ServicesService servicesService) { + public StreamController(StreamService streamService) { this.streamService = streamService; - this.servicesService = servicesService; } @PostMapping("/all") @@ -36,15 +30,10 @@ public class StreamController { @PostMapping("/{port}") public List getStreams(@PathVariable int port, @RequestBody Pagination pagination) { - final Optional serviceOptional = servicesService.findByPort(port); - if (serviceOptional.isPresent()) { - if (pagination.isFavorites()) { - return streamService.findFavoritesByService(pagination, serviceOptional.get()); - } else { - return streamService.findAllByService(pagination, serviceOptional.get()); - } + if (pagination.isFavorites()) { + return streamService.findFavoritesByService(pagination, port); } else { - return Collections.emptyList(); + return streamService.findAllByService(pagination, port); } } diff --git a/src/main/java/ru/serega6531/packmate/model/CtfService.java b/src/main/java/ru/serega6531/packmate/model/CtfService.java index 574b896..8c1f7b0 100644 --- a/src/main/java/ru/serega6531/packmate/model/CtfService.java +++ b/src/main/java/ru/serega6531/packmate/model/CtfService.java @@ -1,16 +1,14 @@ package ru.serega6531.packmate.model; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; -import lombok.ToString; -import javax.persistence.*; -import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; @Data @Entity @Table(name = "service") -@ToString(exclude = "streams") public class CtfService { @Id @@ -18,8 +16,4 @@ public class CtfService { private String name; - @OneToMany(mappedBy = "service", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonIgnore - private List streams; - } \ No newline at end of file diff --git a/src/main/java/ru/serega6531/packmate/model/FoundPattern.java b/src/main/java/ru/serega6531/packmate/model/FoundPattern.java new file mode 100644 index 0000000..f1721d1 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/model/FoundPattern.java @@ -0,0 +1,38 @@ +package ru.serega6531.packmate.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.*; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@GenericGenerator( + name = "found_pattern_generator", + strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", + parameters = { + @org.hibernate.annotations.Parameter(name = "sequence_name", value = "found_pattern_seq"), + @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"), + @org.hibernate.annotations.Parameter(name = "increment_size", value = "1") + } +) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@ToString +public class FoundPattern { + + @Id + @GeneratedValue(generator = "found_pattern_generator") + @JsonIgnore + private int id; + private int patternId; + private int startPosition; + private int endPosition; + +} + + diff --git a/src/main/java/ru/serega6531/packmate/model/Packet.java b/src/main/java/ru/serega6531/packmate/model/Packet.java index 6976e0c..cc60bd2 100644 --- a/src/main/java/ru/serega6531/packmate/model/Packet.java +++ b/src/main/java/ru/serega6531/packmate/model/Packet.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; +import java.util.Set; @Data @Entity @@ -42,6 +43,9 @@ public class Packet { @JsonIgnore private Stream stream; + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + private Set matches; + private long timestamp; private boolean incoming; // true если от клиента к серверу, иначе false diff --git a/src/main/java/ru/serega6531/packmate/model/Stream.java b/src/main/java/ru/serega6531/packmate/model/Stream.java index 6ec9842..0bb6477 100644 --- a/src/main/java/ru/serega6531/packmate/model/Stream.java +++ b/src/main/java/ru/serega6531/packmate/model/Stream.java @@ -7,6 +7,7 @@ import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.List; +import java.util.Set; @Data @ToString(exclude = "packets") @@ -26,13 +27,13 @@ public class Stream { @GeneratedValue(generator = "stream_generator") private Long id; - @ManyToOne - @JoinColumn(name = "service_id", nullable = false) - private CtfService service; + @Column(name = "service_id") + private int service; private Protocol protocol; @OneToMany(mappedBy = "stream", cascade = CascadeType.ALL, orphanRemoval = true) + @OrderColumn @JsonIgnore private List packets; @@ -41,7 +42,7 @@ public class Stream { private long endTimestamp; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - private List foundPatterns; + private Set foundPatterns; private boolean favorite; diff --git a/src/main/java/ru/serega6531/packmate/repository/StreamRepository.java b/src/main/java/ru/serega6531/packmate/repository/StreamRepository.java index c3c0a47..4530abb 100644 --- a/src/main/java/ru/serega6531/packmate/repository/StreamRepository.java +++ b/src/main/java/ru/serega6531/packmate/repository/StreamRepository.java @@ -2,7 +2,6 @@ package ru.serega6531.packmate.repository; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.Pattern; import ru.serega6531.packmate.model.Stream; @@ -18,13 +17,13 @@ public interface StreamRepository extends JpaRepository { List findAllByIdLessThanAndFavoriteIsTrueAndFoundPatternsContaining(long streamId, Pattern pattern, Pageable pageable); - List findAllByServiceAndIdGreaterThanAndFavoriteIsTrue(CtfService service, long streamId, Pageable pageable); + List findAllByServiceAndIdGreaterThanAndFavoriteIsTrue(int service, long streamId, Pageable pageable); - List findAllByServiceAndIdLessThanAndFavoriteIsTrue(CtfService service, long streamId, Pageable pageable); + List findAllByServiceAndIdLessThanAndFavoriteIsTrue(int service, long streamId, Pageable pageable); - List findAllByServiceAndIdGreaterThanAndFavoriteIsTrueAndFoundPatternsContaining(CtfService service, long streamId, Pattern pattern, Pageable pageable); + List findAllByServiceAndIdGreaterThanAndFavoriteIsTrueAndFoundPatternsContaining(int service, long streamId, Pattern pattern, Pageable pageable); - List findAllByServiceAndIdLessThanAndFavoriteIsTrueAndFoundPatternsContaining(CtfService service, long streamId, Pattern pattern, Pageable pageable); + List findAllByServiceAndIdLessThanAndFavoriteIsTrueAndFoundPatternsContaining(int service, long streamId, Pattern pattern, Pageable pageable); List findAllByIdGreaterThan(long streamId, Pageable pageable); @@ -34,13 +33,13 @@ public interface StreamRepository extends JpaRepository { List findAllByIdLessThanAndFoundPatternsContaining(long streamId, Pattern pattern, Pageable pageable); - List findAllByServiceAndIdGreaterThan(CtfService service, long streamId, Pageable pageable); + List findAllByServiceAndIdGreaterThan(int service, long streamId, Pageable pageable); - List findAllByServiceAndIdLessThan(CtfService service, long streamId, Pageable pageable); + List findAllByServiceAndIdLessThan(int service, long streamId, Pageable pageable); - List findAllByServiceAndIdGreaterThanAndFoundPatternsContaining(CtfService service, long streamId, Pattern pattern, Pageable pageable); + List findAllByServiceAndIdGreaterThanAndFoundPatternsContaining(int service, long streamId, Pattern pattern, Pageable pageable); - List findAllByServiceAndIdLessThanAndFoundPatternsContaining(CtfService service, long streamId, Pattern pattern, Pageable pageable); + List findAllByServiceAndIdLessThanAndFoundPatternsContaining(int service, long streamId, Pattern pattern, Pageable pageable); } diff --git a/src/main/java/ru/serega6531/packmate/service/PatternService.java b/src/main/java/ru/serega6531/packmate/service/PatternService.java index 28512fc..3b65556 100644 --- a/src/main/java/ru/serega6531/packmate/service/PatternService.java +++ b/src/main/java/ru/serega6531/packmate/service/PatternService.java @@ -6,12 +6,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import ru.serega6531.packmate.model.FoundPattern; import ru.serega6531.packmate.model.Pattern; import ru.serega6531.packmate.model.PatternType; import ru.serega6531.packmate.model.Stream; import ru.serega6531.packmate.repository.PatternRepository; import java.util.*; +import java.util.regex.Matcher; import java.util.stream.Collectors; @Service @@ -32,26 +34,61 @@ public class PatternService { log.info("Loaded {} patterns", patterns.size()); } + public Pattern find(int id) { + return patterns.get(id); + } + public Collection findAll() { return patterns.values(); } - public List findMatching(byte[] bytes, boolean incoming) { + public Set findMatches(byte[] bytes, boolean incoming) { String content = new String(bytes); return patterns.values().stream() .filter(p -> p.getType() == (incoming ? PatternType.INPUT : PatternType.OUTPUT) || p.getType() == PatternType.BOTH) - .filter(pattern -> matches(pattern, content)) - .collect(Collectors.toList()); + .map(pattern -> match(pattern, content)) + .flatMap(List::stream) + .collect(Collectors.toSet()); } - private boolean matches(Pattern pattern, String content) { + private List match(Pattern pattern, String content) { + List found = new ArrayList<>(); + if (pattern.isRegex()) { final java.util.regex.Pattern regex = compilePattern(pattern); - return regex.matcher(content).find(); + final Matcher matcher = regex.matcher(content); + + while (matcher.find()) { + found.add(FoundPattern.builder() + .patternId(pattern.getId()) + .startPosition(matcher.start()) + .endPosition(matcher.end()) + .build()); + } + + return found; } else { - return StringUtils.containsIgnoreCase(content, pattern.getValue()); + int startSearch = 0; + + final String value = pattern.getValue(); + while (true) { + int start = StringUtils.indexOfIgnoreCase(content, value, startSearch); + + if (start == -1) { + return found; + } + + int end = start + value.length() - 1; + found.add(FoundPattern.builder() + .patternId(pattern.getId()) + .startPosition(start) + .endPosition(end) + .build()); + + startSearch = end + 1; + } } } @@ -68,7 +105,7 @@ public class PatternService { } pattern.getMatchedStreams().clear(); - patterns.remove(pattern.getId()); + patterns.remove(id); compiledPatterns.remove(pattern.getValue()); repository.delete(pattern); } @@ -76,8 +113,9 @@ public class PatternService { public Pattern save(Pattern pattern) { log.info("Добавлен новый паттерн {} со значением {}", pattern.getName(), pattern.getValue()); - patterns.put(pattern.getId(), pattern); - return repository.save(pattern); + final Pattern saved = repository.save(pattern); + patterns.put(saved.getId(), pattern); + return saved; } private java.util.regex.Pattern compilePattern(Pattern pattern) { diff --git a/src/main/java/ru/serega6531/packmate/service/ServicesService.java b/src/main/java/ru/serega6531/packmate/service/ServicesService.java index 73b5a46..4b1e942 100644 --- a/src/main/java/ru/serega6531/packmate/service/ServicesService.java +++ b/src/main/java/ru/serega6531/packmate/service/ServicesService.java @@ -50,9 +50,10 @@ public class ServicesService { } public CtfService save(CtfService service) { - log.info("Добавлен новый сервис {} на порту {}", service.getName(), service.getPort()); - services.put(service.getPort(), service); - return repository.save(service); + log.info("Добавлен или изменен сервис {} на порту {}", service.getName(), service.getPort()); + final CtfService saved = repository.save(service); + services.put(saved.getPort(), service); + return saved; } } diff --git a/src/main/java/ru/serega6531/packmate/service/StreamService.java b/src/main/java/ru/serega6531/packmate/service/StreamService.java index 24d3b8a..39b191d 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamService.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamService.java @@ -18,6 +18,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.*; import java.util.regex.Matcher; +import java.util.stream.Collectors; import java.util.zip.GZIPInputStream; import java.util.zip.ZipException; @@ -85,7 +86,7 @@ public class StreamService { stream.setTtl(firstIncoming.isPresent() ? firstIncoming.get().getTtl() : 0); stream.setStartTimestamp(packets.get(0).getTimestamp()); stream.setEndTimestamp(packets.get(packets.size() - 1).getTimestamp()); - stream.setService(serviceOptional.get()); + stream.setService(serviceOptional.get().getPort()); if (ignoreEmptyPackets) { packets.removeIf(packet -> packet.getContent().length == 0); @@ -174,14 +175,19 @@ public class StreamService { Stream savedStream = save(stream); - Set matches = new HashSet<>(); + Set foundPatterns = new HashSet<>(); for (ru.serega6531.packmate.model.Packet packet : packets) { packet.setStream(savedStream); - matches.addAll(patternService.findMatching(packet.getContent(), packet.isIncoming())); + final Set matches = patternService.findMatches(packet.getContent(), packet.isIncoming()); + packet.setMatches(matches); + foundPatterns.addAll(matches.stream() + .map(FoundPattern::getPatternId) + .map(patternService::find) + .collect(Collectors.toList())); } - savedStream.setFoundPatterns(new ArrayList<>(matches)); + savedStream.setFoundPatterns(foundPatterns); savedStream.setPackets(packetService.saveAll(packets)); savedStream = save(savedStream); @@ -277,7 +283,7 @@ public class StreamService { } } - public List findFavoritesByService(Pagination pagination, CtfService service) { + public List findFavoritesByService(Pagination pagination, int service) { PageRequest page = PageRequest.of(0, pagination.getPageSize(), pagination.getDirection(), "id"); if (pagination.getPattern() != null) { // задан паттерн для поиска @@ -313,7 +319,7 @@ public class StreamService { } } - public List findAllByService(Pagination pagination, CtfService service) { + public List findAllByService(Pagination pagination, int service) { PageRequest page = PageRequest.of(0, pagination.getPageSize(), pagination.getDirection(), "id"); if (pagination.getPattern() != null) { // задан паттерн для поиска diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2137896..5ae077f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,10 +9,10 @@ spring: ddl-auto: update properties: hibernate: - format_sql: true +# format_sql: true temp: use_jdbc_metadata_defaults: false - show-sql: true +# show-sql: true enable-capture: true