From a0ceda4cb48a4ecefd02bcb977f5d0fb528fbde0 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 5 Apr 2020 23:55:29 +0300 Subject: [PATCH 1/8] =?UTF-8?q?=D0=A0=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B4=20=D1=87=D1=82=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC?= =?UTF-8?q?=20pcap=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packmate/ApplicationConfiguration.java | 28 +++++++++ .../packmate/PackmateApplication.java | 5 +- .../packmate/TimeoutStreamsSaver.java | 1 + .../packmate/model/enums/CaptureMode.java | 7 +++ .../AbstractPcapWorker.java} | 58 +++-------------- .../packmate/pcap/FilePcapWorker.java | 59 ++++++++++++++++++ .../packmate/pcap/LivePcapWorker.java | 62 +++++++++++++++++++ .../serega6531/packmate/pcap/PcapWorker.java | 12 ++++ src/main/resources/application.yml | 1 + 9 files changed, 181 insertions(+), 52 deletions(-) create mode 100644 src/main/java/ru/serega6531/packmate/model/enums/CaptureMode.java rename src/main/java/ru/serega6531/packmate/{PcapWorker.java => pcap/AbstractPcapWorker.java} (83%) create mode 100644 src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java create mode 100644 src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java create mode 100644 src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java diff --git a/src/main/java/ru/serega6531/packmate/ApplicationConfiguration.java b/src/main/java/ru/serega6531/packmate/ApplicationConfiguration.java index ee7e15f..c049d50 100644 --- a/src/main/java/ru/serega6531/packmate/ApplicationConfiguration.java +++ b/src/main/java/ru/serega6531/packmate/ApplicationConfiguration.java @@ -1,20 +1,33 @@ package ru.serega6531.packmate; +import org.pcap4j.core.PcapNativeException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; +import ru.serega6531.packmate.model.enums.CaptureMode; +import ru.serega6531.packmate.pcap.FilePcapWorker; +import ru.serega6531.packmate.pcap.LivePcapWorker; +import ru.serega6531.packmate.pcap.PcapWorker; +import ru.serega6531.packmate.service.ServicesService; +import ru.serega6531.packmate.service.StreamService; + +import java.net.UnknownHostException; @Configuration @EnableWebSecurity +@EnableScheduling +@EnableWebSocket public class ApplicationConfiguration extends WebSecurityConfigurerAdapter implements WebSocketConfigurer { @Value("${account-login}") @@ -30,6 +43,21 @@ public class ApplicationConfiguration extends WebSecurityConfigurerAdapter imple this.webSocketHandler = webSocketHandler; } + @Bean(destroyMethod = "stop") + @Autowired + public PcapWorker pcapWorker(ServicesService servicesService, + StreamService streamService, + @Value("${local-ip}") String localIpString, + @Value("${interface-name}") String interfaceName, + @Value("${pcap-file}") String filename, + @Value("${capture-mode}") CaptureMode captureMode) throws PcapNativeException, UnknownHostException { + if(captureMode == CaptureMode.LIVE) { + return new LivePcapWorker(servicesService, streamService, localIpString, interfaceName); + } else { + return new FilePcapWorker(servicesService, streamService, localIpString, filename); + } + } + @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() diff --git a/src/main/java/ru/serega6531/packmate/PackmateApplication.java b/src/main/java/ru/serega6531/packmate/PackmateApplication.java index 4054f15..2cf49fb 100644 --- a/src/main/java/ru/serega6531/packmate/PackmateApplication.java +++ b/src/main/java/ru/serega6531/packmate/PackmateApplication.java @@ -6,12 +6,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.web.socket.config.annotation.EnableWebSocket; +import ru.serega6531.packmate.pcap.PcapWorker; @SpringBootApplication -@EnableScheduling -@EnableWebSocket public class PackmateApplication { @Value("${enable-capture}") diff --git a/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java b/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java index 68acaab..b4bd9bf 100644 --- a/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java +++ b/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java @@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import ru.serega6531.packmate.model.enums.Protocol; +import ru.serega6531.packmate.pcap.PcapWorker; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/ru/serega6531/packmate/model/enums/CaptureMode.java b/src/main/java/ru/serega6531/packmate/model/enums/CaptureMode.java new file mode 100644 index 0000000..3a9e751 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/model/enums/CaptureMode.java @@ -0,0 +1,7 @@ +package ru.serega6531.packmate.model.enums; + +public enum CaptureMode { + + LIVE, FILE + +} diff --git a/src/main/java/ru/serega6531/packmate/PcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/AbstractPcapWorker.java similarity index 83% rename from src/main/java/ru/serega6531/packmate/PcapWorker.java rename to src/main/java/ru/serega6531/packmate/pcap/AbstractPcapWorker.java index e19744d..be37015 100644 --- a/src/main/java/ru/serega6531/packmate/PcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/AbstractPcapWorker.java @@ -1,25 +1,22 @@ -package ru.serega6531.packmate; +package ru.serega6531.packmate.pcap; import com.google.common.collect.*; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.tuple.ImmutablePair; -import org.pcap4j.core.*; +import org.pcap4j.core.PacketListener; +import org.pcap4j.core.PcapHandle; import org.pcap4j.packet.IpV4Packet; import org.pcap4j.packet.Packet; import org.pcap4j.packet.TcpPacket; import org.pcap4j.packet.UdpPacket; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.enums.Protocol; import ru.serega6531.packmate.model.pojo.UnfinishedStream; import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.StreamService; -import javax.annotation.PreDestroy; import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; @@ -29,16 +26,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; -@Component @Slf4j -public class PcapWorker implements PacketListener { +public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { private final ServicesService servicesService; private final StreamService streamService; - private final PcapNetworkInterface device; - private PcapHandle pcap = null; - private final ExecutorService listenerExecutorService; + protected PcapHandle pcap = null; + protected final ExecutorService listenerExecutorService; private final InetAddress localIp; @@ -51,11 +46,9 @@ public class PcapWorker implements PacketListener { private final SetMultimap> fins = HashMultimap.create(); private final SetMultimap> acks = HashMultimap.create(); - @Autowired - public PcapWorker(ServicesService servicesService, - StreamService streamService, - @Value("${interface-name}") String interfaceName, - @Value("${local-ip}") String localIpString) throws PcapNativeException, UnknownHostException { + public AbstractPcapWorker(ServicesService servicesService, + StreamService streamService, + String localIpString) throws UnknownHostException { this.servicesService = servicesService; this.streamService = streamService; @@ -67,37 +60,6 @@ public class PcapWorker implements PacketListener { BasicThreadFactory factory = new BasicThreadFactory.Builder() .namingPattern("pcap-worker-listener").build(); listenerExecutorService = Executors.newSingleThreadExecutor(factory); - device = Pcaps.getDevByName(interfaceName); - } - - void start() throws PcapNativeException { - log.info("Using interface " + device.getName()); - pcap = device.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 100); - - BasicThreadFactory factory = new BasicThreadFactory.Builder() - .namingPattern("pcap-worker-loop").build(); - ExecutorService loopExecutorService = Executors.newSingleThreadExecutor(factory); - try { - log.info("Intercept started"); - pcap.loop(-1, this, loopExecutorService); - } catch (InterruptedException ignored) { - Thread.currentThread().interrupt(); - // выходим - } catch (Exception e) { - log.error("Error while capturing packet", e); - stop(); - } - } - - @PreDestroy - @SneakyThrows - private void stop() { - if (pcap != null && pcap.isOpen()) { - pcap.breakLoop(); - pcap.close(); - } - - log.info("Intercept stopped"); } public void gotPacket(Packet rawPacket) { @@ -241,7 +203,7 @@ public class PcapWorker implements PacketListener { } @SneakyThrows - int closeTimeoutStreams(Protocol protocol, long timeoutMillis) { + public int closeTimeoutStreams(Protocol protocol, long timeoutMillis) { return listenerExecutorService.submit(() -> { int streamsClosed = 0; diff --git a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java new file mode 100644 index 0000000..7a8f1ea --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java @@ -0,0 +1,59 @@ +package ru.serega6531.packmate.pcap; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.pcap4j.core.PcapNativeException; +import org.pcap4j.core.Pcaps; +import org.pcap4j.packet.Packet; +import ru.serega6531.packmate.service.ServicesService; +import ru.serega6531.packmate.service.StreamService; + +import java.io.EOFException; +import java.io.File; +import java.net.UnknownHostException; + +@Slf4j +public class FilePcapWorker extends AbstractPcapWorker { + + private final File file; + + public FilePcapWorker(ServicesService servicesService, + StreamService streamService, + String localIpString, + String filename) throws UnknownHostException { + super(servicesService, streamService, localIpString); + + file = new File(filename); + if(!file.exists()) { + throw new IllegalArgumentException("File " + file.getAbsolutePath() + " does not exist"); + } + } + + @SneakyThrows + @Override + public void start() { + pcap = Pcaps.openOffline(file.getAbsolutePath()); + + while (pcap.isOpen()) { + try { + final Packet packet = pcap.getNextPacketEx(); + gotPacket(packet); + } catch (PcapNativeException e) { + log.error("Pcap read", e); + Thread.sleep(100); + } catch (EOFException e) { + stop(); + break; + } + } + } + + @SneakyThrows + public void stop() { + if (pcap != null && pcap.isOpen()) { + pcap.close(); + } + + log.info("Intercept stopped"); + } +} diff --git a/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java new file mode 100644 index 0000000..0c69a6d --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java @@ -0,0 +1,62 @@ +package ru.serega6531.packmate.pcap; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.pcap4j.core.PcapNativeException; +import org.pcap4j.core.PcapNetworkInterface; +import org.pcap4j.core.Pcaps; +import ru.serega6531.packmate.service.ServicesService; +import ru.serega6531.packmate.service.StreamService; + +import java.net.UnknownHostException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Slf4j +public class LivePcapWorker extends AbstractPcapWorker { + + private final PcapNetworkInterface device; + + public LivePcapWorker(ServicesService servicesService, + StreamService streamService, + String localIpString, + String interfaceName) throws PcapNativeException, UnknownHostException { + super(servicesService, streamService, localIpString); + device = Pcaps.getDevByName(interfaceName); + + if(device == null) { + throw new IllegalArgumentException("Device " + interfaceName + " does not exist"); + } + } + + public void start() throws PcapNativeException { + log.info("Using interface " + device.getName()); + pcap = device.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 100); + + BasicThreadFactory factory = new BasicThreadFactory.Builder() + .namingPattern("pcap-worker-loop").build(); + ExecutorService loopExecutorService = Executors.newSingleThreadExecutor(factory); + try { + log.info("Intercept started"); + pcap.loop(-1, this, loopExecutorService); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + // выходим + } catch (Exception e) { + log.error("Error while capturing packet", e); + stop(); + } + } + + @SneakyThrows + public void stop() { + if (pcap != null && pcap.isOpen()) { + pcap.breakLoop(); + pcap.close(); + } + + log.info("Intercept stopped"); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java new file mode 100644 index 0000000..62ee4c6 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java @@ -0,0 +1,12 @@ +package ru.serega6531.packmate.pcap; + +import org.pcap4j.core.PcapNativeException; +import ru.serega6531.packmate.model.enums.Protocol; + +public interface PcapWorker { + + void start() throws PcapNativeException; + void stop(); + int closeTimeoutStreams(Protocol protocol, long timeoutMillis); + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3b39146..ed78283 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,6 +15,7 @@ spring: enable-capture: true +capture-mode: LIVE # LIVE, FILE interface-name: enp0s31f6 local-ip: "192.168.0.125" account-login: BinaryBears From 0391d55e91fd817cb86f6866b7bfbb879072f9d3 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Mon, 6 Apr 2020 01:46:06 +0300 Subject: [PATCH 2/8] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=8D=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD=D1=82=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=D0=B0?= =?UTF-8?q?=20pcap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + docker-compose.yml | 3 ++ .../packmate/PackmateApplication.java | 12 ++++--- .../ApplicationConfiguration.java | 3 +- .../packmate/controller/PcapController.java | 36 +++++++++++++++++++ .../packmate/pcap/FilePcapWorker.java | 4 ++- .../packmate/service/PcapService.java | 29 +++++++++++++++ src/main/resources/application.yml | 1 + 8 files changed, 83 insertions(+), 6 deletions(-) rename src/main/java/ru/serega6531/packmate/{ => configuration}/ApplicationConfiguration.java (97%) create mode 100644 src/main/java/ru/serega6531/packmate/controller/PcapController.java create mode 100644 src/main/java/ru/serega6531/packmate/service/PcapService.java diff --git a/.gitignore b/.gitignore index 69eef86..985e68d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ src/main/resources/static/* +*.pcap HELP.md .gradle diff --git a/docker-compose.yml b/docker-compose.yml index c969e43..f0709f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,8 @@ services: DB_NAME: ${PACKMATE_DB_NAME:-packmate} INTERFACE: ${PACKMATE_INTERFACE} LOCAL_IP: ${PACKMATE_LOCAL_IP} + MODE: ${PACKMATE_MODE:-LIVE} + PCAP_FILE: ${PACKMATE_PCAP_FILE} WEB_LOGIN: ${PACKMATE_WEB_LOGIN:-BinaryBears} WEB_PASSWORD: ${PACKMATE_WEB_PASSWORD:-123456} env_file: @@ -21,6 +23,7 @@ services: "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", "-jar", "/app/app.jar", "--spring.datasource.url=jdbc:postgresql://127.0.0.1:65001/$${DB_NAME}", "--spring.datasource.username=$${DB_USER}", "--spring.datasource.password=$${DB_PASSWORD}", + "--capture-mode=$${MODE}", "--pcap-file=$${PCAP_FILE}", "--interface-name=$${INTERFACE}", "--local-ip=$${LOCAL_IP}", "--account-login=$${WEB_LOGIN}", "--account-password=$${WEB_PASSWORD}", "--server.port=65000", "--server.address=0.0.0.0" ] diff --git a/src/main/java/ru/serega6531/packmate/PackmateApplication.java b/src/main/java/ru/serega6531/packmate/PackmateApplication.java index 2cf49fb..ddad525 100644 --- a/src/main/java/ru/serega6531/packmate/PackmateApplication.java +++ b/src/main/java/ru/serega6531/packmate/PackmateApplication.java @@ -6,7 +6,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; -import ru.serega6531.packmate.pcap.PcapWorker; +import ru.serega6531.packmate.model.enums.CaptureMode; +import ru.serega6531.packmate.service.PcapService; @SpringBootApplication public class PackmateApplication { @@ -14,15 +15,18 @@ public class PackmateApplication { @Value("${enable-capture}") private boolean enableCapture; + @Value("${capture-mode}") + private CaptureMode captureMode; + public static void main(String[] args) { SpringApplication.run(PackmateApplication.class, args); } @EventListener(ApplicationReadyEvent.class) public void afterStartup(ApplicationReadyEvent event) throws PcapNativeException { - if (enableCapture) { - final PcapWorker pcapWorker = event.getApplicationContext().getBean(PcapWorker.class); - pcapWorker.start(); + if (enableCapture && captureMode == CaptureMode.LIVE) { + final PcapService pcapService = event.getApplicationContext().getBean(PcapService.class); + pcapService.start(); } } diff --git a/src/main/java/ru/serega6531/packmate/ApplicationConfiguration.java b/src/main/java/ru/serega6531/packmate/configuration/ApplicationConfiguration.java similarity index 97% rename from src/main/java/ru/serega6531/packmate/ApplicationConfiguration.java rename to src/main/java/ru/serega6531/packmate/configuration/ApplicationConfiguration.java index c049d50..fcfcee9 100644 --- a/src/main/java/ru/serega6531/packmate/ApplicationConfiguration.java +++ b/src/main/java/ru/serega6531/packmate/configuration/ApplicationConfiguration.java @@ -1,4 +1,4 @@ -package ru.serega6531.packmate; +package ru.serega6531.packmate.configuration; import org.pcap4j.core.PcapNativeException; import org.springframework.beans.factory.annotation.Autowired; @@ -15,6 +15,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; +import ru.serega6531.packmate.WebSocketHandler; import ru.serega6531.packmate.model.enums.CaptureMode; import ru.serega6531.packmate.pcap.FilePcapWorker; import ru.serega6531.packmate.pcap.LivePcapWorker; diff --git a/src/main/java/ru/serega6531/packmate/controller/PcapController.java b/src/main/java/ru/serega6531/packmate/controller/PcapController.java new file mode 100644 index 0000000..7199f68 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/controller/PcapController.java @@ -0,0 +1,36 @@ +package ru.serega6531.packmate.controller; + +import org.pcap4j.core.PcapNativeException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.serega6531.packmate.service.PcapService; + +@RestController +@RequestMapping("/api/pcap/") +public class PcapController { + + private final PcapService service; + + @Autowired + public PcapController(PcapService service) { + this.service = service; + } + + @GetMapping("/started") + public boolean started() { + return service.isStarted(); + } + + public boolean isRunning() { + return true; //TODO + } + + @PostMapping("/start") + public void start() throws PcapNativeException { + service.start(); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java index 7a8f1ea..6a541f1 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java @@ -42,6 +42,7 @@ public class FilePcapWorker extends AbstractPcapWorker { log.error("Pcap read", e); Thread.sleep(100); } catch (EOFException e) { + log.info("All packets processed"); stop(); break; } @@ -54,6 +55,7 @@ public class FilePcapWorker extends AbstractPcapWorker { pcap.close(); } - log.info("Intercept stopped"); + //TODO закрывать все стримы + log.info("Pcap closed"); } } diff --git a/src/main/java/ru/serega6531/packmate/service/PcapService.java b/src/main/java/ru/serega6531/packmate/service/PcapService.java new file mode 100644 index 0000000..b503bd3 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/PcapService.java @@ -0,0 +1,29 @@ +package ru.serega6531.packmate.service; + +import lombok.Getter; +import org.pcap4j.core.PcapNativeException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.serega6531.packmate.pcap.PcapWorker; + +@Service +public class PcapService { + + @Getter + private boolean started = false; + + private final PcapWorker worker; + + @Autowired + public PcapService(PcapWorker worker) { + this.worker = worker; + } + + public synchronized void start() throws PcapNativeException { + if(!started) { + started = true; + worker.start(); + } + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ed78283..4abd2b1 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -17,6 +17,7 @@ spring: enable-capture: true capture-mode: LIVE # LIVE, FILE interface-name: enp0s31f6 +pcap-file: file.pcap local-ip: "192.168.0.125" account-login: BinaryBears account-password: 123456 From 733d92cbf82ebd659e38539b1fa76cf87dd7d558 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Mon, 6 Apr 2020 23:10:01 +0300 Subject: [PATCH 3/8] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=BE=D0=B5=20=D0=B2=D1=80=D0=B5=D0=BC=D1=8F=20=D0=BF?= =?UTF-8?q?=D0=B0=D0=BA=D0=B5=D1=82=D0=B0=20=D0=BF=D1=80=D0=B8=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B5=20pcap=20?= =?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packmate/TimeoutStreamsSaver.java | 2 + .../packmate/controller/PcapController.java | 4 -- .../packmate/pcap/AbstractPcapWorker.java | 46 +++++++++++++------ .../packmate/pcap/FilePcapWorker.java | 16 +++++-- .../packmate/pcap/LivePcapWorker.java | 8 ++-- .../serega6531/packmate/pcap/PcapWorker.java | 9 ++++ 6 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java b/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java index b4bd9bf..d251fb7 100644 --- a/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java +++ b/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java @@ -3,6 +3,7 @@ package ru.serega6531.packmate; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import ru.serega6531.packmate.model.enums.Protocol; @@ -12,6 +13,7 @@ import java.util.concurrent.TimeUnit; @Component @Slf4j +@ConditionalOnProperty(name = "capture-mode", havingValue = "LIVE") public class TimeoutStreamsSaver { private final PcapWorker pcapWorker; diff --git a/src/main/java/ru/serega6531/packmate/controller/PcapController.java b/src/main/java/ru/serega6531/packmate/controller/PcapController.java index 7199f68..c314975 100644 --- a/src/main/java/ru/serega6531/packmate/controller/PcapController.java +++ b/src/main/java/ru/serega6531/packmate/controller/PcapController.java @@ -24,10 +24,6 @@ public class PcapController { return service.isStarted(); } - public boolean isRunning() { - return true; //TODO - } - @PostMapping("/start") public void start() throws PcapNativeException { service.start(); diff --git a/src/main/java/ru/serega6531/packmate/pcap/AbstractPcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/AbstractPcapWorker.java index be37015..e211eff 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/AbstractPcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/AbstractPcapWorker.java @@ -20,6 +20,7 @@ import ru.serega6531.packmate.service.StreamService; import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutorService; @@ -33,7 +34,10 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { private final StreamService streamService; protected PcapHandle pcap = null; - protected final ExecutorService listenerExecutorService; + protected final ExecutorService loopExecutorService; + + // во время работы должен быть != null + protected ExecutorService processorExecutorService; private final InetAddress localIp; @@ -58,8 +62,8 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { } BasicThreadFactory factory = new BasicThreadFactory.Builder() - .namingPattern("pcap-worker-listener").build(); - listenerExecutorService = Executors.newSingleThreadExecutor(factory); + .namingPattern("pcap-loop").build(); + loopExecutorService = Executors.newSingleThreadExecutor(factory); } public void gotPacket(Packet rawPacket) { @@ -67,14 +71,16 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { return; } + final long time = pcap.getTimestamp().getTime(); + if (rawPacket.contains(TcpPacket.class)) { - gotTcpPacket(rawPacket); + gotTcpPacket(rawPacket, time); } else if (rawPacket.contains(UdpPacket.class)) { - gotUdpPacket(rawPacket); + gotUdpPacket(rawPacket, time); } } - private void gotTcpPacket(Packet rawPacket) { + private void gotTcpPacket(Packet rawPacket, long time) { final IpV4Packet.IpV4Header ipHeader = rawPacket.get(IpV4Packet.class).getHeader(); Inet4Address sourceIp = ipHeader.getSrcAddr(); Inet4Address destIp = ipHeader.getDstAddr(); @@ -96,9 +102,7 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { servicesService.findService(sourceIp, sourcePort, destIp, destPort); if (serviceOptional.isPresent()) { - final long time = System.currentTimeMillis(); - - listenerExecutorService.execute(() -> { + processorExecutorService.execute(() -> { UnfinishedStream stream = addNewPacket(sourceIp, destIp, time, sourcePort, destPort, ttl, content, Protocol.TCP); if (log.isDebugEnabled()) { @@ -116,7 +120,7 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { } } - private void gotUdpPacket(Packet rawPacket) { + private void gotUdpPacket(Packet rawPacket, long time) { final IpV4Packet.IpV4Header ipHeader = rawPacket.get(IpV4Packet.class).getHeader(); Inet4Address sourceIp = ipHeader.getSrcAddr(); Inet4Address destIp = ipHeader.getDstAddr(); @@ -135,9 +139,7 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { servicesService.findService(sourceIp, sourcePort, destIp, destPort); if (serviceOptional.isPresent()) { - final long time = System.currentTimeMillis(); - - listenerExecutorService.execute(() -> { + processorExecutorService.execute(() -> { UnfinishedStream stream = addNewPacket(sourceIp, destIp, time, sourcePort, destPort, ttl, content, Protocol.UDP); if (log.isDebugEnabled()) { @@ -202,9 +204,25 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener { } } + @Override + @SneakyThrows + public void closeAllStreams(Protocol protocol) { + final var streams = (protocol == Protocol.TCP) ? this.unfinishedTcpStreams : this.unfinishedUdpStreams; + + Multimaps.asMap(streams).forEach((key, value) -> + streamService.saveNewStream(key, new ArrayList<>(value))); + + streams.clear(); + if (protocol == Protocol.TCP) { + fins.clear(); + acks.clear(); + } + } + + @Override @SneakyThrows public int closeTimeoutStreams(Protocol protocol, long timeoutMillis) { - return listenerExecutorService.submit(() -> { + return processorExecutorService.submit(() -> { int streamsClosed = 0; final long time = System.currentTimeMillis(); diff --git a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java index 6a541f1..f74fea2 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java @@ -2,9 +2,11 @@ package ru.serega6531.packmate.pcap; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.apache.tomcat.util.threads.InlineExecutorService; import org.pcap4j.core.PcapNativeException; import org.pcap4j.core.Pcaps; import org.pcap4j.packet.Packet; +import ru.serega6531.packmate.model.enums.Protocol; import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.StreamService; @@ -27,13 +29,19 @@ public class FilePcapWorker extends AbstractPcapWorker { if(!file.exists()) { throw new IllegalArgumentException("File " + file.getAbsolutePath() + " does not exist"); } + + processorExecutorService = new InlineExecutorService(); } @SneakyThrows @Override public void start() { pcap = Pcaps.openOffline(file.getAbsolutePath()); + loopExecutorService.execute(this::runScan); + } + @SneakyThrows + private void runScan() { while (pcap.isOpen()) { try { final Packet packet = pcap.getNextPacketEx(); @@ -42,8 +50,9 @@ public class FilePcapWorker extends AbstractPcapWorker { log.error("Pcap read", e); Thread.sleep(100); } catch (EOFException e) { - log.info("All packets processed"); stop(); + + log.info("All packets processed"); break; } } @@ -53,9 +62,10 @@ public class FilePcapWorker extends AbstractPcapWorker { public void stop() { if (pcap != null && pcap.isOpen()) { pcap.close(); + log.info("Pcap closed"); } - //TODO закрывать все стримы - log.info("Pcap closed"); + closeAllStreams(Protocol.TCP); + closeAllStreams(Protocol.UDP); } } diff --git a/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java index 0c69a6d..16a38e9 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java @@ -10,7 +10,6 @@ import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.StreamService; import java.net.UnknownHostException; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @Slf4j @@ -28,15 +27,16 @@ public class LivePcapWorker extends AbstractPcapWorker { if(device == null) { throw new IllegalArgumentException("Device " + interfaceName + " does not exist"); } + + BasicThreadFactory factory = new BasicThreadFactory.Builder() + .namingPattern("pcap-processor").build(); + processorExecutorService = Executors.newSingleThreadExecutor(factory); } public void start() throws PcapNativeException { log.info("Using interface " + device.getName()); pcap = device.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 100); - BasicThreadFactory factory = new BasicThreadFactory.Builder() - .namingPattern("pcap-worker-loop").build(); - ExecutorService loopExecutorService = Executors.newSingleThreadExecutor(factory); try { log.info("Intercept started"); pcap.loop(-1, this, loopExecutorService); diff --git a/src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java index 62ee4c6..b79b891 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/PcapWorker.java @@ -7,6 +7,15 @@ public interface PcapWorker { void start() throws PcapNativeException; void stop(); + + /** + * Выполняется в вызывающем потоке + */ + void closeAllStreams(Protocol protocol); + + /** + * Выполняется в потоке обработчика + */ int closeTimeoutStreams(Protocol protocol, long timeoutMillis); } From e1b11cfdee7cb1d88294c2312e035c8eb483dfd5 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Mon, 6 Apr 2020 23:52:08 +0300 Subject: [PATCH 4/8] =?UTF-8?q?=D0=9E=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=B5=20=D0=B8=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=86=D0=B5=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 ++++++++++++++++--- README_EN.md | 20 ++++++++++++++++--- docker-compose.yml | 2 +- .../ApplicationConfiguration.java | 4 +++- .../model/enums/SubscriptionMessageType.java | 6 +++++- .../packmate/pcap/FilePcapWorker.java | 8 ++++++++ .../packmate/service/PcapService.java | 7 ++++++- .../packmate/service/SubscriptionService.java | 10 ++++++++-- 8 files changed, 65 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e03a52f..512a313 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Утилита перехвата и анализа трафика для CTF. #### Фичи: +* Поддерживает перехват живого трафика и обработку pcap файлов * Поддерживает текстовые и бинарные сервисы * Умеет отображать совпадения паттернов в пакетах цветом * Подстрока @@ -51,9 +52,7 @@ git submodule update --init --recursive В файле необходимо прописать: ```bash -# Интерфейс, на котором производится перехват трафика -PACKMATE_INTERFACE=wlan0 -# Локальный IP сервера на указанном интерфейсе +# Локальный IP сервера на указанном интерфейсе или в pcap файле PACKMATE_LOCAL_IP=192.168.1.124 # Имя пользователя для web-авторизации PACKMATE_WEB_LOGIN=SomeUser @@ -61,6 +60,21 @@ PACKMATE_WEB_LOGIN=SomeUser PACKMATE_WEB_PASSWORD=SomeSecurePassword ``` +Если мы перехватываем трафик сервера (лучший вариант, если есть возможность): +```bash +# Режим работы - перехват +PACKMATE_MODE=LIVE +# Интерфейс, на котором производится перехват трафика +PACKMATE_INTERFACE=wlan0 +``` +Если мы анализируем pcap дамп: +```bash +# Режим работы - анализ файла +PACKMATE_MODE=FILE +# Путь до файла от корня проекта +PACKMATE_PCAP_FILE=dump.pcap +``` + ### Запуск После указания нужных настроек в env-файле, можно запустить приложение: ```bash diff --git a/README_EN.md b/README_EN.md index 5b22879..5f8b3bf 100644 --- a/README_EN.md +++ b/README_EN.md @@ -7,6 +7,7 @@ Advanced network traffic flow analyzer for A/D CTFs. #### Features: +* Can monitor live traffic or analyze pcap files * Supports binary and textual services * Can highlight found patterns in packets * Substring @@ -50,9 +51,7 @@ It must be called `.env` and located at the root of the project. Contents of the file: ```bash -# Interface to capture on -PACKMATE_INTERFACE=wlan0 -# Local IP on said interface to tell incoming packets from outgoing +# Local IP on network interface or in pcap file to tell incoming packets from outgoing PACKMATE_LOCAL_IP=192.168.1.124 # Username for the web interface PACKMATE_WEB_LOGIN=SomeUser @@ -60,6 +59,21 @@ PACKMATE_WEB_LOGIN=SomeUser PACKMATE_WEB_PASSWORD=SomeSecurePassword ``` +If we are capturing live traffic (best option if possible): +```bash +# Mode: capturing +PACKMATE_MODE=LIVE +# Interface to capture on +PACKMATE_INTERFACE=wlan0 +``` +If we are analyzing pcap dump: +```bash +# Mode: dump analyzing +PACKMATE_MODE=FILE +# Path to pcap file from project root +PACKMATE_PCAP_FILE=dump.pcap +``` + ### Launch After filling in env file you can launch the app: ```bash diff --git a/docker-compose.yml b/docker-compose.yml index f0709f3..efcbc53 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,7 @@ services: network_mode: "host" image: packmate-app:v1 command: [ - "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", + "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000", "-jar", "/app/app.jar", "--spring.datasource.url=jdbc:postgresql://127.0.0.1:65001/$${DB_NAME}", "--spring.datasource.username=$${DB_USER}", "--spring.datasource.password=$${DB_PASSWORD}", "--capture-mode=$${MODE}", "--pcap-file=$${PCAP_FILE}", diff --git a/src/main/java/ru/serega6531/packmate/configuration/ApplicationConfiguration.java b/src/main/java/ru/serega6531/packmate/configuration/ApplicationConfiguration.java index fcfcee9..cbec7ef 100644 --- a/src/main/java/ru/serega6531/packmate/configuration/ApplicationConfiguration.java +++ b/src/main/java/ru/serega6531/packmate/configuration/ApplicationConfiguration.java @@ -22,6 +22,7 @@ import ru.serega6531.packmate.pcap.LivePcapWorker; import ru.serega6531.packmate.pcap.PcapWorker; import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.StreamService; +import ru.serega6531.packmate.service.SubscriptionService; import java.net.UnknownHostException; @@ -48,6 +49,7 @@ public class ApplicationConfiguration extends WebSecurityConfigurerAdapter imple @Autowired public PcapWorker pcapWorker(ServicesService servicesService, StreamService streamService, + SubscriptionService subscriptionService, @Value("${local-ip}") String localIpString, @Value("${interface-name}") String interfaceName, @Value("${pcap-file}") String filename, @@ -55,7 +57,7 @@ public class ApplicationConfiguration extends WebSecurityConfigurerAdapter imple if(captureMode == CaptureMode.LIVE) { return new LivePcapWorker(servicesService, streamService, localIpString, interfaceName); } else { - return new FilePcapWorker(servicesService, streamService, localIpString, filename); + return new FilePcapWorker(servicesService, streamService, subscriptionService, localIpString, filename); } } 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 1d44fda..d757866 100644 --- a/src/main/java/ru/serega6531/packmate/model/enums/SubscriptionMessageType.java +++ b/src/main/java/ru/serega6531/packmate/model/enums/SubscriptionMessageType.java @@ -1,5 +1,9 @@ package ru.serega6531.packmate.model.enums; public enum SubscriptionMessageType { - SAVE_SERVICE, SAVE_PATTERN, DELETE_SERVICE, DELETE_PATTERN, NEW_STREAM, COUNTERS_UPDATE + SAVE_SERVICE, SAVE_PATTERN, + DELETE_SERVICE, DELETE_PATTERN, + NEW_STREAM, + COUNTERS_UPDATE, + PCAP_STARTED, PCAP_STOPPED } diff --git a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java index f74fea2..6276cb0 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java @@ -7,8 +7,11 @@ import org.pcap4j.core.PcapNativeException; import org.pcap4j.core.Pcaps; import org.pcap4j.packet.Packet; import ru.serega6531.packmate.model.enums.Protocol; +import ru.serega6531.packmate.model.enums.SubscriptionMessageType; +import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.StreamService; +import ru.serega6531.packmate.service.SubscriptionService; import java.io.EOFException; import java.io.File; @@ -17,13 +20,16 @@ import java.net.UnknownHostException; @Slf4j public class FilePcapWorker extends AbstractPcapWorker { + private final SubscriptionService subscriptionService; private final File file; public FilePcapWorker(ServicesService servicesService, StreamService streamService, + SubscriptionService subscriptionService, String localIpString, String filename) throws UnknownHostException { super(servicesService, streamService, localIpString); + this.subscriptionService = subscriptionService; file = new File(filename); if(!file.exists()) { @@ -67,5 +73,7 @@ public class FilePcapWorker extends AbstractPcapWorker { closeAllStreams(Protocol.TCP); closeAllStreams(Protocol.UDP); + + subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.PCAP_STOPPED, null)); } } diff --git a/src/main/java/ru/serega6531/packmate/service/PcapService.java b/src/main/java/ru/serega6531/packmate/service/PcapService.java index b503bd3..dacb64e 100644 --- a/src/main/java/ru/serega6531/packmate/service/PcapService.java +++ b/src/main/java/ru/serega6531/packmate/service/PcapService.java @@ -4,6 +4,8 @@ import lombok.Getter; import org.pcap4j.core.PcapNativeException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import ru.serega6531.packmate.model.enums.SubscriptionMessageType; +import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.pcap.PcapWorker; @Service @@ -12,16 +14,19 @@ public class PcapService { @Getter private boolean started = false; + private final SubscriptionService subscriptionService; private final PcapWorker worker; @Autowired - public PcapService(PcapWorker worker) { + public PcapService(SubscriptionService subscriptionService, PcapWorker worker) { + this.subscriptionService = subscriptionService; this.worker = worker; } public synchronized void start() throws PcapNativeException { if(!started) { started = true; + subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.PCAP_STARTED, null)); worker.start(); } } diff --git a/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java b/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java index 207a978..c4092f0 100644 --- a/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java +++ b/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java @@ -2,6 +2,7 @@ package ru.serega6531.packmate.service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -39,10 +40,15 @@ public class SubscriptionService { log.info("User unsubscribed: {}", Objects.requireNonNull(session.getRemoteAddress()).getHostName()); } - void broadcast(SubscriptionMessage message) { + /** + * Вызов потокобезопасный + */ + @SneakyThrows + public void broadcast(SubscriptionMessage message) { + final TextMessage messageJson = objectToTextMessage(message); subscribers.forEach(s -> { try { - s.sendMessage(objectToTextMessage(message)); + s.sendMessage(messageJson); } catch (IOException | SockJsTransportFailureException e) { log.warn("WS", e); } From b8967f548683e3f95ac7faced00702e457563747 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Tue, 7 Apr 2020 00:51:08 +0300 Subject: [PATCH 5/8] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BB=D0=B0=D0=B4=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index efcbc53..f0709f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,7 @@ services: network_mode: "host" image: packmate-app:v1 command: [ - "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000", + "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", "-jar", "/app/app.jar", "--spring.datasource.url=jdbc:postgresql://127.0.0.1:65001/$${DB_NAME}", "--spring.datasource.username=$${DB_USER}", "--spring.datasource.password=$${DB_PASSWORD}", "--capture-mode=$${MODE}", "--pcap-file=$${PCAP_FILE}", From d35046b2a6dd407528fdd3ed11ad04c1c79cff4f Mon Sep 17 00:00:00 2001 From: serega6531 Date: Tue, 7 Apr 2020 15:57:18 +0300 Subject: [PATCH 6/8] =?UTF-8?q?=D0=91=D0=B0=D0=B3=D1=84=D0=B8=D0=BA=D1=81?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/serega6531/packmate/model/Stream.java | 1 + .../java/ru/serega6531/packmate/pcap/FilePcapWorker.java | 1 + .../ru/serega6531/packmate/service/PatternService.java | 2 +- .../ru/serega6531/packmate/service/ServicesService.java | 2 +- .../ru/serega6531/packmate/service/StreamOptimizer.java | 8 ++++++-- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/serega6531/packmate/model/Stream.java b/src/main/java/ru/serega6531/packmate/model/Stream.java index 2524d97..3023d2f 100644 --- a/src/main/java/ru/serega6531/packmate/model/Stream.java +++ b/src/main/java/ru/serega6531/packmate/model/Stream.java @@ -35,6 +35,7 @@ public class Stream { @OneToMany(mappedBy = "stream", cascade = CascadeType.ALL) @JsonIgnore + @OrderBy("id") private List packets; private long startTimestamp; diff --git a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java index 6276cb0..8bc28a7 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/FilePcapWorker.java @@ -42,6 +42,7 @@ public class FilePcapWorker extends AbstractPcapWorker { @SneakyThrows @Override public void start() { + log.info("Using file " + file.getAbsolutePath()); pcap = Pcaps.openOffline(file.getAbsolutePath()); loopExecutorService.execute(this::runScan); } diff --git a/src/main/java/ru/serega6531/packmate/service/PatternService.java b/src/main/java/ru/serega6531/packmate/service/PatternService.java index 46974b9..dc5579e 100644 --- a/src/main/java/ru/serega6531/packmate/service/PatternService.java +++ b/src/main/java/ru/serega6531/packmate/service/PatternService.java @@ -83,7 +83,7 @@ public class PatternService { final Pattern saved = repository.save(pattern); 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, saved)); return saved; } diff --git a/src/main/java/ru/serega6531/packmate/service/ServicesService.java b/src/main/java/ru/serega6531/packmate/service/ServicesService.java index 66f8142..4eed16d 100644 --- a/src/main/java/ru/serega6531/packmate/service/ServicesService.java +++ b/src/main/java/ru/serega6531/packmate/service/ServicesService.java @@ -66,7 +66,7 @@ public class ServicesService { } public CtfService save(CtfService service) { - log.info("Added or edited service {} at port {}", service.getName(), service.getPort()); + log.info("Added or edited service '{}' at port {}", service.getName(), service.getPort()); final CtfService saved = repository.save(service); services.put(saved.getPort(), saved); subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.SAVE_SERVICE, saved)); diff --git a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java index 7050fc8..21eb5e6 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java @@ -122,8 +122,12 @@ public class StreamOptimizer { } if (httpStarted) { - content = URLDecoder.decode(content, StandardCharsets.UTF_8.toString()); - packet.setContent(content.getBytes()); + try { + content = URLDecoder.decode(content, StandardCharsets.UTF_8.toString()); + packet.setContent(content.getBytes()); + } catch (IllegalArgumentException e) { + log.warn("urldecode", e); + } } } else { httpStarted = false; From 1c397db4751a18e2fa2db2cdb12e5e4b8330fb24 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Tue, 7 Apr 2020 23:19:56 +0300 Subject: [PATCH 7/8] =?UTF-8?q?=D0=92=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20postgres,=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=B8=D0=BD=D0=B4?= =?UTF-8?q?=D0=B5=D0=BA=D1=81=20=D0=BD=D0=B0=20packet.stream=5Fid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 3 ++- .gitignore | 1 + docker-compose.yml | 2 ++ src/main/java/ru/serega6531/packmate/model/Packet.java | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index b194fa0..cbf065e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,4 +4,5 @@ screenshots .* docker-compose.yml Dockerfile_* -README* \ No newline at end of file +docker/postgres_data +README* diff --git a/.gitignore b/.gitignore index 985e68d..c34419c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ src/main/resources/static/* *.pcap +docker/postgres_data HELP.md .gradle diff --git a/docker-compose.yml b/docker-compose.yml index f0709f3..58f074e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -41,6 +41,8 @@ services: POSTGRES_DB: ${PACKMATE_DB_NAME:-packmate} env_file: - .env + volumes: + - "./docker/postgres_data:/var/lib/postgresql/data" network_mode: "host" image: packmate-db:v1 restart: unless-stopped diff --git a/src/main/java/ru/serega6531/packmate/model/Packet.java b/src/main/java/ru/serega6531/packmate/model/Packet.java index b0a6f7b..77af081 100644 --- a/src/main/java/ru/serega6531/packmate/model/Packet.java +++ b/src/main/java/ru/serega6531/packmate/model/Packet.java @@ -24,6 +24,7 @@ import java.util.Set; @NoArgsConstructor @AllArgsConstructor @Builder +@Table(indexes = { @Index(name = "stream_id_index", columnList = "stream_id") }) public class Packet { @Id From 4e0cfd14470fe51d2636ed5bb945ee0bdde92627 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Fri, 10 Apr 2020 21:56:45 +0300 Subject: [PATCH 8/8] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=84=D1=80=D0=BE=D0=BD=D1=82=D0=B5=D0=BD=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- README_EN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 512a313..67047e9 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ git submodule update --init --recursive сетевой интерфейс хоста, его название указывается переменной окружения (об этом ниже). `packmate-db` настроен на прослушивание порта 65001 с локальным IP. -При этом файлы БД не монтируются как volume, поэтому при пересоздании контейнера все стримы теряются. +Файлы БД сохраняются в ./docker/postgres_data, поэтому для обнуления базы нужно удалить эту папку. ### Настройка Программа берет основные настройки из переменных окружения, поэтому для удобства diff --git a/README_EN.md b/README_EN.md index 5f8b3bf..19b0c06 100644 --- a/README_EN.md +++ b/README_EN.md @@ -42,7 +42,7 @@ git submodule update --init --recursive This program uses Docker and docker-compose. `packmate-db` will listen to port 65001 at localhost. -Database files do not mount as volume, so upon container recreation, all data will be lost. +Database files are saved in ./docker/postgres_data, so to reset database you have to delete that directory. ### Settings This program retrieves settings from environment variables,