54feeba6d5ae7b70ccf4357fe5bb62f9e30554f7
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / detection / SignatureDetector.java
1 package edu.uci.iotproject.detection;
2
3 import edu.uci.iotproject.Conversation;
4 import edu.uci.iotproject.TcpReassembler;
5 import edu.uci.iotproject.analysis.TcpConversationUtils;
6 import edu.uci.iotproject.util.PcapPacketUtils;
7 import org.pcap4j.core.PacketListener;
8 import org.pcap4j.core.PcapPacket;
9
10 import java.util.List;
11
12 /**
13  * TODO add class documentation.
14  *
15  * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
16  * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
17  */
18 public class SignatureDetector implements PacketListener {
19
20     /**
21      * The signature that this {@link SignatureDetector} is trying to detect in the observed traffic.
22      */
23     private final List<List<PcapPacket>> mSignature;
24
25     /**
26      * For reassembling the observed traffic into TCP connections.
27      */
28     private final TcpReassembler mTcpReassembler = new TcpReassembler();
29
30     public SignatureDetector(List<List<PcapPacket>> signature) {
31         mSignature = signature;
32     }
33
34
35     @Override
36     public void gotPacket(PcapPacket packet) {
37         // Present packet to TCP reassembler so that it can be mapped to a connection (if it is a TCP packet).
38         mTcpReassembler.gotPacket(packet);
39
40     }
41
42     private void performDetection() {
43         // Let's start out simple by building a version that only works for signatures that do not span across multiple
44         // TCP conversations...
45         for (Conversation c : mTcpReassembler.getTcpConversations()) {
46             for (List<PcapPacket> sequence : mSignature) {
47                 boolean matchFound = isSequenceInConversation(sequence, c);
48
49             }
50         }
51     }
52
53     /**
54      * Examine if a {@link Conversation} contains a given sequence of packets. Note: the current implementation actually
55      * searches for a substring as it does not allow for interleaved packets in {@code c} that are not in
56      * {@code sequence}; for example, if {@code sequence} consists of packet lengths [2, 3, 5] and {@code c} consists of
57      * packet lengths [2, 3, 4, 5], the result will be {@code false}. If we are to allow interleaved packets, we need
58      * a modified version of <a href="https://stackoverflow.com/a/20545604/1214974">this</a>.
59      * @param sequence The sequence to look for.
60      * @param c The {@link Conversation} to search for {@code sequence} in.
61      * @return {@code true} if {@code c} contains {@code sequence}, {@code false} otherwise.
62      */
63     private boolean isSequenceInConversation(List<PcapPacket> sequence, Conversation c) {
64         // The packets we match against differ depending on whether the signature is a TLS or non-TLS signature.
65         boolean tlsSequence = isTlsSequence(sequence);
66         if (tlsSequence && !c.isTls()) {
67             // If we're looking for a TLS signature and this conversation does not appear to be a TLS conversation, we
68             // are done. Note: this assumes that they do NOT start performing TLS on new ports that are not captured in
69             // Conversation.isTls()
70             return false;
71         }
72         // Based on TLS or non-TLS signature, fetch the corresponding list of packets to match against.
73         List<PcapPacket> packets = tlsSequence ? c.getTlsApplicationDataPackets() : c.getPackets();
74         // If sequence is longer than the conversation, it can obviously not be contained in the conversation.
75         if (packets.size() < sequence.size()) {
76             return false;
77         }
78         int seqIdx = 0;
79         int convIdx = 0;
80         while (convIdx < packets.size()) {
81             PcapPacket seqPkt = sequence.get(seqIdx);
82             PcapPacket convPkt = packets.get(convIdx);
83             if (convPkt.getOriginalLength() == seqPkt.getOriginalLength()) {
84                 // TODO should also check direction of packets -- how to?
85                 // A match, advance both indices to consider next packet in sequence vs. next packet in conversation
86                 seqIdx++;
87                 convIdx++;
88                 if (seqIdx == sequence.size()) {
89                     // we managed to match the full sequence in the conversation.
90                     return true;
91                 }
92             } else {
93                 // Mismatch.
94                 if (seqIdx > 0) {
95                     /*
96                      * If we managed to match parts of sequence, we restart the search for sequence in c at the index of
97                      * c where the current mismatch occurred. I.e., we must reset seqIdx, but leave convIdx untouched.
98                      */
99                     seqIdx = 0;
100                 } else {
101                     /*
102                      * First packet of sequence didn't match packet at convIdx of conversation, so we move forward in
103                      * conversation, i.e., we continue the search for sequence in c starting at index convIdx+1 of c.
104                      */
105                     convIdx++;
106                 }
107             }
108         }
109         return false;
110     }
111
112     private boolean isTlsSequence(List<PcapPacket> sequence) {
113         // NOTE: Assumes ALL packets in sequence pertain to the same TCP connection!
114         PcapPacket firstPkt = sequence.get(0);
115         int srcPort = PcapPacketUtils.getSourcePort(firstPkt);
116         int dstPort = PcapPacketUtils.getDestinationPort(firstPkt);
117         return TcpConversationUtils.isTlsPort(srcPort) || TcpConversationUtils.isTlsPort(dstPort);
118     }
119
120 }