From: rtrimana Date: Tue, 5 Feb 2019 01:39:30 +0000 (-0800) Subject: Removing SmartPlugDetector. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=8b52037e885f115be6ddd69596d9f1c8773895c7;hp=5c58e0e7c0546f88866f04d4f1d627bc6f0045f1;p=pingpong.git Removing SmartPlugDetector. --- diff --git a/Code/Projects/SmartPlugDetector/.gitignore b/Code/Projects/SmartPlugDetector/.gitignore deleted file mode 100644 index b0ff774..0000000 --- a/Code/Projects/SmartPlugDetector/.gitignore +++ /dev/null @@ -1,65 +0,0 @@ -# Borrowed from https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore - -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/dictionaries - -# Sensitive or high-churn files: -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.xml -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml - -# Gradle: (combination of the JetBrains gitiginre and Gradle gitignore at ) -.idea/**/gradle.xml -.idea/**/libraries -.gradle -/build/ -# Ignore Gradle GUI config -gradle-app.setting -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar -# Cache of project -.gradletasknamecache -# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties - -# CMake -cmake-build-debug/ - -# Mongo Explorer plugin: -.idea/**/mongoSettings.xml - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# ignore misc as it changes a lot depending on local settings -- however may need to be included later on. -.idea/misc.xml - diff --git a/Code/Projects/SmartPlugDetector/.idea/compiler.xml b/Code/Projects/SmartPlugDetector/.idea/compiler.xml deleted file mode 100644 index 6691f42..0000000 --- a/Code/Projects/SmartPlugDetector/.idea/compiler.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/.idea/copyright/profiles_settings.xml b/Code/Projects/SmartPlugDetector/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf3..0000000 --- a/Code/Projects/SmartPlugDetector/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/.idea/encodings.xml b/Code/Projects/SmartPlugDetector/.idea/encodings.xml deleted file mode 100644 index 15a15b2..0000000 --- a/Code/Projects/SmartPlugDetector/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/.idea/modules.xml b/Code/Projects/SmartPlugDetector/.idea/modules.xml deleted file mode 100644 index 7eb5abd..0000000 --- a/Code/Projects/SmartPlugDetector/.idea/modules.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/.idea/modules/PacketLevelSignatureExtractor.iml b/Code/Projects/SmartPlugDetector/.idea/modules/PacketLevelSignatureExtractor.iml deleted file mode 100644 index 202c5ac..0000000 --- a/Code/Projects/SmartPlugDetector/.idea/modules/PacketLevelSignatureExtractor.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/.idea/vcs.xml b/Code/Projects/SmartPlugDetector/.idea/vcs.xml deleted file mode 100644 index c2365ab..0000000 --- a/Code/Projects/SmartPlugDetector/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/build.gradle b/Code/Projects/SmartPlugDetector/build.gradle deleted file mode 100644 index 2027ed3..0000000 --- a/Code/Projects/SmartPlugDetector/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -group 'edu.uci.iotproject' -version '1.0-SNAPSHOT' - -apply plugin: 'java' -apply plugin: 'application' - -// Increase max memory -applicationDefaultJvmArgs = ["-Xmx300g"] - -sourceCompatibility = 1.8 - -//mainClassName = "edu.uci.iotproject.Main" -//mainClassName = "edu.uci.iotproject.detection.SignatureDetector" -//mainClassName = "edu.uci.iotproject.detection.layer2.Layer2SignatureDetector" -//mainClassName = "edu.uci.iotproject.evaluation.DetectionResultsAnalyzer" -mainClassName = System.getProperty("mainClass") - - -repositories { - mavenCentral() -} - -dependencies { - testCompile group: 'junit', name: 'junit', version: '4.11' - - // pcap4j - // Updated to v2 alpha as the stable release does not include packet timestamps - // v2 should add support for TCP session reassembly as well, although it does not appear to be part of the lib yet. - compile 'org.pcap4j:pcap4j-core:2.0.0-alpha' - compile 'org.pcap4j:pcap4j-packetfactory-static:2.0.0-alpha' - - // pcap4j logging dependency - compile 'org.slf4j:slf4j-jdk14:1.8.0-beta2' - - // Apache Commons Math for clustering - compile 'org.apache.commons:commons-math3:3.6.1' - - // JGraphT: Java Graph library - compile 'org.jgrapht:jgrapht-core:1.2.0' -} \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/devices/dlink_switch/dlink-june-26-2018.timestamps b/Code/Projects/SmartPlugDetector/devices/dlink_switch/dlink-june-26-2018.timestamps deleted file mode 100644 index 5aba10d..0000000 --- a/Code/Projects/SmartPlugDetector/devices/dlink_switch/dlink-june-26-2018.timestamps +++ /dev/null @@ -1,147 +0,0 @@ -10:12:06 AM -10:14:17 AM -10:16:29 AM -10:18:41 AM -10:20:53 AM -10:23:06 AM -10:25:12 AM -10:27:24 AM -10:29:36 AM -10:31:47 AM -10:33:59 AM -10:36:11 AM -10:38:23 AM -10:40:34 AM -10:42:46 AM -10:44:58 AM -10:47:10 AM -10:49:21 AM -10:51:33 AM -10:53:45 AM -10:55:56 AM -10:58:08 AM -11:00:20 AM -11:02:32 AM -11:04:44 AM -11:06:55 AM -11:09:07 AM -11:11:19 AM -11:13:31 AM -11:15:43 AM -11:17:54 AM -11:20:06 AM -11:22:18 AM -11:24:30 AM -11:26:42 AM -11:28:53 AM -11:31:05 AM -11:33:17 AM -11:35:29 AM -11:37:41 AM -11:39:53 AM -11:42:05 AM -11:44:16 AM -11:46:28 AM -11:48:40 AM -11:50:52 AM -11:53:04 AM -11:55:16 AM -11:57:27 AM -11:59:39 AM -12:01:51 PM -12:04:03 PM -12:06:15 PM -12:08:26 PM -12:10:38 PM -12:12:50 PM -12:15:02 PM -12:17:14 PM -12:19:25 PM -12:21:37 PM -12:23:49 PM -12:26:01 PM -12:28:13 PM -12:30:25 PM -12:32:36 PM -12:34:48 PM -12:37:00 PM -12:39:12 PM -12:41:24 PM -12:43:35 PM -12:45:47 PM -12:47:59 PM -12:50:11 PM -12:52:23 PM -12:54:34 PM -12:56:46 PM -12:58:58 PM -01:01:10 PM -01:03:22 PM -01:05:34 PM -01:07:45 PM -01:09:57 PM -01:12:09 PM -01:14:21 PM -01:16:33 PM -01:18:44 PM -01:20:56 PM -01:23:08 PM -01:25:20 PM -01:27:31 PM -01:29:43 PM -01:31:55 PM -01:34:07 PM -01:36:19 PM -01:38:30 PM -01:40:42 PM -01:42:54 PM -01:45:06 PM -01:47:18 PM -01:49:29 PM -01:51:41 PM -01:53:53 PM -01:56:05 PM -01:58:17 PM -02:00:29 PM -02:02:40 PM -02:04:52 PM -02:07:04 PM -02:09:16 PM -02:11:27 PM -02:13:39 PM -02:15:51 PM -02:18:03 PM -02:20:14 PM -02:22:26 PM -02:24:38 PM -02:26:50 PM -02:29:02 PM -02:31:13 PM -02:33:25 PM -02:35:37 PM -02:37:49 PM -02:40:01 PM -02:42:12 PM -02:44:24 PM -02:46:36 PM -02:48:48 PM -02:51:00 PM -02:53:12 PM -02:55:23 PM -02:57:35 PM -02:59:47 PM -03:01:59 PM -03:04:11 PM -03:06:22 PM -03:08:34 PM -03:10:46 PM -03:12:58 PM -03:15:10 PM -03:17:22 PM -03:19:33 PM -03:21:45 PM -03:23:57 PM -03:26:09 PM -03:28:21 PM -03:30:32 PM -03:32:44 PM diff --git a/Code/Projects/SmartPlugDetector/devices/tplink_switch/datapoints.csv b/Code/Projects/SmartPlugDetector/devices/tplink_switch/datapoints.csv deleted file mode 100644 index e20e14c..0000000 --- a/Code/Projects/SmartPlugDetector/devices/tplink_switch/datapoints.csv +++ /dev/null @@ -1,212 +0,0 @@ -2018-06-14T21:26:52.605940Z, 583, 1514 -2018-06-14T21:26:52.735845Z, 257, 117 -2018-06-14T21:26:52.751637Z, 557, 1232 -2018-06-14T21:26:52.942376Z, 97, 1514 -2018-06-14T21:31:15.929711Z, 257, 117 -2018-06-14T21:31:15.955136Z, 557, 1232 -2018-06-14T21:31:16.053208Z, 97, 1514 -2018-06-14T21:33:27.814139Z, 257, 117 -2018-06-14T21:33:27.838872Z, 556, 1231 -2018-06-14T21:33:27.944639Z, 97, 1514 -2018-06-14T21:35:39.384597Z, 257, 117 -2018-06-14T21:35:39.399549Z, 557, 1232 -2018-06-14T21:35:39.493602Z, 97, 1514 -2018-06-14T21:37:51.337631Z, 257, 117 -2018-06-14T21:37:51.346803Z, 556, 1231 -2018-06-14T21:37:51.464128Z, 97, 1514 -2018-06-14T21:40:02.949700Z, 257, 117 -2018-06-14T21:40:02.958853Z, 557, 1232 -2018-06-14T21:40:03.060923Z, 97, 1514 -2018-06-14T21:42:14.773280Z, 257, 117 -2018-06-14T21:42:14.782190Z, 556, 1232 -2018-06-14T21:42:15.013423Z, 97, 1514 -2018-06-14T21:44:26.515492Z, 257, 117 -2018-06-14T21:44:26.531874Z, 557, 1233 -2018-06-14T21:44:26.724732Z, 97, 1514 -2018-06-14T21:46:38.112283Z, 257, 117 -2018-06-14T21:46:38.123799Z, 556, 1231 -2018-06-14T21:46:38.371410Z, 97, 1514 -2018-06-14T21:48:49.822864Z, 257, 117 -2018-06-14T21:48:49.831109Z, 557, 1232 -2018-06-14T21:48:49.920489Z, 97, 1514 -2018-06-14T21:51:01.570404Z, 257, 117 -2018-06-14T21:51:01.580522Z, 556, 1232 -2018-06-14T21:51:01.686542Z, 97, 1514 -2018-06-14T21:53:13.290982Z, 257, 117 -2018-06-14T21:53:13.300135Z, 557, 1232 -2018-06-14T21:53:13.388833Z, 97, 1514 -2018-06-14T21:55:25.010146Z, 257, 117 -2018-06-14T21:55:25.018841Z, 556, 1231 -2018-06-14T21:55:25.107384Z, 97, 1514 -2018-06-14T21:57:36.737105Z, 257, 117 -2018-06-14T21:57:36.747764Z, 557, 1232 -2018-06-14T21:57:36.848624Z, 97, 1514 -2018-06-14T21:59:48.451103Z, 257, 117 -2018-06-14T21:59:48.459599Z, 556, 1231 -2018-06-14T21:59:48.550304Z, 97, 1514 -2018-06-14T22:02:00.123236Z, 257, 117 -2018-06-14T22:02:00.174134Z, 557, 1233 -2018-06-14T22:02:00.274621Z, 97, 1514 -2018-06-14T22:04:11.987297Z, 257, 117 -2018-06-14T22:04:11.999329Z, 556, 1231 -2018-06-14T22:04:12.101197Z, 97, 1514 -2018-06-14T22:06:23.548097Z, 257, 117 -2018-06-14T22:06:23.557567Z, 557, 1232 -2018-06-14T22:06:23.655666Z, 97, 1514 -2018-06-14T22:08:35.266519Z, 257, 117 -2018-06-14T22:08:35.276110Z, 556, 1232 -2018-06-14T22:08:35.372971Z, 97, 1514 -2018-06-14T22:10:46.993448Z, 257, 117 -2018-06-14T22:10:47.004664Z, 557, 1232 -2018-06-14T22:10:47.094221Z, 97, 1514 -2018-06-14T22:12:58.719472Z, 257, 117 -2018-06-14T22:12:58.729955Z, 556, 1231 -2018-06-14T22:12:58.825877Z, 97, 1514 -2018-06-14T22:15:10.424740Z, 257, 117 -2018-06-14T22:15:10.439685Z, 557, 1232 -2018-06-14T22:15:10.529340Z, 97, 1514 -2018-06-14T22:17:22.490347Z, 257, 117 -2018-06-14T22:17:22.499099Z, 556, 1231 -2018-06-14T22:17:22.602375Z, 97, 1514 -2018-06-14T22:19:33.901877Z, 257, 117 -2018-06-14T22:19:34.027607Z, 557, 1232 -2018-06-14T22:19:34.267480Z, 97, 1514 -2018-06-14T22:21:45.607148Z, 257, 117 -2018-06-14T22:21:45.615804Z, 556, 1231 -2018-06-14T22:21:45.705662Z, 97, 1514 -2018-06-14T22:23:57.442622Z, 257, 117 -2018-06-14T22:23:57.683565Z, 557, 1232 -2018-06-14T22:23:57.798191Z, 97, 1514 -2018-06-14T22:26:09.017436Z, 257, 117 -2018-06-14T22:26:09.027137Z, 556, 1231 -2018-06-14T22:26:09.122329Z, 97, 1514 -2018-06-14T22:28:20.722388Z, 257, 117 -2018-06-14T22:28:20.733875Z, 557, 1233 -2018-06-14T22:28:20.824306Z, 97, 1514 -2018-06-14T22:30:32.443171Z, 257, 117 -2018-06-14T22:30:32.451523Z, 556, 1231 -2018-06-14T22:30:32.568985Z, 97, 1514 -2018-06-14T22:32:44.142809Z, 257, 117 -2018-06-14T22:32:44.153146Z, 557, 1232 -2018-06-14T22:32:44.240783Z, 97, 1514 -2018-06-14T22:34:55.819124Z, 257, 117 -2018-06-14T22:34:55.828083Z, 556, 1231 -2018-06-14T22:34:55.921204Z, 97, 1514 -2018-06-14T22:37:07.879332Z, 257, 117 -2018-06-14T22:37:07.888554Z, 557, 1233 -2018-06-14T22:37:07.988689Z, 97, 1514 -2018-06-14T22:39:19.274678Z, 257, 117 -2018-06-14T22:39:19.288124Z, 556, 1231 -2018-06-14T22:39:19.656442Z, 97, 1514 -2018-06-14T22:41:30.964690Z, 257, 117 -2018-06-14T22:41:30.973618Z, 557, 1233 -2018-06-14T22:41:31.067046Z, 97, 1514 -2018-06-14T22:43:43.077721Z, 257, 117 -2018-06-14T22:43:43.086330Z, 556, 1231 -2018-06-14T22:43:43.181685Z, 97, 1514 -2018-06-14T22:45:54.827796Z, 257, 117 -2018-06-14T22:45:55.069246Z, 557, 1232 -2018-06-14T22:45:55.160465Z, 97, 1514 -2018-06-14T22:48:06.406787Z, 257, 117 -2018-06-14T22:48:06.417554Z, 556, 1231 -2018-06-14T22:48:06.508248Z, 97, 1514 -2018-06-14T22:50:18.410511Z, 257, 117 -2018-06-14T22:50:18.428958Z, 557, 1233 -2018-06-14T22:50:18.517176Z, 97, 1514 -2018-06-14T22:52:30.194505Z, 257, 117 -2018-06-14T22:52:30.435770Z, 556, 1231 -2018-06-14T22:52:30.538992Z, 97, 1514 -2018-06-14T22:54:41.863578Z, 257, 117 -2018-06-14T22:54:41.880756Z, 557, 1232 -2018-06-14T22:54:42.084464Z, 97, 1514 -2018-06-14T22:56:53.560739Z, 257, 117 -2018-06-14T22:56:53.569597Z, 556, 1232 -2018-06-14T22:56:53.673619Z, 97, 1514 -2018-06-14T22:59:05.382524Z, 257, 117 -2018-06-14T22:59:05.518950Z, 557, 1233 -2018-06-14T22:59:05.759331Z, 97, 1514 -2018-06-14T23:01:17.010034Z, 257, 117 -2018-06-14T23:01:17.020314Z, 556, 1231 -2018-06-14T23:01:17.111675Z, 97, 1514 -2018-06-14T23:03:28.880684Z, 257, 117 -2018-06-14T23:03:29.072908Z, 557, 1233 -2018-06-14T23:03:29.162062Z, 97, 1233 -2018-06-14T23:03:29.372873Z, 97, 1233 -2018-06-14T23:03:29.796823Z, 97, 1233 -2018-06-14T23:03:30.644846Z, 97, 1233 -2018-06-14T23:05:40.295435Z, 583, 1514 -2018-06-14T23:05:40.406380Z, 257, 117 -2018-06-14T23:05:40.414912Z, 556, 1231 -2018-06-14T23:05:40.510786Z, 97, 1514 -2018-06-14T23:07:52.137010Z, 257, 117 -2018-06-14T23:07:52.145417Z, 557, 1232 -2018-06-14T23:07:52.238296Z, 97, 1514 -2018-06-14T23:10:03.836854Z, 257, 117 -2018-06-14T23:10:03.845785Z, 556, 1231 -2018-06-14T23:10:03.954532Z, 97, 1514 -2018-06-14T23:12:15.863692Z, 257, 117 -2018-06-14T23:12:15.872553Z, 557, 1232 -2018-06-14T23:12:15.960238Z, 97, 1514 -2018-06-14T23:14:27.433510Z, 257, 117 -2018-06-14T23:14:27.444485Z, 556, 1232 -2018-06-14T23:14:27.581636Z, 97, 1514 -2018-06-14T23:16:39.095173Z, 257, 117 -2018-06-14T23:16:39.106066Z, 557, 1232 -2018-06-14T23:16:39.333696Z, 97, 1514 -2018-06-14T23:18:50.777902Z, 257, 117 -2018-06-14T23:18:50.793779Z, 556, 1231 -2018-06-14T23:18:51.008180Z, 97, 1514 -2018-06-14T23:21:02.468604Z, 257, 117 -2018-06-14T23:21:02.476717Z, 557, 1232 -2018-06-14T23:21:02.568758Z, 97, 1514 -2018-06-14T23:23:14.178586Z, 257, 117 -2018-06-14T23:23:14.187241Z, 556, 1231 -2018-06-14T23:23:14.275795Z, 97, 1514 -2018-06-14T23:25:25.823314Z, 257, 117 -2018-06-14T23:25:25.832887Z, 557, 1232 -2018-06-14T23:25:25.922327Z, 97, 1514 -2018-06-14T23:27:37.579030Z, 257, 117 -2018-06-14T23:27:37.591104Z, 556, 1231 -2018-06-14T23:27:38.078402Z, 97, 1514 -2018-06-14T23:29:49.339321Z, 257, 117 -2018-06-14T23:29:49.348203Z, 557, 1232 -2018-06-14T23:29:49.461787Z, 97, 1514 -2018-06-14T23:32:01.186019Z, 257, 117 -2018-06-14T23:32:01.428258Z, 556, 1231 -2018-06-14T23:32:01.533656Z, 97, 1514 -2018-06-14T23:34:12.834815Z, 257, 117 -2018-06-14T23:34:12.843481Z, 557, 1232 -2018-06-14T23:34:12.928779Z, 97, 1514 -2018-06-14T23:36:24.544064Z, 257, 117 -2018-06-14T23:36:24.557290Z, 556, 1232 -2018-06-14T23:36:24.650229Z, 97, 1514 -2018-06-14T23:38:36.223538Z, 257, 117 -2018-06-14T23:38:36.233426Z, 557, 1233 -2018-06-14T23:38:36.327259Z, 97, 1514 -2018-06-14T23:40:49.179957Z, 257, 117 -2018-06-14T23:40:49.188599Z, 556, 1231 -2018-06-14T23:40:49.298503Z, 97, 1514 -2018-06-14T23:42:59.647277Z, 257, 117 -2018-06-14T23:42:59.656010Z, 557, 1233 -2018-06-14T23:42:59.757990Z, 97, 1514 -2018-06-14T23:45:11.460191Z, 257, 117 -2018-06-14T23:45:11.468421Z, 556, 1232 -2018-06-14T23:45:11.562054Z, 97, 1514 -2018-06-14T23:47:23.154254Z, 257, 117 -2018-06-14T23:47:23.169868Z, 557, 1232 -2018-06-14T23:47:23.332188Z, 97, 1514 -2018-06-14T23:49:34.819052Z, 257, 117 -2018-06-14T23:49:34.833029Z, 556, 1232 -2018-06-14T23:49:34.951756Z, 97, 1514 -2018-06-14T23:51:46.542034Z, 257, 117 -2018-06-14T23:51:46.554905Z, 557, 1232 -2018-06-14T23:51:46.647936Z, 97, 1514 -2018-06-14T23:53:58.191828Z, 257, 117 -2018-06-14T23:53:58.200872Z, 556, 1232 -2018-06-14T23:53:58.304961Z, 97, 1514 -2018-06-14T23:56:09.961905Z, 257, 117 -2018-06-14T23:56:09.971113Z, 557, 1232 -2018-06-14T23:56:10.063261Z, 97, 1514 -2018-06-14T23:58:21.713165Z, 257, 117 -2018-06-14T23:58:21.722455Z, 556, 1231 -2018-06-14T23:58:21.808565Z, 97, \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/devices/tplink_switch/tplink-feb-13-2018.timestamps b/Code/Projects/SmartPlugDetector/devices/tplink_switch/tplink-feb-13-2018.timestamps deleted file mode 100644 index ca011b8..0000000 --- a/Code/Projects/SmartPlugDetector/devices/tplink_switch/tplink-feb-13-2018.timestamps +++ /dev/null @@ -1,12 +0,0 @@ -2:38:04 PM -2:39:03 PM -2:40:05 PM -2:41:08 PM -2:42:07 PM -2:43:09 PM -2:45:25 PM -2:46:27 PM -2:47:28 PM -2:48:29 PM -2:49:31 PM -2:50:30 PM diff --git a/Code/Projects/SmartPlugDetector/devices/tplink_switch/tplink-june-14-2018.timestamps b/Code/Projects/SmartPlugDetector/devices/tplink_switch/tplink-june-14-2018.timestamps deleted file mode 100644 index 58b118e..0000000 --- a/Code/Projects/SmartPlugDetector/devices/tplink_switch/tplink-june-14-2018.timestamps +++ /dev/null @@ -1,680 +0,0 @@ -2:24:40 PM -2:26:52 PM -2:29:04 PM -2:31:15 PM -2:33:27 PM -2:35:39 PM -2:37:51 PM -2:40:02 PM -2:42:14 PM -2:44:26 PM -2:46:37 PM -2:48:49 PM -2:51:01 PM -2:53:13 PM -2:55:24 PM -2:57:36 PM -2:59:48 PM -3:02:00 PM -3:04:11 PM -3:06:23 PM -3:08:35 PM -3:10:46 PM -3:12:58 PM -3:15:10 PM -3:17:22 PM -3:19:33 PM -3:21:45 PM -3:23:57 PM -3:26:08 PM -3:28:20 PM -3:30:32 PM -3:32:44 PM -3:34:55 PM -3:37:07 PM -3:39:19 PM -3:41:30 PM -3:43:42 PM -3:45:54 PM -3:48:06 PM -3:50:18 PM -3:52:29 PM -3:54:41 PM -3:56:53 PM -3:59:05 PM -4:01:16 PM -4:03:28 PM -4:05:40 PM -4:07:52 PM -4:10:03 PM -4:12:15 PM -4:14:27 PM -4:16:38 PM -4:18:50 PM -4:21:02 PM -4:23:14 PM -4:25:25 PM -4:27:37 PM -4:29:49 PM -4:32:00 PM -4:34:12 PM -4:36:24 PM -4:38:36 PM -4:40:47 PM -4:42:59 PM -4:45:11 PM -4:47:22 PM -4:49:34 PM -4:51:46 PM -4:53:58 PM -4:56:09 PM -4:58:21 PM -5:00:33 PM -5:02:44 PM -5:04:56 PM -5:07:08 PM -5:09:20 PM -5:11:31 PM -5:13:43 PM -5:15:55 PM -5:18:06 PM -5:20:18 PM -5:22:30 PM -5:24:42 PM -5:26:53 PM -5:29:05 PM -5:31:17 PM -5:33:28 PM -5:35:40 PM -5:37:52 PM -5:40:03 PM -5:42:15 PM -5:44:27 PM -5:46:39 PM -5:48:50 PM -5:51:02 PM -5:53:14 PM -5:55:25 PM -5:57:37 PM -5:59:49 PM -6:02:01 PM -6:04:12 PM -6:06:24 PM -6:08:36 PM -6:10:48 PM -6:13:00 PM -6:15:11 PM -6:17:23 PM -6:19:35 PM -6:21:47 PM -6:23:58 PM -6:26:10 PM -6:28:22 PM -6:30:33 PM -6:32:45 PM -6:34:57 PM -6:37:09 PM -6:39:20 PM -6:41:32 PM -6:43:44 PM -6:45:55 PM -6:48:07 PM -6:50:19 PM -6:52:31 PM -6:54:42 PM -6:56:54 PM -6:59:06 PM -7:01:18 PM -7:03:29 PM -7:05:41 PM -7:07:53 PM -7:10:04 PM -7:12:16 PM -7:14:28 PM -7:16:40 PM -7:18:51 PM -7:21:03 PM -7:23:15 PM -7:25:26 PM -7:27:38 PM -7:29:50 PM -7:32:02 PM -7:34:13 PM -7:36:25 PM -7:38:37 PM -7:40:48 PM -7:43:00 PM -7:45:12 PM -7:47:23 PM -7:49:35 PM -7:51:47 PM -7:53:59 PM -7:56:10 PM -7:58:22 PM -8:00:34 PM -8:02:46 PM -8:04:57 PM -8:07:09 PM -8:09:21 PM -8:11:32 PM -8:13:44 PM -8:15:56 PM -8:18:08 PM -8:20:19 PM -8:22:31 PM -8:24:43 PM -8:26:55 PM -8:29:06 PM -8:31:18 PM -8:33:30 PM -8:35:41 PM -8:37:53 PM -8:40:05 PM -8:42:17 PM -8:44:28 PM -8:46:40 PM -8:48:52 PM -8:51:03 PM -8:53:15 PM -8:55:27 PM -8:57:39 PM -8:59:50 PM -9:02:02 PM -9:04:14 PM -9:06:26 PM -9:08:37 PM -9:10:49 PM -9:13:01 PM -9:15:13 PM -9:17:24 PM -9:19:36 PM -9:21:48 PM -9:23:59 PM -9:26:11 PM -9:28:23 PM -9:30:35 PM -9:32:46 PM -9:34:58 PM -9:37:10 PM -9:39:22 PM -9:41:33 PM -9:43:45 PM -9:45:57 PM -9:48:09 PM -9:50:20 PM -9:52:32 PM -9:54:44 PM -9:56:56 PM -9:59:07 PM -10:01:19 PM -10:03:31 PM -10:05:43 PM -10:07:54 PM -10:10:06 PM -10:12:18 PM -10:14:29 PM -10:16:41 PM -10:18:53 PM -10:21:05 PM -10:23:17 PM -10:25:29 PM -10:27:40 PM -10:29:52 PM -10:32:04 PM -10:34:16 PM -10:36:27 PM -10:38:39 PM -10:40:51 PM -10:43:02 PM -10:45:14 PM -10:47:26 PM -10:49:38 PM -10:51:49 PM -10:54:01 PM -10:56:13 PM -10:58:25 PM -11:00:36 PM -11:02:48 PM -11:05:00 PM -11:07:12 PM -11:09:23 PM -11:11:35 PM -11:13:47 PM -11:15:58 PM -11:18:10 PM -11:20:22 PM -11:22:33 PM -11:24:45 PM -11:26:57 PM -11:29:09 PM -11:31:20 PM -11:33:32 PM -11:35:44 PM -11:37:56 PM -11:40:07 PM -11:42:19 PM -11:44:31 PM -11:46:42 PM -11:48:54 PM -11:51:06 PM -11:53:17 PM -11:55:29 PM -11:57:41 PM -11:59:53 PM -12:02:04 AM -12:04:16 AM -12:06:28 AM -12:08:40 AM -12:10:51 AM -12:13:03 AM -12:15:15 AM -12:17:27 AM -12:19:38 AM -12:21:50 AM -12:24:02 AM -12:26:13 AM -12:28:25 AM -12:30:37 AM -12:32:49 AM -12:35:00 AM -12:37:12 AM -12:39:24 AM -12:41:36 AM -12:43:47 AM -12:45:59 AM -12:48:11 AM -12:50:23 AM -12:52:34 AM -12:54:46 AM -12:56:58 AM -12:59:10 AM -1:01:21 AM -1:03:33 AM -1:05:45 AM -1:07:57 AM -1:10:08 AM -1:12:20 AM -1:14:32 AM -1:16:44 AM -1:18:55 AM -1:21:07 AM -1:23:19 AM -1:25:31 AM -1:27:42 AM -1:29:54 AM -1:32:06 AM -1:34:18 AM -1:36:29 AM -1:38:41 AM -1:40:53 AM -1:43:04 AM -1:45:16 AM -1:47:28 AM -1:49:40 AM -1:51:51 AM -1:54:03 AM -1:56:15 AM -1:58:27 AM -2:00:38 AM -2:02:50 AM -2:05:02 AM -2:07:13 AM -2:09:25 AM -2:11:37 AM -2:13:48 AM -2:16:00 AM -2:18:12 AM -2:20:24 AM -2:22:35 AM -2:24:47 AM -2:26:59 AM -2:29:11 AM -2:31:22 AM -2:33:34 AM -2:35:46 AM -2:37:57 AM -2:40:09 AM -2:42:21 AM -2:44:33 AM -2:46:44 AM -2:48:56 AM -2:51:08 AM -2:53:19 AM -2:55:31 AM -2:57:43 AM -2:59:55 AM -3:02:06 AM -3:04:18 AM -3:06:30 AM -3:08:42 AM -3:10:53 AM -3:13:05 AM -3:15:17 AM -3:17:29 AM -3:19:40 AM -3:21:52 AM -3:24:04 AM -3:26:15 AM -3:28:27 AM -3:30:39 AM -3:32:51 AM -3:35:02 AM -3:37:14 AM -3:39:26 AM -3:41:37 AM -3:43:49 AM -3:46:01 AM -3:48:13 AM -3:50:24 AM -3:52:36 AM -3:54:48 AM -3:57:00 AM -3:59:11 AM -4:01:23 AM -4:03:35 AM -4:05:47 AM -4:07:58 AM -4:10:10 AM -4:12:22 AM -4:14:33 AM -4:16:45 AM -4:18:57 AM -4:21:09 AM -4:23:20 AM -4:25:32 AM -4:27:44 AM -4:29:56 AM -4:32:07 AM -4:34:19 AM -4:36:31 AM -4:38:42 AM -4:40:54 AM -4:43:06 AM -4:45:18 AM -4:47:29 AM -4:49:41 AM -4:51:53 AM -4:54:05 AM -4:56:16 AM -4:58:28 AM -5:00:40 AM -5:02:52 AM -5:05:03 AM -5:07:15 AM -5:09:27 AM -5:11:39 AM -5:13:50 AM -5:16:02 AM -5:18:14 AM -5:20:26 AM -5:22:38 AM -5:24:49 AM -5:27:01 AM -5:29:13 AM -5:31:25 AM -5:33:36 AM -5:35:48 AM -5:38:00 AM -5:40:11 AM -5:42:23 AM -5:44:35 AM -5:46:47 AM -5:48:58 AM -5:51:10 AM -5:53:22 AM -5:55:33 AM -5:57:45 AM -5:59:57 AM -6:02:09 AM -6:04:21 AM -6:06:32 AM -6:08:44 AM -6:10:56 AM -6:13:07 AM -6:15:19 AM -6:17:31 AM -6:19:43 AM -6:21:54 AM -6:24:06 AM -6:26:18 AM -6:28:30 AM -6:30:41 AM -6:32:53 AM -6:35:05 AM -6:37:17 AM -6:39:28 AM -6:41:40 AM -6:43:52 AM -6:46:03 AM -6:48:15 AM -6:50:27 AM -6:52:39 AM -6:54:50 AM -6:57:02 AM -6:59:14 AM -7:01:26 AM -7:03:37 AM -7:05:49 AM -7:08:01 AM -7:10:13 AM -7:12:24 AM -7:14:36 AM -7:16:48 AM -7:18:59 AM -7:21:11 AM -7:23:23 AM -7:25:35 AM -7:27:46 AM -7:29:58 AM -7:32:10 AM -7:34:22 AM -7:36:33 AM -7:38:45 AM -7:40:57 AM -7:43:08 AM -7:45:20 AM -7:47:32 AM -7:49:44 AM -7:51:55 AM -7:54:07 AM -7:56:19 AM -7:58:30 AM -8:00:42 AM -8:02:54 AM -8:05:06 AM -8:07:17 AM -8:09:29 AM -8:11:41 AM -8:13:53 AM -8:16:04 AM -8:18:16 AM -8:20:28 AM -8:22:39 AM -8:24:51 AM -8:27:03 AM -8:29:15 AM -8:31:26 AM -8:33:38 AM -8:35:50 AM -8:38:01 AM -8:40:13 AM -8:42:25 AM -8:44:36 AM -8:46:48 AM -8:49:00 AM -8:51:11 AM -8:53:23 AM -8:55:35 AM -8:57:47 AM -8:59:58 AM -9:02:10 AM -9:04:22 AM -9:06:34 AM -9:08:45 AM -9:10:57 AM -9:13:09 AM -9:15:21 AM -9:17:32 AM -9:19:44 AM -9:21:56 AM -9:24:07 AM -9:26:19 AM -9:28:31 AM -9:30:43 AM -9:32:54 AM -9:35:06 AM -9:37:18 AM -9:39:30 AM -9:41:41 AM -9:43:53 AM -9:46:05 AM -9:48:18 AM -9:50:30 AM -9:52:42 AM -9:54:54 AM -9:57:06 AM -9:59:18 AM -10:01:30 AM -10:03:42 AM -10:05:54 AM -10:08:07 AM -10:10:19 AM -10:12:31 AM -10:14:43 AM -10:16:55 AM -10:19:07 AM -10:21:19 AM -10:23:32 AM -10:25:44 AM -10:27:56 AM -10:30:08 AM -10:32:20 AM -10:34:32 AM -10:36:44 AM -10:38:56 AM -10:41:09 AM -10:43:21 AM -10:45:33 AM -10:47:45 AM -10:49:57 AM -10:52:09 AM -10:54:21 AM -10:56:34 AM -10:58:46 AM -11:00:58 AM -11:03:10 AM -11:05:22 AM -11:07:34 AM -11:09:46 AM -11:11:58 AM -11:14:11 AM -11:16:23 AM -11:18:35 AM -11:20:47 AM -11:22:59 AM -11:25:11 AM -11:27:23 AM -11:29:35 AM -11:31:48 AM -11:34:00 AM -11:36:12 AM -11:38:23 AM -11:40:35 AM -11:42:47 AM -11:44:59 AM -11:47:10 AM -11:49:22 AM -11:51:34 AM -11:53:46 AM -11:55:57 AM -11:58:09 AM -12:00:21 PM -12:02:33 PM -12:04:44 PM -12:06:56 PM -12:09:08 PM -12:11:20 PM -12:13:31 PM -12:15:43 PM -12:17:55 PM -12:20:06 PM -12:22:18 PM -12:24:30 PM -12:26:42 PM -12:28:54 PM -12:31:05 PM -12:33:17 PM -12:35:29 PM -12:37:40 PM -12:39:52 PM -12:42:04 PM -12:44:16 PM -12:46:27 PM -12:48:39 PM -12:50:51 PM -12:53:02 PM -12:55:14 PM -12:57:26 PM -12:59:38 PM -1:01:50 PM -1:04:01 PM -1:06:13 PM -1:08:25 PM -1:10:36 PM -1:12:48 PM -1:15:00 PM -1:17:12 PM -1:19:23 PM -1:21:35 PM -1:23:47 PM -1:25:58 PM -1:28:10 PM -1:30:22 PM -1:32:34 PM -1:34:45 PM -1:36:57 PM -1:39:09 PM -1:41:20 PM -1:43:32 PM -1:45:44 PM -1:47:56 PM -1:50:07 PM -1:52:19 PM -1:54:31 PM -1:56:43 PM -1:58:54 PM -2:01:06 PM -2:03:18 PM -2:05:29 PM -2:07:41 PM -2:09:53 PM -2:12:05 PM -2:14:16 PM -2:16:28 PM -2:18:40 PM -2:20:51 PM -2:23:03 PM -2:25:15 PM -2:27:27 PM -2:29:39 PM -2:31:50 PM -2:34:02 PM -2:36:14 PM -2:38:26 PM -2:40:37 PM -2:42:49 PM -2:45:01 PM -2:47:13 PM -2:49:24 PM -2:51:36 PM -2:53:48 PM -2:56:00 PM -2:58:11 PM -3:00:23 PM -3:02:35 PM -3:04:47 PM -3:06:58 PM -3:09:10 PM -3:11:22 PM -3:13:34 PM -3:15:45 PM diff --git a/Code/Projects/SmartPlugDetector/execute_layer2_smarthome_all_detection.sh b/Code/Projects/SmartPlugDetector/execute_layer2_smarthome_all_detection.sh deleted file mode 100755 index 1cf9087..0000000 --- a/Code/Projects/SmartPlugDetector/execute_layer2_smarthome_all_detection.sh +++ /dev/null @@ -1,241 +0,0 @@ -#!/bin/bash - -#set -x # echo invoked commands to std out - -# Base dir should point to the experimental_result folder which contains the subfolders: -# - 'smarthome' which contains the traces collected while other devices are idle -# - 'standalone' which contains signatures and the traces used to generate the signatures. -BASE_DIR=$1 -readonly BASE_DIR - -OUTPUT_DIR=$2 -readonly OUTPUT_DIR - -PCAPS_BASE_DIR="$BASE_DIR/smarthome" -readonly PCAPS_BASE_DIR - -SIGNATURES_BASE_DIR="$BASE_DIR/standalone" -readonly SIGNATURES_BASE_DIR - -# ==================================================== ARLO CAMERA ===================================================== -PCAP_FILE="$PCAPS_BASE_DIR/arlo-camera/wlan1/arlo-camera.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE (TODO: may possibly be the .incomplete signatures) -ON_SIGNATURE="$SIGNATURES_BASE_DIR/arlo-camera/signatures/arlo-camera-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/arlo-camera/signatures/arlo-camera-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/arlo-camera/arlo-camera.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="213" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= BLOSSOM SPRINKLER ================================================== -PCAP_FILE="$PCAPS_BASE_DIR/blossom-sprinkler/wlan1/blossom-sprinkler.wlan1.detection.pcap" - -# DEVICE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-device-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-device-side.sig" -RESULTS_FILE="$OUTPUT_DIR/blossom-sprinkler/blossom-sprinkler.wlan1.detection.pcap___device-side.detectionresults" -SIGNATURE_DURATION="9274" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/blossom-sprinkler/blossom-sprinkler.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="3670" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== D-LINK PLUG ===================================================== -PCAP_FILE="$PCAPS_BASE_DIR/dlink-plug/wlan1/dlink-plug.wlan1.detection.pcap" - -# DEVICE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-onSignature-device-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-offSignature-device-side.sig" -RESULTS_FILE="$OUTPUT_DIR/dlink-plug/dlink-plug.wlan1.detection.pcap___device-side.detectionresults" -SIGNATURE_DURATION="8866" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/dlink-plug/dlink-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="193" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== D-LINK SIREN ==================================================== -PCAP_FILE="$PCAPS_BASE_DIR/dlink-siren/wlan1/dlink-siren.wlan1.detection.pcap" - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-siren/signatures/dlink-siren-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-siren/signatures/dlink-siren-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/dlink-siren/dlink-siren.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="71" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ===================================================== HUE BULB ======================================================= -PCAP_FILE="$PCAPS_BASE_DIR/hue-bulb/wlan1/hue-bulb.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/hue-bulb/signatures/hue-bulb-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/hue-bulb/signatures/hue-bulb-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/hue-bulb/hue-bulb.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="27" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= KWIKSET DOORLOCK =================================================== -PCAP_FILE="$PCAPS_BASE_DIR/kwikset-doorlock/wlan1/kwikset-doorlock.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/kwikset-doorlock/signatures/kwikset-doorlock-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/kwikset-doorlock/signatures/kwikset-doorlock-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/kwikset-doorlock/kwikset-doorlock.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="3161" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= NEST THERMOSTAT ==================================================== -PCAP_FILE="$PCAPS_BASE_DIR/nest-thermostat/wlan1/nest-thermostat.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/nest-thermostat/signatures/nest-thermostat-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/nest-thermostat/signatures/nest-thermostat-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/nest-thermostat/nest-thermostat.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="1179" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ====================================================== ST PLUG ======================================================= -PCAP_FILE="$PCAPS_BASE_DIR/st-plug/wlan1/st-plug.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/st-plug/signatures/st-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/st-plug/signatures/st-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/st-plug/st-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="2445" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== TP-LINK BULB ==================================================== -PCAP_FILE="$PCAPS_BASE_DIR/tplink-bulb/wlan1/tplink-bulb.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-bulb/signatures/tplink-bulb-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-bulb/signatures/tplink-bulb-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/tplink-bulb/tplink-bulb.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="162" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION' -onmacfilters 50:c7:bf:.* -offmacfilters 50:c7:bf:.*" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== TP-LINK PLUG ==================================================== -PCAP_FILE="$PCAPS_BASE_DIR/tplink-plug/wlan1/tplink-plug.wlan1.detection.pcap" - -# DEVICE SIDE (both the 112, 115 and 556, 1293 sequences) -ON_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-onSignature-device-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-offSignature-device-side.sig" -RESULTS_FILE="$OUTPUT_DIR/tplink-plug/tplink-plug.wlan1.detection.pcap___device-side.detectionresults" -SIGNATURE_DURATION="3660" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION' -onmacfilters 50:c7:bf:.*;50:c7:bf:.* -offmacfilters 50:c7:bf:.*;50:c7:bf:.*" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# DEVICE SIDE OUTBOUND (contains only those packets that go through the WAN port, i.e., only the 556, 1293 sequence) -ON_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-onSignature-device-side-outbound.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-offSignature-device-side-outbound.sig" -RESULTS_FILE="$OUTPUT_DIR/tplink-plug/tplink-plug.wlan1.detection.pcap___device-side-outbound.detectionresults" -SIGNATURE_DURATION="224" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION' -onmacfilters 50:c7:bf:.* -offmacfilters 50:c7:bf:.*" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# Phone side does not make sense as it is merely a subset of the device side and does not differentiate ONs from OFFs. -# ====================================================================================================================== - - - -# ================================================== WEMO INSIGHT PLUG ================================================= -PCAP_FILE="$PCAPS_BASE_DIR/wemo-insight-plug/wlan1/wemo-insight-plug.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-insight-plug/signatures/wemo-insight-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-insight-plug/signatures/wemo-insight-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/wemo-insight-plug/wemo-insight-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="106" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ===================================================== WEMO PLUG ====================================================== -PCAP_FILE="$PCAPS_BASE_DIR/wemo-plug/wlan1/wemo-plug.wlan1.detection.pcap" - -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-plug/signatures/wemo-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-plug/signatures/wemo-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/wemo-plug/wemo-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="147" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/execute_layer2_smarthome_all_detection_results_analysis.sh b/Code/Projects/SmartPlugDetector/execute_layer2_smarthome_all_detection_results_analysis.sh deleted file mode 100755 index 7d0689d..0000000 --- a/Code/Projects/SmartPlugDetector/execute_layer2_smarthome_all_detection_results_analysis.sh +++ /dev/null @@ -1,187 +0,0 @@ -#!/bin/bash - -# Base directory where the smarthome evaluation traces and timestamp files are stored, -# (i.e., /some/arbitrary/local/path/experimental_result/smarthome) -TIMESTAMPS_BASE_DIR=$1 -readonly TIMESTAMPS_BASE_DIR - -# Base directory for the detection results files for the smarthome experiment -RESULTS_BASE_DIR=$2 -readonly RESULTS_BASE_DIR - - - -# ==================================================== ARLO CAMERA ===================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/arlo-camera/timestamps/arlo-camera-smarthome-nov-15-2018.timestamps" -RESULTS_FILE="$RESULTS_BASE_DIR/arlo-camera/arlo-camera.wlan1.detection.pcap___phone-side.detectionresults" -# Put the analysis results in the same folder as the detection results. -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" - - -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= BLOSSOM SPRINKLER ================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/blossom-sprinkler/timestamps/blossom-sprinkler-smarthome-jan-14-2019.timestamps" - -# DEVICE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/blossom-sprinkler/blossom-sprinkler.wlan1.detection.pcap___device-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/blossom-sprinkler/blossom-sprinkler.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== D-LINK PLUG ===================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/dlink-plug/timestamps/dlink-plug-smarthome-nov-8-2018.timestamps" - -# DEVICE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/dlink-plug/dlink-plug.wlan1.detection.pcap___device-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/dlink-plug/dlink-plug.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== D-LINK SIREN ==================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/dlink-siren/timestamps/dlink-siren-smarthome-nov-10-2018.timestamps" - -#PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/dlink-siren/dlink-siren.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ===================================================== HUE BULB ======================================================= -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/hue-bulb/timestamps/hue-bulb-smarthome-nov-20-2018.timestamps" - -# Has no device side signature. - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/hue-bulb/hue-bulb.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= KWIKSET DOORLOCK =================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/kwikset-doorlock/timestamps/kwikset-doorlock-smarthome-nov-10-2018.timestamps" - -# Has no device side signature. - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/kwikset-doorlock/kwikset-doorlock.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= NEST THERMOSTAT ==================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/nest-thermostat/timestamps/nest-thermostat-smarthome-nov-16-2018.timestamps" - -# Has no device side signature. - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/nest-thermostat/nest-thermostat.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ====================================================== ST PLUG ======================================================= -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/st-plug/timestamps/st-plug-smarthome-nov-13-2018.timestamps" - -# Has no device side signature. - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/st-plug/st-plug.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== TP-LINK BULB ==================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/tplink-bulb/timestamps/tplink-bulb-smarthome-nov-19-2018.timestamps" - -# Has no device side signature. - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/tplink-bulb/tplink-bulb.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== TP-LINK PLUG ==================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/tplink-plug/timestamps/tplink-plug-smarthome-nov-9-2018.timestamps" - -# DEVICE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/tplink-plug/tplink-plug.wlan1.detection.pcap___device-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" - -# DEVICE SIDE OUTBOUND -RESULTS_FILE="$RESULTS_BASE_DIR/tplink-plug/tplink-plug.wlan1.detection.pcap___device-side-outbound.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================== WEMO INSIGHT PLUG ================================================= -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/wemo-insight-plug/timestamps/wemo-insight-plug-smarthome-nov-22-2018.timestamps" - -# Has no device side signature. - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/wemo-insight-plug/wemo-insight-plug.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ===================================================== WEMO PLUG ====================================================== -TIMESTAMPS_FILE="$TIMESTAMPS_BASE_DIR/wemo-plug/timestamps/wemo-plug-smarthome-nov-21-2018.timestamps" - -# Has no device side signature. - -# PHONE SIDE -RESULTS_FILE="$RESULTS_BASE_DIR/wemo-plug/wemo-plug.wlan1.detection.pcap___phone-side.detectionresults" -ANALYSIS_RESULTS_FILE="$RESULTS_FILE.analysis" -PROGRAM_ARGS="'$TIMESTAMPS_FILE' '$RESULTS_FILE' '$ANALYSIS_RESULTS_FILE'" -./gradlew run -DmainClass=edu.uci.iotproject.evaluation.DetectionResultsAnalyzer --args="$PROGRAM_ARGS" -# ====================================================================================================================== \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/execute_layer2_unb_all_detection.sh b/Code/Projects/SmartPlugDetector/execute_layer2_unb_all_detection.sh deleted file mode 100755 index 0a44835..0000000 --- a/Code/Projects/SmartPlugDetector/execute_layer2_unb_all_detection.sh +++ /dev/null @@ -1,215 +0,0 @@ -#!/bin/bash - -#set -x # echo invoked commands to std out - -# Arg1 should point to the UNB trace (PCAP w/o any expected events). -PCAP_FILE=$1 - -readonly PCAP_FILE - -# Arg2 should point to the base directory for signature files (i.e., /some/local/path/experimental_result/standalone) -SIGNATURES_BASE_DIR=$2 -readonly SIGNATURES_BASE_DIR - -# Arg3 should point to folder where the detection results for the UNB trace are to be output. -OUTPUT_DIR=$3 -readonly OUTPUT_DIR - -# ==================================================== ARLO CAMERA ===================================================== -# Has no device side signature. - -# PHONE SIDE (TODO: may possibly be the .incomplete signatures) -ON_SIGNATURE="$SIGNATURES_BASE_DIR/arlo-camera/signatures/arlo-camera-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/arlo-camera/signatures/arlo-camera-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/arlo-camera/arlo-camera.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="213" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= BLOSSOM SPRINKLER ================================================== -# DEVICE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-device-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-device-side.sig" -RESULTS_FILE="$OUTPUT_DIR/blossom-sprinkler/blossom-sprinkler.wlan1.detection.pcap___device-side.detectionresults" -SIGNATURE_DURATION="9274" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/blossom-sprinkler/blossom-sprinkler.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="3670" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== D-LINK PLUG ===================================================== -# DEVICE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-onSignature-device-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-offSignature-device-side.sig" -RESULTS_FILE="$OUTPUT_DIR/dlink-plug/dlink-plug.wlan1.detection.pcap___device-side.detectionresults" -SIGNATURE_DURATION="8866" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-plug/signatures/dlink-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/dlink-plug/dlink-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="193" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== D-LINK SIREN ==================================================== -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-siren/signatures/dlink-siren-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/dlink-siren/signatures/dlink-siren-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/dlink-siren/dlink-siren.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="71" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ===================================================== HUE BULB ======================================================= -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/hue-bulb/signatures/hue-bulb-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/hue-bulb/signatures/hue-bulb-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/hue-bulb/hue-bulb.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="27" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= KWIKSET DOORLOCK =================================================== -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/kwikset-doorlock/signatures/kwikset-doorlock-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/kwikset-doorlock/signatures/kwikset-doorlock-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/kwikset-doorlock/kwikset-doorlock.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="3161" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ================================================= NEST THERMOSTAT ==================================================== -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/nest-thermostat/signatures/nest-thermostat-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/nest-thermostat/signatures/nest-thermostat-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/nest-thermostat/nest-thermostat.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="1179" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ====================================================== ST PLUG ======================================================= -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/st-plug/signatures/st-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/st-plug/signatures/st-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/st-plug/st-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="2445" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== TP-LINK BULB ==================================================== -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-bulb/signatures/tplink-bulb-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-bulb/signatures/tplink-bulb-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/tplink-bulb/tplink-bulb.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="162" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION' -onmacfilters 50:c7:bf:.* -offmacfilters 50:c7:bf:.*" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ==================================================== TP-LINK PLUG ==================================================== -# DEVICE SIDE (both the 112, 115 and 556, 1293 sequences) -ON_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-onSignature-device-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-offSignature-device-side.sig" -RESULTS_FILE="$OUTPUT_DIR/tplink-plug/tplink-plug.wlan1.detection.pcap___device-side.detectionresults" -SIGNATURE_DURATION="3660" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION' -onmacfilters 50:c7:bf:.*;50:c7:bf:.* -offmacfilters 50:c7:bf:.*;50:c7:bf:.*" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# DEVICE SIDE OUTBOUND (contains only those packets that go through the WAN port, i.e., only the 556, 1293 sequence) -ON_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-onSignature-device-side-outbound.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/tplink-plug/signatures/tplink-plug-offSignature-device-side-outbound.sig" -RESULTS_FILE="$OUTPUT_DIR/tplink-plug/tplink-plug.wlan1.detection.pcap___device-side-outbound.detectionresults" -SIGNATURE_DURATION="224" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION' -onmacfilters 50:c7:bf:.* -offmacfilters 50:c7:bf:.*" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" - -# Phone side does not make sense as it is merely a subset of the device side and does not differentiate ONs from OFFs. -# ====================================================================================================================== - - - -# ================================================== WEMO INSIGHT PLUG ================================================= -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-insight-plug/signatures/wemo-insight-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-insight-plug/signatures/wemo-insight-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/wemo-insight-plug/wemo-insight-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="106" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== - - - -# ===================================================== WEMO PLUG ====================================================== -# Has no device side signature. - -# PHONE SIDE -ON_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-plug/signatures/wemo-plug-onSignature-phone-side.sig" -OFF_SIGNATURE="$SIGNATURES_BASE_DIR/wemo-plug/signatures/wemo-plug-offSignature-phone-side.sig" -RESULTS_FILE="$OUTPUT_DIR/wemo-plug/wemo-plug.wlan1.detection.pcap___phone-side.detectionresults" -SIGNATURE_DURATION="147" - -PROGRAM_ARGS="'$PCAP_FILE' '$ON_SIGNATURE' '$OFF_SIGNATURE' '$RESULTS_FILE' '$SIGNATURE_DURATION'" -./gradlew run -DmainClass=edu.uci.iotproject.detection.layer2.Layer2SignatureDetector --args="$PROGRAM_ARGS" -# ====================================================================================================================== \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/execute_layer2_unsw_all_detection.sh b/Code/Projects/SmartPlugDetector/execute_layer2_unsw_all_detection.sh deleted file mode 100755 index 9ac4569..0000000 --- a/Code/Projects/SmartPlugDetector/execute_layer2_unsw_all_detection.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -# Arg1 should point to the folder with UNSW traces (PCAP files w/o any expected events). -UNSW_TRACES_DIR=$1 - -# Arg2 should point to the base directory for signature files (i.e., /some/local/path/experimental_result/standalone) -SIGNATURES_BASE_DIR=$2 -readonly SIGNATURES_BASE_DIR - -# Arg3 should point to base directory where the detection results for the UNSW trace are to be output. -# Subfolders will be created for each individual pcap file in UNSW_TRACES_DIR. -OUTPUT_DIR=$3 -readonly OUTPUT_DIR - -#set -x # echo invoked commands to std out - -for PCAP_FILE in $UNSW_TRACES_DIR/*.pcap; do - # skip non pcap files - [ -e "$PCAP_FILE" ] || continue - # make an output sub dir in the base output dir that is the filename minus extension - OUTPUT_SUB_DIR=$(basename "$PCAP_FILE" .pcap) - ./execute_layer2_unb_all_detection.sh $PCAP_FILE $SIGNATURES_BASE_DIR $OUTPUT_DIR/$OUTPUT_SUB_DIR -done - - diff --git a/Code/Projects/SmartPlugDetector/gradle/wrapper/gradle-wrapper.jar b/Code/Projects/SmartPlugDetector/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 9411448..0000000 Binary files a/Code/Projects/SmartPlugDetector/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/gradle/wrapper/gradle-wrapper.properties b/Code/Projects/SmartPlugDetector/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a17f184..0000000 --- a/Code/Projects/SmartPlugDetector/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Tue Aug 21 11:14:11 PDT 2018 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip diff --git a/Code/Projects/SmartPlugDetector/gradlew b/Code/Projects/SmartPlugDetector/gradlew deleted file mode 100755 index 9d82f78..0000000 --- a/Code/Projects/SmartPlugDetector/gradlew +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/Code/Projects/SmartPlugDetector/gradlew.bat b/Code/Projects/SmartPlugDetector/gradlew.bat deleted file mode 100644 index aec9973..0000000 --- a/Code/Projects/SmartPlugDetector/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_OFF.pcap b/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_OFF.pcap deleted file mode 100644 index b30fad9..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_OFF.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_ON.pcap b/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_ON.pcap deleted file mode 100644 index a85b153..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_ON.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_ON_SUBSET.pcap b/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_ON_SUBSET.pcap deleted file mode 100644 index 209bfbf..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_LOCAL_ON_SUBSET.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_REMOTE_CHARGING_ON.pcap b/Code/Projects/SmartPlugDetector/pcap/TP_LINK_REMOTE_CHARGING_ON.pcap deleted file mode 100644 index 73a92d4..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_REMOTE_CHARGING_ON.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_REMOTE_ON.pcap b/Code/Projects/SmartPlugDetector/pcap/TP_LINK_REMOTE_ON.pcap deleted file mode 100644 index d53625e..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/TP_LINK_REMOTE_ON.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/pcap/wlan1.local.dns.pcap b/Code/Projects/SmartPlugDetector/pcap/wlan1.local.dns.pcap deleted file mode 100644 index 8c945a0..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/wlan1.local.dns.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/pcap/wlan1.local.remote.dns.pcap b/Code/Projects/SmartPlugDetector/pcap/wlan1.local.remote.dns.pcap deleted file mode 100644 index 7e96a6d..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/wlan1.local.remote.dns.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/pcap/wlan1.remote.dns.pcap b/Code/Projects/SmartPlugDetector/pcap/wlan1.remote.dns.pcap deleted file mode 100644 index 8e99963..0000000 Binary files a/Code/Projects/SmartPlugDetector/pcap/wlan1.remote.dns.pcap and /dev/null differ diff --git a/Code/Projects/SmartPlugDetector/settings.gradle b/Code/Projects/SmartPlugDetector/settings.gradle deleted file mode 100644 index 29c528a..0000000 --- a/Code/Projects/SmartPlugDetector/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'SmartPlugDetector' - diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/ConversationPair.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/ConversationPair.java deleted file mode 100644 index b864ee5..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/ConversationPair.java +++ /dev/null @@ -1,149 +0,0 @@ -package edu.uci.iotproject; - -import org.pcap4j.core.PcapHandle; -import org.pcap4j.core.PcapPacket; - -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.Map; - -/** - * Models a (TCP) conversation/connection/session/flow (packet's belonging to the same session between a client and a - * server). - * Holds a pair of packet lengths from {@link PcapPacket}s identified as pertaining to the flow. - * Here we consider pairs of packet lengths, e.g., from device to cloud and cloud to device. - * We collect these pairs of data points as signatures that we can plot on a graph. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class ConversationPair { - - /* Begin instance properties */ - /** - * The PrintWriter object that writes data points into file - */ - private PrintWriter pw; - - /** - * The direction of conversation - * true = device to server to device - */ - private Direction direction; - - /** - * If this is the first packet processed then the value is true (it is false otherwise). - */ - private boolean firstPacket; - - /** - * Count the frequencies of points - */ - private Map pointFreq; - private String dataPoint; - - /** - * Four possible directions of conversations. - * E.g., DEVICE_TO_SERVER means the conversation is started from - * a device-server packet and then a server-device as a response. - * SERVER_TO_DEVICE means the conversation is started from a - * server-device packet and then a device-server packet as a response. - * The same pattern applies to PHONE_TO_SERVER and SERVER_TO_PHONE - * directions. - */ - public enum Direction { - DEVICE_TO_SERVER, - SERVER_TO_DEVICE, - PHONE_TO_SERVER, - SERVER_TO_PHONE - } - - /** - * Constructs a ConversationPair object. - * @param fileName The file name to write data points into. - * @param direction The direction of the first packet of the pair. - */ - public ConversationPair(String fileName, Direction direction) { - try { - this.pw = new PrintWriter(fileName, "UTF-8"); - } catch(UnsupportedEncodingException | - FileNotFoundException e) { - e.printStackTrace(); - } - this.direction = direction; - this.firstPacket = true; - this.pointFreq = new HashMap<>(); - this.dataPoint = null; - } - - /** - * Writes conversation pair's packet lengths. - * @param packet The {@link PcapPacket} object that has packet information. - * @param fromClient If true then this packet comes from client, e.g., device. - * @param fromServer If true then this packet comes from server. - */ - public void writeConversationPair(PcapPacket packet, boolean fromClient, boolean fromServer) { - - // Write device data point first and then server - if (direction == Direction.DEVICE_TO_SERVER || direction == Direction.PHONE_TO_SERVER) { - if (fromClient && firstPacket) { // first packet - pw.print(packet.getTimestamp() + ", " + packet.getPayload().length() + ", "); - System.out.print(packet.getTimestamp() + ", " + packet.getPayload().length() + ", "); - dataPoint = Integer.toString(packet.getPayload().length()) + ", "; - firstPacket = false; - } else if (fromServer && !firstPacket) { // second packet - pw.println(packet.getPayload().length()); - System.out.println(packet.getPayload().length()); - dataPoint = dataPoint + Integer.toString(packet.getPayload().length()); - countFrequency(dataPoint); - firstPacket = true; - } - // Write server data point first and then device - } else if (direction == Direction.SERVER_TO_DEVICE || direction == Direction.SERVER_TO_PHONE) { - if (fromServer && firstPacket) { // first packet - pw.print(packet.getTimestamp() + ", " + packet.getPayload().length() + ", "); - dataPoint = Integer.toString(packet.getPayload().length()) + ", "; - firstPacket = false; - } else if (fromClient && !firstPacket) { // second packet - pw.println(packet.getPayload().length()); - dataPoint = dataPoint + Integer.toString(packet.getPayload().length()); - countFrequency(dataPoint); - firstPacket = true; - } - } - } - - /** - * Counts the frequencies of data points. - * @param dataPoint One data point for a conversation pair, e.g., 556, 1232. - */ - private void countFrequency(String dataPoint) { - - Integer freq = null; - if (pointFreq.containsKey(dataPoint)) { - freq = pointFreq.get(dataPoint); - } else { - freq = new Integer(0); - } - freq = freq + 1; - pointFreq.put(dataPoint, freq); - } - - /** - * Prints the frequencies of data points from the Map. - */ - public void printListFrequency() { - for(Map.Entry entry : pointFreq.entrySet()) { - System.out.println(entry.getKey() + " - " + entry.getValue()); - } - } - - /** - * Close the PrintWriter object. - */ - public void close() { - pw.close(); - } -} \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsMap.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsMap.java deleted file mode 100644 index 0db01f8..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/DnsMap.java +++ /dev/null @@ -1,111 +0,0 @@ -package edu.uci.iotproject; - -import org.pcap4j.core.PacketListener; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.Packet; -import org.pcap4j.packet.DnsPacket; -import org.pcap4j.packet.DnsResourceRecord; -import org.pcap4j.packet.namednumber.DnsResourceRecordType; - - -import java.net.Inet4Address; -import java.net.UnknownHostException; -import java.util.*; - - -/** - * This is a class that does DNS mapping. - * Basically an IP address is mapped to its - * respective DNS hostnames. - * - * @author Rahmadi Trimananda (rtrimana@uci.edu) - * @version 0.1 - */ -public class DnsMap implements PacketListener { - - /* Class properties */ - private Map> ipToHostnameMap; - - /* Class constants */ - private static final Set EMPTY_SET = Collections.unmodifiableSet(new HashSet<>()); - - - /* Constructor */ - public DnsMap() { - ipToHostnameMap = new HashMap<>(); - } - - @Override - public void gotPacket(PcapPacket packet) { - try { - validateAndAddNewEntry(packet); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - } - - /** - * Gets a packet and determine if this is a DNS packet - * - * @param packet Packet object - * @return DnsPacket object or null - */ - private DnsPacket getDnsPacket(Packet packet) { - DnsPacket dnsPacket = packet.get(DnsPacket.class); - return dnsPacket; - } - - /** - * Checks DNS packet and build the map data structure that - * maps IP addresses to DNS hostnames - * - * @param packet PcapPacket object - */ - public void validateAndAddNewEntry(PcapPacket packet) throws UnknownHostException { - // Make sure that this is a DNS packet - DnsPacket dnsPacket = getDnsPacket(packet); - if (dnsPacket != null) { - // We only care about DNS answers - if (dnsPacket.getHeader().getAnswers().size() != 0) { - String hostname = dnsPacket.getHeader().getQuestions().get(0).getQName().getName(); - for(DnsResourceRecord answer : dnsPacket.getHeader().getAnswers()) { - // We only care about type A records - if (!answer.getDataType().equals(DnsResourceRecordType.A)) - continue; - // Sanity check. For some reason the hostname appears to be the empty string in the answer . - // We hence have to assume that all answers correspond to a single question that holds the hostname as part of its object tree. - // Therefore, if there are more questions in one query-reply exchange, we are in trouble. - if (!answer.getName().getName().equals("") && !answer.getName().getName().equals(hostname)) - throw new RuntimeException("[DNS parser] mismatch between hostname in question and hostname in answer"); - // The IP in byte representation. - byte[] ipBytes = answer.getRData().getRawData(); - // Convert to string representation. - String ip = Inet4Address.getByAddress(ipBytes).getHostAddress(); - Set hostnameSet = new HashSet<>(); - hostnameSet.add(hostname); - // Update or insert depending on presence of key: - // Concat the existing set and the new set if ip already present as key, - // otherwise add an entry for ip pointing to new set. - ipToHostnameMap.merge(ip, hostnameSet, (v1, v2) -> { v1.addAll(v2); return v1; }); - } - } - } - } - - - /** - * Checks DNS packet and build the map data structure that - * maps IP addresses to DNS hostnames - * - * @param address Address to check - * @param hostname Hostname to check - */ - public boolean isRelatedToCloudServer(String address, String hostname) { - return ipToHostnameMap.getOrDefault(address, EMPTY_SET).contains(hostname); - } - - public Set getHostnamesForIp(String ip) { - Set hostnames = ipToHostnameMap.get(ip); - return hostnames != null ? Collections.unmodifiableSet(hostnames) : null; - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPattern.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPattern.java deleted file mode 100644 index aca63ab..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPattern.java +++ /dev/null @@ -1,215 +0,0 @@ -package edu.uci.iotproject; - -import org.pcap4j.core.*; -import org.pcap4j.packet.*; -import org.pcap4j.packet.DnsPacket; -import org.pcap4j.packet.namednumber.DnsResourceRecordType; - -import java.io.EOFException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.*; -import java.util.concurrent.TimeoutException; - -/** - * TODO add class documentation. - * TODO: At this point, this class is still in transition to having multiple hostnames and lists of packets - * - * @author Janus Varmarken - */ -public class FlowPattern { - - /** - * Class properties - */ - private final String mPatternId; - private final String hostname; // The hostname that this {@code FlowPattern} is associated with. - - /** - * The order of packet lengths that defines this {@link FlowPattern} - * TODO: this is a simplified representation, we should also include information about direction of each packet. - */ - private final List flowPacketOrder; - private final Map> mHostnameToPacketLengthsMap; - private final List mHostnameList; - private final PcapHandle mPcap; - - - /** - * Class constants - */ - - - /** - * Constructor #1 - */ - public FlowPattern(String mPatternId, String hostname, PcapHandle mPcap) { - this.mPatternId = mPatternId; - this.hostname = hostname; - this.mHostnameList = null; - this.mPcap = mPcap; - this.mHostnameToPacketLengthsMap = null; - this.flowPacketOrder = new ArrayList(); - processPcap(); - } - - - /** - * Process the PcapHandle to strip off unnecessary packets and just get the integer array of packet lengths - */ - private void processPcap() { - - PcapPacket packet; - try { - while ((packet = mPcap.getNextPacketEx()) != null) { - // For now, we only work support pattern search in TCP over IPv4. - IpV4Packet ipPacket = packet.get(IpV4Packet.class); - TcpPacket tcpPacket = packet.get(TcpPacket.class); - if (ipPacket == null || tcpPacket == null) - continue; - if (tcpPacket.getPayload() == null) // We skip non-payload control packets as these are less predictable - continue; - int packetLength = tcpPacket.getPayload().length(); - flowPacketOrder.add(packetLength); - } - } catch (EOFException eofe) { - System.out.println("[ FlowPattern ] Finished processing a training PCAP stream!"); - System.out.println("[ FlowPattern ] Pattern for " + mPatternId + ": " + Arrays.toString(flowPacketOrder.toArray())); - } catch (PcapNativeException | - TimeoutException | - NotOpenException ex) { - ex.printStackTrace(); - } - } - - - /** - * Process the PcapHandle to strip off unnecessary packets. - * We then map list of hostnames to their respective arrays of packet lengths - */ - private void processPcapToMap() { - - PcapPacket packet; - try { - int hostIndex = -1; - Set addressSet = new HashSet<>(); - while ((packet = mPcap.getNextPacketEx()) != null) { - // For now, we only work support pattern search in TCP over IPv4. - IpV4Packet ipPacket = packet.get(IpV4Packet.class); - TcpPacket tcpPacket = packet.get(TcpPacket.class); - if (ipPacket == null || tcpPacket == null) { - continue; - } - if (tcpPacket.getPayload() == null) { - // We skip non-payload control packets as these are less predictable - continue; - } - // We assume that if it is not a local address then it is a cloud server address - InetAddress srcAddress = ipPacket.getHeader().getSrcAddr(); - InetAddress dstAddress = ipPacket.getHeader().getDstAddr(); - boolean fromServer = !srcAddress.isSiteLocalAddress(); - boolean fromClient = !dstAddress.isSiteLocalAddress(); - if (!fromServer && !fromClient) { - // Packet not related to pattern, skip it - continue; - } else { - // We relate and assume that this address is from our cloud server - String cloudAddress = null; - if (fromClient) { - cloudAddress = dstAddress.getHostAddress(); - } else { // fromServer - cloudAddress = srcAddress.getHostAddress(); - } - //System.out.println("\nCloud address: " + cloudAddress); - if (!addressSet.contains(cloudAddress)) { - addressSet.add(cloudAddress); - hostIndex++; - } - - String hostname = mHostnameList.get(hostIndex); - List packetLengthsList = mHostnameToPacketLengthsMap.containsKey(hostname) ? - mHostnameToPacketLengthsMap.get(hostname) : new ArrayList<>(); - int packetLength = tcpPacket.getPayload().length(); - packetLengthsList.add(packetLength); - mHostnameToPacketLengthsMap.put(hostname, packetLengthsList); - } - } - } catch (EOFException eofe) { - System.out.println("[ FlowPattern ] Finished processing a training PCAP stream!"); - System.out.println("[ FlowPattern ] Pattern for " + mPatternId + ": " + Arrays.toString(mHostnameToPacketLengthsMap.entrySet().toArray())); - } catch (PcapNativeException | - TimeoutException | - NotOpenException ex) { - ex.printStackTrace(); - } - } - - - /** - * Constructor #2 - */ - public FlowPattern(String mPatternId, List mHostnameList, PcapHandle mPcap) { - this.mPatternId = mPatternId; - this.hostname = null; - this.mHostnameList = mHostnameList; - this.mPcap = mPcap; - this.flowPacketOrder = null; - this.mHostnameToPacketLengthsMap = new HashMap<>(); - processPcapToMap(); - } - - - public String getPatternId() { - return mPatternId; - } - - - public String getHostname() { - return hostname; - } - - - /** - * Get the sequence of packet lengths that defines this {@code FlowPattern}. - * @return the sequence of packet lengths that defines this {@code FlowPattern}. - */ - public List getPacketOrder() { - return flowPacketOrder; - } - - - /** - * Get the sequence of packet lengths based on input hostname. - * @return the sequence of packet lengths that defines this {@code FlowPattern}. - */ - public List getPacketOrder(String hostname) { - return mHostnameToPacketLengthsMap.get(hostname); - } - - - /** - * Get the list of associated hostnames. - * @return the associated hostnames that define this {@code FlowPattern}. - */ - public List getHostnameList() { - return mHostnameList; - } - - - /** - * Get the length of the List of {@code FlowPattern}. - * @return the length of the List of {@code FlowPattern}. - */ - public int getLength() { - return flowPacketOrder.size(); - } - - - /** - * Get the length of the List of {@code FlowPattern}. - * @return the length of the List of {@code FlowPattern}. - */ - public int getLength(String hostname) { - return mHostnameToPacketLengthsMap.get(hostname).size(); - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPatternFinder.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPatternFinder.java deleted file mode 100644 index c384852..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/FlowPatternFinder.java +++ /dev/null @@ -1,357 +0,0 @@ -package edu.uci.iotproject; - -import edu.uci.iotproject.comparison.ComparisonFunctions; -import edu.uci.iotproject.comparison.CompleteMatchPatternComparisonResult; -import edu.uci.iotproject.comparison.PatternComparisonTask; -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import org.pcap4j.core.NotOpenException; -import org.pcap4j.core.PcapHandle; -import org.pcap4j.core.PcapNativeException; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.DnsPacket; -import org.pcap4j.packet.IpV4Packet; -import org.pcap4j.packet.TcpPacket; - -import java.io.*; -import java.net.UnknownHostException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.*; - - -/** - *

Provides functionality for searching for the presence of a {@link FlowPattern} in a PCAP trace.

- * - *

- * The (entire) PCAP trace is traversed and parsed on one thread (specifically, the thread that calls - * {@link #findFlowPattern()}). This thread builds a {@link DnsMap} using the DNS packets present in the trace and uses - * that {@code DnsMap} to reassemble {@link Conversation}s that potentially match the provided - * {@link FlowPattern} (in that one end/party of said conversations matches the hostname(s) specified by the given - * {@code FlowPattern}). - * These potential matches are then examined on background worker thread(s) to determine if they are indeed a (complete) - * match of the provided {@code FlowPattern}. - *

- * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class FlowPatternFinder { - - /* Begin class properties */ - /** - * {@link ExecutorService} responsible for parallelizing pattern searches. - * Declared as static to allow for reuse of threads across different instances of {@code FlowPatternFinder} and to - * avoid the overhead of initializing a new thread pool for each {@code FlowPatternFinder} instance. - */ - private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(); - /* End class properties */ - - /* Begin instance properties */ - /** - * Holds a set of {@link Conversation}s that potentially match {@link #mPattern} since each individual - * {@code Conversation} is communication with the hostname identified by {@code mPattern.getHostname()}. - * Note that due to limitations of the {@link Set} interface (specifically, there is no {@code get(T t)} method), - * we have to resort to a {@link Map} (in which keys map to themselves) to "mimic" a set with {@code get(T t)} - * functionality. - * - * @see this question on StackOverflow.com - */ - private final Map mConversations; - - /** - * Holds a list of trigger times. - */ - private final List mTriggerTimes; - private static int triggerListCounter; - - private final DnsMap mDnsMap; - private final PcapHandle mPcap; - private final FlowPattern mPattern; - private final ConversationPair mConvPair; - private final String FILE = "./devices/tplink_switch/datapoints.csv"; - //private final String REF_FILE = "./devices/dlink_switch/dlink-june-26-2018.timestamps"; - private final String REF_FILE = "./devices/tplink_switch/tplink-june-14-2018.timestamps"; - //private final String REF_FILE = "./devices/tplink_switch/tplink-feb-13-2018.timestamps"; - // Router time is in CET and we use PST for the trigger times - // Difference is 7 hours x 3600 x 1000ms = 25,200,000ms - private final long TIME_OFFSET = 25200000; - - private final List> mPendingComparisons = new ArrayList<>(); - /* End instance properties */ - - /** - * Constructs a new {@code FlowPatternFinder}. - * @param pcap an open {@link PcapHandle} that provides access to the trace that is to be examined. - * @param pattern the {@link FlowPattern} to search for. - */ - public FlowPatternFinder(PcapHandle pcap, FlowPattern pattern) { - this.mConversations = new HashMap<>(); - this.mTriggerTimes = readTriggerTimes(REF_FILE); - triggerListCounter = 0; - this.mDnsMap = new DnsMap(); - this.mPcap = Objects.requireNonNull(pcap, - String.format("Argument of type '%s' cannot be null", PcapHandle.class.getSimpleName())); - this.mPattern = Objects.requireNonNull(pattern, - String.format("Argument of type '%s' cannot be null", FlowPattern.class.getSimpleName())); - this.mConvPair = new ConversationPair(FILE, ConversationPair.Direction.DEVICE_TO_SERVER); - } - - - private List readTriggerTimes(String refFileName) { - - List listTriggerTimes = new ArrayList<>(); - try { - File file = new File(refFileName); - BufferedReader br = new BufferedReader(new FileReader(file)); - String s; - while ((s = br.readLine()) != null) { - listTriggerTimes.add(timeToMillis(s, false)); - } - } catch (IOException e) { - e.printStackTrace(); - } - System.out.println("List has: " + listTriggerTimes.size()); - - return listTriggerTimes; - } - - /** - * Starts the pattern search. - */ - public void start() { - - //findFlowPattern(); - findSignatureBasedOnTimestamp(); - } - - /** - * Find patterns based on the FlowPattern object (run by a thread) - */ - private void findFlowPattern() { - try { - PcapPacket packet; -// TODO: The new comparison method is pending -// TODO: For now, just compare using one hostname and one list per FlowPattern -// List hostnameList = mPattern.getHostnameList(); -// int hostIndex = 0; - while ((packet = mPcap.getNextPacketEx()) != null) { - // Let DnsMap handle DNS packets. - if (packet.get(DnsPacket.class) != null) { - // Check if this is a valid DNS packet - mDnsMap.validateAndAddNewEntry(packet); - continue; - } - // For now, we only work support pattern search in TCP over IPv4. - final IpV4Packet ipPacket = packet.get(IpV4Packet.class); - final TcpPacket tcpPacket = packet.get(TcpPacket.class); - if (ipPacket == null || tcpPacket == null) { - continue; - } - - String srcAddress = ipPacket.getHeader().getSrcAddr().getHostAddress(); - String dstAddress = ipPacket.getHeader().getDstAddr().getHostAddress(); - int srcPort = tcpPacket.getHeader().getSrcPort().valueAsInt(); - int dstPort = tcpPacket.getHeader().getDstPort().valueAsInt(); - // Is this packet related to the pattern; i.e. is it going to (or coming from) the cloud server? - boolean fromServer = mDnsMap.isRelatedToCloudServer(srcAddress, mPattern.getHostname()); - boolean fromClient = mDnsMap.isRelatedToCloudServer(dstAddress, mPattern.getHostname()); -// String currentHostname = hostnameList.get(hostIndex); -// boolean fromServer = mDnsMap.isRelatedToCloudServer(srcAddress, currentHostname); -// boolean fromClient = mDnsMap.isRelatedToCloudServer(dstAddress, currentHostname); - if (!fromServer && !fromClient) { - // Packet not related to pattern, skip it. - continue; - } - - // Conversations (connections/sessions) are identified by the four-tuple - // (clientIp, clientPort, serverIp, serverPort) (see Conversation Javadoc). - // Create "dummy" conversation for looking up an existing entry. - Conversation conversation = fromClient ? new Conversation(srcAddress, srcPort, dstAddress, dstPort) : - new Conversation(dstAddress, dstPort, srcAddress, srcPort); - // Add the packet so that the "dummy" conversation can be immediately added to the map if no entry - // exists for the conversation that the current packet belongs to. - if (tcpPacket.getHeader().getFin()) { - // Record FIN packets. - conversation.addFinPacket(packet); - } - if (tcpPacket.getPayload() != null) { - // Record regular payload packets. - conversation.addPacket(packet, true); - } - // Note: does not make sense to call attemptAcknowledgementOfFin here as the new packet has no FINs - // in its list, so if this packet is an ACK, it would not be added anyway. - // Need to retain a final reference to get access to the packet in the lambda below. - final PcapPacket finalPacket = packet; - // Add the new conversation to the map if an equal entry is not already present. - // If an existing entry is already present, the current packet is simply added to that conversation. - mConversations.merge(conversation, conversation, (existingEntry, toMerge) -> { - // toMerge may not have any payload packets if the current packet is a FIN packet. - if (toMerge.getPackets().size() > 0) { - existingEntry.addPacket(toMerge.getPackets().get(0), true); - } - if (toMerge.getFinAckPairs().size() > 0) { - // Add the FIN packet to the existing entry. - existingEntry.addFinPacket(toMerge.getFinAckPairs().get(0).getFinPacket()); - } - if (finalPacket.get(TcpPacket.class).getHeader().getAck()) { - existingEntry.attemptAcknowledgementOfFin(finalPacket); - } - return existingEntry; - }); - // Refresh reference to point to entry in map (in case packet was added to existing entry). - conversation = mConversations.get(conversation); - if (conversation.isGracefullyShutdown()) { - // Conversation terminated gracefully, so we can now start analyzing it. - // Remove the Conversation from the map and start the analysis. - // Any future packets identified by the same four tuple will be tied to a new Conversation instance. - mConversations.remove(conversation); - // Create comparison task and send to executor service. - PatternComparisonTask comparisonTask = - new PatternComparisonTask<>(conversation, mPattern, ComparisonFunctions.SUB_SEQUENCE_COMPLETE_MATCH); - mPendingComparisons.add(EXECUTOR_SERVICE.submit(comparisonTask)); - // Increment hostIndex to find the next - - } - } - } catch (EOFException eofe) { - // TODO should check for leftover conversations in map here and fire tasks for those. - // TODO [cont'd] such tasks may be present if connections did not terminate gracefully or if there are longlived connections. - System.out.println("[ findFlowPattern ] Finished processing entire PCAP stream!"); - System.out.println("[ findFlowPattern ] Now waiting for comparisons to finish..."); - // Wait for all comparisons to finish, then output their results to std.out. - for(Future comparisonTask : mPendingComparisons) { - try { - // Blocks until result is ready. - CompleteMatchPatternComparisonResult comparisonResult = comparisonTask.get(); - if (comparisonResult.getResult()) { - System.out.println(comparisonResult.getTextualDescription()); - } - } catch (InterruptedException|ExecutionException e) { - e.printStackTrace(); - } - } - } catch (UnknownHostException | - PcapNativeException | - NotOpenException | - TimeoutException ex) { - ex.printStackTrace(); - } - } - - /** - * Find patterns based on the FlowPattern object (run by a thread) - */ - private void findSignatureBasedOnTimestamp() { - try { - PcapPacket packet; -// TODO: The new comparison method is pending -// TODO: For now, just compare using one hostname and one list per FlowPattern - while ((packet = mPcap.getNextPacketEx()) != null) { - // Let DnsMap handle DNS packets. - if (packet.get(DnsPacket.class) != null) { - // Check if this is a valid DNS packet - mDnsMap.validateAndAddNewEntry(packet); - continue; - } - // For now, we only work support pattern search in TCP over IPv4. - final IpV4Packet ipPacket = packet.get(IpV4Packet.class); - final TcpPacket tcpPacket = packet.get(TcpPacket.class); - if (ipPacket == null || tcpPacket == null) { - continue; - } - - String srcAddress = ipPacket.getHeader().getSrcAddr().getHostAddress(); - String dstAddress = ipPacket.getHeader().getDstAddr().getHostAddress(); - int srcPort = tcpPacket.getHeader().getSrcPort().valueAsInt(); - int dstPort = tcpPacket.getHeader().getDstPort().valueAsInt(); - //System.out.println("Timestamp packet: " + packet.getTimestamp()); - // Is this packet related to the pattern; i.e. is it going to (or coming from) the cloud server? - boolean fromServer = mDnsMap.isRelatedToCloudServer(srcAddress, mPattern.getHostname()); - boolean fromClient = mDnsMap.isRelatedToCloudServer(dstAddress, mPattern.getHostname()); - if (!fromServer && !fromClient) { - // Packet not related to pattern, skip it. - continue; - } - // Record the conversation pairs - if (tcpPacket.getPayload() != null && checkTimeStamp(packet)) { - //if (tcpPacket.getPayload() != null) { - mConvPair.writeConversationPair(packet, fromClient, fromServer); - } - } - } catch (EOFException eofe) { - triggerListCounter = 0; - mConvPair.close(); - System.out.println("[ findFlowPattern ] ConversationPair writer closed!"); - System.out.println("[ findFlowPattern ] Frequencies of data points:"); - mConvPair.printListFrequency(); - } catch (UnknownHostException | - PcapNativeException | - NotOpenException | - TimeoutException ex) { - ex.printStackTrace(); - } - } - - private boolean checkTimeStamp(PcapPacket packet) { - - // Extract time from the packet's timestamp - String timeStamp = packet.getTimestamp().toString(); - String timeString = timeStamp.substring(timeStamp.indexOf("T") + 1, timeStamp.indexOf(".")); - // Timestamps are in CET (ahead of PST) so it should be deducted by TIME_OFFSET - long time = timeToMillis(timeString, true) - TIME_OFFSET; - //long time = timeToMillis(timeString, true); - - //System.out.println("Gets here: " + time + " trigger time: " + mTriggerTimes.get(triggerListCounter)); - - // We accept packets that are at most 3 seconds away from the trigger time - if ((mTriggerTimes.get(triggerListCounter) <= time) && - (time <= mTriggerTimes.get(triggerListCounter) + 3000)) { - //System.out.println("Gets here 1: " + timeString + " index: " + triggerListCounter); - return true; - } else { - // Handle the case that the timestamp is > 3000, but < next timestamp - // in the list. We ignore these packets. - if (time < mTriggerTimes.get(triggerListCounter)) { - // Timestamp is smaller than trigger, ignore! - //System.out.println("Gets here 2: " + timeString + " index: " + triggerListCounter); - return false; - } else { // Timestamp is greater than trigger, increment! - triggerListCounter = triggerListCounter + 1; - //System.out.println("Gets here 3: " + timeString + " index: " + triggerListCounter); - //return false; - return checkTimeStamp(packet); - } - } - - //System.out.println("Timestamp: " + timeToMillis(time, true)); - //String time2 = "21:38:08"; - //System.out.println("Timestamp: " + timeToMillis(time2, true)); - } - - /** - * A private function that returns time in milliseconds. - * @param time The time in the form of String. - * @param is24Hr If true, then this is in 24-hour format. - */ - private long timeToMillis(String time, boolean is24Hr) { - - String format = null; - if (is24Hr) { - format = "hh:mm:ss"; - } else { // 12 Hr format - format = "hh:mm:ss aa"; - } - DateFormat sdf = new SimpleDateFormat(format); - Date date = null; - try { - date = sdf.parse(time); - } catch(Exception e) { - e.printStackTrace(); - } - if (date == null) - return 0; - return date.getTime(); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java deleted file mode 100644 index f1056b0..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/Main.java +++ /dev/null @@ -1,905 +0,0 @@ -package edu.uci.iotproject; - -import static edu.uci.iotproject.analysis.UserAction.Type; - -import edu.uci.iotproject.analysis.*; -import edu.uci.iotproject.io.TriggerTimesFileReader; -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.trafficreassembly.layer3.TcpReassembler; -import edu.uci.iotproject.util.PcapPacketUtils; -import edu.uci.iotproject.util.PrintUtils; -import org.apache.commons.math3.stat.clustering.Cluster; -import org.apache.commons.math3.stat.clustering.DBSCANClusterer; -import org.pcap4j.core.*; -import org.pcap4j.packet.namednumber.DataLinkType; - -import java.io.EOFException; -import java.net.UnknownHostException; -import java.time.Duration; -import java.time.Instant; -import java.util.*; -import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * This is a system that reads PCAP files to compare - * patterns of DNS hostnames, packet sequences, and packet - * lengths with training data to determine certain events - * or actions for smart home devices. - * - * @author Janus Varmarken - * @author Rahmadi Trimananda (rtrimana@uci.edu) - * @version 0.1 - */ -public class Main { - - - public static void main(String[] args) throws PcapNativeException, NotOpenException, EOFException, TimeoutException, UnknownHostException { - // ------------------------------------------------------------------------------------------------------------- - // ------------ # Code for extracting traffic generated by a device within x seconds of a trigger # ------------ - // Paths to input and output files (consider supplying these as arguments instead) and IP of the device for - // which traffic is to be extracted: - String path = "/scratch/July-2018"; // Rahmadi -// String path = "/Users/varmarken/temp/UCI IoT Project/experiments"; // Janus - boolean verbose = true; - final String onPairsPath = "/scratch/July-2018/on.txt"; - final String offPairsPath = "/scratch/July-2018/off.txt"; - - // 1) D-Link July 26 experiment -// final String inputPcapFile = path + "/2018-07/dlink/dlink.wlan1.local.pcap"; -// 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? - // Actual training -// final String inputPcapFile = path + "/2018-10/dlink-plug/dlink-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-10/dlink-plug/dlink-plug-processed.pcap"; -// final String triggerTimesFile = path + "/2018-10/dlink-plug/dlink-plug-oct-17-2018.timestamps"; -// final String deviceIp = "192.168.1.199"; // .246 == phone; .199 == dlink plug? - // TODO: EXPERIMENT - November 7, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/dlink-plug/wlan1/dlink-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/dlink-plug/wlan1/dlink-plug-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/dlink-plug/timestamps/dlink-plug-nov-7-2018.timestamps"; -// final String deviceIp = "192.168.1.199"; // .246 == phone; .199 == dlink plug? -//// final String deviceIp = "192.168.1.246"; // .246 == phone; .199 == dlink plug? - - // 2) TP-Link July 25 experiment -// final String inputPcapFile = path + "/2018-07/tplink/tplink.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-07/tplink/tplink-processed.pcap"; -// final String triggerTimesFile = path + "/2018-07/tplink/tplink-july-25-2018.timestamps"; -// final String deviceIp = "192.168.1.159"; - // Actual training -// final String inputPcapFile = path + "/2018-10/tplink-plug/tplink-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-10/tplink-plug/tplink-plug-processed.pcap"; -// final String triggerTimesFile = path + "/2018-10/tplink-plug/tplink-plug-oct-17-2018.timestamps"; -// final String deviceIp = "192.168.1.159"; // .246 == phone; .159 == tplink plug - // TODO: EXPERIMENT - November 8, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/tplink-plug/wlan1/tplink-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/tplink-plug/wlan1/tplink-plug-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/tplink-plug/timestamps/tplink-plug-nov-8-2018.timestamps"; -// final String deviceIp = "192.168.1.159"; // .246 == phone; .159 == tplink plug -//// final String deviceIp = "192.168.1.246"; // .246 == phone; .159 == tplink plug - - // 2b) TP-Link July 25 experiment TRUNCATED: - // Only contains "true local" events, i.e., before the behavior changes to remote-like behavior. - // Last included event is at July 25 10:38:11; file filtered to only include packets with arrival time <= 10:38:27. -// final String inputPcapFile = path + "/2018-07/tplink/tplink.wlan1.local.truncated.pcap"; -// final String outputPcapFile = path + "/2018-07/tplink/tplink-processed.truncated.pcap"; -// final String triggerTimesFile = path + "/2018-07/tplink/tplink-july-25-2018.truncated.timestamps"; -// final String deviceIp = "192.168.1.159"; - - // 3) SmartThings Plug July 25 experiment -// final String inputPcapFile = path + "/2018-07/stplug/stplug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-07/stplug/stplug-processed.pcap"; -// final String triggerTimesFile = path + "/2018-07/stplug/smartthings-july-25-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) - // October 18 -// final String inputPcapFile = path + "/2018-10/st-plug/st-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-10/st-plug/st-plug-processed.pcap"; -// final String triggerTimesFile = path + "/2018-10/st-plug/st-plug-oct-18-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) - // TODO: EXPERIMENT - November 12, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/st-plug/wlan1/st-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/st-plug/wlan1/st-plug-processed.pcap"; -//// final String inputPcapFile = path + "/experimental_result/standalone/st-plug/eth1/st-plug.eth1.local.pcap"; -//// final String outputPcapFile = path + "/experimental_result/standalone/st-plug/eth1/st-plug-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/st-plug/timestamps/st-plug-nov-12-2018.timestamps"; -//// final String deviceIp = "192.168.1.142"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) -// final String deviceIp = "192.168.1.246"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) - - // 4) Wemo July 30 experiment -// final String inputPcapFile = path + "/2018-07/wemo/wemo.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-07/wemo/wemo-processed.pcap"; -// final String triggerTimesFile = path + "/2018-07/wemo/wemo-july-30-2018.timestamps"; -// final String deviceIp = "192.168.1.145"; // .246 == phone; .145 == WeMo - // TODO: EXPERIMENT - November 20, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/wemo-plug/wlan1/wemo-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/wemo-plug/wlan1/wemo-plug-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/wemo-plug/timestamps/wemo-plug-nov-20-2018.timestamps"; -//// final String deviceIp = "192.168.1.145"; // .246 == phone; .145 == WeMo -// final String deviceIp = "192.168.1.246"; // .246 == phone; .145 == WeMo - - // 5) Wemo Insight July 31 experiment -// final String inputPcapFile = path + "/2018-07/wemoinsight/wemoinsight.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-07/wemoinsight/wemoinsight-processed.pcap"; -// final String triggerTimesFile = path + "/2018-07/wemoinsight/wemo-insight-july-31-2018.timestamps"; -// final String deviceIp = "192.168.1.135"; - // TODO: EXPERIMENT - November 21, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/wemo-insight-plug/wlan1/wemo-insight-plug.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/wemo-insight-plug/wlan1/wemo-insight-plug-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/wemo-insight-plug/timestamps/wemo-insight-plug-nov-21-2018.timestamps"; -//// final String deviceIp = "192.168.1.145"; // .246 == phone; .135 == WeMo Insight -// final String deviceIp = "192.168.1.246"; // .246 == phone; .135 == WeMo Insight - - // 6) TP-Link Bulb August 1 experiment -// final String inputPcapFile = path + "/2018-08/tplink-bulb/tplinkbulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/tplink-bulb/tplinkbulb-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/tplink-bulb/tplink-bulb-aug-3-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .140 == TP-Link bulb - // TODO: EXPERIMENT - November 16, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/tplink-bulb/wlan1/tplink-bulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/tplink-bulb/wlan1/tplink-bulb-processed.pcap"; -//// final String inputPcapFile = path + "/experimental_result/standalone/tplink-bulb/eth0/tplink-bulb.eth1.local.pcap"; -//// final String outputPcapFile = path + "/experimental_result/standalone/tplink-bulb/eth0/tplink-bulb-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/tplink-bulb/timestamps/tplink-bulb-nov-16-2018.timestamps"; -//// final String deviceIp = "192.168.1.140"; // .246 == phone; .140 == TP-Link bulb -// final String deviceIp = "192.168.1.246"; // .246 == phone; .140 == TP-Link bulb - - // 7) Kwikset Doorlock August 6 experiment -// final String inputPcapFile = path + "/2018-08/kwikset-doorlock/kwikset-doorlock.data.wlan1.pcap"; -//// final String inputPcapFile = path + "/2018-08/kwikset-doorlock/kwikset-doorlock.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/kwikset-doorlock/kwikset-doorlock-processed.pcap"; -//// final String triggerTimesFile = path + "/2018-08/kwikset-doorlock/kwikset-doorlock-aug-6-2018.timestamps"; -// final String triggerTimesFile = path + "/2018-08/kwikset-doorlock/kwikset-doorlock-8hr-data-oct-11-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) - // TODO: EXPERIMENT - November 10, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/kwikset-doorlock/wlan1/kwikset-doorlock.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/kwikset-doorlock/wlan1/kwikset-doorlock-processed.pcap"; -//// final String inputPcapFile = path + "/experimental_result/standalone/kwikset-doorlock/eth1/kwikset-doorlock.eth1.local.pcap"; -//// final String outputPcapFile = path + "/experimental_result/standalone/kwikset-doorlock/eth1/kwikset-doorlock-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/kwikset-doorlock/timestamps/kwikset-doorlock-nov-10-2018.timestamps"; -//// final String deviceIp = "192.168.1.142"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) -// final String deviceIp = "192.168.1.246"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) - - // September 12, 2018 - includes both wlan1 and eth1 interfaces -// final String inputPcapFile = path + "/2018-08/kwikset-doorlock/kwikset3.wlan1.local.pcap"; -// //final String inputPcapFile = path + "/2018-08/kwikset-doorlock/kwikset3.eth1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/kwikset-doorlock/kwikset3-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/kwikset-doorlock/kwikset-doorlock-sept-12-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .142 == SmartThings Hub (note: use eth0 capture for this!) - - // 8) Hue Bulb August 7 experiment -// final String inputPcapFile = path + "/2018-08/hue-bulb/hue-bulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/hue-bulb/hue-bulb-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/hue-bulb/hue-bulb-aug-7-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; - // October 30 experiment -// final String inputPcapFile = path + "/2018-10/hue-bulb/hue-bulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-10/hue-bulb/hue-bulb-processed.pcap"; -// final String triggerTimesFile = path + "/2018-10/hue-bulb/hue-bulb-oct-30-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .100 == Hue hub - // TODO: EXPERIMENT - November 19, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/hue-bulb/wlan1/hue-bulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/hue-bulb/wlan1/hue-bulb-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/hue-bulb/timestamps/hue-bulb-nov-19-2018.timestamps"; -//// final String deviceIp = "192.168.1.100"; // .246 == phone; .100 == Hue hub -// final String deviceIp = "192.168.1.246"; // .246 == phone; .100 == Hue hub - - // 9) Lifx Bulb August 8 experiment -// final String inputPcapFile = path + "/2018-08/lifx-bulb/lifx-bulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/lifx-bulb/lifx-bulb-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/lifx-bulb/lifx-bulb-aug-8-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .231 == Lifx - // October 18 -// final String inputPcapFile = path + "/2018-10/lifx-bulb/lifx-bulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-10/lifx-bulb/lifx-bulb-processed.pcap"; -// final String triggerTimesFile = path + "/2018-10/lifx-bulb/lifx-bulb-oct-18-2018.timestamps"; -// final String deviceIp = "192.168.1.231"; // .246 == phone; .231 == Lifx - // November 1 -// final String inputPcapFile = path + "/2018-10/lifx-bulb/lifx-bulb.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-10/lifx-bulb/lifx-bulb-processed.pcap"; -// final String triggerTimesFile = path + "/2018-10/lifx-bulb/lifx-bulb-nov-1-2018.timestamps"; -// final String deviceIp = "192.168.1.231"; // .246 == phone; .231 == Lifx - - // 10) Amcrest Camera August 9 experiment -// final String inputPcapFile = path + "/2018-08/amcrest-camera/amcrest-camera.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/amcrest-camera/amcrest-camera-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/amcrest-camera/amcrest-camera-aug-9-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .235 == camera - - // 11) Arlo Camera August 10 experiment -// final String inputPcapFile = path + "/2018-08/arlo-camera/arlo-camera.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/arlo-camera/arlo-camera-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/arlo-camera/arlo-camera-aug-10-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .140 == camera - // TODO: EXPERIMENT - November 13, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/arlo-camera/wlan1/arlo-camera.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/arlo-camera/wlan1/arlo-camera-processed.pcap"; -//// final String inputPcapFile = path + "/experimental_result/standalone/arlo-camera/eth0/arlo-camera.eth1.local.pcap"; -//// final String outputPcapFile = path + "/experimental_result/standalone/arlo-camera/eth0/arlo-camera-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/arlo-camera/timestamps/arlo-camera-nov-13-2018.timestamps"; -//// final String deviceIp = "192.168.1.140"; // .246 == phone; .140 == camera -// final String deviceIp = "192.168.1.246"; // .246 == phone; .140 == camera - - // 12) Blossom sprinkler August 13 experiment -// final String inputPcapFile = path + "/2018-08/blossom/blossom.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/blossom/blossom-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/blossom/blossom-aug-13-2018.timestamps"; -// final String deviceIp = "192.168.1.229"; // .246 == phone; .229 == sprinkler -// // 2 November -// final String inputPcapFile = path + "/2018-10/blossom-sprinkler/blossom-sprinkler.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-10/blossom-sprinkler/blossom-sprinkler-processed.pcap"; -// final String triggerTimesFile = path + "/2018-10/blossom-sprinkler/blossom-sprinkler-nov-2-2018.timestamps"; -// final String deviceIp = "192.168.1.229"; // .246 == phone; .229 == sprinkler - // January 9, 11, 13, 14 -// final String inputPcapFile = path + "/experimental_result/standalone/blossom-sprinkler/wlan1/blossom-sprinkler.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/blossom-sprinkler/wlan1/blossom-sprinkler-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/blossom-sprinkler/timestamps/blossom-sprinkler-standalone-jan-14-2019.timestamps"; -//// final String triggerTimesFile = path + "/experimental_result/standalone/blossom-sprinkler/timestamps/blossom-sprinkler-standalone-jan-11-2019.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .229 == sprinkler -//// final String deviceIp = "192.168.1.229"; // .246 == phone; .229 == sprinkler - -// // 13) DLink siren August 14 experiment -// final String inputPcapFile = path + "/2018-08/dlink-siren/dlink-siren.wlan1.local.pcap"; -// //final String inputPcapFile = path + "/evaluation/dlink-siren/dlink-siren.data.wlan1.pcap"; -// final String outputPcapFile = path + "/2018-08/dlink-siren/dlink-siren-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/dlink-siren/dlink-siren-oct-12-2018.timestamps"; -// //final String triggerTimesFile = path + "/2018-08/dlink-siren/dlink-siren-aug-14-2018.timestamps"; -// //final String triggerTimesFile = path + "/actual/timestamps/dlink-siren-8hr-data-oct-10-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .183 == siren - // TODO: EXPERIMENT - November 9, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/dlink-siren/wlan1/dlink-siren.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/dlink-siren/wlan1/dlink-siren-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/dlink-siren/timestamps/dlink-siren-nov-9-2018.timestamps"; -//// final String deviceIp = "192.168.1.183"; // .246 == phone; .183 == siren -// final String deviceIp = "192.168.1.246"; // .246 == phone; .183 == siren - - // 14) Nest thermostat August 15 experiment -// final String inputPcapFile = path + "/2018-08/nest/nest.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/nest/nest-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/nest/nest-aug-15-2018.timestamps"; -// final String deviceIp = "192.168.1.246"; // .246 == phone; .127 == Nest thermostat -// // TODO: EXPERIMENT - November 14, 2018 -// final String inputPcapFile = path + "/experimental_result/standalone/nest-thermostat/wlan1/nest-thermostat.wlan1.local.pcap"; -// final String outputPcapFile = path + "/experimental_result/standalone/nest-thermostat/wlan1/nest-thermostat-processed.pcap"; -//// final String inputPcapFile = path + "/experimental_result/standalone/nest-thermostat/eth0/nest-thermostat.eth1.local.pcap"; -//// final String outputPcapFile = path + "/experimental_result/standalone/nest-thermostat/eth0/nest-thermostat-processed.pcap"; -// final String triggerTimesFile = path + "/experimental_result/standalone/nest-thermostat/timestamps/nest-thermostat-nov-15-2018.timestamps"; -//// final String deviceIp = "192.168.1.127"; // .246 == phone; .127 == Nest thermostat -// final String deviceIp = "192.168.1.246"; // .246 == phone; .127 == Nest thermostat - - // 15) Alexa August 16 experiment -// final String inputPcapFile = path + "/2018-08/alexa/alexa.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/alexa/alexa-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/alexa/alexa-aug-16-2018.timestamps"; -// final String deviceIp = "192.168.1.225"; // .246 == phone; .225 == Alexa - // August 17 -// final String inputPcapFile = path + "/2018-08/alexa/alexa2.wlan1.local.pcap"; -// final String outputPcapFile = path + "/2018-08/alexa/alexa2-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/alexa/alexa-aug-17-2018.timestamps"; -// final String deviceIp = "192.168.1.225"; // .246 == phone; .225 == Alexa - - // September 17 -// final String inputPcapFile = path + "/2018-08/noise/noise.eth1.pcap"; -// final String outputPcapFile = path + "/2018-08/noise/noise-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/noise/noise-sept-17-2018.timestamps"; -// final String deviceIp = "192.168.1.142"; // .142 == SmartThings Hub; .199 == dlink plug; .183 == siren - // September 26 - D-Link noise -// final String inputPcapFile = path + "/2018-08/noise/noise.dlink.wlan1.pcap"; -// final String outputPcapFile = path + "/2018-08/noise/noise-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/noise/dlink-noise-sept-26-2018.timestamps"; -// final String deviceIp = "192.168.1.183"; // .199 == dlink plug; .183 == siren - // September 27 - Kwikset noise -// final String inputPcapFile = path + "/2018-08/noise/noise.kwikset.eth1.pcap"; -// final String outputPcapFile = path + "/2018-08/noise/noise-processed.pcap"; -// final String triggerTimesFile = path + "/2018-08/noise/kwikset-doorlock-noise-sept-27-2018.timestamps"; -// final String deviceIp = "192.168.1.142"; // .142 == SmartThings Hub; - - // TODO: The below part is just for 15-second time sensitivity experiment - // TODO: The below part is just for 15-second time sensitivity experiment - // TODO: The below part is just for 15-second time sensitivity experiment - // D-Link plug -// final String triggerTimesFile = path + "/experimental_result/standalone/dlink-plug/timestamps/dlink-plug-nov-7-2018.timestamps"; -//// final String onSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-onSignature-phone-side.sig"; -//// final String offSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-offSignature-phone-side.sig"; -// final String onSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-offSignature-device-side.sig"; - // TP-Link plug - final String triggerTimesFile = path + "/experimental_result/standalone/tplink-plug/timestamps/tplink-plug-nov-8-2018.timestamps"; -//// final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-phone-side.sig"; -//// final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-phone-side.sig"; -// final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-device-side-outbound.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-device-side-outbound.sig"; - final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-device-side.sig"; - final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-device-side.sig"; - - // D-Link siren -// final String triggerTimesFile = path + "/experimental_result/standalone/dlink-siren/timestamps/dlink-siren-nov-9-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/dlink-siren/signatures/dlink-siren-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/dlink-siren/signatures/dlink-siren-offSignature-phone-side.sig"; - // Kwikset door lock -// final String triggerTimesFile = path + "/experimental_result/standalone/kwikset-doorlock/timestamps/kwikset-doorlock-nov-10-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/kwikset-doorlock/signatures/kwikset-doorlock-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/kwikset-doorlock/signatures/kwikset-doorlock-offSignature-phone-side.sig"; - // SmartThings plug -// final String triggerTimesFile = path + "/experimental_result/standalone/st-plug/timestamps/st-plug-nov-12-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/st-plug/signatures/st-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/st-plug/signatures/st-plug-offSignature-phone-side.sig"; - // Arlo Q -// final String triggerTimesFile = path + "/experimental_result/standalone/arlo-camera/timestamps/arlo-camera-nov-13-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/arlo-camera/signatures/arlo-camera-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/arlo-camera/signatures/arlo-camera-offSignature-phone-side.sig"; - // Nest thermostat -// final String triggerTimesFile = path + "/experimental_result/standalone/nest-thermostat/timestamps/nest-thermostat-nov-15-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/nest-thermostat/signatures/nest-thermostat-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/nest-thermostat/signatures/nest-thermostat-offSignature-phone-side.sig"; - // Blossom sprinkler -// final String triggerTimesFile = path + "/experimental_result/standalone/blossom-sprinkler/timestamps/blossom-sprinkler-standalone-jan-14-2019.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-device-side.sig"; -// final String onSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-phone-side.sig"; - // TP-Link bulb -// final String triggerTimesFile = path + "/experimental_result/standalone/tplink-bulb/timestamps/tplink-bulb-nov-16-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/tplink-bulb/signatures/tplink-bulb-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/tplink-bulb/signatures/tplink-bulb-offSignature-phone-side.sig"; - // Philips hue -// final String triggerTimesFile = path + "/2018-08/hue-bulb/hue-bulb-aug-7-2018.timestamps"; -// final String onSignatureFile = path + "/training/hue-bulb/signatures/hue-bulb-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/hue-bulb/signatures/hue-bulb-offSignature-phone-side.sig"; - // WeMo plug -// final String triggerTimesFile = path + "/experimental_result/standalone/wemo-plug/timestamps/wemo-plug-nov-20-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/wemo-plug/signatures/wemo-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/wemo-plug/signatures/wemo-plug-offSignature-phone-side.sig"; - // WeMo Insight plug -// final String triggerTimesFile = path + "/experimental_result/standalone/wemo-insight-plug/timestamps/wemo-insight-plug-nov-21-2018.timestamps"; -// final String onSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-offSignature-phone-side.sig"; - - - TriggerTimesFileReader ttfr = new TriggerTimesFileReader(); - List triggerTimes = ttfr.readTriggerTimes(triggerTimesFile, false); - - System.out.println("ON signature file in use is " + onSignatureFile); - System.out.println("OFF signature file in use is " + offSignatureFile); - - List>> onSignature = PrintUtils.deserializeSignatureFromFile(onSignatureFile); - List>> offSignature = PrintUtils.deserializeSignatureFromFile(offSignatureFile); - - List signatureTimestamps = new ArrayList<>(); - // Load ON signature last packet's timestamp - // Get the last only - List> lastListOn = onSignature.get(onSignature.size()-1); - for (List list : lastListOn) { - // Get timestamp Instant from the last packet - int lastPacketIndex = list.size()-1; - signatureTimestamps.add(list.get(lastPacketIndex).getTimestamp()); - } - // Load OFF signature last packet's timestamp - // Get the last only - List> lastListOff = offSignature.get(offSignature.size()-1); - for (List list : lastListOff) { - // Get timestamp Instant from the last packet - int lastPacketIndex = list.size()-1; - signatureTimestamps.add(list.get(lastPacketIndex).getTimestamp()); - } - // Sort the timestamps - signatureTimestamps.sort((p1, p2) -> { - return p1.compareTo(p2); - }); - - Iterator iterTrig = triggerTimes.iterator(); - Iterator iterSign = signatureTimestamps.iterator(); - System.out.println("Trigger to Last Packet:"); - while (iterTrig.hasNext() && iterSign.hasNext()) { - Instant trigInst = (Instant) iterTrig.next(); - Instant signInst = (Instant) iterSign.next(); - Duration dur = Duration.between(trigInst, signInst); - long duration = dur.toMillis(); - // Check duration --- should be below 15 seconds - if (duration >= 0 && duration <= 15000) { - System.out.println(dur.toMillis()); - } else if (duration > 15000) { - while (duration > 15000) { // that means we have to move to the next trigger - trigInst = (Instant) iterTrig.next(); - dur = Duration.between(trigInst, signInst); - duration = dur.toMillis(); - } - System.out.println(dur.toMillis()); - } else { // below 0 / negative --- that means we have to move to the next signature - while (duration < 0) { // that means we have to move to the next trigger - signInst = (Instant) iterSign.next(); - dur = Duration.between(trigInst, signInst); - duration = dur.toMillis(); - } - System.out.println(dur.toMillis()); - } - } - - - // ========================================================================== - List firstSignatureTimestamps = new ArrayList<>(); - List lastSignatureTimestamps = new ArrayList<>(); - List> firstListOnSign = onSignature.get(0); - List> lastListOnSign = onSignature.get(onSignature.size()-1); - // Load ON signature first and last packet's timestamps - for (List list : firstListOnSign) { - // Get timestamp Instant from the last packet - firstSignatureTimestamps.add(list.get(0).getTimestamp()); - } - for (List list : lastListOnSign) { - // Get timestamp Instant from the last packet - int lastPacketIndex = list.size()-1; - lastSignatureTimestamps.add(list.get(lastPacketIndex).getTimestamp()); - } - - List> firstListOffSign = offSignature.get(0); - List> lastListOffSign = offSignature.get(offSignature.size()-1); - // Load OFF signature first and last packet's timestamps - for (List list : firstListOffSign) { - // Get timestamp Instant from the last packet - firstSignatureTimestamps.add(list.get(0).getTimestamp()); - } - for (List list : lastListOffSign) { - // Get timestamp Instant from the last packet - int lastPacketIndex = list.size()-1; - lastSignatureTimestamps.add(list.get(lastPacketIndex).getTimestamp()); - } - // Sort the timestamps - firstSignatureTimestamps.sort((p1, p2) -> { - return p1.compareTo(p2); - }); - // Sort the timestamps - lastSignatureTimestamps.sort((p1, p2) -> { - return p1.compareTo(p2); - }); - - Iterator iterFirst = firstSignatureTimestamps.iterator(); - Iterator iterLast = lastSignatureTimestamps.iterator(); - System.out.println("First to Last Packet:"); - while (iterFirst.hasNext() && iterLast.hasNext()) { - Instant firstInst = (Instant) iterFirst.next(); - Instant lastInst = (Instant) iterLast.next(); - Duration dur = Duration.between(firstInst, lastInst); - long duration = dur.toMillis(); - // Check duration --- should be below 15 seconds - if (duration >= 0 && duration <= 15000) { - System.out.println(dur.toMillis()); - } else if (duration > 15000) { - while (duration > 15000) { // that means we have to move to the next trigger - firstInst = (Instant) iterFirst.next(); - dur = Duration.between(firstInst, lastInst); - duration = dur.toMillis(); - } - System.out.println(dur.toMillis()); - } else { // below 0 / negative --- that means we have to move to the next signature - while (duration < 0) { // that means we have to move to the next trigger - lastInst = (Instant) iterLast.next(); - dur = Duration.between(firstInst, lastInst); - duration = dur.toMillis(); - } - System.out.println(dur.toMillis()); - } - if (duration > 8000) { - break; - } - } - - // TODO: The above part is just for 15-second time sensitivity experiment - // TODO: The above part is just for 15-second time sensitivity experiment - // TODO: The above part is just for 15-second time sensitivity experiment - - - - -// TriggerTimesFileReader ttfr = new TriggerTimesFileReader(); -// List triggerTimes = ttfr.readTriggerTimes(triggerTimesFile, false); -// // Tag each trigger with "ON" or "OFF", assuming that the first trigger is an "ON" and that they alternate. -// List userActions = new ArrayList<>(); -// for (int i = 0; i < triggerTimes.size(); i++) { -// userActions.add(new UserAction(i % 2 == 0 ? Type.TOGGLE_ON : Type.TOGGLE_OFF, triggerTimes.get(i))); -// } -// TriggerTrafficExtractor tte = new TriggerTrafficExtractor(inputPcapFile, triggerTimes, deviceIp); -// final PcapDumper outputter = Pcaps.openDead(DataLinkType.EN10MB, 65536).dumpOpen(outputPcapFile); -// DnsMap dnsMap = new DnsMap(); -// TcpReassembler tcpReassembler = new TcpReassembler(); -// TrafficLabeler trafficLabeler = new TrafficLabeler(userActions); -// tte.performExtraction(pkt -> { -// try { -// outputter.dump(pkt); -// } catch (NotOpenException e) { -// e.printStackTrace(); -// } -// }, dnsMap, tcpReassembler, trafficLabeler); -// outputter.flush(); -// outputter.close(); -// -// if (tte.getPacketsIncludedCount() != trafficLabeler.getTotalPacketCount()) { -// // Sanity/debug check -// throw new AssertionError(String.format("mismatch between packet count in %s and %s", -// TriggerTrafficExtractor.class.getSimpleName(), TrafficLabeler.class.getSimpleName())); -// } -// -// // Extract all conversations present in the filtered trace. -// List allConversations = tcpReassembler.getTcpConversations(); -// // Group conversations by hostname. -// Map> convsByHostname = TcpConversationUtils.groupConversationsByHostname(allConversations, dnsMap); -// System.out.println("Grouped conversations by hostname."); -// // For each hostname, count the frequencies of packet lengths exchanged with that hostname. -// final Map> pktLenFreqsByHostname = new HashMap<>(); -// convsByHostname.forEach((host, convs) -> pktLenFreqsByHostname.put(host, TcpConversationUtils.countPacketLengthFrequencies(convs))); -// System.out.println("Counted frequencies of packet lengths exchanged with each hostname."); -// // For each hostname, count the frequencies of packet sequences (i.e., count how many conversations exchange a -// // sequence of packets of some specific lengths). -// final Map> pktSeqFreqsByHostname = new HashMap<>(); -// convsByHostname.forEach((host, convs) -> pktSeqFreqsByHostname.put(host, TcpConversationUtils.countPacketSequenceFrequencies(convs))); -// System.out.println("Counted frequencies of packet sequences exchanged with each hostname."); -// // For each hostname, count frequencies of packet pairs exchanged with that hostname across all conversations -// final Map> pktPairFreqsByHostname = -// TcpConversationUtils.countPacketPairFrequenciesByHostname(allConversations, dnsMap); -// System.out.println("Counted frequencies of packet pairs per hostname"); -// // For each user action, reassemble the set of TCP connections occurring shortly after -// final Map> userActionToConversations = trafficLabeler.getLabeledReassembledTcpTraffic(); -// final Map>> userActionsToConvsByHostname = trafficLabeler.getLabeledReassembledTcpTraffic(dnsMap); -// System.out.println("Reassembled TCP conversations occurring shortly after each user event"); -// -// -// -// /* -// * NOTE: no need to generate these more complex on/off maps that also contain mappings from hostname and -// * sequence identifiers as we do not care about hostnames and sequences during clustering. -// * We can simply use the UserAction->List map to generate ON/OFF groupings of conversations. -// */ -// -//// // Contains all ON events: hostname -> sequence identifier -> list of conversations with that sequence -//// Map>> ons = new HashMap<>(); -//// // Contains all OFF events: hostname -> sequence identifier -> list of conversations with that sequence -//// Map>> offs = new HashMap<>(); -//// userActionsToConvsByHostname.forEach((ua, hostnameToConvs) -> { -//// Map>> outer = ua.getType() == Type.TOGGLE_ON ? ons : offs; -//// hostnameToConvs.forEach((host, convs) -> { -//// Map> seqsToConvs = TcpConversationUtils. -//// groupConversationsByPacketSequence(convs, verbose); -//// outer.merge(host, seqsToConvs, (oldMap, newMap) -> { -//// newMap.forEach((sequence, cs) -> oldMap.merge(sequence, cs, (list1, list2) -> { -//// list1.addAll(list2); -//// return list1; -//// })); -//// return oldMap; -//// }); -//// }); -//// }); -//// -//// System.out.println("==== ON ===="); -//// // Print out all the pairs into a file for ON events -//// File fileOnEvents = new File(onPairsPath); -//// PrintWriter pwOn = null; -//// try { -//// pwOn = new PrintWriter(fileOnEvents); -//// } catch(Exception ex) { -//// ex.printStackTrace(); -//// } -//// for(Map.Entry>> entry : ons.entrySet()) { -//// Map> seqsToConvs = entry.getValue(); -//// for(Map.Entry> entryConv : seqsToConvs.entrySet()) { -//// List listConv = entryConv.getValue(); -//// // Just get the first Conversation because all Conversations in this group -//// // should have the same pairs of Application Data. -//// for(Conversation conv : listConv) { -//// // Process only if it is a TLS packet -//// if (conv.isTls()) { -//// List tlsAppDataList = TcpConversationUtils.extractTlsAppDataPacketPairs(conv); -//// for(PcapPacketPair pair: tlsAppDataList) { -//// System.out.println(PrintUtils.toCsv(pair, dnsMap)); -//// pwOn.println(PrintUtils.toCsv(pair, dnsMap)); -//// } -//// } else { // Non-TLS conversations -//// List packetList = TcpConversationUtils.extractPacketPairs(conv); -//// for(PcapPacketPair pair: packetList) { -//// System.out.println(PrintUtils.toCsv(pair, dnsMap)); -//// pwOn.println(PrintUtils.toCsv(pair, dnsMap)); -//// } -//// } -//// } -//// } -//// } -//// pwOn.close(); -//// -//// System.out.println("==== OFF ===="); -//// // Print out all the pairs into a file for ON events -//// File fileOffEvents = new File(offPairsPath); -//// PrintWriter pwOff = null; -//// try { -//// pwOff = new PrintWriter(fileOffEvents); -//// } catch(Exception ex) { -//// ex.printStackTrace(); -//// } -//// for(Map.Entry>> entry : offs.entrySet()) { -//// Map> seqsToConvs = entry.getValue(); -//// for(Map.Entry> entryConv : seqsToConvs.entrySet()) { -//// List listConv = entryConv.getValue(); -//// // Just get the first Conversation because all Conversations in this group -//// // should have the same pairs of Application Data. -//// for(Conversation conv : listConv) { -//// // Process only if it is a TLS packet -//// if (conv.isTls()) { -//// List tlsAppDataList = TcpConversationUtils.extractTlsAppDataPacketPairs(conv); -//// for(PcapPacketPair pair: tlsAppDataList) { -//// System.out.println(PrintUtils.toCsv(pair, dnsMap)); -//// pwOff.println(PrintUtils.toCsv(pair, dnsMap)); -//// } -//// } else { // Non-TLS conversations -//// List packetList = TcpConversationUtils.extractPacketPairs(conv); -//// for (PcapPacketPair pair : packetList) { -//// System.out.println(PrintUtils.toCsv(pair, dnsMap)); -//// pwOff.println(PrintUtils.toCsv(pair, dnsMap)); -//// } -//// } -//// } -//// } -//// } -//// pwOff.close(); -// -// -// // ================================================ CLUSTERING ================================================ -// // Note: no need to use the more convoluted on/off maps; can simply use the UserAction->List map -// // when don't care about hostnames and sequences (see comment earlier). -//// List onConversations = userActionToConversations.entrySet().stream(). -//// filter(e -> e.getKey().getType() == Type.TOGGLE_ON). // drop all OFF events from stream -//// map(e -> e.getValue()). // no longer interested in the UserActions -//// flatMap(List::stream). // flatten List> to a List -//// collect(Collectors.toList()); -//// List offConversations = userActionToConversations.entrySet().stream(). -//// filter(e -> e.getKey().getType() == Type.TOGGLE_OFF). -//// map(e -> e.getValue()). -//// flatMap(List::stream). -//// collect(Collectors.toList()); -//// //Collections.sort(onConversations, (c1, c2) -> c1.getPackets().) -//// -//// List onPairs = onConversations.stream(). -//// map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) : -//// TcpConversationUtils.extractPacketPairs(c)). -//// flatMap(List::stream). // flatten List> to List<> -//// collect(Collectors.toList()); -//// List offPairs = offConversations.stream(). -//// map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) : -//// TcpConversationUtils.extractPacketPairs(c)). -//// flatMap(List::stream). // flatten List> to List<> -//// collect(Collectors.toList()); -//// // Note: need to update the DnsMap of all PcapPacketPairs if we want to use the IP/hostname-sensitive distance. -//// Stream.concat(Stream.of(onPairs), Stream.of(offPairs)).flatMap(List::stream).forEach(p -> p.setDnsMap(dnsMap)); -//// // Perform clustering on conversation logged as part of all ON events. -////// DBSCANClusterer onClusterer = new DBSCANClusterer<>(10.0, 45); -//// DBSCANClusterer onClusterer = new DBSCANClusterer<>(2, 2); -//// //DBSCANClusterer onClusterer = new DBSCANClusterer<>(10.0, 10); -//// List> onClusters = onClusterer.cluster(onPairs); -//// // Perform clustering on conversation logged as part of all OFF events. -////// DBSCANClusterer offClusterer = new DBSCANClusterer<>(10.0, 45); -//// DBSCANClusterer offClusterer = new DBSCANClusterer<>(2, 2); -//// //DBSCANClusterer offClusterer = new DBSCANClusterer<>(10.0, 10); -//// List> offClusters = offClusterer.cluster(offPairs); -//// // Sort the conversations as reference -//// List sortedAllConversation = TcpConversationUtils.sortConversationList(allConversations); -//// // Output clusters -//// System.out.println("========================================"); -//// System.out.println(" Clustering results for ON "); -//// System.out.println(" Number of clusters: " + onClusters.size()); -//// int count = 0; -//// List>> ppListOfListReadOn = new ArrayList<>(); -//// List>> ppListOfListListOn = new ArrayList<>(); -//// for (Cluster c : onClusters) { -//// System.out.println(String.format("<<< Cluster #%02d (%03d points) >>>", ++count, c.getPoints().size())); -//// System.out.print(PrintUtils.toSummaryString(c)); -//// if(c.getPoints().size() > 45 && c.getPoints().size() < 55) { -//// //if(c.getPoints().size() > 25) { -//// // Print to file -//// List> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c); -//// ppListOfListListOn.add(ppListOfList); -//// } -//// } -//// // TODO: Merging test -//// ppListOfListListOn = PcapPacketUtils.mergeSignatures(ppListOfListListOn, sortedAllConversation); -//// // TODO: Need to remove sequence 550 567 for Blossom phone side since it is not a good signature (overlap)! -////// PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 1); -//// // TODO: Need to remove sequence 69 296 for Blossom device side since it is not a good signature (overlap)! -////// PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 2); -//// // TODO: Need to remove sequence number 2 for ST plug since it is not a good signature! -//// //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 2); -//// // TODO: Need to remove sequence number 0 for Arlo Camera since it is not a good signature! -//// //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 0); -//// // TODO: Need to remove sequence number 0 for TP-Link plug since it is not a good signature! -//// // TODO: This sequence actually belongs to the local communication between the plug and the phone -//// //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 0); -//// ppListOfListListOn = PcapPacketUtils.sortSignatures(ppListOfListListOn); -//// PcapPacketUtils.printSignatures(ppListOfListListOn); -//// //count = 0; -//// /*for (List> ll : ppListOfListListOn) { -//// PrintUtils.serializeClustersIntoFile("./onSignature" + ++count + ".sig", ll); -//// ppListOfListReadOn.add(PrintUtils.deserializeClustersFromFile("./onSignature" + count + ".sig")); -//// }*/ -//// PrintUtils.serializeSignatureIntoFile("./onSignature.sig", ppListOfListListOn); -//// ppListOfListReadOn = PrintUtils.deserializeSignatureFromFile("./onSignature.sig"); -//// -//// System.out.println("========================================"); -//// System.out.println(" Clustering results for OFF "); -//// System.out.println(" Number of clusters: " + offClusters.size()); -//// count = 0; -//// List>> ppListOfListReadOff = new ArrayList<>(); -//// List>> ppListOfListListOff = new ArrayList<>(); -//// for (Cluster c : offClusters) { -//// System.out.println(String.format("<<< Cluster #%03d (%06d points) >>>", ++count, c.getPoints().size())); -//// System.out.print(PrintUtils.toSummaryString(c)); -//// if(c.getPoints().size() > 45 && c.getPoints().size() < 55) { -//// //if(c.getPoints().size() > 25) { -//// // Print to file -//// List> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c); -//// ppListOfListListOff.add(ppListOfList); -//// } -//// } -//// // TODO: Merging test -//// ppListOfListListOff = PcapPacketUtils.mergeSignatures(ppListOfListListOff, sortedAllConversation); -//// // TODO: Need to remove sequence 69 296 for Blossom device side since it is not a good signature (overlap)! -////// PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 3); -//// // TODO: Need to remove sequence number 1 for Nest Thermostat since it is not a good signature! -//// //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 1); -//// // TODO: Need to remove sequence number 0 for Arlo Camera since it is not a good signature! -////// PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 1); -//// // TODO: Need to remove sequence number 2 for ST plug since it is not a good signature! -//// //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 2); -//// // TODO: Need to remove sequence number 0 for TP-Link plug since it is not a good signature! -//// // TODO: This sequence actually belongs to the local communication between the plug and the phone -//// //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 0); -//// ppListOfListListOff = PcapPacketUtils.sortSignatures(ppListOfListListOff); -//// PcapPacketUtils.printSignatures(ppListOfListListOff); -//// //count = 0; -//// /*for (List> ll : ppListOfListListOff) { -//// PrintUtils.serializeClustersIntoFile("./offSignature" + ++count + ".sig", ll); -//// ppListOfListReadOff.add(PrintUtils.deserializeClustersFromFile("./offSignature" + count + ".sig")); -//// }*/ -//// PrintUtils.serializeSignatureIntoFile("./offSignature.sig", ppListOfListListOff); -//// ppListOfListReadOff = PrintUtils.deserializeSignatureFromFile("./offSignature.sig"); -//// System.out.println("========================================"); -// // ============================================================================================================ -// -// // TODO: This part is just for DBSCAN sensitivity experiment -// // TODO: This part is just for DBSCAN sensitivity experiment -// // TODO: This part is just for DBSCAN sensitivity experiment -// // TODO: This part is just for DBSCAN sensitivity experiment -// // TODO: This part is just for DBSCAN sensitivity experiment -// List onConversations = userActionToConversations.entrySet().stream(). -// filter(e -> e.getKey().getType() == Type.TOGGLE_ON). // drop all OFF events from stream -// map(e -> e.getValue()). // no longer interested in the UserActions -// flatMap(List::stream). // flatten List> to a List -// collect(Collectors.toList()); -// List offConversations = userActionToConversations.entrySet().stream(). -// filter(e -> e.getKey().getType() == Type.TOGGLE_OFF). -// map(e -> e.getValue()). -// flatMap(List::stream). -// collect(Collectors.toList()); -// //Collections.sort(onConversations, (c1, c2) -> c1.getPackets().) -// -// List onPairs = onConversations.stream(). -// map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) : -// TcpConversationUtils.extractPacketPairs(c)). -// flatMap(List::stream). // flatten List> to List<> -// collect(Collectors.toList()); -// List offPairs = offConversations.stream(). -// map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) : -// TcpConversationUtils.extractPacketPairs(c)). -// flatMap(List::stream). // flatten List> to List<> -// collect(Collectors.toList()); -// // Note: need to update the DnsMap of all PcapPacketPairs if we want to use the IP/hostname-sensitive distance. -// Stream.concat(Stream.of(onPairs), Stream.of(offPairs)).flatMap(List::stream).forEach(p -> p.setDnsMap(dnsMap)); -// -// double eps = 10; // loop from eps 1-10 -// int minPts = 50; // loop from minPts 30-50 -// for(int epsCount = 7; epsCount <= eps; epsCount++) { -// for(int minPtsCount = 30; minPtsCount <= minPts; minPtsCount++) { -// System.out.println("Eps: " + epsCount + " --- minPts: " + minPtsCount); -// DBSCANClusterer onClusterer = new DBSCANClusterer<>(epsCount, minPtsCount); -// DBSCANClusterer offClusterer = new DBSCANClusterer<>(epsCount, minPtsCount); -// List> onClusters = onClusterer.cluster(onPairs); -// List> offClusters = offClusterer.cluster(offPairs); -// // Sort the conversations as reference -// List sortedAllConversation = TcpConversationUtils.sortConversationList(allConversations); -// // Output clusters -// System.out.println("========================================"); -// System.out.println(" Clustering results for ON "); -// System.out.println(" Number of clusters: " + onClusters.size()); -// int count = 0; -// List>> ppListOfListListOn = new ArrayList<>(); -// for (Cluster c : onClusters) { -// System.out.println(String.format("<<< Cluster #%02d (%03d points) >>>", ++count, c.getPoints().size())); -//// System.out.print(PrintUtils.toSummaryString(c)); -// if (c.getPoints().size() > 45 && c.getPoints().size() < 55) { -//// if(c.getPoints().size() > 25) { -// // Print to file -// List> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c); -// ppListOfListListOn.add(ppListOfList); -// } -// } -// PcapPacketUtils.printSignatures(ppListOfListListOn); -// -// System.out.println("========================================"); -// System.out.println(" Clustering results for OFF "); -// System.out.println(" Number of clusters: " + offClusters.size()); -// count = 0; -// List>> ppListOfListListOff = new ArrayList<>(); -// for (Cluster c : offClusters) { -// System.out.println(String.format("<<< Cluster #%03d (%06d points) >>>", ++count, c.getPoints().size())); -//// System.out.print(PrintUtils.toSummaryString(c)); -// if (c.getPoints().size() > 45 && c.getPoints().size() < 55) { -// //if(c.getPoints().size() > 25) { -// // Print to file -// List> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c); -// ppListOfListListOff.add(ppListOfList); -// } -// } -// PcapPacketUtils.printSignatures(ppListOfListListOff); -// System.out.println(); -// System.out.println(); -// System.out.println(); -// // ============================================================================================================ -// } -// } - - -// // ================================================================================================ -// // <<< Some work-in-progress/explorative code that extracts a "representative" sequence >>> -// // -// // Currently need to know relevant hostname in advance :( -// String hostname = "events.tplinkra.com"; -//// String hostname = "rfe-us-west-1.dch.dlink.com"; -// // Conversations with 'hostname' for ON events. -// List onsForHostname = new ArrayList<>(); -// // Conversations with 'hostname' for OFF events. -// List offsForHostname = new ArrayList<>(); -// // "Unwrap" sequence groupings in ons/offs maps. -// ons.get(hostname).forEach((k,v) -> onsForHostname.addAll(v)); -// offs.get(hostname).forEach((k,v) -> offsForHostname.addAll(v)); -// -// -// Map> onsForHostnameGroupedByTlsAppDataSequence = TcpConversationUtils.groupConversationsByTlsApplicationDataPacketSequence(onsForHostname); -// -// -// // Extract representative sequence for ON and OFF by providing the list of conversations with -// // 'hostname' observed for each event type (the training data). -// SequenceExtraction seqExtraction = new SequenceExtraction(); -//// ExtractedSequence extractedSequenceForOn = seqExtraction.extract(onsForHostname); -//// ExtractedSequence extractedSequenceForOff = seqExtraction.extract(offsForHostname); -// -// ExtractedSequence extractedSequenceForOn = seqExtraction.extractByTlsAppData(onsForHostname); -// ExtractedSequence extractedSequenceForOff = seqExtraction.extractByTlsAppData(offsForHostname); -// -// // Let's check how many ONs align with OFFs and vice versa (that is, how many times an event is incorrectly -// // labeled). -// int onsLabeledAsOff = 0; -// Integer[] representativeOnSeq = TcpConversationUtils.getPacketLengthSequence(extractedSequenceForOn.getRepresentativeSequence()); -// Integer[] representativeOffSeq = TcpConversationUtils.getPacketLengthSequence(extractedSequenceForOff.getRepresentativeSequence()); -// SequenceAlignment seqAlg = seqExtraction.getAlignmentAlgorithm(); -// for (Conversation c : onsForHostname) { -// Integer[] onSeq = TcpConversationUtils.getPacketLengthSequence(c); -// if (seqAlg.calculateAlignment(representativeOffSeq, onSeq) <= extractedSequenceForOff.getMaxAlignmentCost()) { -// onsLabeledAsOff++; -// } -// } -// int offsLabeledAsOn = 0; -// for (Conversation c : offsForHostname) { -// Integer[] offSeq = TcpConversationUtils.getPacketLengthSequence(c); -// if (seqAlg.calculateAlignment(representativeOnSeq, offSeq) <= extractedSequenceForOn.getMaxAlignmentCost()) { -// offsLabeledAsOn++; -// } -// } -// System.out.println(""); -// // ================================================================================================ -// -// -// // ------------------------------------------------------------------------------------------------------------- -// // ------------------------------------------------------------------------------------------------------------- - } - -} - - -// TP-Link MAC 50:c7:bf:33:1f:09 and usually IP 192.168.1.159 (remember to verify per file) -// frame.len >= 556 && frame.len <= 558 && ip.addr == 192.168.1.159 \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketFilter.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketFilter.java deleted file mode 100644 index 529faf4..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package edu.uci.iotproject.analysis; - -import org.pcap4j.core.PcapPacket; - -/** - * TODO add class documentation. - * - * @author Janus Varmarken - */ -public interface PcapPacketFilter { - - boolean shouldIncludePacket(PcapPacket packet); - -} 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 deleted file mode 100644 index 2d6e9aa..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/PcapPacketPair.java +++ /dev/null @@ -1,182 +0,0 @@ -package edu.uci.iotproject.analysis; - -import edu.uci.iotproject.DnsMap; -import edu.uci.iotproject.util.PcapPacketUtils; -import org.apache.commons.math3.stat.clustering.Clusterable; -import org.pcap4j.core.PcapPacket; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import static edu.uci.iotproject.util.PcapPacketUtils.getSourceIp; - -/** - *

- * A simple wrapper for holding a pair of packets (e.g., a request and associated reply packet). - *

- * - * Note: we use the deprecated version - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class PcapPacketPair implements Clusterable { - - /** - * If {@code true}, {@link #distanceFrom(PcapPacketPair)} will only consider if the sources of the two packets in - * the {@link PcapPacketPair}s being compared match in terms of whether the IP is a local or a remote IP. It will - * not check if the IPs/hostnames are actually the same. Set to {@code false} to make the comparison more - * strict, i.e., to enforce the requirement that the respective IPs (or hostnames) in the packets of the two - * {@link PcapPacketPair}s must be identical. - */ - private static final boolean SIMPLIFIED_SOURCE_COMPARISON = true; - - private final PcapPacket mFirst; - - private final Optional mSecond; - - /** - * IP to hostname mappings. - * Allows for grouping packets with different source IPs that map to the same hostname into one cluster. - */ - private DnsMap mDnsMap; // TODO implement and invoke setter - - public PcapPacketPair(PcapPacket first, PcapPacket second) { - mFirst = first; - mSecond = Optional.ofNullable(second); - } - - public PcapPacket getFirst() { return mFirst; } - - public boolean isFirstClient() { - String firstIp = PcapPacketUtils.getSourceIp(mFirst); - InetAddress ia = null; - try { - ia = InetAddress.getByName(firstIp); - } catch (UnknownHostException ex) { - ex.printStackTrace(); - } - return ia.isSiteLocalAddress(); - } - - public Optional getSecond() { return mSecond; } - - public boolean isSecondClient() { - // Return the value of the second source if it is not null - if (mSecond.isPresent()) { - String secondIp = PcapPacketUtils.getSourceIp(mSecond.get()); - InetAddress ia = null; - try { - ia = InetAddress.getByName(secondIp); - } catch (UnknownHostException ex) { - ex.printStackTrace(); - } - return ia.isSiteLocalAddress(); - } else { - // When it is null, we always return the opposite of the first source's status - return !isFirstClient(); - } - } - - /** - * Get the {@link DnsMap} that is queried for hostnames mappings when performing IP/hostname-sensitive clustering. - * @return the {@link DnsMap} that is queried for hostnames mappings when performing IP/hostname-sensitive clustering. - */ - public DnsMap getDnsMap() { - return mDnsMap; - } - - /** - * Set the {@link DnsMap} to be queried for hostnames mappings when performing IP/hostname-sensitive clustering. - * @param dnsMap a {@code DnsMap} to be queried for hostnames mappings when performing IP/hostname-sensitive clustering. - */ - public void setDnsMap(final DnsMap dnsMap) { - mDnsMap = dnsMap; - } - - @Override - public String toString() { - return String.format("%d, %s", - getFirst().getOriginalLength(), - getSecond().map(pkt -> Integer.toString(pkt.getOriginalLength())).orElse("null")); - } - - // ================================================================================================================= - // Begin implementation of org.apache.commons.math3.stat.clustering.Clusterable interface - @Override - public double distanceFrom(PcapPacketPair that) { - if (SIMPLIFIED_SOURCE_COMPARISON) { - // Direction of packets in terms of client-to-server or server-to-client must match, but we don't care about - // IPs and hostnames - if (this.isFirstClient() != that.isFirstClient() || this.isSecondClient() != that.isSecondClient()) { - // Distance is maximal if mismatch in direction of packets - return Double.MAX_VALUE; - } - } else { - // Strict mode enabled: IPs/hostnames must match! - // Extract src ips of both packets of each pair. - String thisSrc1 = getSourceIp(this.getFirst()); - String thisSrc2 = this.getSecond().map(pp -> getSourceIp(pp)).orElse(""); - String thatSrc1 = getSourceIp(that.getFirst()); - String thatSrc2 = that.getSecond().map(pp -> getSourceIp(pp)).orElse(""); - - // Replace IPs with hostnames if possible. - thisSrc1 = mapToHostname(thisSrc1); - thisSrc2 = mapToHostname(thisSrc2); - thatSrc1 = mapToHostname(thatSrc1); - thatSrc2 = mapToHostname(thatSrc2); - - if(!thisSrc1.equals(thatSrc1) || !thisSrc2.equals(thatSrc2)) { - // Distance is maximal if sources differ. - return Double.MAX_VALUE; - } - } - - // If the sources match, the distance is the Euclidean distance between each pair of packet lengths. - int thisLen1 = this.getFirst().getOriginalLength(); - // TODO should discard pairs w/o second packet from clustering; replace below with getSecond().get() when done. - int thisLen2 = this.getSecond().map(pp -> pp.getOriginalLength()).orElse(0); - int thatLen1 = that.getFirst().getOriginalLength(); - // TODO should discard pairs w/o second packet from clustering; replace below with getSecond().get() when done. - int thatLen2 = that.getSecond().map(pp -> pp.getOriginalLength()).orElse(0); - return Math.sqrt( - Math.pow(thisLen1 - thatLen1, 2) + - Math.pow(thisLen2 - thatLen2, 2) - ); - } - - @Override - public PcapPacketPair centroidOf(Collection p) { - // No notion of centroid in DBSCAN - throw new UnsupportedOperationException("Not implemented; no notion of a centroid in DBSCAN."); - } - // End implementation of org.apache.commons.math3.stat.clustering.Clusterable interface - // ================================================================================================================= - - private String mapToHostname(String ip) { - Set hostnames = mDnsMap.getHostnamesForIp(ip); - if (hostnames != null && hostnames.size() > 0) { - // append hostnames back-to-back separated by a delimiter if more than one item in set - // note: use sorted() to ensure that output remains consistent (as Set has no internal ordering of elements) - String result = hostnames.stream().sorted().collect(Collectors.joining(" ")); - if (hostnames.size() > 1) { - // One IP can map to multiple hostnames, although that is rare. For now just raise a warning. - String warningStr = String.format( - "%s.mapToHostname(): encountered an IP (%s) that maps to multiple hostnames (%s)", - getClass().getSimpleName(), ip, result); - System.err.println(warningStr); - } - return result; - } - // If unable to map to a hostname, return ip for ease of use; caller can overwrite input value, defaulting to - // the original value if no mapping is found: - // String src = ""; - // src = mapToHostname(src); // src is now either a hostname or the original ip. - return ip; - } - -} 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 deleted file mode 100644 index a4217cc..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TcpConversationUtils.java +++ /dev/null @@ -1,464 +0,0 @@ -package edu.uci.iotproject.analysis; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.DnsMap; -import edu.uci.iotproject.util.PcapPacketUtils; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.IpV4Packet; -import org.pcap4j.packet.TcpPacket; - -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static edu.uci.iotproject.util.PcapPacketUtils.*; - -/** - * Utility functions for analyzing and structuring (sets of) {@link Conversation}s. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class TcpConversationUtils { - - /** - * Identifies the adjacency type of the signature for merging. - */ - public enum SignaturePosition { - NOT_ADJACENT, - LEFT_ADJACENT, - RIGHT_ADJACENT - } - - /** - *

- * 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 {@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) { - 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<>(); -// for(PcapPacket pp : packets) { -// System.out.print(pp.length() + " "); -// } -// System.out.println(); - - int i = 0; - while (i < packets.size()) { - PcapPacket p1 = packets.get(i); - String p1SrcIp = p1.get(IpV4Packet.class).getHeader().getSrcAddr().getHostAddress(); - int p1SrcPort = p1.get(TcpPacket.class).getHeader().getSrcPort().valueAsInt(); - if (i+1 < packets.size()) { - PcapPacket p2 = packets.get(i+1); - if (PcapPacketUtils.isSource(p2, p1SrcIp, p1SrcPort)) { - // Two packets in a row going in the same direction -> create one item pair for p1 - pairs.add(new PcapPacketPair(p1, null)); - // Advance one packet as the following two packets may form a valid two-item pair. - i++; - } else { - // The two packets form a response-reply pair, create two-item pair. - pairs.add(new PcapPacketPair(p1, p2)); - // Advance two packets as we have already processed the packet at index i+1 in order to create the pair. - i += 2; - //i++; - } - } else { - // Last packet of conversation => one item pair - pairs.add(new PcapPacketPair(p1, null)); - // Advance i to ensure termination. - i++; - } - } - return pairs; - // TODO: what if there is long time between response and reply packet? Should we add a threshold and exclude those cases? - } - - /** - * Given a collection of TCP conversations and associated DNS mappings, groups the conversations by hostname. - * @param tcpConversations The collection of TCP conversations. - * @param ipHostnameMappings The associated DNS mappings. - * @return A map where each key is a hostname and its associated value is a list of conversations where one of the - * two communicating hosts is that hostname (i.e. its IP maps to the hostname). - */ - public static Map> groupConversationsByHostname(Collection tcpConversations, DnsMap ipHostnameMappings) { - HashMap> result = new HashMap<>(); - for (Conversation c : tcpConversations) { - if (c.getPackets().size() == 0) { - String warningStr = String.format("Detected a %s [%s] with no payload packets.", - c.getClass().getSimpleName(), c.toString()); - System.err.println(warningStr); - continue; - } - IpV4Packet firstPacketIp = c.getPackets().get(0).get(IpV4Packet.class); - String ipSrc = firstPacketIp.getHeader().getSrcAddr().getHostAddress(); - String ipDst = firstPacketIp.getHeader().getDstAddr().getHostAddress(); - // Check if src or dst IP is associated with one or more hostnames. - Set hostnames = ipHostnameMappings.getHostnamesForIp(ipSrc); - if (hostnames == null) { - // No luck with src ip (possibly because it's a client->srv packet), try dst ip. - hostnames = ipHostnameMappings.getHostnamesForIp(ipDst); - } - if (hostnames != null) { - // Put a reference to the conversation for each of the hostnames that the conversation's IP maps to. - for (String hostname : hostnames) { - List newValue = new ArrayList<>(); - newValue.add(c); - result.merge(hostname, newValue, (l1, l2) -> { l1.addAll(l2); return l1; }); - } - if (hostnames.size() > 1) { - // Print notice of IP mapping to multiple hostnames (debugging) - System.err.println(String.format("%s: encountered an IP that maps to multiple (%d) hostnames", - TcpConversationUtils.class.getSimpleName(), hostnames.size())); - } - } else { - // If no hostname mapping, store conversation under the key that is the concatenation of the two IPs. - // In order to ensure consistency when mapping conversations, use lexicographic order to select which IP - // goes first. - String delimiter = "_"; - // Note that the in case the comparison returns 0, the strings are equal, so it doesn't matter which of - // ipSrc and ipDst go first (also, this case should not occur in practice as it means that the device is - // communicating with itself!) - String key = ipSrc.compareTo(ipDst) <= 0 ? ipSrc + delimiter + ipDst : ipDst + delimiter + ipSrc; - List newValue = new ArrayList<>(); - newValue.add(c); - result.merge(key, newValue, (l1, l2) -> { l1.addAll(l2); return l1; }); - } - } - return result; - } - - public static Map countPacketSequenceFrequencies(Collection conversations) { - Map result = new HashMap<>(); - for (Conversation conv : conversations) { - if (conv.getPackets().size() == 0) { - // Skip conversations with no payload packets. - continue; - } - StringBuilder sb = new StringBuilder(); - for (PcapPacket pp : conv.getPackets()) { - sb.append(pp.length() + " "); - } - result.merge(sb.toString(), 1, (i1, i2) -> i1+i2); - } - return result; - } - - /** - * Given a {@link Collection} of {@link Conversation}s, builds a {@link Map} from {@link String} to {@link List} - * of {@link Conversation}s such that each key is the concatenation of the packet lengths of all payload packets - * (i.e., the set of packets returned by {@link Conversation#getPackets()}) separated by a delimiter of any - * {@link Conversation} pointed to by that key. In other words, what the {@link Conversation}s {@code cs} pointed to - * by the key {@code s} have in common is that they all contain exactly the same number of payload packets and - * these payload packets are identical across all {@code Conversation}s in {@code cs} in terms of packet - * length and packet order. For example, if the key is "152 440 550", this means that every individual - * {@code Conversation} in the list of {@code Conversation}s pointed to by that key contain exactly three payload - * packet of lengths 152, 440, and 550, and these three packets are ordered in the order prescribed by the key. - * - * @param conversations The collection of {@code Conversation}s to group by packet sequence. - * @param verbose If set to {@code true}, the grouping (and therefore the key) will also include SYN/SYNACK, - * FIN/FINACK, RST packets, and each payload-carrying packet will have an indication of the direction - * of the packet prepended. - * @return a {@link Map} from {@link String} to {@link List} of {@link Conversation}s such that each key is the - * concatenation of the packet lengths of all payload packets (i.e., the set of packets returned by - * {@link Conversation#getPackets()}) separated by a delimiter of any {@link Conversation} pointed to - * by that key. - */ - public static Map> groupConversationsByPacketSequence(Collection conversations, boolean verbose) { - return conversations.stream().collect(Collectors.groupingBy(c -> toSequenceString(c, verbose))); - } - - public static Map> groupConversationsByTlsApplicationDataPacketSequence(Collection conversations) { - return conversations.stream().collect(Collectors.groupingBy( - c -> c.getTlsApplicationDataPackets().stream().map(p -> Integer.toString(p.getOriginalLength())). - reduce("", (s1, s2) -> s1.length() == 0 ? s2 : s1 + " " + s2)) - ); - } - - /** - * Given a {@link Conversation}, counts the frequencies of each unique packet length seen as part of the - * {@code Conversation}. - * @param c The {@code Conversation} for which unique packet length frequencies are to be determined. - * @return A mapping from packet length to its frequency. - */ - public static Map countPacketLengthFrequencies(Conversation c) { - Map result = new HashMap<>(); - for (PcapPacket packet : c.getPackets()) { - result.merge(packet.length(), 1, (i1, i2) -> i1 + i2); - } - return result; - } - - /** - * Like {@link #countPacketLengthFrequencies(Conversation)}, but counts packet length frequencies for a collection - * of {@code Conversation}s, i.e., the frequency of a packet length becomes the total number of packets with that - * length across all {@code Conversation}s in {@code conversations}. - * @param conversations The collection of {@code Conversation}s for which packet length frequencies are to be - * counted. - * @return A mapping from packet length to its frequency. - */ - public static Map countPacketLengthFrequencies(Collection conversations) { - Map result = new HashMap<>(); - for (Conversation c : conversations) { - Map intermediateResult = countPacketLengthFrequencies(c); - for (Map.Entry entry : intermediateResult.entrySet()) { - result.merge(entry.getKey(), entry.getValue(), (i1, i2) -> i1 + i2); - } - } - return result; - } - - public static Map countPacketPairFrequencies(Collection pairs) { - Map result = new HashMap<>(); - for (PcapPacketPair ppp : pairs) { - result.merge(ppp.toString(), 1, (i1, i2) -> i1 + i2); - } - return result; - } - - public static Map> countPacketPairFrequenciesByHostname(Collection tcpConversations, DnsMap ipHostnameMappings) { - Map> convsByHostname = groupConversationsByHostname(tcpConversations, ipHostnameMappings); - HashMap> result = new HashMap<>(); - for (Map.Entry> entry : convsByHostname.entrySet()) { - // Merge all packet pairs exchanged during the course of all conversations with hostname into one list - List allPairsExchangedWithHostname = new ArrayList<>(); - entry.getValue().forEach(conversation -> allPairsExchangedWithHostname.addAll(extractPacketPairs(conversation))); - // Then count the frequencies of packet pairs exchanged with the hostname, irrespective of individual - // conversations - result.put(entry.getKey(), countPacketPairFrequencies(allPairsExchangedWithHostname)); - } - return result; - } - - /** - * Given a {@link Conversation}, extract its packet length sequence. - * @param c The {@link Conversation} from which a packet length sequence is to be extracted. - * @return An {@code Integer[]} that holds the packet lengths of all payload-carrying packets in {@code c}. The - * packet lengths in the returned array are ordered by packet timestamp. - */ - public static Integer[] getPacketLengthSequence(Conversation c) { - return getPacketLengthSequence(c.getPackets()); - } - - - /** - * Given a {@link Conversation}, extract its packet length sequence, but only include packet lengths of those - * packets that carry TLS Application Data. - * @param c The {@link Conversation} from which a TLS Application Data packet length sequence is to be extracted. - * @return An {@code Integer[]} that holds the packet lengths of all packets in {@code c} that carry TLS Application - * Data. The packet lengths in the returned array are ordered by packet timestamp. - */ - public static Integer[] getPacketLengthSequenceTlsAppDataOnly(Conversation c) { - if (!c.isTls()) { - throw new IllegalArgumentException("Provided " + c.getClass().getSimpleName() + " was not a TLS session"); - } - return getPacketLengthSequence(c.getTlsApplicationDataPackets()); - } - - /** - * Given a list of packets, extract the packet lengths and wrap them in an array such that the packet lengths in the - * resulting array appear in the same order as their corresponding packets in the input list. - * @param packets The list of packets for which the packet lengths are to be extracted. - * @return An array containing the packet lengths in the same order as their corresponding packets in the input list. - */ - private static Integer[] getPacketLengthSequence(List packets) { - return packets.stream().map(pkt -> pkt.getOriginalLength()).toArray(Integer[]::new); - } - - /** - * Builds a string representation of the sequence of packets exchanged as part of {@code c}. - * @param c The {@link Conversation} for which a string representation of the packet sequence is to be constructed. - * @param verbose {@code true} if set to true, the returned sequence string will also include SYN/SYNACK, - * FIN/FINACK, RST packets, as well as an indication of the direction of payload-carrying packets. - * @return a string representation of the sequence of packets exchanged as part of {@code c}. - */ - private static String toSequenceString(Conversation c, boolean verbose) { - // Payload-parrying packets are always included, but only prepend direction if verbose output is chosen. - Stream s = c.getPackets().stream().map(p -> verbose ? c.getDirection(p).toCompactString() + p.getOriginalLength() : Integer.toString(p.getOriginalLength())); - if (verbose) { - // In the verbose case, we also print SYN, FIN and RST packets. - // Convert the SYN packets to a string representation and prepend them in front of the payload packets. - s = Stream.concat(c.getSynPackets().stream().map(p -> isSyn(p) && isAck(p) ? "SYNACK" : "SYN"), s); - // Convert the FIN packets to a string representation and append them after the payload packets. - s = Stream.concat(s, c.getFinAckPairs().stream().map(f -> f.isAcknowledged() ? "FINACK" : "FIN")); - // Convert the RST packets to a string representation and append at the end. - s = Stream.concat(s, c.getRstPackets().stream().map(r -> "RST")); - } - /* - * Note: the collector internally uses a StringBuilder, which is more efficient than simply doing string - * concatenation as in the following example: - * s.reduce("", (s1, s2) -> s1.length() == 0 ? s2 : s1 + " " + s2); - * (above code is O(N^2) where N is the number of characters) - */ - return s.collect(Collectors.joining(" ")); - } - - /** - * Set of port numbers that we consider TLS traffic. - * Note: purposefully initialized as a {@link HashSet} to get O(1) {@code contains()} call. - */ - private static final Set TLS_PORTS = Stream.of(443, 8443, 41143). - collect(Collectors.toCollection(HashSet::new)); - - /** - * Check if a given port number is considered a TLS port. - * @param port The port number to check. - * @return {@code true} if the port number is considered a TLS port, {@code false} otherwise. - */ - public static boolean isTlsPort(int port) { - return TLS_PORTS.contains(port); - } - - /** - * Appends a space to {@code sb} iff {@code sb} already contains some content. - * @param sb A {@link StringBuilder} that should have a space appended iff it is not empty. - */ - private static void appendSpaceIfNotEmpty(StringBuilder sb) { - if (sb.length() != 0) { - sb.append(" "); - } - } - - /** - * Given a list of {@link Conversation} objects, sort them by timestamps. - * @param conversations The list of {@link Conversation} objects to be sorted. - * @return A sorted list of {@code Conversation} based on timestamps of the first - * packet in the {@code Conversation}. - */ - public static List sortConversationList(List conversations) { - // Get rid of Conversation objects with no packets. - conversations.removeIf(x -> x.getPackets().size() == 0); - // Sort the list based on the first packet's timestamp! - Collections.sort(conversations, (c1, c2) -> - c1.getPackets().get(0).getTimestamp().compareTo(c2.getPackets().get(0).getTimestamp())); - return conversations; - } - - /** - * Given a {@code List} of {@link Conversation} objects, find one that has the given {@code List} - * of {@code PcapPacket}. - * @param conversations The {@code List} of {@link Conversation} objects as reference. - * @param ppList The {@code List} of {@code PcapPacket} objects to search in the {@code List} of {@link Conversation}. - * @return A {@code Conversation} that contains the given {@code List} of {@code PcapPacket}. - */ - public static Conversation returnConversation(List ppList, List conversations) { - // TODO: This part of comparison takes into account that the list of conversations is not sorted - // TODO: We could optimize this to have a better performance by requiring a sorted-by-timestamp list - // TODO: as a parameter - // Find a Conversation that ppList is part of - for (Conversation c : conversations) { - // Figure out if c is the Conversation that ppList is in - if (isPartOfConversation(ppList, c)) { - return c; - } - } - // Return null if not found - return null; - } - - /** - * Given a {@link Conversation} objects, check if {@code List} of {@code PcapPacket} is part of it and return the - * adjacency label based on {@code SignaturePosition}. - * @param conversation The {@link Conversation} object as reference. - * @param ppListFirst The first {@code List} of {@code PcapPacket} objects in the {@link Conversation}. - * @param ppListSecond The second {@code List} of {@code PcapPacket} objects in the {@link Conversation} whose - * position will be observed in the {@link Conversation} with respect to ppListFirst. - * @return A {@code SignaturePosition} that represents the position of the signature against another signature - * in a {@link Conversation}. - */ - public static SignaturePosition isPartOfConversationAndAdjacent(List ppListFirst, - List ppListSecond, - Conversation conversation) { - // Take the first element in ppList and compare it - // The following elements in ppList are guaranteed to be in the same Conversation - // TODO: This part of comparison takes into account that the list of conversations is not sorted - // TODO: We could optimize this to have a better performance by requiring a sorted-by-timestamp list - // TODO: as a parameter - if (isPartOfConversation(ppListSecond, conversation)) { - // Compare the first element of ppListSecond with the last element of ppListFirst to know - // whether ppListSecond is RIGHT_ADJACENT relative to ppListFirst. - PcapPacket lastElOfFirstList = ppListFirst.get(ppListFirst.size() - 1); - PcapPacket firstElOfSecondList = ppListSecond.get(0); - // If the positions of the two are in order, then they are adjacent. - int indexOfLastElOfFirstList = returnIndexInConversation(lastElOfFirstList, conversation); - int indexOfFirstElOfSecondList = returnIndexInConversation(firstElOfSecondList, conversation); - if(indexOfLastElOfFirstList + 1 == indexOfFirstElOfSecondList) { - return SignaturePosition.RIGHT_ADJACENT; - } - // NOT RIGHT_ADJACENT, so check for LEFT_ADJACENT. - // Compare the first element of ppListRight with the last element of ppListSecond to know - // whether ppListSecond is LEFT_ADJACENT relative to ppListFirst. - PcapPacket firstElOfFirstList = ppListFirst.get(0); - PcapPacket lastElOfSecondList = ppListSecond.get(ppListSecond.size() - 1); - // If the positions of the two are in order, then they are adjacent. - int indexOfFirstElOfFirstList = returnIndexInConversation(firstElOfFirstList, conversation); - int indexOfLastElOfSecondList = returnIndexInConversation(lastElOfSecondList, conversation); - if(indexOfLastElOfSecondList + 1 == indexOfFirstElOfFirstList) { - return SignaturePosition.LEFT_ADJACENT; - } - } - // Return NOT_ADJACENT if not found. - return SignaturePosition.NOT_ADJACENT; - } - - /** - * Given a {@link Conversation} objects, check if {@code List} of {@code PcapPacket} is part of it. - * @param conversation The {@link Conversation} object as reference. - * @param ppList The {@code List} of {@code PcapPacket} objects to search in the {@link Conversation}. - * @return A {@code Boolean} value that represents the presence of the {@code List} of {@code PcapPacket} in - * the {@link Conversation}. - */ - private static boolean isPartOfConversation(List ppList, Conversation conversation) { - // Find the first element of ppList in conversation. - if (conversation.getPackets().contains(ppList.get(0))) - return true; - // Return false if not found. - return false; - } - - /** - * Given a {@link Conversation} objects, check the index of a {@code PcapPacket} in it. - * @param conversation The {@link Conversation} object as reference. - * @param pp The {@code PcapPacket} object to search in the {@link Conversation}. - * @return An {@code Integer} value that gives the index of the {@code PcapPacket} in the {@link Conversation}. - */ - private static int returnIndexInConversation(PcapPacket pp, Conversation conversation) { - // Find pp in conversation. - if (conversation.getPackets().contains(pp)) - return conversation.getPackets().indexOf(pp); - // Return -1 if not found. - return -1; - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TrafficLabeler.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TrafficLabeler.java deleted file mode 100644 index 983de12..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TrafficLabeler.java +++ /dev/null @@ -1,146 +0,0 @@ -package edu.uci.iotproject.analysis; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.DnsMap; -import edu.uci.iotproject.trafficreassembly.layer3.TcpReassembler; -import org.pcap4j.core.PacketListener; -import org.pcap4j.core.PcapPacket; - -import java.time.Instant; -import java.util.*; -import java.util.function.Function; - -/** - * A {@link PacketListener} that marks network traffic as (potentially) related to a user's actions by comparing the - * timestamp of each packet to the timestamps of the provided list of user actions. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class TrafficLabeler implements PacketListener { - - private final Map> mActionToTrafficMap; - private final List mActionsSorted; - /** - * The total number of packets labeled, i.e, the sum of the sizes of the values in {@link #mActionToTrafficMap}. - */ - private long mPackets = 0; - - public TrafficLabeler(List userActions) { - // Init map with empty lists (no packets have been mapped to UserActions at the onset). - mActionToTrafficMap = new HashMap<>(); - userActions.forEach(ua -> mActionToTrafficMap.put(ua, new ArrayList<>())); - // Sort list of UserActions by timestamp in order to facilitate fast Packet-to-UserAction mapping. - // For safety reasons, we create an internal copy of the list to prevent external code from changing the list's - // contents as that would render our assumptions about order of elements invalid. - // In addition, this also ensures that we do not break assumptions made by external code as we avoid reordering - // the elements of the list passed from the external code. - // If performance is to be favored over safety, assign userActions to mActionsSorted directly. - mActionsSorted = new ArrayList<>(); - mActionsSorted.addAll(userActions); - Collections.sort(mActionsSorted, (ua1, ua2) -> ua1.getTimestamp().compareTo(ua2.getTimestamp())); - } - - - @Override - public void gotPacket(PcapPacket packet) { - // Locate UserAction corresponding to packet, if any. - int index = Collections.binarySearch(mActionsSorted, new UserAction(null, packet.getTimestamp()), (listItem, key) -> { - // Start of inclusion interval is the time of the user action - Instant intervalStart = listItem.getTimestamp(); - // End of inclusion interval is some arbitrary number of milliseconds after the user action. - Instant intervalEnd = intervalStart.plusMillis(TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS); - if (key.getTimestamp().isAfter(intervalStart) && key.getTimestamp().isBefore(intervalEnd)) { - // Packet lies within specified interval after the current UserAction, so we're done. - // Communicate termination to binarySearch by returning 0 which indicates equality. - return 0; - } - // If packet lies outside inclusion interval of current list item, continue search in lower or upper half of - // list depending on whether the timestamp of the current list item is smaller or greater than that of the - // packet. - return listItem.getTimestamp().compareTo(key.getTimestamp()); - }); - if (index >= 0) { - // Associate the packet to the its corresponding user action (located during the binary search above). - mActionToTrafficMap.get(mActionsSorted.get(index)).add(packet); - mPackets++; - } - // Ignore packet if it is not found to be in temporal proximity of a user action. - } - - /** - * Get the total number of packets labeled by this {@code TrafficLabeler}. - * - * @return the total number of packets labeled by this {@code TrafficLabeler}. - */ - public long getTotalPacketCount() { - return mPackets; - } - - /** - * Get the labeled traffic. - * - * @return A {@link Map} in which a {@link UserAction} points to a {@link List} of {@link PcapPacket}s believed to - * be related (occurring as a result of) that {@code UserAction}. - */ - public Map> getLabeledTraffic() { - return Collections.unmodifiableMap(mActionToTrafficMap); - } - - /** - * Like {@link #getLabeledTraffic()}, but allows the caller to supply a mapping function that is applied to - * the traffic associated with each {@link UserAction} (the traffic label) before returning the labeled traffic. - * This may for example be useful for a caller who wishes to perform some postprocessing of labeled traffic, e.g., - * in order to perform additional filtering or to transform the representation of labeled traffic. - *

- * An example usecase is provided in {@link #getLabeledReassembledTcpTraffic()} which uses this function to - * build a {@link Map} in which a {@link UserAction} points to the reassembled TCP connections believed to have - * occurred as a result of that {@code UserAction}. - *

- * - * @param mappingFunction A mapping function that converts a {@link List} of {@link PcapPacket} into some other type - * {@code T}. - * @param The return type of {@code mappingFunction}. - * @return A {@link Map} in which a {@link UserAction} points to the result of applying {@code mappingFunction} to - * the set of packets believed to be related (occurring as a result of) that {@code UserAction}. - */ - public Map getLabeledTraffic(Function, T> mappingFunction) { - Map result = new HashMap<>(); - mActionToTrafficMap.forEach((ua, packets) -> result.put(ua, mappingFunction.apply(packets))); - return result; - } - - - /** - * Get the labeled traffic reassembled as TCP connections (note: discards all non-TCP traffic). - * - * @return A {@link Map} in which a {@link UserAction} points to a {@link List} of {@link Conversation}s believed to - * be related (occurring as a result of) that {@code UserAction}. - */ - public Map> getLabeledReassembledTcpTraffic() { - return getLabeledTraffic(packets -> { - TcpReassembler tcpReassembler = new TcpReassembler(); - packets.forEach(p -> tcpReassembler.gotPacket(p)); - return tcpReassembler.getTcpConversations(); - }); - } - - /** - * Like {@link #getLabeledReassembledTcpTraffic()}, but uses the provided {@code ipHostnameMappings} to group - * {@link Conversation}s by hostname. - * - * @param ipHostnameMappings A {@link DnsMap} with IP to hostname mappings used for reverse DNS lookup. - * @return A {@link Map} in which a {@link UserAction} points to the set of {@link Conversation}s believed to be - * related (occurring as a result of) that {@code UserAction}. More precisely, each {@code UserAction} in - * the returned {@code Map} points to another {@code Map} in which a hostname points to the set of - * {@code Conversation}s involving that hostname. - */ - public Map>> getLabeledReassembledTcpTraffic(DnsMap ipHostnameMappings) { - return getLabeledTraffic(packets -> { - TcpReassembler tcpReassembler = new TcpReassembler(); - packets.forEach(p -> tcpReassembler.gotPacket(p)); - return TcpConversationUtils.groupConversationsByHostname(tcpReassembler.getTcpConversations(), ipHostnameMappings); - }); - } - -} \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TriggerTrafficExtractor.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TriggerTrafficExtractor.java deleted file mode 100644 index 0a22d63..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/TriggerTrafficExtractor.java +++ /dev/null @@ -1,114 +0,0 @@ -package edu.uci.iotproject.analysis; - -import edu.uci.iotproject.io.PcapHandleReader; -import org.pcap4j.core.*; - -import java.time.Instant; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * TODO add class documentation. - * - * @author Janus Varmarken - */ -public class TriggerTrafficExtractor implements PcapPacketFilter { - - private final String mPcapFilePath; - private final List mTriggerTimes; - private final String mDeviceIp; - - private int mTriggerIndex = 0; - - /** - * The total number of packets marked for inclusion during one run of {@link #performExtraction(PacketListener...)}. - */ - private long mIncludedPackets = 0; - - public static final int INCLUSION_WINDOW_MILLIS = 15_000; - - public TriggerTrafficExtractor(String pcapFilePath, List triggerTimes, String deviceIp) throws PcapNativeException, NotOpenException { - mPcapFilePath = pcapFilePath; - // Ensure that trigger times are sorted in ascending as we rely on this fact in the logic that works out if a - // packet is related to a trigger. - Collections.sort(triggerTimes, (i1, i2) -> { - if (i1.isBefore(i2)) return -1; - else if (i2.isBefore(i1)) return 1; - else return 0; - }); - mTriggerTimes = Collections.unmodifiableList(triggerTimes); - mDeviceIp = deviceIp; - } - - - public void performExtraction(PacketListener... extractedPacketsConsumers) throws PcapNativeException, NotOpenException, TimeoutException { - // Reset trigger index and packet counter in case client code chooses to rerun the extraction. - mTriggerIndex = 0; - mIncludedPackets = 0; - PcapHandle handle; - try { - handle = Pcaps.openOffline(mPcapFilePath, PcapHandle.TimestampPrecision.NANO); - } catch (PcapNativeException pne) { - handle = Pcaps.openOffline(mPcapFilePath); - } - // Use the native support for BPF to immediately filter irrelevant traffic. - handle.setFilter("ip host " + mDeviceIp, BpfProgram.BpfCompileMode.OPTIMIZE); - PcapHandleReader pcapReader = new PcapHandleReader(handle, this, extractedPacketsConsumers); - pcapReader.readFromHandle(); - - } - - /** - * Return the number of extracted packets (i.e., packets selected for inclusion) as a result of the most recent call - * to {@link #performExtraction(PacketListener...)}. - * - * @return the number of extracted packets (i.e., packets selected for inclusion) as a result of the most recent - * call to {@link #performExtraction(PacketListener...)}. - */ - public long getPacketsIncludedCount() { - return mIncludedPackets; - } - - @Override - public boolean shouldIncludePacket(PcapPacket packet) { - // New version. Simpler, but slower: the later a packet arrives, the more elements of mTriggerTimes will need to - // be traversed. - boolean include = mTriggerTimes.stream().anyMatch( - trigger -> trigger.isBefore(packet.getTimestamp()) && - packet.getTimestamp().isBefore(trigger.plusMillis(INCLUSION_WINDOW_MILLIS)) - ); - if (include) { - mIncludedPackets++; - } - return include; - - /* - // Old version. Faster, but more complex - is it correct? - if (mTriggerIndex >= mTriggerTimes.size()) { - // Don't include packet if we've exhausted the list of trigger times. - return false; - } - - // TODO hmm, is this correct? - Instant trigger = mTriggerTimes.get(mTriggerIndex); - if (trigger.isBefore(packet.getTimestamp()) && - packet.getTimestamp().isBefore(trigger.plusMillis(INCLUSION_WINDOW_MILLIS))) { - // Packet lies within INCLUSION_WINDOW_MILLIS after currently considered trigger, include it. - return true; - } else { - if (!trigger.isBefore(packet.getTimestamp())) { - // Packet is before currently considered trigger, so it shouldn't be included - return false; - } else { - // Packet is >= INCLUSION_WINDOW_MILLIS after currently considered trigger. - // Proceed to next trigger to see if it lies in range of that. - // Note that there's an assumption here that no two trigger intervals don't overlap! - mTriggerIndex++; - return shouldIncludePacket(packet); - } - } - */ - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/UserAction.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/UserAction.java deleted file mode 100644 index 408d66a..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/analysis/UserAction.java +++ /dev/null @@ -1,108 +0,0 @@ -package edu.uci.iotproject.analysis; - -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; - -/** - * Models a user's action, such as toggling the smart plug on/off at a given time. - * - * @author Janus Varmarken - */ -public class UserAction { - - private static volatile DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ISO_ZONED_DATE_TIME. - withZone(ZoneId.of("America/Los_Angeles")); - - /** - * Sets the {@link DateTimeFormatter} used when outputting a user action as a string and parsing a user action from - * a string. - * @param formatter The formatter to use for outputting and parsing. - */ - public static void setTimestampFormatter(DateTimeFormatter formatter) { - TIMESTAMP_FORMATTER = formatter; - } - - /** - * Instantiates a {@code UserAction} from a string that obeys the format used in {@link UserAction#toString()}. - * @param string The string that represents a {@code UserAction} - * @return A {@code UserAction} resulting from deserializing the string. - */ - public static UserAction fromString(String string) { - String[] parts = string.split("@"); - if (parts.length != 2) { - throw new IllegalArgumentException("Invalid string format"); - } - // If any of these two parses fail, an exception is thrown -- no need to check return values. - UserAction.Type actionType = UserAction.Type.valueOf(parts[0].trim()); - Instant timestamp = TIMESTAMP_FORMATTER.parse(parts[1].trim(), Instant::from); - return new UserAction(actionType, timestamp); - } - - - /** - * The specific type of action the user performed. - */ - private final Type mType; - - /** - * The time the action took place. - */ - private final Instant mTimestamp; - - public UserAction(Type typeOfAction, Instant timeOfAction) { - mType = typeOfAction; - mTimestamp = timeOfAction; - } - - /** - * Get the specific type of action performed by the user. - * @return the specific type of action performed by the user. - */ - public Type getType() { - return mType; - } - - /** - * Get the time at which the user performed this action. - * @return the time at which the user performed this action. - */ - public Instant getTimestamp() { - return mTimestamp; - } - - /** - * Enum for indicating what type of action the user performed. - */ - public enum Type { - TOGGLE_ON, TOGGLE_OFF - } - - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof UserAction) { - UserAction that = (UserAction) obj; - return this.mType == that.mType && this.mTimestamp.equals(that.mTimestamp); - } else { - return false; - } - } - - @Override - public int hashCode() { - final int prime = 31; - int hashCode = 17; - hashCode = prime * hashCode + mType.hashCode(); - hashCode = prime * hashCode + mTimestamp.hashCode(); - return hashCode; - } - - @Override - public String toString() { - return String.format("%s @ %s", mType.name(), TIMESTAMP_FORMATTER.format(mTimestamp)); - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/AbstractPatternComparisonResult.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/AbstractPatternComparisonResult.java deleted file mode 100644 index cadadbe..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/AbstractPatternComparisonResult.java +++ /dev/null @@ -1,49 +0,0 @@ -package edu.uci.iotproject.comparison; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.FlowPattern; - -/** - * Models the result of comparing a {@link Conversation} and a {@link FlowPattern}. - * - * @param The type of the result; can be something as simple as a {@code Boolean} for a complete match comparison or - * or a complex data type for more sophisticated comparisons. - */ -public abstract class AbstractPatternComparisonResult { - - /** - * The result of the comparison. - */ - private final T mResult; - - /** - * The {@code Conversation} that was compared against {@link #mFlowPattern}. - */ - protected final Conversation mConversation; - - /** - * The {@code FlowPattern} that {@link #mConversation} was compared against. - */ - protected final FlowPattern mFlowPattern; - - public AbstractPatternComparisonResult(Conversation conversation, FlowPattern flowPattern, T result) { - this.mResult = result; - this.mConversation = conversation; - this.mFlowPattern = flowPattern; - } - - /** - * Gets the result of the comparison. - * @return the result of the comparison - */ - public T getResult() { - return mResult; - } - - /** - * Get a textual description of the comparison result suitable for output on std.out. - * @return a textual description of the comparison result suitable for output on std.out. - */ - abstract public String getTextualDescription(); - -} \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/ComparisonFunctions.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/ComparisonFunctions.java deleted file mode 100644 index 960d6a7..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/ComparisonFunctions.java +++ /dev/null @@ -1,77 +0,0 @@ -package edu.uci.iotproject.comparison; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.FlowPattern; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.TcpPacket; - -import java.util.List; -import java.util.function.BiFunction; - -/** - * Contains concrete implementations of comparison functions that compare a {@link Conversation} and a {@link FlowPattern}. - * These functions are supplied to {@link PatternComparisonTask} which in turn facilitates comparison on a background thread. - * This design provides plugability: currently, we only support complete match comparison, but further down the road we - * can simply introduce more sophisticated comparison functions here (e.g. Least Common Substring) simply replace the - * argument passed to the {@link PatternComparisonTask} constructor to switch between the different implementations. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class ComparisonFunctions { - - /** - * Comparison function that checks for a complete match, i.e. a match in which every packet in the - * {@link Conversation} has the same length as the corresponding packet in the {@link FlowPattern}. - */ - public static final BiFunction COMPLETE_MATCH = (conversation, flowPattern) -> { - List convPackets = conversation.getPackets(); - if (convPackets.size() != flowPattern.getLength()) { - return new CompleteMatchPatternComparisonResult(conversation, flowPattern, false); - } - for (int i = 0; i < convPackets.size(); i++) { - TcpPacket tcpPacket = convPackets.get(i).get(TcpPacket.class); - if (tcpPacket.getPayload().length() != flowPattern.getPacketOrder().get(i)) { - return new CompleteMatchPatternComparisonResult(conversation, flowPattern, false); - } - } - return new CompleteMatchPatternComparisonResult(conversation, flowPattern, true); - }; - - /** - * Comparison function that searches a {@link Conversation} looking for the presence of a complete match of a {@link FlowPattern}. - * Unlike {@link #COMPLETE_MATCH}, which searches for a 1:1 match between the {@code Conversation} and the {@code FlowPattern}, - * this function targets cases where the {@code Conversation} is longer than the {@code FlowPattern}. - * In other words, this function searches for a complete match of a sub sequence of packets in the {@code Conversation}. - * Note: this is a slow, brute force search. - */ - public static final BiFunction SUB_SEQUENCE_COMPLETE_MATCH = new BiFunction() { - // TODO needs review; I was tired when I wrote this :). - private boolean find(Conversation conversation, FlowPattern flowPattern, int nextIndex, int matchedIndices) { - if (matchedIndices == flowPattern.getLength()) { - // Found a full sub sequence. - return true; - } - List convPackets = conversation.getPackets(); - if (nextIndex >= convPackets.size()) { - // Reached end of list without finding a match. - return false; - } - if (convPackets.get(nextIndex).get(TcpPacket.class).getPayload().length() == flowPattern.getPacketOrder().get(matchedIndices)) { - // So far, so good. Still need to check if the remainder of the sub sequence is present. - return find(conversation, flowPattern, ++nextIndex, ++matchedIndices); - } else { - // Miss; trace back and retry the search starting at the index immediately after the index from the - // recursive calls potentially started matching some of the sub sequence. - return find(conversation, flowPattern, nextIndex-matchedIndices+1, 0); - } - } - - @Override - public CompleteMatchPatternComparisonResult apply(Conversation conversation, FlowPattern flowPattern) { - return new CompleteMatchPatternComparisonResult(conversation, flowPattern, find(conversation, flowPattern, 0, 0)); - } - - }; - -} \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/CompleteMatchPatternComparisonResult.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/CompleteMatchPatternComparisonResult.java deleted file mode 100644 index 960a0d0..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/CompleteMatchPatternComparisonResult.java +++ /dev/null @@ -1,30 +0,0 @@ -package edu.uci.iotproject.comparison; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.FlowPattern; - -/** - * The result of a search for a complete match. Serves as an example implementation of - * {@link AbstractPatternComparisonResult}. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class CompleteMatchPatternComparisonResult extends AbstractPatternComparisonResult { - - public CompleteMatchPatternComparisonResult(Conversation conversation, FlowPattern flowPattern, Boolean result) { - super(conversation, flowPattern, result); - } - - @Override - public String getTextualDescription() { - if (getResult()) { - return String.format("[ find ] Detected a COMPLETE MATCH of pattern '%s' at %s!", - mFlowPattern.getPatternId(), mConversation.getPackets().get(0).getTimestamp().toString()); - } else { - return String.format("[ miss ] flow starting at %s was **not** a complete match of pattern '%s'", - mConversation.getPackets().get(0).getTimestamp().toString(), mFlowPattern.getPatternId()); - } - } - -} \ No newline at end of file diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/PatternComparisonTask.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/PatternComparisonTask.java deleted file mode 100644 index 5a888b7..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/PatternComparisonTask.java +++ /dev/null @@ -1,40 +0,0 @@ -package edu.uci.iotproject.comparison; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.FlowPattern; - -import java.util.concurrent.Callable; -import java.util.function.BiFunction; - -/** - * A task that compares a given {@link Conversation} and {@link FlowPattern} using a provided comparison function. - * The task implements {@link Callable} and can hence be executed on a background thread. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class PatternComparisonTask> implements Callable { - - private final Conversation mConversation; - private final FlowPattern mFlowPattern; - private final BiFunction mComparator; - - /** - * Create a new {@code PatternComparisonTask}. - * - * @param conversation The conversation to compare against {@code pattern}. - * @param pattern The pattern to compare against {@code conversation}. - * @param comparisonFunction The function that compares {@code pattern} and {@code conversation}. - */ - public PatternComparisonTask(Conversation conversation, FlowPattern pattern, BiFunction comparisonFunction) { - this.mConversation = conversation; - this.mFlowPattern = pattern; - this.mComparator = comparisonFunction; - } - - @Override - public R call() throws Exception { - return mComparator.apply(mConversation, mFlowPattern); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/AlignmentPricer.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/AlignmentPricer.java deleted file mode 100644 index 0552279..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/AlignmentPricer.java +++ /dev/null @@ -1,70 +0,0 @@ -package edu.uci.iotproject.comparison.seqalignment; - -import java.util.function.ToIntBiFunction; -import java.util.function.ToIntFunction; - -/** - * Provides a generic implementation for the calculation of the cost of aligning two elements of a sequence as part of - * the sequence alignment algorithm (the algorithm is implemented in {@link SequenceAlignment}). - * - * @param The type of the elements that are being aligned. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class AlignmentPricer { - - /** - * A function that provides the cost of aligning a {@link T} with a gap. - */ - private final ToIntFunction mGapCostFunction; - - /** - * A function that provides the cost of aligning a {@link T} with some other {@link T}. - */ - private final ToIntBiFunction mAlignmentCostFunction; - - /** - * Constructs a new {@link AlignmentPricer}. - * - * @param alignmentCostFunction A function that specifies the cost of aligning a {@link T} with some other {@link T} - * (e.g., based on the values of the properties of the two instances). - * @param gapCostFunction A function that specifies the cost of aligning a {@link T} with a gap. Note that the - * function is free to specify different gap costs for different {@link T}s. - */ - public AlignmentPricer(ToIntBiFunction alignmentCostFunction, ToIntFunction gapCostFunction) { - mAlignmentCostFunction = alignmentCostFunction; - mGapCostFunction = gapCostFunction; - } - - /** - * Calculate the cost of aligning {@code item1} with {@code item2}. If either of the two arguments is set to - * {@code null}, the cost of aligning the other argument with a gap will be returned. Note that both arguments - * cannot be {@code null} at the same time as that translates to aligning a gap with a gap, which is pointless. - * - * @param item1 The first of the two aligned objects. Set to {@code null} to calculate the cost of aligning - * {@code item2} with a gap. - * @param item2 The second of the two aligned objects. Set to {@code null} to calculate the cost of aligning - * {@code item2} with a gap. - * @return The cost of aligning {@code item1} with {@code item2}. - */ - public int alignmentCost(T item1, T item2) { - // If both arguments are null, the caller is aligning a gap with a gap which is pointless might as well remove - // both gaps in that case!) - if (item1 == null && item2 == null) { - throw new IllegalArgumentException("Both arguments cannot be null: you are aligning a gap with a gap!"); - } - // If one item is null, it means we're aligning an int with a gap. - // Invoke the provided gap cost function to get the gap cost. - if (item1 == null) { - return mGapCostFunction.applyAsInt(item2); - } - if (item2 == null) { - return mGapCostFunction.applyAsInt(item1); - } - // If both arguments are present, we simply delegate the task of calculating the cost of aligning the two items - // to the provided alignment cost function. - return mAlignmentCostFunction.applyAsInt(item1, item2); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/ExtractedSequence.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/ExtractedSequence.java deleted file mode 100644 index 2d193a9..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/ExtractedSequence.java +++ /dev/null @@ -1,41 +0,0 @@ -package edu.uci.iotproject.comparison.seqalignment; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import org.pcap4j.core.PcapPacket; - -import java.util.List; - -/** - * TODO add class documentation. - * - * @author Janus Varmarken - */ -public class ExtractedSequence { - - private final Conversation mRepresentativeSequence; - - private final int mMaxAlignmentCost; - - private final String mSequenceString; - - public ExtractedSequence(Conversation sequence, int maxAlignmentCost, boolean tlsAppDataAlignment) { - mRepresentativeSequence = sequence; - mMaxAlignmentCost = maxAlignmentCost; - StringBuilder sb = new StringBuilder(); - List pkts = tlsAppDataAlignment ? sequence.getTlsApplicationDataPackets() : sequence.getPackets(); - pkts.forEach(p -> { - if (sb.length() != 0) sb.append(" "); - sb.append(p.getOriginalLength()); - }); - mSequenceString = sb.toString(); - } - - public Conversation getRepresentativeSequence() { - return mRepresentativeSequence; - } - - public int getMaxAlignmentCost() { - return mMaxAlignmentCost; - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SampleIntegerAlignmentPricer.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SampleIntegerAlignmentPricer.java deleted file mode 100644 index a09a10d..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SampleIntegerAlignmentPricer.java +++ /dev/null @@ -1,23 +0,0 @@ -package edu.uci.iotproject.comparison.seqalignment; - -/** - * A sample {@link AlignmentPricer} for computing the cost of aligning integer values. In this sample implementation, - * the cost of aligning two integers {@code i1} and {@code i2} is {@code Math.abs(i1 - i2)}, i.e., it is the absolute - * value of the difference between {@code i1} and {@code i2}. The cost of aligning an integer {@code i} with a gap is - * simply {@code i}, i.e., the gap is essentially treated as a zero. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class SampleIntegerAlignmentPricer extends AlignmentPricer { - - /** - * Constructs a new {@link SampleIntegerAlignmentPricer}. - */ - public SampleIntegerAlignmentPricer() { - // Cost of aligning integers i1 and i2 is the absolute value of their difference. - // Cost of aligning integer i with a gap is i (as it was aligned with 0). - super((i1,i2) -> Math.abs(i1 - i2) , (i) -> i); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SequenceAlignment.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SequenceAlignment.java deleted file mode 100644 index 005d7ff..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SequenceAlignment.java +++ /dev/null @@ -1,75 +0,0 @@ -package edu.uci.iotproject.comparison.seqalignment; - -/** - * A generic implementation of the sequence alignment algorithm given in Kleinberg's and Tardos' "Algorithm Design". - * This implementation is the basic version. There is a more complex version which significantly reduces the space - * complexity at a slight cost to time complexity. - * - * @param The unit of the alignment, or, in other words, the granularity of the - * alignment. For example, for 'classical' string alignment (as in sequence alignment where we - * try to align two strings character by character -- the example most often used in books on - * algorithms) this would be a {@link Character}. As a second example, by specifying - * {@link String}, one can decrease the granularity so as to align blocks of characters - * (e.g., if one wants to align to two string arrays). - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class SequenceAlignment { - - - /** - * Provides the cost of aligning two {@link ALIGNMENT_UNIT}s with one another as well as the cost of aligning an - * {@link ALIGNMENT_UNIT} with a gap. - */ - private final AlignmentPricer mAlignmentPricer; - - /** - * Constructs a new {@link SequenceAlignment}. The new instance relies on the provided {@code alignmentPricer} to - * provide the cost of aligning two {@link ALIGNMENT_UNIT}s as well as the cost of aligning an - * {@link ALIGNMENT_UNIT} with a gap. - * - * @param alignmentPricer An {@link AlignmentPricer} that provides the cost of aligning two {@link ALIGNMENT_UNIT}s - * with one another as well as the cost of aligning an {@link ALIGNMENT_UNIT} with a gap. - */ - public SequenceAlignment(AlignmentPricer alignmentPricer) { - mAlignmentPricer = alignmentPricer; - } - - - /** - * Calculates the cost of aligning {@code sequence1} with {@code sequence2}. - * - * @param sequence1 A sequence that is to be aligned with {@code sequence2}. - * @param sequence2 A sequence that is to be aligned with {@code sequence1}. - * - * @return The cost of aligning {@code sequence1} with {@code sequence2}. - */ - public int calculateAlignment(ALIGNMENT_UNIT[] sequence1, ALIGNMENT_UNIT[] sequence2) { - int[][] costs = new int[sequence1.length + 1][sequence2.length +1]; - /* - * TODO: - * This is a homebrewn initialization; it is different from the one in the Kleinberg book - is it correct? - * It tries to add support for *different* gap costs depending on the input (e.g., such that one can say that - * matching a 'c' with a gap is more expensive than matching a 'b' with a gap). - */ - for (int i = 1; i <= sequence1.length; i++) { - costs[i][0] = mAlignmentPricer.alignmentCost(sequence1[i-1], null) + costs[i-1][0]; - } - for (int j = 1; j <= sequence2.length; j++) { - costs[0][j] = mAlignmentPricer.alignmentCost(sequence2[j-1], null) + costs[0][j-1]; - } - for (int j = 1; j <= sequence2.length; j++) { - for (int i = 1; i <= sequence1.length; i++) { - // The cost when current items of both sequences are aligned. - int costAligned = mAlignmentPricer.alignmentCost(sequence2[j-1], sequence1[i-1]) + costs[i-1][j-1]; - // The cost when current item from sequence1 is not aligned (it's matched with a gap) - int seq1ItemNotMached = mAlignmentPricer.alignmentCost(sequence1[i-1], null) + costs[i-1][j]; - // The cost when current item from sequence2 is not aligned (it's matched with a gap) - int seq2ItemNotMached = mAlignmentPricer.alignmentCost(sequence2[j-1], null) + costs[i][j-1]; - costs[i][j] = Math.min(costAligned, Math.min(seq1ItemNotMached, seq2ItemNotMached)); - } - } - return costs[sequence1.length][sequence2.length]; - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SequenceExtraction.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SequenceExtraction.java deleted file mode 100644 index 6aaa318..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/comparison/seqalignment/SequenceExtraction.java +++ /dev/null @@ -1,152 +0,0 @@ -package edu.uci.iotproject.comparison.seqalignment; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.analysis.TcpConversationUtils; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * TODO add class documentation. - * - * @author Janus Varmarken - */ -public class SequenceExtraction { - - - private final SequenceAlignment mAlignmentAlg; - - - public SequenceExtraction() { - mAlignmentAlg = new SequenceAlignment<>(new AlignmentPricer<>((i1,i2) -> Math.abs(i1-i2), i -> 10)); - } - - - public SequenceExtraction(SequenceAlignment alignmentAlgorithm) { - mAlignmentAlg = alignmentAlgorithm; - } - - /** - * Gets the {@link SequenceAlignment} used to perform the sequence extraction. - * @return the {@link SequenceAlignment} used to perform the sequence extraction. - */ - public SequenceAlignment getAlignmentAlgorithm() { - return mAlignmentAlg; - } - - // Initial -// /** -// * -// * @param convsForAction A set of {@link Conversation}s known to be associated with a single type of user action. -// */ -// public void extract(List convsForAction) { -// int maxDifference = 0; -// -// for (int i = 0; i < convsForAction.size(); i++) { -// for (int j = i+1; j < convsForAction.size(); i++) { -// Integer[] sequence1 = getPacketLengthSequence(convsForAction.get(i)); -// Integer[] sequence2 = getPacketLengthSequence(convsForAction.get(j)); -// int alignmentCost = mAlignmentAlg.calculateAlignment(sequence1, sequence2); -// if (alignmentCost > maxDifference) { -// maxDifference = alignmentCost; -// } -// } -// } -// -// } - - -// public void extract(Map> hostnameToConvs) { -// int maxDifference = 0; -// -// for (int i = 0; i < convsForAction.size(); i++) { -// for (int j = i+1; j < convsForAction.size(); i++) { -// Integer[] sequence1 = getPacketLengthSequence(convsForAction.get(i)); -// Integer[] sequence2 = getPacketLengthSequence(convsForAction.get(j)); -// int alignmentCost = mAlignmentAlg.calculateAlignment(sequence1, sequence2); -// if (alignmentCost > maxDifference) { -// maxDifference = alignmentCost; -// } -// } -// } -// -// } - - // Building signature from entire sequence - public ExtractedSequence extract(List convsForActionForHostname) { - // First group conversations by packet sequences. - // TODO: the introduction of SYN/SYNACK, FIN/FINACK and RST as part of the sequence ID may be undesirable here - // as it can potentially result in sequences that are equal in terms of payload packets to be considered - // different due to differences in how they are terminated. - Map> groupedBySequence = - TcpConversationUtils.groupConversationsByPacketSequence(convsForActionForHostname, false); - - // Then get a hold of one of the conversations that gave rise to the most frequent sequence. - Conversation mostFrequentConv = null; - int maxFrequency = 0; - for (Map.Entry> seqMapEntry : groupedBySequence.entrySet()) { - if (seqMapEntry.getValue().size() > maxFrequency) { - // Found a more frequent sequence - maxFrequency = seqMapEntry.getValue().size(); - // We just pick the first conversation as the representative conversation for this sequence type. - mostFrequentConv = seqMapEntry.getValue().get(0); - } else if (seqMapEntry.getValue().size() == maxFrequency) { - // This sequence has the same frequency as the max frequency seen so far. - // Break ties by choosing the longest sequence. - // First get an arbitrary representative of currently examined sequence; we just pick the first. - Conversation c = seqMapEntry.getValue().get(0); - mostFrequentConv = c.getPackets().size() > mostFrequentConv.getPackets().size() ? c : mostFrequentConv; - } - } - // Now find the maximum cost of aligning the most frequent (or, alternatively longest) conversation with the - // each of the rest of the conversations also associated with this action and hostname. - int maxCost = 0; - final Integer[] mostFrequentConvSeq = TcpConversationUtils.getPacketLengthSequence(mostFrequentConv); - for (Conversation c : convsForActionForHostname) { - if (c == mostFrequentConv) { - // Don't compute distance to self. - continue; - } - Integer[] cSeq = TcpConversationUtils.getPacketLengthSequence(c); - int alignmentCost = mAlignmentAlg.calculateAlignment(mostFrequentConvSeq, cSeq); - if (alignmentCost > maxCost) { - maxCost = alignmentCost; - } - } - return new ExtractedSequence(mostFrequentConv, maxCost, false); - } - - // Building signature from only TLS Application Data packets - public ExtractedSequence extractByTlsAppData(List convsForActionForHostname) { - // TODO: temporary hack to avoid 97-only conversations for dlink plug. We need some preprocessing/data cleaning. - convsForActionForHostname = convsForActionForHostname.stream().filter(c -> c.getTlsApplicationDataPackets().size() > 1).collect(Collectors.toList()); - - Map> groupedByTlsAppDataSequence = - TcpConversationUtils.groupConversationsByTlsApplicationDataPacketSequence(convsForActionForHostname); - // Get a Conversation representing the most frequent TLS application data sequence. - Conversation mostFrequentConv = groupedByTlsAppDataSequence.values().stream().max((l1, l2) -> { - // The frequency of a conversation with a specific packet sequence is the list size as that represents how - // many conversations exhibit that packet sequence. - // Hence, the difference between the list sizes can be used directly as the return value of the Comparator. - // Note: we break ties by choosing the one with the most TLS application data packets (i.e., the longest - // sequence) in case the frequencies are equal. - int diff = l1.size() - l2.size(); - return diff != 0 ? diff : l1.get(0).getTlsApplicationDataPackets().size() - l2.get(0).getTlsApplicationDataPackets().size(); - }).get().get(0); // Just pick the first as a representative of the most frequent sequence. - // Lengths of TLS Application Data packets in the most frequent (or most frequent and longest) conversation. - Integer[] mostFreqSeq = TcpConversationUtils.getPacketLengthSequenceTlsAppDataOnly(mostFrequentConv); - // Now find the maximum cost of aligning the most frequent (or, alternatively longest) conversation with the - // each of the rest of the conversations also associated with this action and hostname. - int maxCost = 0; - for (Conversation c : convsForActionForHostname) { - if (c == mostFrequentConv) continue; - int cost = mAlignmentAlg.calculateAlignment(mostFreqSeq, TcpConversationUtils.getPacketLengthSequenceTlsAppDataOnly(c)); - maxCost = cost > maxCost ? cost : maxCost; - } - return new ExtractedSequence(mostFrequentConv, maxCost, true); - // Now find the maximum cost of aligning the most frequent (or, alternatively longest) conversation with the - // each of the rest of the conversations also associated with this action and hostname. - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/AbstractClusterMatcher.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/AbstractClusterMatcher.java deleted file mode 100644 index 45c6a55..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/AbstractClusterMatcher.java +++ /dev/null @@ -1,72 +0,0 @@ -package edu.uci.iotproject.detection; - -import org.pcap4j.core.PcapPacket; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * Base class for classes that search a traffic trace for sequences of packets that "belong to" a given cluster (in - * other words, classes that attempt to classify traffic as pertaining to a given cluster). - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -abstract public class AbstractClusterMatcher { - - /** - * The cluster that describes the sequence of packets that this {@link AbstractClusterMatcher} is trying to detect - * in the observed traffic. - */ - protected final List> mCluster; - - /** - * Observers registered for callbacks from this {@link AbstractClusterMatcher}. - */ - protected final List mObservers; - - protected AbstractClusterMatcher(List> cluster) { - // ===================== PRECONDITION SECTION ===================== - cluster = Objects.requireNonNull(cluster, "cluster cannot be null"); - if (cluster.isEmpty() || cluster.stream().anyMatch(inner -> inner.isEmpty())) { - throw new IllegalArgumentException("cluster is empty (or contains an empty inner List)"); - } - for (List clusterMember : cluster) { - if (clusterMember.size() != cluster.get(0).size()) { - throw new IllegalArgumentException("All sequences in cluster must contain the same number of packets"); - } - } - // ================================================================ - // Let the subclass prune the provided cluster - mCluster = pruneCluster(cluster); - mObservers = new ArrayList<>(); - } - - /** - * Register for callbacks from this cluster matcher. - * @param observer The target of the callbacks. - */ - public final void addObserver(ClusterMatcherObserver observer) { - mObservers.add(observer); - } - - /** - * Deregister for callbacks from this cluster matcher. - * @param observer The callback target that is to be deregistered. - */ - public final void removeObserver(ClusterMatcherObserver observer) { - mObservers.remove(observer); - } - - /** - * Allows subclasses to specify how to prune the input cluster provided to the constructor. - * @param cluster The input cluster provided to the constructor. - * @return The pruned cluster to use in place of the input cluster. - */ - abstract protected List> pruneCluster(List> cluster); - - // TODO: move Direction outside Conversation so that this is less confusing. -// abstract protected Conversation.Direction[] getPacketDirections(List packets); - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/AbstractSignatureDetector.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/AbstractSignatureDetector.java deleted file mode 100644 index b99116c..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/AbstractSignatureDetector.java +++ /dev/null @@ -1,77 +0,0 @@ -package edu.uci.iotproject.detection; - -import org.pcap4j.core.PcapPacket; - -import java.util.*; - -/** - * TODO add class documentation. - * - * @author Janus Varmarken - */ -public abstract class AbstractSignatureDetector implements ClusterMatcherObserver { - - - /** - * The signature that this {@link AbstractSignatureDetector} is searching for. - */ - private final List>> mSignature; - - /** - * The {@link AbstractClusterMatcher}s in charge of detecting each individual sequence of packets that together make - * up the the signature. - */ - private final List mClusterMatchers; - - /** - * For each {@code i} ({@code i >= 0 && i < pendingMatches.length}), {@code pendingMatches[i]} holds the matches - * found by the {@link AbstractClusterMatcher} at {@code mClusterMatchers.get(i)} that have yet to be "consumed", - * i.e., have yet to be included in a signature detected by this {@link AbstractSignatureDetector} (a signature can - * be encompassed of multiple packet sequences occurring shortly after one another on multiple connections). - */ - private final List>[] pendingMatches; - - /** - * Maps an {@link AbstractClusterMatcher} to its corresponding index in {@link #pendingMatches}. - */ - private final Map mClusterMatcherIds; - - public AbstractSignatureDetector(List>> searchedSignature) { - mSignature = Collections.unmodifiableList(searchedSignature); - List clusterMatchers = new ArrayList<>(); - for (List> cluster : mSignature) { - AbstractClusterMatcher clusterMatcher = constructClusterMatcher(cluster); - clusterMatcher.addObserver(this); - clusterMatchers.add(clusterMatcher); - } - mClusterMatchers = Collections.unmodifiableList(clusterMatchers); - pendingMatches = new List[mClusterMatchers.size()]; - for (int i = 0; i < pendingMatches.length; i++) { - pendingMatches[i] = new ArrayList<>(); - } - Map clusterMatcherIds = new HashMap<>(); - for (int i = 0; i < mClusterMatchers.size(); i++) { - clusterMatcherIds.put(mClusterMatchers.get(i), i); - } - mClusterMatcherIds = Collections.unmodifiableMap(clusterMatcherIds); - } - - abstract protected AbstractClusterMatcher constructClusterMatcher(List> cluster); - - /** - * Encapsulates a {@code List} so as to allow the list to be used as a vertex in a graph while avoiding - * the expensive {@link AbstractList#equals(Object)} calls when adding vertices to the graph. - * Using this wrapper makes the incurred {@code equals(Object)} calls delegate to {@link Object#equals(Object)} - * instead of {@link AbstractList#equals(Object)}. The net effect is a faster implementation, but the graph will not - * recognize two lists that contain the same items--from a value and not reference point of view--as the same - * vertex. However, this is fine for our purposes -- in fact restricting it to reference equality seems more - * appropriate. - */ - private static class Vertex { - private final List sequence; - private Vertex(List wrappedSequence) { - sequence = wrappedSequence; - } - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/ClusterMatcherObserver.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/ClusterMatcherObserver.java deleted file mode 100644 index d67c520..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/ClusterMatcherObserver.java +++ /dev/null @@ -1,26 +0,0 @@ -package edu.uci.iotproject.detection; - -import org.pcap4j.core.PcapPacket; - -import java.util.List; - -/** - * Interface used by client code to register for receiving a notification whenever an {@link AbstractClusterMatcher} - * detects traffic that matches an element of its associated cluster. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public interface ClusterMatcherObserver { - - /** - * Callback that is invoked by an {@link AbstractClusterMatcher} whenever it detects traffic that matches an element - * of its associated cluster. - * - * @param clusterMatcher The {@link AbstractClusterMatcher} that detected a match (i.e., classified traffic as - * pertaining to its associated cluster). - * @param match The traffic that was deemed to match the cluster associated with {@code clusterMatcher}. - */ - void onMatch(AbstractClusterMatcher clusterMatcher, List match); - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/SignatureDetectorObserver.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/SignatureDetectorObserver.java deleted file mode 100644 index c2d8e09..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/SignatureDetectorObserver.java +++ /dev/null @@ -1,22 +0,0 @@ -package edu.uci.iotproject.detection; - -import org.pcap4j.core.PcapPacket; - -import java.util.List; - -/** - * Used for registering for notifications from a signature detector. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public interface SignatureDetectorObserver { - - /** - * Invoked when the signature detector has detected the presence of a signature in the traffic that it's examining. - * @param searchedSignature The signature that the signature detector reporting the match is searching for. - * @param matchingTraffic The actual traffic trace that matches the searched signature. - */ - void onSignatureDetected(List>> searchedSignature, List> matchingTraffic); - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2ClusterMatcher.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2ClusterMatcher.java deleted file mode 100644 index 5021c31..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2ClusterMatcher.java +++ /dev/null @@ -1,153 +0,0 @@ -package edu.uci.iotproject.detection.layer2; - -import edu.uci.iotproject.trafficreassembly.layer2.Layer2FlowReassembler; -import edu.uci.iotproject.trafficreassembly.layer2.Layer2Flow; -import edu.uci.iotproject.trafficreassembly.layer2.Layer2FlowReassemblerObserver; -import edu.uci.iotproject.detection.AbstractClusterMatcher; -import edu.uci.iotproject.trafficreassembly.layer2.Layer2FlowObserver; -import org.pcap4j.core.*; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -/** - * Attempts to detect members of a cluster (packet sequence mutations) in layer 2 flows. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class Layer2ClusterMatcher extends AbstractClusterMatcher implements Layer2FlowReassemblerObserver, Layer2FlowObserver { - - /** - * Maps from a flow to a table of {@link Layer2SequenceMatcher}s for that particular flow. The table {@code t} is - * structured such that {@code t[i][j]} is a {@link Layer2SequenceMatcher} that attempts to match member {@code i} - * of {@link #mCluster} and has so far matched {@code j} packets of that particular sequence. - */ - private final Map mPerFlowSeqMatchers = new HashMap<>(); - - private final Function mFlowFilter; - - /** - * Create a new {@link Layer2ClusterMatcher} that attempts to find occurrences of {@code cluster}'s members. - * @param cluster The sequence mutations that the new {@link Layer2ClusterMatcher} should search for. - */ - public Layer2ClusterMatcher(List> cluster) { - // Consider all flows if no flow filter specified. - this(cluster, flow -> true); - } - - /** - * Create a new {@link Layer2ClusterMatcher} that attempts to find occurrences of {@code cluster}'s members. - * @param cluster The sequence mutations that the new {@link Layer2ClusterMatcher} should search for. - * @param flowFilter A filter that defines what {@link Layer2Flow}s the new {@link Layer2ClusterMatcher} should - * search for {@code cluster}'s members in. If {@code flowFilter} returns {@code true}, the flow - * will be included (searched). Note that {@code flowFilter} is only queried once for each flow, - * namely when the {@link Layer2FlowReassembler} notifies the {@link Layer2ClusterMatcher} about - * the new flow. This functionality may for example come in handy when one only wants to search - * for matches in the subset of flows that involves a specific (range of) MAC(s). - */ - public Layer2ClusterMatcher(List> cluster, Function flowFilter) { - super(cluster); - mFlowFilter = flowFilter; - } - - @Override - public void onNewPacket(Layer2Flow flow, PcapPacket newPacket) { - if (mPerFlowSeqMatchers.get(flow) == null) { - // If this is the first time we encounter this flow, we need to set up sequence matchers for it. - // All sequences of the cluster have the same length, so we only need to compute the length of the nested - // arrays once. We want to make room for a cluster matcher in each state, including the initial empty state - // but excluding the final "full match" state (as there is no point in keeping a terminated sequence matcher - // around), so the length of the inner array is simply the sequence length. - Layer2SequenceMatcher[][] matchers = new Layer2SequenceMatcher[mCluster.size()][mCluster.get(0).size()]; - // Prepare a "state 0" sequence matcher for each sequence variation in the cluster. - for (int i = 0; i < matchers.length; i++) { - matchers[i][0] = new Layer2SequenceMatcher(mCluster.get(i)); - } - // Associate the new sequence matcher table with the new flow - mPerFlowSeqMatchers.put(flow, matchers); - } - // Fetch table that contains sequence matchers for this flow. - Layer2SequenceMatcher[][] matchers = mPerFlowSeqMatchers.get(flow); - // Present the packet to all sequence matchers. - for (int i = 0; i < matchers.length; i++) { - // Present packet to the sequence matchers that has advanced the most first. This is to prevent discarding - // the sequence matchers that have advanced the most in the special case where the searched sequence - // contains two packets of the same length going in the same direction. - for (int j = matchers[i].length - 1; j >= 0 ; j--) { - Layer2SequenceMatcher sm = matchers[i][j]; - if (sm == null) { - // There is currently no sequence matcher that has managed to match j packets. - continue; - } - boolean matched = sm.matchPacket(newPacket); - if (matched) { - if (sm.getMatchedPacketsCount() == sm.getTargetSequencePacketCount()) { - // Sequence matcher has a match. Report it to observers. - mObservers.forEach(o -> o.onMatch(this, sm.getMatchedPackets())); - // Remove the now terminated sequence matcher. - matchers[i][j] = null; - } else { - // Sequence matcher advanced one step, so move it to its corresponding new position iff the - // packet that advanced it has a later timestamp than that of the last matched packet of the - // sequence matcher at the new index, if any. In most traces, a small amount of the packets - // appear out of order (with regards to their timestamp), which is why this check is required. - // Obviously it would not be needed if packets where guaranteed to be processed in timestamp - // order here. - if (matchers[i][j+1] == null || - newPacket.getTimestamp().isAfter(matchers[i][j+1].getLastPacket().getTimestamp())) { - matchers[i][j+1] = sm; - } - } - // We always want to have a sequence matcher in state 0, regardless of if the one that advanced - // from state zero completed its matching or if it replaced a different one in state 1 or not. - if (sm.getMatchedPacketsCount() == 1) { - matchers[i][j] = new Layer2SequenceMatcher(sm.getTargetSequence()); - } - } - } - } - } - - - @Override - protected List> pruneCluster(List> cluster) { - // Note: we assume that all sequences in the input cluster are of the same length and that their packet - // directions are identical. - List> prunedCluster = new ArrayList<>(); - for (List originalClusterSeq : cluster) { - boolean alreadyPresent = prunedCluster.stream().anyMatch(pcPkts -> { - for (int i = 0; i < pcPkts.size(); i++) { - if (pcPkts.get(i).getOriginalLength() != originalClusterSeq.get(i).getOriginalLength()) { - return false; - } - } - return true; - }); - if (!alreadyPresent) { - // Add the sequence if not already present in the pruned cluster. - prunedCluster.add(originalClusterSeq); - } - } - return prunedCluster; - } - - private static final boolean DEBUG = false; - - @Override - public void onNewFlow(Layer2FlowReassembler reassembler, Layer2Flow newFlow) { - // New flow detected. Check if we should consider it when searching for cluster member matches. - if (mFlowFilter.apply(newFlow)) { - if (DEBUG) { - System.out.println(">>> ACCEPTING FLOW: " + newFlow + " <<<"); - } - // Subscribe to the new flow to get updates whenever a new packet pertaining to the flow is processed. - newFlow.addFlowObserver(this); - } else if (DEBUG) { - System.out.println(">>> IGNORING FLOW: " + newFlow + " <<<"); - } - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2SequenceMatcher.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2SequenceMatcher.java deleted file mode 100644 index 672fb72..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2SequenceMatcher.java +++ /dev/null @@ -1,173 +0,0 @@ -package edu.uci.iotproject.detection.layer2; - -import edu.uci.iotproject.analysis.TriggerTrafficExtractor; -import edu.uci.iotproject.util.PcapPacketUtils; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.util.MacAddress; - -import java.util.ArrayList; -import java.util.List; - -/** - * Attempts to detect the presence of a specific packet sequence in the set of packets provided through multiple calls - * to {@link #matchPacket(PcapPacket)}, considering only layer 2 information. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class Layer2SequenceMatcher { - - /** - * The sequence this {@link Layer2SequenceMatcher} is searching for. - */ - private final List mSequence; - - /** - * Buffer of actual packets seen so far that match the searched sequence (i.e., constitutes a subsequence of the - * searched sequence). - */ - private final List mMatchedPackets = new ArrayList<>(); - - /** - * Models the directions of packets in {@link #mSequence}. As the sequence matcher assumes that it is only presented - * with packet from a single flow (packets exchanged between two devices), we can model the packet directions with a - * single bit. We don't have any notion "phone to device" or "device to phone" as we don't know the MAC addresses - * of devices in advance during matching. - */ - private final boolean[] mPacketDirections; - - /** - * Create a {@code Layer2SequenceMatcher}. - * @param sequence The sequence to match against (search for). - */ - public Layer2SequenceMatcher(List sequence) { - mSequence = sequence; - // Compute packet directions for sequence. - mPacketDirections = new boolean[sequence.size()]; - for (int i = 0; i < sequence.size(); i++) { - if (i == 0) { - // No previous packet; boolean parameter is ignored in this special case. - mPacketDirections[i] = getPacketDirection(null, true, sequence.get(i)); - } else { - // Base direction marker on direction of previous packet. - PcapPacket prevPkt = mSequence.get(i-1); - boolean prevPktDirection = mPacketDirections[i-1]; - mPacketDirections[i] = getPacketDirection(prevPkt, prevPktDirection, sequence.get(i)); - } - } - } - - /** - * Attempt to advance this {@code Layer2SequenceMatcher} by matching {@code packet} against the packet that this - * {@code Layer2SequenceMatcher} expects as the next packet of the sequence it is searching for. - * @param packet - * @return {@code true} if this {@code Layer2SequenceMatcher} could advance by adding {@code packet} to its set of - * matched packets, {@code false} otherwise. - */ - public boolean matchPacket(PcapPacket packet) { - if (getMatchedPacketsCount() == getTargetSequencePacketCount()) { - // We already matched the entire sequence, so we can't match any more packets. - return false; - } - - // Verify that new packet pertains to same flow as previously matched packets, if any. - if (getMatchedPacketsCount() > 0) { - MacAddress pktSrc = PcapPacketUtils.getEthSrcAddr(packet); - MacAddress pktDst = PcapPacketUtils.getEthDstAddr(packet); - MacAddress earlierPktSrc = PcapPacketUtils.getEthSrcAddr(mMatchedPackets.get(0)); - MacAddress earlierPktDst = PcapPacketUtils.getEthDstAddr(mMatchedPackets.get(0)); - if (!(pktSrc.equals(earlierPktSrc) && pktDst.equals(earlierPktDst) || - pktSrc.equals(earlierPktDst) && pktDst.equals(earlierPktSrc))) { - return false; - } - } - - // Get representative of the packet we expect to match next. - PcapPacket expected = mSequence.get(mMatchedPackets.size()); - // First verify if the received packet has the length we're looking for. - if (packet.getOriginalLength() == expected.getOriginalLength()) { - // If this is the first packet, we only need to verify that its length is correct. Time constraints are - // obviously satisfied as there are no previous packets. Furthermore, direction matches by definition as we - // don't know the MAC of the device (or phone) in advance, so we can't enforce a rule saying "first packet - // must originate from this particular MAC". - if (getMatchedPacketsCount() == 0) { - // Store packet as matched and advance. - mMatchedPackets.add(packet); - return true; - } - // Check if direction of packet matches expected direction. - boolean actualDirection = getPacketDirection(mMatchedPackets.get(getMatchedPacketsCount()-1), - mPacketDirections[getMatchedPacketsCount()-1], packet); - boolean expectedDirection = mPacketDirections[getMatchedPacketsCount()]; - if (actualDirection != expectedDirection) { - return false; - } - // Next apply timing constraints: - // 1: to be a match, the packet must have a later timestamp than any other packet currently matched - // 2: does adding the packet cause the max allowed time between first packet and last packet to be exceeded? - if (!packet.getTimestamp().isAfter(mMatchedPackets.get(getMatchedPacketsCount()-1).getTimestamp())) { - return false; - } - if (packet.getTimestamp().isAfter(mMatchedPackets.get(0).getTimestamp(). - plusMillis(TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS))) { - return false; - } - // If we made it here, it means that this packet has the expected length, direction, and obeys the timing - // constraints, so we store it and advance. - mMatchedPackets.add(packet); - if (mMatchedPackets.size() == mSequence.size()) { - // TODO report (to observers?) that we are done? - } - return true; - } - return false; - } - - public int getMatchedPacketsCount() { - return mMatchedPackets.size(); - } - - public int getTargetSequencePacketCount() { - return mSequence.size(); - } - - public List getTargetSequence() { - return mSequence; - } - - public List getMatchedPackets() { - return mMatchedPackets; - } - - /** - * Utility for {@code getMatchedPackets().get(getMatchedPackets().size()-1)}. - * @return The last matched packet, or {@code null} if no packets have been matched yet. - */ - public PcapPacket getLastPacket() { - return mSequence.size() > 0 ? mSequence.get(mSequence.size()-1) : null; - } - - /** - * Compute the direction of a packet based on the previous packet. If no previous packet is provided, the direction - * of {@code currPkt} is {@code true} by definition. - * @param prevPkt The previous packet, if any. - * @param prevPktDirection The computed direction of the previous packet - * @param currPkt The current packet for which the direction is to be determined. - * @return The direction of {@code currPkt}. - */ - private boolean getPacketDirection(PcapPacket prevPkt, boolean prevPktDirection, PcapPacket currPkt) { - if (prevPkt == null) { - // By definition, use true as direction marker for first packet - return true; - } - if (PcapPacketUtils.getEthSrcAddr(prevPkt).equals(PcapPacketUtils.getEthSrcAddr(currPkt))) { - // Current packet goes in same direction as previous packet. - return prevPktDirection; - } else { - // Current packet goes in opposite direction of previous packet. - return !prevPktDirection; - } - } - - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2SignatureDetector.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2SignatureDetector.java deleted file mode 100644 index a721914..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer2/Layer2SignatureDetector.java +++ /dev/null @@ -1,352 +0,0 @@ -package edu.uci.iotproject.detection.layer2; - -import edu.uci.iotproject.analysis.TriggerTrafficExtractor; -import edu.uci.iotproject.analysis.UserAction; -import edu.uci.iotproject.detection.AbstractClusterMatcher; -import edu.uci.iotproject.detection.ClusterMatcherObserver; -import edu.uci.iotproject.detection.SignatureDetectorObserver; -import edu.uci.iotproject.io.PcapHandleReader; -import edu.uci.iotproject.io.PrintWriterUtils; -import edu.uci.iotproject.trafficreassembly.layer2.Layer2Flow; -import edu.uci.iotproject.trafficreassembly.layer2.Layer2FlowReassembler; -import edu.uci.iotproject.util.PrintUtils; -import org.jgrapht.GraphPath; -import org.jgrapht.alg.shortestpath.DijkstraShortestPath; -import org.jgrapht.graph.DefaultWeightedEdge; -import org.jgrapht.graph.SimpleDirectedWeightedGraph; -import org.pcap4j.core.*; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.time.Duration; -import java.util.*; -import java.util.function.Function; -import java.util.regex.Pattern; - -/** - * Performs layer 2 signature detection. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class Layer2SignatureDetector implements PacketListener, ClusterMatcherObserver { - - /** - * If set to {@code true}, output written to the results file is also dumped to standard out. - */ - private static boolean DUPLICATE_OUTPUT_TO_STD_OUT = true; - - private static List> parseSignatureMacFilters(String filtersString) { - List> filters = new ArrayList<>(); - String[] filterRegexes = filtersString.split(";"); - for (String filterRegex : filterRegexes) { - final Pattern regex = Pattern.compile(filterRegex); - // Create a filter that includes all flows where one of the two MAC addresses match the regex. - filters.add(flow -> regex.matcher(flow.getEndpoint1().toString()).matches() || regex.matcher(flow.getEndpoint2().toString()).matches()); - } - return filters; - } - - public static void main(String[] args) throws PcapNativeException, NotOpenException, IOException { - // Parse required parameters. - if (args.length < 5) { - String errMsg = String.format("Usage: %s inputPcapFile onSignatureFile offSignatureFile resultsFile" + - "\n inputPcapFile: the target of the detection" + - "\n onSignatureFile: the file that contains the ON signature to search for" + - "\n offSignatureFile: the file that contains the OFF signature to search for" + - "\n resultsFile: where to write the results of the detection" + - "\n signatureDuration: the maximum duration of signature detection", - Layer2SignatureDetector.class.getSimpleName()); - System.out.println(errMsg); - String optParamsExplained = "Above are the required, positional arguments. In addition to these, the " + - "following options and associated positional arguments may be used:\n" + - " '-onmacfilters ;;...;' which specifies that sequence matching should ONLY" + - " be performed on flows where the MAC of one of the two endpoints matches the given regex. Note " + - "that you MUST specify a regex for each cluster of the signature. This is to facilitate more " + - "aggressive filtering on parts of the signature (e.g., the communication that involves the " + - "smart home device itself as one can drop all flows that do not include an endpoint with a MAC " + - "that matches the vendor's prefix).\n" + - " '-offmacfilters ;;...;' works exactly the same as onmacfilters, but " + - "applies to the OFF signature instead of the ON signature.\n" + - " '-sout ' true/false literal indicating if output should also be printed to std out; default is true."; - System.out.println(optParamsExplained); - return; - } - final String pcapFile = args[0]; - final String onSignatureFile = args[1]; - final String offSignatureFile = args[2]; - final String resultsFile = args[3]; - final int signatureDuration = Integer.parseInt(args[4]); - - // Parse optional parameters. - List> onSignatureMacFilters = null, offSignatureMacFilters = null; - final int optParamsStartIdx = 5; - if (args.length > optParamsStartIdx) { - for (int i = optParamsStartIdx; i < args.length; i++) { - if (args[i].equalsIgnoreCase("-onMacFilters")) { - // Next argument is the cluster-wise MAC filters (separated by semicolons). - onSignatureMacFilters = parseSignatureMacFilters(args[i+1]); - } else if (args[i].equalsIgnoreCase("-offMacFilters")) { - // Next argument is the cluster-wise MAC filters (separated by semicolons). - offSignatureMacFilters = parseSignatureMacFilters(args[i+1]); - } else if (args[i].equalsIgnoreCase("-sout")) { - // Next argument is a boolean true/false literal. - DUPLICATE_OUTPUT_TO_STD_OUT = Boolean.parseBoolean(args[i+1]); - } - } - } - - // Prepare file outputter. - File outputFile = new File(resultsFile); - outputFile.getParentFile().mkdirs(); - final PrintWriter resultsWriter = new PrintWriter(new FileWriter(outputFile)); - // Include metadata as comments at the top - PrintWriterUtils.println("# Detection results for:", resultsWriter, DUPLICATE_OUTPUT_TO_STD_OUT); - PrintWriterUtils.println("# - inputPcapFile: " + pcapFile, resultsWriter, DUPLICATE_OUTPUT_TO_STD_OUT); - PrintWriterUtils.println("# - onSignatureFile: " + onSignatureFile, resultsWriter, DUPLICATE_OUTPUT_TO_STD_OUT); - PrintWriterUtils.println("# - offSignatureFile: " + offSignatureFile, resultsWriter, DUPLICATE_OUTPUT_TO_STD_OUT); - resultsWriter.flush(); - - // Create signature detectors and add observers that output their detected events. - List>> onSignature = PrintUtils.deserializeSignatureFromFile(onSignatureFile); - List>> offSignature = PrintUtils.deserializeSignatureFromFile(offSignatureFile); - Layer2SignatureDetector onDetector = onSignatureMacFilters == null ? - new Layer2SignatureDetector(onSignature) : new Layer2SignatureDetector(onSignature, onSignatureMacFilters, signatureDuration); - Layer2SignatureDetector offDetector = offSignatureMacFilters == null ? - new Layer2SignatureDetector(offSignature) : new Layer2SignatureDetector(offSignature, offSignatureMacFilters, signatureDuration); - onDetector.addObserver((signature, match) -> { - UserAction event = new UserAction(UserAction.Type.TOGGLE_ON, match.get(0).get(0).getTimestamp()); - PrintWriterUtils.println(event, resultsWriter, DUPLICATE_OUTPUT_TO_STD_OUT); - }); - offDetector.addObserver((signature, match) -> { - UserAction event = new UserAction(UserAction.Type.TOGGLE_OFF, match.get(0).get(0).getTimestamp()); - PrintWriterUtils.println(event, resultsWriter, DUPLICATE_OUTPUT_TO_STD_OUT); - }); - - // Load the PCAP file - PcapHandle handle; - try { - handle = Pcaps.openOffline(pcapFile, PcapHandle.TimestampPrecision.NANO); - } catch (PcapNativeException pne) { - handle = Pcaps.openOffline(pcapFile); - } - PcapHandleReader reader = new PcapHandleReader(handle, p -> true, onDetector, offDetector); - // Parse the file - reader.readFromHandle(); - - // Flush output to results file and close it. - resultsWriter.flush(); - resultsWriter.close(); - } - - /** - * The signature that this {@link Layer2SignatureDetector} is searching for. - */ - private final List>> mSignature; - - /** - * The {@link Layer2ClusterMatcher}s in charge of detecting each individual sequence of packets that together make - * up the the signature. - */ - private final List mClusterMatchers; - - /** - * For each {@code i} ({@code i >= 0 && i < mPendingMatches.length}), {@code mPendingMatches[i]} holds the matches - * found by the {@link Layer2ClusterMatcher} at {@code mClusterMatchers.get(i)} that have yet to be "consumed", - * i.e., have yet to be included in a signature detected by this {@link Layer2SignatureDetector} (a signature can - * be encompassed of multiple packet sequences occurring shortly after one another on multiple connections). - */ - private final List>[] mPendingMatches; - - /** - * Maps a {@link Layer2ClusterMatcher} to its corresponding index in {@link #mPendingMatches}. - */ - private final Map mClusterMatcherIds; - - /** - * In charge of reassembling layer 2 packet flows. - */ - private final Layer2FlowReassembler mFlowReassembler = new Layer2FlowReassembler(); - - private final List mObservers = new ArrayList<>(); - - private int mInclusionTimeMillis; - - public Layer2SignatureDetector(List>> searchedSignature) { - this(searchedSignature, null, 0); - } - - public Layer2SignatureDetector(List>> searchedSignature, List> flowFilters, int inclusionTimeMillis) { - if (flowFilters != null && flowFilters.size() != searchedSignature.size()) { - throw new IllegalArgumentException("If flow filters are used, there must be a flow filter for each cluster of the signature."); - } - mSignature = Collections.unmodifiableList(searchedSignature); - List clusterMatchers = new ArrayList<>(); - for (int i = 0; i < mSignature.size(); i++) { - List> cluster = mSignature.get(i); - Layer2ClusterMatcher clusterMatcher = flowFilters == null ? - new Layer2ClusterMatcher(cluster) : new Layer2ClusterMatcher(cluster, flowFilters.get(i)); - clusterMatcher.addObserver(this); - clusterMatchers.add(clusterMatcher); - } - mClusterMatchers = Collections.unmodifiableList(clusterMatchers); - mPendingMatches = new List[mClusterMatchers.size()]; - for (int i = 0; i < mPendingMatches.length; i++) { - mPendingMatches[i] = new ArrayList<>(); - } - Map clusterMatcherIds = new HashMap<>(); - for (int i = 0; i < mClusterMatchers.size(); i++) { - clusterMatcherIds.put(mClusterMatchers.get(i), i); - } - mClusterMatcherIds = Collections.unmodifiableMap(clusterMatcherIds); - // Register all cluster matchers to receive a notification whenever a new flow is encountered. - mClusterMatchers.forEach(cm -> mFlowReassembler.addObserver(cm)); - mInclusionTimeMillis = - inclusionTimeMillis == 0 ? TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS : inclusionTimeMillis; - } - - @Override - public void gotPacket(PcapPacket packet) { - // Forward packet processing to the flow reassembler that in turn notifies the cluster matchers as appropriate - mFlowReassembler.gotPacket(packet); - } - - @Override - public void onMatch(AbstractClusterMatcher clusterMatcher, List match) { - // TODO: a cluster matcher found a match - if (clusterMatcher instanceof Layer2ClusterMatcher) { - // Add the match at the corresponding index - mPendingMatches[mClusterMatcherIds.get(clusterMatcher)].add(match); - checkSignatureMatch(); - } - } - - public void addObserver(SignatureDetectorObserver observer) { - mObservers.add(observer); - } - - public boolean removeObserver(SignatureDetectorObserver observer) { - return mObservers.remove(observer); - } - - - @SuppressWarnings("Duplicates") - private void checkSignatureMatch() { - // << Graph-based approach using Balint's idea. >> - // This implementation assumes that the packets in the inner lists (the sequences) are ordered by asc timestamp. - - // There cannot be a signature match until each Layer3ClusterMatcher has found a match of its respective sequence. - if (Arrays.stream(mPendingMatches).noneMatch(l -> l.isEmpty())) { - // Construct the DAG - final SimpleDirectedWeightedGraph graph = - new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class); - // Add a vertex for each match found by all cluster matchers. - // And maintain an array to keep track of what cluster matcher each vertex corresponds to - final List[] vertices = new List[mPendingMatches.length]; - for (int i = 0; i < mPendingMatches.length; i++) { - vertices[i] = new ArrayList<>(); - for (List sequence : mPendingMatches[i]) { - Vertex v = new Vertex(sequence); - vertices[i].add(v); // retain reference for later when we are to add edges - graph.addVertex(v); // add to vertex to graph - } - } - // Add dummy source and sink vertices to facilitate search. - final Vertex source = new Vertex(null); - final Vertex sink = new Vertex(null); - graph.addVertex(source); - graph.addVertex(sink); - // The source is connected to all vertices that wrap the sequences detected by cluster matcher at index 0. - // Note: zero cost edges as this is just a dummy link to facilitate search from a common start node. - for (Vertex v : vertices[0]) { - DefaultWeightedEdge edge = graph.addEdge(source, v); - graph.setEdgeWeight(edge, 0.0); - } - // Similarly, all vertices that wrap the sequences detected by the last cluster matcher of the signature - // are connected to the sink node. - for (Vertex v : vertices[vertices.length-1]) { - DefaultWeightedEdge edge = graph.addEdge(v, sink); - graph.setEdgeWeight(edge, 0.0); - } - // Now link sequences detected by the cluster matcher at index i to sequences detected by the cluster - // matcher at index i+1 if they obey the timestamp constraint (i.e., that the latter is later in time than - // the former). - for (int i = 0; i < vertices.length; i++) { - int j = i + 1; - if (j < vertices.length) { - for (Vertex iv : vertices[i]) { - PcapPacket ivLast = iv.sequence.get(iv.sequence.size()-1); - for (Vertex jv : vertices[j]) { - PcapPacket jvFirst = jv.sequence.get(jv.sequence.size()-1); - if (ivLast.getTimestamp().isBefore(jvFirst.getTimestamp())) { - DefaultWeightedEdge edge = graph.addEdge(iv, jv); - // The weight is the duration of the i'th sequence plus the duration between the i'th - // and i+1'th sequence. - Duration d = Duration. - between(iv.sequence.get(0).getTimestamp(), jvFirst.getTimestamp()); - // Unfortunately weights are double values, so must convert from long to double. - // TODO: need nano second precision? If so, use d.toNanos(). - // TODO: risk of overflow when converting from long to double..? - graph.setEdgeWeight(edge, Long.valueOf(d.toMillis()).doubleValue()); - } - // Alternative version if we cannot assume that sequences are ordered by timestamp: -// if (iv.sequence.stream().max(Comparator.comparing(PcapPacket::getTimestamp)).get() -// .getTimestamp().isBefore(jv.sequence.stream().min( -// Comparator.comparing(PcapPacket::getTimestamp)).get().getTimestamp())) { -// -// } - } - } - } - } - // Graph construction complete, run shortest-path to find a (potential) signature match. - DijkstraShortestPath dijkstra = new DijkstraShortestPath<>(graph); - GraphPath shortestPath = dijkstra.getPath(source, sink); - if (shortestPath != null) { - // The total weight is the duration between the first packet of the first sequence and the last packet - // of the last sequence, so we simply have to compare the weight against the timeframe that we allow - // the signature to span. For now we just use the inclusion window we defined for training purposes. - // Note however, that we must convert back from double to long as the weight is stored as a double in - // JGraphT's API. - if (((long)shortestPath.getWeight()) < mInclusionTimeMillis) { - // There's a signature match! - // Extract the match from the vertices - List> signatureMatch = new ArrayList<>(); - for(Vertex v : shortestPath.getVertexList()) { - if (v == source || v == sink) { - // Skip the dummy source and sink nodes. - continue; - } - signatureMatch.add(v.sequence); - // As there is a one-to-one correspondence between vertices[] and pendingMatches[], we know that - // the sequence we've "consumed" for index i of the matched signature is also at index i in - // pendingMatches. We must remove it from pendingMatches so that we don't use it to construct - // another signature match in a later call. - mPendingMatches[signatureMatch.size()-1].remove(v.sequence); - } - // Declare success: notify observers - mObservers.forEach(obs -> obs.onSignatureDetected(mSignature, - Collections.unmodifiableList(signatureMatch))); - } - } - } - } - - /** - * Encapsulates a {@code List} so as to allow the list to be used as a vertex in a graph while avoiding - * the expensive {@link AbstractList#equals(Object)} calls when adding vertices to the graph. - * Using this wrapper makes the incurred {@code equals(Object)} calls delegate to {@link Object#equals(Object)} - * instead of {@link AbstractList#equals(Object)}. The net effect is a faster implementation, but the graph will not - * recognize two lists that contain the same items--from a value and not reference point of view--as the same - * vertex. However, this is fine for our purposes -- in fact restricting it to reference equality seems more - * appropriate. - */ - private static class Vertex { - private final List sequence; - private Vertex(List wrappedSequence) { - sequence = wrappedSequence; - } - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer3/Layer3ClusterMatcher.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer3/Layer3ClusterMatcher.java deleted file mode 100644 index b9584ff..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer3/Layer3ClusterMatcher.java +++ /dev/null @@ -1,334 +0,0 @@ -package edu.uci.iotproject.detection.layer3; - -import edu.uci.iotproject.detection.AbstractClusterMatcher; -import edu.uci.iotproject.detection.ClusterMatcherObserver; -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.trafficreassembly.layer3.TcpReassembler; -import edu.uci.iotproject.analysis.TcpConversationUtils; -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.*; - -/** - * Searches a traffic trace for sequences of packets "belong to" a given cluster (in other words, attempts to classify - * traffic as pertaining to a given cluster). - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class Layer3ClusterMatcher extends AbstractClusterMatcher implements PacketListener { - - // Test client - public static void main(String[] args) throws PcapNativeException, NotOpenException { - -// 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"; - - List> signature = PrintUtils.deserializeClustersFromFile(signatureFile); - Layer3ClusterMatcher clusterMatcher = new Layer3ClusterMatcher(signature, null, - (sig, match) -> System.out.println( - 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); - } catch (PcapNativeException pne) { - handle = Pcaps.openOffline(inputPcapFile); - } - PcapHandleReader reader = new PcapHandleReader(handle, p -> true, clusterMatcher); - reader.readFromHandle(); - clusterMatcher.performDetection(); - } - - /** - * The ordered directions of packets in the sequences that make up {@link #mCluster}. - */ - private final Conversation.Direction[] mClusterMemberDirections; - - /** - * For reassembling the observed traffic into TCP connections. - */ - private final TcpReassembler mTcpReassembler = new TcpReassembler(); - - /** - * IP of the router's WAN port (if analyzed traffic is captured at the ISP's point of view). - */ - private final String mRouterWanIp; - - /** - * Create a {@link Layer3ClusterMatcher}. - * @param cluster The cluster that traffic is matched against. - * @param routerWanIp The router's WAN IP if examining traffic captured at the ISP's point of view (used for - * determining the direction of packets). - * @param detectionObservers Client code that wants to get notified whenever the {@link Layer3ClusterMatcher} detects that - * (a subset of) the examined traffic is similar to the traffic that makes up - * {@code cluster}, i.e., when the examined traffic is classified as pertaining to - * {@code cluster}. - */ - public Layer3ClusterMatcher(List> cluster, String routerWanIp, - ClusterMatcherObserver... detectionObservers) { - super(cluster); - Objects.requireNonNull(detectionObservers, "detectionObservers cannot be null"); - for (ClusterMatcherObserver obs : detectionObservers) { - addObserver(obs); - } - // Build the cluster members' direction sequence. - // Note: assumes that the provided cluster was captured within the local network (routerWanIp is set to null). - mClusterMemberDirections = getPacketDirections(cluster.get(0), null); - /* - * Enforce restriction on cluster members: all representatives must exhibit the same direction pattern and - * contain the same number of packets. Note that this is a somewhat heavy operation, so it may be disabled later - * on in favor of performance. However, it is only run once (at instantiation), so the overhead may be warranted - * in order to ensure correctness, especially during the development/debugging phase. - */ - if (mCluster.stream(). - anyMatch(inner -> !Arrays.equals(mClusterMemberDirections, getPacketDirections(inner, null)))) { - throw new IllegalArgumentException( - "cluster members must contain the same number of packets and exhibit the same packet direction " + - "pattern" - ); - } - mRouterWanIp = routerWanIp; - } - - @Override - public void gotPacket(PcapPacket packet) { - // Present packet to TCP reassembler so that it can be mapped to a connection (if it is a TCP packet). - mTcpReassembler.gotPacket(packet); - } - - /** - * Get the cluster that describes the packet sequence that this {@link Layer3ClusterMatcher} is searching for. - * @return the cluster that describes the packet sequence that this {@link Layer3ClusterMatcher} is searching for. - */ - public List> getCluster() { - return mCluster; - } - - public void performDetection() { - /* - * Let's start out simple by building a version that only works for signatures that do not span across multiple - * TCP conversations... - */ - for (Conversation c : mTcpReassembler.getTcpConversations()) { - if (c.isTls() && c.getTlsApplicationDataPackets().isEmpty() || !c.isTls() && c.getPackets().isEmpty()) { - // Skip empty conversations. - continue; - } - for (List signatureSequence : mCluster) { - if (isTlsSequence(signatureSequence) != c.isTls()) { - // We consider it a mismatch if one is a TLS application data sequence and the other is not. - continue; - } - // 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: 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; - while ((match = findSubsequenceInSequence(signatureSequence, cPkts, mClusterMemberDirections, null)). - isPresent()) { - List matchSeq = match.get(); - // Notify observers about the match. - mObservers.forEach(o -> o.onMatch(Layer3ClusterMatcher.this, matchSeq)); - /* - * 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()); - } - } - /* - * TODO: - * if no item in cluster matches, also perform a distance-based matching to cover those cases where we did - * not manage to capture every single mutation of the sequence during training. - * - * Need to compute average/centroid of cluster to do so...? Compute within-cluster variance, then check if - * distance between input conversation and cluster average/centroid is smaller than or equal to the computed - * variance? - */ - } - } - - /** - * Checks if {@code sequence} is a sequence of TLS packets. Note: the current implementation relies on inspection - * of the port numbers when deciding between TLS vs. non-TLS. Therefore, only the first packet of {@code sequence} - * is examined as it is assumed that all packets in {@code sequence} pertain to the same {@link Conversation} and - * hence share the same set of two src/dst port numbers (albeit possibly alternating between which one is the src - * and which one is the dst, as packets in {@code sequence} may be in alternating directions). - * @param sequence The sequence of packets for which it is to be determined if it is a sequence of TLS packets or - * non-TLS packets. - * @return {@code true} if {@code sequence} is a sequence of TLS packets, {@code false} otherwise. - */ - private boolean isTlsSequence(List sequence) { - // NOTE: Assumes ALL packets in sequence pertain to the same TCP connection! - PcapPacket firstPkt = sequence.get(0); - int srcPort = getSourcePort(firstPkt); - int dstPort = getDestinationPort(firstPkt); - return TcpConversationUtils.isTlsPort(srcPort) || TcpConversationUtils.isTlsPort(dstPort); - } - - /** - * Examine if a given sequence of packets ({@code sequence}) contains a given shorter sequence of packets - * ({@code subsequence}). Note: the current implementation actually searches for a substring as it does not allow - * for interleaving packets in {@code sequence} that are not in {@code subsequence}; for example, if - * {@code subsequence} consists of packet lengths [2, 3, 5] and {@code sequence} consists of packet lengths - * [2, 3, 4, 5], the result will be that there is no match (because of the interleaving 4). If we are to allow - * interleaving packets, we need a modified version of - * this. - * - * @param subsequence The sequence to search for. - * @param sequence The sequence to search. - * @param subsequenceDirections The directions of packets in {@code subsequence} such that for all {@code i}, - * {@code subsequenceDirections[i]} is the direction of the packet returned by - * {@code subsequence.get(i)}. May be set to {@code null}, in which this call will - * internally compute the packet directions. - * @param sequenceDirections The directions of packets in {@code sequence} such that for all {@code i}, - * {@code sequenceDirections[i]} is the direction of the packet returned by - * {@code sequence.get(i)}. May be set to {@code null}, in which this call will internally - * compute the packet directions. - * - * @return An {@link Optional} containing the part of {@code sequence} that matches {@code subsequence}, or an empty - * {@link Optional} if no part of {@code sequence} matches {@code subsequence}. - */ - private Optional> findSubsequenceInSequence(List subsequence, - List sequence, - Conversation.Direction[] subsequenceDirections, - Conversation.Direction[] sequenceDirections) { - 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); - } - if (sequenceDirections == null) { - sequenceDirections = getPacketDirections(sequence, mRouterWanIp); - } - int subseqIdx = 0; - int seqIdx = 0; - while (seqIdx < sequence.size()) { - PcapPacket subseqPkt = subsequence.get(subseqIdx); - PcapPacket seqPkt = sequence.get(seqIdx); - // We only have a match if packet lengths and directions match. - if (subseqPkt.getOriginalLength() == seqPkt.getOriginalLength() && - subsequenceDirections[subseqIdx] == sequenceDirections[seqIdx]) { - // A match; advance both indices to consider next packet in subsequence vs. next packet in sequence. - subseqIdx++; - seqIdx++; - if (subseqIdx == subsequence.size()) { - // We managed to match the entire subsequence in sequence. - // Return the sublist of sequence that matches subsequence. - /* - * TODO: - * ASSUMES THE BACKING LIST (i.e., 'sequence') IS _NOT_ STRUCTURALLY MODIFIED, hence may not work - * for live traces! - */ - return Optional.of(sequence.subList(seqIdx - subsequence.size(), seqIdx)); - } - } else { - // Mismatch. - if (subseqIdx > 0) { - /* - * If we managed to match parts of subsequence, we restart the search for subsequence in sequence at - * the index of sequence where the current mismatch occurred. I.e., we must reset subseqIdx, but - * leave seqIdx untouched. - */ - subseqIdx = 0; - } else { - /* - * First packet of subsequence didn't match packet at seqIdx of sequence, so we move forward in - * sequence, i.e., we continue the search for subsequence in sequence starting at index seqIdx+1 of - * sequence. - */ - seqIdx++; - } - } - } - return Optional.empty(); - } - - /** - * Given a cluster, produces a pruned version of that cluster. In the pruned version, there are no duplicate cluster - * members. Two cluster members are considered identical if their packets lengths and packet directions are - * identical. The resulting pruned cluster is unmodifiable (this applies to both the outermost list as well as the - * nested lists) in order to preserve its integrity when exposed to external code (e.g., through - * {@link #getCluster()}). - * - * @param cluster A cluster to prune. - * @return The resulting pruned cluster. - */ - @Override - protected List> pruneCluster(List> cluster) { - List> prunedCluster = new ArrayList<>(); - for (List originalClusterSeq : cluster) { - boolean alreadyPresent = false; - for (List prunedClusterSeq : prunedCluster) { - Optional> duplicate = findSubsequenceInSequence(originalClusterSeq, prunedClusterSeq, - mClusterMemberDirections, mClusterMemberDirections); - if (duplicate.isPresent()) { - alreadyPresent = true; - break; - } - } - if (!alreadyPresent) { - prunedCluster.add(Collections.unmodifiableList(originalClusterSeq)); - } - } - return Collections.unmodifiableList(prunedCluster); - } - - /** - * Given a {@code List}, generate a {@code Conversation.Direction[]} such that each entry in the - * resulting {@code Conversation.Direction[]} specifies the direction of the {@link PcapPacket} at the corresponding - * index in the input list. - * @param packets The list of packets for which to construct a corresponding array of packet directions. - * @param routerWanIp The IP of the router's WAN port. This is used for determining the direction of packets when - * the traffic is captured just outside the local network (at the ISP side of the router). Set to - * {@code null} if {@code packets} stem from traffic captured within the local network. - * @return A {@code Conversation.Direction[]} specifying the direction of the {@link PcapPacket} at the - * corresponding index in {@code packets}. - */ - private static Conversation.Direction[] getPacketDirections(List packets, String routerWanIp) { - Conversation.Direction[] directions = new Conversation.Direction[packets.size()]; - for (int i = 0; i < packets.size(); i++) { - PcapPacket pkt = packets.get(i); - if (getSourceIp(pkt).equals(getDestinationIp(pkt))) { - // Sanity check: we shouldn't be processing loopback traffic - throw new AssertionError("loopback traffic detected"); - } - if (isSrcIpLocal(pkt) || getSourceIp(pkt).equals(routerWanIp)) { - directions[i] = Conversation.Direction.CLIENT_TO_SERVER; - } else if (isDstIpLocal(pkt) || getDestinationIp(pkt).equals(routerWanIp)) { - directions[i] = Conversation.Direction.SERVER_TO_CLIENT; - } else { - //throw new IllegalArgumentException("no local IP or router WAN port IP found, can't detect direction"); - } - } - return directions; - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer3/SignatureDetector.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer3/SignatureDetector.java deleted file mode 100644 index 0c4324d..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/detection/layer3/SignatureDetector.java +++ /dev/null @@ -1,666 +0,0 @@ -package edu.uci.iotproject.detection.layer3; - -import edu.uci.iotproject.analysis.TriggerTrafficExtractor; -import edu.uci.iotproject.analysis.UserAction; -import edu.uci.iotproject.detection.AbstractClusterMatcher; -import edu.uci.iotproject.detection.ClusterMatcherObserver; -import edu.uci.iotproject.io.PcapHandleReader; -import edu.uci.iotproject.util.PrintUtils; -import org.jgrapht.GraphPath; -import org.jgrapht.alg.shortestpath.DijkstraShortestPath; -import org.jgrapht.graph.DefaultWeightedEdge; -import org.jgrapht.graph.SimpleDirectedWeightedGraph; -import org.pcap4j.core.*; - -import java.time.Duration; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; -import java.util.*; -import java.util.function.Consumer; - -/** - * Detects an event signature that spans one or multiple TCP connections. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class SignatureDetector implements PacketListener, ClusterMatcherObserver { - - // Test client - public static void main(String[] args) throws PcapNativeException, NotOpenException { -// if (args.length < 3) { -// String errMsg = String.format("Usage: %s inputPcapFile onSignatureFile offSignatureFile", -// SignatureDetector.class.getSimpleName()); -// System.out.println(errMsg); -// return; -// } -// final String inputPcapFile = args[0]; -// final String onSignatureFile = args[1]; -// final String offSignatureFile = args[2]; - - String path = "/scratch/July-2018"; // Rahmadi -// String path = "/Users/varmarken/temp/UCI IoT Project/experiments"; // Janus -// String path = "/home/jvarmark/iot_project/datasets"; // Hera (server) -// String path = "/raid/varmarken/iot_project/datasets"; // Zeus (server) - - // No activity test - //final String inputPcapFile = path + "/evaluation/no-activity/no-activity.wlan1.pcap"; - - // D-Link Siren experiment -// final String inputPcapFile = path + "/evaluation/dlink-siren/dlink-siren.data.wlan1.pcap"; -// final String inputPcapFile = path + "/evaluation/dlink-siren/dlink-siren.eth0.local.pcap"; - // D-Link Siren DEVICE signatures -// final String onSignatureFile = path + "/2018-08/dlink-siren/onSignature-DLink-Siren-device.sig"; -// final String offSignatureFile = path + "/2018-08/dlink-siren/offSignature-DLink-Siren-device.sig"; - // D-Link Siren PHONE signatures -// final String onSignatureFile = path + "/2018-08/dlink-siren/onSignature-DLink-Siren-phone.sig"; -// final String offSignatureFile = path + "/2018-08/dlink-siren/offSignature-DLink-Siren-phone.sig"; - // TODO: EXPERIMENT - November 19, 2018 - // Hue Bulb experiment -// final String inputPcapFile = path + "/2018-08/hue-bulb/hue-bulb.wlan1.local.pcap"; - // Hue Bulb PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/hue-bulb/signatures/hue-bulb-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/hue-bulb/signatures/hue-bulb-offSignature-phone-side.sig"; - - /* - // Kwikset Doorlock Sep 12 experiment -// final String inputPcapFile = path + "/evaluation/kwikset-doorlock/kwikset-doorlock.data.wlan1.pcap"; - final String inputPcapFile = path + "/evaluation/kwikset-doorlock/kwikset-doorlock.data.eth0.pcap"; -// // Kwikset Doorlock PHONE signatures - final String onSignatureFile = path + "/2018-08/kwikset-doorlock/onSignature-Kwikset-Doorlock-phone-new.sig"; - final String offSignatureFile = path + "/2018-08/kwikset-doorlock/offSignature-Kwikset-Doorlock-phone-new.sig"; - */ - - // D-Link Plug experiment - //final String inputPcapFile = path + "/evaluation/dlink/dlink-plug.data.wlan1.pcap"; -// final String inputPcapFile = path + "/evaluation/dlink/dlink-plug.data.eth0.pcap"; - - // D-Link Plug DEVICE signatures -// final String onSignatureFile = path + "/2018-07/dlink/onSignature-DLink-Plug-device.sig"; -// final String offSignatureFile = path + "/2018-07/dlink/offSignature-DLink-Plug-device.sig"; - // D-Link Plug PHONE signatures -// final String onSignatureFile = path + "/2018-07/dlink/onSignature-DLink-Plug-phone.sig"; -// final String offSignatureFile = path + "/2018-07/dlink/offSignature-DLink-Plug-phone.sig"; - - // TODO: The following are negative tests against the PCAP file from UNSW -// final String inputPcapFile = path + "/UNSW/16-10-04.pcap"; // TODO: Seems to be broken! Zero-payload! -// final String inputPcapFile = path + "/UNSW/16-10-12.pcap"; - -// final String inputPcapFile = path + "/UNSW/16-09-28.pcap"; // TODO: Seems to be broken! Zero-payload! -// final String inputPcapFile = path + "/UNSW/16-10-02.pcap"; // TODO: Seems to be broken! -// final String inputPcapFile = path + "/UNSW/16-10-03.pcap"; // TODO: Seems to be broken! -// final String inputPcapFile = path + "/UNSW/16-10-04-a.pcap"; // TODO: Seems to be broken! Zero-payload! -// final String inputPcapFile = path + "/UNSW/16-10-04-b.pcap"; // TODO: Seems to be broken! Zero-payload! -// final String inputPcapFile = path + "/UNSW/16-10-07.pcap"; // TODO: Seems to be broken! -// final String inputPcapFile = path + "/UNSW/16-10-08.pcap"; // TODO: Seems to be broken! -// final String inputPcapFile = path + "/UNSW/16-10-09.pcap"; // TODO: Seems to be broken! -// final String inputPcapFile = path + "/UNSW/16-10-10.pcap"; // TODO: Seems to be broken! -// final String inputPcapFile = path + "/UNSW/16-10-11.pcap"; // TODO: Seems to be broken! - // TODO: The following one is very long!!! - Split into smaller files! -// final String inputPcapFile = path + "/UNSW/16-10-12-a.pcap"; -// final String inputPcapFile = path + "/UNSW/16-10-12-b.pcap"; -// final String inputPcapFile = path + "/UNSW/16-10-12-c.pcap"; -// final String inputPcapFile = path + "/UNSW/16-10-12-d.pcap"; - -// final String inputPcapFile = path + "/UNSW/16-09-23.pcap"; -// final String inputPcapFile = path + "/UNSW/16-09-24.pcap"; -// final String inputPcapFile = path + "/UNSW/16-09-25.pcap"; -// final String inputPcapFile = path + "/UNSW/16-09-26.pcap"; -// final String inputPcapFile = path + "/UNSW/16-09-27.pcap"; -// final String inputPcapFile = path + "/UNSW/16-09-29.pcap"; -// final String inputPcapFile = path + "/UNSW/16-10-01.pcap"; -// final String inputPcapFile = path + "/UNSW/16-10-06.pcap"; - // Negative test: dataset from UNB -// final String inputPcapFile = path + "/evaluation/negative-datasets/UNB/Monday-WorkingHours_one-local-endpoint-001.pcap"; - - // TODO: The following are tests for signatures against training data - - // D-Link Plug experiment -// final String inputPcapFile = path + "/training/dlink-plug/wlan1/dlink-plug.wlan1.local.pcap"; - // D-Link Plug DEVICE signatures -// final String onSignatureFile = path + "/training/dlink-plug/signatures/dlink-plug-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/training/dlink-plug/signatures/dlink-plug-offSignature-device-side.sig"; - // D-Link Plug PHONE signatures -// final String onSignatureFile = path + "/training/dlink-plug/signatures/dlink-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/dlink-plug/signatures/dlink-plug-offSignature-phone-side.sig"; - - // TODO: EXPERIMENT - November 7, 2018 - // D-Link Plug experiment - //final String inputPcapFile = path + "/experimental_result/standalone/dlink-plug/wlan1/dlink-plug.wlan1.local.pcap"; - //final String inputPcapFile = path + "/experimental_result/smarthome/dlink-plug/wlan1/dlink-plug.wlan1.detection.pcap"; - //final String inputPcapFile = path + "/experimental_result/smarthome/dlink-plug/eth0/dlink-plug.eth0.detection.pcap"; - // D-Link Plug DEVICE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-offSignature-device-side.sig"; - // D-Link Plug PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-offSignature-phone-side.sig"; - - // TODO: EXPERIMENT - November 9, 2018 - // D-Link Siren experiment - //final String inputPcapFile = path + "/experimental_result/standalone/dlink-siren/wlan1/dlink-siren.wlan1.local.pcap"; - //final String inputPcapFile = path + "/experimental_result/smarthome/dlink-siren/wlan1/dlink-siren.wlan1.detection.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/dlink-siren/eth0/dlink-siren.eth0.detection.pcap"; - // D-Link Siren DEVICE signatures - // TODO: The device signature does not have pairs---only one packet which is 216, so we don't consider this as a signature -// final String onSignatureFile = path + "/experimental_result/standalone/dlink-siren/signatures/dlink-siren-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/dlink-siren/signatures/dlink-siren-offSignature-device-side.sig"; - // D-Link Siren PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/dlink-siren/signatures/dlink-siren-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/dlink-siren/signatures/dlink-siren-offSignature-phone-side.sig"; -// final String onSignatureFile = path + "/training/signatures/dlink-siren/dlink-siren-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/signatures/dlink-siren/dlink-siren-offSignature-phone-side.sig"; - - // TP-Link Plug experiment -//// final String inputPcapFile = path + "/training/tplink-plug/wlan1/tplink-plug.wlan1.local.pcap"; -//// final String inputPcapFile = path + "/experimental_result/wifi-Sniffer/tests2/airtool_2019-01-04_11.08.45.AM.pcap"; -// final String inputPcapFile = path + "/experimental_result/wifi-Sniffer/tests2/command-frames-only.pcap"; -// // TP-Link Plug DEVICE signatures -// final String onSignatureFile = path + "/training/tplink-plug/signatures/tplink-plug-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/training/tplink-plug/signatures/tplink-plug-offSignature-device-side.sig"; - // TODO: EXPERIMENT - November 8, 2018 - // TP-Link Plug experiment -// final String inputPcapFile = path + "/experimental_result/standalone/tplink-plug/wlan1/tplink-plug.wlan1.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/standalone/tplink-plug/eth0/tplink-plug.eth0.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/tplink-plug/wlan1/tplink-plug.wlan1.detection.pcap"; - //final String inputPcapFile = path + "/experimental_result/smarthome/tplink-plug/eth0/tplink-plug.eth0.detection.pcap"; - // TP-Link Plug DEVICE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-device-side.sig"; -// final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-device-side-outbound.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-device-side-outbound.sig"; - // TP-Link Plug PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-phone-side.sig"; - - // Arlo camera experiment -// final String inputPcapFile = path + "/training/arlo-camera/wlan1/arlo-camera.wlan1.local.pcap"; -//// // TP-Link Plug DEVICE signatures -// final String onSignatureFile = path + "/training/arlo-camera/signatures/arlo-camera-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/arlo-camera/signatures/arlo-camera-offSignature-phone-side.sig"; - // TODO: EXPERIMENT - November 13, 2018 - // Arlo Camera experiment -// final String inputPcapFile = path + "/experimental_result/standalone/arlo-camera/wlan1/arlo-camera.wlan1.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/standalone/arlo-camera/eth0/arlo-camera.eth0.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/arlo-camera/wlan1/arlo-camera.wlan1.detection.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/arlo-camera/eth0/arlo-camera.eth0.detection.pcap"; -// final String inputPcapFile = path + "/training/arlo-camera/eth0/arlo-camera.eth0.local.pcap"; - // Arlo Camera PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/arlo-camera/signatures/arlo-camera-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/arlo-camera/signatures/arlo-camera-offSignature-phone-side.sig"; - - // Amazon Alexa experiment -// final String inputPcapFile = path + "/training/amazon-alexa/wlan1/alexa2.wlan1.local.pcap"; -// // TP-Link Plug DEVICE signatures -// final String onSignatureFile = path + "/training/amazon-alexa/signatures/amazon-alexa-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/training/amazon-alexa/signatures/amazon-alexa-offSignature-device-side.sig"; - - // SmartThings Plug experiment -// final String inputPcapFile = path + "/training/st-plug/wlan1/st-plug.wlan1.local.pcap"; -// // SmartThings Plug DEVICE signatures -// //final String onSignatureFile = path + "/training/st-plug/signatures/st-plug-onSignature-device-side.sig"; -// //final String offSignatureFile = path + "/training/st-plug/signatures/st-plug-offSignature-device-side.sig"; -// // SmartThings Plug PHONE signatures -// final String onSignatureFile = path + "/training/st-plug/signatures/st-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/st-plug/signatures/st-plug-offSignature-phone-side.sig"; - // TODO: EXPERIMENT - November 12, 2018 - // SmartThings Plug experiment -// final String inputPcapFile = path + "/experimental_result/standalone/st-plug/wlan1/st-plug.wlan1.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/standalone/st-plug/eth0/st-plug.eth0.local.pcap"; -// //final String inputPcapFile = path + "/experimental_result/smarthome/st-plug/wlan1/st-plug.wlan1.detection.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/st-plug/eth0/st-plug.eth0.detection.pcap"; -// // SmartThings Plug PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/st-plug/signatures/st-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/st-plug/signatures/st-plug-offSignature-phone-side.sig"; -// final String onSignatureFile = path + "/training/signatures/st-plug/st-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/signatures/st-plug/st-plug-offSignature-phone-side.sig"; - - // TODO: EXPERIMENT - January 9, 2018 - // Blossom Sprinkler experiment -// final String inputPcapFile = path + "/experimental_result/standalone/blossom-sprinkler/wlan1/blossom-sprinkler.wlan1.local.pcap"; - final String inputPcapFile = path + "/experimental_result/smarthome/blossom-sprinkler/eth0/blossom-sprinkler.eth0.detection.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/blossom-sprinkler/wlan1/blossom-sprinkler.wlan1.detection.pcap"; - // Blossom Sprinkler DEVICE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-device-side.sig"; - // Blossom Sprinkler PHONE signatures - final String onSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-phone-side.sig"; - final String offSignatureFile = path + "/experimental_result/standalone/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-phone-side.sig"; - - // LiFX Bulb experiment -// final String inputPcapFile = path + "/training/lifx-bulb/wlan1/lifx-bulb.wlan1.local.pcap"; -// // LiFX Bulb DEVICE signatures -// final String onSignatureFile = path + "/training/lifx-bulb/signatures/lifx-bulb-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/training/lifx-bulb/signatures/lifx-bulb-offSignature-device-side.sig"; - // LiFX Bulb PHONE signatures -// final String onSignatureFile = path + "/training/lifx-bulb/signatures/lifx-bulb-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/lifx-bulb/signatures/lifx-bulb-offSignature-phone-side.sig"; - - // Blossom Sprinkler experiment -// //final String inputPcapFile = path + "/training/blossom-sprinkler/wlan1/blossom-sprinkler.wlan1.local.pcap"; -// final String inputPcapFile = path + "/2018-08/blossom/blossom.wlan1.local.pcap"; -// //final String inputPcapFile = path + "/training/blossom-sprinkler/eth0/blossom-sprinkler.eth0.local.pcap"; -// // Blossom Sprinkler DEVICE signatures -// final String onSignatureFile = path + "/training/blossom-sprinkler/signatures/blossom-sprinkler-onSignature-device-side.sig"; -// final String offSignatureFile = path + "/training/blossom-sprinkler/signatures/blossom-sprinkler-offSignature-device-side.sig"; - - // Nest Thermostat experiment -// final String inputPcapFile = path + "/training/nest-thermostat/wlan1/nest-thermostat.wlan1.local.pcap"; -// // Nest Thermostat DEVICE signatures -//// final String onSignatureFile = path + "/training/nest-thermostat/signatures/nest-thermostat-onSignature-device-side.sig"; -//// final String offSignatureFile = path + "/training/nest-thermostat/signatures/nest-thermostat-offSignature-device-side.sig"; -// // Nest Thermostat PHONE signatures -// final String onSignatureFile = path + "/training/nest-thermostat/signatures/nest-thermostat-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/nest-thermostat/signatures/nest-thermostat-offSignature-phone-side.sig"; - // TODO: EXPERIMENT - November 15, 2018 - // Nest Thermostat experiment -// final String inputPcapFile = path + "/experimental_result/standalone/nest-thermostat/wlan1/nest-thermostat.wlan1.local.pcap"; -//// final String inputPcapFile = path + "/experimental_result/standalone/nest-thermostat/eth0/nest-thermostat.eth0.local.pcap"; -//// final String inputPcapFile = path + "/experimental_result/smarthome/nest-thermostat/wlan1/nest-thermostat.wlan1.detection.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/nest-thermostat/eth0/nest-thermostat.eth0.detection.pcap"; -//// // Nest Thermostat PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/nest-thermostat/signatures/nest-thermostat-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/nest-thermostat/signatures/nest-thermostat-offSignature-phone-side.sig"; - - /* - // Hue Bulb experiment - final String inputPcapFile = path + "/training/hue-bulb/wlan1/hue-bulb.wlan1.local.pcap"; - // Hue Bulb PHONE signatures - final String onSignatureFile = path + "/training/hue-bulb/signatures/hue-bulb-onSignature-phone-side.sig"; - final String offSignatureFile = path + "/training/hue-bulb/signatures/hue-bulb-offSignature-phone-side.sig"; - */ - - - - // TP-Link Bulb experiment -// final String inputPcapFile = path + "/training/tplink-bulb/wlan1/tplink-bulb.wlan1.local.pcap"; -// // TP-Link Bulb PHONE signatures -// final String onSignatureFile = path + "/training/tplink-bulb/signatures/tplink-bulb-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/tplink-bulb/signatures/tplink-bulb-offSignature-phone-side.sig"; - // TODO: EXPERIMENT - November 16, 2018 - // TP-Link Bulb experiment -// final String inputPcapFile = path + "/experimental_result/standalone/tplink-bulb/wlan1/tplink-bulb.wlan1.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/standalone/tplink-bulb/eth0/tplink-bulb.eth0.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/tplink-bulb/wlan1/tplink-bulb.wlan1.detection.pcap"; -//// final String inputPcapFile = path + "/experimental_result/smarthome/tplink-bulb/eth0/tplink-bulb.eth0.detection.pcap"; -// // TP-Link Bulb PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/tplink-bulb/signatures/tplink-bulb-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/tplink-bulb/signatures/tplink-bulb-offSignature-phone-side.sig"; - - /* - // WeMo Plug experiment - final String inputPcapFile = path + "/training/wemo-plug/wlan1/wemo-plug.wlan1.local.pcap"; - // WeMo Plug PHONE signatures - final String onSignatureFile = path + "/training/wemo-plug/signatures/wemo-plug-onSignature-device-side.sig"; - final String offSignatureFile = path + "/training/wemo-plug/signatures/wemo-plug-offSignature-device-side.sig"; - */ - // TODO: EXPERIMENT - November 20, 2018 - // WeMo Plug experiment -// final String inputPcapFile = path + "/experimental_result/standalone/wemo-plug/wlan1/wemo-plug.wlan1.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/standalone/wemo-plug/eth0/wemo-plug.eth0.local.pcap"; - // TODO: WE HAVE 4 ADDITIONAL EVENTS (TRIGGERED MANUALLY), SO WE JUST IGNORE THEM BECAUSE THEY HAPPENED BEFORE - // TODO: THE ACTUAL TRIGGERS -// final String inputPcapFile = path + "/experimental_result/smarthome/wemo-plug/wlan1/wemo-plug.wlan1.detection.pcap"; -//// final String inputPcapFile = path + "/experimental_result/smarthome/wemo-plug/eth0/wemo-plug.eth0.detection.pcap"; -// // WeMo Plug PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/wemo-plug/signatures/wemo-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/wemo-plug/signatures/wemo-plug-offSignature-phone-side.sig"; - - /* - // WeMo Insight Plug experiment - final String inputPcapFile = path + "/training/wemo-insight-plug/wlan1/wemo-insight-plug.wlan1.local.pcap"; - // WeMo Insight Plug PHONE signatures - final String onSignatureFile = path + "/training/wemo-insight-plug/signatures/wemo-insight-plug-onSignature-device-side.sig"; - final String offSignatureFile = path + "/training/wemo-insight-plug/signatures/wemo-insight-plug-offSignature-device-side.sig"; - */ - // TODO: EXPERIMENT - November 21, 2018 - // WeMo Insight Plug experiment -// final String inputPcapFile = path + "/experimental_result/standalone/wemo-insight-plug/wlan1/wemo-insight-plug.wlan1.local.pcap"; -// final String inputPcapFile = path + "/experimental_result/standalone/wemo-insight-plug/eth0/wemo-insight-plug.eth0.local.pcap"; - // TODO: WE HAVE 1 ADDITIONAL EVENT (FROM WEMO PLUG) -// final String inputPcapFile = path + "/experimental_result/smarthome/wemo-insight-plug/wlan1/wemo-insight-plug.wlan1.detection.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/wemo-insight-plug/eth0/wemo-insight-plug.eth0.detection.pcap"; - // WeMo Insight Plug PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-offSignature-phone-side.sig"; - - - // Kwikset Doorlock Sep 12 experiment -// final String inputPcapFile = path + "/2018-08/kwikset-doorlock/kwikset3.wlan1.local.pcap"; -// // Kwikset Doorlock PHONE signatures -// final String onSignatureFile = path + "/2018-08/kwikset-doorlock/onSignature-Kwikset-Doorlock-phone.sig"; -// final String offSignatureFile = path + "/2018-08/kwikset-doorlock/offSignature-Kwikset-Doorlock-phone.sig"; - // TODO: EXPERIMENT - November 10, 2018 - // Kwikset Door lock experiment -// final String inputPcapFile = path + "/experimental_result/standalone/kwikset-doorlock/wlan1/kwikset-doorlock.wlan1.local.pcap"; -// //final String inputPcapFile = path + "/experimental_result/smarthome/kwikset-doorlock/wlan1/kwikset-doorlock.wlan1.detection.pcap"; -// final String inputPcapFile = path + "/experimental_result/smarthome/kwikset-doorlock/eth0/kwikset-doorlock.eth0.detection.pcap"; -//// // Kwikset Door lock PHONE signatures -// final String onSignatureFile = path + "/experimental_result/standalone/kwikset-doorlock/signatures/kwikset-doorlock-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/experimental_result/standalone/kwikset-doorlock/signatures/kwikset-doorlock-offSignature-phone-side.sig"; -// final String onSignatureFile = path + "/training/signatures/kwikset-doorlock/kwikset-doorlock-onSignature-phone-side.sig"; -// final String offSignatureFile = path + "/training/signatures/kwikset-doorlock/kwikset-doorlock-offSignature-phone-side.sig"; - - - - // D-Link Siren experiment -// final String inputPcapFile = path + "/2018-08/dlink-siren/dlink-siren.wlan1.local.pcap"; - // D-Link Siren DEVICE signatures - //final String onSignatureFile = path + "/2018-08/dlink-siren/onSignature-DLink-Siren-device.sig"; - //final String offSignatureFile = path + "/2018-08/dlink-siren/offSignature-DLink-Siren-device.sig"; - // D-Link Siren PHONE signatures -// final String onSignatureFile = path + "/2018-08/dlink-siren/onSignature-DLink-Siren-phone.sig"; -// final String offSignatureFile = path + "/2018-08/dlink-siren/offSignature-DLink-Siren-phone.sig"; - - - // Output file names used (to make it easy to catch if one forgets to change them) - System.out.println("ON signature file in use is " + onSignatureFile); - System.out.println("OFF signature file in use is " + offSignatureFile); - System.out.println("PCAP file that is the target of detection is " + inputPcapFile); - - List>> onSignature = PrintUtils.deserializeSignatureFromFile(onSignatureFile); - List>> offSignature = PrintUtils.deserializeSignatureFromFile(offSignatureFile); - - // LAN -// SignatureDetector onDetector = new SignatureDetector(onSignature, null); -// SignatureDetector offDetector = new SignatureDetector(offSignature, null); - // WAN - SignatureDetector onDetector = new SignatureDetector(onSignature, "128.195.205.105", 0); - SignatureDetector offDetector = new SignatureDetector(offSignature, "128.195.205.105", 0); - - final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM). - withLocale(Locale.US).withZone(ZoneId.of("America/Los_Angeles")); - - // Outputs information about a detected event to std.out - final Consumer outputter = ua -> { - String eventDescription; - switch (ua.getType()) { - case TOGGLE_ON: - eventDescription = "ON"; - break; - case TOGGLE_OFF: - eventDescription = "OFF"; - break; - default: - throw new AssertionError("unhandled event type"); - } - //String output = String.format("[ !!! %s SIGNATURE DETECTED at %s !!! ]", - // eventDescription, dateTimeFormatter.format(ua.getTimestamp())); - String output = String.format("%s", - dateTimeFormatter.format(ua.getTimestamp())); - System.out.println(output); - }; - - // Let's create observers that construct a UserAction representing the detected event. - final List detectedEvents = new ArrayList<>(); - onDetector.addObserver((searched, match) -> { - PcapPacket firstPkt = match.get(0).get(0); - detectedEvents.add(new UserAction(UserAction.Type.TOGGLE_ON, firstPkt.getTimestamp())); - }); - offDetector.addObserver((searched, match) -> { - PcapPacket firstPkt = match.get(0).get(0); - detectedEvents.add(new UserAction(UserAction.Type.TOGGLE_OFF, firstPkt.getTimestamp())); - }); - - PcapHandle handle; - try { - handle = Pcaps.openOffline(inputPcapFile, PcapHandle.TimestampPrecision.NANO); - } catch (PcapNativeException pne) { - handle = Pcaps.openOffline(inputPcapFile); - } - PcapHandleReader reader = new PcapHandleReader(handle, p -> true, onDetector, offDetector); - reader.readFromHandle(); - - // TODO: need a better way of triggering detection than this... - onDetector.mClusterMatchers.forEach(cm -> cm.performDetection()); - offDetector.mClusterMatchers.forEach(cm -> cm.performDetection()); - - // Sort the list of detected events by timestamp to make it easier to compare it line-by-line with the trigger - // times file. - Collections.sort(detectedEvents, Comparator.comparing(UserAction::getTimestamp)); - - // Output the detected events - detectedEvents.forEach(outputter); - - System.out.println("Number of detected events of type " + UserAction.Type.TOGGLE_ON + ": " + - detectedEvents.stream().filter(ua -> ua.getType() == UserAction.Type.TOGGLE_ON).count()); - System.out.println("Number of detected events of type " + UserAction.Type.TOGGLE_OFF + ": " + - detectedEvents.stream().filter(ua -> ua.getType() == UserAction.Type.TOGGLE_OFF).count()); - - - // TODO: Temporary clean up until we clean the pipeline -// List cleanedDetectedEvents = SignatureDetector.removeDuplicates(detectedEvents); -// cleanedDetectedEvents.forEach(outputter); - } - - /** - * The signature that this {@link SignatureDetector} is searching for. - */ - private final List>> mSignature; - - /** - * The {@link Layer3ClusterMatcher}s in charge of detecting each individual sequence of packets that together make up the - * the signature. - */ - private final List mClusterMatchers; - - /** - * For each {@code i} ({@code i >= 0 && i < pendingMatches.length}), {@code pendingMatches[i]} holds the matches - * found by the {@link Layer3ClusterMatcher} at {@code mClusterMatchers.get(i)} that have yet to be "consumed", i.e., - * have yet to be included in a signature detected by this {@link SignatureDetector} (a signature can be encompassed - * of multiple packet sequences occurring shortly after one another on multiple connections). - */ - private final List>[] pendingMatches; - - /** - * Maps a {@link Layer3ClusterMatcher} to its corresponding index in {@link #pendingMatches}. - */ - private final Map mClusterMatcherIds; - - private final List mObservers = new ArrayList<>(); - - private int mInclusionTimeMillis; - - /** - * Remove duplicates in {@code List} of {@code UserAction} objects. We need to clean this up for user actions - * that appear multiple times. - * TODO: This static method is probably just for temporary and we could get rid of this after we clean up - * TODO: the pipeline - * - * @param listUserAction A {@link List} of {@code UserAction}. - * - */ - public static List removeDuplicates(List listUserAction) { - - // Iterate and check for duplicates (check timestamps) - Set epochSecondSet = new HashSet<>(); - // Create a target list for cleaned up list - List listUserActionClean = new ArrayList<>(); - for(UserAction userAction : listUserAction) { - // Don't insert if any duplicate is found - if(!epochSecondSet.contains(userAction.getTimestamp().getEpochSecond())) { - listUserActionClean.add(userAction); - epochSecondSet.add(userAction.getTimestamp().getEpochSecond()); - } - } - return listUserActionClean; - } - - public SignatureDetector(List>> searchedSignature, String routerWanIp, int inclusionTimeMillis) { - // note: doesn't protect inner lists from changes :'( - mSignature = Collections.unmodifiableList(searchedSignature); - // Generate corresponding/appropriate ClusterMatchers based on the provided signature - List clusterMatchers = new ArrayList<>(); - for (List> cluster : mSignature) { - clusterMatchers.add(new Layer3ClusterMatcher(cluster, routerWanIp, this)); - } - mClusterMatchers = Collections.unmodifiableList(clusterMatchers); - - // < exploratory > - pendingMatches = new List[mClusterMatchers.size()]; - for (int i = 0; i < pendingMatches.length; i++) { - pendingMatches[i] = new ArrayList<>(); - } - Map clusterMatcherIds = new HashMap<>(); - for (int i = 0; i < mClusterMatchers.size(); i++) { - clusterMatcherIds.put(mClusterMatchers.get(i), i); - } - mClusterMatcherIds = Collections.unmodifiableMap(clusterMatcherIds); - mInclusionTimeMillis = - inclusionTimeMillis == 0 ? TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS : inclusionTimeMillis; - } - - public void addObserver(SignatureDetectionObserver observer) { - mObservers.add(observer); - } - - public boolean removeObserver(SignatureDetectionObserver observer) { - return mObservers.remove(observer); - } - - @Override - public void gotPacket(PcapPacket packet) { - // simply delegate packet reception to all ClusterMatchers. - mClusterMatchers.forEach(cm -> cm.gotPacket(packet)); - } - - @Override - public void onMatch(AbstractClusterMatcher clusterMatcher, List match) { - // Add the match at the corresponding index - pendingMatches[mClusterMatcherIds.get(clusterMatcher)].add(match); - checkSignatureMatch(); - } - - private void checkSignatureMatch() { - // << Graph-based approach using Balint's idea. >> - // This implementation assumes that the packets in the inner lists (the sequences) are ordered by asc timestamp. - - // There cannot be a signature match until each Layer3ClusterMatcher has found a match of its respective sequence. - if (Arrays.stream(pendingMatches).noneMatch(l -> l.isEmpty())) { - // Construct the DAG - final SimpleDirectedWeightedGraph graph = - new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class); - // Add a vertex for each match found by all ClusterMatchers - // And maintain an array to keep track of what cluster matcher each vertex corresponds to - final List[] vertices = new List[pendingMatches.length]; - for (int i = 0; i < pendingMatches.length; i++) { - vertices[i] = new ArrayList<>(); - for (List sequence : pendingMatches[i]) { - Vertex v = new Vertex(sequence); - vertices[i].add(v); // retain reference for later when we are to add edges - graph.addVertex(v); // add to vertex to graph - } - } - // Add dummy source and sink vertices to facilitate search. - final Vertex source = new Vertex(null); - final Vertex sink = new Vertex(null); - graph.addVertex(source); - graph.addVertex(sink); - // The source is connected to all vertices that wrap the sequences detected by Layer3ClusterMatcher at index 0. - // Note: zero cost edges as this is just a dummy link to facilitate search from a common start node. - for (Vertex v : vertices[0]) { - DefaultWeightedEdge edge = graph.addEdge(source, v); - graph.setEdgeWeight(edge, 0.0); - } - // Similarly, all vertices that wrap the sequences detected by the last Layer3ClusterMatcher of the signature - // are connected to the sink node. - for (Vertex v : vertices[vertices.length-1]) { - DefaultWeightedEdge edge = graph.addEdge(v, sink); - graph.setEdgeWeight(edge, 0.0); - } - // Now link sequences detected by Layer3ClusterMatcher at index i to sequences detected by Layer3ClusterMatcher at index - // i+1 if they obey the timestamp constraint (i.e., that the latter is later in time than the former). - for (int i = 0; i < vertices.length; i++) { - int j = i + 1; - if (j < vertices.length) { - for (Vertex iv : vertices[i]) { - PcapPacket ivLast = iv.sequence.get(iv.sequence.size()-1); - for (Vertex jv : vertices[j]) { - PcapPacket jvFirst = jv.sequence.get(jv.sequence.size()-1); - if (ivLast.getTimestamp().isBefore(jvFirst.getTimestamp())) { - DefaultWeightedEdge edge = graph.addEdge(iv, jv); - // The weight is the duration of the i'th sequence plus the duration between the i'th - // and i+1'th sequence. - Duration d = Duration. - between(iv.sequence.get(0).getTimestamp(), jvFirst.getTimestamp()); - // Unfortunately weights are double values, so must convert from long to double. - // TODO: need nano second precision? If so, use d.toNanos(). - // TODO: risk of overflow when converting from long to double..? - graph.setEdgeWeight(edge, Long.valueOf(d.toMillis()).doubleValue()); - } - // Alternative version if we cannot assume that sequences are ordered by timestamp: -// if (iv.sequence.stream().max(Comparator.comparing(PcapPacket::getTimestamp)).get() -// .getTimestamp().isBefore(jv.sequence.stream().min( -// Comparator.comparing(PcapPacket::getTimestamp)).get().getTimestamp())) { -// -// } - } - } - } - } - // Graph construction complete, run shortest-path to find a (potential) signature match. - DijkstraShortestPath dijkstra = new DijkstraShortestPath<>(graph); - GraphPath shortestPath = dijkstra.getPath(source, sink); - if (shortestPath != null) { - // The total weight is the duration between the first packet of the first sequence and the last packet - // of the last sequence, so we simply have to compare the weight against the timeframe that we allow - // the signature to span. For now we just use the inclusion window we defined for training purposes. - // Note however, that we must convert back from double to long as the weight is stored as a double in - // JGraphT's API. - if (((long)shortestPath.getWeight()) < mInclusionTimeMillis) { - // There's a signature match! - // Extract the match from the vertices - List> signatureMatch = new ArrayList<>(); - for(Vertex v : shortestPath.getVertexList()) { - if (v == source || v == sink) { - // Skip the dummy source and sink nodes. - continue; - } - signatureMatch.add(v.sequence); - // As there is a one-to-one correspondence between vertices[] and pendingMatches[], we know that - // the sequence we've "consumed" for index i of the matched signature is also at index i in - // pendingMatches. We must remove it from pendingMatches so that we don't use it to construct - // another signature match in a later call. - pendingMatches[signatureMatch.size()-1].remove(v.sequence); - } - // Declare success: notify observers - mObservers.forEach(obs -> obs.onSignatureDetected(mSignature, - Collections.unmodifiableList(signatureMatch))); - } - } - } - } - - /** - * Used for registering for notifications of signatures detected by a {@link SignatureDetector}. - */ - interface SignatureDetectionObserver { - - /** - * Invoked when the {@link SignatureDetector} detects the presence of a signature in the traffic that it's - * examining. - * @param searchedSignature The signature that the {@link SignatureDetector} reporting the match is searching - * for. - * @param matchingTraffic The actual traffic trace that matches the searched signature. - */ - void onSignatureDetected(List>> searchedSignature, - List> matchingTraffic); - } - - /** - * Encapsulates a {@code List} so as to allow the list to be used as a vertex in a graph while avoiding - * the expensive {@link AbstractList#equals(Object)} calls when adding vertices to the graph. - * Using this wrapper makes the incurred {@code equals(Object)} calls delegate to {@link Object#equals(Object)} - * instead of {@link AbstractList#equals(Object)}. The net effect is a faster implementation, but the graph will not - * recognize two lists that contain the same items--from a value and not reference point of view--as the same - * vertex. However, this is fine for our purposes -- in fact restricting it to reference equality seems more - * appropriate. - */ - private static class Vertex { - private final List sequence; - private Vertex(List wrappedSequence) { - sequence = wrappedSequence; - } - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/evaluation/DetectionResultsAnalyzer.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/evaluation/DetectionResultsAnalyzer.java deleted file mode 100644 index 34063d5..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/evaluation/DetectionResultsAnalyzer.java +++ /dev/null @@ -1,108 +0,0 @@ -package edu.uci.iotproject.evaluation; - -import edu.uci.iotproject.analysis.TriggerTrafficExtractor; -import edu.uci.iotproject.analysis.UserAction; -import edu.uci.iotproject.io.PrintWriterUtils; -import edu.uci.iotproject.io.TriggerTimesFileReader; - -import java.io.*; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -/** - * Utility for comparing detected events to logged (actual) events. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class DetectionResultsAnalyzer { - - private static boolean DUPLICATE_OUTPUT_TO_STD_OUT = true; - - public static void main(String[] args) throws IOException { - if (args.length < 3) { - String errMsg = String.format("Usage: %s triggerTimesFile detectionOutputFile [stdOut]" + - "\n - triggerTimesFile: the file that contains the timestamps for the user actions" + - "\n - detectionOutputFile: the file that contains the detected events" + - "\n - analysisResultsFile: where to write the results of the detection analysis" + - "\n - stdOut: optional true/false literal indicating if output should also be printed to std out; default is true", - DetectionResultsAnalyzer.class.getSimpleName()); - return; - } - String triggerTimesFile = args[0]; - File detectionOutputFile = new File(args[1]); - String analysisResultsFile = args[2]; - if (args.length > 3) { - DUPLICATE_OUTPUT_TO_STD_OUT = Boolean.parseBoolean(args[3]); - } - - // -------------------------------------- Parse the input files -------------------------------------- - - // Read the trigger times. - // The trigger times file does not contain event types as we initially assumed that we would just be alternating - // between ON and OFF. - List triggerTimestamps = new TriggerTimesFileReader().readTriggerTimes(triggerTimesFile, false); - // Now generate user actions based on this alternating ON/OFF pattern. - List triggers = new ArrayList<>(); - for (int i = 0; i < triggerTimestamps.size(); i++) { - // NOTE: assumes triggers alternate between ON and OFF - UserAction.Type actionType = i % 2 == 0 ? UserAction.Type.TOGGLE_ON : UserAction.Type.TOGGLE_OFF; - triggers.add(new UserAction(actionType, triggerTimestamps.get(i))); - } - // Read the detection output file, assuming a format as specified in UserAction.toString() - List detectedEvents = new ArrayList<>(); - try (BufferedReader br = new BufferedReader(new FileReader(detectionOutputFile))) { - String s; - while ((s = br.readLine()) != null) { - if (s.startsWith("#")) { - // Ignore comments. - continue; - } - detectedEvents.add(UserAction.fromString(s)); - } - } - - // ----------------- Now ready to compare the detected events with the logged events ----------------- - - // To contain all detected events that could be mapped to a trigger - List truePositives = new ArrayList<>(); - for (UserAction detectedEvent : detectedEvents) { - Optional matchingTrigger = triggers.stream() - .filter(t -> t.getType() == detectedEvent.getType() && - t.getTimestamp().isBefore(detectedEvent.getTimestamp()) && - t.getTimestamp().plusMillis(TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS). - isAfter(detectedEvent.getTimestamp()) - ).findFirst(); - matchingTrigger.ifPresent(mt -> { - // We've consumed the trigger (matched it with a detected event), so remove it so we don't match with - // another detected event. - triggers.remove(mt); - // The current detected event was a true positive as we could match it with a trigger. - truePositives.add(detectedEvent); - }); - } - // Now the false positives are those elements in detectedEvents that are not in truePositives - List falsePositives = new ArrayList<>(); - falsePositives.addAll(detectedEvents); - falsePositives.removeAll(truePositives); - - // Output the results... - PrintWriter outputter = new PrintWriter(new FileWriter(analysisResultsFile)); - PrintWriterUtils.println("---------- False negatives (events that where not detected) ----------", outputter, DUPLICATE_OUTPUT_TO_STD_OUT); - for (UserAction missing : triggers) { - PrintWriterUtils.println(missing, outputter, DUPLICATE_OUTPUT_TO_STD_OUT); - } - PrintWriterUtils.println("Total of " + Integer.toString(triggers.size()), outputter, DUPLICATE_OUTPUT_TO_STD_OUT); - PrintWriterUtils.printEmptyLine(outputter, DUPLICATE_OUTPUT_TO_STD_OUT); - PrintWriterUtils.println("---------- False positives (detected, but no matching trigger) ----------", outputter, DUPLICATE_OUTPUT_TO_STD_OUT); - for (UserAction fp : falsePositives) { - PrintWriterUtils.println(fp, outputter, DUPLICATE_OUTPUT_TO_STD_OUT); - } - PrintWriterUtils.println("Total of " + Integer.toString(falsePositives.size()), outputter, DUPLICATE_OUTPUT_TO_STD_OUT); - outputter.flush(); - outputter.close(); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/evaluation/SanitySignatureGenerator.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/evaluation/SanitySignatureGenerator.java deleted file mode 100644 index 060387a..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/evaluation/SanitySignatureGenerator.java +++ /dev/null @@ -1,121 +0,0 @@ -package edu.uci.iotproject.evaluation; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.trafficreassembly.layer3.TcpReassembler; -import edu.uci.iotproject.io.PcapHandleReader; -import edu.uci.iotproject.util.PrintUtils; -import org.pcap4j.core.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -/** - * Hacky utility for producing a sanity signature for negative test sets. - *

- * More precisely, given information about packet lengths and packet directions known to be present in an input trace, - * this class locates the first occurrence of a matching sequence in the input trace and outputs it to a file in the - * signature format (i.e., a {@code List>>}. - *

- *

- * Note: can only produce simplistic signatures, i.e., a signature that is a single packet sequence that - * occurs on a single TCP connection. - *

- * - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class SanitySignatureGenerator { - - public static void main(String[] args) throws PcapNativeException, NotOpenException { - // The pcap file - final String pcapPath = "/Users/varmarken/temp/UCI IoT Project/experiments/evaluation/negative-datasets/UNB/Monday-WorkingHours_one-local-endpoint.pcap"; - final String sigOutputPath = "/Users/varmarken/temp/UCI IoT Project/experiments/evaluation/negative-datasets/UNB/Monday-WorkingHours_one-local-endpoint_sanity.sig"; - // The sequence of packet lengths known to be present in the trace - final List pktLengths = new ArrayList<>(); - pktLengths.add(340); - pktLengths.add(295); - // ...and their corresponding directions - final List pktDirections = new ArrayList<>(); - pktDirections.add(Conversation.Direction.CLIENT_TO_SERVER); - pktDirections.add(Conversation.Direction.SERVER_TO_CLIENT); - // Is the signature a TLS sequence? - final boolean tlsSequence = false; - - - PcapHandle handle; - try { - handle = Pcaps.openOffline(pcapPath, PcapHandle.TimestampPrecision.NANO); - } catch (PcapNativeException pne) { - handle = Pcaps.openOffline(pcapPath); - } - SequenceFinder seqFinder = new SequenceFinder(pktLengths, pktDirections, tlsSequence, sigOutputPath); - final PcapHandleReader reader = new PcapHandleReader(handle, p -> true, seqFinder); - seqFinder.setPcapHandleReader(reader); - reader.readFromHandle(); - } - - - private static class SequenceFinder implements PacketListener { - private final TcpReassembler mTcpReassembler = new TcpReassembler(); - private final List mPktLengths; - private final List mPktDirections; - private final boolean mTlsSequence; - private PcapHandleReader mReader; - private final String mSignatureOutputPath; - - private SequenceFinder(List pktLengths, - List pktDirections, - boolean tlsSequence, - String sigOutputPath) { - mPktLengths = pktLengths; - mPktDirections = pktDirections; - mTlsSequence = tlsSequence; - mSignatureOutputPath = sigOutputPath; - } - - @Override - public void gotPacket(PcapPacket packet) { - // Skip packets not matching expected length - if (!mPktLengths.contains(packet.getOriginalLength())) { - return; - } - // Otherwise forward to TCP reassembler. - mTcpReassembler.gotPacket(packet); - // We are done as soon as we have one conversation that has the expected number of packets with the expected - // directions. - Optional match = mTcpReassembler.getTcpConversations().stream().filter(c -> { - List cPkts = mTlsSequence ? c.getTlsApplicationDataPackets() : c.getPackets(); - if (cPkts.size() != mPktLengths.size()) { - return false; - } - for (int i = 0; i < cPkts.size(); i++) { - if (c.getDirection(cPkts.get(i)) != mPktDirections.get(i) || - cPkts.get(i).getOriginalLength() != mPktLengths.get(i)) { - return false; - } - } - return true; - }).findFirst(); - if (match.isPresent()) { - System.out.println("match found"); - // Terminate reader; no need to process the full file as we already have the data to produce the signature. - mReader.stopReading(); - // Convert sequence to signature format. - List>> signature = new ArrayList<>(); - List> cluster = new ArrayList<>(); - List sequence = mTlsSequence ? match.get().getTlsApplicationDataPackets() : match.get().getPackets(); - cluster.add(sequence); - signature.add(cluster); - // Output the signature to a file. - PrintUtils.serializeSignatureIntoFile(mSignatureOutputPath, signature); - } - } - - private void setPcapHandleReader(PcapHandleReader reader) { - mReader = reader; - } - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/LiveCapture.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/LiveCapture.java deleted file mode 100644 index 2539415..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/LiveCapture.java +++ /dev/null @@ -1,102 +0,0 @@ -package edu.uci.iotproject.io; - -import org.pcap4j.core.*; -import org.pcap4j.packet.namednumber.DataLinkType; -import org.pcap4j.util.NifSelector; - -import java.io.IOException; -import java.util.Objects; - -/** - * Utility methods for setting up a {@link PcapHandleReader} that reads live traffic from a network interface card. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class LiveCapture { - - // This main method is just for experimental purposes! - public static void main(String[] args) throws PcapNativeException, NotOpenException, InterruptedException { - // ================================================ EXAMPLE USE ================================================ - final String outputPcapFile = System.getProperty("user.home") + "/temp/livecapture42.pcap"; - final PcapDumper outputter = Pcaps.openDead(DataLinkType.EN10MB, 65536).dumpOpen(outputPcapFile); - // Prompt user to select what interface we should be listening to; dump packets to a file. - PcapHandleReader reader = fromCliNicSelection( - p -> { - try { - outputter.dump(p); - } catch (NotOpenException noe) { - noe.printStackTrace(); - } - } - ); - - // Read on separate thread so that we can get a chance to terminate the reader on this thread. - Thread readerThread = new Thread(() -> { - try { - reader.readFromHandle(); - } catch (PcapNativeException e) { - e.printStackTrace(); - } catch (NotOpenException e) { - e.printStackTrace(); - } - }); - readerThread.start(); - - // Pause to let reader read some packets before we terminate it. - Thread.sleep(30_000); - - // Shutdown reader. - reader.stopReading(); - System.out.println("Waiting for " + reader.getClass().getSimpleName() + " to terminate..."); - while (!reader.hasTerminated()); - // remember to flush any buffered output - outputter.flush(); - System.out.println(reader.getClass().getSimpleName() + " terminated."); - // ============================================================================================================= - } - - /** - * Prompts the user to pick a Network Interface Card (NIC) for which live traffic is to be captured, then creates a - * {@link PcapHandleReader} that is ready to start capturing live traffic from that NIC. - * - * @param listeners One or more {@link PacketListener}s to which packets read from the NIC will be delivered. - * - * @return A {@link PcapHandleReader} that is ready to start capturing live traffic from the selected NIC or - * {@code null} if no NICs can be found. - * - * @throws PcapNativeException if an error occurs in the pcap native library. - */ - public static PcapHandleReader fromCliNicSelection(PacketListener... listeners) throws PcapNativeException { - PcapNetworkInterface networkInterface = null; - try { - networkInterface = new NifSelector().selectNetworkInterface(); - } catch (IOException ioe) { - System.err.println("No network interfaces found."); - ioe.printStackTrace(); - } - return networkInterface != null ? fromNic(networkInterface, listeners) : null; - } - - /** - * Creates a {@link PcapHandleReader} that is ready to start capturing live traffic from the provided Network - * Interface Card (NIC). - * - * @param networkInterface The target NIC. - * @param listeners One or more {@link PacketListener}s to which packets read from the NIC will be delivered. - * - * @return A {@link PcapHandleReader} that is ready to start capturing live traffic from the provided NIC. - * - * @throws PcapNativeException if an error occurs in the pcap native library. - */ - public static PcapHandleReader fromNic(PcapNetworkInterface networkInterface, PacketListener... listeners) - throws PcapNativeException { - Objects.requireNonNull(networkInterface); - int snapshotLength = 65536; // in bytes - int readTimeout = 10000; // 0 is infinite on all systems but Solaris - PcapHandle handle = networkInterface.openLive(snapshotLength, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, readTimeout); - // Supply a filter that accepts all packets (p -> true) as we want to examine all traffic. - return new PcapHandleReader(handle, p -> true, listeners); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/PcapHandleReader.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/PcapHandleReader.java deleted file mode 100644 index e52ce25..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/PcapHandleReader.java +++ /dev/null @@ -1,116 +0,0 @@ -package edu.uci.iotproject.io; - -import edu.uci.iotproject.analysis.PcapPacketFilter; -import org.pcap4j.core.*; - -import java.io.EOFException; -import java.util.concurrent.TimeoutException; - -/** - * Reads packets from a {@link PcapHandle} (online or offline) and delivers those packets that pass the test exercised - * by the provided {@link PcapPacketFilter} onto the provided {@link PacketListener}s. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class PcapHandleReader { - - private final PcapPacketFilter mPacketFilter; - private final PcapHandle mHandle; - private final PacketListener[] mPacketListeners; - private volatile boolean mTerminated = false; - - /** - * Create a {@code PcapHandleReader}. - * @param handle An open {@link PcapHandle} that packets will be read from. - * @param packetFilter A {@link PcapPacketFilter} that dictates which of the packets read from {@code handle} should - * be delivered to {@code packetListeners}. Note that while a value of {@code null} is not - * permitted here, the caller can instead simply provide an implementation that always returns - * {@code true} if they want to include all packets read from {@code handle}. - * @param packetListeners One or more {@link PacketListener}s to which those packets read from {@code handle} that - * pass through {@code packetFilter} are delivered. - */ - public PcapHandleReader(PcapHandle handle, PcapPacketFilter packetFilter, PacketListener... packetListeners) { - mHandle = handle; - mPacketFilter = packetFilter; - mPacketListeners = packetListeners; - } - - - /** - * Start reading (and filtering) packets from the provided {@link PcapHandle}. - * @throws PcapNativeException if an error occurs in the pcap native library. - * @throws NotOpenException if the provided {@code PcapHandle} is not open. - */ - public void readFromHandle() throws PcapNativeException, NotOpenException { - int outOfOrderPackets = 0; - try { - PcapPacket prevPacket = null; - PcapPacket packet = null; - - while (!mTerminated) { - try { - packet = mHandle.getNextPacketEx(); - } catch (TimeoutException te) { - System.err.println("timeout occurred while reading from network interface"); - // No need to check termination flag here. Can defer it to the loop condition as it is the next - // instruction anyway. - continue; - } - - if (packet == null) { - System.err.println("null-packet read from handle"); - continue; - } - - if (prevPacket != null && packet.getTimestamp().isBefore(prevPacket.getTimestamp())) { - outOfOrderPackets++; - /* - // Fail early if assumption doesn't hold. - mHandle.close(); - throw new AssertionError("Packets not in ascending temporal order"); - */ - } - if (mPacketFilter.shouldIncludePacket(packet)) { - // Packet accepted for inclusion; deliver it to observing client code. - for (PacketListener consumer : mPacketListeners) { - consumer.gotPacket(packet); - } - } - prevPacket = packet; - } - } catch (EOFException eof) { - // Reached end of file. All good. - System.out.println(String.format("%s: finished reading pcap file", getClass().getSimpleName())); - } - if (outOfOrderPackets > 0) { - System.err.println( - String.format("[[[ %s: %d packets appeared out of order (with regards to their timestamps) ]]]", - getClass().getSimpleName(), outOfOrderPackets)); - } - mHandle.close(); - } - - /** - * Stop reading from the wrapped {@link PcapHandle}. Note that this call only initiates the shutdown by - * setting a termination flag. Shutdown will be deferred until the time at which this flag can be checked by - * {@link #readFromHandle()}. For example, if {@link #readFromHandle()} is currently in the middle of a blocking - * call to {@link PcapHandle#getNextPacketEx()}, shutdown will not occur until the next packet is returned from the - * wrapped {@link PcapHandle} or its read timeout expires. Use {@link #hasTerminated()} to check if the shutdown - * has completed. - */ - public void stopReading() { - mTerminated = true; - } - - /** - * Checks if this {@link PcapHandleReader} has gracefully terminated, i.e., that the wrapped {@link PcapHandle} has - * been closed. - * - * @return {@code true} if this {@link PcapHandleReader} has terminated, {@code false} otherwise. - */ - public boolean hasTerminated() { - return mTerminated && !mHandle.isOpen(); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/PrintWriterUtils.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/PrintWriterUtils.java deleted file mode 100644 index 167993d..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/PrintWriterUtils.java +++ /dev/null @@ -1,43 +0,0 @@ -package edu.uci.iotproject.io; - -import java.io.PrintWriter; - -/** - * Utility methods for (jointly) printing to a {@link PrintWriter} (and standard output). - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public final class PrintWriterUtils { - - private PrintWriterUtils() { - // Disallow instantiation. Static-only class. - } - - /** - * Invoke {@link PrintWriter#println(Object)} passing {@code line} as argument while also printing {@code line} to - * standard output if {@code duplicateToStdOut} is {@code true}. - * @param line The line to be printed. - * @param writer The {@link PrintWriter} that is to print {@code line}. - * @param duplicateToStdOut Set to {@code true} if {@code line} should also be printed in standard output. - */ - public static void println(Object line, PrintWriter writer, boolean duplicateToStdOut) { - if (duplicateToStdOut) { - System.out.println(line); - } - writer.println(line); - } - - /** - * Make writer (and standard output, if {@code duplicateToStdOut} is {@code true}) print an empty line. - * @param writer The writer that {@link PrintWriter#println()} is to be invoked on. - * @param duplicateToStdOut If {@code true}, prints an empty line to standard output. - */ - public static void printEmptyLine(PrintWriter writer, boolean duplicateToStdOut) { - if (duplicateToStdOut) { - System.out.println(); - } - writer.println(); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/TriggerTimesFileReader.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/TriggerTimesFileReader.java deleted file mode 100644 index 75d06ec..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/io/TriggerTimesFileReader.java +++ /dev/null @@ -1,67 +0,0 @@ -package edu.uci.iotproject.io; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; - -/** - * Parses a file to obtain the timestamps at which the smart plug was toggled on/off. - * - * @author Rahmadi Trimananda {@literal } - * @author Janus Varmarken {@literal } - */ -public class TriggerTimesFileReader { - - public static final ZoneId ZONE_ID_LOS_ANGELES = ZoneId.of("America/Los_Angeles"); - public static final ZoneId ZONE_ID_BUDAPEST = ZoneId.of("Europe/Budapest"); - - /** - * Reads a file with trigger timestamps and parses the timestamps into {@link Instant}s using the rules specified - * by {@link #parseTriggerTimestamp(String, boolean)}. - * @param fileName The absolute path to the file with trigger timestamps. - * @param _24hFormat {@code true} if the timestamps in the file are in 24 hour format, {@code false} if they are in - * AM/PM format. - * @return A containing the trigger timestamps represented as {@code Instant}s. - */ - public List readTriggerTimes(String fileName, boolean _24hFormat) { - List listTriggerTimes = new ArrayList<>(); - File file = new File(fileName); - try (BufferedReader br = new BufferedReader(new FileReader(file))) { - String s; - while ((s = br.readLine()) != null) { - listTriggerTimes.add(parseTriggerTimestamp(s, _24hFormat)); - } - } catch (IOException e) { - e.printStackTrace(); - } - System.out.println("List has: " + listTriggerTimes.size()); - return listTriggerTimes; - } - - /** - * Parses a timestamp string to an {@link Instant} (UTC). Assumes timestamps are LA time. - * Format is expected to be either "MM/dd/uuuu HH:mm:ss" or "MM/dd/uuuu h:mm:ss a". - * - * @param timestampStr The string containing a date-time timestamp for LA's timezone. - * @param _24hFormat {@code true} if the time in {@code timestampStr} is given in 24 hour format, {@code false} if - * it is given in AM/PM format. - * @return An {@code Instant} representation of the parsed timestamp. Note that the {@code Instant} marks a point on - * the timeline in UTC. Use {@link Instant#atZone(ZoneId)} to convert to the corresponding time in a given - * timezone. - */ - public Instant parseTriggerTimestamp(String timestampStr, boolean _24hFormat) { - // Note: only one 'h' when not prefixed with leading 0 for 1-9; and only one 'a' for AM/PM marker in Java 8 time - String format = _24hFormat ? "MM/dd/uuuu HH:mm:ss" : "MM/dd/uuuu h:mm:ss a"; - LocalDateTime localDateTime = LocalDateTime.parse(timestampStr, DateTimeFormatter.ofPattern(format, Locale.US)); - ZonedDateTime laZonedDateTime = localDateTime.atZone(ZONE_ID_LOS_ANGELES); - return laZonedDateTime.toInstant(); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/maclayer/MacLayerFlowPattern.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/maclayer/MacLayerFlowPattern.java deleted file mode 100644 index 7cff733..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/maclayer/MacLayerFlowPattern.java +++ /dev/null @@ -1,46 +0,0 @@ -package edu.uci.iotproject.maclayer; - -import java.util.Collections; -import java.util.List; - -/** - * TODO create base class for FlowPattern and derive MacLayer, TCP/IP layer versions from that. - * - * @author Janus Varmarken - */ -public class MacLayerFlowPattern { - - private final List mPacketLengthSequence; - private final String mMacPrefix; - private final String mPatternId; - private final byte[] mMacPreixBytes; - - public MacLayerFlowPattern(String patternId, String macPrefix, List packetLengthSequence) { - mMacPrefix = macPrefix; - mPatternId = patternId; - mPacketLengthSequence = packetLengthSequence; - // Conversion provided by https://stackoverflow.com/a/10839361/1214974 - String[] addressParts = macPrefix.split(":"); - mMacPreixBytes = new byte[addressParts.length]; - for(int i = 0; i < mMacPreixBytes.length; i++) { - Integer hex = Integer.parseInt(addressParts[i], 16); - mMacPreixBytes[i] = hex.byteValue(); - } - } - - public String getPatternId() { - return mPatternId; - } - - public byte[] getMacPrefixRawBytes() { - return mMacPreixBytes; - } - - public List getPacketLengthSequence() { - return Collections.unmodifiableList(mPacketLengthSequence); - } - - public int getLength() { - return mPacketLengthSequence.size(); - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/maclayer/MacLayerFlowPatternFinder.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/maclayer/MacLayerFlowPatternFinder.java deleted file mode 100644 index 6cca3ad..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/maclayer/MacLayerFlowPatternFinder.java +++ /dev/null @@ -1,102 +0,0 @@ -package edu.uci.iotproject.maclayer; - -import edu.uci.iotproject.FlowPattern; -import org.pcap4j.core.NotOpenException; -import org.pcap4j.core.PcapHandle; -import org.pcap4j.core.PcapNativeException; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.RadiotapPacket; - -import java.io.EOFException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.TimeoutException; - -/** - * Performs a search for {@link FlowPattern} - * TODO: May want to create an abstract FlowPatternFinder and then derive MacLayer, TcpipLayer FlowPatternFinders from that one. - * - * @author Janus Varmarken - */ -public class MacLayerFlowPatternFinder { - - private final MacLayerFlowPattern mPattern; - private final PcapHandle mPcap; - - public MacLayerFlowPatternFinder(PcapHandle pcap, MacLayerFlowPattern pattern) { - this.mPcap = Objects.requireNonNull(pcap, - String.format("Argument of type '%s' cannot be null", PcapHandle.class.getSimpleName())); - this.mPattern = Objects.requireNonNull(pattern, - String.format("Argument of type '%s' cannot be null", FlowPattern.class.getSimpleName())); - } - - public void findFlowPattern() { - PcapPacket packet; - try { - // Packets matched to flow pattern searched for. - List patternPackets = new ArrayList<>(); - while ((packet = mPcap.getNextPacketEx()) != null) { - RadiotapPacket radiotapPacket; - try { - // Some packets throw an IAE with message "msi must be between 0 and 6 but is actually: 7" - // when accessing the RadiotapPacket. - radiotapPacket = packet.get(RadiotapPacket.class); - } catch (IllegalArgumentException iae) { - System.out.println(iae.getMessage()); - continue; - } - if (radiotapPacket == null) { - continue; - } - // Restart search if pattern not found within reasonable time frame (hardcoded for now). - if (patternPackets.size() > 0 && packet.getTimestamp().getEpochSecond() - - patternPackets.get(patternPackets.size()-1).getTimestamp().getEpochSecond() > 2) { - patternPackets = new ArrayList<>(); - } - - byte[] rawData = radiotapPacket.getPayload().getRawData(); - // Search rawData for MAC of FlowPattern in sender/receiver section - // [TODO needs verification that this section is actually the sender/receiver section] - if (rawData.length < 16) { - continue; - } - int prefixLength = mPattern.getMacPrefixRawBytes().length; - byte[] mac1 = Arrays.copyOfRange(rawData, 4, prefixLength < 6 ? 4 + prefixLength : 10); - byte[] mac2 = Arrays.copyOfRange(rawData, 10, prefixLength < 6 ? 10 + prefixLength : 16); - if (!Arrays.equals(mac1, mPattern.getMacPrefixRawBytes()) && !Arrays.equals(mac2, mPattern.getMacPrefixRawBytes())) { - // MAC prefix not present in raw data. - continue; - } - // Packet related to device associated with the pattern we are looking for. - int expectedLength = mPattern.getPacketLengthSequence().get(patternPackets.size()); - if (packet.length() == expectedLength) { - patternPackets.add(packet); - if (patternPackets.size() == mPattern.getLength()) { - // Full pattern found, declare success if packets are within some reasonable amount of time of - // one another. - // For now, we use a hardcoded value. - if (patternPackets.get(patternPackets.size()-1).getTimestamp().getEpochSecond() - - patternPackets.get(0).getTimestamp().getEpochSecond() < 5) { - System.out.println(String.format("[ find ] Detected a COMPLETE MATCH of pattern '%s' at %s!", - mPattern.getPatternId(), patternPackets.get(0).getTimestamp().toString())); - } - // Reset search by resetting list. - patternPackets = new ArrayList<>(); - } - } else { - // Discard packet, not relevant to pattern. - continue; - } - } - } catch (EOFException e) { - // TODO wait for, and print, results. - } catch (PcapNativeException|TimeoutException|NotOpenException e) { - e.printStackTrace(); - } - } - -} - - diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2Flow.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2Flow.java deleted file mode 100644 index f8c3237..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2Flow.java +++ /dev/null @@ -1,115 +0,0 @@ -package edu.uci.iotproject.trafficreassembly.layer2; - -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.EthernetPacket; -import org.pcap4j.util.MacAddress; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Models a layer 2 flow: groups packets exchanged between two specific endpoints (MAC addresses). - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class Layer2Flow { - - /** - * The first endpoint of this layer 2 flow. - */ - private final MacAddress mEndpoint1; - - /** - * The second endpoint of this layer 2 flow. - */ - private final MacAddress mEndpoint2; - - /** - * Clients observing for changes to this layer 2 flow. - */ - private final List mFlowObservers = new ArrayList<>(); - - public Layer2Flow(MacAddress endpoint1, MacAddress endpoint2) { - mEndpoint1 = endpoint1; - mEndpoint2 = endpoint2; - } - - /** - * Get the first endpoint of this flow. - * @return the first endpoint of this flow. - */ - public MacAddress getEndpoint1() { - return mEndpoint1; - } - - /** - * Get the second endpoint of this flow. - * @return the second endpoint of this flow. - */ - public MacAddress getEndpoint2() { - return mEndpoint2; - } - - /** - * Register as an observer of this flow. - * @param observer The client that is to be notified whenever this flow changes (has new packets added). - */ - public void addFlowObserver(Layer2FlowObserver observer) { - mFlowObservers.add(observer); - } - - /** - * Deregister as an observer of this flow. - * @param observer The client that no longer wishes to be notified whenever this flow changes. - */ - public void removeFlowObserver(Layer2FlowObserver observer) { - mFlowObservers.remove(observer); - } - - /** - * The packets in the flow. - */ - private final List mPackets = new ArrayList<>(); - - /** - * Add a packet to this flow. - * @param packet The packet that is to be added to the flow. - */ - public void addPacket(PcapPacket packet) { - verifyAddresses(packet); - mPackets.add(packet); - // Notify flow observers of the new packet - mFlowObservers.forEach(o -> o.onNewPacket(this, packet)); - } - - /** - * Get the packets pertaining to this flow. - * @return The packets pertaining to this flow. - */ - public List getPackets() { - return Collections.unmodifiableList(mPackets); - } - - /** - * Verify that a packet pertains to this flow. - * @param packet The packet that is to be verified. - */ - private void verifyAddresses(PcapPacket packet) { - EthernetPacket ethPkt = packet.get(EthernetPacket.class); - MacAddress srcAddr = ethPkt.getHeader().getSrcAddr(); - MacAddress dstAddr = ethPkt.getHeader().getDstAddr(); - if ((mEndpoint1.equals(srcAddr) && mEndpoint2.equals(dstAddr)) || - (mEndpoint1.equals(dstAddr) && mEndpoint2.equals(srcAddr))) { - // All is good. - return; - } - throw new IllegalArgumentException("Mismatch in MACs: packet does not pertain to this flow"); - } - - @Override - public String toString() { - return getClass().getSimpleName() + String.format(" with mEndpoint1=%s and mEndpoint2=%s", mEndpoint1, mEndpoint2); - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowObserver.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowObserver.java deleted file mode 100644 index e1648ba..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowObserver.java +++ /dev/null @@ -1,20 +0,0 @@ -package edu.uci.iotproject.trafficreassembly.layer2; - -import org.pcap4j.core.PcapPacket; - -/** - * Interface for observing a {@link Layer2Flow}. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public interface Layer2FlowObserver { - - /** - * Invoked when a new packet is added to the observed flow. - * @param flow The observed flow. - * @param newPacket The packet that was added to the flow. - */ - void onNewPacket(Layer2Flow flow, PcapPacket newPacket); - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowReassembler.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowReassembler.java deleted file mode 100644 index e7b7304..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowReassembler.java +++ /dev/null @@ -1,86 +0,0 @@ -package edu.uci.iotproject.trafficreassembly.layer2; - -import edu.uci.iotproject.trafficreassembly.layer2.Layer2Flow; -import edu.uci.iotproject.trafficreassembly.layer2.Layer2FlowReassemblerObserver; -import org.pcap4j.core.PacketListener; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.EthernetPacket; -import org.pcap4j.util.MacAddress; - -import java.util.*; - -/** - * Reassembles traffic flows at layer 2, i.e., for each combination of hosts, creates a list of packets exchanged - * between said hosts. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class Layer2FlowReassembler implements PacketListener { - - /** - * Maps a pair of MAC addresses to the packets exchanged between the two hosts. - * The key is the concatenation of the two MAC addresses in hex string format, where the lexicographically smaller - * MAC is at the front of the string. - */ - private final Map mFlows = new HashMap<>(); - - private final List mObservers = new ArrayList<>(); - - @Override - public void gotPacket(PcapPacket packet) { - // TODO: update to 802.11 packet...? - EthernetPacket ethPkt = packet.get(EthernetPacket.class); - - MacAddress srcAddr = ethPkt.getHeader().getSrcAddr(); - MacAddress dstAddr = ethPkt.getHeader().getDstAddr(); - - String key = keyFromAddresses(srcAddr, dstAddr); - // Create a new list if this pair of MAC addresses where not previously encountered and add packet to that list, - // or simply add to an existing list if one is present. - mFlows.computeIfAbsent(key, k -> { - Layer2Flow newFlow = new Layer2Flow(srcAddr, dstAddr); - // Inform observers of the new flow - mObservers.forEach(o -> o.onNewFlow(this, newFlow)); - return newFlow; - }).addPacket(packet); - } - - public void addObserver(Layer2FlowReassemblerObserver observer) { - mObservers.add(observer); - } - - public void removeObserver(Layer2FlowReassemblerObserver observer) { - mObservers.remove(observer); - } - - /** - * Get the traffic flow between two local endpoints ({@link MacAddress}es). - * @param addr1 The first endpoint. - * @param addr2 The second endpoint - * @return The traffic exchanged between the two endpoints. - */ - public Layer2Flow getFlowForAddresses(MacAddress addr1, MacAddress addr2) { - return mFlows.get(keyFromAddresses(addr1, addr2)); - } - - /** - * Get all traffic flows, i.e., a traffic flow for each unique pair of endpoints (MAC addresses). - * @return All traffic flows. - */ - public Collection getFlows() { - return mFlows.values(); - } - - /** - * Given two {@link MacAddress}es, generates the corresponding key string used in {@link #mFlows}. - * @param addr1 The first address. - * @param addr2 The second address. - * @return the key string used in {@link #mFlows} corresponding to the two addresses. - */ - private String keyFromAddresses(MacAddress addr1, MacAddress addr2) { - String addr1Str = addr1.toString(); - String addr2Str = addr2.toString(); - return addr1Str.compareTo(addr2Str) < 0 ? addr1Str + addr2Str : addr2Str + addr1Str; - } -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowReassemblerObserver.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowReassemblerObserver.java deleted file mode 100644 index a71cd19..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer2/Layer2FlowReassemblerObserver.java +++ /dev/null @@ -1,19 +0,0 @@ -package edu.uci.iotproject.trafficreassembly.layer2; - -/** - * For observing a {@link Layer2FlowReassembler}. - * - * @author Janus Varmarken - */ -public interface Layer2FlowReassemblerObserver { - - /** - * Invoked when when a {@link Layer2FlowReassembler} detects a new flow (i.e., when it encounters traffic between two - * MAC addresses that has not previously communicated in the traffic trace). - * - * @param reassembler The {@link Layer2FlowReassembler} that detected the new flow. - * @param newFlow The new flow. - */ - void onNewFlow(Layer2FlowReassembler reassembler, Layer2Flow newFlow); - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/Conversation.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/Conversation.java deleted file mode 100644 index e89e81b..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/Conversation.java +++ /dev/null @@ -1,585 +0,0 @@ -package edu.uci.iotproject.trafficreassembly.layer3; - -import edu.uci.iotproject.analysis.TcpConversationUtils; -import edu.uci.iotproject.util.PcapPacketUtils; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.IpV4Packet; -import org.pcap4j.packet.Packet; -import org.pcap4j.packet.TcpPacket; - -import java.util.*; - -/** - * Models a (TCP) conversation/connection/session/flow (packet's belonging to the same session between a client and a - * server). - * Holds a list of {@link PcapPacket}s identified as pertaining to the flow. Note that this list is not - * considered when determining equality of two {@code Conversation} instances in order to allow for a - * {@code Conversation} to function as a key in data structures such as {@link java.util.Map} and {@link java.util.Set}. - * See {@link #equals(Object)} for the definition of equality. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class Conversation { - - /* Begin instance properties */ - /** - * The IP of the host that is considered the client (i.e. the host that initiates the conversation) - * in this conversation. - */ - private final String mClientIp; - - /** - * The port number used by the host that is considered the client in this conversation. - */ - private final int mClientPort; - - /** - * The IP of the host that is considered the server (i.e. is the responder) in this conversation. - */ - private final String mServerIp; - - /** - * The port number used by the server in this conversation. - */ - private final int mServerPort; - - /** - * The list of packets (with payload) pertaining to this conversation. - */ - private final List mPackets; - - /** - * If {@link #isTls()} is {@code true}, this list contains the subset of {@link #mPackets} which are TLS Application - * Data packets. - */ - private final List mTlsApplicationDataPackets; - - /** - * Contains the sequence numbers used thus far by the host that is considered the client in this - * {@code Conversation}. - * Used for filtering out retransmissions. - */ - private final Set mSeqNumbersClient; - - /** - * Contains the sequence numbers used thus far by the host that is considered the server in this - * {@code Conversation}. - * Used for filtering out retransmissions. - */ - private final Set mSeqNumbersSrv; - - /** - * List of SYN packets pertaining to this conversation. - */ - private final List mSynPackets; - - /** - * List of pairs FINs and their corresponding ACKs associated with this conversation. - */ - private final List mFinPackets; - - /** - * List of RST packets associated with this conversation. - */ - private final List mRstPackets; - - /** - * Boolean to mark the packet as Application Data based on the previous packet that reaches MTU - */ - private boolean mApplicationData; - /* End instance properties */ - - /** - * Factory method for creating a {@code Conversation} from a {@link PcapPacket}. - * @param pcapPacket The {@code PcapPacket} that wraps a TCP segment for which a {@code Conversation} is to be initiated. - * @param clientIsSrc If {@code true}, the source address and source port found in the IP datagram and TCP segment - * wrapped in the {@code PcapPacket} are regarded as pertaining to the client, and the destination - * address and destination port are regarded as pertaining to the server---and vice versa if set - * to {@code false}. - * @return A {@code Conversation} initiated with ip:port for client and server according to the direction of the packet. - */ - public static Conversation fromPcapPacket(PcapPacket pcapPacket, boolean clientIsSrc) { - IpV4Packet ipPacket = pcapPacket.get(IpV4Packet.class); - TcpPacket tcpPacket = pcapPacket.get(TcpPacket.class); - String clientIp = clientIsSrc ? ipPacket.getHeader().getSrcAddr().getHostAddress() : - ipPacket.getHeader().getDstAddr().getHostAddress(); - String srvIp = clientIsSrc ? ipPacket.getHeader().getDstAddr().getHostAddress() : - ipPacket.getHeader().getSrcAddr().getHostAddress(); - int clientPort = clientIsSrc ? tcpPacket.getHeader().getSrcPort().valueAsInt() : - tcpPacket.getHeader().getDstPort().valueAsInt(); - int srvPort = clientIsSrc ? tcpPacket.getHeader().getDstPort().valueAsInt() : - tcpPacket.getHeader().getSrcPort().valueAsInt(); - return new Conversation(clientIp, clientPort, srvIp, srvPort); - } - - /** - * Constructs a new {@code Conversation}. - * @param clientIp The IP of the host that is considered the client (i.e. the host that initiates the conversation) - * in the conversation. - * @param clientPort The port number used by the client for the conversation. - * @param serverIp The IP of the host that is considered the server (i.e. is the responder) in the conversation. - * @param serverPort The port number used by the server for the conversation. - */ - public Conversation(String clientIp, int clientPort, String serverIp, int serverPort) { - this.mClientIp = clientIp; - this.mClientPort = clientPort; - this.mServerIp = serverIp; - this.mServerPort = serverPort; - this.mPackets = new ArrayList<>(); - this.mTlsApplicationDataPackets = new ArrayList<>(); - this.mSeqNumbersClient = new HashSet<>(); - this.mSeqNumbersSrv = new HashSet<>(); - this.mSynPackets = new ArrayList<>(); - this.mFinPackets = new ArrayList<>(); - this.mRstPackets = new ArrayList<>(); - this.mApplicationData = false; - } - - /** - * Add a packet to the list of packets associated with this conversation. - * @param packet The packet that is to be added to (associated with) this conversation. - * @param ignoreRetransmissions Boolean value indicating if retransmissions should be ignored. - * If set to {@code true}, {@code packet} will not be added to the - * internal list of packets pertaining to this {@code Conversation} - * iff the sequence number of {@code packet} was already - * seen in a previous packet. - */ - public void addPacket(PcapPacket packet, boolean ignoreRetransmissions) { - // Precondition: verify that packet does indeed pertain to conversation. - onAddPrecondition(packet); - if (ignoreRetransmissions && isRetransmission(packet)) { - // Packet is a retransmission. Ignore it. - return; - } - // Select direction-dependent set of sequence numbers seen so far and update it with sequence number of new packet. - addSeqNumber(packet); - // Finally add packet to list of packets pertaining to this conversation. - mPackets.add(packet); - // Preserve order of packets in list: sort according to timestamp. - if (mPackets.size() > 1 && - mPackets.get(mPackets.size()-1).getTimestamp().isBefore(mPackets.get(mPackets.size()-2).getTimestamp())) { - Collections.sort(mPackets, (o1, o2) -> { - if (o1.getTimestamp().isBefore(o2.getTimestamp())) { return -1; } - else if (o2.getTimestamp().isBefore(o1.getTimestamp())) { return 1; } - else { return 0; } - }); - } - // If TLS, inspect packet to see if it's a TLS Application Data packet, and if so add it to the list of TLS - // Application Data packets. - if (isTls()) { - TcpPacket tcpPacket = packet.get(TcpPacket.class); - Packet tcpPayload = tcpPacket.getPayload(); - if (tcpPayload == null) { - return; - } - byte[] rawPayload = tcpPayload.getRawData(); - // The SSL record header is at the front of the payload and is 5 bytes long. - // The SSL record header type field (the first byte) is set to 23 if it is an Application Data packet. - if (rawPayload != null && rawPayload.length >= 5) { - if (rawPayload[0] == 23) { - mTlsApplicationDataPackets.add(packet); - // Consider the following packet a data packet if this packet's size == MTU size 1448 - if (rawPayload.length >= 1448) - mApplicationData = true; - } else if (rawPayload[0] == 20) { - // Do nothing for now - CHANGE_CIPHER_SPEC - } else if (rawPayload[0] == 21) { - // Do nothing for now - ALERT - } else if (rawPayload[0] == 22) { - // Do nothing for now - HANDSHAKE - } else { - // If it is TLS with payload, but rawPayload[0] != 23 - if (mApplicationData == true) { - // It is a continuation of the previous packet if the previous packet reaches MTU size 1448 and - // it is not either type 20, 21, or 22 - mTlsApplicationDataPackets.add(packet); - if (rawPayload.length < 1448) - mApplicationData = false; - } - } - } - } - } - - /** - * Get a list of packets pertaining to this {@code Conversation}. - * The returned list is a read-only list. - * @return the list of packets pertaining to this {@code Conversation}. - */ - public List getPackets() { - // Return read-only view to prevent external code from manipulating internal state (preserve invariant). - return Collections.unmodifiableList(mPackets); - } - - /** - * Records a TCP SYN packet as pertaining to this conversation (adds it to the the internal list). - * Attempts to add duplicate SYN packets will be ignored, and the caller is made aware of the attempt to add a - * duplicate by the return value being {@code false}. - * - * @param synPacket A {@link PcapPacket} wrapping a TCP SYN packet. - * @return {@code true} if the packet was successfully added to this {@code Conversation}, {@code false} otherwise. - */ - public boolean addSynPacket(PcapPacket synPacket) { - onAddPrecondition(synPacket); - final IpV4Packet synPacketIpSection = synPacket.get(IpV4Packet.class); - final TcpPacket synPacketTcpSection = synPacket.get(TcpPacket.class); - if (synPacketTcpSection == null || !synPacketTcpSection.getHeader().getSyn()) { - throw new IllegalArgumentException("Not a SYN packet."); - } - // We are only interested in recording one copy of the two SYN packets (one SYN packet in each direction), i.e., - // we want to discard retransmitted SYN packets. - if (mSynPackets.size() >= 2) { - return false; - } - // Check the set of recorded SYN packets to see if we have already recorded a SYN packet going in the same - // direction as the packet given in the argument. - boolean matchingPrevSyn = mSynPackets.stream().anyMatch(p -> { - IpV4Packet pIp = p.get(IpV4Packet.class); - TcpPacket pTcp = p.get(TcpPacket.class); - boolean srcAddrMatch = synPacketIpSection.getHeader().getSrcAddr().getHostAddress(). - equals(pIp.getHeader().getSrcAddr().getHostAddress()); - boolean dstAddrMatch = synPacketIpSection.getHeader().getDstAddr().getHostAddress(). - equals(pIp.getHeader().getDstAddr().getHostAddress()); - boolean srcPortMatch = synPacketTcpSection.getHeader().getSrcPort().valueAsInt() == - pTcp.getHeader().getSrcPort().valueAsInt(); - boolean dstPortMatch = synPacketTcpSection.getHeader().getDstPort().valueAsInt() == - pTcp.getHeader().getDstPort().valueAsInt(); - return srcAddrMatch && dstAddrMatch && srcPortMatch && dstPortMatch; - }); - if (matchingPrevSyn) { - return false; - } - // Update direction-dependent set of sequence numbers and record/log packet. - addSeqNumber(synPacket); - return mSynPackets.add(synPacket); - - /* - mSynPackets.stream().anyMatch(p -> { - IpV4Packet pIp = p.get(IpV4Packet.class); - TcpPacket pTcp = p.get(TcpPacket.class); - boolean srcAddrMatch = synPacketIpSection.getHeader().getSrcAddr().getHostAddress(). - equals(pIp.getHeader().getSrcAddr().getHostAddress()); - boolean dstAddrMatch = synPacketIpSection.getHeader().getDstAddr().getHostAddress(). - equals(pIp.getHeader().getDstAddr().getHostAddress()); - boolean srcPortMatch = synPacketTcpSection.getHeader().getSrcPort().valueAsInt() == - pTcp.getHeader().getSrcPort().valueAsInt(); - boolean dstPortMatch = synPacketTcpSection.getHeader().getDstPort().value() == - pTcp.getHeader().getDstPort().value(); - - boolean fourTupleMatch = srcAddrMatch && dstAddrMatch && srcPortMatch && dstPortMatch; - - boolean seqNoMatch = synPacketTcpSection.getHeader().getSequenceNumber() == - pTcp.getHeader().getSequenceNumber(); - - if (fourTupleMatch && !seqNoMatch) { - // If the four tuple that identifies the conversation matches, but the sequence number is different, - // it means that this SYN packet is, in fact, an attempt to establish a **new** connection, and hence - // the given packet is NOT part of this conversation, even though the ip:port combinations are (by - // chance) selected such that they match this conversation. - throw new IllegalArgumentException("Attempt to add SYN packet that belongs to a different conversation " + - "(which is identified by the same four tuple as this conversation)"); - } - return fourTupleMatch && seqNoMatch; - }); - */ - } - - /** - * Get a list of SYN packets pertaining to this {@code Conversation}. - * The returned list is a read-only list. - * @return the list of SYN packets pertaining to this {@code Conversation}. - */ - public List getSynPackets() { - return Collections.unmodifiableList(mSynPackets); - } - - /** - * Adds a TCP FIN packet to the list of TCP FIN packets associated with this conversation. - * @param finPacket The TCP FIN packet that is to be added to (associated with) this conversation. - */ - public void addFinPacket(PcapPacket finPacket) { - // Precondition: verify that packet does indeed pertain to conversation. - onAddPrecondition(finPacket); - // TODO: should call addSeqNumber here? - addSeqNumber(finPacket); - mFinPackets.add(new FinAckPair(finPacket)); - } - - /** - * Attempt to ACK any FIN packets held by this conversation. - * @param ackPacket The ACK for a FIN previously added to this conversation. - */ - public void attemptAcknowledgementOfFin(PcapPacket ackPacket) { - // Precondition: verify that the packet pertains to this conversation. - onAddPrecondition(ackPacket); - // Mark unack'ed FIN(s) that this ACK matches as ACK'ed (there might be more than one in case of retransmissions..?) - mFinPackets.replaceAll(finAckPair -> !finAckPair.isAcknowledged() && finAckPair.isCorrespondingAckPacket(ackPacket) ? new FinAckPair(finAckPair.getFinPacket(), ackPacket) : finAckPair); - } - - /** - * Retrieves an unmodifiable view of the list of {@link FinAckPair}s associated with this {@code Conversation}. - * @return an unmodifiable view of the list of {@link FinAckPair}s associated with this {@code Conversation}. - */ - public List getFinAckPairs() { - return Collections.unmodifiableList(mFinPackets); - } - - /** - * Get if this {@code Conversation} is considered to have been gracefully shut down. - * A {@code Conversation} has been gracefully shut down if it contains a FIN+ACK pair for both directions - * (client to server, and server to client). - * @return {@code true} if the connection has been gracefully shut down, false otherwise. - */ - public boolean isGracefullyShutdown() { - // The conversation has been gracefully shut down if we have recorded a FIN from both the client and the server which have both been ack'ed. - return mFinPackets.stream().anyMatch(finAckPair -> finAckPair.isAcknowledged() && PcapPacketUtils.isSource(finAckPair.getFinPacket(), mClientIp, mClientPort)) && - mFinPackets.stream().anyMatch(finAckPair -> finAckPair.isAcknowledged() && PcapPacketUtils.isSource(finAckPair.getFinPacket(), mServerIp, mServerPort)); - } - - /** - * Add a TCP segment for which the RST flag is set to this {@code Conversation}. - * @param packet A {@link PcapPacket} wrapping a TCP segment pertaining to this {@code Conversation} for which the - * RST flag is set. - */ - public void addRstPacket(PcapPacket packet) { - /* - * TODO: - * When now also keeping track of RST packets, should we also...? - * 1) Prevent later packets from being added once a RST segment has been added? - * 2) Extend 'isGracefullyShutdown()' to also consider RST segments, or add another method, 'isShutdown()' that - * both considers FIN/ACK (graceful) as well as RST (abrupt/"ungraceful") shutdown? - * 3) Should it be impossible to associate more than one RST segment with each Conversation? - */ - onAddPrecondition(packet); - TcpPacket tcpPacket = packet.get(TcpPacket.class); - if (tcpPacket == null || !tcpPacket.getHeader().getRst()) { - throw new IllegalArgumentException("not a RST packet"); - } - mRstPackets.add(packet); - } - - /** - * Get the TCP segments pertaining to this {@code Conversation} for which it was detected that the RST flag is set. - * @return the TCP segments pertaining to this {@code Conversation} for which it was detected that the RST flag is - * set. - */ - public List getRstPackets() { - return Collections.unmodifiableList(mRstPackets); - } - - // ========================================================================================================= - // We simply reuse equals and hashCode methods of String.class to be able to use this class as a key - // in a Map. - - /** - * Note: currently, equality is determined based on pairwise equality of the elements of the four tuple - * ({@link #mClientIp}, {@link #mClientPort}, {@link #mServerIp}, {@link #mServerPort}) for {@code this} and - * {@code obj}. - * @param obj The object to test for equality with {@code this}. - * @return {@code true} if {@code obj} is considered equal to {@code this} based on the definition of equality given above. - */ - @Override - public boolean equals(Object obj) { - return obj instanceof Conversation && this.toString().equals(obj.toString()); - } - - @Override - public int hashCode() { - return toString().hashCode(); - } - // ========================================================================================================= - - @Override - public String toString() { - return String.format("%s:%d %s:%d", mClientIp, mClientPort, mServerIp, mServerPort); - } - - /** - * Invoke to verify that the precondition holds when a caller attempts to add a packet to this {@code Conversation}. - * An {@link IllegalArgumentException} is thrown if the precondition is violated. - * @param packet the packet to be added to this {@code Conversation} - */ - private void onAddPrecondition(PcapPacket packet) { - // Apply precondition to preserve class invariant: all packets in mPackets must match the 4 tuple that - // defines the conversation. - IpV4Packet ipPacket = Objects.requireNonNull(packet.get(IpV4Packet.class)); - // For now we only support TCP flows. - TcpPacket tcpPacket = Objects.requireNonNull(packet.get(TcpPacket.class)); - String ipSrc = ipPacket.getHeader().getSrcAddr().getHostAddress(); - String ipDst = ipPacket.getHeader().getDstAddr().getHostAddress(); - int srcPort = tcpPacket.getHeader().getSrcPort().valueAsInt(); - int dstPort = tcpPacket.getHeader().getDstPort().valueAsInt(); - String clientIp, serverIp; - int clientPort, serverPort; - if (ipSrc.equals(mClientIp)) { - clientIp = ipSrc; - clientPort = srcPort; - serverIp = ipDst; - serverPort = dstPort; - } else { - clientIp = ipDst; - clientPort = dstPort; - serverIp = ipSrc; - serverPort = srcPort; - } - if (!(clientIp.equals(mClientIp) && clientPort == mClientPort && - serverIp.equals(mServerIp) && serverPort == mServerPort)) { - throw new IllegalArgumentException( - String.format("Attempt to add packet that does not pertain to %s", - Conversation.class.getSimpleName())); - } - } - - /** - *

- * Determines if the TCP packet contained in {@code packet} is a retransmission of a previously seen (logged) - * packet. - *

- * - * - * TODO: - * the current implementation, which uses a set of previously seen sequence numbers, will consider a segment - * with a reused sequence number---occurring as a result of sequence number wrap around for a very long-lived - * connection---as a retransmission (and may therefore end up discarding it even though it is in fact NOT a - * retransmission). Ideas? - * - * - * @param packet The packet. - * @return {@code true} if {@code packet} was determined to be a retransmission, {@code false} otherwise. - */ - public boolean isRetransmission(PcapPacket packet) { - // Extract sequence number. - int seqNo = packet.get(TcpPacket.class).getHeader().getSequenceNumber(); - switch (getDirection(packet)) { - case CLIENT_TO_SERVER: - return mSeqNumbersClient.contains(seqNo); - case SERVER_TO_CLIENT: - return mSeqNumbersSrv.contains(seqNo); - default: - throw new AssertionError(String.format("Unexpected value of enum '%s'", - Direction.class.getSimpleName())); - } - } - - /** - *

- * Is this {@code Conversation} a TLS session? - *

- * - * Note: the current implementation simply examines the port number(s) for 443; it does not verify if the - * application data is indeed encrypted. - * - * @return {@code true} if this {@code Conversation} is interpreted as a TLS session, {@code false} otherwise. - */ - public boolean isTls() { - /* - * TODO: - * - may want to change this to be "return mServerPort == 443 || mClientPort == 443;" in order to also detect - * TLS in those cases where it is not possible to correctly label who is the client and who is the server, - * i.e., when the trace does not contain the SYN/SYNACK exchange. - * - current implementation relies on the server using the conventional TLS port number; may instead want to - * inspect the first 4 bytes of each potential TLS packet to see if they match the SSL record header. - * - * 08/31/18: Added unconvetional TLS ports used by WeMo plugs and LiFX bulb. - * 09/20/18: Moved hardcoded ports to other class to allow other classes to query the set of TLS ports. - */ - return TcpConversationUtils.isTlsPort(mServerPort); - } - - /** - * If this {@code Conversation} is backing a TLS session (i.e., if the value of {@link #isTls()} is {@code true}), - * get the packets labeled as TLS Application Data packets. This is a subset of the full set of payload-carrying - * packets (as returned by {@link #getPackets()}). An exception is thrown if this method is invoked on a - * {@code Conversation} for which {@link #isTls()} returns {@code false}. - * - * @return A list containing exactly those packets that could be identified as TLS Application Data packets (through - * inspecting of the SSL record header). The list may be empty, if no TLS application data packets have been - * recorded for this {@code Conversation}. - */ - public List getTlsApplicationDataPackets() { - if (!isTls()) { - throw new NoSuchElementException("cannot get TLS Application Data packets for non-TLS TCP conversation"); - } - return Collections.unmodifiableList(mTlsApplicationDataPackets); - } - - /** - * Extracts the TCP sequence number from {@code packet} and adds it to the proper set of sequence numbers by - * analyzing the direction of the packet. - * @param packet A TCP packet (wrapped in a {@code PcapPacket}) that was added to this conversation and whose - * sequence number is to be recorded as seen. - */ - private void addSeqNumber(PcapPacket packet) { - // Note: below check is redundant if client code is correct as the call to check the precondition should already - // have been made by the addXPacket method that invokes this method. As such, the call below may be removed in - // favor of speed, but the improvement will be minor, hence the added safety may be worth it. - onAddPrecondition(packet); - // Extract sequence number. - int seqNo = packet.get(TcpPacket.class).getHeader().getSequenceNumber(); - // Determine direction of packet and add packet's sequence number to corresponding set of sequence numbers. - switch (getDirection(packet)) { - case CLIENT_TO_SERVER: - // Client to server packet. - mSeqNumbersClient.add(seqNo); - break; - case SERVER_TO_CLIENT: - // Server to client packet. - mSeqNumbersSrv.add(seqNo); - break; - default: - throw new AssertionError(String.format("Unexpected value of enum '%s'", - Direction.class.getSimpleName())); - } - } - - /** - * Determine the direction of {@code packet}. An {@link IllegalArgumentException} is thrown if {@code packet} does - * not pertain to this conversation. - * - * @param packet The packet whose direction is to be determined. - * @return A {@link Direction} indicating the direction of the packet. - */ - public Direction getDirection(PcapPacket packet) { - IpV4Packet ipPacket = packet.get(IpV4Packet.class); - String ipSrc = ipPacket.getHeader().getSrcAddr().getHostAddress(); - String ipDst = ipPacket.getHeader().getDstAddr().getHostAddress(); - // Determine direction of packet. - if (ipSrc.equals(mClientIp) && ipDst.equals(mServerIp)) { - // Client to server packet. - return Direction.CLIENT_TO_SERVER; - } else if (ipSrc.equals(mServerIp) && ipDst.equals(mClientIp)) { - // Server to client packet. - return Direction.SERVER_TO_CLIENT; - } else { - throw new IllegalArgumentException("getDirection: packet not related to " + getClass().getSimpleName()); - } - } - - /** - * Utility enum for expressing the direction of a packet pertaining to this {@code Conversation}. - */ - public enum Direction { - - CLIENT_TO_SERVER { - @Override - public String toCompactString() { - return "*"; - } - }, - SERVER_TO_CLIENT { - @Override - public String toCompactString() { - return ""; - } - }; - - /** - * Get a compact string representation of this {@code Direction}. - * @return a compact string representation of this {@code Direction}. - */ - abstract public String toCompactString(); - - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/FinAckPair.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/FinAckPair.java deleted file mode 100644 index fe4f032..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/FinAckPair.java +++ /dev/null @@ -1,134 +0,0 @@ -package edu.uci.iotproject.trafficreassembly.layer3; - -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.IpV4Packet; -import org.pcap4j.packet.TcpPacket; - -/** - * Groups a FIN packet and its corresponding ACK packet. Immutable and thread safe. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class FinAckPair { - - private final PcapPacket mFinPacket; - private final PcapPacket mCorrespondingAckPacket; - - /** - * Constructs a {@code FinAckPair} given a FIN packet. - * The corresponding ACK packet field is set to {@code null}. - * @param finPacket A FIN packet. - */ - public FinAckPair(PcapPacket finPacket) { - if (!finPacket.get(TcpPacket.class).getHeader().getFin()) { - throw new IllegalArgumentException("not a FIN packet"); - } - mFinPacket = finPacket; - mCorrespondingAckPacket = null; - } - - /** - * Constructs a {@code FinAckPair} given a FIN and an ACK packet. - * @param finPacket A FIN packet. - * @param correspondingAckPacket The ACK packet corresponding to {@code finPacket}. - */ - public FinAckPair(PcapPacket finPacket, PcapPacket correspondingAckPacket) { - // Enforce class invariant, i.e. that the FIN and ACK are related. - // Note that it is indirectly checked whether finPacket is indeed a FIN packet - // as isCorrespondingAckPacket calls the single parameter constructor. - if (!FinAckPair.isCorrespondingAckPacket(finPacket, correspondingAckPacket)) { - throw new IllegalArgumentException("FIN and ACK not related"); - } - mFinPacket = finPacket; - mCorrespondingAckPacket = correspondingAckPacket; - } - - /** - * Get the FIN packet of this pair. - * @return the FIN packet of this pair. - */ - public PcapPacket getFinPacket() { - return mFinPacket; - } - - /** - * Get the corresponding ACK packet of this pair, if any. - * @return the corresponding ACK packet of this pair, if any. - */ - public PcapPacket getCorrespondingAckPacket() { - return mCorrespondingAckPacket; - } - - /** - * Was the FIN in this {@code FinAckPair} acknowledged? - * - * @return {@code true} if the corresponding ACK has been set in this {@code FinAckPair}. - */ - public boolean isAcknowledged() { - return mFinPacket != null && mCorrespondingAckPacket != null; - } - - /** - * Checks if a given packet is an ACK corresponding to the FIN packet in this {@code FinAckPair}. - * @return {@code true} if {@code packet} is an ACK that corresponds to the FIN in this pair, {@code false} otherwise. - */ - public boolean isCorrespondingAckPacket(PcapPacket packet) { - IpV4Packet inputIpPacket = packet.get(IpV4Packet.class); - TcpPacket inputTcpPacket = packet.get(TcpPacket.class); - if (inputIpPacket == null || inputTcpPacket == null || !inputTcpPacket.getHeader().getAck()) { - return false; - } - - IpV4Packet finIpPacket = mFinPacket.get(IpV4Packet.class); - TcpPacket finTcpPacket = mFinPacket.get(TcpPacket.class); - - // Extract (srcIp:port,dstIp:port) for input and member (FIN) packets. - String inputPacketIpSrc = inputIpPacket.getHeader().getSrcAddr().getHostAddress(); - String inputPacketIpDst = inputIpPacket.getHeader().getDstAddr().getHostAddress(); - int inputPacketPortSrc = inputTcpPacket.getHeader().getSrcPort().valueAsInt(); - int inputPacketPortDst = inputTcpPacket.getHeader().getDstPort().valueAsInt(); - String finPacketIpSrc = finIpPacket.getHeader().getSrcAddr().getHostAddress(); - String finPacketIpDst = finIpPacket.getHeader().getDstAddr().getHostAddress(); - int finPacketPortSrc = finTcpPacket.getHeader().getSrcPort().valueAsInt(); - int finPacketPortDst = finTcpPacket.getHeader().getDstPort().valueAsInt(); - - // For the two packets to be related, the dst of one must be the src of the other. - // Split into multiple if statements for readability. First check IP fields, then ports. - if (!(inputPacketIpDst.equals(finPacketIpSrc) && finPacketIpDst.equals(inputPacketIpSrc))) { - return false; - } - if (!(inputPacketPortDst == finPacketPortSrc && finPacketPortDst == inputPacketPortSrc)) { - return false; - } - - // Packets are (most likely) related (part of same conversation/stream). - // Now all that is left for us to check is if the sequence numbers match. - // Note: recall that the FIN packet advances the seq numbers by 1, - // so the ACK number will be one larger than the seq. number in the FIN packet. - return inputTcpPacket.getHeader().getAcknowledgmentNumber() == finTcpPacket.getHeader().getSequenceNumber() + 1; - } - - /** - * Static method to check if two given packets are a FIN and the corresponding ACK packet. - * The purpose of this method is a workaround to enforce the class invariant in the two parameter constructor. - * Specifically, the following should be avoided: - *
-     *     public FinAckPair(PcapPacket finPacket, PcapPacket correspondingAckPacket) {
-     *         mFinPacket = finPacket;
-     *         // Below line is considered bad practice as the object has not been fully initialized at this stage.
-     *         if (!this.isCorrespondingAckPacket(correspondingAckPacket)) {
-     *             // ... throw exception
-     *         }
-     *     }
-     * 
- * @param finPacket The FIN packet. - * @param ackPacket The ACK packet that is to be checked if it corresponds to the given FIN packet. - * @return {@code true} if the ACK corresponds to the FIN, {@code false} otherwise. - */ - private static boolean isCorrespondingAckPacket(PcapPacket finPacket, PcapPacket ackPacket) { - FinAckPair tmp = new FinAckPair(finPacket); - return tmp.isCorrespondingAckPacket(ackPacket); - } - -} diff --git a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/TcpReassembler.java b/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/TcpReassembler.java deleted file mode 100644 index e150875..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/trafficreassembly/layer3/TcpReassembler.java +++ /dev/null @@ -1,260 +0,0 @@ -package edu.uci.iotproject.trafficreassembly.layer3; - -import org.pcap4j.core.PacketListener; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.*; - -import java.util.*; - -/** - * Reassembles TCP conversations (streams). - * Note: current version only supports TCP over IPv4. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class TcpReassembler implements PacketListener { - - /** - * Holds open {@link Conversation}s, i.e., {@code Conversation}s that have not been detected as - * (gracefully) terminated based on the set of packets observed thus far. - * A {@link Conversation} is moved to {@link #mTerminatedConversations} if it can be determined that it is has - * terminated. Termination can be detected by a) observing two {@link FinAckPair}s, one in each direction, (graceful - * termination, see {@link Conversation#isGracefullyShutdown()}) or b) by observing a SYN packet that matches the - * four tuple of an existing {@code Conversation}, but which holds a different sequence number than the - * same-direction SYN packet recorded for the {@code Conversation}. - *

- * Note that due to limitations of the {@link Set} interface (specifically, there is no {@code get(T t)} method), - * we have to resort to a {@link Map} (in which keys map to themselves) to "mimic" a set with {@code get(T t)} - * functionality. - * - * @see this question on StackOverflow.com - */ - private final Map mOpenConversations = new HashMap<>(); - - /** - * Holds terminated {@link Conversation}s. - */ - private final List mTerminatedConversations = new ArrayList<>(); - - @Override - public void gotPacket(PcapPacket pcapPacket) { - IpV4Packet ipPacket = pcapPacket.get(IpV4Packet.class); - TcpPacket tcpPacket = pcapPacket.get(TcpPacket.class); - - if (ipPacket == null || tcpPacket == null) { - return; - } - // ... TODO? - processPacket(pcapPacket); -// Class clazz = pcapPacket.getClass(); -// RadiotapPacket radiotapPacket = pcapPacket.get(RadiotapPacket.class); -// Dot11ManagementPacket dot11ManagementPacket = pcapPacket.get(Dot11ManagementPacket.class); -// if (dot11ManagementPacket != null) { -// return; -// } -// if (radiotapPacket != null) { -// processRadiotapPacket(pcapPacket); -// } - } - - /** - * Get the reassembled TCP connections. Note that if this is called while packets are still being processed (by - * calls to {@link #gotPacket(PcapPacket)}), the behavior is undefined and the returned list may be inconsistent. - * @return The reassembled TCP connections. - */ - public List getTcpConversations() { - ArrayList combined = new ArrayList<>(); - combined.addAll(mTerminatedConversations); - combined.addAll(mOpenConversations.values()); - return combined; - } - - private void processRadiotapPacket(PcapPacket pcapPacket) { - RadiotapPacket radiotapPacket = pcapPacket.get(RadiotapPacket.class); - - RadiotapPacket.RadiotapHeader header = radiotapPacket.getHeader(); - short length = header.getLength(); - ArrayList radiotapData = header.getDataFields(); - // TODO: We can handle this 802.11 QoS data by creating our own class - // TODO: We only need to handle the first few bytes for source, destination, receiver, and transmitter - // TODO: addresses - Packet dataPacket = radiotapPacket.getPayload(); - int dataLength = dataPacket.length(); - } - - private void processPacket(PcapPacket pcapPacket) { - TcpPacket tcpPacket = pcapPacket.get(TcpPacket.class); - // Handle client connection initiation attempts. - if (tcpPacket.getHeader().getSyn() && !tcpPacket.getHeader().getAck()) { - // A segment with the SYN flag set, but no ACK flag indicates that a client is attempting to initiate a new - // connection. - processNewConnectionRequest(pcapPacket); - return; - } - // Handle server connection initiation acknowledgement - if (tcpPacket.getHeader().getSyn() && tcpPacket.getHeader().getAck()) { - // A segment with both the SYN and ACK flags set indicates that the server has accepted the client's request - // to initiate a new connection. - processNewConnectionAck(pcapPacket); - return; - } - // Handle resets - if (tcpPacket.getHeader().getRst()) { - processRstPacket(pcapPacket); - return; - } - // Handle FINs - if (tcpPacket.getHeader().getFin()) { - // Handle FIN packet. - processFinPacket(pcapPacket); - } - // Handle ACKs (currently only ACKs of FINS) - if (tcpPacket.getHeader().getAck()) { - processAck(pcapPacket); - } - // Handle packets that carry payload (application data). - if (tcpPacket.getPayload() != null) { - processPayloadPacket(pcapPacket); - } - } - - private void processNewConnectionRequest(PcapPacket clientSynPacket) { - // A SYN w/o ACK always originates from the client. - Conversation conv = Conversation.fromPcapPacket(clientSynPacket, true); - conv.addSynPacket(clientSynPacket); - // Is there an ongoing conversation for the same four tuple (clientIp, clientPort, serverIp, serverPort) as - // found in the new SYN packet? - Conversation ongoingConv = mOpenConversations.get(conv); - if (ongoingConv != null) { - if (ongoingConv.isRetransmission(clientSynPacket)) { - // SYN retransmission detected, do nothing. - return; - // TODO: the way retransmission detection is implemented may cause a bug for connections where we have - // not recorded the initial SYN, but only the SYN ACK, as retransmission is determined by comparing the - // sequence numbers of initial SYNs -- and if no initial SYN is present for the Conversation, the new - // SYN will be interpreted as a retransmission. Possible fix: let isRentransmission ALWAYS return false - // when presented with a SYN packet when the Conversation already holds a SYN ACK packet? - } else { - // New SYN has different sequence number than SYN recorded for ongoingConv, so this must be an attempt - // to establish a new conversation with the same four tuple as ongoingConv. - // Mark existing connection as terminated. - // TODO: is this 100% theoretically correct, e.g., if many connection attempts are made back to back? And RST packets? - mTerminatedConversations.add(ongoingConv); - mOpenConversations.remove(ongoingConv); - } - } - // Finally, update the map of open connections with the new connection. - mOpenConversations.put(conv, conv); - } - - - /* - * TODO a problem across the board for all processXPacket methods below: - * if we start the capture in the middle of a TCP connection, we will not have an entry for the conversation in the - * map as we have not seen the initial SYN packet. - * Two ways we can address this: - * a) Perform null-checks and ignore packets for which we have not seen SYN - * + easy to get correct - * - we discard data (issue for long-lived connections!) - * b) Add a corresponding conversation entry whenever we encounter a packet that does not map to a conversation - * + we consider all data - * - not immediately clear if this will introduce bugs (incorrectly mapping packets to wrong conversations?) - * - * [[[ I went with option b) for now; see getOngoingConversationOrCreateNew(PcapPacket pcapPacket). ]]] - */ - - private void processNewConnectionAck(PcapPacket srvSynPacket) { - // Find the corresponding ongoing connection, if any (if we start the capture just *after* the initial SYN, no - // ongoing conversation entry will exist, so it must be created in that case). -// Conversation conv = mOpenConversations.get(Conversation.fromPcapPacket(srvSynPacket, false)); - Conversation conv = getOngoingConversationOrCreateNew(srvSynPacket); - // Note: exploits &&'s short-circuit operation: only attempts to add non-retransmissions. - if (!conv.isRetransmission(srvSynPacket) && !conv.addSynPacket(srvSynPacket)) { - // For safety/debugging: if NOT a retransmission and add fails, - // something has gone terribly wrong/invariant is broken. -// throw new AssertionError("Attempt to add SYN ACK packet that was NOT a retransmission failed." + -// Conversation.class.getSimpleName() + " invariant broken."); - } - } - - private void processRstPacket(PcapPacket rstPacket) { - Conversation conv = getOngoingConversationOrCreateNew(rstPacket); - // Add RST packet to conversation. - conv.addRstPacket(rstPacket); - // Move conversation to set of terminated conversations. - mTerminatedConversations.add(conv); - mOpenConversations.remove(conv, conv); - } - - private void processFinPacket(PcapPacket finPacket) { -// getOngoingConversationForPacket(finPacket).addFinPacket(finPacket); - getOngoingConversationOrCreateNew(finPacket).addFinPacket(finPacket); - } - - private void processAck(PcapPacket ackPacket) { -// getOngoingConversationForPacket(ackPacket).attemptAcknowledgementOfFin(ackPacket); - // Note that unlike the style for SYN, FIN, and payload packets, for "ACK only" packets, we want to avoid - // creating a new conversation. - Conversation conv = getOngoingConversationForPacket(ackPacket); - if (conv != null) { - // The ACK may be an ACK of a FIN, so attempt to mark the FIN as ack'ed. - conv.attemptAcknowledgementOfFin(ackPacket); - if (conv.isGracefullyShutdown()) { - // Move conversation to set of terminated conversations. - mTerminatedConversations.add(conv); - mOpenConversations.remove(conv); - } - } - // Note: add (additional) processing of ACKs (that are not ACKs of FINs) as necessary here... - } - - private void processPayloadPacket(PcapPacket pcapPacket) { -// getOngoingConversationForPacket(pcapPacket).addPacket(pcapPacket, true); - getOngoingConversationOrCreateNew(pcapPacket).addPacket(pcapPacket, true); - } - - /** - * Locates an ongoing conversation (if any) that {@code pcapPacket} pertains to. - * @param pcapPacket The packet that is to be mapped to an ongoing {@code Conversation}. - * @return The {@code Conversation} matching {@code pcapPacket} or {@code null} if there is no match. - */ - private Conversation getOngoingConversationForPacket(PcapPacket pcapPacket) { - // We cannot know if this is a client-to-server or server-to-client packet without trying both options... - Conversation conv = mOpenConversations.get(Conversation.fromPcapPacket(pcapPacket, true)); - if (conv == null) { - conv = mOpenConversations.get(Conversation.fromPcapPacket(pcapPacket, false)); - } - return conv; - } - - /** - * Like {@link #getOngoingConversationForPacket(PcapPacket)}, but creates and inserts a new {@code Conversation} - * into {@link #mOpenConversations} if no open conversation is found (i.e., in the case that - * {@link #getOngoingConversationForPacket(PcapPacket)} returns {@code null}). - * - * @param pcapPacket The packet that is to be mapped to an ongoing {@code Conversation}. - * @return The existing, ongoing {@code Conversation} matching {@code pcapPacket} or the newly created one in case - * no match was found. - */ - private Conversation getOngoingConversationOrCreateNew(PcapPacket pcapPacket) { - Conversation conv = getOngoingConversationForPacket(pcapPacket); - if (conv == null) { - TcpPacket tcpPacket = pcapPacket.get(TcpPacket.class); - if (tcpPacket.getHeader().getSyn() && tcpPacket.getHeader().getAck()) { - // A SYN ACK packet always originates from the server (it is a reply to the initial SYN packet from the client) - conv = Conversation.fromPcapPacket(pcapPacket, false); - } else { - // TODO: can we do anything else but arbitrarily select who is designated as the server in this case? - // We can check if the IP prefix matches a local IP when handling traffic observed inside the local - // network, but that obviously won't be a useful strategy for an observer at the WAN port. - String srcIp = pcapPacket.get(IpV4Packet.class).getHeader().getSrcAddr().getHostAddress(); - // TODO: REPLACE THE ROUTER'S IP WITH A PARAMETER!!! - boolean clientIsSrc = srcIp.startsWith("10.") || srcIp.startsWith("192.168.") || srcIp.equals("128.195.205.105"); - conv = Conversation.fromPcapPacket(pcapPacket, clientIsSrc); - } - mOpenConversations.put(conv, conv); - } - return conv; - } -} 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 deleted file mode 100644 index 067af93..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PcapPacketUtils.java +++ /dev/null @@ -1,484 +0,0 @@ -package edu.uci.iotproject.util; - -import edu.uci.iotproject.trafficreassembly.layer3.Conversation; -import edu.uci.iotproject.analysis.PcapPacketPair; -import edu.uci.iotproject.analysis.TcpConversationUtils; -import edu.uci.iotproject.analysis.TriggerTrafficExtractor; -import org.apache.commons.math3.stat.clustering.Cluster; -import org.pcap4j.core.PcapPacket; -import org.pcap4j.packet.EthernetPacket; -import org.pcap4j.packet.IpV4Packet; -import org.pcap4j.packet.TcpPacket; -import org.pcap4j.util.MacAddress; - -import java.util.*; - -/** - * Utility methods for inspecting {@link PcapPacket} properties. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public final class PcapPacketUtils { - - /** - * This is the threshold value for a signature's number of members - * If after a merging the number of members of a signature falls below this threshold, then we can boldly - * get rid of that signature. - */ - private static final int SIGNATURE_MERGE_THRESHOLD = 5; - - /** - * This is an overlap counter (we consider overlaps between signatures if it happens more than once) - */ - private static int mOverlapCounter = 0; - - - /** - * Gets the source address of the Ethernet part of {@code packet}. - * @param packet The packet for which the Ethernet source address is to be extracted. - * @return The source address of the Ethernet part of {@code packet}. - */ - public static MacAddress getEthSrcAddr(PcapPacket packet) { - return getEthernetPacketOrThrow(packet).getHeader().getSrcAddr(); - } - - /** - * Gets the destination address of the Ethernet part of {@code packet}. - * @param packet The packet for which the Ethernet destination address is to be extracted. - * @return The destination address of the Ethernet part of {@code packet}. - */ - public static MacAddress getEthDstAddr(PcapPacket packet) { - return getEthernetPacketOrThrow(packet).getHeader().getDstAddr(); - } - - /** - * Determines if a given {@link PcapPacket} wraps a {@link TcpPacket}. - * @param packet The {@link PcapPacket} to inspect. - * @return {@code true} if {@code packet} wraps a {@link TcpPacket}, {@code false} otherwise. - */ - public static boolean isTcp(PcapPacket packet) { - return packet.get(TcpPacket.class) != null; - } - - /** - * 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}. - * @throws NullPointerException if {@code packet} does not encapsulate an {@link IpV4Packet}. - */ - public static String getSourceIp(PcapPacket packet) { - return getIpV4PacketOrThrow(packet).getHeader().getSrcAddr().getHostAddress(); - } - - /** - * Gets the destination 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 destination IP of {@code packet} iff {@code packet} wraps an - * {@link IpV4Packet}. - * @throws NullPointerException if {@code packet} does not encapsulate an {@link IpV4Packet}. - */ - public static String getDestinationIp(PcapPacket packet) { - return getIpV4PacketOrThrow(packet).getHeader().getDstAddr().getHostAddress(); - } - - /** - * Gets the source port of a TCP packet. - * @param packet The packet for which the source port is to be extracted. - * @return The source port of the {@link TcpPacket} encapsulated by {@code packet}. - * @throws IllegalArgumentException if {@code packet} does not encapsulate a {@link TcpPacket}. - */ - public static int getSourcePort(PcapPacket packet) { - TcpPacket tcpPacket = packet.get(TcpPacket.class); - if (tcpPacket == null) { - throw new IllegalArgumentException("not a TCP packet"); - } - return tcpPacket.getHeader().getSrcPort().valueAsInt(); - } - - /** - * Gets the destination port of a TCP packet. - * @param packet The packet for which the destination port is to be extracted. - * @return The destination port of the {@link TcpPacket} encapsulated by {@code packet}. - * @throws IllegalArgumentException if {@code packet} does not encapsulate a {@link TcpPacket}. - */ - public static int getDestinationPort(PcapPacket packet) { - TcpPacket tcpPacket = packet.get(TcpPacket.class); - if (tcpPacket == null) { - throw new IllegalArgumentException("not a TCP packet"); - } - return tcpPacket.getHeader().getDstPort().valueAsInt(); - } - - /** - * 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. - * @param ip The IP to look for in the ip.src field of {@code packet}. - * @param port The port to look for in the tcp.port field of {@code packet}. - * @return {@code true} if the given ip+port match the corresponding fields in {@code packet}. - */ - public static boolean isSource(PcapPacket packet, String ip, int port) { - IpV4Packet ipPacket = Objects.requireNonNull(packet.get(IpV4Packet.class)); - // For now we only support TCP flows. - TcpPacket tcpPacket = Objects.requireNonNull(packet.get(TcpPacket.class)); - String ipSrc = ipPacket.getHeader().getSrcAddr().getHostAddress(); - int srcPort = tcpPacket.getHeader().getSrcPort().valueAsInt(); - return ipSrc.equals(ip) && srcPort == port; - } - - /** - * Helper method to determine if the given combination of IP and port matches the destination of the given packet. - * @param packet The packet to check. - * @param ip The IP to look for in the ip.dst field of {@code packet}. - * @param port The port to look for in the tcp.dstport field of {@code packet}. - * @return {@code true} if the given ip+port match the corresponding fields in {@code packet}. - */ - public static boolean isDestination(PcapPacket packet, String ip, int port) { - IpV4Packet ipPacket = Objects.requireNonNull(packet.get(IpV4Packet.class)); - // For now we only support TCP flows. - TcpPacket tcpPacket = Objects.requireNonNull(packet.get(TcpPacket.class)); - String ipDst = ipPacket.getHeader().getDstAddr().getHostAddress(); - int dstPort = tcpPacket.getHeader().getDstPort().valueAsInt(); - return ipDst.equals(ip) && dstPort == port; - } - - /** - * Checks if the source IP address of the {@link IpV4Packet} contained in {@code packet} is a local address, i.e., - * if it pertains to subnet 10.0.0.0/8, 172.16.0.0/16, or 192.168.0.0/16. - * @param packet The packet for which the source IP address is to be examined. - * @return {@code true} if {@code packet} wraps a {@link IpV4Packet} for which the source IP address is a local IP - * address, {@code false} otherwise. - * @throws NullPointerException if {@code packet} does not encapsulate an {@link IpV4Packet}. - */ - public static boolean isSrcIpLocal(PcapPacket packet) { - return getIpV4PacketOrThrow(packet).getHeader().getSrcAddr().isSiteLocalAddress(); - } - - /** - * Checks if the destination IP address of the {@link IpV4Packet} contained in {@code packet} is a local address, - * i.e., if it pertains to subnet 10.0.0.0/8, 172.16.0.0/16, or 192.168.0.0/16. - * @param packet The packet for which the destination IP address is to be examined. - * @return {@code true} if {@code packet} wraps a {@link IpV4Packet} for which the destination IP address is a local - * IP address, {@code false} otherwise. - * @throws NullPointerException if {@code packet} does not encapsulate an {@link IpV4Packet}. - */ - public static boolean isDstIpLocal(PcapPacket packet) { - return getIpV4PacketOrThrow(packet).getHeader().getDstAddr().isSiteLocalAddress(); - } - - /** - * Checks if {@code packet} wraps a TCP packet that has the SYN flag set. - * @param packet A {@link PcapPacket} that is suspected to contain a {@link TcpPacket} for which the SYN flag is set. - * @return {@code true} iff {@code packet} contains a {@code TcpPacket} for which the SYN flag is set, - * {@code false} otherwise. - */ - public static boolean isSyn(PcapPacket packet) { - TcpPacket tcp = packet.get(TcpPacket.class); - return tcp != null && tcp.getHeader().getSyn(); - } - - /** - * Checks if {@code packet} wraps a TCP packet th at has the ACK flag set. - * @param packet A {@link PcapPacket} that is suspected to contain a {@link TcpPacket} for which the ACK flag is set. - * @return {@code true} iff {@code packet} contains a {@code TcpPacket} for which the ACK flag is set, - * {@code false} otherwise. - */ - public static boolean isAck(PcapPacket packet) { - TcpPacket tcp = packet.get(TcpPacket.class); - return tcp != null && tcp.getHeader().getAck(); - } - - /** - * Transform a {@code Cluster} of {@code PcapPacketPair} objects into a {@code List} of {@code List} of - * {@code PcapPacket} objects. - * @param cluster A {@link Cluster} of {@link PcapPacketPair} objects that needs to be transformed. - * @return A {@link List} of {@link List} of {@link PcapPacket} objects as the result of the transformation. - */ - public static List> clusterToListOfPcapPackets(Cluster cluster) { - List> ppListOfList = new ArrayList<>(); - for (PcapPacketPair ppp: cluster.getPoints()) { - // Create a list of PcapPacket objects (list of two members). - List ppList = new ArrayList<>(); - ppList.add(ppp.getFirst()); - if(ppp.getSecond().isPresent()) - ppList.add(ppp.getSecond().get()); - else - ppList.add(null); - // Create a list of list of PcapPacket objects. - ppListOfList.add(ppList); - } - // Sort the list of lists based on the first packet's timestamp! - Collections.sort(ppListOfList, (p1, p2) -> p1. get(0).getTimestamp().compareTo(p2.get(0).getTimestamp())); - return ppListOfList; - } - - /** - * Merge signatures in {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects. - * We cross-check these with {@code List} of {@code Conversation} objects to see - * if two {@code List} of {@code PcapPacket} objects actually belong to the same {@code Conversation}. - * @param signatures A {@link List} of {@link List} of {@link List} of - * {@link PcapPacket} objects that needs to be checked and merged. - * @param conversations A {@link List} of {@link Conversation} objects as reference for merging. - * @return A {@link List} of {@link List} of {@link List} of - * {@link PcapPacket} objects as the result of the merging. - */ - public static List>> - mergeSignatures(List>> signatures, List conversations) { - - // TODO: THIS IS NOT A DEEP COPY; IT BASICALLY CREATES A REFERENCE TO THE SAME LIST OBJECT - // List>> copySignatures = new ArrayList<>(signatures); - // Make a deep copy first. - List>> copySignatures = new ArrayList<>(); - listDeepCopy(copySignatures, signatures); - // Traverse and look into the pairs of signatures. - for (int first = 0; first < signatures.size(); first++) { - List> firstList = signatures.get(first); - for (int second = first+1; second < signatures.size(); second++) { - int maxSignatureEl = 0; // Number of maximum signature elements. - List> secondList = signatures.get(second); - int initialSecondListMembers = secondList.size(); - // Iterate over the signatures in the first list. - for (List signature : firstList) { - signature.removeIf(el -> el == null); // Clean up null elements. - // Return the Conversation that the signature is part of. - Conversation conv = TcpConversationUtils.returnConversation(signature, conversations); - // Find the element of the second list that is a match for that Conversation. - for (List ppList : secondList) { - ppList.removeIf(el -> el == null); // Clean up null elements. - // Check if they are part of a Conversation and are adjacent to the first signature. - // If yes then merge into the first list. - TcpConversationUtils.SignaturePosition position = - TcpConversationUtils.isPartOfConversationAndAdjacent(signature, ppList, conv); - if (position == TcpConversationUtils.SignaturePosition.LEFT_ADJACENT) { - // Merge to the left side of the first signature. - ppList.addAll(signature); - signature = ppList; - maxSignatureEl = signature.size() > maxSignatureEl ? signature.size() : maxSignatureEl; - secondList.remove(ppList); // Remove as we merge. - break; - } else if (position == TcpConversationUtils.SignaturePosition.RIGHT_ADJACENT) { - // Merge to the right side of the first signature. - signature.addAll(ppList); - maxSignatureEl = signature.size() > maxSignatureEl ? signature.size() : maxSignatureEl; - secondList.remove(ppList); // Remove as we merge. - break; - } // TcpConversationUtils.SignaturePosition.NOT_ADJACENT. - } - } - // Call it a successful merging if there are only less than 5 elements from the second list that - // cannot be merged. - if (secondList.size() < SIGNATURE_MERGE_THRESHOLD) { - // Prune the unsuccessfully merged signatures (i.e., these will have size() < maxSignatureEl). - final int maxNumOfEl = maxSignatureEl; - // TODO: DOUBLE CHECK IF WE REALLY NEED TO PRUNE FAILED BINDINGS - // TODO: SOMETIMES THE SEQUENCES ARE JUST INCOMPLETE - // TODO: AND BOTH THE COMPLETE AND INCOMPLETE SEQUENCES ARE VALID SIGNATURES! - firstList.removeIf(el -> el.size() < maxNumOfEl); - // Remove the merged set of signatures when successful. - signatures.remove(secondList); - } else if (secondList.size() < initialSecondListMembers) { - // If only some of the signatures from the second list are merged, this means UNSUCCESSFUL merging. - // Return the original copy of the signatures object. - return copySignatures; - } - } - } - return signatures; - } - - /** - * Deep copy to create an entirely new {@link List} of {@link List} of {@link List} of {@link PcapPacket} objects. - * @param destList A {@link List} of {@link List} of {@link List} of - * {@link PcapPacket} objects that will be the final container of the deep copy - * @param sourceList A {@link List} of {@link List} of {@link List} of - * {@link PcapPacket} objects that will be the source of the deep copy. - */ - private static void listDeepCopy(List>> destList, List>> sourceList) { - - for(List> llPcapPacket : sourceList) { - List> tmpListOfList = new ArrayList<>(); - for(List lPcapPacket : llPcapPacket) { - List tmpList = new ArrayList<>(); - for(PcapPacket pcapPacket : lPcapPacket) { - tmpList.add(pcapPacket); - } - tmpListOfList.add(tmpList); - } - destList.add(tmpListOfList); - } - } - - /** - * Sort the signatures in the {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects. - * The purpose of this is to sort the order of signatures in the signature list. For detection purposes, we need - * to know if one signature occurs earlier/later in time with respect to the other signatures for more confidence - * in detecting the occurrence of an event. - * @param signatures A {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects that needs sorting. - * We assume that innermost {@code List} of {@code PcapPacket} objects have been sorted ascending - * by timestamps. By the time we use this method, we should have sorted it when calling the - * {@code clusterToListOfPcapPackets} method. - * @return A sorted {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects. - */ - public static List>> sortSignatures(List>> signatures) { - // TODO: This is the simplest solution!!! Might not cover all corner cases. - // TODO: Sort the list of lists based on the first packet's timestamps! -// Collections.sort(signatures, (p1, p2) -> { -// //return p1.get(0).get(0).getTimestamp().compareTo(p2.get(0).get(0).getTimestamp()); -// int compare = p1.get(0).get(0).getTimestamp().compareTo(p2.get(0).get(0).getTimestamp()); -// return compare; -// }); - // TODO: The following is a more complete solution that covers corner cases. - // Sort the list of lists based on one-to-one comparison between timestamps of signatures on both lists. - // This also takes into account the fact that the number of signatures in the two lists could be different. - // Additionally, this code forces the comparison between two signatures only if they occur in the - // INCLUSION_WINDOW_MILLIS window; otherwise, it tries to find the right pair of signatures in the time window. - Collections.sort(signatures, (p1, p2) -> { - int compare = 0; - int comparePrev = 0; - int count1 = 0; - int count2 = 0; - // Need to make sure that both are not out of bound! - while (count1 + 1 < p1.size() && count2 + 1 < p2.size()) { - long timestamp1 = p1.get(count1).get(0).getTimestamp().toEpochMilli(); - long timestamp2 = p2.get(count2).get(0).getTimestamp().toEpochMilli(); - // The two timestamps have to be within a 15-second window! - if (Math.abs(timestamp1 - timestamp2) < TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS) { - // If these two are within INCLUSION_WINDOW_MILLIS window then compare! - compare = p1.get(count1).get(0).getTimestamp().compareTo(p2.get(count2).get(0).getTimestamp()); -// if (comparePrev != 0) { // First time since it is 0 -// if (Integer.signum(compare) != Integer.signum(comparePrev)) { -// // Throw an exception if the order of the two signatures is not consistent, -// // E.g., 111, 222, 333 in one occassion and 222, 333, 111 in the other. -// throw new Error("OVERLAP WARNING: " + "" + -// "Please remove one of the sequences: " + -// p1.get(0).get(0).length() + "... OR " + -// p2.get(0).get(0).length() + "..."); -// } -// } - overlapChecking(compare, comparePrev, p1.get(count1), p2.get(count2)); - comparePrev = compare; - count1++; - count2++; - } else { - // If not within INCLUSION_WINDOW_MILLIS window then find the correct pair - // by incrementing one of them. - if (timestamp1 < timestamp2) - count1++; - else - count2++; - } - } - return compare; - }); - return signatures; - } - - /** - * Checks for overlapping between two packet sequences. - * @param compare Current comparison value between packet sequences p1 and p2 - * @param comparePrev Previous comparison value between packet sequences p1 and p2 - * @param sequence1 The packet sequence ({@link List} of {@link PcapPacket} objects). - * @param sequence2 The packet sequence ({@link List} of {@link PcapPacket} objects). - */ - private static void overlapChecking(int compare, int comparePrev, List sequence1, List sequence2) { - - // Check if p1 occurs before p2 but both have same overlap - if (comparePrev != 0) { // First time since it is 0 - if (Integer.signum(compare) != Integer.signum(comparePrev)) { - // Throw an exception if the order of the two signatures is not consistent, - // E.g., 111, 222, 333 in one occassion and 222, 333, 111 in the other. - throw new Error("OVERLAP WARNING: " + "" + - "Two sequences have some overlap. Please remove one of the sequences: " + - sequence1.get(0).length() + "... OR " + - sequence2.get(0).length() + "..."); - } - } - // Check if p1 is longer than p2 and p2 occurs during the occurrence of p1 - int lastIndexOfSequence1 = sequence1.size() - 1; - int lastIndexOfSequence2 = sequence2.size() - 1; - int compareLast = - sequence1.get(lastIndexOfSequence1).getTimestamp().compareTo(sequence2.get(lastIndexOfSequence2).getTimestamp()); - // Check the signs of compare and compareLast - if ((compare <= 0 && compareLast > 0) || - (compareLast <= 0 && compare > 0)) { - mOverlapCounter++; - // TODO: Probably not the best approach but we consider overlap if it happens more than once - if (mOverlapCounter > 1) { - throw new Error("OVERLAP WARNING: " + "" + - "One sequence is in the other. Please remove one of the sequences: " + - sequence1.get(0).length() + "... OR " + - sequence2.get(0).length() + "..."); - } - } - - } - - /** - * Gets the {@link IpV4Packet} contained in {@code packet}, or throws a {@link NullPointerException} if - * {@code packet} does not contain an {@link IpV4Packet}. - * @param packet A {@link PcapPacket} that is expected to contain an {@link IpV4Packet}. - * @return The {@link IpV4Packet} contained in {@code packet}. - * @throws NullPointerException if {@code packet} does not encapsulate an {@link IpV4Packet}. - */ - private static IpV4Packet getIpV4PacketOrThrow(PcapPacket packet) { - return Objects.requireNonNull(packet.get(IpV4Packet.class), "not an IPv4 packet"); - } - - /** - * Gets the {@link EthernetPacket} contained in {@code packet}, or throws a {@link NullPointerException} if - * {@code packet} does not contain an {@link EthernetPacket}. - * @param packet A {@link PcapPacket} that is expected to contain an {@link EthernetPacket}. - * @return The {@link EthernetPacket} contained in {@code packet}. - * @throws NullPointerException if {@code packet} does not encapsulate an {@link EthernetPacket}. - */ - private static final EthernetPacket getEthernetPacketOrThrow(PcapPacket packet) { - return Objects.requireNonNull(packet.get(EthernetPacket.class), "not an Ethernet packet"); - } - - /** - * Print signatures in {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects. - * - * @param signatures A {@link List} of {@link List} of {@link List} of - * {@link PcapPacket} objects that needs to be printed. - */ - public static void printSignatures(List>> signatures) { - - // Iterate over the list of all clusters/sequences - int sequenceCounter = 0; - for(List> listListPcapPacket : signatures) { - // Iterate over every member of a cluster/sequence - System.out.print("====== SEQUENCE " + ++sequenceCounter); - System.out.println(" - " + listListPcapPacket.size() + " MEMBERS ======"); - for(List listPcapPacket : listListPcapPacket) { - // Print out packet lengths in a sequence - int packetCounter = 0; - for(PcapPacket pcapPacket : listPcapPacket) { - if(pcapPacket != null) { - System.out.print(pcapPacket.length()); - } - if(packetCounter < listPcapPacket.size() - 1) { - System.out.print(" "); // Provide space if not last packet - } else { - System.out.println(); // Newline if last packet - } - packetCounter++; - } - } - } - } - - /** - * Remove a sequence in a signature object. - * - * @param signatures A {@link List} of {@link List} of {@link List} of - * {@link PcapPacket} objects. - * @param sequenceIndex An index for a sequence that consists of {{@link List} of {@link List} of - * {@link PcapPacket} objects. - */ - public static void removeSequenceFromSignature(List>> signatures, int sequenceIndex) { - - // Sequence index starts from 0 - signatures.remove(sequenceIndex); - } -} 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 deleted file mode 100644 index 3d3a3be..0000000 --- a/Code/Projects/SmartPlugDetector/src/main/java/edu/uci/iotproject/util/PrintUtils.java +++ /dev/null @@ -1,221 +0,0 @@ -package edu.uci.iotproject.util; - -import edu.uci.iotproject.DnsMap; -import edu.uci.iotproject.analysis.PcapPacketPair; -import org.apache.commons.math3.stat.clustering.Cluster; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import org.pcap4j.core.PcapPacket; - -/** - * Utility methods for generating (output) strings. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class PrintUtils { - - /** - * This is the path for writing the list of list of packet pairs {@code List>} into a file. - * The packet pairs are the pairs in one cluster, so the list represents a cluster that has been derived through - * the DBSCAN algorithm. - * - * E.g., this file could contain a list like the following: - * - * [[1109, 613],[1111, 613],[1115, 613],...] - * - * This list has lists of PcapPacket pairs as its members. We do not maintain the pairs in the form of - * {@code Cluster} objects because there might be a situation where we could combine multiple - * PcapPacketPair objects into a longer signature, i.e., a string of PcapPacket objects and not just a pair. - */ - private static final String SERIALIZABLE_FILE_PATH = "./signature.sig"; - - private PrintUtils() { /* private constructor to prevent instantiation */ } - - /** - * Write the list of list of packet pairs {@code List>} into a file. - * - * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of - * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects. - * We do not maintain the pairs in the form of {@code Cluster} objects because there might be - * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of - * PcapPacket objects and not just a pair. - * - * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the - * default file name {@code SERIALIZABLE_FILE_PATH}. - * @param clusterPackets The {@link Cluster} objects in the form of list of {@code PcapPacket} objects. - */ - public static void serializeClustersIntoFile(String fileName, List> clusterPackets) { - if (fileName == null) - fileName = SERIALIZABLE_FILE_PATH; - try (ObjectOutputStream oos = - new ObjectOutputStream(new FileOutputStream(fileName))) { - oos.writeObject(clusterPackets); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - /** - * Write the signature {@code List>>} into a file. - * - * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of - * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects. - * We do not maintain the pairs in the form of {@code Cluster} objects because there might be - * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of - * PcapPacket objects and not just a pair. - * - * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the - * default file name {@code SERIALIZABLE_FILE_PATH}. - * @param signature The {@link Cluster} objects in the form of list of {@code PcapPacket} objects. - */ - public static void serializeSignatureIntoFile(String fileName, List>> signature) { - if (fileName == null) - fileName = SERIALIZABLE_FILE_PATH; - try (ObjectOutputStream oos = - new ObjectOutputStream(new FileOutputStream(fileName))) { - oos.writeObject(signature); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - /** - * Read the list of list of packet pairs {@code List>} from a file. - * - * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of - * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects. - * We do not maintain the pairs in the form of {@code Cluster} objects because there might be - * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of - * PcapPacket objects and not just a pair. - * - * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the - * default file name {@code SERIALIZABLE_FILE_PATH}. - * @return The list of list of {@link Cluster} objects ({@code List>}) that is read from file. - */ - public static List> deserializeClustersFromFile(String fileName) { - if (fileName == null) - fileName = SERIALIZABLE_FILE_PATH; - List> ppListOfList = null; - try (ObjectInputStream ois = - new ObjectInputStream(new FileInputStream(fileName))) { - ppListOfList = (List>) ois.readObject(); - } catch (Exception ex) { - ex.printStackTrace(); - } - - return ppListOfList; - } - - /** - * Read the list of list of packet pairs {@code List>>} from a file. - * - * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of - * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects. - * We do not maintain the pairs in the form of {@code Cluster} objects because there might be - * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of - * PcapPacket objects and not just a pair. - * - * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the - * default file name {@code SERIALIZABLE_FILE_PATH}. - * @return The list of list of list of {@link Cluster} objects ({@code List>>}) - * that is read from file. - */ - public static List>> deserializeSignatureFromFile(String fileName) { - if (fileName == null) - fileName = SERIALIZABLE_FILE_PATH; - List>> ppListOfListOfList = null; - try (ObjectInputStream ois = - new ObjectInputStream(new FileInputStream(fileName))) { - ppListOfListOfList = (List>>) ois.readObject(); - } catch (Exception ex) { - ex.printStackTrace(); - } - - return ppListOfListOfList; - } - - /** - * 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. - * - * Note: if the {@link PcapPacketPair} has no second element, 0 is printed as the length of the second packet - * in the pair. - * - * @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().map(pp -> pp.getOriginalLength()).orElse(0)); - } - - /** - * 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'. - * - * Note: if the {@link PcapPacketPair} has no second element, 0 is printed as the length of the second packet - * in the pair, and null is printed for its source. - * - * @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 obtain source IPs - String firstSrc = PcapPacketUtils.getSourceIp(packetPair.getFirst()); - // Note: use optional for second item in pair as there might not be one. - Optional secondSrc = packetPair.getSecond().map(pkt -> PcapPacketUtils.getSourceIp(pkt)); - - // If possible, map source IPs to hostnames. - Set firstHostnames = ipHostnameMappings.getHostnamesForIp(firstSrc); - Optional> secondHostnames = secondSrc.map(src -> ipHostnameMappings.getHostnamesForIp(src)); - 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 one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter). - Optional hostnames = secondHostnames.map(hostnameSet -> hostnameSet.stream().collect(Collectors.joining(delimiter))); - // Fall back to IP if we couldn't second pair is present, but we couldn't map to (a) hostname(s). - secondSrc = hostnames.isPresent() ? hostnames : secondSrc; - - // Check if the first source is C (client) or S (server). - String firstSrcCorS = packetPair.isFirstClient() ? "C" : "S"; - String secondSrcCorS = packetPair.isSecondClient() ? "C" : "S"; - - return String.format("%d, %d, %s, %s, %s, %s", packetPair.getFirst().getOriginalLength(), - packetPair.getSecond().map(pp -> pp.getOriginalLength()).orElse(0), - firstSrc, - secondSrc.orElse("null"), - firstSrcCorS, - secondSrcCorS); - } - - /** - * Generate a string that summarizes/describes {@code cluster}. - * @param cluster The {@link Cluster} to summarize/describe. - * @return A string that summarizes/describes {@code cluster}. - */ - public static String toSummaryString(Cluster cluster) { - StringBuilder sb = new StringBuilder(); - for (PcapPacketPair ppp : cluster.getPoints()) { - sb.append(toCsv(ppp, ppp.getDnsMap()) + System.lineSeparator()); - } - return sb.toString(); - } -} diff --git a/Code/Projects/SmartPlugDetector/src/test/java/edu/uci/iotproject/test/SequenceAlignmentTest.java b/Code/Projects/SmartPlugDetector/src/test/java/edu/uci/iotproject/test/SequenceAlignmentTest.java deleted file mode 100644 index 90e8eab..0000000 --- a/Code/Projects/SmartPlugDetector/src/test/java/edu/uci/iotproject/test/SequenceAlignmentTest.java +++ /dev/null @@ -1,279 +0,0 @@ -package edu.uci.iotproject.test; - -import edu.uci.iotproject.comparison.seqalignment.AlignmentPricer; -import edu.uci.iotproject.comparison.seqalignment.SequenceAlignment; -import org.junit.Before; -import org.junit.Test; - -import java.util.function.ToIntBiFunction; -import java.util.function.ToIntFunction; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Tests the implementation of {@link SequenceAlignment}. - * - * @author Janus Varmarken {@literal } - * @author Rahmadi Trimananda {@literal } - */ -public class SequenceAlignmentTest { - - private char[] lowercaseVowels; - private char[] lowercaseConsonants; - - private Character[] meanChars; - private Character[] nameChars; - - /** - * Cost function for the alignment of letters in the example execution of the sequence alignment algorithm in - * Kleinberg's and Tardos' "Algorithm Design", where 'mean' and 'name' are aligned. - */ - private ToIntBiFunction kleinbergExampleAlignmentCostFunc; - - /** - * Cost function for the alignment of letters with gaps in the example execution of the sequence alignment algorithm - * in Kleinberg's and Tardos' "Algorithm Design", where 'mean' and 'name' are aligned. Gap cost is set to 2, - * regardless of input character. - */ - private ToIntFunction kleinbergExampleGapCostFunc; - - /** - * Calculates the cost of aligning a letter with another letter or a letter with a gap according to the cost recipe - * used in the example in Kleinberg & Tardos. - */ - private AlignmentPricer kleinbergAlignmentPricer; - - /** - * Executes the sequence alignment algorithm using the cost function defined in the example in Kleinberg & Tardos, - * i.e., {@link #kleinbergAlignmentPricer}. - */ - private SequenceAlignment kleinbergSequenceAligner; - - @Before - public void initialize() { - // We consider 'y' a vowel for the sake of simplicity. - // Note: we assume an all lowercase string! - lowercaseVowels = new char[] { 'a', 'e', 'i', 'o', 'u', 'y' }; - lowercaseConsonants = new char[] { 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', - 't', 'v', 'w', 'x', 'z' }; - kleinbergExampleAlignmentCostFunc = (c1, c2) -> { - // Unbox to primitive type for the sake of brevity in the statements to follow. - final char char1 = c1.charValue(); - final char char2 = c2.charValue(); - - // If char1 and char2 are the same characters, the cost of aligning them is 0. - if (char1 == char2) return 0; - - final boolean char1IsVowel = isVowel(char1); - final boolean char1IsConsonant = isConsonant(char1); - final boolean char2IsVowel = isVowel(char2); - final boolean char2IsConsonant = isConsonant(char2); - - // Alignment cost is undefined for non alphabet characters. - if (!char1IsVowel && !char1IsConsonant) fail("not an alphabet letter: " + char1); - if (!char2IsVowel && !char2IsConsonant) fail("not an alphabet letter: " + char2); - - // If char1 and char2 are both vowels or both consonants, the cost is 1. - if (char1IsVowel && char2IsVowel || char1IsConsonant && char2IsConsonant) return 1; - - // If one of char1 and char2 is a consonant, while the other is a vowel, the cost is 3. - return 3; - }; - // The cost of a gap is 2, regardless of what letter is aligned with the gap. - kleinbergExampleGapCostFunc = c -> 2; - - // char[] -> Character[] conversion courtesy of https://stackoverflow.com/a/27690990/1214974 - meanChars = "mean".chars().mapToObj(c -> (char)c).toArray(Character[]::new); - nameChars = "name".chars().mapToObj(c -> (char)c).toArray(Character[]::new); - - kleinbergAlignmentPricer = new AlignmentPricer<>(kleinbergExampleAlignmentCostFunc, - kleinbergExampleGapCostFunc); - - kleinbergSequenceAligner = new SequenceAlignment<>(kleinbergAlignmentPricer); - } - - @Test - public void kleinbergExampleOptAlignmentCostShouldBe6() { - // Cost of the optimal alignment of the two words - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(meanChars, nameChars); - final int expectedAlignmentCost = 6; - String msg = String.format("Kleinberg example: computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - - @Test - public void meanAlignedWithEmptyStringShouldBe8() { - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(meanChars, new Character[0]); - // 'mean' aligned with the empty string equals paying four gap costs, so total cost is: 4 * 2 = 8. - final int expectedAlignmentCost = 8; - String msg = String.format("'mean' aligned with empty string: computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - @Test - public void mAlignedWithNameShouldBe6() { - /* - * Note: this also uses the cost function specified in Kleinberg & Tardos. - * Best alignment should be: - * n a m e - * _ _ m _ - * This should have a cost of 3 * gapCost = 6 - */ - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(new Character[] { 'm' }, nameChars); - final int expectedAlignmentCost = 6; - String msg = String.format("'m' aligned with 'name': computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - @Test - public void meAlignedWithNameShouldBe4() { - /* - * Note: this also uses the cost function specified in Kleinberg & Tardos. - * Best alignment should be: - * n a m e - * _ _ m e - * This should have a cost of 2 * gapCost = 4 - */ - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(new Character[] { 'm', 'e' }, nameChars); - final int expectedAlignmentCost = 4; - String msg = String.format("'me' aligned with 'name': computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - // Check that order of arguments doesn't matter - final int optAlignmentCostReversed = kleinbergSequenceAligner.calculateAlignment(nameChars, new Character[] { 'm', 'e' }); - msg = "'me' aligned with 'name': different order of arguments unexpectedly produced different result"; - assertTrue(msg, optAlignmentCostReversed == optAlignmentCost && optAlignmentCostReversed == expectedAlignmentCost); - } - - @Test - public void ameAlignedWithNameShouldBe2() { - /* - * Note: this also uses the cost function specified in Kleinberg & Tardos. - * Best alignment should be: - * n a m e - * _ a m e - * This should have a cost of 1 * gapCost = 2 - */ - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(new Character[] { 'a', 'm', 'e' }, nameChars); - final int expectedAlignmentCost = 2; - String msg = String.format("'ame' aligned with 'name': computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - @Test - public void fameAlignedWithNameShouldBe1() { - /* - * Note: this also uses the cost function specified in Kleinberg & Tardos. - * Best alignment should be: - * n a m e - * f a m e - * This should have a cost of 1 * consonantMatchedWithConsonantCost = 1 - */ - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(new Character[] { 'f', 'a', 'm', 'e' }, - nameChars); - final int expectedAlignmentCost = 1; - String msg = String.format("'fame' aligned with 'name': computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - @Test - public void nameAlignedWithNameShouldBe0() { - /* - * Note: this also uses the cost function specified in Kleinberg & Tardos. - * Best alignment should be: - * n a m e - * n a m e - * This should have a cost of 0. - */ - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(new Character[] { 'n', 'a', 'm', 'e' }, - nameChars); - final int expectedAlignmentCost = 0; - String msg = String.format("'name' aligned with 'name': computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - @Test - public void emanAlignedWithNameShouldBe6() { - /* - * Note: this also uses the cost function specified in Kleinberg & Tardos. - * Best alignment should be: - * - * _ n a m e - * e m a n _ - * - * or - * - * n a m e _ - * _ e m a n - * - * This should have a cost of 2 * gapCost + 2 * consonantMatchedWithConsonantCost = 2 * 2 + 2 * 1 = 6. - */ - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(new Character[] { 'e', 'm', 'a', 'n' }, - nameChars); - final int expectedAlignmentCost = 6; - String msg = String.format("'eman' aligned with 'name': computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - @Test - public void naemAlignedWithNameShouldBe4() { - /* - * Note: this also uses the cost function specified in Kleinberg & Tardos. - * Best alignment should be: - * - * n a _ m e - * n a e m _ - * - * or - * - * n a m e _ - * n a _ e m - * - * This should have a cost of 2 * gapCost = 4. - */ - final int optAlignmentCost = kleinbergSequenceAligner.calculateAlignment(new Character[] { 'n', 'a', 'e', 'm' }, - nameChars); - final int expectedAlignmentCost = 4; - String msg = String.format("'naem' aligned with 'name': computed opt != expected opt (computed=%d expected=%d)", - optAlignmentCost, expectedAlignmentCost); - assertTrue(msg, optAlignmentCost == expectedAlignmentCost); - } - - - /** - * Checks if {@code letter} is a lowercase vowel. Note: for simplicity, 'y' is considered a vowel. - * @param letter A {@code char} expected to be a vowel. - * @return {@code true} if {@code letter} is a vowel, {@code false} otherwise. - */ - private boolean isVowel(char letter) { - for (char vowel : lowercaseVowels) { - if (letter == vowel) { - return true; - } - } - return false; - } - - /** - * Checks if {@code letter} is a lowercase consonant. Note: for simplicity, 'y' is considered a vowel. - * @param letter A {@code char} expected to be a consonant. - * @return {@code true} if {@code letter} is a consonant, {@code false} otherwise. - */ - private boolean isConsonant(char letter) { - for (char consonant : lowercaseConsonants) { - if (letter == consonant) { - return true; - } - } - return false; - } -}