Compare commits

..
Author SHA1 Message Date
Brandon 5551e64166 updated AUR package in readme 2020-08-20 00:40:41 +01:00
Brandon e0aa1423ad removed -A from nmap 2020-08-20 00:32:37 +01:00
Brandon d0d8380296 Merge pull request #158 from RustScan/ba-add-port-and-range-options
Add --port and --range options
2020-08-19 16:26:39 +01:00
Brandon d66ad34f8c Merge branch 'master' into ba-add-port-and-range-options 2020-08-19 16:02:49 +01:00
Brandon 2670ec43df Merge pull request #156 from spenserblack/exclude-files
Exclude files
2020-08-19 00:05:59 +01:00
Bernardo Chaves 90d0b03ba7 Add --port and --range options
These options are mutually exclusive, this means that when a user
selects manual ports we will ignore ranges and vice-versa.

Manually specifying ports won't allow scan randomization for now.
2020-08-17 20:43:44 -04:00
Spenser Black 57eb3627b3 Use absolute image URLs instead of relative 2020-08-17 10:03:04 -04:00
Spenser Black 7e675b7557 Reduce crate size 2020-08-17 09:30:07 -04:00
Bernardo Araujo fdeaa05f23 Merge pull request #152 from RustScan/ba-add-host-resolution
Add host resolution
2020-08-16 18:35:40 -04:00
5 changed files with 156 additions and 32 deletions

No files matched your search

