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