First small step towards pattern search: separate packets related to packet into...
authorJanus Varmarken <varmarken@gmail.com>
Sun, 29 Apr 2018 01:46:40 +0000 (18:46 -0700)
committerJanus Varmarken <varmarken@gmail.com>
Sun, 29 Apr 2018 01:46:40 +0000 (18:46 -0700)
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPattern.java [new file with mode: 0644]
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPatternFinder.java [new file with mode: 0644]
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java

diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPattern.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPattern.java
new file mode 100644 (file)
index 0000000..4b5b8fe
--- /dev/null
@@ -0,0 +1,43 @@
+package edu.uci.iotproject;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * TODO add class documentation.
+ *
+ * @author Janus Varmarken
+ */
+public class FlowPattern {
+
+    private final String patternId;
+
+    /**
+     * The hostname that this {@code FlowPattern} is associated with.
+     */
+    private final String hostname;
+
+    /**
+     * The order of packet lengths that defines this {@link FlowPattern}
+     */
+    private final List<Integer> flowPacketOrder;
+
+    public FlowPattern(String patternId, String hostname, List<Integer> flowPacketOrder) {
+        this.patternId = patternId;
+        this.hostname = hostname;
+        this.flowPacketOrder = Collections.unmodifiableList(flowPacketOrder);
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    /**
+     * Get the the sequence of packet lengths that defines this {@code FlowPattern}.
+     * @return the the sequence of packet lengths that defines this {@code FlowPattern}.
+     */
+    public List<Integer> getPacketOrder() {
+        return flowPacketOrder;
+    }
+
+}
diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPatternFinder.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPatternFinder.java
new file mode 100644 (file)
index 0000000..1732b99
--- /dev/null
@@ -0,0 +1,111 @@
+package edu.uci.iotproject;
+
+import org.pcap4j.core.NotOpenException;
+import org.pcap4j.core.PcapHandle;
+import org.pcap4j.core.PcapNativeException;
+import org.pcap4j.packet.IpV4Packet;
+import org.pcap4j.packet.Packet;
+import org.pcap4j.packet.TcpPacket;
+
+import java.io.EOFException;
+import java.util.*;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Provides functionality for searching for the presence of a {@link FlowPattern} in a PCAP trace.
+ *
+ * @author Janus Varmarken
+ */
+public class FlowPatternFinder {
+
+    private final Map<String, Set<String>> dnsMap;
+    private final Map<Conversation, List<Packet>> connections = new HashMap<>();
+
+    public FlowPatternFinder(Map<String, Set<String>> dnsMap) {
+        this.dnsMap = Objects.requireNonNull(dnsMap);
+    }
+
+    private static final Set<String> EMPTY_SET = Collections.unmodifiableSet(new HashSet<>());
+
+    // TODO clean up exceptions etc.
+    public void findFlowPattern(PcapHandle pcap, FlowPattern pattern)
+            throws PcapNativeException, NotOpenException, TimeoutException {
+        try {
+            Packet packet;
+            while ((packet = pcap.getNextPacketEx()) != null) {
+
+
+                // For now, we only work support pattern search in TCP over IPv4.
+                IpV4Packet ipPacket = packet.get(IpV4Packet.class);
+                TcpPacket tcpPacket = packet.get(TcpPacket.class);
+                if (ipPacket == null || tcpPacket == null) {
+                    continue;
+                }
+                String srcAddress = ipPacket.getHeader().getSrcAddr().getHostAddress();
+                String dstAddress = ipPacket.getHeader().getDstAddr().getHostAddress();
+                int srcPort = tcpPacket.getHeader().getSrcPort().valueAsInt();
+                int dstPort = tcpPacket.getHeader().getDstPort().valueAsInt();
+                // Is this packet related to the pattern and coming from the cloud server?
+                boolean fromServer = dnsMap.getOrDefault(srcAddress, EMPTY_SET).contains(pattern.getHostname());
+                // Is this packet related to the pattern and going to the cloud server?
+                boolean fromClient = dnsMap.getOrDefault(dstAddress, EMPTY_SET).contains(pattern.getHostname());
+                if (!fromServer && !fromClient) {
+                    // Packet not related to pattern, skip it.
+                    continue;
+                }
+                // Identify conversations (connections/sessions) by the four-tuple (clientIp, clientPort, serverIp, serverPort).
+                // TODO: this is strictly not sufficient to differentiate one TCP session from another, but should suffice for now.
+                Conversation conversation = fromClient ? new Conversation(srcAddress, srcPort, dstAddress, dstPort) :
+                        new Conversation(dstAddress, dstPort, srcAddress, srcPort);
+                List<Packet> listWrappedPacket = new ArrayList<>();
+                listWrappedPacket.add(packet);
+                // Create new conversation entry, or append packet to existing.
+                connections.merge(conversation, listWrappedPacket, (v1, v2) -> {
+                    v1.addAll(v2);
+                    return v1;
+                });
+            }
+        } catch (EOFException eofe) {
+            System.out.println("findFlowPattern: finished processing entire file");
+        }
+    }
+
+    /**
+     * Immutable class used for identifying a conversation/connection/session/flow (packet's belonging to the same
+     * session between a client and a server).
+     */
+    private static class Conversation {
+
+        private final String clientIp;
+        private final int clientPort;
+        private final String serverIp;
+        private final int serverPort;
+
+        public Conversation(String clientIp, int clientPort, String serverIp, int serverPort) {
+            this.clientIp = clientIp;
+            this.clientPort = clientPort;
+            this.serverIp = serverIp;
+            this.serverPort = serverPort;
+        }
+
+
+        // =========================================================================================================
+        // We simply reuse equals and hashCode methods of String.class to be able to use this immutable class as a key
+        // in a Map.
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof Conversation && this.toString().equals(obj.toString());
+        }
+        @Override
+        public int hashCode() {
+            return toString().hashCode();
+        }
+        // =========================================================================================================
+
+        @Override
+        public String toString() {
+            return String.format("%s:%d %s:%d", clientIp, clientPort, serverIp, serverPort);
+        }
+    }
+
+}
index d82e134..18bb582 100644 (file)
@@ -29,7 +29,20 @@ public class Main {
         final String fileName = "/users/varmarken/Desktop/wlan1.local.dns.pcap";
         List<DnsPacket> dnsPackets = extractDnsAnswerPackets(fileName);
         Map<String, Set<String>> ipToHostnameMap = constructIpToHostnameMap(dnsPackets);
-        ipToHostnameMap.forEach((k,v) -> System.out.println(String.format("%s => %s", k, v.toString())));
+//        ipToHostnameMap.forEach((k,v) -> System.out.println(String.format("%s => %s", k, v.toString())));
+
+
+        // ====== Debug code ======
+        PcapHandle handle;
+        try {
+            handle = Pcaps.openOffline(fileName, PcapHandle.TimestampPrecision.NANO);
+        } catch (PcapNativeException pne) {
+            handle = Pcaps.openOffline(fileName);
+        }
+        FlowPatternFinder fpf = new FlowPatternFinder(ipToHostnameMap);
+        fpf.findFlowPattern(handle, new FlowPattern("TP_LINK_LOCAL_ON", "events.tplinkra.com", new ArrayList<>()));
+
+        // ========================
     }
 
     /**
@@ -108,6 +121,8 @@ public class Main {
         return result;
     }
 
+
+
 //    /**
 //     * Private class properties
 //     */