1 package edu.uci.iotproject.trafficreassembly.layer2;
3 import edu.uci.iotproject.trafficreassembly.layer2.Layer2Flow;
4 import edu.uci.iotproject.trafficreassembly.layer2.Layer2FlowReassemblerObserver;
5 import org.pcap4j.core.PacketListener;
6 import org.pcap4j.core.PcapPacket;
7 import org.pcap4j.packet.EthernetPacket;
8 import org.pcap4j.util.MacAddress;
13 * Reassembles traffic flows at layer 2, i.e., for each combination of hosts, creates a list of packets exchanged
16 * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
17 * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
19 public class Layer2FlowReassembler implements PacketListener {
22 * Maps a pair of MAC addresses to the packets exchanged between the two hosts.
23 * The key is the concatenation of the two MAC addresses in hex string format, where the lexicographically smaller
24 * MAC is at the front of the string.
26 private final Map<String, Layer2Flow> mFlows = new HashMap<>();
28 private final List<Layer2FlowReassemblerObserver> mObservers = new ArrayList<>();
31 public void gotPacket(PcapPacket packet) {
32 // TODO: update to 802.11 packet...?
33 EthernetPacket ethPkt = packet.get(EthernetPacket.class);
35 MacAddress srcAddr = ethPkt.getHeader().getSrcAddr();
36 MacAddress dstAddr = ethPkt.getHeader().getDstAddr();
38 String key = keyFromAddresses(srcAddr, dstAddr);
39 // Create a new list if this pair of MAC addresses where not previously encountered and add packet to that list,
40 // or simply add to an existing list if one is present.
41 mFlows.computeIfAbsent(key, k -> {
42 Layer2Flow newFlow = new Layer2Flow(srcAddr, dstAddr);
43 // Inform observers of the new flow
44 mObservers.forEach(o -> o.onNewFlow(this, newFlow));
49 public void addObserver(Layer2FlowReassemblerObserver observer) {
50 mObservers.add(observer);
53 public void removeObserver(Layer2FlowReassemblerObserver observer) {
54 mObservers.remove(observer);
58 * Get the traffic flow between two local endpoints ({@link MacAddress}es).
59 * @param addr1 The first endpoint.
60 * @param addr2 The second endpoint
61 * @return The traffic exchanged between the two endpoints.
63 public Layer2Flow getFlowForAddresses(MacAddress addr1, MacAddress addr2) {
64 return mFlows.get(keyFromAddresses(addr1, addr2));
68 * Get all traffic flows, i.e., a traffic flow for each unique pair of endpoints (MAC addresses).
69 * @return All traffic flows.
71 public Collection<Layer2Flow> getFlows() {
72 return mFlows.values();
76 * Given two {@link MacAddress}es, generates the corresponding key string used in {@link #mFlows}.
77 * @param addr1 The first address.
78 * @param addr2 The second address.
79 * @return the key string used in {@link #mFlows} corresponding to the two addresses.
81 private String keyFromAddresses(MacAddress addr1, MacAddress addr2) {
82 String addr1Str = addr1.toString();
83 String addr2Str = addr2.toString();
84 return addr1Str.compareTo(addr2Str) < 0 ? addr1Str + addr2Str : addr2Str + addr1Str;