Finished java-based clustering implementation (note: had to move Clusterable implemen...
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / util / PrintUtils.java
1 package edu.uci.iotproject.util;
2
3 import edu.uci.iotproject.DnsMap;
4 import edu.uci.iotproject.analysis.PcapPacketPair;
5 import org.apache.commons.math3.stat.clustering.Cluster;
6
7 import java.util.Optional;
8 import java.util.Set;
9 import java.util.stream.Collectors;
10
11 /**
12  * Utility methods for generating (output) strings.
13  *
14  * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
15  * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
16  */
17 public class PrintUtils {
18
19     private PrintUtils() { /* private constructor to prevent instantiation */ }
20
21
22     /**
23      * Converts a {@code PcapPacketPair} into a CSV string containing the packet lengths of the two packets in the pair.
24      *
25      * For example, the resulting string will be "123, 456" if the first packet of the pair has a length of 123 and the
26      * second packet of the pair has a length of 456.
27      *
28      * <b>Note:</b> if the {@link PcapPacketPair} has no second element, 0 is printed as the length of the second packet
29      * in the pair.
30      *
31      * @return a CSV string containing the packet lengths of the two packets of the given {@code PcapPacketPair}.
32      */
33     public static String toCsv(PcapPacketPair packetPair) {
34         return String.format("%d, %d", packetPair.getFirst().getOriginalLength(),
35                 packetPair.getSecond().map(pp -> pp.getOriginalLength()).orElse(0));
36     }
37
38     /**
39      * Converts a {@code PcapPacketPair} into a CSV string containing the packet lengths of the two packets in the pair
40      * followed by the source of each packet. The source will be a (set of) hostname(s) if the source IP can be resolved
41      * to a (set of) hostname(s) using the provided {@link DnsMap}.
42      *
43      * For example, the resulting string will be "123, 456, 192.168.1.42, domain.com" if the first packet of the pair
44      * 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
45      * 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
46      * that resolves to 'domain.com'.
47      *
48      * <b>Note:</b> if the {@link PcapPacketPair} has no second element, 0 is printed as the length of the second packet
49      * in the pair, and null is printed for its source.
50      *
51      * @return a CSV string containing the packet lengths of the two packets of the given {@code PcapPacketPair} as well
52      *         as their respective sources.
53      */
54     public static String toCsv(PcapPacketPair packetPair, DnsMap ipHostnameMappings) {
55         // First obtain source IPs
56         String firstSrc = PcapPacketUtils.getSourceIp(packetPair.getFirst());
57         // Note: use optional for second item in pair as there might not be one.
58         Optional<String> secondSrc = packetPair.getSecond().map(pkt -> PcapPacketUtils.getSourceIp(pkt));
59
60         // If possible, map source IPs to hostnames.
61         Set<String> firstHostnames = ipHostnameMappings.getHostnamesForIp(firstSrc);
62         Optional<Set<String>> secondHostnames = secondSrc.map(src -> ipHostnameMappings.getHostnamesForIp(src));
63         final String delimiter = " ";
64         if (firstHostnames != null) {
65             // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter)
66             firstSrc = firstHostnames.stream().collect(Collectors.joining(delimiter));
67         }
68         // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter)
69         Optional<String> hostnames = secondHostnames.map(hostnameSet -> hostnameSet.stream().collect(Collectors.joining(delimiter)));
70         // Fall back to IP if we couldn't second pair is present, but we couldn't map to (a) hostname(s).
71         secondSrc = hostnames.isPresent() ? hostnames : secondSrc;
72
73         // Check if the first source is C (client) or S (server)
74         String firstSrcCorS = packetPair.isFirstClient() ? "C" : "S";
75         String secondSrcCorS = packetPair.isSecondClient() ? "C" : "S";
76
77         return String.format("%d, %d, %s, %s, %s, %s", packetPair.getFirst().getOriginalLength(),
78                 packetPair.getSecond().map(pp -> pp.getOriginalLength()).orElse(0),
79                 firstSrc,
80                 secondSrc.orElse("null"),
81                 firstSrcCorS,
82                 secondSrcCorS);
83     }
84
85     /**
86      * Generate a string that summarizes/describes {@code cluster}.
87      * @param cluster The {@link Cluster} to summarize/describe.
88      * @return A string that summarizes/describes {@code cluster}.
89      */
90     public static String toSummaryString(Cluster<PcapPacketPair> cluster) {
91         StringBuilder sb = new StringBuilder();
92         for (PcapPacketPair ppp : cluster.getPoints()) {
93             sb.append(toCsv(ppp, ppp.getDnsMap()) + System.lineSeparator());
94         }
95         return sb.toString();
96     }
97 }