1 package edu.uci.iotproject.detection.layer2;
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.*;
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.List;
18 * TODO add class documentation.
20 * @author Janus Varmarken
22 public class Layer2ClusterMatcher extends AbstractClusterMatcher implements Layer2FlowReassemblerObserver, Layer2FlowObserver {
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);
29 Layer2FlowReassembler flowReassembler = new Layer2FlowReassembler();
31 Layer2ClusterMatcher l2ClusterMatcher = new Layer2ClusterMatcher(onSignature.get(0));
32 flowReassembler.addObserver(l2ClusterMatcher);
34 final String inputPcapFile = "/Users/varmarken/temp/UCI IoT Project/experiments/2018-07/tplink/tplink.wlan1.local.pcap";
38 handle = Pcaps.openOffline(inputPcapFile, PcapHandle.TimestampPrecision.NANO);
39 } catch (PcapNativeException pne) {
40 handle = Pcaps.openOffline(inputPcapFile);
42 PcapHandleReader reader = new PcapHandleReader(handle, p -> true, flowReassembler);
43 reader.readFromHandle();
49 private final List<Layer2SequenceMatcher> mSeqMatchers;
51 public Layer2ClusterMatcher(List<List<PcapPacket>> 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)));
57 // for (int i = 0; i < mCluster.size(); i++) {
60 // mSeqMatchers[i] = new Layer2SequenceMatcher(mCluster.get(i));
67 // public void gotPacket(PcapPacket packet) {
68 // // Forward the packet to all sequence matchers.
69 // for (Layer2SequenceMatcher matcher : mSeqMatchers) {
70 // matcher.gotPacket(packet);
77 private final Map<Layer2Flow, List<Layer2SequenceMatcher>> mPerFlowSeqMatchers = new HashMap<>();
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);
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()));
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 System.out.println("SEQUENCE MATCHER HAS A MATCH AT " + sm.getMatchedPackets().get(0).getTimestamp());
110 // Mark the sequence matcher for removal. No need to create a replacement one as we do that whenever the
111 // first packet of the sequence is matched (see above).
112 terminatedSeqMatchers.add(sm);
115 // Add the new sequence matchers, if any.
116 mPerFlowSeqMatchers.get(flow).addAll(newSeqMatchers);
117 // Remove the terminated sequence matchers, if any.
118 mPerFlowSeqMatchers.get(flow).removeAll(terminatedSeqMatchers);
123 protected List<List<PcapPacket>> pruneCluster(List<List<PcapPacket>> cluster) {
124 // Note: we assume that all sequences in the input cluster are of the same length and that their packet
125 // directions are identical.
126 List<List<PcapPacket>> prunedCluster = new ArrayList<>();
127 for (List<PcapPacket> originalClusterSeq : cluster) {
128 boolean alreadyPresent = prunedCluster.stream().anyMatch(pcPkts -> {
129 for (int i = 0; i < pcPkts.size(); i++) {
130 if (pcPkts.get(i).getOriginalLength() != originalClusterSeq.get(i).getOriginalLength()) {
136 if (!alreadyPresent) {
137 // Add the sequence if not already present in the pruned cluster.
138 prunedCluster.add(originalClusterSeq);
141 return prunedCluster;
146 public void onNewFlow(Layer2FlowReassembler reassembler, Layer2Flow newFlow) {
147 // Subscribe to the new flow to get updates whenever a new packet pertaining to the flow is processed.
148 newFlow.addFlowObserver(this);