Implementing relaxed matching for layer 2 and layer 3.
[pingpong.git] / Code / Projects / PacketLevelSignatureExtractor / src / main / java / edu / uci / iotproject / util / PcapPacketUtils.java
index 2f20945921b25c54f354835f1f0d28d03c7d2a35..68e7defe8d0924e984191a090d0d0a942ca43ea0 100644 (file)
@@ -1,5 +1,6 @@
 package edu.uci.iotproject.util;
 
+import edu.uci.iotproject.io.PrintWriterUtils;
 import edu.uci.iotproject.trafficreassembly.layer3.Conversation;
 import edu.uci.iotproject.analysis.PcapPacketPair;
 import edu.uci.iotproject.analysis.TcpConversationUtils;
@@ -11,6 +12,8 @@ import org.pcap4j.packet.IpV4Packet;
 import org.pcap4j.packet.TcpPacket;
 import org.pcap4j.util.MacAddress;
 
+import java.io.PrintWriter;
+import java.math.BigInteger;
 import java.util.*;
 
 /**
@@ -232,7 +235,11 @@ public final class PcapPacketUtils {
         List<List<List<PcapPacket>>> copySignatures = new ArrayList<>();
         listDeepCopy(copySignatures, signatures);
         // Traverse and look into the pairs.
-        for (int first = 0; first < signatures.size(); first++) {
+        //for (int first = 0; first < signatures.size(); first++) {
+        int first = 0;
+        int signaturesSize = signatures.size();
+        while(first < signaturesSize) {
+//            System.out.println("First: " + first + " Signatures: " + signatures.get(0).size());
             List<List<PcapPacket>> firstList = signatures.get(first);
             for (int second = first+1; second < signatures.size(); second++) {
                 int maxSignatureEl = 0;
@@ -253,7 +260,9 @@ public final class PcapPacketUtils {
                         if (position == TcpConversationUtils.SignaturePosition.LEFT_ADJACENT) {
                             // Merge to the left side of the first sequence.
                             ppList.addAll(signature);
-                            signature = ppList;
+                            // Remove and then add again to keep the same reference
+                            signature.removeAll(signature);
+                            signature.addAll(ppList);
                             maxSignatureEl = signature.size() > maxSignatureEl ? signature.size() : maxSignatureEl;
                             secondList.remove(ppList); // Remove as we merge.
                             break;
@@ -266,6 +275,7 @@ public final class PcapPacketUtils {
                         } // TcpConversationUtils.SignaturePosition.NOT_ADJACENT.
                     }
                 }
+//                System.out.println("First list size: " + firstList.get(35).size());
                 // Call it a successful merging if there are only less than 5 elements from the second list that
                 // cannot be merged.
                 if (secondList.size() < SIGNATURE_MERGE_THRESHOLD) {
@@ -283,17 +293,40 @@ public final class PcapPacketUtils {
                     return copySignatures;
                 }
             }
+            if (signatures.size() < signaturesSize) {
+                // If there is a concatenation, we check again from index 0
+                signaturesSize = signatures.size();
+                first = 0;
+            } else {
+                signaturesSize = signatures.size();
+                first++;
+            }
+
         }
         return signatures;
     }
 
     /**
-     * Deep copy to create an entirely new {@link List} of {@link List} of {@link List} of {@link PcapPacket} objects.
-     * @param destList A {@link List} of {@link List} of {@link List} of
-     *          {@link PcapPacket} objects that will be the final container of the deep copy
-     * @param sourceList A {@link List} of {@link List} of {@link List} of
-     *          {@link PcapPacket} objects that will be the source of the deep copy.
+     * Clean up null values in in {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects.
+     * @param signature A {@link List} of {@link List} of {@link List} of
+     *          {@link PcapPacket} objects that needs to be cleaned up from null values.
      */
