Make original ClusterMatcher inherit from AbstractClusterMatcher. Reorganize code...
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / FlowPattern.java
1 package edu.uci.iotproject;
2
3 import org.pcap4j.core.*;
4 import org.pcap4j.packet.*;
5 import org.pcap4j.packet.DnsPacket;
6 import org.pcap4j.packet.namednumber.DnsResourceRecordType;
7
8 import java.io.EOFException;
9 import java.net.InetAddress;
10 import java.net.UnknownHostException;
11 import java.util.*;
12 import java.util.concurrent.TimeoutException;
13
14 /**
15  * TODO add class documentation.
16  * TODO: At this point, this class is still in transition to having multiple hostnames and lists of packets
17  *
18  * @author Janus Varmarken
19  */
20 public class FlowPattern {
21
22     /**
23      * Class properties
24      */
25     private final String mPatternId;
26     private final String hostname;  // The hostname that this {@code FlowPattern} is associated with.
27
28     /**
29      * The order of packet lengths that defines this {@link FlowPattern}
30      * TODO: this is a simplified representation, we should also include information about direction of each packet.
31      */
32     private final List<Integer> flowPacketOrder;
33     private final Map<String, List<Integer>> mHostnameToPacketLengthsMap;
34     private final List<String> mHostnameList;
35     private final PcapHandle mPcap;
36
37     
38     /**
39      * Class constants
40      */
41      
42
43     /**
44      * Constructor #1
45      */
46     public FlowPattern(String mPatternId, String hostname, PcapHandle mPcap) {
47         this.mPatternId = mPatternId;
48         this.hostname = hostname;
49         this.mHostnameList = null;
50         this.mPcap = mPcap;
51         this.mHostnameToPacketLengthsMap = null;
52         this.flowPacketOrder = new ArrayList<Integer>();
53         processPcap();
54     }
55
56
57     /**
58      * Process the PcapHandle to strip off unnecessary packets and just get the integer array of packet lengths
59      */
60     private void processPcap() {
61
62         PcapPacket packet;
63         try {
64             while ((packet = mPcap.getNextPacketEx()) != null) {
65                 // For now, we only work support pattern search in TCP over IPv4.
66                 IpV4Packet ipPacket = packet.get(IpV4Packet.class);
67                 TcpPacket tcpPacket = packet.get(TcpPacket.class);
68                 if (ipPacket == null || tcpPacket == null)
69                     continue;
70                 if (tcpPacket.getPayload() == null) // We skip non-payload control packets as these are less predictable
71                     continue; 
72                 int packetLength = tcpPacket.getPayload().length();
73                 flowPacketOrder.add(packetLength);
74             }
75         } catch (EOFException eofe) {
76             System.out.println("[ FlowPattern ] Finished processing a training PCAP stream!");
77             System.out.println("[ FlowPattern ] Pattern for " + mPatternId + ": " + Arrays.toString(flowPacketOrder.toArray()));
78         } catch (PcapNativeException  |
79                  TimeoutException     |
80                  NotOpenException ex) {
81             ex.printStackTrace();
82         }
83     }
84
85
86     /**
87      * Process the PcapHandle to strip off unnecessary packets.
88      * We then map list of hostnames to their respective arrays of packet lengths
89      */
90     private void processPcapToMap() {
91
92         PcapPacket packet;
93         try {
94             int hostIndex = -1;
95             Set<String> addressSet = new HashSet<>();
96             while ((packet = mPcap.getNextPacketEx()) != null) {
97                 // For now, we only work support pattern search in TCP over IPv4.
98                 IpV4Packet ipPacket = packet.get(IpV4Packet.class);
99                 TcpPacket tcpPacket = packet.get(TcpPacket.class);
100                 if (ipPacket == null || tcpPacket == null) {
101                     continue;
102                 }
103                 if (tcpPacket.getPayload() == null) {
104                 // We skip non-payload control packets as these are less predictable
105                     continue;
106                 }
107                 // We assume that if it is not a local address then it is a cloud server address
108                 InetAddress srcAddress = ipPacket.getHeader().getSrcAddr();
109                 InetAddress dstAddress = ipPacket.getHeader().getDstAddr();
110                 boolean fromServer = !srcAddress.isSiteLocalAddress();
111                 boolean fromClient = !dstAddress.isSiteLocalAddress();
112                 if (!fromServer && !fromClient) {
113                     // Packet not related to pattern, skip it
114                     continue;
115                 } else {
116                     // We relate and assume that this address is from our cloud server
117                     String cloudAddress = null;
118                     if (fromClient) {
119                         cloudAddress = dstAddress.getHostAddress();
120                     } else { // fromServer
121                         cloudAddress = srcAddress.getHostAddress();
122                     }
123                     //System.out.println("\nCloud address: " + cloudAddress);
124                     if (!addressSet.contains(cloudAddress)) {
125                         addressSet.add(cloudAddress);
126                         hostIndex++;
127                     }
128
129                     String hostname = mHostnameList.get(hostIndex);
130                     List<Integer> packetLengthsList = mHostnameToPacketLengthsMap.containsKey(hostname) ? 
131                         mHostnameToPacketLengthsMap.get(hostname) : new ArrayList<>();
132                     int packetLength = tcpPacket.getPayload().length();
133                     packetLengthsList.add(packetLength);
134                     mHostnameToPacketLengthsMap.put(hostname, packetLengthsList);
135                 }
136             }
137         } catch (EOFException eofe) {
138             System.out.println("[ FlowPattern ] Finished processing a training PCAP stream!");
139             System.out.println("[ FlowPattern ] Pattern for " + mPatternId + ": " + Arrays.toString(mHostnameToPacketLengthsMap.entrySet().toArray()));
140         } catch (PcapNativeException  |
141                  TimeoutException     |
142                  NotOpenException ex) {
143             ex.printStackTrace();
144         }
145     }
146
147     
148     /**
149      * Constructor #2
150      */
151     public FlowPattern(String mPatternId, List<String> mHostnameList, PcapHandle mPcap) {
152         this.mPatternId = mPatternId;
153         this.hostname = null;
154         this.mHostnameList = mHostnameList;
155         this.mPcap = mPcap;
156         this.flowPacketOrder = null;
157         this.mHostnameToPacketLengthsMap = new HashMap<>();
158         processPcapToMap();
159     }
160
161
162     public String getPatternId() {
163         return mPatternId;
164     }
165
166
167     public String getHostname() {
168         return hostname;
169     }
170
171
172     /**
173      * Get the sequence of packet lengths that defines this {@code FlowPattern}.
174      * @return the sequence of packet lengths that defines this {@code FlowPattern}.
175      */
176     public List<Integer> getPacketOrder() {
177         return flowPacketOrder;
178     }
179
180
181     /**
182      * Get the sequence of packet lengths based on input hostname.
183      * @return the sequence of packet lengths that defines this {@code FlowPattern}.
184      */
185     public List<Integer> getPacketOrder(String hostname) {
186         return mHostnameToPacketLengthsMap.get(hostname);
187     }
188
189
190     /**
191      * Get the list of associated hostnames.
192      * @return the associated hostnames that define this {@code FlowPattern}.
193      */
194     public List<String> getHostnameList() {
195         return mHostnameList;
196     }
197
198     
199     /**
200      * Get the length of the List of {@code FlowPattern}.
201      * @return the length of the List of {@code FlowPattern}.
202      */
203     public int getLength() {
204         return flowPacketOrder.size();
205     }  
206
207
208     /**
209      * Get the length of the List of {@code FlowPattern}.
210      * @return the length of the List of {@code FlowPattern}.
211      */
212     public int getLength(String hostname) {
213         return mHostnameToPacketLengthsMap.get(hostname).size();
214     } 
215 }