Compare commits

..
42 Commits
Author SHA1 Message Date
Brandon b52a990ad0 Merge pull request #95 from RustScan/bee-scheduled-markdown-action
Scheduled markdown action 404 links
2020-08-01 22:47:37 +01:00
Brandon c8404781dc Merge branch 'master' into bee-scheduled-markdown-action 2020-08-01 22:45:29 +01:00
Brandon 6ab43bf213 Merge pull request #96 from bernardoamc/ba-reduce-unsig-int
Refactor ulimit and batch_size logic consider the OS architecture
2020-08-01 21:15:39 +01:00
Brandon da3629cc7b Merge branch 'master' into bee-scheduled-markdown-action 2020-08-01 21:08:11 +01:00
Bernardo de Araujo af344becbc Refactor ulimit and batch_size logic consider the OS architecture
RustScan should be able to run on systems with either 32 or 64 bits. In
order to achieve that we should rely on the `rlimit` library to get the
proper unsigned int type from the system.
2020-08-01 15:45:31 -04:00
Brandon 85b7f9fe7a Merge pull request #94 from RustScan/bee-readme-community-additions
Updated readme
2020-08-01 19:34:00 +01:00
Brandon 9d1d064e71 fixed typo 2020-08-01 19:30:33 +01:00
Brandon 343563818f checking to see if CI works 2020-08-01 17:40:59 +01:00
Brandon bc77814d59 checking to see if CI works 2020-08-01 17:37:49 +01:00
Brandon 42b72ea114 added daily 404 link checking 2020-08-01 17:31:46 +01:00
Brandon d73c66482e Updated readme 2020-08-01 17:07:50 +01:00
Brandon 82e3128641 Update README.md 2020-08-01 13:21:53 +01:00
Brandon 679d1a787d Merge pull request #92 from RustScan/dependabot/cargo/colored-2.0.0
Bump colored from 1.9.3 to 2.0.0
2020-08-01 11:42:04 +01:00
dependabot-preview[bot] 813b6753c8 Bump colored from 1.9.3 to 2.0.0
Bumps [colored](https://github.com/mackwic/colored) from 1.9.3 to 2.0.0.
- [Release notes](https://github.com/mackwic/colored/releases)
- [Changelog](https://github.com/mackwic/colored/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mackwic/colored/compare/v1.9.3...v2.0.0)

Signed-off-by: dependabot-preview[bot] <[email protected]>
2020-08-01 10:35:53 +00:00
Brandon 51df49836b Merge pull request #91 from bernardoamc/ba-refactor-ip-parsing
Fail early when the specified IP format is not valid
2020-08-01 11:18:53 +01:00
Bernardo de Araujo 2df98016c9 Fail early when the specified IP format is not valid
We can let structopt parse the supplied IP for us and fail early when
that IP address is invalid. We can also let IpAddr let us know when an
IP is an ipv4 or ipv6 without relying on the user to supply this
information to us.
2020-08-01 00:15:19 -04:00
Brandon deb8bb3216 rust fmt 2020-07-31 16:23:28 +01:00
Brandon 6ce8fe1afd trying to fix docs.rs 2020-07-31 14:23:38 +01:00
Brandon 8aa9a44949 updating lock file 2020-07-31 13:34:33 +01:00
Brandon 416602dd02 added ipv6 to readme 2020-07-31 13:34:04 +01:00
Brandon a2e7125e03 updated cargo.toml 2020-07-31 13:33:24 +01:00
Brandon 10acad243c Merge pull request #87 from RustScan/ipv6-support
Ipv6 support
2020-07-31 13:02:56 +01:00
Brandon 5d69339cc7 cargo fmt 2020-07-31 11:33:08 +01:00
Brandon d8fd12694c fixed tests 2020-07-31 11:32:02 +01:00
Brandon 7d4084d06c added ipv6 support to nmap command 2020-07-31 11:21:58 +01:00
Brandon 365be75689 Merge branch 'ipv6-support' of github.com:brandonskerritt/RustScan into ipv6-support 2020-07-31 02:11:28 +01:00
Brandon 5ea316c5db ipv6 is now implemented. Just need to do a final cleanup 2020-07-31 02:11:09 +01:00
Brandon b363529045 ipv6 is now implemented. Just need to do a final cleanup 2020-07-31 01:30:35 +01:00
Brandon ed378f7fc8 Either this doesnt work or my internet is broken 2020-07-31 01:17:38 +01:00
Brandon aa3c591016 added logging module 2020-07-30 23:44:48 +01:00
Brandon ef893fdcb8 Update README.md 2020-07-30 12:49:22 +01:00
Brandon b78a8ad0af edited contributing.md 2020-07-30 12:39:54 +01:00
Brandon 7ad7e34abc Updated comments -> issues bot 2020-07-30 12:24:36 +01:00
Brandon e41393b4ad Update Dockerfile 2020-07-30 11:22:45 +01:00
Brandon 6d72037974 Code finally compiles 2020-07-30 02:17:17 +01:00
Brandon 66486b2467 scanner.rs now works 2020-07-30 01:46:38 +01:00
Brandon 4b085d97f2 added ipv6 testing 2020-07-29 18:11:57 +01:00
Brandon 3951c25dff end of dya 2020-07-29 01:50:36 +01:00
Brandon 071c437206 sending to smackhack 2020-07-29 00:45:47 +01:00
Brandon 7d351f2025 socketaddr is now ipv4 and ipv6 2020-07-28 23:12:08 +01:00
Brandon 8ce14c5690 Added arguments in structopts for ipv6 2020-07-28 02:23:07 +01:00
Brandon 6cf71a1529 switching branches real quick 2020-07-28 01:07:57 +01:00
10 changed files with 395 additions and 146 deletions

No files matched your search

+1 -1
View File
@@ -1,2 +1,2 @@
todo:
keyword: "TODO"
keyword: "// TODO"
+8 -1
View File
@@ -45,4 +45,11 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
args: --all -- --check
links:
name: markdown-link-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: gaurav-nelson/github-action-markdown-link-check@v1
@@ -0,0 +1,18 @@
name: Check Markdown links
on:
push:
branches:
- master
schedule:
# Run everyday at 9:00 AM (See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07)
- cron: "0 9 * * *"
jobs:
markdown-link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: gaurav-nelson/github-action-markdown-link-check@v1
with:
use-quiet-mode: 'yes'
Generated
+87 -3
View File
@@ -1,5 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
@@ -133,9 +142,9 @@ dependencies = [
[[package]]
name = "colored"
version = "1.9.3"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
@@ -162,6 +171,19 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "event-listener"
version = "2.2.1"
@@ -302,6 +324,15 @@ dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "js-sys"
version = "0.3.42"
@@ -448,6 +479,12 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.7"
@@ -463,6 +500,24 @@ version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
[[package]]
name = "rlimit"
version = "0.3.0"
@@ -475,11 +530,13 @@ dependencies = [
[[package]]
name = "rustscan"
version = "1.3.0"
version = "1.4.1"
dependencies = [
"async-std",
"colored",
"env_logger",
"futures",
"log",
"rlimit",
"shell-words",
"structopt",
@@ -588,6 +645,15 @@ dependencies = [
"syn",
]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@@ -597,6 +663,15 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
@@ -734,6 +809,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
+4 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "rustscan"
version = "1.3.0"
version = "1.4.1"
authors = ["Bee <[email protected]>"]
edition = "2018"
description = "Faster Nmap Scanning with Rust"
@@ -14,12 +14,14 @@ readme="README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
colored = "1.9.3"
colored = "2.0.0"
structopt = "0.3.15"
async-std = "1.6.2"
futures = "0.3"
rlimit = "0.3.0"
shell-words = "1.0.0"
log = "0.4.0"
env_logger = "0.7.1"
[package.metadata.deb]
depends = "$auto, nmap"
+49 -19
View File
@@ -1,6 +1,6 @@
<p align="center">
➡️
<a href="https://discord.gg/r38pna">Discord</a> |
<a href="https://discord.gg/GFrQsGy">Discord</a> |
<a href="https://github.com/RustScan/RustScan#-full-installation-guide">Installation Guide</a> |
<a href="https://github.com/RustScan/RustScan#-usage">Usage Guide</a>
⬅️
@@ -17,7 +17,7 @@
<img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/rustscan/rustscan/total?label=GitHub%20Downloads">
<img alt="Crates.io" src="https://img.shields.io/crates/d/rustscan?label=Cargo%20Downloads">
<img alt="Discord" src="https://img.shields.io/discord/736614461313515576">
<img alt="Actions" src="https://github.com/RustScan/RustScan/workflows/Continuous%20integration/badge.svg">
<img alt="Actions" src="https://github.com/RustScan/RustScan/workflows/Continuous%20integration/badge.svg?branch=master">
</p>
<hr>
@@ -62,6 +62,7 @@ RustScans **only** job is to reduce the friction between finding open ports and
* Saves you time by automatically piping it into Nmap. No more manual copying and pasting!
* Does one thing and does it well. **Only** purpose is to improve Nmap, not replace it!
* Let's you choose what Nmap commands to run, or uses the default.
* IPv6 Support
# 🔭 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?
@@ -78,21 +79,18 @@ Why spend time running fast scans and manually copying the ports, or waiting for
| Actually useful | ❌ | ✅ | ❌ |
| Realises it's not useful, and pipes the only useful data into the only useful port scanner | ✅ | ❌ | ❌ |
## ‼️ Important Links
## 🙋 FAQ
> I think this would be a great port scanner on its own without Nmap!
| Installation Guide | Documentation | Discord |
| ------------------ | ------------- | ------- |
| 📖 [Installation Guide](https://github.com/RustScan/RustScan#-full-installation-guide) | 📚 [Documentation](https://github.com/RustScan/RustScan/issues/89) | 🦜 [Discord](https://discord.gg/GFrQsGy)
No. If you want a fast port scanner, use Masscan.
> I have this great idea for a script to get information on ports / hosts
## 🙋 Table of Contents
* 📖 [Installation Guide](https://github.com/RustScan/RustScan#-full-installation-guide)
* 🦜 [Discord](https://discord.gg/GFrQsGy)
* 🤸 [Usage](https://github.com/RustScan/RustScan#-usage)
* 🎪 [Contributing](https://github.com/RustScan/RustScan#-contributing)
Great. Contribute it to Nmap! :D
> Not everyone has nmap installed....
If you're a pentester, then yes, you have Nmap installed.
> I want to contribute!
Great! I'd love some help with this. Read the [contributing.md file](contributing.md) file for more information!
# 📖 Full Installation Guide
**You need Nmap**. If you have Kali Linux or Parrot OS installed, you already have Nmap. If not, [follow the nmap install guide](https://nmap.org/download.html).
@@ -277,13 +275,45 @@ To increase accuracy, the easiest way is to increase the timeout. The default is
Decreasing accuracy gives some speed bonus, but my testing found that batch size dramatically changed the speed whereas timeout did, but not so much.
# 🎪 Contributing
# 🎪 Community
Howdy Space Cow-Person 🤠🌌
RustScan is always looking for contributors. Whether that's spelling mistakes or major changes, your help is **wanted** and welcomed here.
Before contributing, read our [code of conduct](https://github.com/RustScan/RustScan/blob/master/CODE_OF_CONDUCT.md).
TL;DR if you abuse members of our community you will be **perma-banned** 🤗
RustScan has 2 major labels for GitHub issues you should look at:
* Good First issue
These are issues for newcomers to open source!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
* Help wanted
These are issues that aren't really for newcomers, but we could still do wiht help!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22)
If you want to, solve the issue or comment on the issue for help.
The flow for contributing to open source software is:
* Fork the repo
* Make changes
* Pull request to the repo
And then comment on the issue that you've done.
RustScan also has some `// TODO`'s in the codebase, which are meant more for the core team but we wouldn't say no to help with these issues.
If you have any feature suggestions or bugs, leave a GitHub issue. We welcome any and all support :D
We communicate over Discord. [Click here](https://discord.gg/GFrQsGy) to join our Discord community!
## Rewarding you
I cannot pay you :-( But, I can place your GitHub profile on the README under `#Contributors` as a thank you! :)
Please read the [contributing.md file](contributing.md)
# 💻 Other Hacking Projects By This Author
## 🧮 Ciphey
Ciphey is an automated decryption tool using artifical intelligence & natural language processing.
[Check it out here!](https://github.com/ciphey/ciphey)
## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-)
+29 -4
View File
@@ -1,6 +1,31 @@
This is my first Rust project! As such, I expect there are many, many bugs involved or things that can be sped up.
Howdy Space Cow-Person 🤠🌌
If you're looking to get involved, we make use of Good First Issues / Help Wanted tags. Click this link to see all the issues we could use help with!
[https://github.com/brandonskerritt/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22](https://github.com/brandonskerritt/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
RustScan is always looking for contributors. Whether that's spelling mistakes or major changes, your help is **wanted** and welcomed here.
Please leave issues / pull requests, I'd love to learn more about this amazing language :)
Before contributing, read our [code of conduct](https://github.com/RustScan/RustScan/blob/master/CODE_OF_CONDUCT.md).
TL;DR if you abuse members of our community you will be **perma-banned** with no chance to get unbanned. No warnings either. 🤗
RustScan has 2 major labels for GitHub issues you should look at:
* Good First issue
These are issues for newcomers to open source!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
* Help wanted
These are issues that aren't really for newcomers, but we could still do wiht help!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22)
If you want to, solve the issue or comment on the issue for help.
The flow for contributing to open source software is:
* Fork the repo
* Make changes
* Pull request to the repo
And then comment on the issue that you've done.
RustScan also has some `// TODO`'s in the codebase, which are meant more for the core team but we wouldn't say no to help with these issues.
If you have any feature suggestions or bugs, leave a GitHub issue. We welcome any and all support :D
## Rewarding you
I cannot pay you :-( But, I can place your GitHub profile on the README under `#Contributors` as a thank you! :)
-1
View File
@@ -18,4 +18,3 @@ RUN echo "objcopy = { path = \"arm-linux-gnueabihf-objcopy\" }" >> /root/.cargo/
COPY ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
1
+125 -74
View File
@@ -8,9 +8,17 @@ use futures::executor::block_on;
use rlimit::Resource;
use rlimit::{getrlimit, setrlimit};
use std::process::{exit, Command};
use std::time::Duration;
use std::{net::IpAddr, time::Duration};
use structopt::StructOpt;
// Average value for Ubuntu
const DEFAULT_FILE_DESCRIPTORS_LIMIT: rlimit::rlim = 8000;
// Safest batch size based on experimentation
const AVERAGE_BATCH_SIZE: rlimit::rlim = 3000;
#[macro_use]
extern crate log;
#[derive(StructOpt, Debug)]
#[structopt(name = "rustscan", setting = structopt::clap::AppSettings::TrailingVarArg)]
/// Fast Port Scanner built in Rust.
@@ -18,7 +26,8 @@ use structopt::StructOpt;
/// specified server may not be able to handle this many socket connections at once.
struct Opts {
/// The IP address to scan
ip: String,
#[structopt(parse(try_from_str))]
ip: IpAddr,
///Quiet mode. Only output the ports. No Nmap. Useful for grep or outputting to a file.
#[structopt(short, long)]
@@ -29,15 +38,15 @@ struct Opts {
/// it will do every port at the same time. Although, your OS may not
/// support this.
#[structopt(short, long, default_value = "4500")]
batch_size: u64,
batch_size: u32,
/// The timeout in milliseconds before a port is assumed to be closed.
#[structopt(short, long, default_value = "1500")]
timeout: u64,
timeout: u32,
/// Automatically ups the ULIMIT with the value you provided.
#[structopt(short, long)]
ulimit: Option<u64>,
ulimit: Option<rlimit::rlim>,
/// The Nmap arguments to run.
/// To use the argument -A, end RustScan's args with '-- -A'.
@@ -48,77 +57,29 @@ struct Opts {
}
/// Faster Nmap scanning with Rust
/// If you're looking for the actual scanning, check out the module Scanner.
fn main() {
let mut opts = Opts::from_args();
// logger
env_logger::init();
let user_nmap_options = if opts.command.is_empty() {
"-A -vvv".to_string()
} else {
opts.command.join(" ")
};
info!("Starting up");
let opts = Opts::from_args();
info!("Mains() `opts` arguments are {:?}", opts);
if !opts.quiet {
print_opening();
}
// Updates ulimit when the argument is set
if opts.ulimit.is_some() {
let limit = opts.ulimit.unwrap();
if !opts.quiet {
println!("Automatically upping ulimit to {}", limit);
}
match setrlimit(Resource::NOFILE, limit, limit) {
Ok(_) => {}
Err(_) => println!("ERROR. Failed to set Ulimit."),
}
}
let (x, _) = getrlimit(Resource::NOFILE).unwrap();
// if maximum limit is lower than batch size
// automatically re-adjust the batch size
if x < opts.batch_size {
if !opts.quiet {
println!("{}", "WARNING: Your file description limit is lower than selected batch size. Please considering upping this (how to is on the README). NOTE: this may be dangerous and may cause harm to sensitive servers. Automatically reducing Batch Size to match your limit, this process isn't harmful but reduces speed.".red());
}
// TODO this is a joke please fix
// if the OS supports high file limits like 8000
// but the user selected a batch size higher than this
// reduce to a lower number
// basically, ubuntu is 8000
// but i can only get it to work on < 5k in testing
// 5k is default, so 3000 seems safe
if x > 8000 {
opts.batch_size = 3000
} else {
opts.batch_size = x - 100u64;
}
}
// else if the ulimit is higher than batch size
// tell the user they can increase batch size
// if the user set ulimit arg they probably know what they are doing so don't print this
else if x + 2 > opts.batch_size && (opts.ulimit.is_none()) {
if !opts.quiet {
println!(
"Your file description limit is higher than the batch size. You can potentially increase the speed by increasing the batch size, but this may cause harm to sensitive servers. Your limit is {}, try batch size {}.",
x,
x - 1u64
);
}
}
// the user has asked to automatically up the ulimit
let ulimit: rlimit::rlim = adjust_ulimit_size(&opts);
let batch_size: u32 = infer_batch_size(&opts, ulimit);
// 65535 + 1 because of 0 indexing
let scanner = Scanner::new(
&opts.ip,
opts.ip,
1,
65536,
opts.batch_size,
Duration::from_millis(opts.timeout),
65535,
batch_size,
Duration::from_millis(opts.timeout.into()),
opts.quiet,
);
let scan_result = block_on(scanner.run());
@@ -132,7 +93,7 @@ fn main() {
// if no ports are found, suggest running with less
if nmap_str_ports.is_empty() {
panic!("{} Looks like I didn't find any open ports. This is usually caused by a high batch size.
\n*I used {} threads, consider lowering to {} with {} or a comfortable number lfor your system.
\n*I used {} batch size, consider lowering to {} with {} or a comfortable number for your system.
\n Alternatively, increase the timeout if your ping is high. Rustscan -T 2000 for 2000 second timeout.", "ERROR".red(),
opts.batch_size,
(opts.batch_size / 2).to_string().green(),
@@ -153,14 +114,14 @@ fn main() {
exit(1);
}
let nmap_args = format!(
"{} {} {} {} {} {}",
&user_nmap_options, "-vvv", "-Pn", "-p", &ports_str, opts.ip
);
let addr = opts.ip.to_string();
let user_nmap_args =
shell_words::split(&opts.command.join(" ")).expect("failed to parse nmap arguments");
let nmap_args = build_nmap_arguments(&addr, &ports_str, &user_nmap_args, opts.ip.is_ipv6());
if !opts.quiet {
println!("The Nmap command to be run is {}", &nmap_args);
println!("The Nmap command to be run is {}", &nmap_args.join(" "));
}
let nmap_args = shell_words::split(&nmap_args).expect("failed to parse nmap arguments");
// Runs the nmap command and spawns it as a process.
let mut child = Command::new("nmap")
@@ -171,7 +132,9 @@ fn main() {
child.wait().expect("failed to wait on nmap process");
}
/// Prints the opening title of RustScan
fn print_opening() {
info!("Printing opening");
let s = "
_____ _ _____
| __ \\ | | / ____|
@@ -183,16 +146,104 @@ fn print_opening() {
println!("{}\n", s.green());
}
fn build_nmap_arguments<'a>(
addr: &'a str,
ports: &'a str,
user_args: &'a Vec<String>,
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 {
arguments.push("-6");
}
arguments.push("-p");
arguments.push(ports);
arguments.push(addr);
arguments
}
fn adjust_ulimit_size(opts: &Opts) -> rlimit::rlim {
if opts.ulimit.is_some() {
let limit: rlimit::rlim = opts.ulimit.unwrap();
match setrlimit(Resource::NOFILE, limit, limit) {
Ok(_) => {
if !opts.quiet {
println!("\nAutomatically increasing ulimit value to {}.\n", limit);
}
}
Err(_) => println!("{}", "ERROR. Failed to set ulimit value.".red()),
}
}
let (rlim, _) = getrlimit(Resource::NOFILE).unwrap();
rlim
}
fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u32 {
let mut batch_size: rlimit::rlim = opts.batch_size.into();
// Adjust the batch size when the ulimit value is lower than the desired batch size
if ulimit < batch_size {
if !opts.quiet {
println!("{}", "WARNING: Your file description limit is lower than the provided batch size. Please considering upping this (instructions in our README). NOTE: this may be dangerous and may cause harm to sensitive servers. Automatically reducing the batch Size to match your system's limit, this process isn't harmful but reduces speed.".red());
}
// When the OS supports high file limits like 8000, but the user
// selected a batch size higher than this we should reduce it to
// a lower number.
if ulimit > DEFAULT_FILE_DESCRIPTORS_LIMIT {
batch_size = AVERAGE_BATCH_SIZE
} else {
batch_size = ulimit - 100
}
}
// When the ulimit is higher than the batch size let the user know that the
// batch size can be increased unless they specified the ulimit themselves.
else if ulimit + 2 > batch_size && (opts.ulimit.is_none()) {
if !opts.quiet {
println!(
"Your file descriptor limit is higher than the batch size. You can potentially increase the speed by increasing the batch size, but this may cause harm to sensitive servers. Your limit is {}, try batch size {}.",
ulimit,
ulimit - 1
);
}
}
batch_size as u32
}
#[cfg(test)]
mod tests {
use super::Scanner;
use async_std::task::block_on;
use std::time::Duration;
use std::{net::IpAddr, time::Duration};
#[test]
fn does_it_run() {
// Makes sure te program still runs and doesn't panic
let scanner = Scanner::new("127.0.0.1", 1, 65536, 1000, Duration::from_millis(10), true);
let addr = match "127.0.0.1".parse::<IpAddr>() {
Ok(res) => res,
Err(_) => panic!("Could not parse IP Address"),
};
let scanner = Scanner::new(addr, 1, 65535, 1000, Duration::from_millis(10), true);
let scan_result = block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
assert_eq!(1, 1);
}
fn does_it_run_ipv6() {
// Makes sure te program still runs and doesn't panic
let addr = match "::1".parse::<IpAddr>() {
Ok(res) => res,
Err(_) => panic!("Could not parse IP Address"),
};
let scanner = Scanner::new(addr, 1, 65535, 1000, Duration::from_millis(10), true);
let scan_result = block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
assert_eq!(1, 1);
+74 -41
View File
@@ -6,24 +6,30 @@ use futures::stream::FuturesUnordered;
use std::time::Duration;
use std::{
io::ErrorKind,
net::{Shutdown, SocketAddr},
net::{IpAddr, Shutdown, SocketAddr},
};
/// The class for the scanner
/// Host is data type IpAddr and is the host address
/// start & end is where the port scan starts and ends
/// batch_size is how many ports at a time should be scanned
/// Timeout is the time RustScan should wait before declaring a port closed. As datatype Duration.
/// Quiet is whether or not RustScan should print things, or wait until the end to print only open ports.
pub struct Scanner {
host: String,
start: u64,
end: u64,
batch_size: u64,
host: IpAddr,
start: u16,
end: u16,
batch_size: u32,
timeout: Duration,
quiet: bool,
}
impl Scanner {
pub fn new(
host: &str,
start: u64,
end: u64,
batch_size: u64,
host: IpAddr,
start: u16,
end: u16,
batch_size: u32,
timeout: Duration,
quiet: bool,
) -> Self {
@@ -37,9 +43,14 @@ impl Scanner {
}
}
pub async fn run(&self) -> Vec<u64> {
let ports: Vec<u64> = (self.start..self.end).collect();
let mut open_ports: std::vec::Vec<u64> = Vec::new();
/// Runs scan_range with chunk sizes
/// If you want to run RustScan normally, this is the entry point used
/// Returns all open ports as Vec<u16>
pub async fn run(&self) -> Vec<u16> {
let ports: Vec<u16> = (self.start..self.end).collect();
let mut open_ports: std::vec::Vec<u16> = Vec::new();
// TODO change this to port size
// to fix bug when we introduce custom port ranges
for range in ports.chunks(self.batch_size as usize) {
let mut ports = self.scan_range(range).await;
@@ -49,14 +60,15 @@ impl Scanner {
open_ports
}
async fn scan_range(&self, range: &[u64]) -> Vec<u64> {
/// Given a range of ports, scan them all.
/// Returns a vector of open ports.
async fn scan_range(&self, range: &[u16]) -> Vec<u16> {
let mut ftrs = FuturesUnordered::new();
for port in range {
ftrs.push(self.scan_port(port));
ftrs.push(self.scan_port(*port));
}
let mut open_ports: Vec<u64> = Vec::new();
let mut open_ports: Vec<u16> = Vec::new();
while let Some(result) = ftrs.next().await {
match result {
Ok(port) => open_ports.push(port),
@@ -67,39 +79,60 @@ impl Scanner {
open_ports
}
async fn scan_port(&self, port: &u64) -> io::Result<u64> {
let addr = format!("{}:{}", self.host, port);
match addr.parse() {
Ok(sock_addr) => match self.connect(sock_addr).await {
Ok(stream_result) => {
match stream_result.shutdown(Shutdown::Both) {
_ => {}
}
if !self.quiet {
println!("Open {}", port.to_string().purple());
}
Ok(*port)
/// Given a port, scan it.
/// Turns the address into a SocketAddr
/// Deals with the <result> type
/// If it experiences error ErrorKind::Other then too many files are open and it Panics!
/// ese any other error, it returns the error in Result as a string
/// If no errors occur, it returns the port number in Result to signify the port is open.
/// This function mainly deals with the logic of Results handling.
/// # Example
///
/// self.scan_port(10:u16)
///
/// Note: `self` must contain `self.host`.
async fn scan_port(&self, port: u16) -> io::Result<u16> {
let addr = SocketAddr::new(self.host, port);
// println!("{:?}", addr);
match self.connect(addr).await {
Ok(x) => {
// match stream_result.shutdown(Shutdown::Both)
info!("Shutting down stream");
match x.shutdown(Shutdown::Both) {
_ => {}
}
Err(e) => match e.kind() {
ErrorKind::Other => {
eprintln!("{:?}", e); // in case we get too many open files
panic!("Too many open files. Please reduce batch size. The default is 5000. Try -b 2500.");
}
_ => Err(io::Error::new(io::ErrorKind::Other, e.to_string())),
},
},
Err(e) => {
eprintln!("Unable to convert to socket address {:?}", e);
panic!("Unable to convert to socket address");
if !self.quiet {
println!("Open {}", port.to_string().purple());
}
// if connection successful
// shut down stream
// return port
Ok(port)
}
Err(e) => match e.kind() {
ErrorKind::Other => {
panic!("Too many open files. Please reduce batch size. The default is 5000. Try -b 2500.");
}
_ => Err(io::Error::new(io::ErrorKind::Other, e.to_string())),
},
}
}
/// Performs the connection to the socket with timeout
/// # Example
///
/// let port: u16 = 80
/// // Host is an IpAddr type
/// let host = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// let addr = SocketAddr::new(host, port)
/// self.connect(addr)
/// // returns Result which is either Ok(stream) for port is open, or Er for port is closed.
/// // Timeout occurs after self.timeout seconds
///
async fn connect(&self, addr: SocketAddr) -> io::Result<TcpStream> {
let stream =
io::timeout(self.timeout, async move { TcpStream::connect(addr).await }).await?;
info!("Returning okay from connect");
Ok(stream)
}
}