From 52a3c15b27ab7fda8819347986cd7adb18c28b1e Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 11:39:21 -0600 Subject: [PATCH 01/31] main: Open the dump files For now, I'll use unwrap to make this die if the file cannot be opened for reading. In the future, it'll just want a match block around it that errors out and exits. Or maybe I should try the ? trait? Food for thought. Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.rs b/src/main.rs index fcbe5f8..35c336f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,8 @@ extern crate csv; extern crate clap; use clap::{App, Arg}; +use std::fs::File; + const VERSION: &str = env!("CARGO_PKG_VERSION"); const AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); @@ -33,6 +35,8 @@ fn main() { Some(results) => { for dump in results { println!("Dumps: {:?}", dump); + + let file = File::open(dump).unwrap(); } } None => panic!("No dump filenames given; cannot do anything."), From a46e7d85d6e72711132344389bc7c060b803cfe2 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 11:42:37 -0600 Subject: [PATCH 02/31] Set up empty lib.rs file Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/lib.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/lib.rs diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e69de29 From 1eb1de47ee5987c904f1043a324337212ff2ef73 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 11:42:54 -0600 Subject: [PATCH 03/31] lib: Use external csv crate Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index e69de29..9898be0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1 @@ +extern crate csv; From 72125081efbe513be8e398bca64b87e77ed23cb7 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 11:44:18 -0600 Subject: [PATCH 04/31] lib: Start on dump module Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 3 +++ src/lib.rs | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 src/dump.rs diff --git a/src/dump.rs b/src/dump.rs new file mode 100644 index 0000000..7733a07 --- /dev/null +++ b/src/dump.rs @@ -0,0 +1,3 @@ +// {Host, Protocol, Port} => Host +// {Plugin ID, CVE, CVSS, Name, Synopsis, Description, Solution, See Also} => Plugin +// {Plugin Output} => Detection (&Host, &Plugin) also diff --git a/src/lib.rs b/src/lib.rs index 9898be0..ef9a7b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,3 @@ extern crate csv; +pub mod dump; +pub use dump::*; From b31a9319b19c95d78343d0f83365ade2c812be54 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 12:56:37 -0600 Subject: [PATCH 05/31] dump: Add five structs To get started, we'll use these. Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 7733a07..04ba99a 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,3 +1,18 @@ // {Host, Protocol, Port} => Host // {Plugin ID, CVE, CVSS, Name, Synopsis, Description, Solution, See Also} => Plugin // {Plugin Output} => Detection (&Host, &Plugin) also + +struct Record { +} + +struct Plugin { +} + +struct Host { +} + +struct Detection { +} + +pub struct Dump { +} From 3128857793c3234a53bd06546c478908a8f07c0d Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 12:59:40 -0600 Subject: [PATCH 06/31] dump: Add .read fn and use it in main Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 6 ++++++ src/main.rs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 04ba99a..6a87934 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -16,3 +16,9 @@ struct Detection { pub struct Dump { } + +impl Dump { + pub fn read(rdr: R) -> Dump { + Dump {} + } +} diff --git a/src/main.rs b/src/main.rs index 35c336f..1af2333 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,8 @@ fn main() { println!("Dumps: {:?}", dump); let file = File::open(dump).unwrap(); + + Dump::read(file); } } None => panic!("No dump filenames given; cannot do anything."), From a37886096756bc97f4eb509ab102591c9cf018a8 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 12:59:58 -0600 Subject: [PATCH 07/31] main: Resolve namespace errors by using nessify::* Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 1af2333..7392e27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ extern crate csv; extern crate clap; use clap::{App, Arg}; +use nessify::*; use std::fs::File; const VERSION: &str = env!("CARGO_PKG_VERSION"); From 8d84febd927ee8da83c4ad6b7d2fb2ffcff04d80 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 13:01:06 -0600 Subject: [PATCH 08/31] cargo: Add serde and serde_derive as first-class dependencies Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- Cargo.lock | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ 2 files changed, 53 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 02bbe6c..ce37453 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,12 +57,53 @@ version = "0.0.0" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "textwrap" @@ -77,6 +118,11 @@ name = "unicode-width" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" @@ -85,6 +131,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "2e20fde37801e83c891a2dc4ebd3b81f0da4d1fb67a9e0a2a3b921e2536a58ee" +"checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea" +"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/Cargo.toml b/Cargo.toml index d10c248..1624986 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,5 @@ license = 'MIT' [dependencies] clap = { version = '~2.32', default-features = false } csv = '~1.0' +serde = { version = '~1.0', features = ['derive'] } +serde_derive = '~1.0' From 0f6e4feeedab3992710a7b9a511c9e28c00f0cec Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 13:01:24 -0600 Subject: [PATCH 09/31] lib: Wire up serde and serde_derive Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index ef9a7b1..a8b0469 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,9 @@ extern crate csv; + +extern crate serde; + +#[macro_use] +extern crate serde_derive; + pub mod dump; pub use dump::*; From e448dd7a8412f151e183a534cba6a8571afa2bdf Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:09:56 -0600 Subject: [PATCH 10/31] Dump::read: Instantiate a csv::Reader and begin to use it Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dump.rs b/src/dump.rs index 6a87934..e851709 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -19,6 +19,10 @@ pub struct Dump { impl Dump { pub fn read(rdr: R) -> Dump { - Dump {} + let mut reader = csv::Reader::from_reader(rdr); + + Dump { + filename: "test".to_string(), + } } } From 33eb946dff3ce5c43df48dc51a40b61125e3a6c0 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:10:45 -0600 Subject: [PATCH 11/31] Record: Add fields These correspond one-to-one with the fields in a Nessus CSV file. Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index e851709..bc70232 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -3,6 +3,19 @@ // {Plugin Output} => Detection (&Host, &Plugin) also struct Record { + plugin_id: i32, + cve: String, + cvss: String, + risk: String, + host: String, + protocol: String, + port: u32, + name: String, + synopsis: String, + description: String, + solution: String, + see_also: String, + plugin_output: String, } struct Plugin { From e1c3873164d25e817bba6f7db4de36795bdfb624 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:11:16 -0600 Subject: [PATCH 12/31] Record: derive Debug and Deserialize Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dump.rs b/src/dump.rs index bc70232..6c2582c 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -2,6 +2,7 @@ // {Plugin ID, CVE, CVSS, Name, Synopsis, Description, Solution, See Also} => Plugin // {Plugin Output} => Detection (&Host, &Plugin) also +#[derive(Debug, Deserialize)] struct Record { plugin_id: i32, cve: String, From d0c284cc51a40f3b26627a3979065a48ec056434 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:11:42 -0600 Subject: [PATCH 13/31] Record: Add serde mappings between field headers and fields Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 6c2582c..3e23fce 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -4,18 +4,31 @@ #[derive(Debug, Deserialize)] struct Record { + #[serde(rename = "Plugin ID")] plugin_id: i32, + #[serde(rename = "CVE")] cve: String, + #[serde(rename = "CVSS")] cvss: String, + #[serde(rename = "Risk")] risk: String, + #[serde(rename = "Host")] host: String, + #[serde(rename = "Protocol")] protocol: String, + #[serde(rename = "Port")] port: u32, + #[serde(rename = "Name")] name: String, + #[serde(rename = "Synopsis")] synopsis: String, + #[serde(rename = "Description")] description: String, + #[serde(rename = "Solution")] solution: String, + #[serde(rename = "See Also")] see_also: String, + #[serde(rename = "Plugin Output")] plugin_output: String, } From 1b75e384970424a269e57ad9b0759d96bdffc3b8 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:19:49 -0600 Subject: [PATCH 14/31] dump: Fill out fields in Plugin, Host, Detection, Dump structs Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 3e23fce..b19baca 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,3 +1,5 @@ +use std::net::IpAddr; + // {Host, Protocol, Port} => Host // {Plugin ID, CVE, CVSS, Name, Synopsis, Description, Solution, See Also} => Plugin // {Plugin Output} => Detection (&Host, &Plugin) also @@ -33,15 +35,32 @@ struct Record { } struct Plugin { + id: i32, + cve: Vec, + cvss: String, + risk: String, + name: String, + synopsis: String, + description: String, + solution: String, + see_also: String, } struct Host { + hostname: String, + addr: IpAddr, } struct Detection { + host: Host, + port: u32, + protocol: String, + plugin: Plugin, + plugin_output: String, } pub struct Dump { + filename: String, } impl Dump { From 1dfe104e539545c875e0a6918d19eac7a6882ce7 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:22:29 -0600 Subject: [PATCH 15/31] Plugin: Add PartialEq trait to Plugin Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index b19baca..18826b2 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,3 +1,5 @@ +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; use std::net::IpAddr; // {Host, Protocol, Port} => Host @@ -46,6 +48,15 @@ struct Plugin { see_also: String, } +impl PartialEq for Plugin { + fn eq(&self, other: &Plugin) -> bool { + let mut s = DefaultHasher::new(); + let mut o = DefaultHasher::new(); + self.hash(&mut s); + other.hash(&mut o); + s.finish() == o.finish() + } +} struct Host { hostname: String, addr: IpAddr, From 3f9f4ef5b86e5057bf531077599bf633aa720511 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:23:28 -0600 Subject: [PATCH 16/31] Plugin: Define Hash trait for Plugin as well This is done primarily because the cve field needs to be excluded. A plugin with a different cve field should not exist. Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 18826b2..cc8890f 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -57,6 +57,19 @@ impl PartialEq for Plugin { s.finish() == o.finish() } } + +impl Hash for Plugin { + fn hash(&self, state: &mut H) { + self.id.hash(state); + self.cvss.hash(state); + self.risk.hash(state); + self.name.hash(state); + self.synopsis.hash(state); + self.description.hash(state); + self.solution.hash(state); + self.see_also.hash(state); + } +} struct Host { hostname: String, addr: IpAddr, From 5f23ae8c20fe837cc3f7ef10e4cc0e677f9e2501 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:24:12 -0600 Subject: [PATCH 17/31] Plugin: Derive Clone, Eq traits Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dump.rs b/src/dump.rs index cc8890f..bc98a80 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -36,6 +36,7 @@ struct Record { plugin_output: String, } +#[derive(Clone, Eq)] struct Plugin { id: i32, cve: Vec, From 45576881e71f7004822d7331ccbf653448b9aa2d Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:24:23 -0600 Subject: [PATCH 18/31] Host: Derive Clone, Hash, Eq, PartialEq traits Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index bc98a80..9b1a978 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -71,6 +71,8 @@ impl Hash for Plugin { self.see_also.hash(state); } } + +#[derive(Clone, Hash, Eq, PartialEq)] struct Host { hostname: String, addr: IpAddr, From 0ef7c7dc65cf6168d9176b4f4a3942bd297ae6ce Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:24:33 -0600 Subject: [PATCH 19/31] Detection: Derive Clone, Hash, Eq, PartialEq traits Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dump.rs b/src/dump.rs index 9b1a978..74f1247 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -78,6 +78,7 @@ struct Host { addr: IpAddr, } +#[derive(Clone, Hash, Eq, PartialEq)] struct Detection { host: Host, port: u32, From 68a100e6770fc1c7ab650c7b2df69ce17525c7af Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:25:36 -0600 Subject: [PATCH 20/31] Dump::read: Begin parsing the CSV file N.b. that csv::Reader already uses BufReader---I initially planned on adding it in here but plans changed. Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/dump.rs b/src/dump.rs index 74f1247..5a3bb35 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,4 +1,4 @@ -use std::collections::hash_map::DefaultHasher; +use std::collections::{hash_map::DefaultHasher, HashSet}; use std::hash::{Hash, Hasher}; use std::net::IpAddr; @@ -95,6 +95,20 @@ impl Dump { pub fn read(rdr: R) -> Dump { let mut reader = csv::Reader::from_reader(rdr); + let mut plugins: HashSet = HashSet::new(); + let mut hosts: HashSet = HashSet::new(); + let mut detections: HashSet = HashSet::new(); + + reader + .deserialize() + .filter_map(|result| -> Option { result.ok() }) + .for_each(|record| { + }); + + println!("plugins: {}", plugins.len()); + println!("hosts: {}", hosts.len()); + println!("detections: {}", detections.len()); + Dump { filename: "test".to_string(), } From 08a8077ff4dc70020af3e2a27d8d842ed7e4e758 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:27:47 -0600 Subject: [PATCH 21/31] Dump::read: Extract the Plugin fields from the Record Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 5a3bb35..c614fd8 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -103,6 +103,18 @@ impl Dump { .deserialize() .filter_map(|result| -> Option { result.ok() }) .for_each(|record| { + let record_plugin = Plugin { + id: record.plugin_id, + cve: vec![record.cve], + cvss: record.cvss, + risk: record.risk, + name: record.name, + synopsis: record.synopsis, + description: record.description, + solution: record.solution, + see_also: record.see_also, + }; + }); println!("plugins: {}", plugins.len()); From 8df72c8a2a978617cae51eb8b7b9c593011fb768 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:29:05 -0600 Subject: [PATCH 22/31] Dump::read: Also parse out the Host fields from the Record Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index c614fd8..3b3711e 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -115,6 +115,11 @@ impl Dump { see_also: record.see_also, }; + let record_host = Host { + hostname: record.host.clone(), + addr: record.host.parse().unwrap(), + }; + }); println!("plugins: {}", plugins.len()); From 1886858f5793fc67bacf8654f1bf53bf9bbb43ea Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:35:35 -0600 Subject: [PATCH 23/31] Dump::read: Fill Plugins into the HashSet Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 3b3711e..6765d84 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -120,6 +120,20 @@ impl Dump { addr: record.host.parse().unwrap(), }; + if let Some(plugin) = plugins.get(&record_plugin) { + if !plugin.cve.contains(record_plugin.cve.first().unwrap()) { + plugins.replace(Plugin { + cve: [plugin.cve.as_slice(), record_plugin.cve.as_slice()].concat(), + ..(plugin.clone()) + }); + + print!("p"); + } + } else { + assert_eq!(plugins.insert(record_plugin.clone()), true); + + print!("P"); + } }); println!("plugins: {}", plugins.len()); From 434a21ceaa500e11aa12234af4a1b75c48571d82 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:35:55 -0600 Subject: [PATCH 24/31] Dump::read: Fill Hosts into their HashSet Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 6765d84..351ce30 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -134,6 +134,13 @@ impl Dump { print!("P"); } + + let host = hosts.get(&record_host); + + if host.is_none() { + assert_eq!(hosts.insert(record_host.clone()), true); + print!("H") + } }); println!("plugins: {}", plugins.len()); From 3afb32a171f0c5d5eb2555466af9d681d48bdc92 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:37:13 -0600 Subject: [PATCH 25/31] Dump::read: Finish reading and parsing and such Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 351ce30..555bd77 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -87,8 +87,10 @@ struct Detection { plugin_output: String, } +#[allow(dead_code)] pub struct Dump { filename: String, + detections: Vec, } impl Dump { @@ -141,6 +143,19 @@ impl Dump { assert_eq!(hosts.insert(record_host.clone()), true); print!("H") } + + let plugin: Plugin = plugins.get(&record_plugin).unwrap().clone(); + let host: Host = hosts.get(&record_host).unwrap().clone(); + + let record_detection = Detection { + host, + plugin, + plugin_output: record.plugin_output, + port: record.port, + protocol: record.protocol, + }; + + detections.insert(record_detection); }); println!("plugins: {}", plugins.len()); @@ -149,6 +164,7 @@ impl Dump { Dump { filename: "test".to_string(), + detections: detections.iter().cloned().collect(), } } } From 59d7c63e8f7455eb0fefb56c4379aea5dc449315 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 14:37:25 -0600 Subject: [PATCH 26/31] Dump::read: Add a couple of minutia Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dump.rs b/src/dump.rs index 555bd77..5033365 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -101,6 +101,7 @@ impl Dump { let mut hosts: HashSet = HashSet::new(); let mut detections: HashSet = HashSet::new(); + // TODO refactor for efficiency and conciseness reader .deserialize() .filter_map(|result| -> Option { result.ok() }) @@ -158,6 +159,8 @@ impl Dump { detections.insert(record_detection); }); + println!(); + println!("plugins: {}", plugins.len()); println!("hosts: {}", hosts.len()); println!("detections: {}", detections.len()); From db0953341fe3094553b920ce70674d6ff737c3b5 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 15:31:33 -0600 Subject: [PATCH 27/31] dump: Move Record struct into its own file Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 35 ++--------------------------------- src/dump/record.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 33 deletions(-) create mode 100644 src/dump/record.rs diff --git a/src/dump.rs b/src/dump.rs index 5033365..2106dc1 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -2,39 +2,7 @@ use std::collections::{hash_map::DefaultHasher, HashSet}; use std::hash::{Hash, Hasher}; use std::net::IpAddr; -// {Host, Protocol, Port} => Host -// {Plugin ID, CVE, CVSS, Name, Synopsis, Description, Solution, See Also} => Plugin -// {Plugin Output} => Detection (&Host, &Plugin) also - -#[derive(Debug, Deserialize)] -struct Record { - #[serde(rename = "Plugin ID")] - plugin_id: i32, - #[serde(rename = "CVE")] - cve: String, - #[serde(rename = "CVSS")] - cvss: String, - #[serde(rename = "Risk")] - risk: String, - #[serde(rename = "Host")] - host: String, - #[serde(rename = "Protocol")] - protocol: String, - #[serde(rename = "Port")] - port: u32, - #[serde(rename = "Name")] - name: String, - #[serde(rename = "Synopsis")] - synopsis: String, - #[serde(rename = "Description")] - description: String, - #[serde(rename = "Solution")] - solution: String, - #[serde(rename = "See Also")] - see_also: String, - #[serde(rename = "Plugin Output")] - plugin_output: String, -} +mod record; #[derive(Clone, Eq)] struct Plugin { @@ -86,6 +54,7 @@ struct Detection { plugin: Plugin, plugin_output: String, } +use record::*; #[allow(dead_code)] pub struct Dump { diff --git a/src/dump/record.rs b/src/dump/record.rs new file mode 100644 index 0000000..9821ec6 --- /dev/null +++ b/src/dump/record.rs @@ -0,0 +1,33 @@ +// {Host, Protocol, Port} => Host +// {Plugin ID, CVE, CVSS, Name, Synopsis, Description, Solution, See Also} => Plugin +// {Plugin Output} => Detection (&Host, &Plugin) also + +#[derive(Debug, Deserialize)] +pub struct Record { + #[serde(rename = "Plugin ID")] + pub plugin_id: i32, + #[serde(rename = "CVE")] + pub cve: String, + #[serde(rename = "CVSS")] + pub cvss: String, + #[serde(rename = "Risk")] + pub risk: String, + #[serde(rename = "Host")] + pub host: String, + #[serde(rename = "Protocol")] + pub protocol: String, + #[serde(rename = "Port")] + pub port: u32, + #[serde(rename = "Name")] + pub name: String, + #[serde(rename = "Synopsis")] + pub synopsis: String, + #[serde(rename = "Description")] + pub description: String, + #[serde(rename = "Solution")] + pub solution: String, + #[serde(rename = "See Also")] + pub see_also: String, + #[serde(rename = "Plugin Output")] + pub plugin_output: String, +} From 2c461d9e2ad9e65811b4376945110d369d1ad8fe Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 15:33:51 -0600 Subject: [PATCH 28/31] dump: Move host into its own module Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 9 ++------- src/dump/host.rs | 7 +++++++ 2 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 src/dump/host.rs diff --git a/src/dump.rs b/src/dump.rs index 2106dc1..ab32cbd 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,7 +1,7 @@ use std::collections::{hash_map::DefaultHasher, HashSet}; use std::hash::{Hash, Hasher}; -use std::net::IpAddr; +mod host; mod record; #[derive(Clone, Eq)] @@ -40,12 +40,6 @@ impl Hash for Plugin { } } -#[derive(Clone, Hash, Eq, PartialEq)] -struct Host { - hostname: String, - addr: IpAddr, -} - #[derive(Clone, Hash, Eq, PartialEq)] struct Detection { host: Host, @@ -54,6 +48,7 @@ struct Detection { plugin: Plugin, plugin_output: String, } +use host::*; use record::*; #[allow(dead_code)] diff --git a/src/dump/host.rs b/src/dump/host.rs new file mode 100644 index 0000000..70cedf2 --- /dev/null +++ b/src/dump/host.rs @@ -0,0 +1,7 @@ +use std::net::IpAddr; + +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub struct Host { + pub hostname: String, + pub addr: IpAddr, +} From fcb89d918ee199eb62a9d8059b992f23c563a3a7 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 15:35:04 -0600 Subject: [PATCH 29/31] dump: Move Plugin struct into its own module Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 41 +++-------------------------------------- src/dump/plugin.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 38 deletions(-) create mode 100644 src/dump/plugin.rs diff --git a/src/dump.rs b/src/dump.rs index ab32cbd..1d89556 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,45 +1,9 @@ -use std::collections::{hash_map::DefaultHasher, HashSet}; -use std::hash::{Hash, Hasher}; +use std::collections::HashSet; mod host; +mod plugin; mod record; -#[derive(Clone, Eq)] -struct Plugin { - id: i32, - cve: Vec, - cvss: String, - risk: String, - name: String, - synopsis: String, - description: String, - solution: String, - see_also: String, -} - -impl PartialEq for Plugin { - fn eq(&self, other: &Plugin) -> bool { - let mut s = DefaultHasher::new(); - let mut o = DefaultHasher::new(); - self.hash(&mut s); - other.hash(&mut o); - s.finish() == o.finish() - } -} - -impl Hash for Plugin { - fn hash(&self, state: &mut H) { - self.id.hash(state); - self.cvss.hash(state); - self.risk.hash(state); - self.name.hash(state); - self.synopsis.hash(state); - self.description.hash(state); - self.solution.hash(state); - self.see_also.hash(state); - } -} - #[derive(Clone, Hash, Eq, PartialEq)] struct Detection { host: Host, @@ -49,6 +13,7 @@ struct Detection { plugin_output: String, } use host::*; +use plugin::*; use record::*; #[allow(dead_code)] diff --git a/src/dump/plugin.rs b/src/dump/plugin.rs new file mode 100644 index 0000000..39e4d38 --- /dev/null +++ b/src/dump/plugin.rs @@ -0,0 +1,38 @@ +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; + +#[derive(Clone, Debug, Eq)] +pub struct Plugin { + pub id: i32, + pub cve: Vec, + pub cvss: String, + pub risk: String, + pub name: String, + pub synopsis: String, + pub description: String, + pub solution: String, + pub see_also: String, +} + +impl PartialEq for Plugin { + fn eq(&self, other: &Plugin) -> bool { + let mut s = DefaultHasher::new(); + let mut o = DefaultHasher::new(); + self.hash(&mut s); + other.hash(&mut o); + s.finish() == o.finish() + } +} + +impl Hash for Plugin { + fn hash(&self, state: &mut H) { + self.id.hash(state); + self.cvss.hash(state); + self.risk.hash(state); + self.name.hash(state); + self.synopsis.hash(state); + self.description.hash(state); + self.solution.hash(state); + self.see_also.hash(state); + } +} From feb6c2d1fcd871c7743eb21ac6c36348c0dee800 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 15:35:33 -0600 Subject: [PATCH 30/31] dump: Move Detection struct into its own module Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 11 +++-------- src/dump/detection.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 src/dump/detection.rs diff --git a/src/dump.rs b/src/dump.rs index 1d89556..c86375c 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,21 +1,16 @@ use std::collections::HashSet; +mod detection; mod host; mod plugin; mod record; -#[derive(Clone, Hash, Eq, PartialEq)] -struct Detection { - host: Host, - port: u32, - protocol: String, - plugin: Plugin, - plugin_output: String, -} +use detection::*; use host::*; use plugin::*; use record::*; +#[derive(Debug, Clone)] #[allow(dead_code)] pub struct Dump { filename: String, diff --git a/src/dump/detection.rs b/src/dump/detection.rs new file mode 100644 index 0000000..40f14ab --- /dev/null +++ b/src/dump/detection.rs @@ -0,0 +1,11 @@ +use super::host::*; +use super::plugin::*; + +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub struct Detection { + pub host: Host, + pub port: u32, + pub protocol: String, + pub plugin: Plugin, + pub plugin_output: String, +} From 4c3a1de7c2622a55a7e460168441e221a7c9ccd0 Mon Sep 17 00:00:00 2001 From: Kristofer Rye Date: Wed, 6 Feb 2019 15:36:06 -0600 Subject: [PATCH 31/31] Begin testing dump module Signed-off-by: Kristofer Rye Tested-by: Kristofer Rye --- src/dump.rs | 15 ++------------- tests/dump.rs | 14 ++++++++++++++ tests/main.rs | 1 + 3 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 tests/dump.rs create mode 100644 tests/main.rs diff --git a/src/dump.rs b/src/dump.rs index c86375c..7573457 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -13,8 +13,8 @@ use record::*; #[derive(Debug, Clone)] #[allow(dead_code)] pub struct Dump { - filename: String, - detections: Vec, + pub filename: String, + pub detections: Vec, } impl Dump { @@ -53,20 +53,15 @@ impl Dump { cve: [plugin.cve.as_slice(), record_plugin.cve.as_slice()].concat(), ..(plugin.clone()) }); - - print!("p"); } } else { assert_eq!(plugins.insert(record_plugin.clone()), true); - - print!("P"); } let host = hosts.get(&record_host); if host.is_none() { assert_eq!(hosts.insert(record_host.clone()), true); - print!("H") } let plugin: Plugin = plugins.get(&record_plugin).unwrap().clone(); @@ -83,12 +78,6 @@ impl Dump { detections.insert(record_detection); }); - println!(); - - println!("plugins: {}", plugins.len()); - println!("hosts: {}", hosts.len()); - println!("detections: {}", detections.len()); - Dump { filename: "test".to_string(), detections: detections.iter().cloned().collect(), diff --git a/tests/dump.rs b/tests/dump.rs new file mode 100644 index 0000000..8c83ec7 --- /dev/null +++ b/tests/dump.rs @@ -0,0 +1,14 @@ +use nessify::dump::*; + +#[test] +fn parses_no_records_if_schema_is_bad() { + let data = "invalid,csv +what are you,doing"; + + let dump: Dump = Dump::read(data.as_bytes()); + + dbg!(dump.clone()); + + assert_eq!(dump.clone().filename, "test"); + assert_eq!(dump.clone().detections.len(), 0); +} diff --git a/tests/main.rs b/tests/main.rs new file mode 100644 index 0000000..259ced5 --- /dev/null +++ b/tests/main.rs @@ -0,0 +1 @@ +mod dump;