Implement grouping of conversations by hostname
authorJanus Varmarken <varmarken@gmail.com>
Wed, 25 Jul 2018 22:16:21 +0000 (15:16 -0700)
committerJanus Varmarken <varmarken@gmail.com>
Wed, 25 Jul 2018 22:16:21 +0000 (15:16 -0700)
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsMap.java
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TcpConversationUtils.java

index d88f0cfbb553392636b5ae2b501b4333203555bf..0db01f8e7fe50470fac848b7ea8bb72effb735ed 100644 (file)
@@ -103,4 +103,9 @@ public class DnsMap implements PacketListener {
     public boolean isRelatedToCloudServer(String address, String hostname) {
         return ipToHostnameMap.getOrDefault(address, EMPTY_SET).contains(hostname);
     }
+
+    public Set<String> getHostnamesForIp(String ip) {
+        Set<String> hostnames = ipToHostnameMap.get(ip);
+        return hostnames != null ? Collections.unmodifiableSet(hostnames) : null;
+    }
 }
index c96e36ad0a6bfd2c0e55601bd40c323974933fcc..4a05501aaa3a7f36a8d129bc784cf375f02e3454 100644 (file)
@@ -11,10 +11,7 @@ import org.pcap4j.packet.namednumber.DataLinkType;
 import java.io.EOFException;
 import java.net.UnknownHostException;
 import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -222,7 +219,9 @@ public class Main {
         }
         System.out.println("packet length frequency map created");
 
-
+        Map<String, List<Conversation>> hostnameConversationMap =
+                TcpConversationUtils.groupConversationsByHostname(tcpReassembler.getTcpConversations(), dnsMap);
+        System.out.println("hostnameConversationMap created");
         // ----------------------------
     }
 
index a598f81ccc19953dd323cdc13d96be7cc04264ad..2f5f4157a19d0b9fd3c2779908e6cfe777b16481 100644 (file)
@@ -1,13 +1,13 @@
 package edu.uci.iotproject.analysis;
 
 import edu.uci.iotproject.Conversation;
+import edu.uci.iotproject.DnsMap;
 import edu.uci.iotproject.util.PcapPacketUtils;
 import org.pcap4j.core.PcapPacket;
 import org.pcap4j.packet.IpV4Packet;
 import org.pcap4j.packet.TcpPacket;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
 
 /**
  * TODO add class documentation.
@@ -48,4 +48,53 @@ public class TcpConversationUtils {
         // TODO: what if there is long time between response and reply packet? Should we add a threshold and exclude those cases?
     }
 
+
+    public static Map<String, List<Conversation>> groupConversationsByHostname(List<Conversation> tcpConversations, DnsMap ipHostnameMappings) {
+        HashMap<String, List<Conversation>> result = new HashMap<>();
+        for (Conversation c : tcpConversations) {
+            if (c.getPackets().size() == 0) {
+                String warningStr = String.format("Detected a %s [%s] with no payload packets.",
+                        c.getClass().getSimpleName(), c.toString());
+                System.err.println(warningStr);
+                continue;
+            }
+            IpV4Packet firstPacketIp = c.getPackets().get(0).get(IpV4Packet.class);
+            String ipSrc = firstPacketIp.getHeader().getSrcAddr().getHostAddress();
+            String ipDst = firstPacketIp.getHeader().getDstAddr().getHostAddress();
+            // Check if src or dst IP is associated with one or more hostnames.
+            Set<String> hostnames = ipHostnameMappings.getHostnamesForIp(ipSrc);
+            if (hostnames == null) {
+                // No luck with src ip (possibly because it's a client->srv packet), try dst ip.
+                hostnames = ipHostnameMappings.getHostnamesForIp(ipDst);
+            }
+            if (hostnames != null) {
+                // Put a reference to the conversation for each of the hostnames that the conversation's IP maps to.
+                for (String hostname : hostnames) {
+                    List<Conversation> newValue = new ArrayList<>();
+                    newValue.add(c);
+                    result.merge(hostname, newValue, (l1, l2) -> { l1.addAll(l2); return l1; });
+                }
+                if (hostnames.size() > 1) {
+                    // Print notice of IP mapping to multiple hostnames (debugging)
+                    System.err.println(String.format("%s: encountered an IP that maps to multiple (%d) hostnames",
+                            TcpConversationUtils.class.getSimpleName(), hostnames.size()));
+                }
+            } else {
+                // If no hostname mapping, store conversation under the key that is the concatenation of the two IPs.
+                // In order to ensure consistency when mapping conversations, use lexicographic order to select which IP
+                // goes first.
+                String delimiter = "_";
+                // Note that the in case the comparison returns 0, the strings are equal, so it doesn't matter which of
+                // ipSrc and ipDst go first (also, this case should not occur in practice as it means that the device is
+                // communicating with itself!)
+                String key = ipSrc.compareTo(ipDst) <= 0 ? ipSrc + delimiter + ipDst : ipDst + delimiter + ipSrc;
+                List<Conversation> newValue = new ArrayList<>();
+                newValue.add(c);
+                result.merge(key, newValue, (l1, l2) -> { l1.addAll(l2); return l1; });
+            }
+        }
+        return result;
+    }
+
+
 }