Make original ClusterMatcher inherit from AbstractClusterMatcher. Reorganize code...
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / detection / layer2 / Layer2SequenceMatcher.java
1 package edu.uci.iotproject.detection.layer2;
2
3 import edu.uci.iotproject.analysis.TriggerTrafficExtractor;
4 import org.pcap4j.core.PcapPacket;
5
6 import java.util.ArrayList;
7 import java.util.List;
8
9 /**
10  * Attempts to detect the presence of a specific packet sequence in the set of packets provided through multiple calls
11  * to {@link #matchPacket(PcapPacket)}, considering only layer 2 information.
12  *
13  * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
14  * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
15  */
16 public class Layer2SequenceMatcher {
17
18     /**
19      * The sequence this {@link Layer2SequenceMatcher} is searching for.
20      */
21     private final List<PcapPacket> mSequence;
22
23     /**
24      * Buffer of actual packets seen so far that match the searched sequence (i.e., constitutes a subsequence of the
25      * searched sequence).
26      */
27     private final List<PcapPacket> mMatchedPackets = new ArrayList<>();
28
29     /**
30      * Create a {@code Layer2SequenceMatcher}.
31      * @param sequence The sequence to match against (search for).
32      */
33     public Layer2SequenceMatcher(List<PcapPacket> sequence) {
34         mSequence = sequence;
35     }
36
37     /**
38      * Attempt to advance this {@code Layer2SequenceMatcher} by matching {@code packet} against the packet that this
39      * {@code Layer2SequenceMatcher} expects as the next packet of the sequence it is searching for.
40      * @param packet
41      * @return {@code true} if this {@code Layer2SequenceMatcher} could advance by adding {@code packet} to its set of
42      *         matched packets, {@code false} otherwise.
43      */
44     public boolean matchPacket(PcapPacket packet) {
45         // The packet we want to match next.
46         PcapPacket expected = mSequence.get(mMatchedPackets.size());
47         // First verify if the received packet has the length we're looking for.
48         if (packet.getOriginalLength() == expected.getOriginalLength()) {
49             // Next apply timing constraints:
50             // - to be a match, the packet must have a later timestamp than any other packet currently matched
51             // - does adding the packet cause the max allowed time between first packet and last packet to be exceeded?
52             if (mMatchedPackets.size() > 0 &&
53                     !packet.getTimestamp().isAfter(mMatchedPackets.get(mMatchedPackets.size()-1).getTimestamp())) {
54                 return false;
55             }
56             if (mMatchedPackets.size() > 0 &&
57                     packet.getTimestamp().
58                             isAfter(mMatchedPackets.get(0).getTimestamp().
59                                     plusMillis(TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS))) {
60                 // Packet too
61                 return false;
62             }
63             // TODO (how to) check directions?
64             // This packet has a length matching next packet of searched sequence, so we store it and advance.
65             mMatchedPackets.add(packet);
66             if (mMatchedPackets.size() == mSequence.size()) {
67                 // TODO report (to observers?) that we are done.
68             }
69             return true;
70         }
71         return false;
72     }
73
74     public int getMatchedPacketsCount() {
75         return mMatchedPackets.size();
76     }
77
78     public int getTargetSequencePacketCount() {
79         return mSequence.size();
80     }
81
82     public List<PcapPacket> getTargetSequence() {
83         return mSequence;
84     }
85
86     public List<PcapPacket> getMatchedPackets() {
87         return mMatchedPackets;
88     }
89 }