+    public static void cleanSignature(List<List<List<PcapPacket>>> signature) {
+
+        for(List<List<PcapPacket>> listOfListPcap : signature) {
+            for(List<PcapPacket> listOfPcap : listOfListPcap) {
+                listOfPcap.removeIf(el -> el == null);
+            }
+        }
+    }
+
+        /**
+         * Deep copy to create an entirely new {@link List} of {@link List} of {@link List} of {@link PcapPacket} objects.
+         * @param destList A {@link List} of {@link List} of {@link List} of
+         *          {@link PcapPacket} objects that will be the final container of the deep copy
+         * @param sourceList A {@link List} of {@link List} of {@link List} of
+         *          {@link PcapPacket} objects that will be the source of the deep copy.
+         */
     private static void listDeepCopy(List<List<List<PcapPacket>>> destList, List<List<List<PcapPacket>>> sourceList) {
 
         for(List<List<PcapPacket>> llPcapPacket : sourceList) {
@@ -346,7 +379,8 @@ public final class PcapPacketUtils {
                 if (Math.abs(timestamp1 - timestamp2) < TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS) {
                     // If these two are within INCLUSION_WINDOW_MILLIS window then compare!
                     compare = p1.get(count1).get(0).getTimestamp().compareTo(p2.get(count2).get(0).getTimestamp());
-                    overlapChecking(compare, comparePrev, p1.get(count1), p2.get(count2));
+                    overlapChecking(compare, comparePrev, p1.get(count1), p2.get(count2),
+                            signatures.indexOf(p1), signatures.indexOf(p2));
                     comparePrev = compare;
                     count1++;
                     count2++;
@@ -370,8 +404,12 @@ public final class PcapPacketUtils {
      * @param comparePrev Previous comparison value between packet sequences p1 and p2
      * @param sequence1 The packet sequence ({@link List} of {@link PcapPacket} objects).
      * @param sequence2 The packet sequence ({@link List} of {@link PcapPacket} objects).
+     * @param indexSequence1 The index of packet sequence ({@link List} of {@link PcapPacket} objects).
+     * @param indexSequence2 The index of packet sequence ({@link List} of {@link PcapPacket} objects).
      */
-    private static void overlapChecking(int compare, int comparePrev, List<PcapPacket> sequence1, List<PcapPacket> sequence2) {
+    private static void overlapChecking(int compare, int comparePrev,
+                                        List<PcapPacket> sequence1, List<PcapPacket> sequence2,
+                                        int indexSequence1, int indexSequence2) {
 
         // Check if p1 occurs before p2 but both have same overlap
         if (comparePrev != 0) { // First time since it is 0
@@ -386,7 +424,13 @@ public final class PcapPacketUtils {
         }
         // Check if p1 is longer than p2 and p2 occurs during the occurrence of p1
         int lastIndexOfSequence1 = sequence1.size() - 1;
+        // Check if the last index is null
+        while (sequence1.get(lastIndexOfSequence1) == null)
+            lastIndexOfSequence1--;
         int lastIndexOfSequence2 = sequence2.size() - 1;
+        // Check if the last index is null
+        while (sequence2.get(lastIndexOfSequence2) == null)
+            lastIndexOfSequence2--;
         int compareLast =
                 sequence1.get(lastIndexOfSequence1).getTimestamp().compareTo(sequence2.get(lastIndexOfSequence2).getTimestamp());
         // Check the signs of compare and compareLast
@@ -431,26 +475,38 @@ public final class PcapPacketUtils {
      *
      * @param signatures A {@link List} of {@link List} of {@link List} of
      *          {@link PcapPacket} objects that needs to be printed.
+     * @param resultsWriter PrintWriter object to write into log file.
+     * @param printToOutput Boolean to decide whether to print out to screen or just log file.
      */
-    public static void printSignatures(List<List<List<PcapPacket>>> signatures) {
+    public static void printSignatures(List<List<List<PcapPacket>>> signatures, PrintWriter resultsWriter, boolean
+                                       printToOutput) {
 
         // Iterate over the list of all clusters/sequences
         int sequenceCounter = 0;
         for(List<List<PcapPacket>> listListPcapPacket : signatures) {
             // Iterate over every member of a cluster/sequence
-            System.out.print("====== SEQUENCE " + ++sequenceCounter);
-            System.out.println(" - " + listListPcapPacket.size() + " MEMBERS ======");
+            PrintWriterUtils.print("====== SEQUENCE " + ++sequenceCounter, resultsWriter, printToOutput);
+            PrintWriterUtils.println(" - " + listListPcapPacket.size() + " MEMBERS ======", resultsWriter,
+                    printToOutput);
             for(List<PcapPacket> listPcapPacket : listListPcapPacket) {
                 // Print out packet lengths in a sequence
                 int packetCounter = 0;
                 for(PcapPacket pcapPacket : listPcapPacket) {
                     if(pcapPacket != null) {
-                        System.out.print(pcapPacket.length());
+                        String srcIp = pcapPacket.get(IpV4Packet.class).getHeader().getSrcAddr().getHostAddress();
+                        String dstIp = pcapPacket.get(IpV4Packet.class).getHeader().getDstAddr().getHostAddress();
+                        String direction = srcIp.startsWith("10.") || srcIp.startsWith("192.168.") ?
+                                "(C-" : "(S-";
+                        direction = dstIp.startsWith("10.") || dstIp.startsWith("192.168.") ?
+                                direction + "C)" : direction + "S)";
+                        PrintWriterUtils.print(pcapPacket.length() + direction, resultsWriter, printToOutput);
                     }
                     if(packetCounter < listPcapPacket.size() - 1) {
-                        System.out.print(" ");  // Provide space if not last packet
+                        // Provide space if not last packet
+                        PrintWriterUtils.print(" ", resultsWriter, printToOutput);
                     } else {
-                        System.out.println();      // Newline if last packet
+                        // Newline if last packet
+                        PrintWriterUtils.println("", resultsWriter, printToOutput);
                     }
                     packetCounter++;
                 }
@@ -615,11 +671,20 @@ public final class PcapPacketUtils {
                                                        PcapPacket lowerBound, PcapPacket upperBound) {
 
         List<PcapPacket> listBounds = new ArrayList<>();
+        // Just return the lower and upper bounds when their values are the same --- faster
+        if (lowerBound.length() == upperBound.length()) {
+            listBounds.add(0, lowerBound);
+            listBounds.add(1, upperBound);
+            return listBounds;
+        }
         // Iterate over PcapPacket one by one
         for(List<List<PcapPacket>> listOfListPcapPacket : corePointRange) {
             List<PcapPacket> listCorePointLowerBound = listOfListPcapPacket.get(0);
             List<PcapPacket> listCorePointUpperBound = listOfListPcapPacket.get(1);
             for(PcapPacket corePointLowerBound : listCorePointLowerBound) {
+                if (corePointLowerBound == null) { // Skip if null!
+                    continue;
+                }
                 PcapPacket corePointUpperBound =
                         listCorePointUpperBound.get(listCorePointLowerBound.indexOf(corePointLowerBound));
                 // Return if the match for the core point bounds is found
@@ -783,4 +848,17 @@ public final class PcapPacketUtils {
         // Sequence index starts from 0
         signatures.remove(sequenceIndex);
     }
+
+    /**
+     * Convert a String MAC address into a byte array.
+     *
+     * @param macAddress A String that contains a MAC address to be converted into byte array.
+     */
+    public static byte[] stringToByteMacAddress(String macAddress) {
+
+        BigInteger biMacAddress = new BigInteger(macAddress, 16);
+        byte[] byteMacAddress = biMacAddress.toByteArray();
+        // Return from 1 to 6 since element 0 is 0 because of using BigInteger's method.
+        return Arrays.copyOfRange(byteMacAddress, 1, 7);
+    }
 }