From: Janus Varmarken Date: Tue, 11 Sep 2018 00:33:49 +0000 (-0700) Subject: Added support for extracting packet pairs of only TLS Application Data packets (see... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=94cab9d7599e690eff4a5ba697b7fc2f1574aa23;p=pingpong.git Added support for extracting packet pairs of only TLS Application Data packets (see TcpConversationUtils.extractTlsAppDataPacketPairs(Conversation)). Added support for converting PcapPacketPairs to CSV string (see PrintUtils.java). --- diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketPair.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketPair.java index 1d28895..db5c839 100644 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketPair.java +++ b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketPair.java @@ -3,9 +3,10 @@ package edu.uci.iotproject.analysis; import org.pcap4j.core.PcapPacket; /** - * TODO add class documentation. + * A simple wrapper for holding a pair of packets (e.g., a request and associated reply packet). * - * @author Janus Varmarken + * @author Janus Varmarken {@literal } + * @author Rahmadi Trimananda {@literal } */ public class PcapPacketPair { @@ -24,6 +25,7 @@ public class PcapPacketPair { @Override public String toString() { - return getFirst().length() + ", " + (getSecond() == null ? "null" : getSecond().length()); + return getFirst().getOriginalLength() + ", " + (getSecond() == null ? "null" : getSecond().getOriginalLength()); } + } diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TcpConversationUtils.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TcpConversationUtils.java index 470b15f..9e25d1d 100644 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TcpConversationUtils.java +++ b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TcpConversationUtils.java @@ -24,17 +24,43 @@ public class TcpConversationUtils { /** *

* Given a {@link Conversation}, extract its set of "packet pairs", i.e., pairs of request-reply packets. + * The extracted pairs are formed from the full set of payload-carrying TCP packets. *

* * Note: in the current implementation, if one endpoint sends multiple packets back-to-back with no * interleaved reply packets from the other endpoint, such packets are converted to one-item pairs (i.e., instances - * of {@lin PcapPacketPair} where {@link PcapPacketPair#getSecond()} is {@code null}). + * of {@link PcapPacketPair} where {@link PcapPacketPair#getSecond()} is {@code null}). * * @param conv The {@code Conversation} for which packet pairs are to be extracted. * @return The packet pairs extracted from {@code conv}. */ public static List extractPacketPairs(Conversation conv) { - List packets = conv.getPackets(); + return extractPacketPairs(conv.getPackets()); + } + + + /** + *

+ * Given a {@link Conversation}, extract its set of "packet pairs", i.e., pairs of request-reply packets. + * The extracted pairs are formed from the full set of TLS Application Data packets. + *

+ * + * Note: in the current implementation, if one endpoint sends multiple packets back-to-back with no + * interleaved reply packets from the other endpoint, such packets are converted to one-item pairs (i.e., instances + * of {@link PcapPacketPair} where {@link PcapPacketPair#getSecond()} is {@code null}). + * + * @param conv The {@code Conversation} for which packet pairs are to be extracted. + * @return The packet pairs extracted from {@code conv}. + */ + public static List extractTlsAppDataPacketPairs(Conversation conv) { + if (!conv.isTls()) { + throw new IllegalArgumentException(String.format("Provided %s argument is not a TLS session")); + } + return extractPacketPairs(conv.getTlsApplicationDataPackets()); + } + + // Helper method for implementing the public API of similarly named methods. + private static List extractPacketPairs(List packets) { List pairs = new ArrayList<>(); int i = 0; while (i < packets.size()) { diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PcapPacketUtils.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PcapPacketUtils.java index 311fc66..8f998ee 100644 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PcapPacketUtils.java +++ b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PcapPacketUtils.java @@ -14,6 +14,17 @@ import java.util.Objects; */ public final class PcapPacketUtils { + /** + * Gets the source IP (in decimal format) of an IPv4 packet. + * @param packet The packet for which the IPv4 source address is to be extracted. + * @return The decimal representation of the source IP of {@code packet} iff {@code packet} wraps an + * {@link IpV4Packet}, otherwise {@code null}. + */ + public static String getSourceIp(PcapPacket packet) { + IpV4Packet ipPacket = packet.get(IpV4Packet.class); + return ipPacket == null ? null : ipPacket.getHeader().getSrcAddr().getHostAddress(); + } + /** * Helper method to determine if the given combination of IP and port matches the source of the given packet. * @param packet The packet to check. diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PrintUtils.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PrintUtils.java new file mode 100644 index 0000000..75a0035 --- /dev/null +++ b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PrintUtils.java @@ -0,0 +1,68 @@ +package edu.uci.iotproject.util; + +import edu.uci.iotproject.DnsMap; +import edu.uci.iotproject.analysis.PcapPacketPair; + +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Utility methods for generating (output) strings. + * + * @author Janus Varmarken {@literal } + * @author Rahmadi Trimananda {@literal } + */ +public class PrintUtils { + + private PrintUtils() { /* private constructor to prevent instantiation */ } + + + /** + * Converts a {@code PcapPacketPair} into a CSV string containing the packet lengths of the two packets in the pair. + * + * For example, the resulting string will be "123, 456" if the first packet of the pair has a length of 123 and the + * second packet of the pair has a length of 456. + * + * @return a CSV string containing the packet lengths of the two packets of the given {@code PcapPacketPair}. + */ + public static String toCsv(PcapPacketPair packetPair) { + return String.format("%d, %d", packetPair.getFirst().getOriginalLength(), + packetPair.getSecond().getOriginalLength()); + } + + /** + * Converts a {@code PcapPacketPair} into a CSV string containing the packet lengths of the two packets in the pair + * followed by the source of each packet. The source will be a (set of) hostname(s) if the source IP can be resolved + * to a (set of) hostname(s) using the provided {@link DnsMap}. + * + * For example, the resulting string will be "123, 456, 192.168.1.42, domain.com" if the first packet of the pair + * has a length of 123, the second packet of the pair has a length of 456, the first packet of the pair the pair has + * a source IP of '192.168.1.42' that cannot be resolved to a hostname, and the second packet of the pair has an IP + * that resolves to 'domain.com'. + * + * @return a CSV string containing the packet lengths of the two packets of the given {@code PcapPacketPair} as well + * as their respective sources. + */ + public static String toCsv(PcapPacketPair packetPair, DnsMap ipHostnameMappings) { + // First optain source IPs + String firstSrc = PcapPacketUtils.getSourceIp(packetPair.getFirst()); + String secondSrc = PcapPacketUtils.getSourceIp(packetPair.getSecond()); + + // If possible, map source IPs to hostnames. + Set firstHostnames = ipHostnameMappings.getHostnamesForIp(firstSrc); + Set secondHostnames = ipHostnameMappings.getHostnamesForIp(secondSrc); + final String delimiter = " "; + if (firstHostnames != null) { + // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter) + firstSrc = firstHostnames.stream().collect(Collectors.joining(delimiter)); + } + if (secondHostnames != null) { + // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter) + secondSrc = secondHostnames.stream().collect(Collectors.joining(delimiter)); + } + + return String.format("%d, %d, %s, %s", packetPair.getFirst().getOriginalLength(), + packetPair.getSecond().getOriginalLength(), firstSrc, secondSrc); + } + +}