Added support for extracting packet pairs of only TLS Application Data packets (see...
authorJanus Varmarken <varmarken@gmail.com>
Tue, 11 Sep 2018 00:33:49 +0000 (17:33 -0700)
committerJanus Varmarken <varmarken@gmail.com>
Tue, 11 Sep 2018 00:34:01 +0000 (17:34 -0700)
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketPair.java
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TcpConversationUtils.java
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PcapPacketUtils.java
Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PrintUtils.java [new file with mode: 0644]

index 1d2889566fb625515cf39ee611a452ea656352a5..db5c839c4d9028988a0a36138c0b971646733886 100644 (file)
@@ -3,9 +3,10 @@ package edu.uci.iotproject.analysis;
 import org.pcap4j.core.PcapPacket;
 
 /**
- * TODO add class documentation.
+ * A simple wrapper for holding a pair of packets (e.g., a request and associated reply packet).
  *
- * @author Janus Varmarken
+ * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
+ * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
  */
 public class PcapPacketPair {
 
@@ -24,6 +25,7 @@ public class PcapPacketPair {
 
     @Override
     public String toString() {
-        return getFirst().length() + ", "  + (getSecond() == null ? "null" : getSecond().length());
+        return getFirst().getOriginalLength() + ", "  + (getSecond() == null ? "null" : getSecond().getOriginalLength());
     }
+
 }
index 470b15f2e2ea0bbb133597d77b25fca31dd8d20c..9e25d1dd4159dc378fa6c930f55ac83d8327a33f 100644 (file)
@@ -24,17 +24,43 @@ public class TcpConversationUtils {
     /**
      * <p>
      *      Given a {@link Conversation}, extract its set of "packet pairs", i.e., pairs of request-reply packets.
+     *      <em>The extracted pairs are formed from the full set of payload-carrying TCP packets.</em>
      * </p>
      *
      * <b>Note:</b> in the current implementation, if one endpoint sends multiple packets back-to-back with no
      * interleaved reply packets from the other endpoint, such packets are converted to one-item pairs (i.e., instances
-     * of {@lin PcapPacketPair} where {@link PcapPacketPair#getSecond()} is {@code null}).
+     * of {@link PcapPacketPair} where {@link PcapPacketPair#getSecond()} is {@code null}).
      *
      * @param conv The {@code Conversation} for which packet pairs are to be extracted.
      * @return The packet pairs extracted from {@code conv}.
      */
     public static List<PcapPacketPair> extractPacketPairs(Conversation conv) {
-        List<PcapPacket> packets = conv.getPackets();
+        return extractPacketPairs(conv.getPackets());
+    }
+
+
+    /**
+     * <p>
+     *      Given a {@link Conversation}, extract its set of "packet pairs", i.e., pairs of request-reply packets.
+     *      <em>The extracted pairs are formed from the full set of TLS Application Data packets.</em>
+     * </p>
+     *
+     * <b>Note:</b> in the current implementation, if one endpoint sends multiple packets back-to-back with no
+     * interleaved reply packets from the other endpoint, such packets are converted to one-item pairs (i.e., instances
+     * of {@link PcapPacketPair} where {@link PcapPacketPair#getSecond()} is {@code null}).
+     *
+     * @param conv The {@code Conversation} for which packet pairs are to be extracted.
+     * @return The packet pairs extracted from {@code conv}.
+     */
+    public static List<PcapPacketPair> extractTlsAppDataPacketPairs(Conversation conv) {
+        if (!conv.isTls()) {
+            throw new IllegalArgumentException(String.format("Provided %s argument is not a TLS session"));
+        }
+        return extractPacketPairs(conv.getTlsApplicationDataPackets());
+    }
+
+    // Helper method for implementing the public API of similarly named methods.
+    private static List<PcapPacketPair> extractPacketPairs(List<PcapPacket> packets) {
         List<PcapPacketPair> pairs = new ArrayList<>();
         int i = 0;
         while (i < packets.size()) {
index 311fc6669e377e6e5d06e39ec4af917437d92c58..8f998eea3c8d3878c222fe63decd7c9e85d93491 100644 (file)
@@ -14,6 +14,17 @@ import java.util.Objects;
  */
 public final class PcapPacketUtils {
 
+    /**
+     * Gets the source IP (in decimal format) of an IPv4 packet.
+     * @param packet The packet for which the IPv4 source address is to be extracted.
+     * @return The decimal representation of the source IP of {@code packet} <em>iff</em> {@code packet} wraps an
+     *         {@link IpV4Packet}, otherwise {@code null}.
+     */
+    public static String getSourceIp(PcapPacket packet) {
+        IpV4Packet ipPacket = packet.get(IpV4Packet.class);
+        return ipPacket == null ? null : ipPacket.getHeader().getSrcAddr().getHostAddress();
+    }
+
     /**
      * Helper method to determine if the given combination of IP and port matches the source of the given packet.
      * @param packet The packet to check.
diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PrintUtils.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PrintUtils.java
new file mode 100644 (file)
index 0000000..75a0035
--- /dev/null
@@ -0,0 +1,68 @@
+package edu.uci.iotproject.util;
+
+import edu.uci.iotproject.DnsMap;
+import edu.uci.iotproject.analysis.PcapPacketPair;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Utility methods for generating (output) strings.
+ *
+ * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
+ * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
+ */
+public class PrintUtils {
+
+    private PrintUtils() { /* private constructor to prevent instantiation */ }
+
+
+    /**
+     * Converts a {@code PcapPacketPair} into a CSV string containing the packet lengths of the two packets in the pair.
+     *
+     * For example, the resulting string will be "123, 456" if the first packet of the pair has a length of 123 and the
+     * second packet of the pair has a length of 456.
+     *
+     * @return a CSV string containing the packet lengths of the two packets of the given {@code PcapPacketPair}.
+     */
+    public static String toCsv(PcapPacketPair packetPair) {
+        return String.format("%d, %d", packetPair.getFirst().getOriginalLength(),
+                packetPair.getSecond().getOriginalLength());
+    }
+
+    /**
+     * Converts a {@code PcapPacketPair} into a CSV string containing the packet lengths of the two packets in the pair
+     * followed by the source of each packet. The source will be a (set of) hostname(s) if the source IP can be resolved
+     * to a (set of) hostname(s) using the provided {@link DnsMap}.
+     *
+     * For example, the resulting string will be "123, 456, 192.168.1.42, domain.com" if the first packet of the pair
+     * has a length of 123, the second packet of the pair has a length of 456, the first packet of the pair the pair has
+     * a source IP of '192.168.1.42' that cannot be resolved to a hostname, and the second packet of the pair has an IP
+     * that resolves to 'domain.com'.
+     *
+     * @return a CSV string containing the packet lengths of the two packets of the given {@code PcapPacketPair} as well
+     *         as their respective sources.
+     */
+    public static String toCsv(PcapPacketPair packetPair, DnsMap ipHostnameMappings) {
+        // First optain source IPs
+        String firstSrc = PcapPacketUtils.getSourceIp(packetPair.getFirst());
+        String secondSrc = PcapPacketUtils.getSourceIp(packetPair.getSecond());
+
+        // If possible, map source IPs to hostnames.
+        Set<String> firstHostnames = ipHostnameMappings.getHostnamesForIp(firstSrc);
+        Set<String> secondHostnames = ipHostnameMappings.getHostnamesForIp(secondSrc);
+        final String delimiter = " ";
+        if (firstHostnames != null) {
+            // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter)
+            firstSrc = firstHostnames.stream().collect(Collectors.joining(delimiter));
+        }
+        if (secondHostnames != null) {
+            // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter)
+            secondSrc = secondHostnames.stream().collect(Collectors.joining(delimiter));
+        }
+
+        return String.format("%d, %d, %s, %s", packetPair.getFirst().getOriginalLength(),
+                packetPair.getSecond().getOriginalLength(), firstSrc, secondSrc);
+    }
+
+}