diff --git a/Cargo.lock b/Cargo.lock index 6a337e2..26192f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,25 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -45,6 +65,21 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "clap" +version = "2.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "core-foundation" version = "0.7.0" @@ -464,6 +499,7 @@ dependencies = [ name = "nform" version = "0.1.0" dependencies = [ + "clap", "hex", "pcap", "reqwest", @@ -802,6 +838,12 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "syn" version = "1.0.31" @@ -827,6 +869,15 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "time" version = "0.1.43" @@ -924,6 +975,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -947,6 +1004,12 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.2" diff --git a/Cargo.toml b/Cargo.toml index ae8ea7b..bdcaad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,5 @@ edition = "2018" [dependencies] pcap = "0.7.0" hex = "0.4" +clap = "2.33.1" reqwest = { version = "0.10.6", features = ["blocking", "json"] } diff --git a/src/main.rs b/src/main.rs index 74fba90..8ad0ae4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,56 +2,72 @@ use pcap::Device; use std::collections::HashMap; use std::time::Instant; use std::env; +use std::process; +use clap::ArgMatches; + +mod utils; + +static mut CONFIG: Option = None; struct Config { threshold: u32, wait: u32, + use_discord: bool, discord_channel_id: String, discord_token: String } impl Config { - fn parse() -> Result { - - - let discord_channel_id = match env::var("DISCORD_CHANNEL_ID") { - Ok(id) => id, - _ => { - println!("Not notifying with discord. Not DISCORD_CHANNEL_ID env set."); - let value = String::from(""); - value + fn parse(matches: &ArgMatches) -> Result { + + let mut use_discord = false; + + let discord_channel_id = match matches.value_of("channel") { + Some(channel) => { + use_discord = true; + channel.to_string() + }, + None => match env::var("DISCORD_CHANNEL_ID") { + Ok(channel) => { + use_discord = true; + channel.to_string() + }, + Err(_) => { + use_discord = false; + String::from("") + } } }; - let discord_token = match env::var("DISCORD_TOKEN") { - Ok(token) => token, - _ => { - println!("Not notifying with discord. Not DISCORD_TOKEN env set."); - let value = String::from(""); - value - } + let discord_token = match matches.value_of("token") { + Some(value) => { + use_discord = true; + value.to_string() + }, + None => match env::var("DISCORD_TOKEN") { + Ok(value) => { + use_discord = true; + value.to_string() + }, + Err(_) => { + use_discord = false; + String::from("") + } + } }; // Instantiate Offender HitCounter with Threshold of 10 packets. - let threshold = match env::args().nth(1) { - Some(threshold) => threshold.parse().expect("Threshold must be a integer"), - _ => { - println!("Using default packet threshold of 5"); - 5 - } - }; + let threshold: u32 = matches.value_of("threshold").unwrap_or("5").parse() + .expect("threshold must be an integer"); + + let wait: u32 = matches.value_of("wait").unwrap_or("10").parse() + .expect("wait must be an integer"); - let wait = match env::args().nth(2) { - Some(wait) => wait.parse().expect("wait must be an integer"), - _ => { - println!("Using default discord notfication delay wait of 10 seconds"); - 10 - } - }; Ok(Config { threshold, wait, + use_discord, discord_channel_id, discord_token, }) @@ -190,8 +206,12 @@ fn notify_discord(intruder: &DecodedPacket) { fn main() { + // Parse Config with Clap + let matches = utils::parse_args(); + // Parse Config - let config = Config::parse().unwrap(); + // CONFIG = Some(Config::parse(&matches).unwrap()); + let config = Config::parse(&matches).unwrap(); // Instantiate Capture Device let mut cap = Device::lookup().unwrap() @@ -201,11 +221,10 @@ fn main() { println!("===== Config ==========================================="); println!("Threshold: {} (Only triggers after this many packets)", config.threshold); println!(" Wait: {} (Waits this many seconds before sending another Discord Message)", config.wait); - if config.discord_channel_id == "".to_string() || config.discord_token == "".to_string() { - println!(" Notify: None (set DISCORD_TOKEN and DISCORD_CHANNEL_ID env var to notify with Discord bot)"); - } else { + if config.use_discord { println!(" Notify: Discord"); - + } else { + println!(" Notify: None (set DISCORD_TOKEN and DISCORD_CHANNEL_ID env var to notify with Discord bot)"); } println!("========================================================="); @@ -227,3 +246,5 @@ fn main() { } } + + diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..99f7e2f --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,44 @@ +extern crate clap; + +pub fn parse_args() -> clap::ArgMatches<'static> { + let matches = clap::App::new("nform - Be nform'd of nmap scan") + .version("0.1.0") + .author("Ryan Plyler ") + .about("Detects stealth nmap scans and notifies via Discord Bot") + .arg(clap::Arg::with_name("threshold") + .short("t") + .long("threshold") + .takes_value(true) + .help("Number of scanning packets to capture before triggered")) + .arg(clap::Arg::with_name("discord") + .short("d") + .long("discord") + .takes_value(false) + .help("Use discord bot to notify of scanning activity")) + .arg(clap::Arg::with_name("token") + .short("k") + .long("token") + .takes_value(true) + .help("Discord Bot Auth token")) + .arg(clap::Arg::with_name("channel") + .short("c") + .long("channel") + .takes_value(true) + .help("Discord Bot channel ID")) + .arg(clap::Arg::with_name("wait") + .short("w") + .long("wait") + .takes_value(true) + .help("Delay in seconds between discord notifications")) + .get_matches(); + + matches +} + + + + + + + +