+5
View File
@@ -10,6 +10,11 @@ license = "MIT"
keywords = ["port", "scanning", "nmap"]
categories = ["command-line-utilities"]
readme="README.md"
exclude = [
".github/*",
"pictures/*",
"rustscan-debbuilder/*",
]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+15 -13
View File
@@ -5,13 +5,13 @@
<a href="https://github.com/RustScan/RustScan#-usage">Usage Guide</a>
⬅️
<br>
<img src="pictures/rustscan.png">
<img src="https://github.com/RustScan/RustScan/blob/master/pictures/rustscan.png?raw=true">
</p>
<p align="center">
<u><b> Turns a 17 minutes Nmap scan into 19 seconds. </b></u><br> Find all open ports <b>fast</b> with RustScan, automatically pipe them into Nmap.
</p>
<p align="center">
<img alt="AUR version" src="https://img.shields.io/aur/version/rustscan-bin">
<img alt="AUR version" src="https://img.shields.io/aur/version/rustscan">
<img src="https://img.shields.io/badge/Built%20with-Rust-Purple">
<img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/w/brandonskerritt/rustscan">
<img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/rustscan/rustscan/total?label=GitHub%20Downloads">
@@ -23,7 +23,7 @@
| <p align="center"><a href="https://hub.docker.com/r/cmnatic/rustscan">🐋 Docker (Recommended) </a></p> | <p align="center"><a href="https://github.com/RustScan/RustScan/releases">👩‍💻 Kali / Debian </p> | <p align="center"><a href="https://aur.archlinux.org/packages/rustscan/">🏗️ Arch </a></p> | <p align="center"><a href="https://crates.io/crates/rustscan">🔧 Cargo (Universal) </a></p> |
| ---- | ---- | ---- | --- |
| <p align="center"><img src="pictures/docker.png" /></p> | <p align="center"><img src="pictures/kali.png" /></p> | <p align="center"><img src="pictures/arch.png" /></p> | <p align="center"><img src="pictures/rust.png" /></p>
| <p align="center"><img src="https://github.com/RustScan/RustScan/blob/master/pictures/docker.png?raw=true" /></p> | <p align="center"><img src="https://github.com/RustScan/RustScan/blob/master/pictures/kali.png?raw=true" /></p> | <p align="center"><img src="https://github.com/RustScan/RustScan/blob/master/pictures/arch.png?raw=true" /></p> | <p align="center"><img src="https://github.com/RustScan/RustScan/blob/master/pictures/rust.png?raw=true" /></p>
| `docker pull rustscan/rustscan:alpine` <p>[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`
<hr>
@@ -42,8 +42,8 @@
</tr>
<tr>
<th>Gif</th>
<td><img src="pictures/with_rustscan.gif" alt="The guy she tells you not to worry about"></td>
<td><img src="pictures/without_rustscan.gif" alt="You"></td>
<td><img src="https://github.com/RustScan/RustScan/blob/master/pictures/with_rustscan.gif?raw=true" alt="The guy she tells you not to worry about"></td>
<td><img src="https://github.com/RustScan/RustScan/blob/master/pictures/without_rustscan.gif?raw=true" alt="You"></td>
</tr>
<tr>
<th>Time</th>
@@ -79,7 +79,7 @@ RustScans **only** job is to reduce the friction between finding open ports and
# 🔭 Why RustScan?
Why spend time running fast scans and manually copying the ports, or waiting for a 20 minute scan to finish when you can just do all 65k ports in less than a minute?
![gif](pictures/8seconds.gif)
![gif](https://github.com/RustScan/RustScan/blob/master/pictures/8seconds.gif?raw=true)
**RustScan running in 8 seconds and finding all open ports out of 65k.**
@@ -213,13 +213,12 @@ 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] <ips>... [-- <command>...]
rustscan [FLAGS] [OPTIONS] <ips-or-hosts>... [-- <command>...]
FLAGS:
-a, --accessible
@@ -231,6 +230,9 @@ OPTIONS:
-b, --batch-size <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 <ports>... A list of comma separed ports to be scanned. Example: 80,443,8080. These ports will
be scanned sequentially
-r, --range <range> A range of ports with format start-end. Example: 1-1000
--scan-order <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]
@@ -238,11 +240,11 @@ OPTIONS:
-u, --ulimit <ulimit> Automatically ups the ULIMIT with the value you provided
ARGS:
<ips>... A list of comma separated IP addresses to be scanned
<command>... 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)'\"")
<ips-or-hosts>... A list of comma separated IP addresses or hosts to be scanned
<command>... 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.
+64 -3
View File
@@ -40,6 +40,35 @@ arg_enum! {
}
}
#[derive(Debug)]
pub struct PortRange {
start: u16,
end: u16,
}
fn parse_range(input: &str) -> Result<PortRange, String> {
let range = input
.split("-")
.map(|x| x.parse::<u16>())
.collect::<Result<Vec<u16>, std::num::ParseIntError>>();
if range.is_err() {
return Err(String::from(
"the range format must be 'start-end'. Example: 1-1000.",
));
}
match range.unwrap().as_slice() {
[start, end] => Ok(PortRange {
start: *start,
end: *end,
}),
_ => Err(String::from(
"the range format must be 'start-end'. Example: 1-1000.",
)),
}
}
#[derive(StructOpt, Debug)]
#[structopt(name = "rustscan", setting = structopt::clap::AppSettings::TrailingVarArg)]
/// Fast Port Scanner built in Rust.
@@ -52,6 +81,15 @@ struct Opts {
#[structopt(use_delimiter = true, required = true)]
ips_or_hosts: Vec<String>,
/// A list of comma separed ports to be scanned. Example: 80,443,8080.
/// These ports will be scanned sequentially.
#[structopt(short, long, use_delimiter = true)]
ports: Option<Vec<u16>>,
/// A range of ports with format start-end. Example: 1-1000.
#[structopt(short, long, conflicts_with = "ports", parse(try_from_str = parse_range))]
range: Option<PortRange>,
///Quiet mode. Only output the ports. No Nmap. Useful for grep or outputting to a file.
#[structopt(short, long)]
quiet: bool,
@@ -97,7 +135,15 @@ fn main() {
env_logger::init();
info!("Starting up");
let opts = Opts::from_args();
let mut opts = Opts::from_args();
if opts.ports.is_none() && opts.range.is_none() {
opts.range = Some(PortRange {
start: LOWEST_PORT_NUMBER,
end: TOP_PORT_NUMBER,
});
}
info!("Mains() `opts` arguments are {:?}", opts);
if !opts.quiet && !opts.accessible {
@@ -119,7 +165,7 @@ fn main() {
batch_size,
Duration::from_millis(opts.timeout.into()),
opts.quiet,
PortStrategy::pick(LOWEST_PORT_NUMBER, TOP_PORT_NUMBER, opts.scan_order),
PortStrategy::pick(opts.range, opts.ports, opts.scan_order),
);
let scan_result = block_on(scanner.run());
@@ -223,7 +269,6 @@ fn build_nmap_arguments<'a>(
is_ipv6: bool,
) -> Vec<&'a str> {
let mut arguments: Vec<&str> = user_args.iter().map(AsRef::as_ref).collect();
arguments.push("-A");
arguments.push("-vvv");
if is_ipv6 {
@@ -322,6 +367,8 @@ mod tests {
fn batch_size_lowered() {
let opts = Opts {
ips_or_hosts: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
batch_size: 50_000,
timeout: 1_000,
@@ -339,6 +386,8 @@ mod tests {
fn batch_size_lowered_average_size() {
let opts = Opts {
ips_or_hosts: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
batch_size: 50_000,
timeout: 1_000,
@@ -357,6 +406,8 @@ mod tests {
// to ULIMIT - 100
let opts = Opts {
ips_or_hosts: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
batch_size: 50_000,
timeout: 1_000,
@@ -374,6 +425,8 @@ mod tests {
// ulimit == batch_size
let opts = Opts {
ips_or_hosts: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: true,
batch_size: 50_000,
timeout: 1_000,
@@ -396,6 +449,8 @@ mod tests {
fn test_high_ulimit_no_quiet_mode() {
let opts = Opts {
ips_or_hosts: vec!["127.0.0.1".to_owned()],
ports: None,
range: None,
quiet: false,
batch_size: 10,
timeout: 1_000,
@@ -414,6 +469,8 @@ mod tests {
fn parse_correct_ips_or_hosts() {
let opts = Opts {
ips_or_hosts: vec!["127.0.0.1".to_owned(), "google.com".to_owned()],
ports: None,
range: None,
quiet: true,
batch_size: 10,
timeout: 1_000,
@@ -431,6 +488,8 @@ mod tests {
fn parse_correct_and_incorrect_ips_or_hosts() {
let opts = Opts {
ips_or_hosts: vec!["127.0.0.1".to_owned(), "im_wrong".to_owned()],
ports: None,
range: None,
quiet: true,
batch_size: 10,
timeout: 1_000,
@@ -448,6 +507,8 @@ mod tests {
fn parse_incorrect_ips_or_hosts() {
let opts = Opts {
ips_or_hosts: vec!["im_wrong".to_owned(), "300.10.1.1".to_owned()],
ports: None,
range: None,
quiet: true,
batch_size: 10,
timeout: 1_000,
+46 -10
View File
@@ -1,5 +1,5 @@
mod range_iterator;
use super::ScanOrder;
use super::{PortRange, ScanOrder};
use range_iterator::RangeIterator;
/// Represents options of port scanning.
@@ -7,20 +7,40 @@ use range_iterator::RangeIterator;
/// Right now all these options involve ranges, but in the future
/// it will also contain custom lists of ports.
pub enum PortStrategy {
Manual(Vec<u16>),
Serial(SerialRange),
Random(RandomRange),
}
impl PortStrategy {
pub fn pick(start: u16, end: u16, scan_type: ScanOrder) -> Self {
match scan_type {
ScanOrder::Serial => PortStrategy::Serial(SerialRange { start, end }),
ScanOrder::Random => PortStrategy::Random(RandomRange { start, end }),
pub fn pick(range: Option<PortRange>, ports: Option<Vec<u16>>, order: ScanOrder) -> Self {
match order {
ScanOrder::Serial => match ports.is_none() {
true => {
let range = range.as_ref().unwrap();
PortStrategy::Serial(SerialRange {
start: range.start,
end: range.end,
})
}
false => PortStrategy::Manual(ports.unwrap()),
},
ScanOrder::Random => match ports.is_none() {
true => {
let range = range.as_ref().unwrap();
PortStrategy::Random(RandomRange {
start: range.start,
end: range.end,
})
}
false => PortStrategy::Manual(ports.unwrap()),
},
}
}
pub fn order(&self) -> Vec<u16> {
match self {
PortStrategy::Manual(ports) => ports.to_vec(),
PortStrategy::Serial(range) => range.generate(),
PortStrategy::Random(range) => range.generate(),
}
@@ -71,18 +91,20 @@ impl RangeOrder for RandomRange {
#[cfg(test)]
mod tests {
use super::PortStrategy;
use crate::ScanOrder;
use crate::{PortRange, ScanOrder};
#[test]
fn serial_strategy() {
let strategy = PortStrategy::pick(1, 100, ScanOrder::Serial);
fn serial_strategy_with_range() {
let range = PortRange { start: 1, end: 100 };
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Serial);
let result = strategy.order();
let expected_range = (1..100).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
}
#[test]
fn random_strategy() {
let strategy = PortStrategy::pick(1, 100, ScanOrder::Random);
fn random_strategy_with_range() {
let range = PortRange { start: 1, end: 100 };
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let mut result = strategy.order();
let expected_range = (1..100).into_iter().collect::<Vec<u16>>();
assert_ne!(expected_range, result);
@@ -90,4 +112,18 @@ mod tests {
result.sort();
assert_eq!(expected_range, result);
}
#[test]
fn serial_strategy_with_ports() {
let strategy = PortStrategy::pick(None, Some(vec![80, 443]), ScanOrder::Serial);
let result = strategy.order();
assert_eq!(vec![80, 443], result);
}
#[test]
fn random_strategy_with_ports_does_not_randomize_ports() {
let strategy = PortStrategy::pick(None, Some(vec![80, 443]), ScanOrder::Random);
let result = strategy.order();
assert_eq!(vec![80, 443], result);
}
}
+26 -6
View File
@@ -139,7 +139,7 @@ impl Scanner {
#[cfg(test)]
mod tests {
use super::*;
use crate::ScanOrder;
use crate::{PortRange, ScanOrder};
use async_std::task::block_on;
use std::{net::IpAddr, time::Duration};
@@ -147,7 +147,11 @@ mod tests {
fn scanner_runs() {
// Makes sure the program still runs and doesn't panic
let addrs = vec!["127.0.0.1".parse::<IpAddr>().unwrap()];
let strategy = PortStrategy::pick(1, 1_000, ScanOrder::Random);
let range = PortRange {
start: 1,
end: 1_000,
};
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
@@ -157,7 +161,11 @@ mod tests {
fn ipv6_scanner_runs() {
// Makes sure the program still runs and doesn't panic
let addrs = vec!["::1".parse::<IpAddr>().unwrap()];
let strategy = PortStrategy::pick(1, 1_000, ScanOrder::Random);
let range = PortRange {
start: 1,
end: 1_000,
};
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
@@ -166,7 +174,11 @@ mod tests {
#[test]
fn quad_zero_scanner_runs() {
let addrs = vec!["0.0.0.0".parse::<IpAddr>().unwrap()];
let strategy = PortStrategy::pick(1, 1_000, ScanOrder::Random);
let range = PortRange {
start: 1,
end: 1_000,
};
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
block_on(scanner.run());
assert_eq!(1, 1);
@@ -174,7 +186,11 @@ mod tests {
#[test]
fn google_dns_runs() {
let addrs = vec!["8.8.8.8".parse::<IpAddr>().unwrap()];
let strategy = PortStrategy::pick(400, 445, ScanOrder::Random);
let range = PortRange {
start: 400,
end: 445,
};
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
block_on(scanner.run());
assert_eq!(1, 1);
@@ -185,7 +201,11 @@ mod tests {
let addrs = vec!["8.8.8.8".parse::<IpAddr>().unwrap()];
// mac should have this automatically scaled down
let strategy = PortStrategy::pick(400, 600, ScanOrder::Random);
let range = PortRange {
start: 400,
end: 600,
};
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
block_on(scanner.run());
assert_eq!(1, 1);