Introduction to Network Traffic Analysis
Network Traffic Analysis involves monitoring, capturing, and analyzing network traffic to detect security threats, performance issues, and anomalous behavior. Java provides robust libraries for packet capture, protocol analysis, and network monitoring.
Key Features
- Packet Capture: Real-time network packet interception
- Protocol Analysis: Deep inspection of network protocols
- Traffic Statistics: Bandwidth monitoring and flow analysis
- Anomaly Detection: Identification of suspicious patterns
- Security Monitoring: Threat detection and intrusion prevention
Implementation Guide
Dependencies
Add to your pom.xml:
<properties>
<pcap4j.version>1.8.2</pcap4j.version>
<netty.version>4.1.100.Final</netty.version>
<jackson.version>2.15.2</jackson.version>
<jnetpcap.version>2.1.0</jnetpcap.version>
</properties>
<dependencies>
<!-- Packet Capture -->
<dependency>
<groupId>org.pcap4j</groupId>
<artifactId>pcap4j-core</artifactId>
<version>${pcap4j.version}</version>
</dependency>
<dependency>
<groupId>org.pcap4j</groupId>
<artifactId>pcap4j-packetfactory-static</artifactId>
<version>${pcap4j.version}</version>
</dependency>
<!-- Alternative: jNetPcap -->
<dependency>
<groupId>org.jnetpcap</groupId>
<artifactId>jnetpcap</artifactId>
<version>${jnetpcap.version}</version>
</dependency>
<!-- Network Utilities -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
<!-- Utilities -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.13.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
Core Packet Capture Implementation
Network Interface Manager
package com.example.traffic.analysis;
import org.pcap4j.core.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
public class NetworkInterfaceManager {
private static final Logger logger = LoggerFactory.getLogger(NetworkInterfaceManager.class);
public List<NetworkInterfaceInfo> getNetworkInterfaces() throws PcapNativeException {
List<PcapNetworkInterface> allDevices = Pcaps.findAllDevs();
List<NetworkInterfaceInfo> interfaces = new ArrayList<>();
for (PcapNetworkInterface device : allDevices) {
NetworkInterfaceInfo info = new NetworkInterfaceInfo();
info.setName(device.getName());
info.setDescription(device.getDescription());
// Get IP addresses
List<InetAddress> addresses = new ArrayList<>();
for (PcapAddress addr : device.getAddresses()) {
if (addr.getAddress() != null) {
addresses.add(addr.getAddress());
}
}
info.setAddresses(addresses);
// Check if interface is up
info.setUp(device.isUp());
info.setLoopback(device.isLoopBack());
interfaces.add(info);
}
return interfaces;
}
public PcapNetworkInterface getInterfaceByName(String interfaceName) throws PcapNativeException {
List<PcapNetworkInterface> allDevices = Pcaps.findAllDevs();
for (PcapNetworkInterface device : allDevices) {
if (device.getName().equals(interfaceName)) {
return device;
}
}
throw new IllegalArgumentException("Network interface not found: " + interfaceName);
}
public PcapNetworkInterface getDefaultInterface() throws PcapNativeException {
InetAddress addr = InetAddress.getLocalHost();
PcapNetworkInterface device = Pcaps.getDevByAddress(addr);
if (device == null) {
throw new IllegalStateException("No default network interface found");
}
return device;
}
public void printAvailableInterfaces() throws PcapNativeException {
List<NetworkInterfaceInfo> interfaces = getNetworkInterfaces();
System.out.println("=== Available Network Interfaces ===");
for (int i = 0; i < interfaces.size(); i++) {
NetworkInterfaceInfo info = interfaces.get(i);
System.out.printf("%d. %s (%s)%n", i, info.getName(), info.getDescription());
System.out.printf(" Addresses: %s%n", info.getAddresses());
System.out.printf(" Status: %s, Loopback: %s%n",
info.isUp() ? "UP" : "DOWN", info.isLoopback());
System.out.println();
}
}
}
class NetworkInterfaceInfo {
private String name;
private String description;
private List<InetAddress> addresses;
private boolean isUp;
private boolean isLoopback;
// Getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public List<InetAddress> getAddresses() { return addresses; }
public void setAddresses(List<InetAddress> addresses) { this.addresses = addresses; }
public boolean isUp() { return isUp; }
public void setUp(boolean isUp) { this.isUp = isUp; }
public boolean isLoopback() { return isLoopback; }
public void setLoopback(boolean isLoopback) { this.isLoopback = isLoopback; }
}
Packet Capture Engine
package com.example.traffic.analysis;
import org.pcap4j.core.*;
import org.pcap4j.packet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
public class PacketCaptureEngine {
private static final Logger logger = LoggerFactory.getLogger(PacketCaptureEngine.class);
private final ExecutorService executorService;
private final PacketProcessor packetProcessor;
private final TrafficStatistics statistics;
private PcapHandle handle;
private volatile boolean isCapturing;
private AtomicLong packetCount;
public PacketCaptureEngine(PacketProcessor packetProcessor) {
this.executorService = Executors.newFixedThreadPool(4);
this.packetProcessor = packetProcessor;
this.statistics = new TrafficStatistics();
this.packetCount = new AtomicLong(0);
}
public void startCapture(PcapNetworkInterface networkInterface,
String filter, int snapshotLen, int timeout)
throws PcapNativeException, NotOpenException {
logger.info("Starting packet capture on interface: {}", networkInterface.getName());
// Open the network interface
handle = networkInterface.openLive(snapshotLen,
PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, timeout);
// Set packet filter if provided
if (filter != null && !filter.trim().isEmpty()) {
handle.setFilter(filter, BpfProgram.BpfCompileMode.OPTIMIZE);
logger.info("Applied packet filter: {}", filter);
}
isCapturing = true;
packetCount.set(0);
statistics.reset();
// Start capture in separate thread
CompletableFuture.runAsync(this::captureLoop, executorService);
logger.info("Packet capture started successfully");
}
public void startCapture(String interfaceName, String filter,
int snapshotLen, int timeout)
throws PcapNativeException, NotOpenException {
NetworkInterfaceManager interfaceManager = new NetworkInterfaceManager();
PcapNetworkInterface networkInterface = interfaceManager.getInterfaceByName(interfaceName);
startCapture(networkInterface, filter, snapshotLen, timeout);
}
private void captureLoop() {
logger.info("Packet capture loop started");
try {
while (isCapturing && handle.isOpen()) {
Packet packet = handle.getNextPacket();
if (packet != null) {
processPacket(packet);
}
}
} catch (Exception e) {
if (isCapturing) { // Only log if we're supposed to be capturing
logger.error("Error in packet capture loop", e);
}
}
logger.info("Packet capture loop stopped");
}
private void processPacket(Packet packet) {
long count = packetCount.incrementAndGet();
statistics.update(packet);
// Process packet asynchronously
CompletableFuture.runAsync(() -> {
try {
packetProcessor.processPacket(packet, count);
} catch (Exception e) {
logger.error("Error processing packet", e);
}
}, executorService);
// Log progress every 1000 packets
if (count % 1000 == 0) {
logger.info("Captured {} packets", count);
}
}
public void stopCapture() {
logger.info("Stopping packet capture");
isCapturing = false;
if (handle != null && handle.isOpen()) {
try {
handle.breakLoop();
handle.close();
} catch (Exception e) {
logger.warn("Error closing packet capture handle", e);
}
}
executorService.shutdown();
logger.info("Packet capture stopped. Total packets: {}", packetCount.get());
}
public TrafficStatistics getStatistics() {
return statistics;
}
public long getPacketCount() {
return packetCount.get();
}
public boolean isCapturing() {
return isCapturing;
}
public void saveCaptureToFile(String filename) throws IOException, NotOpenException {
if (handle == null || !handle.isOpen()) {
throw new IllegalStateException("Capture not active");
}
PcapDumper dumper = handle.dumpOpen(filename);
logger.info("Saving capture to file: {}", filename);
// Note: This is a simplified implementation
// In production, you'd want to implement proper file capture
}
}
interface PacketProcessor {
void processPacket(Packet packet, long packetNumber);
}
class TrafficStatistics {
private final AtomicLong totalPackets;
private final AtomicLong totalBytes;
private final AtomicLong tcpPackets;
private final AtomicLong udpPackets;
private final AtomicLong icmpPackets;
private final AtomicLong otherPackets;
private long startTime;
public TrafficStatistics() {
this.totalPackets = new AtomicLong(0);
this.totalBytes = new AtomicLong(0);
this.tcpPackets = new AtomicLong(0);
this.udpPackets = new AtomicLong(0);
this.icmpPackets = new AtomicLong(0);
this.otherPackets = new AtomicLong(0);
this.startTime = System.currentTimeMillis();
}
public void update(Packet packet) {
totalPackets.incrementAndGet();
totalBytes.addAndGet(packet.length());
if (packet.contains(TcpPacket.class)) {
tcpPackets.incrementAndGet();
} else if (packet.contains(UdpPacket.class)) {
udpPackets.incrementAndGet();
} else if (packet.contains(IcmpV4CommonPacket.class)) {
icmpPackets.incrementAndGet();
} else {
otherPackets.incrementAndGet();
}
}
public void reset() {
totalPackets.set(0);
totalBytes.set(0);
tcpPackets.set(0);
udpPackets.set(0);
icmpPackets.set(0);
otherPackets.set(0);
startTime = System.currentTimeMillis();
}
// Getters
public long getTotalPackets() { return totalPackets.get(); }
public long getTotalBytes() { return totalBytes.get(); }
public long getTcpPackets() { return tcpPackets.get(); }
public long getUdpPackets() { return udpPackets.get(); }
public long getIcmpPackets() { return icmpPackets.get(); }
public long getOtherPackets() { return otherPackets.get(); }
public double getPacketsPerSecond() {
long elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000;
return elapsedSeconds > 0 ? (double) totalPackets.get() / elapsedSeconds : 0;
}
public double getBytesPerSecond() {
long elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000;
return elapsedSeconds > 0 ? (double) totalBytes.get() / elapsedSeconds : 0;
}
public void printStatistics() {
System.out.println("=== Traffic Statistics ===");
System.out.printf("Total Packets: %,d%n", totalPackets.get());
System.out.printf("Total Bytes: %,d%n", totalBytes.get());
System.out.printf("TCP Packets: %,d%n", tcpPackets.get());
System.out.printf("UDP Packets: %,d%n", udpPackets.get());
System.out.printf("ICMP Packets: %,d%n", icmpPackets.get());
System.out.printf("Other Packets: %,d%n", otherPackets.get());
System.out.printf("Packets/Second: %.2f%n", getPacketsPerSecond());
System.out.printf("Bytes/Second: %.2f%n", getBytesPerSecond());
System.out.printf("Capture Duration: %d seconds%n",
(System.currentTimeMillis() - startTime) / 1000);
}
}
Protocol Analysis
Packet Analyzer
package com.example.traffic.analysis;
import org.pcap4j.packet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
public class PacketAnalyzer implements PacketProcessor {
private static final Logger logger = LoggerFactory.getLogger(PacketAnalyzer.class);
private final FlowTracker flowTracker;
private final SecurityDetector securityDetector;
private final ProtocolAnalyzer protocolAnalyzer;
public PacketAnalyzer() {
this.flowTracker = new FlowTracker();
this.securityDetector = new SecurityDetector();
this.protocolAnalyzer = new ProtocolAnalyzer();
}
@Override
public void processPacket(Packet packet, long packetNumber) {
try {
// Extract basic packet information
PacketInfo packetInfo = extractPacketInfo(packet, packetNumber);
// Track network flows
flowTracker.trackPacket(packetInfo);
// Analyze protocols
protocolAnalyzer.analyzeProtocol(packetInfo);
// Detect security threats
securityDetector.analyzeForThreats(packetInfo);
// Log interesting packets
if (isInterestingPacket(packetInfo)) {
logPacket(packetInfo);
}
} catch (Exception e) {
logger.warn("Error analyzing packet {}", packetNumber, e);
}
}
private PacketInfo extractPacketInfo(Packet packet, long packetNumber) {
PacketInfo info = new PacketInfo();
info.setPacketNumber(packetNumber);
info.setTimestamp(System.currentTimeMillis());
info.setLength(packet.length());
info.setRawPacket(packet);
// Extract Ethernet header
if (packet.contains(EthernetPacket.class)) {
EthernetPacket eth = packet.get(EthernetPacket.class);
info.setSrcMac(eth.getHeader().getSrcAddr());
info.setDstMac(eth.getHeader().getDstAddr());
info.setEtherType(eth.getHeader().getType());
}
// Extract IP header
if (packet.contains(IpV4Packet.class)) {
IpV4Packet ip = packet.get(IpV4Packet.class);
info.setSrcIp(ip.getHeader().getSrcAddr());
info.setDstIp(ip.getHeader().getDstAddr());
info.setProtocol(ip.getHeader().getProtocol());
info.setTtl(ip.getHeader().getTtl());
info.setTos(ip.getHeader().getTos());
}
// Extract TCP header
if (packet.contains(TcpPacket.class)) {
TcpPacket tcp = packet.get(TcpPacket.class);
info.setSrcPort(tcp.getHeader().getSrcPort().valueAsInt());
info.setDstPort(tcp.getHeader().getDstPort().valueAsInt());
info.setTcpFlags(tcp.getHeader().getFlags());
info.setSequenceNumber(tcp.getHeader().getSequenceNumber());
info.setAckNumber(tcp.getHeader().getAcknowledgmentNumber());
info.setWindowSize(tcp.getHeader().getWindow());
// Extract payload if available
if (tcp.getPayload() != null) {
info.setPayload(tcp.getPayload().getRawData());
info.setPayloadLength(tcp.getPayload().length());
}
}
// Extract UDP header
if (packet.contains(UdpPacket.class)) {
UdpPacket udp = packet.get(UdpPacket.class);
info.setSrcPort(udp.getHeader().getSrcPort().valueAsInt());
info.setDstPort(udp.getHeader().getDstPort().valueAsInt());
if (udp.getPayload() != null) {
info.setPayload(udp.getPayload().getRawData());
info.setPayloadLength(udp.getPayload().length());
}
}
// Determine packet direction (simplified)
info.setDirection(determinePacketDirection(info));
return info;
}
private PacketDirection determinePacketDirection(PacketInfo packetInfo) {
// This is a simplified implementation
// In production, you'd compare with local IP ranges
if (packetInfo.getSrcIp() != null && packetInfo.getDstIp() != null) {
try {
if (packetInfo.getSrcIp().isSiteLocalAddress()) {
return PacketDirection.OUTBOUND;
} else if (packetInfo.getDstIp().isSiteLocalAddress()) {
return PacketDirection.INBOUND;
}
} catch (Exception e) {
// Ignore and return unknown
}
}
return PacketDirection.UNKNOWN;
}
private boolean isInterestingPacket(PacketInfo packetInfo) {
// Define criteria for "interesting" packets
return packetInfo.getDstPort() == 80 || // HTTP
packetInfo.getDstPort() == 443 || // HTTPS
packetInfo.getDstPort() == 22 || // SSH
packetInfo.getDstPort() == 53 || // DNS
packetInfo.getProtocol() == 1 || // ICMP
securityDetector.isSuspicious(packetInfo);
}
private void logPacket(PacketInfo packetInfo) {
if (logger.isDebugEnabled()) {
logger.debug("Packet {}: {}:{} -> {}:{} [{}] {} bytes",
packetInfo.getPacketNumber(),
packetInfo.getSrcIp(), packetInfo.getSrcPort(),
packetInfo.getDstIp(), packetInfo.getDstPort(),
getProtocolName(packetInfo.getProtocol()),
packetInfo.getLength());
}
}
private String getProtocolName(byte protocol) {
switch (protocol) {
case 1: return "ICMP";
case 6: return "TCP";
case 17: return "UDP";
default: return "UNKNOWN";
}
}
public FlowTracker getFlowTracker() {
return flowTracker;
}
public SecurityDetector getSecurityDetector() {
return securityDetector;
}
public ProtocolAnalyzer getProtocolAnalyzer() {
return protocolAnalyzer;
}
}
class PacketInfo {
private long packetNumber;
private long timestamp;
private int length;
private Packet rawPacket;
// Layer 2
private org.pcap4j.util.MacAddress srcMac;
private org.pcap4j.util.MacAddress dstMac;
private EthernetPacket.EtherType etherType;
// Layer 3
private InetAddress srcIp;
private InetAddress dstIp;
private byte protocol;
private short ttl;
private byte tos;
// Layer 4
private int srcPort;
private int dstPort;
private TcpPacket.TcpFlags tcpFlags;
private long sequenceNumber;
private long ackNumber;
private short windowSize;
// Payload
private byte[] payload;
private int payloadLength;
// Analysis
private PacketDirection direction;
// Getters and setters
public long getPacketNumber() { return packetNumber; }
public void setPacketNumber(long packetNumber) { this.packetNumber = packetNumber; }
public long getTimestamp() { return timestamp; }
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
public int getLength() { return length; }
public void setLength(int length) { this.length = length; }
public Packet getRawPacket() { return rawPacket; }
public void setRawPacket(Packet rawPacket) { this.rawPacket = rawPacket; }
public org.pcap4j.util.MacAddress getSrcMac() { return srcMac; }
public void setSrcMac(org.pcap4j.util.MacAddress srcMac) { this.srcMac = srcMac; }
public org.pcap4j.util.MacAddress getDstMac() { return dstMac; }
public void setDstMac(org.pcap4j.util.MacAddress dstMac) { this.dstMac = dstMac; }
public EthernetPacket.EtherType getEtherType() { return etherType; }
public void setEtherType(EthernetPacket.EtherType etherType) { this.etherType = etherType; }
public InetAddress getSrcIp() { return srcIp; }
public void setSrcIp(InetAddress srcIp) { this.srcIp = srcIp; }
public InetAddress getDstIp() { return dstIp; }
public void setDstIp(InetAddress dstIp) { this.dstIp = dstIp; }
public byte getProtocol() { return protocol; }
public void setProtocol(byte protocol) { this.protocol = protocol; }
public short getTtl() { return ttl; }
public void setTtl(short ttl) { this.ttl = ttl; }
public byte getTos() { return tos; }
public void setTos(byte tos) { this.tos = tos; }
public int getSrcPort() { return srcPort; }
public void setSrcPort(int srcPort) { this.srcPort = srcPort; }
public int getDstPort() { return dstPort; }
public void setDstPort(int dstPort) { this.dstPort = dstPort; }
public TcpPacket.TcpFlags getTcpFlags() { return tcpFlags; }
public void setTcpFlags(TcpPacket.TcpFlags tcpFlags) { this.tcpFlags = tcpFlags; }
public long getSequenceNumber() { return sequenceNumber; }
public void setSequenceNumber(long sequenceNumber) { this.sequenceNumber = sequenceNumber; }
public long getAckNumber() { return ackNumber; }
public void setAckNumber(long ackNumber) { this.ackNumber = ackNumber; }
public short getWindowSize() { return windowSize; }
public void setWindowSize(short windowSize) { this.windowSize = windowSize; }
public byte[] getPayload() { return payload; }
public void setPayload(byte[] payload) { this.payload = payload; }
public int getPayloadLength() { return payloadLength; }
public void setPayloadLength(int payloadLength) { this.payloadLength = payloadLength; }
public PacketDirection getDirection() { return direction; }
public void setDirection(PacketDirection direction) { this.direction = direction; }
public String getFlowKey() {
if (srcIp != null && dstIp != null && srcPort > 0 && dstPort > 0) {
return String.format("%s:%d-%s:%d-%d",
srcIp.getHostAddress(), srcPort,
dstIp.getHostAddress(), dstPort,
protocol);
}
return null;
}
}
enum PacketDirection {
INBOUND, OUTBOUND, UNKNOWN
}
Flow Tracking
package com.example.traffic.analysis;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
public class FlowTracker {
private final Map<String, NetworkFlow> activeFlows;
private final Map<String, AtomicLong> hostStatistics;
private final Map<Integer, AtomicLong> portStatistics;
private final long flowTimeout;
public FlowTracker() {
this.activeFlows = new ConcurrentHashMap<>();
this.hostStatistics = new ConcurrentHashMap<>();
this.portStatistics = new ConcurrentHashMap<>();
this.flowTimeout = 300000; // 5 minutes
}
public void trackPacket(PacketInfo packetInfo) {
String flowKey = packetInfo.getFlowKey();
if (flowKey == null) return;
// Update host statistics
updateHostStatistics(packetInfo.getSrcIp());
updateHostStatistics(packetInfo.getDstIp());
// Update port statistics
updatePortStatistics(packetInfo.getSrcPort());
updatePortStatistics(packetInfo.getDstPort());
// Track flow
NetworkFlow flow = activeFlows.computeIfAbsent(flowKey,
k -> new NetworkFlow(packetInfo));
flow.update(packetInfo);
// Clean up old flows
cleanupExpiredFlows();
}
private void updateHostStatistics(InetAddress host) {
if (host != null) {
String hostKey = host.getHostAddress();
hostStatistics.computeIfAbsent(hostKey, k -> new AtomicLong(0))
.incrementAndGet();
}
}
private void updatePortStatistics(int port) {
if (port > 0) {
portStatistics.computeIfAbsent(port, k -> new AtomicLong(0))
.incrementAndGet();
}
}
private void cleanupExpiredFlows() {
long currentTime = System.currentTimeMillis();
Iterator<Map.Entry<String, NetworkFlow>> iterator = activeFlows.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, NetworkFlow> entry = iterator.next();
NetworkFlow flow = entry.getValue();
if (currentTime - flow.getLastActivity() > flowTimeout) {
iterator.remove();
// Could store completed flows for analysis
}
}
}
public List<NetworkFlow> getActiveFlows() {
return new ArrayList<>(activeFlows.values());
}
public List<NetworkFlow> getTopFlowsByBytes(int limit) {
List<NetworkFlow> flows = new ArrayList<>(activeFlows.values());
flows.sort((f1, f2) -> Long.compare(f2.getTotalBytes(), f1.getTotalBytes()));
return flows.subList(0, Math.min(limit, flows.size()));
}
public List<Map.Entry<String, AtomicLong>> getTopHosts(int limit) {
List<Map.Entry<String, AtomicLong>> hosts = new ArrayList<>(hostStatistics.entrySet());
hosts.sort((e1, e2) -> Long.compare(e2.getValue().get(), e1.getValue().get()));
return hosts.subList(0, Math.min(limit, hosts.size()));
}
public List<Map.Entry<Integer, AtomicLong>> getTopPorts(int limit) {
List<Map.Entry<Integer, AtomicLong>> ports = new ArrayList<>(portStatistics.entrySet());
ports.sort((e1, e2) -> Long.compare(e2.getValue().get(), e1.getValue().get()));
return ports.subList(0, Math.min(limit, ports.size()));
}
public FlowStatistics getFlowStatistics() {
FlowStatistics stats = new FlowStatistics();
stats.setTotalFlows(activeFlows.size());
stats.setTotalHosts(hostStatistics.size());
stats.setTotalPorts(portStatistics.size());
// Calculate average flow duration and size
long totalDuration = 0;
long totalBytes = 0;
for (NetworkFlow flow : activeFlows.values()) {
totalDuration += (System.currentTimeMillis() - flow.getStartTime());
totalBytes += flow.getTotalBytes();
}
if (!activeFlows.isEmpty()) {
stats.setAverageFlowDuration(totalDuration / activeFlows.size());
stats.setAverageFlowSize(totalBytes / activeFlows.size());
}
return stats;
}
}
class NetworkFlow {
private final String flowKey;
private final InetAddress srcIp;
private final InetAddress dstIp;
private final int srcPort;
private final int dstPort;
private final byte protocol;
private final long startTime;
private long lastActivity;
private long packetCount;
private long totalBytes;
private long srcToDstBytes;
private long dstToSrcBytes;
private Set<TcpPacket.TcpFlags> observedFlags;
public NetworkFlow(PacketInfo packetInfo) {
this.flowKey = packetInfo.getFlowKey();
this.srcIp = packetInfo.getSrcIp();
this.dstIp = packetInfo.getDstIp();
this.srcPort = packetInfo.getSrcPort();
this.dstPort = packetInfo.getDstPort();
this.protocol = packetInfo.getProtocol();
this.startTime = System.currentTimeMillis();
this.lastActivity = startTime;
this.packetCount = 0;
this.totalBytes = 0;
this.srcToDstBytes = 0;
this.dstToSrcBytes = 0;
this.observedFlags = new HashSet<>();
}
public void update(PacketInfo packetInfo) {
lastActivity = System.currentTimeMillis();
packetCount++;
totalBytes += packetInfo.getLength();
// Track direction
if (packetInfo.getSrcIp().equals(srcIp)) {
srcToDstBytes += packetInfo.getLength();
} else {
dstToSrcBytes += packetInfo.getLength();
}
// Track TCP flags
if (packetInfo.getTcpFlags() != null) {
observedFlags.add(packetInfo.getTcpFlags());
}
}
// Getters
public String getFlowKey() { return flowKey; }
public InetAddress getSrcIp() { return srcIp; }
public InetAddress getDstIp() { return dstIp; }
public int getSrcPort() { return srcPort; }
public int getDstPort() { return dstPort; }
public byte getProtocol() { return protocol; }
public long getStartTime() { return startTime; }
public long getLastActivity() { return lastActivity; }
public long getPacketCount() { return packetCount; }
public long getTotalBytes() { return totalBytes; }
public long getSrcToDstBytes() { return srcToDstBytes; }
public long getDstToSrcBytes() { return dstToSrcBytes; }
public Set<TcpPacket.TcpFlags> getObservedFlags() { return observedFlags; }
public long getDuration() {
return lastActivity - startTime;
}
public double getBytesPerSecond() {
long durationSeconds = getDuration() / 1000;
return durationSeconds > 0 ? (double) totalBytes / durationSeconds : 0;
}
public boolean isActive() {
return (System.currentTimeMillis() - lastActivity) < 300000; // 5 minutes
}
}
class FlowStatistics {
private int totalFlows;
private int totalHosts;
private int totalPorts;
private long averageFlowDuration;
private long averageFlowSize;
// Getters and setters
public int getTotalFlows() { return totalFlows; }
public void setTotalFlows(int totalFlows) { this.totalFlows = totalFlows; }
public int getTotalHosts() { return totalHosts; }
public void setTotalHosts(int totalHosts) { this.totalHosts = totalHosts; }
public int getTotalPorts() { return totalPorts; }
public void setTotalPorts(int totalPorts) { this.totalPorts = totalPorts; }
public long getAverageFlowDuration() { return averageFlowDuration; }
public void setAverageFlowDuration(long averageFlowDuration) { this.averageFlowDuration = averageFlowDuration; }
public long getAverageFlowSize() { return averageFlowSize; }
public void setAverageFlowSize(long averageFlowSize) { this.averageFlowSize = averageFlowSize; }
}
Security Detection
Security Detector
```java
package com.example.traffic.analysis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class SecurityDetector {
private static final Logger logger = LoggerFactory.getLogger(SecurityDetector.class);
private final Map<String, AtomicInteger> suspiciousHosts;
private final Map<String, AtomicInteger> portScanAttempts;
private final Set<Integer> monitoredPorts;
private final AnomalyDetector anomalyDetector;
// Security thresholds
private static final int PORT_SCAN_THRESHOLD = 10;
private static final int SUSPICIOUS_PACKET_THRESHOLD = 5;
private static final long TIME_WINDOW_MS = 60000; // 1 minute
public SecurityDetector() {
this.suspiciousHosts = new ConcurrentHashMap<>();
this.portScanAttempts = new ConcurrentHashMap<>();
this.monitoredPorts = new HashSet<>(Arrays.asList(22, 23, 80, 443, 3389, 5900));
this.anomalyDetector = new AnomalyDetector();
}
public void analyzeForThreats(PacketInfo packetInfo) {
detectPortScans(packetInfo);
detectSuspiciousFlags(packetInfo);
detectProtocolAnomalies(packetInfo);
detectFloodingAttacks(packetInfo);
anomalyDetector.analyzePacket(packetInfo);
}
private void detectPortScans(PacketInfo packetInfo) {
if (packetInfo.getDstPort() > 0 && monitoredPorts.contains(packetInfo.getDstPort())) {
String hostKey = packetInfo.getSrcIp().getHostAddress();
String scanKey = hostKey + "-" + packetInfo.getDstPort();
AtomicInteger count = portScanAttempts.computeIfAbsent(scanKey,
k -> new AtomicInteger(0));
int attempts = count.incrementAndGet();
if (attempts >= PORT_SCAN_THRESHOLD) {
logger.warn("Potential port scan detected from {} to port {}",
hostKey, packetInfo.getDstPort());
// Reset counter after detection
count.set(0);
}
}
}
private void detectSuspiciousFlags(PacketInfo packetInfo) {
if (packetInfo.getTcpFlags() != null) {
// NULL scan detection
if (packetInfo.getTcpFlags().isEmpty()) {
logSuspiciousActivity(packetInfo, "NULL scan detected");
}
// FIN scan detection
if (packetInfo.getTcpFlags().contains(TcpPacket.TcpFlag.FIN) &&
!packetInfo.getTcpFlags().contains(Tcp
Advanced Java Supply Chain Security, Kubernetes Hardening & Runtime Threat Detection
Sigstore Rekor in Java – https://macronepal.com/blog/sigstore-rekor-in-java/
Explains integrating Sigstore Rekor into Java systems to create a transparent, tamper-proof log of software signatures and metadata for verifying supply chain integrity.
Securing Java Applications with Chainguard Wolfi – https://macronepal.com/blog/securing-java-applications-with-chainguard-wolfi-a-comprehensive-guide/
Explains using Chainguard Wolfi minimal container images to reduce vulnerabilities and secure Java applications with hardened, lightweight runtime environments.
Cosign Image Signing in Java Complete Guide – https://macronepal.com/blog/cosign-image-signing-in-java-complete-guide/
Explains how to digitally sign container images using Cosign in Java-based workflows to ensure authenticity and prevent unauthorized modifications.
Secure Supply Chain Enforcement Kyverno Image Verification for Java Containers – https://macronepal.com/blog/secure-supply-chain-enforcement-kyverno-image-verification-for-java-containers/
Explains enforcing Kubernetes policies with Kyverno to verify container image signatures and ensure only trusted Java container images are deployed.
Pod Security Admission in Java Securing Kubernetes Deployments for JVM Applications – https://macronepal.com/blog/pod-security-admission-in-java-securing-kubernetes-deployments-for-jvm-applications/
Explains Kubernetes Pod Security Admission policies that enforce security rules like restricted privileges and safe configurations for Java workloads.
Securing Java Applications at Runtime Kubernetes Security Context – https://macronepal.com/blog/securing-java-applications-at-runtime-a-guide-to-kubernetes-security-context/
Explains how Kubernetes security contexts control runtime permissions, user IDs, and access rights for Java containers to improve isolation.
Process Anomaly Detection in Java Behavioral Monitoring – https://macronepal.com/blog/process-anomaly-detection-in-java-comprehensive-behavioral-monitoring-2/
Explains detecting abnormal runtime behavior in Java applications to identify potential security threats using process monitoring techniques.
Achieving Security Excellence CIS Benchmark Compliance for Java Applications – https://macronepal.com/blog/achieving-security-excellence-implementing-cis-benchmark-compliance-for-java-applications/
Explains applying CIS security benchmarks to Java environments to standardize hardening and improve overall system security posture.
Process Anomaly Detection in Java Behavioral Monitoring – https://macronepal.com/blog/process-anomaly-detection-in-java-comprehensive-behavioral-monitoring/
Explains behavioral monitoring of Java processes to detect anomalies and improve runtime security through continuous observation and analysis.