Adding range-based detection (improved the results for Nest Thermostat and Arlo Camera.
[pingpong.git] / Code / Projects / PacketLevelSignatureExtractor / src / main / java / edu / uci / iotproject / evaluation / SanitySignatureGenerator.java
1 package edu.uci.iotproject.evaluation;
2
3 import edu.uci.iotproject.trafficreassembly.layer3.Conversation;
4 import edu.uci.iotproject.trafficreassembly.layer3.TcpReassembler;
5 import edu.uci.iotproject.io.PcapHandleReader;
6 import edu.uci.iotproject.util.PrintUtils;
7 import org.pcap4j.core.*;
8
9 import java.util.ArrayList;
10 import java.util.List;
11 import java.util.Optional;
12
13 /**
14  * Hacky utility for producing a sanity signature for negative test sets.
15  * <p>
16  * More precisely, given information about packet lengths and packet directions known to be present in an input trace,
17  * this class locates the first occurrence of a matching sequence in the input trace and outputs it to a file in the
18  * signature format (i.e., a {@code List<List<List<PcapPacket>>>}.
19  * </p>
20  * <p>
21  *     Note: can only produce simplistic signatures, i.e., a signature that is a <em>single</em> packet sequence that
22  *     occurs on a single TCP connection.
23  * </p>
24  *
25  *
26  * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
27  * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
28  */
29 public class SanitySignatureGenerator {
30
31     public static void main(String[] args) throws PcapNativeException, NotOpenException {
32         // The pcap file
33         final String pcapPath = "/Users/varmarken/temp/UCI IoT Project/experiments/evaluation/negative-datasets/UNB/Monday-WorkingHours_one-local-endpoint.pcap";
34         final String sigOutputPath = "/Users/varmarken/temp/UCI IoT Project/experiments/evaluation/negative-datasets/UNB/Monday-WorkingHours_one-local-endpoint_sanity.sig";
35         // The sequence of packet lengths known to be present in the trace
36         final List<Integer> pktLengths = new ArrayList<>();
37         pktLengths.add(340);
38         pktLengths.add(295);
39         // ...and their corresponding directions
40         final List<Conversation.Direction> pktDirections = new ArrayList<>();
41         pktDirections.add(Conversation.Direction.CLIENT_TO_SERVER);
42         pktDirections.add(Conversation.Direction.SERVER_TO_CLIENT);
43         // Is the signature a TLS sequence?
44         final boolean tlsSequence = false;
45
46
47         PcapHandle handle;
48         try {
49             handle = Pcaps.openOffline(pcapPath, PcapHandle.TimestampPrecision.NANO);
50         } catch (PcapNativeException pne) {
51             handle = Pcaps.openOffline(pcapPath);
52         }
53         SequenceFinder seqFinder = new SequenceFinder(pktLengths, pktDirections, tlsSequence, sigOutputPath);
54         final PcapHandleReader reader = new PcapHandleReader(handle, p -> true, seqFinder);
55         seqFinder.setPcapHandleReader(reader);
56         reader.readFromHandle();
57     }
58
59
60     private static class SequenceFinder implements PacketListener {
61         private final TcpReassembler mTcpReassembler = new TcpReassembler();
62         private final List<Integer> mPktLengths;
63         private final List<Conversation.Direction> mPktDirections;
64         private final boolean mTlsSequence;
65         private PcapHandleReader mReader;
66         private final String mSignatureOutputPath;
67
68         private SequenceFinder(List<Integer> pktLengths,
69                                List<Conversation.Direction> pktDirections,
70                                boolean tlsSequence,
71                                String sigOutputPath) {
72             mPktLengths = pktLengths;
73             mPktDirections = pktDirections;
74             mTlsSequence = tlsSequence;
75             mSignatureOutputPath = sigOutputPath;
76         }
77
78         @Override
79         public void gotPacket(PcapPacket packet) {
80             // Skip packets not matching expected length
81             if (!mPktLengths.contains(packet.getOriginalLength())) {
82                 return;
83             }
84             // Otherwise forward to TCP reassembler.
85             mTcpReassembler.gotPacket(packet);
86             // We are done as soon as we have one conversation that has the expected number of packets with the expected
87             // directions.
88             Optional<Conversation> match = mTcpReassembler.getTcpConversations().stream().filter(c -> {
89                 List<PcapPacket> cPkts = mTlsSequence ? c.getTlsApplicationDataPackets() : c.getPackets();
90                 if (cPkts.size() != mPktLengths.size()) {
91                     return false;
92                 }
93                 for (int i = 0; i < cPkts.size(); i++) {
94                     if (c.getDirection(cPkts.get(i)) != mPktDirections.get(i) ||
95                             cPkts.get(i).getOriginalLength() != mPktLengths.get(i)) {
96                         return false;
97                     }
98                 }
99                 return true;
100             }).findFirst();
101             if (match.isPresent()) {
102                 System.out.println("match found");
103                 // Terminate reader; no need to process the full file as we already have the data to produce the signature.
104                 mReader.stopReading();
105                 // Convert sequence to signature format.
106                 List<List<List<PcapPacket>>> signature = new ArrayList<>();
107                 List<List<PcapPacket>> cluster = new ArrayList<>();
108                 List<PcapPacket> sequence = mTlsSequence ? match.get().getTlsApplicationDataPackets() : match.get().getPackets();
109                 cluster.add(sequence);
110                 signature.add(cluster);
111                 // Output the signature to a file.
112                 PrintUtils.serializeIntoFile(mSignatureOutputPath, signature);
113             }
114         }
115
116         private void setPcapHandleReader(PcapHandleReader reader) {
117             mReader = reader;
118         }
119     }
120
121 }