5 Commits
v3.1 ... v3.3

Author SHA1 Message Date
Sergey
7986658bd1 Update configuration 2023-07-26 18:21:49 +00:00
Sergey
4fed53244d Merge branch 'update-frontend' into 'master'
Update frontend to show packet offsets

See merge request packmate/Packmate!21
2023-07-24 22:30:47 +00:00
Sergey Shkurov
37fd548364 Update frontend to show packet offsets 2023-07-25 02:28:56 +04:00
Sergey Shkurov
fcd7918125 Update frontend to use dark theme 2023-05-01 23:23:11 +02:00
Sergey Shkurov
c88ca8abbd Update frontend 2023-05-01 21:18:26 +02:00
14 changed files with 118 additions and 82 deletions

View File

@@ -17,11 +17,13 @@ COPY --from=1 /tmp/compile/build/libs/packmate-*-SNAPSHOT.jar app.jar
CMD [ "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", \
"-jar", "/app/app.jar", "--spring.datasource.url=jdbc:postgresql://127.0.0.1:65001/packmate", \
"--spring.datasource.password=${DB_PASSWORD}", \
"--capture-mode=${MODE}", "--pcap-file=${PCAP_FILE}", \
"--interface-name=${INTERFACE}", "--local-ip=${LOCAL_IP}", "--account-login=${WEB_LOGIN}", \
"--old-streams-cleanup-enabled=${OLD_STREAMS_CLEANUP_ENABLED}", "--cleanup-interval=${OLD_STREAMS_CLEANUP_INTERVAL}", \
"--old-streams-threshold=${OLD_STREAMS_CLEANUP_THRESHOLD}", \
"--account-password=${WEB_PASSWORD}", "--server.port=65000", "--server.address=0.0.0.0" \
"--packmate.capture-mode=${MODE}", "--packmate.pcap-file=${PCAP_FILE}", \
"--packmate.interface-name=${INTERFACE}", "--packmate.local-ip=${LOCAL_IP}", \
"--packmate.web.account-login=${WEB_LOGIN}", "--packmate.web.account-password=${WEB_PASSWORD}", \
"--packmate.cleanup.enabled=${OLD_STREAMS_CLEANUP_ENABLED}", \
"--packmate.cleanup.interval=${OLD_STREAMS_CLEANUP_INTERVAL}", \
"--packmate.cleanup.threshold=${OLD_STREAMS_CLEANUP_THRESHOLD}", \
"--server.port=65000", "--server.address=0.0.0.0" \
]
EXPOSE 65000

View File

