From c7f7365d26715352fbf43fc5da3b6025ce61095b Mon Sep 17 00:00:00 2001 From: Janus Varmarken Date: Tue, 25 Sep 2018 18:28:22 -0700 Subject: [PATCH] SignatureDetector.java: now also detects when the same sequence occurs multiple times in the same conversation. --- .../detection/SignatureDetector.java | 73 +++++++++++++------ 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/SignatureDetector.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/SignatureDetector.java index c97828b..cdcad85 100644 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/SignatureDetector.java +++ b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/SignatureDetector.java @@ -7,7 +7,9 @@ import edu.uci.iotproject.io.PcapHandleReader; import edu.uci.iotproject.util.PrintUtils; import org.pcap4j.core.*; +import java.time.ZoneId; import java.util.*; +import java.util.stream.Collectors; import static edu.uci.iotproject.util.PcapPacketUtils.*; @@ -19,24 +21,22 @@ import static edu.uci.iotproject.util.PcapPacketUtils.*; */ public class SignatureDetector implements PacketListener { + // Test client public static void main(String[] args) throws PcapNativeException, NotOpenException { - // Test client + // String path = "/scratch/July-2018"; // Rahmadi String path = "/Users/varmarken/temp/UCI IoT Project/experiments"; // Janus final String inputPcapFile = path + "/2018-07/dlink/dlink.wlan1.local.pcap"; final String signatureFile = path + "/2018-07/dlink/offSignature1.sig"; -// final String outputPcapFile = path + "/2018-07/dlink/dlink-processed.pcap"; -// final String triggerTimesFile = path + "/2018-07/dlink/dlink-july-26-2018.timestamps"; -// final String deviceIp = "192.168.1.199"; // .246 == phone; .199 == dlink plug? List> signature = PrintUtils.serializeClustersFromFile(signatureFile); SignatureDetector signatureDetector = new SignatureDetector(signature, null, (sig, match) -> System.out.println( - String.format("[ !!! SIGNATURE DETECTED AT %s !!! ]", match.get(0).getTimestamp().toString()) + String.format("[ !!! SIGNATURE DETECTED AT %s !!! ]", + match.get(0).getTimestamp().atZone(ZoneId.of("America/Los_Angeles"))) ) ); - PcapHandle handle; try { handle = Pcaps.openOffline(inputPcapFile, PcapHandle.TimestampPrecision.NANO); @@ -151,26 +151,55 @@ public class SignatureDetector implements PacketListener { // Fetch set of packets to examine based on TLS or not. List cPkts = c.isTls() ? c.getTlsApplicationDataPackets() : c.getPackets(); /* + * Note: we embed the attempt to detect the signature sequence in a loop in order to capture those cases + * where the same signature sequence appears multiple times in one Conversation. + * + * Note: as the cluster can be made up of identical sequences, we must keep track of whether we detected + * a match and, if so, break the inner for-each loop in order to prevent raising an alarm for each + * cluster-member (prevent duplicate detections of the same event). However, a negative side-effect of + * this is that, in doing so, we will also skip searching for subsequent different cluster members in + * the current conversation if the current cluster member is a match. + * * Note: since we expect all sequences that together make up the signature to exhibit the same direction * pattern, we can simply pass the precomputed direction array for the signature sequence so that it * won't have to be recomputed internally in each call to findSubsequenceInSequence(). */ - Optional> match = - findSubsequenceInSequence(signatureSequence, cPkts, mSignatureDirections, null); - match.ifPresent(ps -> Arrays.stream(mObservers).forEach(o -> o.onSignatureDetected(mSignature, ps))); - if (match.isPresent()) { + Optional> match; + boolean matchFound = false; + while ((match = findSubsequenceInSequence(signatureSequence, cPkts, mSignatureDirections, null)). + isPresent()) { + matchFound = true; + List matchSeq = match.get(); + // Notify observers about the match. + Arrays.stream(mObservers).forEach(o -> o.onSignatureDetected(mSignature, matchSeq)); /* - * We found an element in the signature cluster that was present in conversation, so no need to scan - * conversation for remaining members of signature cluster (in fact, we'd be getting duplicate - * output in those cases where the cluster is made up of identical sequences if we did not stop the - * search here). - * - * TODO: - * How do we handle those cases where the conversation matches the signature more than once (for - * example, the long-lived connections used for sending the trigger from the cloud)? + * Get the index in cPkts of the last packet in the sequence of packets that matches the searched + * signature sequence. */ + int matchSeqEndIdx = cPkts.indexOf(matchSeq.get(matchSeq.size()-1)); + // We restart the search for the signature sequence immediately after that index, so truncate cPkts. + cPkts = cPkts.stream().skip(matchSeqEndIdx + 1).collect(Collectors.toList()); + } + if (matchFound) { + // Break inner for-each loop in order to avoid duplicate detection of same event (see comment above) break; } + + +// match.ifPresent(ps -> Arrays.stream(mObservers).forEach(o -> o.onSignatureDetected(mSignature, ps))); +// if (match.isPresent()) { +// /* +// * We found an element in the signature cluster that was present in conversation, so no need to scan +// * conversation for remaining members of signature cluster (in fact, we'd be getting duplicate +// * output in those cases where the cluster is made up of identical sequences if we did not stop the +// * search here). +// * +// * TODO: +// * How do we handle those cases where the conversation matches the signature more than once (for +// * example, the long-lived connections used for sending the trigger from the cloud)? +// */ +// break; +// } } } } @@ -262,14 +291,14 @@ public class SignatureDetector implements PacketListener { List sequence, Conversation.Direction[] subsequenceDirections, Conversation.Direction[] sequenceDirections) { - if (isTlsSequence(subsequence) != isTlsSequence(sequence)) { - // We consider it a mismatch if one is a TLS application data sequence and the other is not. - return Optional.empty(); - } if (sequence.size() < subsequence.size()) { // If subsequence is longer, it cannot be contained in sequence. return Optional.empty(); } + if (isTlsSequence(subsequence) != isTlsSequence(sequence)) { + // We consider it a mismatch if one is a TLS application data sequence and the other is not. + return Optional.empty(); + } // If packet directions have not been precomputed by calling code, we need to construct them. if (subsequenceDirections == null) { subsequenceDirections = getPacketDirections(subsequence, mRouterWanIp); -- 2.34.1