diff --git a/Cargo.lock b/Cargo.lock
index d673c82..2463c39 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -208,6 +208,19 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+[[package]]
+name = "cidr-utils"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89f7b6372f3c783f6d44c0da283d3694af4104967bf2371cb3bdc9d09e1cfe00"
+dependencies = [
+ "debug-helper",
+ "num-bigint",
+ "num-traits",
+ "once_cell",
+ "regex",
+]
+
[[package]]
name = "clap"
version = "2.33.2"
@@ -266,6 +279,12 @@ dependencies = [
"lazy_static",
]
+[[package]]
+name = "debug-helper"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8a5bb894f24f42c247f19b25928a88e31867c0f84552c05df41a9dd527435e"
+
[[package]]
name = "dirs"
version = "3.0.1"
@@ -521,6 +540,36 @@ dependencies = [
"fastrand",
]
+[[package]]
+name = "num-bigint"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
+dependencies = [
+ "autocfg",
+]
+
[[package]]
name = "num_cpus"
version = "1.13.0"
@@ -763,6 +812,7 @@ version = "1.8.0"
dependencies = [
"ansi_term 0.12.1",
"async-std",
+ "cidr-utils",
"colored",
"colorful",
"dirs",
diff --git a/Cargo.toml b/Cargo.toml
index a4ee885..783b498 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,6 +33,7 @@ ansi_term = "0.12.1"
toml = "0.5.6"
serde = "1.0.115"
serde_derive = "1.0.115"
+cidr-utils = "0.5.0"
[package.metadata.deb]
depends = "$auto, nmap"
diff --git a/README.md b/README.md
index 5474abd..79dbdb3 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
-
+
@@ -21,10 +21,10 @@
-| 🐋 Docker (Recommended)
| 👩💻 Kali / Debian
| 🏗️ Arch
| 🔧 Cargo (Universal)
|
-| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
-| 
| 
| 
| 
|
-| `docker pull rustscan/rustscan:alpine` [Usage](https://github.com/RustScan/RustScan#docker-whale) | [Read the install guide](https://github.com/brandonskerritt/RustScan/blob/master/README.md#%EF%B8%8F-debian--kali) | `yay -S rustscan` | `cargo install rustscan` |
+|
🐋 Docker (Recommended)
| 👩💻 Kali / Debian
| 🏗️ Arch
| 🔧 Cargo (Universal)
|
+| ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
+| 
| 
| 
| 
|
+| `docker pull rustscan/rustscan:alpine` [Usage](https://github.com/RustScan/RustScan#docker-whale) | [Read the install guide](https://github.com/Rustscan/RustScan/blob/master/README.md#%EF%B8%8F-debian--kali) | `yay -S rustscan` | `cargo install rustscan` |
@@ -111,7 +111,7 @@ Note: sometimes Rust doesn't add Cargo to the path. Please see [this issue](http
Download the .deb file from the releases page:
-[https://github.com/brandonskerritt/RustScan/releases](https://github.com/brandonskerritt/RustScan/releases)
+[https://github.com/RustScan/RustScan/releases](https://github.com/RustScan/RustScan/releases)
Run the command `dpkg -i` on the file.
@@ -229,14 +229,15 @@ server may not be able to handle this many socket connections at once. - Discord
https://github.com/RustScan/RustScan
USAGE:
- rustscan [FLAGS] [OPTIONS] [ips-or-hosts]... [-- ...]
+ rustscan [FLAGS] [OPTIONS] [addresses]... [-- ...]
FLAGS:
- --accessible Accessible mode. Turns off features which negatively affect screen readers
- -h, --help Prints help information
- -i, --ignore-config Whether to ignore the configuration file or not
- -q, --quiet Quiet mode. Only output the ports. No Nmap. Useful for grep or outputting to a file
- -V, --version Prints version information
+ --accessible Accessible mode. Turns off features which negatively affect screen readers
+ -h, --help Prints help information
+ -n, --no-config Whether to ignore the configuration file or not
+ --no-nmap Turns off Nmap
+ -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.
@@ -251,11 +252,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 CIDRs, IPs, 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)'\"")
```
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.
@@ -269,7 +270,7 @@ Your operating system may not support this, but it is worth it to play around an
This binary accepts a configuration file that is read from the home directory of the user. It follows the TOML format
and accepts the following fields:
-- `ips_or_hosts`
+- `addresses`
- `ports`
- `range`
- `scan_order`
@@ -283,7 +284,7 @@ and accepts the following fields:
### Format example
```toml
-ips_or_hosts = ["127.0.0.1", "192.168.0.1", "www.google.com"]
+addresses = ["127.0.0.1", "192.168.0.0/30", "www.google.com"]
command = ["-A"]
ports = [80, 443, 8080]
range = { start = 1, end = 10 }
@@ -364,7 +365,7 @@ Windows Subsystem for Linux does not support ulimit (see issue #39).
The best way is to use it on a host computer, in Docker, or in a VM that isn't WSL.
**Automatic Ulimit updating**
-We are currently working on automatic Ulimit updating. If it is too high, it will lower itself. If it is too low, it will suggest a higher Ulimit. Watch [this issue](https://github.com/brandonskerritt/RustScan/issues/25) for more.
+We are currently working on automatic Ulimit updating. If it is too high, it will lower itself. If it is too low, it will suggest a higher Ulimit. Watch [this issue](https://github.com/RustScan/RustScan/issues/25) for more.
## 🔌 Nmap Custom Flags
@@ -432,7 +433,9 @@ Please read the [contributing.md file](contributing.md)
## Contributors ✨
+
[](#contributors-)
+
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -469,6 +472,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
diff --git a/src/input.rs b/src/input.rs
index 0bab9b0..267cee6 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -54,9 +54,9 @@ fn parse_range(input: &str) -> Result {
/// - Discord https://discord.gg/GFrQsGy
/// - GitHub https://github.com/RustScan/RustScan
pub struct Opts {
- /// A list of comma separated IP addresses or hosts to be scanned.
+ /// A list of comma separated CIDRs, IPs, or hosts to be scanned.
#[structopt(use_delimiter = true)]
- pub ips_or_hosts: Vec,
+ pub addresses: Vec,
/// A list of comma separed ports to be scanned. Example: 80,443,8080.
#[structopt(short, long, use_delimiter = true)]
@@ -146,15 +146,7 @@ impl Opts {
}
}
- merge_required!(
- ips_or_hosts,
- quiet,
- accessible,
- batch_size,
- timeout,
- scan_order,
- command
- );
+ merge_required!(addresses, quiet, accessible, batch_size, timeout, scan_order, command);
}
fn merge_optional(&mut self, config: &Config) {
@@ -177,7 +169,7 @@ impl Opts {
/// generate the final Opts struct.
#[derive(Debug, Deserialize)]
pub struct Config {
- ips_or_hosts: Option>,
+ addresses: Option>,
ports: Option>,
range: Option,
quiet: Option,
@@ -196,7 +188,7 @@ impl Config {
///
/// # Format
///
- /// ips_or_hosts = ["127.0.0.1", "127.0.0.1"]
+ /// addresses = ["127.0.0.1", "127.0.0.1"]
/// ports = [80, 443, 8080]
/// quiet = true
/// scan_order: "Serial"
@@ -254,7 +246,7 @@ mod tests {
#[test]
fn opts_no_merge_when_config_is_ignored() {
let mut opts = Opts {
- ips_or_hosts: vec![],
+ addresses: vec![],
ports: None,
range: None,
quiet: false,
@@ -269,7 +261,7 @@ mod tests {
};
let config = Config {
- ips_or_hosts: Some(vec!["127.0.0.1".to_owned()]),
+ addresses: Some(vec!["127.0.0.1".to_owned()]),
ports: None,
range: None,
quiet: Some(true),
@@ -284,7 +276,7 @@ mod tests {
opts.merge(&config);
- assert_eq!(opts.ips_or_hosts, vec![] as Vec);
+ assert_eq!(opts.addresses, vec![] as Vec);
assert_eq!(opts.quiet, false);
assert_eq!(opts.accessible, false);
assert_eq!(opts.timeout, 0);
@@ -295,7 +287,7 @@ mod tests {
#[test]
fn opts_merge_required_arguments() {
let mut opts = Opts {
- ips_or_hosts: vec![],
+ addresses: vec![],
ports: None,
range: None,
quiet: false,
@@ -310,7 +302,7 @@ mod tests {
};
let config = Config {
- ips_or_hosts: Some(vec!["127.0.0.1".to_owned()]),
+ addresses: Some(vec!["127.0.0.1".to_owned()]),
ports: None,
no_nmap: Some(false),
range: None,
@@ -325,7 +317,7 @@ mod tests {
opts.merge_required(&config);
- assert_eq!(opts.ips_or_hosts, config.ips_or_hosts.unwrap());
+ assert_eq!(opts.addresses, config.addresses.unwrap());
assert_eq!(opts.quiet, config.quiet.unwrap());
assert_eq!(opts.timeout, config.timeout.unwrap());
assert_eq!(opts.command, config.command.unwrap());
@@ -336,7 +328,7 @@ mod tests {
#[test]
fn opts_merge_optional_arguments() {
let mut opts = Opts {
- ips_or_hosts: vec![],
+ addresses: vec![],
ports: None,
range: None,
quiet: false,
@@ -351,7 +343,7 @@ mod tests {
};
let config = Config {
- ips_or_hosts: None,
+ addresses: None,
ports: Some(vec![80, 403]),
range: Some(PortRange {
start: 1,
diff --git a/src/main.rs b/src/main.rs
index f11642b..6fcd46b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,16 +11,15 @@ use scanner::Scanner;
mod port_strategy;
use port_strategy::PortStrategy;
+use cidr_utils::cidr::IpCidr;
use colorful::Color;
use colorful::Colorful;
use futures::executor::block_on;
use rlimit::Resource;
use rlimit::{getrlimit, setrlimit};
-
use std::collections::HashMap;
use std::net::ToSocketAddrs;
use std::process::Command;
-use std::str::FromStr;
use std::{net::IpAddr, time::Duration};
extern crate colorful;
@@ -51,7 +50,7 @@ fn main() {
print_opening();
}
- let ips: Vec = parse_ips(&opts);
+ let ips: Vec = parse_addresses(&opts);
if ips.is_empty() {
warning!("No IPs could be resolved, aborting scan.", false);
@@ -183,12 +182,12 @@ fn build_nmap_arguments<'a>(
arguments
}
-fn parse_ips(opts: &Opts) -> Vec {
+fn parse_addresses(opts: &Opts) -> Vec {
let mut ips: Vec = Vec::new();
- for ip_or_host in &opts.ips_or_hosts {
- match IpAddr::from_str(ip_or_host) {
- Ok(ip) => ips.push(ip),
+ for ip_or_host in &opts.addresses {
+ match IpCidr::from_str(ip_or_host) {
+ Ok(cidr) => cidr.iter().for_each(|ip| ips.push(ip)),
_ => match format!("{}:{}", &ip_or_host, 80).to_socket_addrs() {
Ok(mut iter) => ips.push(iter.nth(0).unwrap().ip()),
_ => {
@@ -262,12 +261,15 @@ fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u16 {
#[cfg(test)]
mod tests {
- use crate::{adjust_ulimit_size, infer_batch_size, parse_ips, print_opening, Opts, ScanOrder};
+ use crate::{
+ adjust_ulimit_size, infer_batch_size, parse_addresses, print_opening, Opts, ScanOrder,
+ };
+ use std::net::Ipv4Addr;
#[test]
fn batch_size_lowered() {
let opts = Opts {
- ips_or_hosts: vec!["127.0.0.1".to_owned()],
+ addresses: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
@@ -288,7 +290,7 @@ mod tests {
#[test]
fn batch_size_lowered_average_size() {
let opts = Opts {
- ips_or_hosts: vec!["127.0.0.1".to_owned()],
+ addresses: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
@@ -310,7 +312,7 @@ mod tests {
// because ulimit and batch size are same size, batch size is lowered
// to ULIMIT - 100
let opts = Opts {
- ips_or_hosts: vec!["127.0.0.1".to_owned()],
+ addresses: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
@@ -331,7 +333,7 @@ mod tests {
fn batch_size_adjusted_2000() {
// ulimit == batch_size
let opts = Opts {
- ips_or_hosts: vec!["127.0.0.1".to_owned()],
+ addresses: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
@@ -357,7 +359,7 @@ mod tests {
#[test]
fn test_high_ulimit_no_quiet_mode() {
let opts = Opts {
- ips_or_hosts: vec!["127.0.0.1".to_owned()],
+ addresses: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: false,
@@ -377,9 +379,9 @@ mod tests {
}
#[test]
- fn parse_correct_ips_or_hosts() {
+ fn parse_correct_addresses() {
let opts = Opts {
- ips_or_hosts: vec!["127.0.0.1".to_owned(), "google.com".to_owned()],
+ addresses: vec!["127.0.0.1".to_owned(), "192.168.0.0/30".to_owned()],
ports: None,
range: None,
quiet: true,
@@ -392,15 +394,24 @@ mod tests {
no_config: false,
no_nmap: false,
};
- let ips = parse_ips(&opts);
+ let ips = parse_addresses(&opts);
- assert_eq!(2, ips.len());
+ assert_eq!(
+ ips,
+ [
+ Ipv4Addr::new(127, 0, 0, 1),
+ Ipv4Addr::new(192, 168, 0, 0),
+ Ipv4Addr::new(192, 168, 0, 1),
+ Ipv4Addr::new(192, 168, 0, 2),
+ Ipv4Addr::new(192, 168, 0, 3)
+ ]
+ );
}
#[test]
- fn parse_correct_and_incorrect_ips_or_hosts() {
+ fn parse_correct_host_addresses() {
let opts = Opts {
- ips_or_hosts: vec!["127.0.0.1".to_owned(), "im_wrong".to_owned()],
+ addresses: vec!["google.com".to_owned()],
ports: None,
range: None,
quiet: true,
@@ -413,15 +424,15 @@ mod tests {
no_config: false,
no_nmap: false,
};
- let ips = parse_ips(&opts);
+ let ips = parse_addresses(&opts);
- assert_eq!(1, ips.len());
+ assert_eq!(ips.len(), 1);
}
#[test]
- fn parse_incorrect_ips_or_hosts() {
+ fn parse_correct_and_incorrect_addresses() {
let opts = Opts {
- ips_or_hosts: vec!["im_wrong".to_owned(), "300.10.1.1".to_owned()],
+ addresses: vec!["127.0.0.1".to_owned(), "im_wrong".to_owned()],
ports: None,
range: None,
quiet: true,
@@ -434,8 +445,29 @@ mod tests {
no_config: false,
no_nmap: false,
};
- let ips = parse_ips(&opts);
+ let ips = parse_addresses(&opts);
- assert_eq!(0, ips.len());
+ assert_eq!(ips, [Ipv4Addr::new(127, 0, 0, 1),]);
+ }
+
+ #[test]
+ fn parse_incorrect_addresses() {
+ let opts = Opts {
+ addresses: vec!["im_wrong".to_owned(), "300.10.1.1".to_owned()],
+ ports: None,
+ range: None,
+ quiet: true,
+ batch_size: 10,
+ timeout: 1_000,
+ ulimit: Some(2_000),
+ command: Vec::new(),
+ accessible: false,
+ scan_order: ScanOrder::Serial,
+ no_config: false,
+ no_nmap: false,
+ };
+ let ips = parse_addresses(&opts);
+
+ assert_eq!(ips.is_empty(), true);
}
}