Добавлен поиск паттернов в прошлых стримах

This commit is contained in:
serega6531
2021-01-10 03:03:43 +03:00
parent 4d1d581448
commit dd0dd9aa62
6 changed files with 96 additions and 3 deletions

View File

@@ -32,6 +32,15 @@ public class PatternController {
service.enable(id, enabled); 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 @PostMapping
public PatternDto addPattern(@RequestBody PatternDto dto) { public PatternDto addPattern(@RequestBody PatternDto dto) {
dto.setEnabled(true); dto.setEnabled(true);

View File

@@ -42,7 +42,10 @@ public class Pattern {
private PatternActionType actionType; private PatternActionType actionType;
private long searchStartTimestamp;
@ManyToMany(mappedBy = "foundPatterns", fetch = FetchType.LAZY) @ManyToMany(mappedBy = "foundPatterns", fetch = FetchType.LAZY)
private List<Stream> matchedStreams; private List<Stream> matchedStreams;
} }

View File

@@ -6,6 +6,7 @@ import org.hibernate.annotations.GenericGenerator;
import ru.serega6531.packmate.model.enums.Protocol; import ru.serega6531.packmate.model.enums.Protocol;
import javax.persistence.*; import javax.persistence.*;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -40,8 +41,8 @@ public class Stream {
private long endTimestamp; private long endTimestamp;
@ManyToMany(cascade = CascadeType.ALL) @ManyToMany
private Set<Pattern> foundPatterns; private Set<Pattern> foundPatterns = new HashSet<>();
private boolean favorite; private boolean favorite;

View File

@@ -4,6 +4,7 @@ public enum SubscriptionMessageType {
SAVE_SERVICE, SAVE_PATTERN, SAVE_SERVICE, SAVE_PATTERN,
DELETE_SERVICE, DELETE_PATTERN, DELETE_SERVICE, DELETE_PATTERN,
NEW_STREAM, NEW_STREAM,
FINISH_LOOKBACK,
COUNTERS_UPDATE, COUNTERS_UPDATE,
ENABLE_PATTERN, DISABLE_PATTERN, ENABLE_PATTERN, DISABLE_PATTERN,
PCAP_STARTED, PCAP_STOPPED PCAP_STARTED, PCAP_STOPPED

View File

@@ -1,8 +1,10 @@
package ru.serega6531.packmate.service; package ru.serega6531.packmate.service;
import com.google.common.collect.Iterables;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper; import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.serega6531.packmate.model.FoundPattern; import ru.serega6531.packmate.model.FoundPattern;
import ru.serega6531.packmate.model.Pattern; 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.model.pojo.SubscriptionMessage;
import ru.serega6531.packmate.repository.PatternRepository; import ru.serega6531.packmate.repository.PatternRepository;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -23,6 +27,7 @@ import java.util.stream.Collectors;
public class PatternService { public class PatternService {
private final PatternRepository repository; private final PatternRepository repository;
private final StreamService streamService;
private final SubscriptionService subscriptionService; private final SubscriptionService subscriptionService;
private final Map<Integer, Pattern> patterns = new HashMap<>(); private final Map<Integer, Pattern> patterns = new HashMap<>();
@@ -30,8 +35,10 @@ public class PatternService {
@Autowired @Autowired
public PatternService(PatternRepository repository, public PatternService(PatternRepository repository,
@Lazy StreamService streamService,
SubscriptionService subscriptionService) { SubscriptionService subscriptionService) {
this.repository = repository; this.repository = repository;
this.streamService = streamService;
this.subscriptionService = subscriptionService; this.subscriptionService = subscriptionService;
repository.findAll().forEach(p -> patterns.put(p.getId(), p)); repository.findAll().forEach(p -> patterns.put(p.getId(), p));
@@ -55,6 +62,11 @@ public class PatternService {
return new PatternMatcher(bytes, list).findMatches(); return new PatternMatcher(bytes, list).findMatches();
} }
public Optional<FoundPattern> tryMatch(byte[] bytes, Pattern pattern) {
Set<FoundPattern> matches = new PatternMatcher(bytes, List.of(pattern)).findMatches();
return Optional.ofNullable(Iterables.getOnlyElement(matches, null));
}
public void enable(int id, boolean enabled) { public void enable(int id, boolean enabled) {
final Pattern pattern = find(id); final Pattern pattern = find(id);
if (pattern != null) { if (pattern != null) {
@@ -81,13 +93,32 @@ public class PatternService {
} }
} }
pattern.setSearchStartTimestamp(System.currentTimeMillis());
final Pattern saved = repository.save(pattern); final Pattern saved = repository.save(pattern);
patterns.put(saved.getId(), saved); patterns.put(saved.getId(), saved);
log.info("Added new pattern '{}' with value '{}'", pattern.getName(), pattern.getValue()); log.info("Added new pattern '{}' with value '{}'", pattern.getName(), pattern.getValue());
subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.SAVE_PATTERN, toDto(saved))); subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.SAVE_PATTERN, toDto(saved)));
return 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) { public Pattern fromDto(PatternDto dto) {
return modelMapper.map(dto, Pattern.class); return modelMapper.map(dto, Pattern.class);
} }

View File

@@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -123,6 +124,21 @@ public class StreamService {
return true; return true;
} }
@Async
public void processLookbackPattern(Pattern pattern, long start, long end) {
List<Stream> 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<Packet> packets, Stream stream) { private void processUserAgent(List<Packet> packets, Stream stream) {
String ua = null; String ua = null;
for (Packet packet : packets) { for (Packet packet : packets) {
@@ -169,6 +185,30 @@ public class StreamService {
return foundPatterns; return foundPatterns;
} }
private boolean matchPattern(List<Packet> 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<FoundPattern> 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<Packet> packets) { private boolean isStreamIgnored(List<Packet> packets) {
for (Packet packet : packets) { for (Packet packet : packets) {
PatternDirectionType direction = packet.isIncoming() ? PatternDirectionType.INPUT : PatternDirectionType.OUTPUT; PatternDirectionType direction = packet.isIncoming() ? PatternDirectionType.INPUT : PatternDirectionType.OUTPUT;
@@ -203,7 +243,6 @@ public class StreamService {
repository.setFavorite(id, favorite); repository.setFavorite(id, favorite);
} }
@SuppressWarnings("ConstantConditions")
public List<Stream> findAll(Pagination pagination, Optional<Integer> service, boolean onlyFavorites) { public List<Stream> findAll(Pagination pagination, Optional<Integer> service, boolean onlyFavorites) {
PageRequest page = PageRequest.of(0, pagination.getPageSize(), pagination.getDirection(), "id"); PageRequest page = PageRequest.of(0, pagination.getPageSize(), pagination.getDirection(), "id");
@@ -229,6 +268,11 @@ public class StreamService {
return repository.findAll(spec, page).getContent(); return repository.findAll(spec, page).getContent();
} }
public List<Stream> findAllBetweenTimestamps(long start, long end) {
Specification<Stream> spec = streamTimestampBetween(start, end);
return repository.findAll(spec);
}
public StreamDto streamToDto(Stream stream) { public StreamDto streamToDto(Stream stream) {
return modelMapper.map(stream, StreamDto.class); return modelMapper.map(stream, StreamDto.class);
} }
@@ -253,6 +297,10 @@ public class StreamService {
return (root, query, cb) -> cb.lessThan(root.get("id"), id); return (root, query, cb) -> cb.lessThan(root.get("id"), id);
} }
private Specification<Stream> streamTimestampBetween(long start, long end) {
return (root, query, cb) -> cb.between(root.get("startTimestamp"), start, end);
}
private Specification<Stream> streamPatternsContains(Pattern pattern) { private Specification<Stream> streamPatternsContains(Pattern pattern) {
return (root, query, cb) -> cb.isMember(pattern, root.get("foundPatterns")); return (root, query, cb) -> cb.isMember(pattern, root.get("foundPatterns"));
} }