1 package edu.uci.iotproject.maclayer;
3 import edu.uci.iotproject.FlowPattern;
4 import org.pcap4j.core.NotOpenException;
5 import org.pcap4j.core.PcapHandle;
6 import org.pcap4j.core.PcapNativeException;
7 import org.pcap4j.core.PcapPacket;
8 import org.pcap4j.packet.RadiotapPacket;
10 import java.io.EOFException;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.List;
14 import java.util.Objects;
15 import java.util.concurrent.TimeoutException;
18 * Performs a search for {@link FlowPattern}
19 * TODO: May want to create an abstract FlowPatternFinder and then derive MacLayer, TcpipLayer FlowPatternFinders from that one.
21 * @author Janus Varmarken
23 public class MacLayerFlowPatternFinder {
25 private final MacLayerFlowPattern mPattern;
26 private final PcapHandle mPcap;
28 public MacLayerFlowPatternFinder(PcapHandle pcap, MacLayerFlowPattern pattern) {
29 this.mPcap = Objects.requireNonNull(pcap,
30 String.format("Argument of type '%s' cannot be null", PcapHandle.class.getSimpleName()));
31 this.mPattern = Objects.requireNonNull(pattern,
32 String.format("Argument of type '%s' cannot be null", FlowPattern.class.getSimpleName()));
35 public void findFlowPattern() {
38 // Packets matched to flow pattern searched for.
39 List<PcapPacket> patternPackets = new ArrayList<>();
40 while ((packet = mPcap.getNextPacketEx()) != null) {
41 RadiotapPacket radiotapPacket;
43 // Some packets throw an IAE with message "msi must be between 0 and 6 but is actually: 7"
44 // when accessing the RadiotapPacket.
45 radiotapPacket = packet.get(RadiotapPacket.class);
46 } catch (IllegalArgumentException iae) {
47 System.out.println(iae.getMessage());
50 if (radiotapPacket == null) {
53 // Restart search if pattern not found within reasonable time frame (hardcoded for now).
54 if (patternPackets.size() > 0 && packet.getTimestamp().getEpochSecond() -
55 patternPackets.get(patternPackets.size()-1).getTimestamp().getEpochSecond() > 2) {
56 patternPackets = new ArrayList<>();
59 byte[] rawData = radiotapPacket.getPayload().getRawData();
60 // Search rawData for MAC of FlowPattern in sender/receiver section
61 // [TODO needs verification that this section is actually the sender/receiver section]
62 if (rawData.length < 16) {
65 int prefixLength = mPattern.getMacPrefixRawBytes().length;
66 byte[] mac1 = Arrays.copyOfRange(rawData, 4, prefixLength < 6 ? 4 + prefixLength : 10);
67 byte[] mac2 = Arrays.copyOfRange(rawData, 10, prefixLength < 6 ? 10 + prefixLength : 16);
68 if (!Arrays.equals(mac1, mPattern.getMacPrefixRawBytes()) && !Arrays.equals(mac2, mPattern.getMacPrefixRawBytes())) {
69 // MAC prefix not present in raw data.
72 // Packet related to device associated with the pattern we are looking for.
73 int expectedLength = mPattern.getPacketLengthSequence().get(patternPackets.size());
74 if (packet.length() == expectedLength) {
75 patternPackets.add(packet);
76 if (patternPackets.size() == mPattern.getLength()) {
77 // Full pattern found, declare success if packets are within some reasonable amount of time of
79 // For now, we use a hardcoded value.
80 if (patternPackets.get(patternPackets.size()-1).getTimestamp().getEpochSecond() -
81 patternPackets.get(0).getTimestamp().getEpochSecond() < 5) {
82 System.out.println(String.format("[ find ] Detected a COMPLETE MATCH of pattern '%s' at %s!",
83 mPattern.getPatternId(), patternPackets.get(0).getTimestamp().toString()));
85 // Reset search by resetting list.
86 patternPackets = new ArrayList<>();
89 // Discard packet, not relevant to pattern.
93 } catch (EOFException e) {
94 // TODO wait for, and print, results.
95 } catch (PcapNativeException|TimeoutException|NotOpenException e) {