Cleanup of layer 2 sequence detection: get rid of some experimental classes
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / detection / Layer2ClusterMatcher.java
1 package edu.uci.iotproject.detection;
2
3 import edu.uci.iotproject.L2FlowReassembler;
4 import edu.uci.iotproject.Layer2Flow;
5 import edu.uci.iotproject.Layer2FlowReassemblerObserver;
6 import edu.uci.iotproject.io.PcapHandleReader;
7 import edu.uci.iotproject.util.PrintUtils;
8 import org.pcap4j.core.*;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14
15 /**
16  * TODO add class documentation.
17  *
18  * @author Janus Varmarken
19  */
20 public class Layer2ClusterMatcher extends AbstractClusterMatcher implements Layer2FlowReassemblerObserver, Layer2FlowObserver {
21
22     public static void main(String[] args) throws PcapNativeException, NotOpenException {
23         final String onSignatureFile = "/Users/varmarken/temp/UCI IoT Project/experiments/training/signatures/tplink-plug/tplink-plug-onSignature-device-side.sig";
24         List<List<List<PcapPacket>>> onSignature = PrintUtils.deserializeSignatureFromFile(onSignatureFile);
25
26
27         L2FlowReassembler flowReassembler = new L2FlowReassembler();
28
29         Layer2ClusterMatcher l2ClusterMatcher = new Layer2ClusterMatcher(onSignature.get(0));
30         flowReassembler.addObserver(l2ClusterMatcher);
31
32         final String inputPcapFile = "/Users/varmarken/temp/UCI IoT Project/experiments/2018-07/tplink/tplink.wlan1.local.pcap";
33
34         PcapHandle handle;
35         try {
36             handle = Pcaps.openOffline(inputPcapFile, PcapHandle.TimestampPrecision.NANO);
37         } catch (PcapNativeException pne) {
38             handle = Pcaps.openOffline(inputPcapFile);
39         }
40         PcapHandleReader reader = new PcapHandleReader(handle, p -> true, flowReassembler);
41         reader.readFromHandle();
42
43
44     }
45
46
47     private final List<Layer2SequenceMatcher> mSeqMatchers;
48
49     public Layer2ClusterMatcher(List<List<PcapPacket>> cluster) {
50         super(cluster);
51         // Setup a sequence matcher for each sequence of the pruned cluster
52         mSeqMatchers = new ArrayList<>();
53         mCluster.forEach(seq -> mSeqMatchers.add(new Layer2SequenceMatcher(seq)));
54
55 //        for (int i = 0; i < mCluster.size(); i++) {
56 //
57 //
58 //            mSeqMatchers[i] = new Layer2SequenceMatcher(mCluster.get(i));
59 //
60 //
61 //        }
62     }
63
64 //    @Override
65 //    public void gotPacket(PcapPacket packet) {
66 //        // Forward the packet to all sequence matchers.
67 //        for (Layer2SequenceMatcher matcher : mSeqMatchers) {
68 //            matcher.gotPacket(packet);
69 //        }
70 //
71 //
72 //    }
73
74
75     private final Map<Layer2Flow, List<Layer2SequenceMatcher>> mPerFlowSeqMatchers = new HashMap<>();
76
77     @Override
78     public void onNewPacket(Layer2Flow flow, PcapPacket newPacket) {
79         if (mPerFlowSeqMatchers.get(flow) == null) {
80             // If this is the first time we encounter this flow, we need to set up sequence matchers for it.
81             List<Layer2SequenceMatcher> matchers = new ArrayList<>();
82             mCluster.forEach(seq -> matchers.add(new Layer2SequenceMatcher(seq)));
83             mPerFlowSeqMatchers.put(flow, matchers);
84         }
85         // Buffer for new sequence matchers that will take over the job of observing for the first packet when a
86         // sequence matcher advances beyond the first packet.
87         List<Layer2SequenceMatcher> newSeqMatchers = new ArrayList<>();
88         // Buffer for sequence matchers that have terminated and are to be removed from mPerFlowSeqMatchers.
89         List<Layer2SequenceMatcher> terminatedSeqMatchers = new ArrayList<>();
90         // Present the new packet to all sequence matchers
91         for (Layer2SequenceMatcher sm : mPerFlowSeqMatchers.get(flow)) {
92             boolean matched = sm.matchPacket(newPacket);
93             if (matched && sm.getMatchedPacketsCount() == 1) {
94                 // Setup a new sequence matcher that matches from the beginning of the sequence so as to keep
95                 // progressing in the sequence matcher that just matched the current packet, while still allowing
96                 // for matches of the full sequence in later traffic. This is to accommodate the case where the
97                 // first packet of a sequence is detected in an early packet, but where the remaining packets of
98                 // that sequence do not appear until way later in time (e.g., if the first packet of the sequence
99                 // by chance is generated from traffic unrelated to the trigger traffic).
100                 // Note that we must store the new sequence matcher in a buffer and add it outside the loop in order to
101                 // prevent concurrent modification exceptions.
102                 newSeqMatchers.add(new Layer2SequenceMatcher(sm.getTargetSequence()));
103             }
104             if (matched && sm.getMatchedPacketsCount() == sm.getTargetSequencePacketCount()) {
105                 // This sequence matcher has a match of the sequence it was searching for
106                 // TODO report it.... for now just do a dummy printout.
107                 System.out.println("SEQUENCE MATCHER HAS A MATCH AT " + sm.getMatchedPackets().get(0).getTimestamp());
108                 // Mark the sequence matcher for removal. No need to create a replacement one as we do that whenever the
109                 // first packet of the sequence is matched (see above).
110                 terminatedSeqMatchers.add(sm);
111             }
112         }
113         // Add the new sequence matchers, if any.
114         mPerFlowSeqMatchers.get(flow).addAll(newSeqMatchers);
115         // Remove the terminated sequence matchers, if any.
116         mPerFlowSeqMatchers.get(flow).removeAll(terminatedSeqMatchers);
117     }
118
119
120     @Override
121     protected List<List<PcapPacket>> pruneCluster(List<List<PcapPacket>> cluster) {
122         // Note: we assume that all sequences in the input cluster are of the same length and that their packet
123         // directions are identical.
124         List<List<PcapPacket>> prunedCluster = new ArrayList<>();
125         for (List<PcapPacket> originalClusterSeq : cluster) {
126             boolean alreadyPresent = prunedCluster.stream().anyMatch(pcPkts -> {
127                 for (int i = 0; i < pcPkts.size(); i++) {
128                     if (pcPkts.get(i).getOriginalLength() != originalClusterSeq.get(i).getOriginalLength()) {
129                         return false;
130                     }
131                 }
132                 return true;
133             });
134             if (!alreadyPresent) {
135                 // Add the sequence if not already present in the pruned cluster.
136                 prunedCluster.add(originalClusterSeq);
137             }
138         }
139         return prunedCluster;
140     }
141
142
143     @Override
144     public void onNewFlow(L2FlowReassembler reassembler, Layer2Flow newFlow) {
145         // Subscribe to the new flow to get updates whenever a new packet pertaining to the flow is processed.
146         newFlow.addFlowObserver(this);
147     }
148 }