@@ -5,19 +5,19 @@ import org.modelmapper.ModelMapper;
import org.modelmapper.TypeMap;
import org.pcap4j.core.PcapNativeException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import ru.serega6531.packmate.model.Pattern;
import ru.serega6531.packmate.model.Stream;
import ru.serega6531.packmate.model.enums.CaptureMode;
import ru.serega6531.packmate.model.pojo.StreamDto;
import ru.serega6531.packmate.pcap.FilePcapWorker;
import ru.serega6531.packmate.pcap.LivePcapWorker;
import ru.serega6531.packmate.pcap.NoOpPcapWorker;
import ru.serega6531.packmate.pcap.PcapWorker;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.service.ServicesService;
import ru.serega6531.packmate.service.StreamService;
import ru.serega6531.packmate.service.SubscriptionService;
@@ -29,6 +29,7 @@ import java.util.stream.Collectors;
@Configuration
@EnableScheduling
@EnableAsync
@ConfigurationPropertiesScan("ru.serega6531.packmate.properties")
public class ApplicationConfiguration {
@Bean(destroyMethod = "stop")
@@ -36,14 +37,12 @@ public class ApplicationConfiguration {
public PcapWorker pcapWorker(ServicesService servicesService,
StreamService streamService,
SubscriptionService subscriptionService,
@Value("${local-ip}") String localIpString,
@Value("${interface-name}") String interfaceName,
@Value("${pcap-file}") String filename,
@Value("${capture-mode}") CaptureMode captureMode) throws PcapNativeException, UnknownHostException {
return switch (captureMode) {
case LIVE -> new LivePcapWorker(servicesService, streamService, localIpString, interfaceName);
PackmateProperties properties
) throws PcapNativeException, UnknownHostException {
return switch (properties.captureMode()) {
case LIVE -> new LivePcapWorker(servicesService, streamService, properties.localIp(), properties.interfaceName());
case FILE ->
new FilePcapWorker(servicesService, streamService, subscriptionService, localIpString, filename);
new FilePcapWorker(servicesService, streamService, subscriptionService, properties.localIp(), properties.pcapFile());
case VIEW -> new NoOpPcapWorker();
};
}

View File

@@ -1,7 +1,6 @@
package ru.serega6531.packmate.configuration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
@@ -14,23 +13,18 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import ru.serega6531.packmate.properties.PackmateProperties;
@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfiguration {
@Value("${account-login}")
private String login;
@Value("${account-password}")
private String password;
@Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
public InMemoryUserDetailsManager userDetailsService(PackmateProperties properties, PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username(login)
.password(passwordEncoder.encode(password))
.username(properties.web().accountLogin())
.password(passwordEncoder.encode(properties.web().accountPassword()))
.roles("USER")
.build();

View File

@@ -52,11 +52,11 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener {
protected AbstractPcapWorker(ServicesService servicesService,
StreamService streamService,
String localIpString) throws UnknownHostException {
InetAddress localIp) throws UnknownHostException {
this.servicesService = servicesService;
this.streamService = streamService;
this.localIp = InetAddress.getByName(localIpString);
this.localIp = localIp;
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("pcap-loop").build();

View File

@@ -16,6 +16,7 @@ import ru.serega6531.packmate.service.SubscriptionService;
import java.io.EOFException;
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Slf4j
@@ -27,9 +28,9 @@ public class FilePcapWorker extends AbstractPcapWorker {
public FilePcapWorker(ServicesService servicesService,
StreamService streamService,
SubscriptionService subscriptionService,
String localIpString,
InetAddress localIp,
String filename) throws UnknownHostException {
super(servicesService, streamService, localIpString);
super(servicesService, streamService, localIp);
this.subscriptionService = subscriptionService;
File directory = new File("pcaps");

View File

@@ -10,6 +10,7 @@ import ru.serega6531.packmate.exception.PcapInterfaceNotFoundException;
import ru.serega6531.packmate.service.ServicesService;
import ru.serega6531.packmate.service.StreamService;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
@@ -23,9 +24,9 @@ public class LivePcapWorker extends AbstractPcapWorker {
public LivePcapWorker(ServicesService servicesService,
StreamService streamService,
String localIpString,
InetAddress localIp,
String interfaceName) throws PcapNativeException, UnknownHostException {
super(servicesService, streamService, localIpString);
super(servicesService, streamService, localIp);
device = Pcaps.getDevByName(interfaceName);
if (device == null) {

View File

@@ -0,0 +1,38 @@
package ru.serega6531.packmate.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import ru.serega6531.packmate.model.enums.CaptureMode;
import java.net.InetAddress;
@ConfigurationProperties("packmate")
public record PackmateProperties(
CaptureMode captureMode,
String interfaceName,
String pcapFile,
InetAddress localIp,
WebProperties web,
TimeoutProperties timeout,
CleanupProperties cleanup,
boolean ignoreEmptyPackets
) {
public record WebProperties(
String accountLogin,
String accountPassword
) {}
public record TimeoutProperties(
int udpStreamTimeout,
int tcpStreamTimeout,
int checkInterval
){}
public record CleanupProperties(
boolean enabled,
int threshold,
int interval
){}
}

View File

@@ -1,12 +1,13 @@
package ru.serega6531.packmate.service;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.model.CtfService;
import ru.serega6531.packmate.model.enums.SubscriptionMessageType;
import ru.serega6531.packmate.model.pojo.ServiceCreateDto;
@@ -15,10 +16,11 @@ import ru.serega6531.packmate.model.pojo.ServiceUpdateDto;
import ru.serega6531.packmate.model.pojo.SubscriptionMessage;
import ru.serega6531.packmate.repository.ServiceRepository;
import jakarta.annotation.PostConstruct;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
@Slf4j
@@ -38,12 +40,12 @@ public class ServicesService {
SubscriptionService subscriptionService,
@Lazy PcapService pcapService,
ModelMapper modelMapper,
@Value("${local-ip}") String localIpString) throws UnknownHostException {
PackmateProperties properties) {
this.repository = repository;
this.subscriptionService = subscriptionService;
this.pcapService = pcapService;
this.modelMapper = modelMapper;
this.localIp = InetAddress.getByName(localIpString);
this.localIp = properties.localIp();
}
@PostConstruct

View File

@@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -13,6 +12,7 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.model.CtfService;
import ru.serega6531.packmate.model.FoundPattern;
import ru.serega6531.packmate.model.Packet;
@@ -60,7 +60,7 @@ public class StreamService {
SubscriptionService subscriptionService,
RsaKeysHolder keysHolder,
ModelMapper modelMapper,
@Value("${ignore-empty-packets}") boolean ignoreEmptyPackets) {
PackmateProperties properties) {
this.repository = repository;
this.patternService = patternService;
this.servicesService = servicesService;
@@ -68,7 +68,7 @@ public class StreamService {
this.subscriptionService = subscriptionService;
this.keysHolder = keysHolder;
this.modelMapper = modelMapper;
this.ignoreEmptyPackets = ignoreEmptyPackets;
this.ignoreEmptyPackets = properties.ignoreEmptyPackets();
}
/**

View File

@@ -1,31 +1,30 @@
package ru.serega6531.packmate.tasks;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.service.StreamService;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@Component
@Slf4j
@ConditionalOnExpression("${old-streams-cleanup-enabled:false} && '${capture-mode}' == 'LIVE'")
@ConditionalOnExpression("${packmate.cleanup.enabled:false} && '${packmate.capture-mode}' == 'LIVE'")
public class OldStreamsCleanupTask {
private final StreamService service;
private final int oldStreamsThreshold;
public OldStreamsCleanupTask(StreamService service, @Value("${old-streams-threshold}") int oldStreamsThreshold) {
public OldStreamsCleanupTask(StreamService service, PackmateProperties properties) {
this.service = service;
this.oldStreamsThreshold = oldStreamsThreshold;
this.oldStreamsThreshold = properties.cleanup().threshold();
}
@Scheduled(fixedDelayString = "PT${cleanup-interval}M", initialDelayString = "PT1M")
@Scheduled(fixedDelayString = "PT${packmate.cleanup.interval}M", initialDelayString = "PT1M")
public void cleanup() {
ZonedDateTime before = ZonedDateTime.now().minus(oldStreamsThreshold, ChronoUnit.MINUTES);
ZonedDateTime before = ZonedDateTime.now().minusMinutes(oldStreamsThreshold);
log.info("Cleaning up old non-favorite streams (before {})", before);
long deleted = service.cleanupOldStreams(before);
log.info("Deleted {} rows", deleted);

View File

@@ -1,10 +1,10 @@
package ru.serega6531.packmate.tasks;
import org.pcap4j.core.PcapNativeException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.model.enums.CaptureMode;
import ru.serega6531.packmate.service.PcapService;
import ru.serega6531.packmate.service.ServicesService;
@@ -12,29 +12,23 @@ import ru.serega6531.packmate.service.ServicesService;
@Component
public class StartupListener {
@Value("${enable-capture}")
private boolean enableCapture;
@Value("${capture-mode}")
private CaptureMode captureMode;
private final PackmateProperties packmateProperties;
private final PcapService pcapService;
private final ServicesService servicesService;
public StartupListener(PcapService pcapService, ServicesService servicesService) {
public StartupListener(PcapService pcapService, ServicesService servicesService, PackmateProperties packmateProperties) {
this.pcapService = pcapService;
this.servicesService = servicesService;
this.packmateProperties = packmateProperties;
}
@EventListener(ApplicationReadyEvent.class)
public void afterStartup() throws PcapNativeException {
if (enableCapture) {
servicesService.updateFilter();
if (captureMode == CaptureMode.LIVE) {
if (packmateProperties.captureMode() == CaptureMode.LIVE) {
pcapService.start();
}
}
}
}

View File

@@ -2,10 +2,10 @@ package ru.serega6531.packmate.tasks;
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.properties.PackmateProperties;
import ru.serega6531.packmate.model.enums.Protocol;
import ru.serega6531.packmate.pcap.PcapWorker;
@@ -13,7 +13,7 @@ import java.util.concurrent.TimeUnit;
@Component
@Slf4j
@ConditionalOnProperty(name = "capture-mode", havingValue = "LIVE")
@ConditionalOnProperty(name = "packmate.capture-mode", havingValue = "LIVE")
public class TimeoutStreamsSaver {
private final PcapWorker pcapWorker;
@@ -22,14 +22,13 @@ public class TimeoutStreamsSaver {
@Autowired
public TimeoutStreamsSaver(PcapWorker pcapWorker,
@Value("${udp-stream-timeout}") int udpStreamTimeout,
@Value("${tcp-stream-timeout}") int tcpStreamTimeout) {
PackmateProperties properties) {
this.pcapWorker = pcapWorker;
this.udpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(udpStreamTimeout);
this.tcpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(tcpStreamTimeout);
this.udpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(properties.timeout().udpStreamTimeout());
this.tcpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(properties.timeout().tcpStreamTimeout());
}
@Scheduled(fixedRateString = "PT${timeout-stream-check-interval}S", initialDelayString = "PT${timeout-stream-check-interval}S")
@Scheduled(fixedRateString = "PT${packmate.timeout.check-interval}S", initialDelayString = "PT${packmate.timeout.check-interval}S")
public void saveStreams() {
int streamsClosed = pcapWorker.closeTimeoutStreams(Protocol.UDP, udpStreamTimeoutMillis);
if (streamsClosed > 0) {

View File

@@ -1,6 +1,6 @@
spring:
datasource:
url: "jdbc:postgresql://localhost/packmate"
url: "jdbc:postgresql://localhost:5432/packmate"
username: "packmate"
password: "123456"
driver-class-name: org.postgresql.Driver
@@ -14,18 +14,25 @@ spring:
order_inserts: true
database-platform: org.hibernate.dialect.PostgreSQLDialect
server:
compression:
enabled: true
min-response-size: 1KB
enable-capture: true
capture-mode: LIVE # LIVE, FILE, VIEW
interface-name: enp0s31f6
pcap-file: file.pcap
local-ip: "192.168.0.125"
account-login: BinaryBears
account-password: 123456
udp-stream-timeout: 20 # seconds
tcp-stream-timeout: 40 # seconds
timeout-stream-check-interval: 10 # seconds
old-streams-cleanup-enabled: true
old-streams-threshold: 240 # minutes
cleanup-interval: 5 # minutes
ignore-empty-packets: true
packmate:
capture-mode: LIVE # LIVE, FILE, VIEW
interface-name: enp0s31f6
pcap-file: file.pcap
local-ip: "192.168.0.125"
web:
account-login: BinaryBears
account-password: 123456
timeout:
udp-stream-timeout: 20 # seconds
tcp-stream-timeout: 40 # seconds
check-interval: 10 # seconds
cleanup:
enabled: true
threshold: 240 # minutes
interval: 5 # minutes
ignore-empty-packets: true