Implementing relaxed matching for layer 2 and layer 3.
[pingpong.git] / Code / Projects / PacketLevelSignatureExtractor / src / main / java / edu / uci / iotproject / detection / AbstractClusterMatcher.java
1 package edu.uci.iotproject.detection;
2
3 import org.pcap4j.core.PcapPacket;
4
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.Objects;
8
9 /**
10  * Base class for classes that search a traffic trace for sequences of packets that "belong to" a given cluster (in
11  * other words, classes that attempt to classify traffic as pertaining to a given cluster).
12  *
13  * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
14  * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
15  */
16 abstract public class AbstractClusterMatcher {
17
18     /**
19      * The cluster that describes the sequence of packets that this {@link AbstractClusterMatcher} is trying to detect
20      * in the observed traffic.
21      */
22     protected final List<List<PcapPacket>> mCluster;
23
24     /**
25      * Observers registered for callbacks from this {@link AbstractClusterMatcher}.
26      */
27     protected final List<ClusterMatcherObserver> mObservers;
28
29     protected AbstractClusterMatcher(List<List<PcapPacket>> cluster, boolean isRangeBased) {
30         // ===================== PRECONDITION SECTION =====================
31         cluster = Objects.requireNonNull(cluster, "cluster cannot be null");
32         if (cluster.isEmpty() || cluster.stream().anyMatch(inner -> inner.isEmpty())) {
33             throw new IllegalArgumentException("cluster is empty (or contains an empty inner List)");
34         }
35         for (List<PcapPacket> clusterMember : cluster) {
36             if (clusterMember.size() != cluster.get(0).size()) {
37                 throw new IllegalArgumentException("All sequences in cluster must contain the same number of packets");
38             }
39         }
40         // ================================================================
41         // Let the subclass prune the provided cluster---only if it is not range-based
42         if (!isRangeBased) {
43             mCluster = pruneCluster(cluster);
44         } else {
45             mCluster = cluster;
46         }
47         mObservers = new ArrayList<>();
48     }
49
50     /**
51      * Register for callbacks from this cluster matcher.
52      * @param observer The target of the callbacks.
53      */
54     public final void addObserver(ClusterMatcherObserver observer) {
55         mObservers.add(observer);
56     }
57
58     /**
59      * Deregister for callbacks from this cluster matcher.
60      * @param observer The callback target that is to be deregistered.
61      */
62     public final void removeObserver(ClusterMatcherObserver observer) {
63         mObservers.remove(observer);
64     }
65
66     /**
67      * Allows subclasses to specify how to prune the input cluster provided to the constructor.
68      * @param cluster The input cluster provided to the constructor.
69      * @return The pruned cluster to use in place of the input cluster.
70      */
71     abstract protected List<List<PcapPacket>> pruneCluster(List<List<PcapPacket>> cluster);
72
73     // TODO: move Direction outside Conversation so that this is less confusing.
74 //    abstract protected Conversation.Direction[] getPacketDirections(List<PcapPacket> packets);
75
76 }