From dd0dd9aa6214dd4496df0fce5925443e04827cc7 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 10 Jan 2021 03:03:43 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=20=D0=BF=D0=B0=D1=82?= =?UTF-8?q?=D1=82=D0=B5=D1=80=D0=BD=D0=BE=D0=B2=20=D0=B2=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=88=D0=BB=D1=8B=D1=85=20=D1=81=D1=82=D1=80=D0=B8=D0=BC?= =?UTF-8?q?=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PatternController.java | 9 ++++ .../ru/serega6531/packmate/model/Pattern.java | 3 ++ .../ru/serega6531/packmate/model/Stream.java | 5 +- .../model/enums/SubscriptionMessageType.java | 1 + .../packmate/service/PatternService.java | 31 ++++++++++++ .../packmate/service/StreamService.java | 50 ++++++++++++++++++- 6 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/serega6531/packmate/controller/PatternController.java b/src/main/java/ru/serega6531/packmate/controller/PatternController.java index 335b55f..1f95ffc 100644 --- a/src/main/java/ru/serega6531/packmate/controller/PatternController.java +++ b/src/main/java/ru/serega6531/packmate/controller/PatternController.java @@ -32,6 +32,15 @@ public class PatternController { service.enable(id, enabled); } + @PostMapping("/{id}/lookback") + public void lookBack(@PathVariable int id, @RequestBody int minutes) { + if (minutes < 1) { + return; + } + + service.lookBack(id, minutes); + } + @PostMapping public PatternDto addPattern(@RequestBody PatternDto dto) { dto.setEnabled(true); diff --git a/src/main/java/ru/serega6531/packmate/model/Pattern.java b/src/main/java/ru/serega6531/packmate/model/Pattern.java index 26c6fcb..8c55477 100644 --- a/src/main/java/ru/serega6531/packmate/model/Pattern.java +++ b/src/main/java/ru/serega6531/packmate/model/Pattern.java @@ -42,7 +42,10 @@ public class Pattern { private PatternActionType actionType; + private long searchStartTimestamp; + @ManyToMany(mappedBy = "foundPatterns", fetch = FetchType.LAZY) private List matchedStreams; + } diff --git a/src/main/java/ru/serega6531/packmate/model/Stream.java b/src/main/java/ru/serega6531/packmate/model/Stream.java index 6df12e6..ef83b14 100644 --- a/src/main/java/ru/serega6531/packmate/model/Stream.java +++ b/src/main/java/ru/serega6531/packmate/model/Stream.java @@ -6,6 +6,7 @@ import org.hibernate.annotations.GenericGenerator; import ru.serega6531.packmate.model.enums.Protocol; import javax.persistence.*; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -40,8 +41,8 @@ public class Stream { private long endTimestamp; - @ManyToMany(cascade = CascadeType.ALL) - private Set foundPatterns; + @ManyToMany + private Set foundPatterns = new HashSet<>(); private boolean favorite; diff --git a/src/main/java/ru/serega6531/packmate/model/enums/SubscriptionMessageType.java b/src/main/java/ru/serega6531/packmate/model/enums/SubscriptionMessageType.java index 629af1f..921a0aa 100644 --- a/src/main/java/ru/serega6531/packmate/model/enums/SubscriptionMessageType.java +++ b/src/main/java/ru/serega6531/packmate/model/enums/SubscriptionMessageType.java @@ -4,6 +4,7 @@ public enum SubscriptionMessageType { SAVE_SERVICE, SAVE_PATTERN, DELETE_SERVICE, DELETE_PATTERN, NEW_STREAM, + FINISH_LOOKBACK, COUNTERS_UPDATE, ENABLE_PATTERN, DISABLE_PATTERN, PCAP_STARTED, PCAP_STOPPED diff --git a/src/main/java/ru/serega6531/packmate/service/PatternService.java b/src/main/java/ru/serega6531/packmate/service/PatternService.java index 1da14af..af1e054 100644 --- a/src/main/java/ru/serega6531/packmate/service/PatternService.java +++ b/src/main/java/ru/serega6531/packmate/service/PatternService.java @@ -1,8 +1,10 @@ package ru.serega6531.packmate.service; +import com.google.common.collect.Iterables; import lombok.extern.slf4j.Slf4j; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import ru.serega6531.packmate.model.FoundPattern; import ru.serega6531.packmate.model.Pattern; @@ -14,7 +16,9 @@ import ru.serega6531.packmate.model.pojo.PatternDto; import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.repository.PatternRepository; +import java.time.Instant; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; @@ -23,6 +27,7 @@ import java.util.stream.Collectors; public class PatternService { private final PatternRepository repository; + private final StreamService streamService; private final SubscriptionService subscriptionService; private final Map patterns = new HashMap<>(); @@ -30,8 +35,10 @@ public class PatternService { @Autowired public PatternService(PatternRepository repository, + @Lazy StreamService streamService, SubscriptionService subscriptionService) { this.repository = repository; + this.streamService = streamService; this.subscriptionService = subscriptionService; repository.findAll().forEach(p -> patterns.put(p.getId(), p)); @@ -55,6 +62,11 @@ public class PatternService { return new PatternMatcher(bytes, list).findMatches(); } + public Optional tryMatch(byte[] bytes, Pattern pattern) { + Set matches = new PatternMatcher(bytes, List.of(pattern)).findMatches(); + return Optional.ofNullable(Iterables.getOnlyElement(matches, null)); + } + public void enable(int id, boolean enabled) { final Pattern pattern = find(id); if (pattern != null) { @@ -81,13 +93,32 @@ public class PatternService { } } + pattern.setSearchStartTimestamp(System.currentTimeMillis()); + final Pattern saved = repository.save(pattern); patterns.put(saved.getId(), saved); + log.info("Added new pattern '{}' with value '{}'", pattern.getName(), pattern.getValue()); subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.SAVE_PATTERN, toDto(saved))); + return saved; } + public void lookBack(int id, int minutes) { + final Pattern pattern = find(id); + if (pattern != null && pattern.getActionType() == PatternActionType.FIND) { + long end = pattern.getSearchStartTimestamp(); + long start = end - TimeUnit.MINUTES.toMillis(minutes); + + pattern.setSearchStartTimestamp(start); + repository.save(pattern); + + log.info("Scanning for pattern '{}' between {} and {}", pattern.getName(), + Instant.ofEpochMilli(start), Instant.ofEpochMilli(end)); + streamService.processLookbackPattern(pattern, start, end); + } + } + public Pattern fromDto(PatternDto dto) { return modelMapper.map(dto, Pattern.class); } diff --git a/src/main/java/ru/serega6531/packmate/service/StreamService.java b/src/main/java/ru/serega6531/packmate/service/StreamService.java index 7115131..9be3fa4 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamService.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamService.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -123,6 +124,21 @@ public class StreamService { return true; } + @Async + public void processLookbackPattern(Pattern pattern, long start, long end) { + List streams = findAllBetweenTimestamps(start, end); + + for (Stream stream : streams) { + boolean found = matchPattern(stream.getPackets(), pattern); + if (found) { + stream.getFoundPatterns().add(pattern); + repository.save(stream); + } + } + + subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.FINISH_LOOKBACK, pattern.getId())); + } + private void processUserAgent(List packets, Stream stream) { String ua = null; for (Packet packet : packets) { @@ -169,6 +185,30 @@ public class StreamService { return foundPatterns; } + private boolean matchPattern(List packets, Pattern pattern) { + boolean matched = false; + + for (Packet packet : packets) { + PatternDirectionType direction = packet.isIncoming() ? PatternDirectionType.INPUT : PatternDirectionType.OUTPUT; + + if (pattern.getDirectionType() != PatternDirectionType.BOTH && pattern.getDirectionType() != direction) { + continue; + } + + final Optional matchOpt = patternService.tryMatch(packet.getContent(), pattern); + + if (matchOpt.isPresent()) { + FoundPattern match = matchOpt.get(); + packet.getMatches().add(match); + match.setPacket(packet); + + matched = true; + } + } + + return matched; + } + private boolean isStreamIgnored(List packets) { for (Packet packet : packets) { PatternDirectionType direction = packet.isIncoming() ? PatternDirectionType.INPUT : PatternDirectionType.OUTPUT; @@ -203,7 +243,6 @@ public class StreamService { repository.setFavorite(id, favorite); } - @SuppressWarnings("ConstantConditions") public List findAll(Pagination pagination, Optional service, boolean onlyFavorites) { PageRequest page = PageRequest.of(0, pagination.getPageSize(), pagination.getDirection(), "id"); @@ -229,6 +268,11 @@ public class StreamService { return repository.findAll(spec, page).getContent(); } + public List findAllBetweenTimestamps(long start, long end) { + Specification spec = streamTimestampBetween(start, end); + return repository.findAll(spec); + } + public StreamDto streamToDto(Stream stream) { return modelMapper.map(stream, StreamDto.class); } @@ -253,6 +297,10 @@ public class StreamService { return (root, query, cb) -> cb.lessThan(root.get("id"), id); } + private Specification streamTimestampBetween(long start, long end) { + return (root, query, cb) -> cb.between(root.get("startTimestamp"), start, end); + } + private Specification streamPatternsContains(Pattern pattern) { return (root, query, cb) -> cb.isMember(pattern, root.get("foundPatterns")); }