From 573142deeb95bc79faa731f9f8343c6e67fedb5e Mon Sep 17 00:00:00 2001 From: serega6531 Date: Mon, 16 Mar 2020 23:52:16 +0300 Subject: [PATCH 01/12] =?UTF-8?q?=D0=A1=D0=BE=D0=BE=D0=B1=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=20=D0=B0=D0=BD=D0=B3=D0=BB?= =?UTF-8?q?=D0=B8=D0=B9=D1=81=D0=BA=D0=B8=D0=B9,=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BC=D0=B0=D1=82=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- README_EN.md | 38 +++++++++---------- .../ru/serega6531/packmate/PcapWorker.java | 6 +-- .../packmate/TimeoutStreamsSaver.java | 4 +- .../packmate/service/PatternService.java | 4 +- .../packmate/service/ServicesService.java | 4 +- .../packmate/service/StreamOptimizer.java | 4 +- .../packmate/service/StreamService.java | 6 +-- .../service/StreamSubscriptionService.java | 4 +- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index bc2433d..11002dc 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,10 @@ ## Клонирование Поскольку этот репозиторий содержит фронтенд как git submodule, его необходимо клонировать так: ```bash -git clone --recurse-submodules https://gitlab.com/binarybears_ctf/Packmate.git +git clone --recurse-submodules https://gitlab.com/packmate/Packmate.git # Или, на старых версиях git -git clone --recursive https://gitlab.com/binarybears_ctf/Packmate.git +git clone --recursive https://gitlab.com/packmate/Packmate.git ``` Если репозиторий уже был склонирован без подмодулей, необходимо выполнить: diff --git a/README_EN.md b/README_EN.md index 8838e07..06eb927 100644 --- a/README_EN.md +++ b/README_EN.md @@ -14,7 +14,7 @@ Advanced network traffic flow analyzer for A/D CTFs. * Binary substring * Can make certain streams favorite and show only favorite streams * Supports several simultaneous services, can show streams for a specific service or pattern -* Allows to navigate streams using shortcuts +* Allows navigating streams using shortcuts * Has the option to copy packet content in the required format * Can concatenate adjacent packets * Can urldecode text automatically @@ -22,12 +22,12 @@ Advanced network traffic flow analyzer for A/D CTFs. ![Main window](screenshots/Screenshot.png) ## Cloning -As this repository contains frontend part as git submodule, it has to be cloned like this: +As this repository contains frontend part as a git submodule, it has to be cloned like this: ```bash -git clone --recurse-submodules https://gitlab.com/binarybears_ctf/Packmate.git +git clone --recurse-submodules https://gitlab.com/packmate/Packmate.git # Or if you have older git -git clone --recursive https://gitlab.com/binarybears_ctf/Packmate.git +git clone --recursive https://gitlab.com/packmate/Packmate.git ``` If the repository was already cloned without submodule, just run: @@ -39,23 +39,23 @@ git submodule update --init --recursive ## Preparation This program uses Docker and docker-compose. -`packmate-db` will listen port 65001 at localhost. -Database files do not mount as volume, so upon container recreation all data will be lost. +`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. ### Settings -This program retreives settings from environment variables, -so it would be convenient to create env file; +This program retrieves settings from environment variables, +so it would be convenient to create an env file; 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 said interface to tell incoming packets from outgoing PACKMATE_LOCAL_IP=192.168.1.124 -# Username for web interface +# Username for the web interface PACKMATE_WEB_LOGIN=SomeUser -# Password for web interface +# Password for the web interface PACKMATE_WEB_PASSWORD=SomeSecurePassword ``` @@ -67,8 +67,8 @@ sudo docker-compose up --build -d If everything went fine, Packmate will be available on port `65000` from any host -### Accessing web interface -When you open web interface for the first time, you will be asked for login and password +### Accessing the web interface +When you open a web interface for the first time, you will be asked for a login and password you specified in the env file. After entering the credentials, open the settings by clicking on the cogs in the top right corner and enter login and password again. @@ -76,18 +76,18 @@ in the top right corner and enter login and password again. ![Settings](screenshots/Screenshot_Settings.png) All settings are saved in the local storage and will be -lost only upon changing server ip or port. +lost only upon changing server IP or port. ## Usage -First of all you should create game services. +First of all, you should create game services. To do that click `+` in the navbar, -then fill in service name, port and optimization to perform. +then fill in the service name, port, and optimization to perform. -System will start automatically capture streams and show them in a sidebar. -Click at stream to view a list of packets; +The system will start automatically capture streams and show them in a sidebar. +Click at a stream to view a list of packets; you can click a button in the sidebar to switch between binary and text views. -For a simple monitoring of flags there is a system of patterns. +For simple monitoring of flags, there is a system of patterns. To create a pattern open `Patterns` dropdown menu, press `+`, then specify the type of pattern, the pattern itself, highlight color and other things. diff --git a/src/main/java/ru/serega6531/packmate/PcapWorker.java b/src/main/java/ru/serega6531/packmate/PcapWorker.java index 5a981ca..e19744d 100644 --- a/src/main/java/ru/serega6531/packmate/PcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/PcapWorker.java @@ -140,7 +140,7 @@ public class PcapWorker implements PacketListener { UnfinishedStream stream = addNewPacket(sourceIp, destIp, time, sourcePort, destPort, ttl, content, Protocol.TCP); if (log.isDebugEnabled()) { - log.debug("tcp {} {}:{} -> {}:{}, номер пакета {}", + log.debug("tcp {} {}:{} -> {}:{}, packet number {}", serviceOptional.get(), sourceIpString, sourcePort, destIpString, destPort, unfinishedTcpStreams.get(stream).size()); } @@ -179,7 +179,7 @@ public class PcapWorker implements PacketListener { UnfinishedStream stream = addNewPacket(sourceIp, destIp, time, sourcePort, destPort, ttl, content, Protocol.UDP); if (log.isDebugEnabled()) { - log.debug("udp {} {}:{} -> {}:{}, номер пакета {}", + log.debug("udp {} {}:{} -> {}:{}, packet number {}", serviceOptional.get(), sourceIpString, sourcePort, destIpString, destPort, unfinishedUdpStreams.get(stream).size()); } @@ -207,7 +207,7 @@ public class PcapWorker implements PacketListener { final var streams = (protocol == Protocol.TCP) ? this.unfinishedTcpStreams : this.unfinishedUdpStreams; if (!streams.containsKey(stream)) { - log.debug("Начат новый стрим"); + log.debug("New stream started"); } streams.put(stream, packet); diff --git a/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java b/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java index b924b68..68acaab 100644 --- a/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java +++ b/src/main/java/ru/serega6531/packmate/TimeoutStreamsSaver.java @@ -30,12 +30,12 @@ public class TimeoutStreamsSaver { public void saveStreams() { int streamsClosed = pcapWorker.closeTimeoutStreams(Protocol.UDP, udpStreamTimeoutMillis); if (streamsClosed > 0) { - log.info("Закрыто {} udp стримов", streamsClosed); + log.info("{} udp streams closed", streamsClosed); } streamsClosed = pcapWorker.closeTimeoutStreams(Protocol.TCP, tcpStreamTimeoutMillis); if (streamsClosed > 0) { - log.info("Закрыто {} tcp стримов", streamsClosed); + log.info("{} tcp streams closed", streamsClosed); } } diff --git a/src/main/java/ru/serega6531/packmate/service/PatternService.java b/src/main/java/ru/serega6531/packmate/service/PatternService.java index 8983c50..442e430 100644 --- a/src/main/java/ru/serega6531/packmate/service/PatternService.java +++ b/src/main/java/ru/serega6531/packmate/service/PatternService.java @@ -57,7 +57,7 @@ public class PatternService { final Optional optional = repository.findById(id); if (optional.isPresent()) { final Pattern pattern = optional.get(); - log.info("Удален паттерн {} со значением {}", pattern.getName(), pattern.getValue()); + log.info("Removed pattern {} with value {}", pattern.getName(), pattern.getValue()); for (Stream stream : pattern.getMatchedStreams()) { stream.getFoundPatterns().remove(pattern); @@ -83,7 +83,7 @@ public class PatternService { final Pattern saved = repository.save(pattern); patterns.put(saved.getId(), saved); - log.info("Добавлен новый паттерн {} со значением {}", 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 ee93035..34e91b2 100644 --- a/src/main/java/ru/serega6531/packmate/service/ServicesService.java +++ b/src/main/java/ru/serega6531/packmate/service/ServicesService.java @@ -59,14 +59,14 @@ public class ServicesService { } public void deleteByPort(int port) { - log.info("Удален сервис на порту {}", port); + log.info("Removed service at port {}", port); services.remove(port); repository.deleteById(port); subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.DELETE_SERVICE, port)); } public CtfService save(CtfService service) { - log.info("Добавлен или изменен сервис {} на порту {}", 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 3374555..1b0a7c4 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java @@ -209,7 +209,7 @@ public class StreamOptimizer { IOUtils.copy(gzipStream, out); byte[] newContent = ArrayUtils.addAll(httpHeader, out.toByteArray()); - log.debug("Разархивирован gzip: {} -> {} байт", gzipBytes.length, out.size()); + log.debug("GZIP decompressed: {} -> {} bytes", gzipBytes.length, out.size()); return Packet.builder() .incoming(false) @@ -218,7 +218,7 @@ public class StreamOptimizer { .content(newContent) .build(); } catch (ZipException e) { - log.warn("Не удалось разархивировать gzip, оставляем как есть", e); + log.warn("Failed to decompress gzip, leaving as it is", e); } catch (IOException e) { log.error("decompress gzip", e); } diff --git a/src/main/java/ru/serega6531/packmate/service/StreamService.java b/src/main/java/ru/serega6531/packmate/service/StreamService.java index 96b2e41..9b1c2dd 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamService.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamService.java @@ -62,7 +62,7 @@ public class StreamService { ); if (serviceOptional.isEmpty()) { - log.warn("Не удалось сохранить стрим: сервиса на порту {} или {} не существует", + log.warn("Failed to save the stream: service at port {} or {} does not exist", unfinishedStream.getFirstPort(), unfinishedStream.getSecondPort()); return false; } @@ -72,7 +72,7 @@ public class StreamService { packets.removeIf(packet -> packet.getContent().length == 0); if (packets.isEmpty()) { - log.debug("Стрим состоит только из пустых пакетов и не будет сохранен"); + log.debug("Stream consists only of empty packets and will not be saved"); return false; } } @@ -149,7 +149,7 @@ public class StreamService { Stream saved; if (stream.getId() == null) { saved = repository.save(stream); - log.debug("Создан стрим с id {}", saved.getId()); + log.debug("Saved stream with id {}", saved.getId()); } else { saved = repository.save(stream); } diff --git a/src/main/java/ru/serega6531/packmate/service/StreamSubscriptionService.java b/src/main/java/ru/serega6531/packmate/service/StreamSubscriptionService.java index 94db5b5..218d810 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamSubscriptionService.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamSubscriptionService.java @@ -31,12 +31,12 @@ public class StreamSubscriptionService { public void addSubscriber(WebSocketSession session) { subscribers.add(session); - log.info("Подписан пользователь {}", Objects.requireNonNull(session.getRemoteAddress()).getHostName()); + log.info("User subscribed: {}", Objects.requireNonNull(session.getRemoteAddress()).getHostName()); } public void removeSubscriber(WebSocketSession session) { subscribers.remove(session); - log.info("Отписан пользователь {}", Objects.requireNonNull(session.getRemoteAddress()).getHostName()); + log.info("User unsubscribed {}", Objects.requireNonNull(session.getRemoteAddress()).getHostName()); } void broadcast(SubscriptionMessage message) { From 658e3255eb50311b41166b8e122dc3f7b5d3d70a Mon Sep 17 00:00:00 2001 From: serega6531 Date: Tue, 17 Mar 2020 00:15:10 +0300 Subject: [PATCH 02/12] =?UTF-8?q?=D0=A0=D0=B5=D0=BE=D1=80=D0=B3=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D1=84=D0=B0=D0=B9?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 4 ++-- Dockerfile_app => docker/Dockerfile_app | 0 Dockerfile_db => docker/Dockerfile_db | 4 ++-- postgresql.conf => docker/postgresql.conf | 0 update_db_config.sh => docker/update_db_config.sh | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename Dockerfile_app => docker/Dockerfile_app (100%) rename Dockerfile_db => docker/Dockerfile_db (62%) rename postgresql.conf => docker/postgresql.conf (100%) rename update_db_config.sh => docker/update_db_config.sh (100%) diff --git a/docker-compose.yml b/docker-compose.yml index 4b279b5..c969e43 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: container_name: packmate-app build: context: . - dockerfile: Dockerfile_app + dockerfile: docker/Dockerfile_app network_mode: "host" image: packmate-app:v1 command: [ @@ -31,7 +31,7 @@ services: container_name: packmate-db build: context: . - dockerfile: Dockerfile_db + dockerfile: docker/Dockerfile_db args: POSTGRES_USER: ${PACKMATE_DB_USER:-packmate} POSTGRES_PASSWORD: ${PACKMATE_DB_PASSWORD:-K604YnL3G1hp2RDkCZNjGpxbyNpNHTRb} diff --git a/Dockerfile_app b/docker/Dockerfile_app similarity index 100% rename from Dockerfile_app rename to docker/Dockerfile_app diff --git a/Dockerfile_db b/docker/Dockerfile_db similarity index 62% rename from Dockerfile_db rename to docker/Dockerfile_db index e45f946..00b4865 100644 --- a/Dockerfile_db +++ b/docker/Dockerfile_db @@ -8,7 +8,7 @@ ENV POSTGRES_USER ${POSTGRES_USER} ENV POSTGRES_PASSWORD ${POSTGRES_PASSWORD} ENV POSTGRES_DB ${POSTGRES_DB} -COPY postgresql.conf /tmp/postgresql.conf -COPY update_db_config.sh /docker-entrypoint-initdb.d/_update_db_config.sh +COPY docker/postgresql.conf /tmp/postgresql.conf +COPY docker/update_db_config.sh /docker-entrypoint-initdb.d/_update_db_config.sh EXPOSE 65001:65001 diff --git a/postgresql.conf b/docker/postgresql.conf similarity index 100% rename from postgresql.conf rename to docker/postgresql.conf diff --git a/update_db_config.sh b/docker/update_db_config.sh similarity index 100% rename from update_db_config.sh rename to docker/update_db_config.sh From b3cc0de450c7efb558e5bf51074ea160c80eb7ba Mon Sep 17 00:00:00 2001 From: serega6531 Date: Tue, 17 Mar 2020 01:21:40 +0300 Subject: [PATCH 03/12] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=B4=20=D0=BE=D1=82=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BA=D1=83=20=D1=81=D1=87=D0=B5=D1=82=D1=87?= =?UTF-8?q?=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../serega6531/packmate/WebSocketHandler.java | 6 ++-- .../packmate/model/pojo/Counter.java | 18 ++++++++++ .../packmate/service/CountingService.java | 36 +++++++++++++++++++ .../packmate/service/PatternService.java | 4 +-- .../packmate/service/ServicesService.java | 4 +-- .../packmate/service/StreamService.java | 9 +++-- ...nService.java => SubscriptionService.java} | 4 +-- 7 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 src/main/java/ru/serega6531/packmate/model/pojo/Counter.java create mode 100644 src/main/java/ru/serega6531/packmate/service/CountingService.java rename src/main/java/ru/serega6531/packmate/service/{StreamSubscriptionService.java => SubscriptionService.java} (94%) diff --git a/src/main/java/ru/serega6531/packmate/WebSocketHandler.java b/src/main/java/ru/serega6531/packmate/WebSocketHandler.java index f2c93e9..47d362a 100644 --- a/src/main/java/ru/serega6531/packmate/WebSocketHandler.java +++ b/src/main/java/ru/serega6531/packmate/WebSocketHandler.java @@ -5,15 +5,15 @@ import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; -import ru.serega6531.packmate.service.StreamSubscriptionService; +import ru.serega6531.packmate.service.SubscriptionService; @Component public class WebSocketHandler extends TextWebSocketHandler { - private final StreamSubscriptionService subscriptionService; + private final SubscriptionService subscriptionService; @Autowired - public WebSocketHandler(StreamSubscriptionService subscriptionService) { + public WebSocketHandler(SubscriptionService subscriptionService) { this.subscriptionService = subscriptionService; } diff --git a/src/main/java/ru/serega6531/packmate/model/pojo/Counter.java b/src/main/java/ru/serega6531/packmate/model/pojo/Counter.java new file mode 100644 index 0000000..4b601da --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/model/pojo/Counter.java @@ -0,0 +1,18 @@ +package ru.serega6531.packmate.model.pojo; + +import lombok.Getter; + +@Getter +public class Counter { + + private int value = 0; + + public void increment() { + value++; + } + + public void increment(int num) { + value += num; + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/CountingService.java b/src/main/java/ru/serega6531/packmate/service/CountingService.java new file mode 100644 index 0000000..f899e92 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/CountingService.java @@ -0,0 +1,36 @@ +package ru.serega6531.packmate.service; + +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import ru.serega6531.packmate.model.pojo.Counter; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class CountingService { + + private Map servicesPackets = new HashMap<>(); + private Map servicesStreams = new HashMap<>(); + + private Counter totalPackets = new Counter(); + private Counter totalStreams = new Counter(); + + void countStream(int serviceId, int packets) { + getCounter(servicesPackets, serviceId).increment(packets); + getCounter(servicesStreams, serviceId).increment(); + + totalPackets.increment(packets); + totalStreams.increment(); + } + + @Scheduled(cron = "0 * * ? * *") + public void sendCounters() { + //TODO + } + + private Counter getCounter(Map counters, int serviceId) { + return counters.computeIfAbsent(serviceId, c -> new Counter()); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/PatternService.java b/src/main/java/ru/serega6531/packmate/service/PatternService.java index 442e430..46974b9 100644 --- a/src/main/java/ru/serega6531/packmate/service/PatternService.java +++ b/src/main/java/ru/serega6531/packmate/service/PatternService.java @@ -22,13 +22,13 @@ import java.util.stream.Collectors; public class PatternService { private final PatternRepository repository; - private final StreamSubscriptionService subscriptionService; + private final SubscriptionService subscriptionService; private final Map patterns = new HashMap<>(); @Autowired public PatternService(PatternRepository repository, - StreamSubscriptionService subscriptionService) { + SubscriptionService subscriptionService) { this.repository = repository; this.subscriptionService = subscriptionService; diff --git a/src/main/java/ru/serega6531/packmate/service/ServicesService.java b/src/main/java/ru/serega6531/packmate/service/ServicesService.java index 34e91b2..66f8142 100644 --- a/src/main/java/ru/serega6531/packmate/service/ServicesService.java +++ b/src/main/java/ru/serega6531/packmate/service/ServicesService.java @@ -22,7 +22,7 @@ import java.util.Optional; public class ServicesService { private final ServiceRepository repository; - private final StreamSubscriptionService subscriptionService; + private final SubscriptionService subscriptionService; private final InetAddress localIp; @@ -30,7 +30,7 @@ public class ServicesService { @Autowired public ServicesService(ServiceRepository repository, - StreamSubscriptionService subscriptionService, + SubscriptionService subscriptionService, @Value("${local-ip}") String localIpString) throws UnknownHostException { this.repository = repository; this.subscriptionService = subscriptionService; diff --git a/src/main/java/ru/serega6531/packmate/service/StreamService.java b/src/main/java/ru/serega6531/packmate/service/StreamService.java index 9b1c2dd..19afa74 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamService.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamService.java @@ -30,7 +30,8 @@ public class StreamService { private final StreamRepository repository; private final PatternService patternService; private final ServicesService servicesService; - private final StreamSubscriptionService subscriptionService; + private final CountingService countingService; + private final SubscriptionService subscriptionService; private final boolean ignoreEmptyPackets; @@ -40,11 +41,13 @@ public class StreamService { public StreamService(StreamRepository repository, PatternService patternService, ServicesService servicesService, - StreamSubscriptionService subscriptionService, + CountingService countingService, + SubscriptionService subscriptionService, @Value("${ignore-empty-packets}") boolean ignoreEmptyPackets) { this.repository = repository; this.patternService = patternService; this.servicesService = servicesService; + this.countingService = countingService; this.subscriptionService = subscriptionService; this.ignoreEmptyPackets = ignoreEmptyPackets; } @@ -88,6 +91,8 @@ public class StreamService { stream.setEndTimestamp(packets.get(packets.size() - 1).getTimestamp()); stream.setService(service.getPort()); + countingService.countStream(service.getPort(), packets.size()); + new StreamOptimizer(service, packets).optimizeStream(); processUserAgent(packets, stream); diff --git a/src/main/java/ru/serega6531/packmate/service/StreamSubscriptionService.java b/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java similarity index 94% rename from src/main/java/ru/serega6531/packmate/service/StreamSubscriptionService.java rename to src/main/java/ru/serega6531/packmate/service/SubscriptionService.java index 218d810..f140f78 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamSubscriptionService.java +++ b/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java @@ -18,14 +18,14 @@ import java.util.Objects; @Service @Slf4j -public class StreamSubscriptionService { +public class SubscriptionService { private final List subscribers = Collections.synchronizedList(new ArrayList<>()); private final ObjectMapper mapper; @Autowired - public StreamSubscriptionService(ObjectMapper mapper) { + public SubscriptionService(ObjectMapper mapper) { this.mapper = mapper; } From 2611c7685e55fdc6129b24c8373e85dfa97f8fa4 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Tue, 17 Mar 2020 15:40:17 +0300 Subject: [PATCH 04/12] =?UTF-8?q?=D0=9E=D1=82=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=81=D1=87=D0=B5=D1=82=D1=87=D0=B8=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/enums/SubscriptionMessageType.java | 2 +- .../packmate/model/pojo/CountersHolder.java | 23 +++++++++++++++ .../packmate/service/CountingService.java | 29 ++++++++++++++++++- .../packmate/service/SubscriptionService.java | 2 +- 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ru/serega6531/packmate/model/pojo/CountersHolder.java 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 af46d09..1d44fda 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,5 @@ package ru.serega6531.packmate.model.enums; public enum SubscriptionMessageType { - SAVE_SERVICE, SAVE_PATTERN, DELETE_SERVICE, DELETE_PATTERN, NEW_STREAM + SAVE_SERVICE, SAVE_PATTERN, DELETE_SERVICE, DELETE_PATTERN, NEW_STREAM, COUNTERS_UPDATE } diff --git a/src/main/java/ru/serega6531/packmate/model/pojo/CountersHolder.java b/src/main/java/ru/serega6531/packmate/model/pojo/CountersHolder.java new file mode 100644 index 0000000..b39bb8e --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/model/pojo/CountersHolder.java @@ -0,0 +1,23 @@ +package ru.serega6531.packmate.model.pojo; + +import lombok.Getter; + +import java.util.Map; + +@Getter +public class CountersHolder { + + private Map servicesPackets; + private Map servicesStreams; + + private int totalPackets; + private int totalStreams; + + public CountersHolder(Map servicesPackets, Map servicesStreams, + int totalPackets, int totalStreams) { + this.servicesPackets = servicesPackets; + this.servicesStreams = servicesStreams; + this.totalPackets = totalPackets; + this.totalStreams = totalStreams; + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/CountingService.java b/src/main/java/ru/serega6531/packmate/service/CountingService.java index f899e92..a23f8f1 100644 --- a/src/main/java/ru/serega6531/packmate/service/CountingService.java +++ b/src/main/java/ru/serega6531/packmate/service/CountingService.java @@ -1,21 +1,33 @@ package ru.serega6531.packmate.service; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import ru.serega6531.packmate.model.enums.SubscriptionMessageType; import ru.serega6531.packmate.model.pojo.Counter; +import ru.serega6531.packmate.model.pojo.CountersHolder; +import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; @Service public class CountingService { + private final SubscriptionService subscriptionService; + private Map servicesPackets = new HashMap<>(); private Map servicesStreams = new HashMap<>(); private Counter totalPackets = new Counter(); private Counter totalStreams = new Counter(); + @Autowired + public CountingService(SubscriptionService subscriptionService) { + this.subscriptionService = subscriptionService; + } + void countStream(int serviceId, int packets) { getCounter(servicesPackets, serviceId).increment(packets); getCounter(servicesStreams, serviceId).increment(); @@ -26,7 +38,22 @@ public class CountingService { @Scheduled(cron = "0 * * ? * *") public void sendCounters() { - //TODO + subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.COUNTERS_UPDATE, + new CountersHolder( + toIntegerMap(servicesPackets), toIntegerMap(servicesStreams), + totalPackets.getValue(), totalStreams.getValue()))); + + servicesPackets.clear(); + servicesStreams.clear(); + totalPackets = new Counter(); + totalStreams = new Counter(); + } + + private Map toIntegerMap(Map map) { + return map.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + ent -> ent.getValue().getValue())); } private Counter getCounter(Map counters, int serviceId) { diff --git a/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java b/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java index f140f78..207a978 100644 --- a/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java +++ b/src/main/java/ru/serega6531/packmate/service/SubscriptionService.java @@ -36,7 +36,7 @@ public class SubscriptionService { public void removeSubscriber(WebSocketSession session) { subscribers.remove(session); - log.info("User unsubscribed {}", Objects.requireNonNull(session.getRemoteAddress()).getHostName()); + log.info("User unsubscribed: {}", Objects.requireNonNull(session.getRemoteAddress()).getHostName()); } void broadcast(SubscriptionMessage message) { From 373f97784aa61b4dda6490fa9a0dae60bcc5ec4b Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sat, 4 Apr 2020 01:20:42 +0300 Subject: [PATCH 05/12] =?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=80=D0=B0=D1=81=D0=BF=D0=B0=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=BE=D0=B9=20websocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 + gradle/wrapper/gradle-wrapper.properties | 2 +- .../serega6531/packmate/model/CtfService.java | 2 + .../packmate/service/StreamOptimizer.java | 172 ++++++++++++++++++ 4 files changed, 179 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 17babb3..586f0c6 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,9 @@ configurations { repositories { mavenCentral() + + // удалить после выхода стабильной версии Java-WebSocket + maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } dependencies { @@ -32,6 +35,7 @@ dependencies { compile 'org.pcap4j:pcap4j-core:1.8.2' compile 'org.pcap4j:pcap4j-packetfactory-static:1.8.2' compile group: 'com.google.guava', name: 'guava', version: '28.2-jre' + compile group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.5.0-SNAPSHOT' compileOnly 'org.projectlombok:lombok' runtimeOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a2bf131..a4b4429 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/ru/serega6531/packmate/model/CtfService.java b/src/main/java/ru/serega6531/packmate/model/CtfService.java index 01ddf6e..5eb5719 100644 --- a/src/main/java/ru/serega6531/packmate/model/CtfService.java +++ b/src/main/java/ru/serega6531/packmate/model/CtfService.java @@ -22,4 +22,6 @@ public class CtfService { private boolean mergeAdjacentPackets; + private boolean inflateWebSockets = true; //TODO + } \ No newline at end of file diff --git a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java index 1b0a7c4..6274a97 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java @@ -5,6 +5,13 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; +import org.java_websocket.drafts.Draft_6455; +import org.java_websocket.exceptions.InvalidDataException; +import org.java_websocket.exceptions.InvalidHandshakeException; +import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; +import org.java_websocket.framing.Framedata; +import org.java_websocket.handshake.HandshakeImpl1Client; +import org.java_websocket.handshake.HandshakeImpl1Server; import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.utils.Bytes; @@ -13,9 +20,12 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URLDecoder; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; +import java.util.regex.Matcher; +import java.util.stream.Collectors; import java.util.zip.GZIPInputStream; import java.util.zip.ZipException; @@ -28,6 +38,20 @@ public class StreamOptimizer { private static final byte[] GZIP_HEADER = {0x1f, (byte) 0x8b, 0x08}; + private static final java.util.regex.Pattern WEBSOCKET_KEY_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Key: (.+)\\r\\n"); + private static final java.util.regex.Pattern WEBSOCKET_EXTENSIONS_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Extensions?: (.+)\\r\\n"); + private static final java.util.regex.Pattern WEBSOCKET_VERSION_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Version: (\\d+)\\r\\n"); + private static final java.util.regex.Pattern WEBSOCKET_ACCEPT_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Accept: (.+)\\r\\n"); + + private static final String WEBSOCKET_EXTENSION_HEADER = "Sec-WebSocket-Extension: permessage-deflate"; + private static final String WEBSOCKET_EXTENSIONS_HEADER = "Sec-WebSocket-Extensions: permessage-deflate"; + private static final String WEBSOCKET_UPGRADE_HEADER = "Upgrade: websocket\r\n"; + private static final String WEBSOCKET_CONNECTION_HEADER = "Connection: Upgrade\r\n"; + /** * Вызвать для выполнения оптимизаций на переданном списке пакетов. */ @@ -40,6 +64,10 @@ public class StreamOptimizer { urldecodeRequests(); } + if (service.isInflateWebSockets()) { + inflateWebSocket(); + } + if (service.isMergeAdjacentPackets()) { mergeAdjacentPackets(); } @@ -226,4 +254,148 @@ public class StreamOptimizer { return null; } + private void inflateWebSocket() { + if (!new String(packets.get(0).getContent()).contains("HTTP/")) { + return; + } + + final List clientHandshakePackets = packets.stream() + .takeWhile(Packet::isIncoming) + .collect(Collectors.toList()); + + final String clientHandshake = getHandshake(clientHandshakePackets); + if (clientHandshake == null) { + return; + } + + final List serverHandshakePackets = packets.stream() + .skip(clientHandshakePackets.size()) + .takeWhile(p -> !p.isIncoming()) + .collect(Collectors.toList()); + + final String serverHandshake = getHandshake(serverHandshakePackets); + if (serverHandshake == null) { + return; + } + + HandshakeImpl1Server serverHandshakeImpl = fillServerHandshake(serverHandshake); + HandshakeImpl1Client clientHandshakeImpl = fillClientHandshake(clientHandshake); + + if (serverHandshakeImpl == null || clientHandshakeImpl == null) { + return; + } + + final List wsPackets = this.packets.subList( + clientHandshakePackets.size() + serverHandshakePackets.size(), + this.packets.size()); + + final byte[] wsContent = wsPackets.stream() + .map(Packet::getContent) + .reduce(ArrayUtils::addAll) + .orElse(null); + + if (wsContent == null) { + return; + } + + final ByteBuffer frame = ByteBuffer.wrap(wsContent); + Draft_6455 draft = new Draft_6455(new PerMessageDeflateExtension()); + + try { + draft.acceptHandshakeAsServer(clientHandshakeImpl); + draft.acceptHandshakeAsClient(clientHandshakeImpl, serverHandshakeImpl); + } catch (InvalidHandshakeException e) { + log.warn("WebSocket handshake", e); + return; + } + + try { + final List list = draft.translateFrame(frame); + log.info(list.toString()); + } catch (InvalidDataException e) { + log.warn("WebSocket data", e); + } + } + + private String getHandshake(final List packets) { + final String handshake = packets.stream() + .map(Packet::getContent) + .reduce(ArrayUtils::addAll) + .map(String::new) + .orElse(null); + + if (handshake == null || + !handshake.contains(WEBSOCKET_CONNECTION_HEADER) || + !handshake.contains(WEBSOCKET_UPGRADE_HEADER)) { + return null; + } + + if (!handshake.contains(WEBSOCKET_EXTENSION_HEADER) && + !handshake.contains(WEBSOCKET_EXTENSIONS_HEADER)) { + return null; + } + + return handshake; + } + + private HandshakeImpl1Client fillClientHandshake(String clientHandshake) { + Matcher matcher = WEBSOCKET_VERSION_PATTERN.matcher(clientHandshake); + if (!matcher.find()) { + return null; + } + String version = matcher.group(1); + + matcher = WEBSOCKET_KEY_PATTERN.matcher(clientHandshake); + if (!matcher.find()) { + return null; + } + String key = matcher.group(1); + + matcher = WEBSOCKET_EXTENSIONS_PATTERN.matcher(clientHandshake); + if (!matcher.find()) { + return null; + } + String extensions = matcher.group(1); + + HandshakeImpl1Client clientHandshakeImpl = new HandshakeImpl1Client(); + + clientHandshakeImpl.put("Upgrade", "websocket"); + clientHandshakeImpl.put("Connection", "Upgrade"); + clientHandshakeImpl.put("Sec-WebSocket-Version", version); + clientHandshakeImpl.put("Sec-WebSocket-Key", key); + clientHandshakeImpl.put("Sec-WebSocket-Extensions", extensions); + + return clientHandshakeImpl; + } + + private HandshakeImpl1Server fillServerHandshake(String serverHandshake) { + Matcher matcher = WEBSOCKET_VERSION_PATTERN.matcher(serverHandshake); + if (!matcher.find()) { + return null; + } + String version = matcher.group(1); + + matcher = WEBSOCKET_ACCEPT_PATTERN.matcher(serverHandshake); + if (!matcher.find()) { + return null; + } + String accept = matcher.group(1); + + matcher = WEBSOCKET_EXTENSIONS_PATTERN.matcher(serverHandshake); + if (!matcher.find()) { + return null; + } + String extensions = matcher.group(1); + + HandshakeImpl1Server serverHandshakeImpl = new HandshakeImpl1Server(); + + serverHandshakeImpl.put("Upgrade", "websocket"); + serverHandshakeImpl.put("Connection", "Upgrade"); + serverHandshakeImpl.put("Sec-WebSocket-Version", version); + serverHandshakeImpl.put("Sec-WebSocket-Accept", accept); + serverHandshakeImpl.put("Sec-WebSocket-Extensions", extensions); + + return serverHandshakeImpl; + } + } From e25e66d727cdb8ecf0c2096729c768b19fd4291c Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sat, 4 Apr 2020 22:53:29 +0300 Subject: [PATCH 06/12] =?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=80=D0=B0=D1=81=D0=BF=D0=B0=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=BE=D0=B9=20websocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/serega6531/packmate/model/Packet.java | 10 + .../packmate/service/StreamOptimizer.java | 181 ++------------ .../packmate/service/StreamService.java | 4 +- .../packmate/service/WebSocketsParser.java | 221 ++++++++++++++++++ .../packmate/StreamOptimizerTest.java | 10 +- 5 files changed, 252 insertions(+), 174 deletions(-) create mode 100644 src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java diff --git a/src/main/java/ru/serega6531/packmate/model/Packet.java b/src/main/java/ru/serega6531/packmate/model/Packet.java index cc60bd2..603202f 100644 --- a/src/main/java/ru/serega6531/packmate/model/Packet.java +++ b/src/main/java/ru/serega6531/packmate/model/Packet.java @@ -54,4 +54,14 @@ public class Packet { private byte[] content; + @Transient + @JsonIgnore + public String getContentString() { + return new String(content); + } + + public String toString() { + return "Packet(id=" + id + ", content=" + getContentString() + ")"; + } + } diff --git a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java index 6274a97..a161afe 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java @@ -5,13 +5,6 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; -import org.java_websocket.drafts.Draft_6455; -import org.java_websocket.exceptions.InvalidDataException; -import org.java_websocket.exceptions.InvalidHandshakeException; -import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; -import org.java_websocket.framing.Framedata; -import org.java_websocket.handshake.HandshakeImpl1Client; -import org.java_websocket.handshake.HandshakeImpl1Server; import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.utils.Bytes; @@ -20,12 +13,9 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URLDecoder; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; -import java.util.regex.Matcher; -import java.util.stream.Collectors; import java.util.zip.GZIPInputStream; import java.util.zip.ZipException; @@ -34,43 +24,31 @@ import java.util.zip.ZipException; public class StreamOptimizer { private final CtfService service; - private final List packets; + private List packets; private static final byte[] GZIP_HEADER = {0x1f, (byte) 0x8b, 0x08}; - private static final java.util.regex.Pattern WEBSOCKET_KEY_PATTERN = - java.util.regex.Pattern.compile("Sec-WebSocket-Key: (.+)\\r\\n"); - private static final java.util.regex.Pattern WEBSOCKET_EXTENSIONS_PATTERN = - java.util.regex.Pattern.compile("Sec-WebSocket-Extensions?: (.+)\\r\\n"); - private static final java.util.regex.Pattern WEBSOCKET_VERSION_PATTERN = - java.util.regex.Pattern.compile("Sec-WebSocket-Version: (\\d+)\\r\\n"); - private static final java.util.regex.Pattern WEBSOCKET_ACCEPT_PATTERN = - java.util.regex.Pattern.compile("Sec-WebSocket-Accept: (.+)\\r\\n"); - - private static final String WEBSOCKET_EXTENSION_HEADER = "Sec-WebSocket-Extension: permessage-deflate"; - private static final String WEBSOCKET_EXTENSIONS_HEADER = "Sec-WebSocket-Extensions: permessage-deflate"; - private static final String WEBSOCKET_UPGRADE_HEADER = "Upgrade: websocket\r\n"; - private static final String WEBSOCKET_CONNECTION_HEADER = "Connection: Upgrade\r\n"; - /** * Вызвать для выполнения оптимизаций на переданном списке пакетов. */ - public void optimizeStream() { + public List optimizeStream() { if (service.isUngzipHttp()) { unpackGzip(); } - if (service.isUrldecodeHttpRequests()) { - urldecodeRequests(); - } - if (service.isInflateWebSockets()) { inflateWebSocket(); } + if (service.isUrldecodeHttpRequests()) { + urldecodeRequests(); + } + if (service.isMergeAdjacentPackets()) { mergeAdjacentPackets(); } + + return packets; } /** @@ -136,7 +114,7 @@ public class StreamOptimizer { for (Packet packet : packets) { if (packet.isIncoming()) { - String content = new String(packet.getContent()); + String content = packet.getContentString(); if (content.contains("HTTP/")) { httpStarted = true; } @@ -173,7 +151,7 @@ public class StreamOptimizer { i = gzipStartPacket + 1; // продвигаем указатель на следующий после склеенного блок } } else if (!packet.isIncoming()) { - String content = new String(packet.getContent()); + String content = packet.getContentString(); int contentPos = content.indexOf("\r\n\r\n"); boolean http = content.startsWith("HTTP/"); @@ -255,147 +233,16 @@ public class StreamOptimizer { } private void inflateWebSocket() { - if (!new String(packets.get(0).getContent()).contains("HTTP/")) { + if (!packets.get(0).getContentString().contains("HTTP/")) { return; } - final List clientHandshakePackets = packets.stream() - .takeWhile(Packet::isIncoming) - .collect(Collectors.toList()); - - final String clientHandshake = getHandshake(clientHandshakePackets); - if (clientHandshake == null) { + final WebSocketsParser parser = new WebSocketsParser(packets); + if(!parser.isParsed()) { return; } - final List serverHandshakePackets = packets.stream() - .skip(clientHandshakePackets.size()) - .takeWhile(p -> !p.isIncoming()) - .collect(Collectors.toList()); - - final String serverHandshake = getHandshake(serverHandshakePackets); - if (serverHandshake == null) { - return; - } - - HandshakeImpl1Server serverHandshakeImpl = fillServerHandshake(serverHandshake); - HandshakeImpl1Client clientHandshakeImpl = fillClientHandshake(clientHandshake); - - if (serverHandshakeImpl == null || clientHandshakeImpl == null) { - return; - } - - final List wsPackets = this.packets.subList( - clientHandshakePackets.size() + serverHandshakePackets.size(), - this.packets.size()); - - final byte[] wsContent = wsPackets.stream() - .map(Packet::getContent) - .reduce(ArrayUtils::addAll) - .orElse(null); - - if (wsContent == null) { - return; - } - - final ByteBuffer frame = ByteBuffer.wrap(wsContent); - Draft_6455 draft = new Draft_6455(new PerMessageDeflateExtension()); - - try { - draft.acceptHandshakeAsServer(clientHandshakeImpl); - draft.acceptHandshakeAsClient(clientHandshakeImpl, serverHandshakeImpl); - } catch (InvalidHandshakeException e) { - log.warn("WebSocket handshake", e); - return; - } - - try { - final List list = draft.translateFrame(frame); - log.info(list.toString()); - } catch (InvalidDataException e) { - log.warn("WebSocket data", e); - } - } - - private String getHandshake(final List packets) { - final String handshake = packets.stream() - .map(Packet::getContent) - .reduce(ArrayUtils::addAll) - .map(String::new) - .orElse(null); - - if (handshake == null || - !handshake.contains(WEBSOCKET_CONNECTION_HEADER) || - !handshake.contains(WEBSOCKET_UPGRADE_HEADER)) { - return null; - } - - if (!handshake.contains(WEBSOCKET_EXTENSION_HEADER) && - !handshake.contains(WEBSOCKET_EXTENSIONS_HEADER)) { - return null; - } - - return handshake; - } - - private HandshakeImpl1Client fillClientHandshake(String clientHandshake) { - Matcher matcher = WEBSOCKET_VERSION_PATTERN.matcher(clientHandshake); - if (!matcher.find()) { - return null; - } - String version = matcher.group(1); - - matcher = WEBSOCKET_KEY_PATTERN.matcher(clientHandshake); - if (!matcher.find()) { - return null; - } - String key = matcher.group(1); - - matcher = WEBSOCKET_EXTENSIONS_PATTERN.matcher(clientHandshake); - if (!matcher.find()) { - return null; - } - String extensions = matcher.group(1); - - HandshakeImpl1Client clientHandshakeImpl = new HandshakeImpl1Client(); - - clientHandshakeImpl.put("Upgrade", "websocket"); - clientHandshakeImpl.put("Connection", "Upgrade"); - clientHandshakeImpl.put("Sec-WebSocket-Version", version); - clientHandshakeImpl.put("Sec-WebSocket-Key", key); - clientHandshakeImpl.put("Sec-WebSocket-Extensions", extensions); - - return clientHandshakeImpl; - } - - private HandshakeImpl1Server fillServerHandshake(String serverHandshake) { - Matcher matcher = WEBSOCKET_VERSION_PATTERN.matcher(serverHandshake); - if (!matcher.find()) { - return null; - } - String version = matcher.group(1); - - matcher = WEBSOCKET_ACCEPT_PATTERN.matcher(serverHandshake); - if (!matcher.find()) { - return null; - } - String accept = matcher.group(1); - - matcher = WEBSOCKET_EXTENSIONS_PATTERN.matcher(serverHandshake); - if (!matcher.find()) { - return null; - } - String extensions = matcher.group(1); - - HandshakeImpl1Server serverHandshakeImpl = new HandshakeImpl1Server(); - - serverHandshakeImpl.put("Upgrade", "websocket"); - serverHandshakeImpl.put("Connection", "Upgrade"); - serverHandshakeImpl.put("Sec-WebSocket-Version", version); - serverHandshakeImpl.put("Sec-WebSocket-Accept", accept); - serverHandshakeImpl.put("Sec-WebSocket-Extensions", extensions); - - return serverHandshakeImpl; + packets = parser.getParsedPackets(); } } diff --git a/src/main/java/ru/serega6531/packmate/service/StreamService.java b/src/main/java/ru/serega6531/packmate/service/StreamService.java index 19afa74..8d0fc25 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamService.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamService.java @@ -93,7 +93,7 @@ public class StreamService { countingService.countStream(service.getPort(), packets.size()); - new StreamOptimizer(service, packets).optimizeStream(); + packets = new StreamOptimizer(service, packets).optimizeStream(); processUserAgent(packets, stream); Stream savedStream = save(stream); @@ -110,7 +110,7 @@ public class StreamService { private void processUserAgent(List packets, Stream stream) { String ua = null; for (Packet packet : packets) { - String content = new String(packet.getContent()); + String content = packet.getContentString(); final Matcher matcher = userAgentPattern.matcher(content); if (matcher.find()) { ua = matcher.group(1); diff --git a/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java b/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java new file mode 100644 index 0000000..d8bde27 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java @@ -0,0 +1,221 @@ +package ru.serega6531.packmate.service; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; +import org.java_websocket.drafts.Draft_6455; +import org.java_websocket.exceptions.InvalidDataException; +import org.java_websocket.exceptions.InvalidHandshakeException; +import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; +import org.java_websocket.framing.DataFrame; +import org.java_websocket.framing.Framedata; +import org.java_websocket.handshake.HandshakeImpl1Client; +import org.java_websocket.handshake.HandshakeImpl1Server; +import ru.serega6531.packmate.model.Packet; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.stream.Collectors; + +@Slf4j +public class WebSocketsParser { + + private static final java.util.regex.Pattern WEBSOCKET_KEY_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Key: (.+)\\r\\n"); + private static final java.util.regex.Pattern WEBSOCKET_EXTENSIONS_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Extensions?: (.+)\\r\\n"); + private static final java.util.regex.Pattern WEBSOCKET_VERSION_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Version: (\\d+)\\r\\n"); + private static final java.util.regex.Pattern WEBSOCKET_ACCEPT_PATTERN = + java.util.regex.Pattern.compile("Sec-WebSocket-Accept: (.+)\\r\\n"); + + private static final String WEBSOCKET_EXTENSION_HEADER = "Sec-WebSocket-Extension: permessage-deflate"; + private static final String WEBSOCKET_EXTENSIONS_HEADER = "Sec-WebSocket-Extensions: permessage-deflate"; + private static final String WEBSOCKET_UPGRADE_HEADER = "upgrade: websocket\r\n"; + private static final String WEBSOCKET_CONNECTION_HEADER = "connection: upgrade\r\n"; + + private final List packets; + private List frames; + + @Getter + private boolean parsed = false; + private int httpEnd = -1; + + public WebSocketsParser(List packets) { + this.packets = packets; + detectWebSockets(); + } + + private void detectWebSockets() { + final List clientHandshakePackets = packets.stream() + .takeWhile(Packet::isIncoming) + .collect(Collectors.toList()); + + final String clientHandshake = getHandshake(clientHandshakePackets); + if (clientHandshake == null) { + return; + } + + for (int i = clientHandshakePackets.size(); i < packets.size(); i++) { + if (packets.get(i).getContentString().endsWith("\r\n\r\n")) { + httpEnd = i + 1; + break; + } + } + + if (httpEnd == -1) { + return; + } + + final List serverHandshakePackets = packets.subList(clientHandshakePackets.size(), httpEnd); + final String serverHandshake = getHandshake(serverHandshakePackets); + if (serverHandshake == null) { + return; + } + + HandshakeImpl1Server serverHandshakeImpl = fillServerHandshake(serverHandshake); + HandshakeImpl1Client clientHandshakeImpl = fillClientHandshake(clientHandshake); + + if (serverHandshakeImpl == null || clientHandshakeImpl == null) { + return; + } + + Draft_6455 draft = new Draft_6455(new PerMessageDeflateExtension()); + + try { + draft.acceptHandshakeAsServer(clientHandshakeImpl); + draft.acceptHandshakeAsClient(clientHandshakeImpl, serverHandshakeImpl); + } catch (InvalidHandshakeException e) { + log.warn("WebSocket handshake", e); + return; + } + + final List wsPackets = this.packets.subList( + httpEnd, + this.packets.size()); + + final byte[] wsContent = wsPackets.stream() + .map(Packet::getContent) + .reduce(ArrayUtils::addAll) + .orElse(null); + + if (wsContent == null) { + return; + } + + final ByteBuffer frame = ByteBuffer.wrap(wsContent); + + try { + frames = draft.translateFrame(frame); + } catch (InvalidDataException e) { + log.warn("WebSocket data", e); + return; + } + + parsed = true; + } + + public List getParsedPackets() { + if (!parsed) { + throw new IllegalStateException("WS is not parsed"); + } + + final List handshakes = packets.subList(0, httpEnd); + List newPackets = new ArrayList<>(handshakes.size() + frames.size()); + newPackets.addAll(handshakes); + + final Packet lastPacket = packets.get(packets.size() - 1); + + for (Framedata frame : frames) { + if(frame instanceof DataFrame) { + newPackets.add(Packet.builder() + .content(frame.getPayloadData().array()) + .incoming(true) //TODO + .timestamp(lastPacket.getTimestamp()) + .ttl(lastPacket.getTtl()) + .ungzipped(lastPacket.isUngzipped()) + .build() + ); + } + } + + return newPackets; + } + + private String getHandshake(final List packets) { + final String handshake = packets.stream() + .map(Packet::getContent) + .reduce(ArrayUtils::addAll) + .map(String::new) + .orElse(null); + + if (handshake == null || + !handshake.toLowerCase().contains(WEBSOCKET_CONNECTION_HEADER) || + !handshake.toLowerCase().contains(WEBSOCKET_UPGRADE_HEADER)) { + return null; + } + + if (!handshake.contains(WEBSOCKET_EXTENSION_HEADER) && + !handshake.contains(WEBSOCKET_EXTENSIONS_HEADER)) { + return null; + } + + return handshake; + } + + private HandshakeImpl1Client fillClientHandshake(String clientHandshake) { + Matcher matcher = WEBSOCKET_VERSION_PATTERN.matcher(clientHandshake); + if (!matcher.find()) { + return null; + } + String version = matcher.group(1); + + matcher = WEBSOCKET_KEY_PATTERN.matcher(clientHandshake); + if (!matcher.find()) { + return null; + } + String key = matcher.group(1); + + matcher = WEBSOCKET_EXTENSIONS_PATTERN.matcher(clientHandshake); + if (!matcher.find()) { + return null; + } + String extensions = matcher.group(1); + + HandshakeImpl1Client clientHandshakeImpl = new HandshakeImpl1Client(); + + clientHandshakeImpl.put("Upgrade", "websocket"); + clientHandshakeImpl.put("Connection", "Upgrade"); + clientHandshakeImpl.put("Sec-WebSocket-Version", version); + clientHandshakeImpl.put("Sec-WebSocket-Key", key); + clientHandshakeImpl.put("Sec-WebSocket-Extensions", extensions); + + return clientHandshakeImpl; + } + + private HandshakeImpl1Server fillServerHandshake(String serverHandshake) { + Matcher matcher = WEBSOCKET_ACCEPT_PATTERN.matcher(serverHandshake); + if (!matcher.find()) { + return null; + } + String accept = matcher.group(1); + + matcher = WEBSOCKET_EXTENSIONS_PATTERN.matcher(serverHandshake); + if (!matcher.find()) { + return null; + } + String extensions = matcher.group(1); + + HandshakeImpl1Server serverHandshakeImpl = new HandshakeImpl1Server(); + + serverHandshakeImpl.put("Upgrade", "websocket"); + serverHandshakeImpl.put("Connection", "Upgrade"); + serverHandshakeImpl.put("Sec-WebSocket-Accept", accept); + serverHandshakeImpl.put("Sec-WebSocket-Extensions", extensions); + + return serverHandshakeImpl; + } + +} diff --git a/src/test/java/ru/serega6531/packmate/StreamOptimizerTest.java b/src/test/java/ru/serega6531/packmate/StreamOptimizerTest.java index ecdbf5c..67bde4a 100644 --- a/src/test/java/ru/serega6531/packmate/StreamOptimizerTest.java +++ b/src/test/java/ru/serega6531/packmate/StreamOptimizerTest.java @@ -28,8 +28,8 @@ class StreamOptimizerTest { List list = new ArrayList<>(); list.add(p); - new StreamOptimizer(service, list).optimizeStream(); - final String processed = new String(list.get(0).getContent()); + list = new StreamOptimizer(service, list).optimizeStream(); + final String processed = list.get(0).getContentString(); assertTrue(processed.contains("aaabbb")); } @@ -42,8 +42,8 @@ class StreamOptimizerTest { List list = new ArrayList<>(); list.add(p); - new StreamOptimizer(service, list).optimizeStream(); - final String processed = new String(list.get(0).getContent()); + list = new StreamOptimizer(service, list).optimizeStream(); + final String processed = list.get(0).getContentString(); assertTrue(processed.contains("а б")); } @@ -67,7 +67,7 @@ class StreamOptimizerTest { list.add(p5); list.add(p6); - new StreamOptimizer(service, list).optimizeStream(); + list = new StreamOptimizer(service, list).optimizeStream(); assertEquals(4, list.size()); assertEquals(2, list.get(1).getContent().length); From 2688e1fc566918b1614dfdf732fbbcba57d31cf7 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 5 Apr 2020 00:36:52 +0300 Subject: [PATCH 07/12] =?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=80=D0=B0=D1=81=D0=BF=D0=B0=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=BE=D0=B9=20websocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packmate/service/WebSocketsParser.java | 98 ++++++++++++------- 1 file changed, 65 insertions(+), 33 deletions(-) diff --git a/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java b/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java index d8bde27..45ab970 100644 --- a/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java +++ b/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java @@ -37,11 +37,10 @@ public class WebSocketsParser { private static final String WEBSOCKET_CONNECTION_HEADER = "connection: upgrade\r\n"; private final List packets; - private List frames; @Getter private boolean parsed = false; - private int httpEnd = -1; + private List parsedPackets; public WebSocketsParser(List packets) { this.packets = packets; @@ -58,6 +57,7 @@ public class WebSocketsParser { return; } + int httpEnd = -1; for (int i = clientHandshakePackets.size(); i < packets.size(); i++) { if (packets.get(i).getContentString().endsWith("\r\n\r\n")) { httpEnd = i + 1; @@ -92,56 +92,88 @@ public class WebSocketsParser { return; } - final List wsPackets = this.packets.subList( + final List wsPackets = packets.subList( httpEnd, - this.packets.size()); + packets.size()); - final byte[] wsContent = wsPackets.stream() - .map(Packet::getContent) - .reduce(ArrayUtils::addAll) - .orElse(null); - - if (wsContent == null) { + if(wsPackets.isEmpty()) { return; } - final ByteBuffer frame = ByteBuffer.wrap(wsContent); - - try { - frames = draft.translateFrame(frame); - } catch (InvalidDataException e) { - log.warn("WebSocket data", e); - return; - } + final List handshakes = packets.subList(0, httpEnd); + parse(wsPackets, handshakes, draft); parsed = true; } + private void parse(final List wsPackets, final List handshakes, Draft_6455 draft) { + List> sides = sliceToSides(wsPackets); + parsedPackets = new ArrayList<>(handshakes); + + for (List side : sides) { + final Packet lastPacket = side.get(0); + + final byte[] wsContent = side.stream() + .map(Packet::getContent) + .reduce(ArrayUtils::addAll) + .get(); + + final ByteBuffer buffer = ByteBuffer.wrap(wsContent); + List frames; + + try { + frames = draft.translateFrame(buffer); + } catch (InvalidDataException e) { + log.warn("WebSocket data", e); + return; + } + + for (Framedata frame : frames) { + if(frame instanceof DataFrame) { + parsedPackets.add(Packet.builder() + .content(frame.getPayloadData().array()) + .incoming(lastPacket.isIncoming()) + .timestamp(lastPacket.getTimestamp()) + .ttl(lastPacket.getTtl()) + .ungzipped(lastPacket.isUngzipped()) + .build() + ); + } + } + } + } + public List getParsedPackets() { if (!parsed) { throw new IllegalStateException("WS is not parsed"); } - final List handshakes = packets.subList(0, httpEnd); - List newPackets = new ArrayList<>(handshakes.size() + frames.size()); - newPackets.addAll(handshakes); + return parsedPackets; + } - final Packet lastPacket = packets.get(packets.size() - 1); + private List> sliceToSides(List packets) { + List> result = new ArrayList<>(); + List side = new ArrayList<>(); + boolean incoming = true; - for (Framedata frame : frames) { - if(frame instanceof DataFrame) { - newPackets.add(Packet.builder() - .content(frame.getPayloadData().array()) - .incoming(true) //TODO - .timestamp(lastPacket.getTimestamp()) - .ttl(lastPacket.getTtl()) - .ungzipped(lastPacket.isUngzipped()) - .build() - ); + for (Packet packet : packets) { + if(packet.isIncoming() != incoming) { + incoming = packet.isIncoming(); + + if(!side.isEmpty()) { + result.add(side); + side = new ArrayList<>(); + } } + + side.add(packet); } - return newPackets; + if(!side.isEmpty()) { + result.add(side); + } + + return result; } private String getHandshake(final List packets) { From d33ca5e66714c29f8b67e0d71ed568ba35041a34 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 5 Apr 2020 01:51:33 +0300 Subject: [PATCH 08/12] =?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=80=D0=B0=D1=81=D0=BF=D0=B0=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=BE=D0=B9=20websocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/serega6531/packmate/model/CtfService.java | 2 +- src/main/java/ru/serega6531/packmate/model/Packet.java | 2 ++ .../java/ru/serega6531/packmate/service/StreamOptimizer.java | 3 +++ .../java/ru/serega6531/packmate/service/WebSocketsParser.java | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/serega6531/packmate/model/CtfService.java b/src/main/java/ru/serega6531/packmate/model/CtfService.java index 5eb5719..58bef42 100644 --- a/src/main/java/ru/serega6531/packmate/model/CtfService.java +++ b/src/main/java/ru/serega6531/packmate/model/CtfService.java @@ -22,6 +22,6 @@ public class CtfService { private boolean mergeAdjacentPackets; - private boolean inflateWebSockets = true; //TODO + private boolean inflateWebSockets; } \ No newline at end of file diff --git a/src/main/java/ru/serega6531/packmate/model/Packet.java b/src/main/java/ru/serega6531/packmate/model/Packet.java index 603202f..b0a6f7b 100644 --- a/src/main/java/ru/serega6531/packmate/model/Packet.java +++ b/src/main/java/ru/serega6531/packmate/model/Packet.java @@ -52,6 +52,8 @@ public class Packet { private boolean ungzipped; + private boolean webSocketInflated; + private byte[] content; @Transient diff --git a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java index a161afe..7050fc8 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamOptimizer.java @@ -89,6 +89,7 @@ public class StreamOptimizer { final List cut = packets.subList(start, end); final long timestamp = cut.get(0).getTimestamp(); final boolean ungzipped = cut.stream().anyMatch(Packet::isUngzipped); + final boolean webSocketInflated = cut.stream().anyMatch(Packet::isWebSocketInflated); boolean incoming = cut.get(0).isIncoming(); //noinspection OptionalGetWithoutIsPresent final byte[] content = cut.stream() @@ -101,6 +102,7 @@ public class StreamOptimizer { .incoming(incoming) .timestamp(timestamp) .ungzipped(ungzipped) + .webSocketInflated(webSocketInflated) .content(content) .build()); } @@ -221,6 +223,7 @@ public class StreamOptimizer { .incoming(false) .timestamp(cut.get(0).getTimestamp()) .ungzipped(true) + .webSocketInflated(false) .content(newContent) .build(); } catch (ZipException e) { diff --git a/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java b/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java index 45ab970..0486001 100644 --- a/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java +++ b/src/main/java/ru/serega6531/packmate/service/WebSocketsParser.java @@ -136,6 +136,7 @@ public class WebSocketsParser { .timestamp(lastPacket.getTimestamp()) .ttl(lastPacket.getTtl()) .ungzipped(lastPacket.isUngzipped()) + .webSocketInflated(true) .build() ); } From bb5bfb5d65e7b23ec7ce1d2e29cb6a2c11177928 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 5 Apr 2020 01:52:27 +0300 Subject: [PATCH 09/12] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=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 --- frontend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend b/frontend index 6883d55..4e6a685 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit 6883d5566bf61d837d06f5e8eed1834c1ddc4218 +Subproject commit 4e6a685e698ad764a69a0b5ce182b60bf130f3b5 From 78062273e12d3b20f8cbc012fe1a4a179a00e55c Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 5 Apr 2020 02:29:46 +0300 Subject: [PATCH 10/12] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + README_EN.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11002dc..e03a52f 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ * Конкатенирует смежные пакеты * Автоматически проводит urldecode * Разархивирует GZIP в HTTP на лету +* Разархивирует сжатые WebSockets ![Скриншот главного окна](screenshots/Screenshot.png) ## Клонирование diff --git a/README_EN.md b/README_EN.md index 06eb927..5b22879 100644 --- a/README_EN.md +++ b/README_EN.md @@ -18,7 +18,8 @@ Advanced network traffic flow analyzer for A/D CTFs. * Has the option to copy packet content in the required format * Can concatenate adjacent packets * Can urldecode text automatically -* Can automatically decode GZIPed HTTP +* Can automatically decompress GZIPed HTTP +* Can automatically deflate WebSockets with permessages-deflate extension ![Main window](screenshots/Screenshot.png) ## Cloning From c3b36300bfb441eba321331d989e54b5c281fd8c Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 5 Apr 2020 16:52:04 +0300 Subject: [PATCH 11/12] =?UTF-8?q?=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8?= =?UTF-8?q?=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=20Dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/Dockerfile_app | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docker/Dockerfile_app b/docker/Dockerfile_app index 7bda5bc..ec79d2e 100644 --- a/docker/Dockerfile_app +++ b/docker/Dockerfile_app @@ -1,20 +1,20 @@ FROM openjdk:13-jdk-alpine -RUN apk add libpcap npm +RUN apk --no-cache add libpcap npm COPY ./ /app/ WORKDIR /app/frontend/ -RUN npm install && npm run build - -RUN mkdir -p ../src/main/resources/static/ \ - && cp -rf ./dist/* ../src/main/resources/static/ +RUN npm install && npm run build && npm cache clean --force \ + && mkdir -p ../src/main/resources/static/ \ + && mv ./dist/* ../src/main/resources/static/ \ + && rm -rf node_modules WORKDIR /app/ -RUN ./gradlew --no-daemon build - -RUN cp build/libs/packmate-*.jar app.jar +RUN ./gradlew --no-daemon --no-build-cache build \ + && cp build/libs/packmate-*.jar app.jar \ + && ./gradlew --no-daemon clean EXPOSE 65000:65000 From 459dbf0a024c36a2742e6fd339e3bc9eb0386c18 Mon Sep 17 00:00:00 2001 From: serega6531 Date: Sun, 5 Apr 2020 17:57:08 +0300 Subject: [PATCH 12/12] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B5=D0=B7?= =?UTF-8?q?=D0=B4=20=D0=BD=D0=B0=20Java=2015-ea?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/Dockerfile_app | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile_app b/docker/Dockerfile_app index ec79d2e..18bc01d 100644 --- a/docker/Dockerfile_app +++ b/docker/Dockerfile_app @@ -1,4 +1,4 @@ -FROM openjdk:13-jdk-alpine +FROM openjdk:15-ea-jdk-alpine RUN apk --no-cache add libpcap npm