diff --git a/.travis.yml b/.travis.yml index 208339b..607f4c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ jobs: script: - cargo build - cargo test +- "ulimit -n 5000; cargo test timelimits:: -- --ignored --test-threads=1 --show-output" - cargo fmt -- --check after_failure: - wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh diff --git a/Cargo.lock b/Cargo.lock index 0ae154b..114525b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1138,6 +1138,7 @@ dependencies = [ "structopt", "toml", "trust-dns-resolver", + "wait-timeout", ] [[package]] @@ -1463,6 +1464,15 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "waker-fn" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 860d147..20c7501 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,9 @@ cidr-utils = "0.5.0" itertools = "0.9.0" trust-dns-resolver = { version = "0.19.5", features = ["dns-over-rustls"] } +[dev-dependencies] +wait-timeout = "0.2" + [package.metadata.deb] depends = "$auto, nmap" section = "rust" diff --git a/tests/timelimits.rs b/tests/timelimits.rs new file mode 100644 index 0000000..9851a3e --- /dev/null +++ b/tests/timelimits.rs @@ -0,0 +1,108 @@ +/* + * Test rustscan against different targets with a time limit. + * The tests assumes target/debug/rustscan has already been built. + * + * The tests are #[ignore] to avoid running them during normal development. + * + * Their tests in the timelimits module are run by travis during CI. + */ + +use std::process::Command; +use std::time::Duration; +use wait_timeout::ChildExt; + +const TIMEOUT_MARGIN: u32 = 3; + +fn run_rustscan_with_timeout(args: &[&str], timeout: Duration) { + println!("Running: target/debug/rustscan: {}", args.join(" ")); + + use std::time::Instant; + + let start = Instant::now(); + + let mut child = Command::new("target/debug/rustscan") + .args(args) + .spawn() + .unwrap(); + + let mut tries = TIMEOUT_MARGIN; + loop { + match child.wait_timeout(timeout).unwrap() { + Some(_status) => break, + None => { + tries -= 1; + if tries == 0 { + // child hasn't exited yet + child.kill().unwrap(); + child.wait().unwrap().code(); + panic!("Timeout while running command"); + } + } + } + } + let end = Instant::now(); + let duration = end.saturating_duration_since(start).as_secs_f32(); + + println!("time: {:1.1}s", duration); +} + +mod timelimits { + + #[test] + #[ignore] + fn scan_localhost() { + let timeout = super::Duration::from_secs(25); + super::run_rustscan_with_timeout(&["--greppable", "--no-nmap", "127.0.0.1"], timeout); + } + + #[test] + #[ignore] + fn scan_google_com() { + super::run_rustscan_with_timeout( + &[ + "--greppable", + "--no-nmap", + "-u", + "5000", + "-b", + "2500", + "google.com", + ], + super::Duration::from_secs(28), + ); + } + + #[test] + #[ignore] + fn scan_example_com() { + super::run_rustscan_with_timeout( + &[ + "--greppable", + "--no-nmap", + "-u", + "5000", + "-b", + "2500", + "example.com", + ], + super::Duration::from_secs(28), + ); + } + + #[test] + #[ignore] + fn scan_rustscan_cmnatic_co_uk() { + super::run_rustscan_with_timeout( + &[ + "--greppable", + "--no-nmap", + "-u", + "5000", + "-b", + "2500", + "rustscan.cmnatic.co.uk", + ], + super::Duration::from_secs(26), + ); + } +}