Temporary fix for router's IP as client for WAN trace and paths for new tests for...
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / Conversation.java
index c227ce7f5f53ce9ea463d8a331abefda1ea5b48b..490dc4f53264ee40f9b3e7c3d995d9482902cbd0 100644 (file)
@@ -1,8 +1,10 @@
 package edu.uci.iotproject;
 
+import edu.uci.iotproject.analysis.TcpConversationUtils;
 import edu.uci.iotproject.util.PcapPacketUtils;
 import org.pcap4j.core.PcapPacket;
 import org.pcap4j.packet.IpV4Packet;
+import org.pcap4j.packet.Packet;
 import org.pcap4j.packet.TcpPacket;
 
 import java.util.*;
@@ -47,6 +49,12 @@ public class Conversation {
      */
     private final List<PcapPacket> mPackets;
 
+    /**
+     * If {@link #isTls()} is {@code true}, this list contains the subset of {@link #mPackets} which are TLS Application
+     * Data packets.
+     */
+    private final List<PcapPacket> mTlsApplicationDataPackets;
+
     /**
      * Contains the sequence numbers used thus far by the host that is considered the <em>client</em> in this
      * {@code Conversation}.
@@ -75,6 +83,11 @@ public class Conversation {
      * List of RST packets associated with this conversation.
      */
     private final List<PcapPacket> mRstPackets;
+
+    /**
+     * Boolean to mark the packet as Application Data based on the previous packet that reaches MTU
+     */
+    private boolean mApplicationData;
     /* End instance properties */
 
     /**
@@ -114,11 +127,13 @@ public class Conversation {
         this.mServerIp = serverIp;
         this.mServerPort = serverPort;
         this.mPackets = new ArrayList<>();
+        this.mTlsApplicationDataPackets = new ArrayList<>();
         this.mSeqNumbersClient = new HashSet<>();
         this.mSeqNumbersSrv = new HashSet<>();
         this.mSynPackets = new ArrayList<>();
         this.mFinPackets = new ArrayList<>();
         this.mRstPackets = new ArrayList<>();
+        this.mApplicationData = false;
     }
 
     /**
@@ -150,6 +165,41 @@ public class Conversation {
                 else { return 0; }
             });
         }
+        // If TLS, inspect packet to see if it's a TLS Application Data packet, and if so add it to the list of TLS
+        // Application Data packets.
+        if (isTls()) {
+            TcpPacket tcpPacket = packet.get(TcpPacket.class);
+            Packet tcpPayload = tcpPacket.getPayload();
+            if (tcpPayload == null) {
+                return;
+            }
+            byte[] rawPayload = tcpPayload.getRawData();
+            // The SSL record header is at the front of the payload and is 5 bytes long.
+            // The SSL record header type field (the first byte) is set to 23 if it is an Application Data packet.
+            if (rawPayload != null && rawPayload.length >= 5) {
+                if (rawPayload[0] == 23) {
+                    mTlsApplicationDataPackets.add(packet);
+                    // Consider the following packet a data packet if this packet's size == MTU size 1448
+                    if (rawPayload.length >= 1448)
+                        mApplicationData = true;
+                } else if (rawPayload[0] == 20) {
+                    // Do nothing for now - CHANGE_CIPHER_SPEC
+                } else if (rawPayload[0] == 21) {
+                    // Do nothing for now - ALERT
+                } else if (rawPayload[0] == 22) {
+                    // Do nothing for now - HANDSHAKE
+                } else {
+                    // If it is TLS with payload, but rawPayload[0] != 23
+                    if (mApplicationData == true) {
+                        // It is a continuation of the previous packet if the previous packet reaches MTU size 1448 and
+                        // it is not either type 20, 21, or 22
+                        mTlsApplicationDataPackets.add(packet);
+                        if (rawPayload.length < 1448)
+                            mApplicationData = false;
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -412,6 +462,48 @@ public class Conversation {
         }
     }
 
+    /**
+     * <p>
+     *     Is this {@code Conversation} a TLS session?
+     * </p>
+     *
+     * <em>Note: the current implementation simply examines the port number(s) for 443; it does <b>not</b> verify if the
+     * application data is indeed encrypted.</em>
+     *
+     * @return {@code true} if this {@code Conversation} is interpreted as a TLS session, {@code false} otherwise.
+     */
+    public boolean isTls() {
+        /*
+         * TODO:
+         * - may want to change this to be "return mServerPort == 443 || mClientPort == 443;" in order to also detect
+         *   TLS in those cases where it is not possible to correctly label who is the client and who is the server,
+         *   i.e., when the trace does not contain the SYN/SYNACK exchange.
+         * - current implementation relies on the server using the conventional TLS port number; may instead want to
+         *   inspect the first 4 bytes of each potential TLS packet to see if they match the SSL record header.
+         *
+         * 08/31/18: Added unconvetional TLS ports used by WeMo plugs and LiFX bulb.
+         * 09/20/18: Moved hardcoded ports to other class to allow other classes to query the set of TLS ports.
+         */
+        return TcpConversationUtils.isTlsPort(mServerPort);
+    }
+
+    /**
+     * If this {@code Conversation} is backing a TLS session (i.e., if the value of {@link #isTls()} is {@code true}),
+     * get the packets labeled as TLS Application Data packets. This is a subset of the full set of payload-carrying
+     * packets (as returned by {@link #getPackets()}). An exception is thrown if this method is invoked on a
+     * {@code Conversation} for which {@link #isTls()} returns {@code false}.
+     *
+     * @return A list containing exactly those packets that could be identified as TLS Application Data packets (through
+     *         inspecting of the SSL record header). The list may be empty, if no TLS application data packets have been
+     *         recorded for this {@code Conversation}.
+     */
+    public List<PcapPacket> getTlsApplicationDataPackets() {
+        if (!isTls()) {
+            throw new NoSuchElementException("cannot get TLS Application Data packets for non-TLS TCP conversation");
+        }
+        return Collections.unmodifiableList(mTlsApplicationDataPackets);
+    }
+
     /**
      * Extracts the TCP sequence number from {@code packet} and adds it to the proper set of sequence numbers by
      * analyzing the direction of the packet.
@@ -442,11 +534,13 @@ public class Conversation {
     }
 
     /**
-     * Determine the direction of {@code packet}.
+     * Determine the direction of {@code packet}. An {@link IllegalArgumentException} is thrown if {@code packet} does
+     * not pertain to this conversation.
+     *
      * @param packet The packet whose direction is to be determined.
      * @return A {@link Direction} indicating the direction of the packet.
      */
-    private Direction getDirection(PcapPacket packet) {
+    public Direction getDirection(PcapPacket packet) {
         IpV4Packet ipPacket = packet.get(IpV4Packet.class);
         String ipSrc = ipPacket.getHeader().getSrcAddr().getHostAddress();
         String ipDst = ipPacket.getHeader().getDstAddr().getHostAddress();
@@ -465,8 +559,27 @@ public class Conversation {
     /**
      * Utility enum for expressing the direction of a packet pertaining to this {@code Conversation}.
      */
-    private enum Direction {
-        CLIENT_TO_SERVER, SERVER_TO_CLIENT
+    public enum Direction {
+
+        CLIENT_TO_SERVER {
+            @Override
+            public String toCompactString() {
+                return "*";
+            }
+        },
+        SERVER_TO_CLIENT {
+            @Override
+            public String toCompactString() {
+                return "";
+            }
+        };
+
+        /**
+         * Get a compact string representation of this {@code Direction}.
+         * @return a compact string representation of this {@code Direction}.
+         */
+        abstract public String toCompactString();
+
     }
 
-}
\ No newline at end of file
+}