1 package edu.uci.iotproject.detection;
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.*;
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
16 * TODO add class documentation.
18 * @author Janus Varmarken
20 public class Layer2ClusterMatcher extends AbstractClusterMatcher implements Layer2FlowReassemblerObserver, Layer2FlowObserver {
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);
27 L2FlowReassembler flowReassembler = new L2FlowReassembler();
29 Layer2ClusterMatcher l2ClusterMatcher = new Layer2ClusterMatcher(onSignature.get(0));
30 flowReassembler.addObserver(l2ClusterMatcher);
32 final String inputPcapFile = "/Users/varmarken/temp/UCI IoT Project/experiments/2018-07/tplink/tplink.wlan1.local.pcap";
36 handle = Pcaps.openOffline(inputPcapFile, PcapHandle.TimestampPrecision.NANO);
37 } catch (PcapNativeException pne) {
38 handle = Pcaps.openOffline(inputPcapFile);
40 PcapHandleReader reader = new PcapHandleReader(handle, p -> true, flowReassembler);
41 reader.readFromHandle();
47 private final List<Layer2SequenceMatcher> mSeqMatchers;
49 public Layer2ClusterMatcher(List<List<PcapPacket>> 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)));
55 // for (int i = 0; i < mCluster.size(); i++) {
58 // mSeqMatchers[i] = new Layer2SequenceMatcher(mCluster.get(i));
65 // public void gotPacket(PcapPacket packet) {
66 // // Forward the packet to all sequence matchers.
67 // for (Layer2SequenceMatcher matcher : mSeqMatchers) {
68 // matcher.gotPacket(packet);
75 private final Map<Layer2Flow, List<Layer2SequenceMatcher>> mPerFlowSeqMatchers = new HashMap<>();
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);
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()));
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);
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);
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()) {
134 if (!alreadyPresent) {
135 // Add the sequence if not already present in the pruned cluster.
136 prunedCluster.add(originalClusterSeq);
139 return prunedCluster;
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);