1 package edu.uci.iotproject.analysis;
3 import edu.uci.iotproject.Conversation;
4 import edu.uci.iotproject.DnsMap;
5 import edu.uci.iotproject.util.PcapPacketUtils;
6 import org.pcap4j.core.PcapPacket;
7 import org.pcap4j.packet.IpV4Packet;
8 import org.pcap4j.packet.TcpPacket;
13 * TODO add class documentation.
15 * @author Janus Varmarken
17 public class TcpConversationUtils {
19 public static List<PcapPacketPair> extractPacketPairs(Conversation conv) {
20 List<PcapPacket> packets = conv.getPackets();
21 List<PcapPacketPair> pairs = new ArrayList<>();
23 while (i < packets.size()) {
24 PcapPacket p1 = packets.get(i);
25 String p1SrcIp = p1.get(IpV4Packet.class).getHeader().getSrcAddr().getHostAddress();
26 int p1SrcPort = p1.get(TcpPacket.class).getHeader().getSrcPort().valueAsInt();
27 if (i+1 < packets.size()) {
28 PcapPacket p2 = packets.get(i+1);
29 if (PcapPacketUtils.isSource(p2, p1SrcIp, p1SrcPort)) {
30 // Two packets in a row going in the same direction -> create one item pair for p1
31 pairs.add(new PcapPacketPair(p1, null));
32 // Advance one packet as the following two packets may form a valid two-item pair.
35 // The two packets form a response-reply pair, create two-item pair.
36 pairs.add(new PcapPacketPair(p1, p2));
37 // Advance two packets as we have already processed the packet at index i+1 in order to create the pair.
41 // Last packet of conversation => one item pair
42 pairs.add(new PcapPacketPair(p1, null));
43 // Advance i to ensure termination.
48 // TODO: what if there is long time between response and reply packet? Should we add a threshold and exclude those cases?
52 public static Map<String, List<Conversation>> groupConversationsByHostname(List<Conversation> tcpConversations, DnsMap ipHostnameMappings) {
53 HashMap<String, List<Conversation>> result = new HashMap<>();
54 for (Conversation c : tcpConversations) {
55 if (c.getPackets().size() == 0) {
56 String warningStr = String.format("Detected a %s [%s] with no payload packets.",
57 c.getClass().getSimpleName(), c.toString());
58 System.err.println(warningStr);
61 IpV4Packet firstPacketIp = c.getPackets().get(0).get(IpV4Packet.class);
62 String ipSrc = firstPacketIp.getHeader().getSrcAddr().getHostAddress();
63 String ipDst = firstPacketIp.getHeader().getDstAddr().getHostAddress();
64 // Check if src or dst IP is associated with one or more hostnames.
65 Set<String> hostnames = ipHostnameMappings.getHostnamesForIp(ipSrc);
66 if (hostnames == null) {
67 // No luck with src ip (possibly because it's a client->srv packet), try dst ip.
68 hostnames = ipHostnameMappings.getHostnamesForIp(ipDst);
70 if (hostnames != null) {
71 // Put a reference to the conversation for each of the hostnames that the conversation's IP maps to.
72 for (String hostname : hostnames) {
73 List<Conversation> newValue = new ArrayList<>();
75 result.merge(hostname, newValue, (l1, l2) -> { l1.addAll(l2); return l1; });
77 if (hostnames.size() > 1) {
78 // Print notice of IP mapping to multiple hostnames (debugging)
79 System.err.println(String.format("%s: encountered an IP that maps to multiple (%d) hostnames",
80 TcpConversationUtils.class.getSimpleName(), hostnames.size()));
83 // If no hostname mapping, store conversation under the key that is the concatenation of the two IPs.
84 // In order to ensure consistency when mapping conversations, use lexicographic order to select which IP
86 String delimiter = "_";
87 // Note that the in case the comparison returns 0, the strings are equal, so it doesn't matter which of
88 // ipSrc and ipDst go first (also, this case should not occur in practice as it means that the device is
89 // communicating with itself!)
90 String key = ipSrc.compareTo(ipDst) <= 0 ? ipSrc + delimiter + ipDst : ipDst + delimiter + ipSrc;
91 List<Conversation> newValue = new ArrayList<>();
93 result.merge(key, newValue, (l1, l2) -> { l1.addAll(l2); return l1; });