1 package edu.uci.iotproject;
3 import org.pcap4j.core.NotOpenException;
4 import org.pcap4j.core.PcapHandle;
5 import org.pcap4j.core.PcapNativeException;
6 import org.pcap4j.packet.IpV4Packet;
7 import org.pcap4j.packet.Packet;
8 import org.pcap4j.packet.TcpPacket;
10 import java.io.EOFException;
12 import java.util.concurrent.TimeoutException;
15 * Provides functionality for searching for the presence of a {@link FlowPattern} in a PCAP trace.
17 * @author Janus Varmarken
19 public class FlowPatternFinder {
21 private final Map<String, Set<String>> dnsMap;
22 private final Map<Conversation, List<Packet>> connections = new HashMap<>();
24 public FlowPatternFinder(Map<String, Set<String>> dnsMap) {
25 this.dnsMap = Objects.requireNonNull(dnsMap);
28 private static final Set<String> EMPTY_SET = Collections.unmodifiableSet(new HashSet<>());
30 // TODO clean up exceptions etc.
31 public void findFlowPattern(PcapHandle pcap, FlowPattern pattern)
32 throws PcapNativeException, NotOpenException, TimeoutException {
35 while ((packet = pcap.getNextPacketEx()) != null) {
38 // For now, we only work support pattern search in TCP over IPv4.
39 IpV4Packet ipPacket = packet.get(IpV4Packet.class);
40 TcpPacket tcpPacket = packet.get(TcpPacket.class);
41 if (ipPacket == null || tcpPacket == null) {
44 String srcAddress = ipPacket.getHeader().getSrcAddr().getHostAddress();
45 String dstAddress = ipPacket.getHeader().getDstAddr().getHostAddress();
46 int srcPort = tcpPacket.getHeader().getSrcPort().valueAsInt();
47 int dstPort = tcpPacket.getHeader().getDstPort().valueAsInt();
48 // Is this packet related to the pattern and coming from the cloud server?
49 boolean fromServer = dnsMap.getOrDefault(srcAddress, EMPTY_SET).contains(pattern.getHostname());
50 // Is this packet related to the pattern and going to the cloud server?
51 boolean fromClient = dnsMap.getOrDefault(dstAddress, EMPTY_SET).contains(pattern.getHostname());
52 if (!fromServer && !fromClient) {
53 // Packet not related to pattern, skip it.
56 // Identify conversations (connections/sessions) by the four-tuple (clientIp, clientPort, serverIp, serverPort).
57 // TODO: this is strictly not sufficient to differentiate one TCP session from another, but should suffice for now.
58 Conversation conversation = fromClient ? new Conversation(srcAddress, srcPort, dstAddress, dstPort) :
59 new Conversation(dstAddress, dstPort, srcAddress, srcPort);
60 List<Packet> listWrappedPacket = new ArrayList<>();
61 listWrappedPacket.add(packet);
62 // Create new conversation entry, or append packet to existing.
63 connections.merge(conversation, listWrappedPacket, (v1, v2) -> {
68 } catch (EOFException eofe) {
69 System.out.println("findFlowPattern: finished processing entire file");
74 * Immutable class used for identifying a conversation/connection/session/flow (packet's belonging to the same
75 * session between a client and a server).
77 private static class Conversation {
79 private final String clientIp;
80 private final int clientPort;
81 private final String serverIp;
82 private final int serverPort;
84 public Conversation(String clientIp, int clientPort, String serverIp, int serverPort) {
85 this.clientIp = clientIp;
86 this.clientPort = clientPort;
87 this.serverIp = serverIp;
88 this.serverPort = serverPort;
92 // =========================================================================================================
93 // We simply reuse equals and hashCode methods of String.class to be able to use this immutable class as a key
96 public boolean equals(Object obj) {
97 return obj instanceof Conversation && this.toString().equals(obj.toString());
100 public int hashCode() {
101 return toString().hashCode();
103 // =========================================================================================================
106 public String toString() {
107 return String.format("%s:%d %s:%d", clientIp, clientPort, serverIp, serverPort);