diff --git a/.travis.yml b/.travis.yml index a4678e106..4004284d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: rust os: - linux - osx - # - windows + - windows arch: - amd64 diff --git a/Cargo.toml b/Cargo.toml index ddb62bc50..bb66203c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ colored = "2.0.0" structopt = "0.3.16" async-std = "1.6.3" futures = "0.3" -rlimit = "0.4.0" shell-words = "1.0.0" log = "0.4.0" env_logger = "0.7.1" @@ -31,6 +30,9 @@ rand = "0.7.3" colorful = "0.2.1" ansi_term = "0.12.1" +[target."cfg(not(windows))".dependencies] +rlimit = "0.4.0" + [package.metadata.deb] depends = "$auto, nmap" section = "rust" diff --git a/README.md b/README.md index c9794718d..ab2045728 100644 --- a/README.md +++ b/README.md @@ -213,25 +213,23 @@ rustscan -h ``` ``` +rustscan 1.7.1 Fast Port Scanner built in Rust. WARNING Do not use this program against sensitive infrastructure since the specified server may not be able to handle this many socket connections at once. - Discord https://discord.gg/GFrQsGy - GitHub https://github.com/RustScan/RustScan USAGE: - rustscan [FLAGS] [OPTIONS] ... [-- ...] + rustscan [FLAGS] [OPTIONS] ... [-- ...] FLAGS: - -a, --accessible - -h, --help Prints help information - -q, --quiet Quiet mode. Only output the ports. No Nmap. Useful for grep or outputting to a file - -V, --version Prints version information + -h, --help Prints help information + -q, --quiet Quiet mode. Only output the ports. No Nmap. Useful for grep or outputting to a file + -V, --version Prints version information OPTIONS: -b, --batch-size The batch size for port scanning, it increases or slows the speed of scanning. Depends on the open file limit of your OS. If you do 65535 it will do every port at the same time. Although, your OS may not support this [default: 4500] - -p, --ports ... A list of comma separed ports to be scanned. Example: 80,443,8080. - -r, --range A range of ports with format start-end. Example: 1-1000 --scan-order The order of scanning to be performed. The "serial" option will scan ports in ascending order while the "random" option will scan ports randomly [default: serial] [possible values: Serial, Random] @@ -239,11 +237,11 @@ OPTIONS: -u, --ulimit Automatically ups the ULIMIT with the value you provided ARGS: - ... A list of comma separated IP addresses or hosts to be scanned - ... The Nmap arguments to run. To use the argument -A, end RustScan's args with '-- -A'. - Example: 'rustscan -T 1500 127.0.0.1 -- -A -sC'. This command adds -Pn -vvv -p $PORTS - automatically to nmap. For things like --script '(safe and vuln)' enclose it in quotations - marks \"'(safe and vuln)'\"") + ... A list of comma separated IP addresses to be scanned + ... The Nmap arguments to run. To use the argument -A, end RustScan's args with '-- -A'. Example: + 'rustscan -T 1500 127.0.0.1 -- -A -sC'. This command adds -Pn -vvv -p $PORTS automatically to + nmap. For things like --script '(safe and vuln)' enclose it in quotations marks \"'(safe and + vuln)'\"") ``` The format is `rustscan -b 500 -T 1500 192.168.0.1` to scan 192.168.0.1 with 500 batch size with a timeout of 1500ms. The timeout is how long RustScan waits for a response until it assumes the port is closed. diff --git a/src/main.rs b/src/main.rs index 0012d47e5..d72281855 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,9 +11,13 @@ use port_strategy::PortStrategy; use colorful::Color; use colorful::Colorful; use futures::executor::block_on; -use rlimit::Resource; -use rlimit::{getrlimit, setrlimit}; + +#[cfg(not(target_os = "windows"))] +use rlimit::{getrlimit, setrlimit, Resource}; + use std::collections::HashMap; +#[cfg(not(target_os = "windows"))] +use std::convert::TryInto; use std::process::Command; use std::str::FromStr; use std::{net::IpAddr, net::ToSocketAddrs, time::Duration}; @@ -25,9 +29,9 @@ extern crate dirs; const LOWEST_PORT_NUMBER: u16 = 1; const TOP_PORT_NUMBER: u16 = 65535; // Average value for Ubuntu -const DEFAULT_FILE_DESCRIPTORS_LIMIT: rlimit::rlim = 8000; +const DEFAULT_FILE_DESCRIPTORS_LIMIT: u32 = 8000; // Safest batch size based on experimentation -const AVERAGE_BATCH_SIZE: rlimit::rlim = 3000; +const AVERAGE_BATCH_SIZE: u32 = 3000; #[macro_use] extern crate log; @@ -110,7 +114,7 @@ struct Opts { /// Automatically ups the ULIMIT with the value you provided. #[structopt(short, long)] - ulimit: Option, + ulimit: Option, /// The order of scanning to be performed. The "serial" option will /// scan ports in ascending order while the "random" option will scan @@ -156,7 +160,8 @@ fn main() { std::process::exit(1); } - let ulimit: rlimit::rlim = adjust_ulimit_size(&opts); + let ulimit: u32 = adjust_ulimit_size(&opts); + let batch_size: u16 = infer_batch_size(&opts, ulimit); let scanner = Scanner::new( @@ -300,9 +305,10 @@ fn parse_ips(opts: &Opts) -> Vec { ips } -fn adjust_ulimit_size(opts: &Opts) -> rlimit::rlim { +#[cfg(not(target_os = "windows"))] +fn adjust_ulimit_size(opts: &Opts) -> u32 { if opts.ulimit.is_some() { - let limit: rlimit::rlim = opts.ulimit.unwrap(); + let limit: rlimit::rlim = opts.ulimit.unwrap().into(); match setrlimit(Resource::NOFILE, limit, limit) { Ok(_) => { @@ -317,14 +323,21 @@ fn adjust_ulimit_size(opts: &Opts) -> rlimit::rlim { let (rlim, _) = getrlimit(Resource::NOFILE).unwrap(); - rlim + rlim.try_into().unwrap() } -fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u16 { - let mut batch_size: rlimit::rlim = opts.batch_size.into(); +// Rlimit does not support Windows +// set to 1000 if Windows is used +#[cfg(target_os = "windows")] +fn adjust_ulimit_size(_opts: &Opts) -> u32 { + 1000 +} + +fn infer_batch_size(opts: &Opts, ulimit: u32) -> u16 { + let mut batch_size: u32 = opts.batch_size.into(); // Adjust the batch size when the ulimit value is lower than the desired batch size - if ulimit < batch_size { + if ulimit < batch_size && !(cfg!(windows)) { warning!("File limit is lower than default batch size. Consider upping with --ulimt. May cause harm to sensitive servers", opts.quiet ); @@ -336,7 +349,11 @@ fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u16 { // ulimit is smaller than aveage batch size // user must have very small ulimit // decrease batch size to half of ulimit - warning!("Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. "); + if !(cfg!(windows)) { + warning!("Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. "); + } else { + warning!("Windows is known to be much slower than scanning on Unix systems. Use the Docker image if you need faster speeds."); + } info!("Halving batch_size because ulimit is smaller than average batch size"); batch_size = ulimit / 2 } else if ulimit > DEFAULT_FILE_DESCRIPTORS_LIMIT { @@ -362,6 +379,7 @@ fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u16 { mod tests { use crate::{adjust_ulimit_size, infer_batch_size, parse_ips, print_opening, Opts, ScanOrder}; + #[cfg(not(target_os = "windows"))] #[test] fn batch_size_lowered() { let opts = Opts { @@ -381,6 +399,7 @@ mod tests { assert!(batch_size < 50_000); } + #[cfg(not(target_os = "windows"))] #[test] fn batch_size_lowered_average_size() { let opts = Opts { @@ -399,6 +418,7 @@ mod tests { assert!(batch_size == 3_000); } + #[cfg(not(target_os = "windows"))] #[test] fn batch_size_equals_ulimit_lowered() { // because ulimit and batch size are same size, batch size is lowered @@ -419,6 +439,7 @@ mod tests { assert!(batch_size == 4_900); } + #[cfg(not(target_os = "windows"))] #[test] fn batch_size_adjusted_2000() { // ulimit == batch_size diff --git a/src/scripting_engine/mod.rs b/src/scripting_engine/mod.rs new file mode 100644 index 000000000..e69de29bb