mirror of
https://github.com/bee-san/RustScan.git
synced 2026-11-08 01:08:27 -10:00
Compare commits
77
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bf70f0f9a | ||
|
|
57dfb15852 | ||
|
|
282065752c | ||
|
|
982ae0d926 | ||
|
|
53f8a15e16 | ||
|
|
fc214a78b4 | ||
|
|
0ae289c25f | ||
|
|
9326fc4a0f | ||
|
|
c05ebaf857 | ||
|
|
6f8df7e77e | ||
|
|
488853f40e | ||
|
|
57c1e33650 | ||
|
|
699b578ade | ||
|
|
ebe5a326a8 | ||
|
|
abb7a3872c | ||
|
|
f74cb456b1 | ||
|
|
492d2fb3b3 | ||
|
|
af53591ccb | ||
|
|
6405b43f5a | ||
|
|
9a71253697 | ||
|
|
4d6d57fe2c | ||
|
|
a040ab5521 | ||
|
|
a546aa2ac0 | ||
|
|
868e61bb2e | ||
|
|
c4f8ceb336 | ||
|
|
9d80fb4fa7 | ||
|
|
e659d51976 | ||
|
|
64f4aecacd | ||
|
|
afe2a9452f | ||
|
|
4a6e74d507 | ||
|
|
eb905f7e7a | ||
|
|
561e7fb2f0 | ||
|
|
e5d22a0421 | ||
|
|
33c9388586 | ||
|
|
4dfe76737b | ||
|
|
cc0b344232 | ||
|
|
abaf100da9 | ||
|
|
43602793e0 | ||
|
|
7b827991c1 | ||
|
|
f4555ecb98 | ||
|
|
2fb8a399a7 | ||
|
|
e612ddc4e6 | ||
|
|
8bf75846d3 | ||
|
|
bf1cb3a5d0 | ||
|
|
01975d7238 | ||
|
|
8c4cc77e6b | ||
|
|
b0c1ab3177 | ||
|
|
6812cc3051 | ||
|
|
2800adec34 | ||
|
|
cf1aa67a21 | ||
|
|
c9708671e8 | ||
|
|
461f9aaa6d | ||
|
|
01a74b72df | ||
|
|
d301cf3b20 | ||
|
|
5e8d45bf01 | ||
|
|
bc5b2eea7e | ||
|
|
c8a8915682 | ||
|
|
d786e24186 | ||
|
|
5b536621e6 | ||
|
|
c05f40ae70 | ||
|
|
24b9f8d8d3 | ||
|
|
bda392c9a7 | ||
|
|
3836480486 | ||
|
|
2291ba73d2 | ||
|
|
e0af8a306a | ||
|
|
cb0f4f7a92 | ||
|
|
402bea4b06 | ||
|
|
f44dda0360 | ||
|
|
965a173032 | ||
|
|
d95cae6677 | ||
|
|
2f92d5583a | ||
|
|
8d8da79640 | ||
|
|
e5b4a2f443 | ||
|
|
a0b877729e | ||
|
|
743fa1cad6 | ||
|
|
a0561d4728 | ||
|
|
b2a1bd2e7a |
No files matched your search
@@ -173,6 +173,35 @@
|
||||
"contributions": [
|
||||
"platform"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "buermarc",
|
||||
"name": "buermarc",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/44375277?v=4",
|
||||
"profile": "https://github.com/buermarc",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "bergabman",
|
||||
"name": "bergabman",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/44554109?v=4",
|
||||
"profile": "https://github.com/bergabman",
|
||||
"contributions": [
|
||||
"code",
|
||||
"bug",
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dmitris",
|
||||
"name": "Dmitry Savintsev",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/31205?v=4",
|
||||
"profile": "https://github.com/dmitris",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
github: brandonskerritt
|
||||
github: bee-san
|
||||
patreon: brandonskerritt
|
||||
ko_fi: hacker
|
||||
custom: ["https://monzo.me/bee", "https://paypal.me/brandonskerritt"]
|
||||
@@ -0,0 +1,4 @@
|
||||
template: |
|
||||
## What’s Changed
|
||||
|
||||
$CHANGES
|
||||
+77
@@ -43,3 +43,80 @@ pkg/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/rust,archlinuxpackages
|
||||
*.deb
|
||||
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
.idea/*
|
||||
.idea
|
||||
.idea*
|
||||
+13
-13
@@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation.
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
|
||||
Generated
+144
-71
@@ -41,9 +41,9 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.4.1"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59386c3aa61f4e14c4ddda1a6744c119b4bf278ec9f866d3c20bc5728ee0eb97"
|
||||
checksum = "43de69555a39d52918e2bc33a408d3c0a86c829b212d898f4ca25d21a6387478"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
@@ -52,53 +52,68 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "0.1.2"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90f47c78ea98277cb1f5e6f60ba4fc762f5eafe9f6511bc2f7dfd8b75c225650"
|
||||
checksum = "a831e74aa1937d3bbd3a356f34c23dbc6b6f0abc5160bd5484a9f75d5e76aea8"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c07d34f7bea9658346df5745d5c7b121c475aab7f7ec7c3dc5905d33ddefc899"
|
||||
dependencies = [
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"futures-lite",
|
||||
"multitask",
|
||||
"parking 1.0.6",
|
||||
"scoped-tls",
|
||||
"waker-fn",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "0.1.11"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ae22a338d28c75b53702b66f77979062cb29675db376d99e451af4fa79dedb3"
|
||||
checksum = "38628c78a34f111c5a6b98fc87dfc056cd1590b61afe748b145be4623c56d194"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"log",
|
||||
"once_cell",
|
||||
"parking 2.0.0",
|
||||
"parking",
|
||||
"polling",
|
||||
"socket2",
|
||||
"vec-arena",
|
||||
"waker-fn",
|
||||
"wepoll-sys-stjepang",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-mutex"
|
||||
version = "1.2.0"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "065de1ccf10280d0d75c2f3a71a970ee1007c85c51aa3e7deee1df100f1dfadb"
|
||||
checksum = "20e85981fc34e84cdff3fc2c9219189752633fdc538a06df8b5ac45b68a4f3a9"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.6.3"
|
||||
version = "1.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c8da367da62b8ff2313c406c9ac091c1b31d67a165becdd2de380d846260f7"
|
||||
checksum = "3c92085acfce8b32e5b261d0b59b8f3309aee69fea421ea3f271f8b93225754f"
|
||||
dependencies = [
|
||||
"async-executor",
|
||||
"async-global-executor",
|
||||
"async-io",
|
||||
"async-mutex",
|
||||
"async-task",
|
||||
@@ -108,6 +123,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"gloo-timers",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
@@ -144,15 +160,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@@ -173,12 +189,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "0.5.2"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea5800d29218fea137b0880387e5948694a23c93fcdde157006966693a865c7c"
|
||||
checksum = "2640778f8053e72c11f621b0a5175a0560a269282aa98ed85107773ab8e2a556"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"waker-fn",
|
||||
@@ -198,9 +215,9 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.59"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"
|
||||
checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -209,10 +226,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
name = "cidr-utils"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
checksum = "89f7b6372f3c783f6d44c0da283d3694af4104967bf2371cb3bdc9d09e1cfe00"
|
||||
dependencies = [
|
||||
"debug-helper",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10040cdf04294b565d9e0319955430099ec3813a64c952b86a41200ad714ae48"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0",
|
||||
"atty",
|
||||
@@ -266,6 +296,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"
|
||||
@@ -286,6 +322,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
@@ -301,9 +343,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.4.0"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cd41440ae7e4734bbd42302f63eaba892afc93a3912dad84006247f0dedb0e"
|
||||
checksum = "68082183f458867ce7cddea16d4df4443c1537112c0c09c450dedc09daf5c719"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
@@ -361,15 +403,15 @@ checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "0.1.11"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97999970129b808f0ccba93211201d431fcc12d7e1ffae03a61b5cedd1a7ced2"
|
||||
checksum = "5b77e08e656f472d8ea84c472fa8b0a7a917883048e1cf2d4e34a323cd0aaf63"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking 2.0.0",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
@@ -438,6 +480,19 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
@@ -465,6 +520,15 @@ dependencies = [
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.44"
|
||||
@@ -491,9 +555,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.76"
|
||||
version = "0.2.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
|
||||
checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@@ -511,14 +575,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "multitask"
|
||||
version = "0.2.0"
|
||||
name = "num-bigint"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c09c35271e7dcdb5f709779111f2c8e8ab8e06c1b587c1c6a9e179d865aaa5b4"
|
||||
checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"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]]
|
||||
@@ -537,12 +620,6 @@ version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
@@ -583,9 +660,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "0.1.7"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53c5afb3e8bc82c2780a807374bda0fb8886904d8e9d51e6f4f3743fb1dd27fb"
|
||||
checksum = "0307b8c7f438902536321f63c28cab0362f6ee89f1c7da47e3642ff956641c8b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -596,9 +673,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.9"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
|
||||
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
@@ -709,9 +786,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.5"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
@@ -748,9 +825,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
|
||||
checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"blake2b_simd",
|
||||
@@ -760,16 +837,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustscan"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"async-std",
|
||||
"cidr-utils",
|
||||
"colored",
|
||||
"colorful",
|
||||
"dirs",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"gcd",
|
||||
"itertools",
|
||||
"log",
|
||||
"rand",
|
||||
"rlimit",
|
||||
@@ -780,23 +859,17 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.115"
|
||||
version = "1.0.116"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
|
||||
checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.115"
|
||||
version = "1.0.116"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
|
||||
checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -859,9 +932,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.39"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
|
||||
checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -924,9 +997,9 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "vec-arena"
|
||||
version = "0.5.2"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cb18268690309760d59ee1a9b21132c126ba384f374c59a94db4bc03adeb561"
|
||||
checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
@@ -942,9 +1015,9 @@ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
checksum = "9571542c2ce85ce642e6b58b3364da2fb53526360dfb7c211add4f5c23105ff7"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
|
||||
+7
-5
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustscan"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
authors = ["Bee <[email protected]>"]
|
||||
edition = "2018"
|
||||
description = "Faster Nmap Scanning with Rust"
|
||||
@@ -19,7 +19,7 @@ exclude = [
|
||||
[dependencies]
|
||||
colored = "2.0.0"
|
||||
structopt = "0.3.17"
|
||||
async-std = "1.6.3"
|
||||
async-std = "1.6.4"
|
||||
futures = "0.3"
|
||||
rlimit = "0.4.0"
|
||||
shell-words = "1.0.0"
|
||||
@@ -31,8 +31,10 @@ rand = "0.7.3"
|
||||
colorful = "0.2.1"
|
||||
ansi_term = "0.12.1"
|
||||
toml = "0.5.6"
|
||||
serde = "1.0.115"
|
||||
serde_derive = "1.0.115"
|
||||
serde = "1.0.116"
|
||||
serde_derive = "1.0.116"
|
||||
cidr-utils = "0.5.0"
|
||||
itertools = "0.9.0"
|
||||
|
||||
[package.metadata.deb]
|
||||
depends = "$auto, nmap"
|
||||
@@ -40,4 +42,4 @@ section = "rust"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
panic = 'abort'
|
||||
panic = 'abort'
|
||||
+5
-2
@@ -1,8 +1,11 @@
|
||||
FROM rust:alpine as builder
|
||||
LABEL maintainer="CMNatic <https://github.com/CMNatic">
|
||||
RUN apk add --no-cache build-base
|
||||
|
||||
# Encourage some layer caching here rather then copying entire directory that includes docs to builder container ~CMN
|
||||
WORKDIR /usr/src/rustscan
|
||||
COPY . .
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY src src
|
||||
RUN cargo install --path .
|
||||
|
||||
FROM alpine:3.12
|
||||
@@ -13,4 +16,4 @@ RUN addgroup -S rustscan && \
|
||||
apk add --no-cache nmap nmap-scripts wget
|
||||
COPY --from=builder /usr/local/cargo/bin/rustscan /usr/local/bin/rustscan
|
||||
USER rustscan
|
||||
ENTRYPOINT [ "/usr/local/bin/rustscan" ]
|
||||
ENTRYPOINT [ "/usr/local/bin/rustscan" ]
|
||||
@@ -13,7 +13,7 @@
|
||||
<p align="center">
|
||||
<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 commit activity" src="https://img.shields.io/github/commit-activity/w/Rustscan/Rustscan">
|
||||
<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">
|
||||
@@ -21,10 +21,10 @@
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
| <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="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` |
|
||||
| <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="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:v1.9.0` <p>[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` |
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -111,9 +111,9 @@ 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 commpand `dpkg -i` on the file.
|
||||
Run the command `dpkg -i` on the file.
|
||||
|
||||
Note: sometimes you can double click the file to achieve the same result.
|
||||
|
||||
@@ -130,22 +130,22 @@ To install Docker, [follow their guide](https://docs.docker.com/engine/install/)
|
||||
|
||||
**Once Docker is installed, you can either build your own image using the `Dockerfile` (alpine) provided in the repo, or alternatively, use the published Docker image like below (most convenient)**
|
||||
|
||||
Please see our [DockerHub](https://hub.docker.com/repository/docker/rustscan/rustscan) for further info, however, note that we have two Docker images:
|
||||
Please see our [DockerHub](https://hub.docker.com/repository/docker/rustscan/rustscan) for further our published versions. However, we recommend using our latest release [v1.9.0](https://github.com/RustScan/RustScan/releases/tag/1.9.0)
|
||||
|
||||
```
|
||||
rustscan/rustscan:alpine
|
||||
Stable and supported: rustscan/rustscan:v1.9.0
|
||||
|
||||
rustscan/rustscan:latest
|
||||
Bleeding edge (run at your own risk!): rustscan/rustscan:latest
|
||||
```
|
||||
|
||||
We strongly recommend using the `alpine` tag, as this is the latest major - stable - release of RustScan. This READMDE uses the `alpine` image by default, however, note that the`latest` image is considered experimental.
|
||||
We strongly recommend using the `v1.9.0` tag, as this is the latest major - stable - release of RustScan. This README uses the `v1.9.0` image by default, however, note that the `latest` image is considered experimental.
|
||||
|
||||
#### To get started:
|
||||
|
||||
Simply run this command against the IP you want to target:
|
||||
|
||||
```bash
|
||||
docker run -it --rm --name rustscan rustscan/rustscan:alpine <rustscan arguments here> <ip address to scan>
|
||||
docker run -it --rm --name rustscan rustscan/rustscan:v1.9.0 <rustscan arguments here> <ip address to scan>
|
||||
```
|
||||
|
||||
Note: this will scan the Docker's localhost, not your own.
|
||||
@@ -155,13 +155,13 @@ Once done, you will no longer need to re-download the image (except when RustSca
|
||||
You will have to run this command every time, so we suggest aliasing it to something memorable.
|
||||
|
||||
```bash
|
||||
alias rustscan='docker run -it --rm --name rustscan rustscan/rustscan:alpine'
|
||||
alias rustscan='docker run -it --rm --name rustscan rustscan/rustscan:v1.9.0'
|
||||
```
|
||||
|
||||
Then we can:
|
||||
Then we can scan:
|
||||
|
||||
```bash
|
||||
rustscan 127.0.0.1 -t 500 -b 1500 -- -A
|
||||
rustscan 192.168.1.0/24 -t 500 -b 1500 -- -A
|
||||
```
|
||||
|
||||
#### To build your own image:
|
||||
@@ -188,15 +188,7 @@ docker build -t <yourimagename> .
|
||||
|
||||
**Note for Mac users** Mac OS has a very, very small ulimit size. This will negatively impact RustScan by a significant amount. Please use the Docker container, or tell RustScan to up the ulimit size on every run.
|
||||
|
||||
Tap the brew:
|
||||
|
||||
```bash
|
||||
brew tap brandonskerritt/rustscan
|
||||
```
|
||||
|
||||
Install it:
|
||||
|
||||
```bash
|
||||
brew install rustscan
|
||||
```
|
||||
|
||||
@@ -229,14 +221,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]... [-- <command>...]
|
||||
rustscan [FLAGS] [OPTIONS] [addresses]... [-- <command>...]
|
||||
|
||||
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 <batch-size> The batch size for port scanning, it increases or slows the speed of scanning.
|
||||
@@ -251,14 +244,14 @@ OPTIONS:
|
||||
-u, --ulimit <ulimit> Automatically ups the ULIMIT with the value you provided
|
||||
|
||||
ARGS:
|
||||
<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)'\"")
|
||||
<addresses>... A list of comma separated CIDRs, IPs, 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.
|
||||
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.
|
||||
|
||||
The batch size determines how fast RustScan is. Set it to 65k, and it will scan all 65k ports at the same time. This means at at 65k batch size, RustScan will take TIMEOUT long to scan all ports. Essentially, if timeout is 1000ms, **RustScan can scan in 1 second**.
|
||||
|
||||
@@ -269,7 +262,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 +276,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 }
|
||||
@@ -301,6 +294,8 @@ This program, by default, scans 5000 ports at a time (5000 per second).
|
||||
|
||||
This may cause damage to a server, or may make it incredibly obvious you are scanning the server.
|
||||
|
||||
Servers as well as individual services can block your IP completely after a huge amount of simultaneous connections/tries, Possibly causing you to see false positives. False positives are open ports at the initial scanning process later found closed when you want to do further scanning, or connect to it.
|
||||
|
||||
There are 2 ways to deal with this;
|
||||
|
||||
1. Decrease batch size
|
||||
@@ -364,7 +359,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,9 +427,7 @@ Please read the [contributing.md file](contributing.md)
|
||||
## Contributors ✨
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
|
||||
[](#contributors-)
|
||||
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
@@ -465,12 +458,14 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center"><a href="https://swag.lgbt"><img src="https://avatars2.githubusercontent.com/u/25358963?v=4" width="100px;" alt=""/><br /><sub><b>Cass</b></sub></a><br /><a href="#platform-caass" title="Packaging/porting to new platform">📦</a> <a href="https://github.com/RustScan/RustScan/commits?author=caass" title="Code">💻</a> <a href="https://github.com/RustScan/RustScan/issues?q=author%3Acaass" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/niklasmohrin"><img src="https://avatars0.githubusercontent.com/u/47574893?v=4" width="100px;" alt=""/><br /><sub><b>Niklas Mohrin</b></sub></a><br /><a href="https://github.com/RustScan/RustScan/commits?author=niklasmohrin" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://liberapay.com/Artem4/"><img src="https://avatars0.githubusercontent.com/u/5614476?v=4" width="100px;" alt=""/><br /><sub><b>Artem Polishchuk</b></sub></a><br /><a href="#platform-tim77" title="Packaging/porting to new platform">📦</a></td>
|
||||
<td align="center"><a href="https://github.com/buermarc"><img src="https://avatars2.githubusercontent.com/u/44375277?v=4" width="100px;" alt=""/><br /><sub><b>buermarc</b></sub></a><br /><a href="https://github.com/RustScan/RustScan/commits?author=buermarc" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/bergabman"><img src="https://avatars1.githubusercontent.com/u/44554109?v=4" width="100px;" alt=""/><br /><sub><b>bergabman</b></sub></a><br /><a href="https://github.com/RustScan/RustScan/commits?author=bergabman" title="Code">💻</a> <a href="https://github.com/RustScan/RustScan/issues?q=author%3Abergabman" title="Bug reports">🐛</a> <a href="#design-bergabman" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/dmitris"><img src="https://avatars0.githubusercontent.com/u/31205?v=4" width="100px;" alt=""/><br /><sub><b>Dmitry Savintsev</b></sub></a><br /><a href="https://github.com/RustScan/RustScan/commits?author=dmitris" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
+1
-1
@@ -11,7 +11,7 @@ RustScan has 2 major labels for GitHub issues you should look at:
|
||||
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!
|
||||
These are issues that aren't really for newcomers, but we could still do with 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.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
//! # Usage
|
||||
//! ```
|
||||
//! // Initiate Benchmark vector
|
||||
//! let mut bm = Benchmark::init();
|
||||
//! // Start named timer with name
|
||||
//! let mut example_bench = NamedTimer::start("Example Bench");
|
||||
//! // Stop named timer
|
||||
//! example_bench.stop();
|
||||
//! // Add named timer to Benchmarks
|
||||
//! bm.push(example_bench);
|
||||
//! // Print Benchmark Summary
|
||||
//! info!({}, bm.summary());
|
||||
//! ```
|
||||
use std::time::Instant;
|
||||
|
||||
/// A Benchmark struct to hold NamedTimers with name, start and end Instants,
|
||||
#[derive(Debug)]
|
||||
pub struct Benchmark {
|
||||
named_timers: Vec<NamedTimer>,
|
||||
}
|
||||
|
||||
impl Benchmark {
|
||||
pub fn init() -> Self {
|
||||
Self {
|
||||
named_timers: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn push(&mut self, timer: NamedTimer) {
|
||||
self.named_timers.push(timer);
|
||||
}
|
||||
|
||||
/// Summary of the benchmarks will destruct the vector,
|
||||
/// formats every element the same way and return
|
||||
/// a single String with all the available information
|
||||
/// for easy printing
|
||||
pub fn summary(&self) -> String {
|
||||
let mut summary = String::from("\nRustScan Benchmark Summary");
|
||||
|
||||
for timer in &self.named_timers {
|
||||
if timer.start.is_some() && timer.end.is_some() {
|
||||
let runtime_secs = timer
|
||||
.end
|
||||
.unwrap()
|
||||
.saturating_duration_since(timer.start.unwrap())
|
||||
.as_secs_f32();
|
||||
summary.push_str(&format!("\n{0: <10} | {1: <10}s", timer.name, runtime_secs))
|
||||
}
|
||||
}
|
||||
summary
|
||||
}
|
||||
}
|
||||
|
||||
/// The purpose of NamedTimer is to hold a name,
|
||||
/// start Instant and end Instant for a specific timer.
|
||||
/// The given name will be presented in the benchmark summary,
|
||||
/// start and end Instants will be used for calculating runtime.
|
||||
#[derive(Debug)]
|
||||
pub struct NamedTimer {
|
||||
name: &'static str,
|
||||
start: Option<Instant>,
|
||||
end: Option<Instant>,
|
||||
}
|
||||
|
||||
impl NamedTimer {
|
||||
pub fn start(name: &'static str) -> Self {
|
||||
Self {
|
||||
name: name,
|
||||
start: Some(Instant::now()),
|
||||
end: None,
|
||||
}
|
||||
}
|
||||
pub fn end(&mut self) {
|
||||
self.end = Some(Instant::now());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn benchmark() {
|
||||
let mut benchmarks = Benchmark::init();
|
||||
let mut test_timer = NamedTimer::start("test");
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
test_timer.end();
|
||||
benchmarks.push(test_timer);
|
||||
benchmarks.push(NamedTimer::start("only_start"));
|
||||
assert!(benchmarks
|
||||
.summary()
|
||||
.contains("\nRustScan Benchmark Summary\ntest | 0."));
|
||||
assert_ne!(benchmarks.summary().contains("only_start"), true);
|
||||
}
|
||||
+92
-122
@@ -1,4 +1,5 @@
|
||||
use serde_derive::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use structopt::{clap::arg_enum, StructOpt};
|
||||
|
||||
@@ -23,6 +24,7 @@ pub struct PortRange {
|
||||
pub end: u16,
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
fn parse_range(input: &str) -> Result<PortRange, String> {
|
||||
let range = input
|
||||
.split("-")
|
||||
@@ -54,9 +56,9 @@ fn parse_range(input: &str) -> Result<PortRange, String> {
|
||||
/// - 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<String>,
|
||||
pub addresses: Vec<String>,
|
||||
|
||||
/// A list of comma separed ports to be scanned. Example: 80,443,8080.
|
||||
#[structopt(short, long, use_delimiter = true)]
|
||||
@@ -70,9 +72,9 @@ pub struct Opts {
|
||||
#[structopt(short, long)]
|
||||
pub no_config: bool,
|
||||
|
||||
/// Quiet mode. Only output the ports. No Nmap. Useful for grep or outputting to a file.
|
||||
/// Greppable mode. Only output the ports. No Nmap. Useful for grep or outputting to a file.
|
||||
#[structopt(short, long)]
|
||||
pub quiet: bool,
|
||||
pub greppable: bool,
|
||||
|
||||
/// Accessible mode. Turns off features which negatively affect screen readers.
|
||||
#[structopt(long)]
|
||||
@@ -110,8 +112,13 @@ pub struct Opts {
|
||||
/// For things like --script '(safe and vuln)' enclose it in quotations marks \"'(safe and vuln)'\"")
|
||||
#[structopt(last = true)]
|
||||
pub command: Vec<String>,
|
||||
|
||||
/// Use the top 1000 ports.
|
||||
#[structopt(long)]
|
||||
pub top: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Opts {
|
||||
pub fn read() -> Self {
|
||||
let mut opts = Opts::from_args();
|
||||
@@ -146,15 +153,7 @@ impl Opts {
|
||||
}
|
||||
}
|
||||
|
||||
merge_required!(
|
||||
ips_or_hosts,
|
||||
quiet,
|
||||
accessible,
|
||||
batch_size,
|
||||
timeout,
|
||||
scan_order,
|
||||
command
|
||||
);
|
||||
merge_required!(addresses, greppable, accessible, batch_size, timeout, scan_order, command);
|
||||
}
|
||||
|
||||
fn merge_optional(&mut self, config: &Config) {
|
||||
@@ -168,19 +167,31 @@ impl Opts {
|
||||
}
|
||||
}
|
||||
|
||||
merge_optional!(ports, range, ulimit);
|
||||
// Only use top ports when the user asks for them
|
||||
if self.top {
|
||||
if config.ports.is_some() {
|
||||
let mut ports: Vec<u16> = Vec::with_capacity(config.ports.clone().unwrap().len());
|
||||
for entry in config.ports.clone().unwrap().keys() {
|
||||
ports.push(entry.parse().unwrap())
|
||||
}
|
||||
self.ports = Some(ports);
|
||||
}
|
||||
}
|
||||
|
||||
merge_optional!(range, ulimit);
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct used to deserialize the options specified within our config file.
|
||||
/// These will be further merged with our command line arguments in order to
|
||||
/// generate the final Opts struct.
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Config {
|
||||
ips_or_hosts: Option<Vec<String>>,
|
||||
ports: Option<Vec<u16>>,
|
||||
addresses: Option<Vec<String>>,
|
||||
ports: Option<HashMap<String, u16>>,
|
||||
range: Option<PortRange>,
|
||||
quiet: Option<bool>,
|
||||
greppable: Option<bool>,
|
||||
accessible: Option<bool>,
|
||||
batch_size: Option<u16>,
|
||||
timeout: Option<u32>,
|
||||
@@ -190,35 +201,34 @@ pub struct Config {
|
||||
command: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Config {
|
||||
/// Reads the configuration file with TOML format and parses it into a
|
||||
/// Config struct.
|
||||
///
|
||||
/// # 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"
|
||||
///
|
||||
pub fn read() -> Self {
|
||||
let path = match dirs::home_dir() {
|
||||
Some(mut path) => {
|
||||
path.push(".rustscan.toml");
|
||||
path
|
||||
}
|
||||
let mut home_dir = match dirs::home_dir() {
|
||||
Some(dir) => dir,
|
||||
None => panic!("Could not infer config file path."),
|
||||
};
|
||||
home_dir.push(".rustscan.toml");
|
||||
|
||||
let contents = match fs::read_to_string(&path) {
|
||||
Ok(content) => content,
|
||||
Err(_) => {
|
||||
println!("Could not find configation file at {:?}", &path);
|
||||
String::new()
|
||||
let mut content = String::new();
|
||||
if home_dir.exists() {
|
||||
content = match fs::read_to_string(home_dir) {
|
||||
Ok(content) => content,
|
||||
Err(_) => String::new(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let config: Config = match toml::from_str(&contents) {
|
||||
let config: Config = match toml::from_str(&content) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
println!("Found {} in configuration file.\nAborting scan.\n", e);
|
||||
@@ -233,42 +243,53 @@ impl Config {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Config, Opts, PortRange, ScanOrder};
|
||||
impl Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
addresses: Some(vec!["127.0.0.1".to_owned()]),
|
||||
ports: None,
|
||||
range: None,
|
||||
greppable: Some(true),
|
||||
batch_size: Some(25_000),
|
||||
timeout: Some(1_000),
|
||||
ulimit: None,
|
||||
no_nmap: Some(false),
|
||||
command: Some(vec!["-A".to_owned()]),
|
||||
accessible: Some(true),
|
||||
scan_order: Some(ScanOrder::Random),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Opts {
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
addresses: vec![],
|
||||
ports: None,
|
||||
range: None,
|
||||
greppable: true,
|
||||
batch_size: 0,
|
||||
timeout: 0,
|
||||
ulimit: None,
|
||||
command: vec![],
|
||||
accessible: false,
|
||||
no_nmap: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: true,
|
||||
top: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opts_no_merge_when_config_is_ignored() {
|
||||
let mut opts = Opts {
|
||||
ips_or_hosts: vec![],
|
||||
ports: None,
|
||||
range: None,
|
||||
quiet: false,
|
||||
batch_size: 0,
|
||||
timeout: 0,
|
||||
ulimit: None,
|
||||
command: vec![],
|
||||
accessible: false,
|
||||
no_nmap: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: true,
|
||||
};
|
||||
|
||||
let config = Config {
|
||||
ips_or_hosts: Some(vec!["127.0.0.1".to_owned()]),
|
||||
ports: None,
|
||||
range: None,
|
||||
quiet: Some(true),
|
||||
batch_size: Some(25_000),
|
||||
timeout: Some(1_000),
|
||||
ulimit: None,
|
||||
no_nmap: Some(false),
|
||||
command: Some(vec!["-A".to_owned()]),
|
||||
accessible: Some(true),
|
||||
scan_order: Some(ScanOrder::Random),
|
||||
};
|
||||
let mut opts = Opts::default();
|
||||
let config = Config::default();
|
||||
|
||||
opts.merge(&config);
|
||||
|
||||
assert_eq!(opts.ips_or_hosts, vec![] as Vec<String>);
|
||||
assert_eq!(opts.quiet, false);
|
||||
assert_eq!(opts.addresses, vec![] as Vec<String>);
|
||||
assert_eq!(opts.greppable, true);
|
||||
assert_eq!(opts.accessible, false);
|
||||
assert_eq!(opts.timeout, 0);
|
||||
assert_eq!(opts.command, vec![] as Vec<String>);
|
||||
@@ -277,39 +298,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn opts_merge_required_arguments() {
|
||||
let mut opts = Opts {
|
||||
ips_or_hosts: vec![],
|
||||
ports: None,
|
||||
range: None,
|
||||
quiet: false,
|
||||
batch_size: 0,
|
||||
timeout: 0,
|
||||
ulimit: None,
|
||||
command: vec![],
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
|
||||
let config = Config {
|
||||
ips_or_hosts: Some(vec!["127.0.0.1".to_owned()]),
|
||||
ports: None,
|
||||
no_nmap: Some(false),
|
||||
range: None,
|
||||
quiet: Some(true),
|
||||
batch_size: Some(25_000),
|
||||
timeout: Some(1_000),
|
||||
ulimit: None,
|
||||
command: Some(vec!["-A".to_owned()]),
|
||||
accessible: Some(true),
|
||||
scan_order: Some(ScanOrder::Random),
|
||||
};
|
||||
let mut opts = Opts::default();
|
||||
let config = Config::default();
|
||||
|
||||
opts.merge_required(&config);
|
||||
|
||||
assert_eq!(opts.ips_or_hosts, config.ips_or_hosts.unwrap());
|
||||
assert_eq!(opts.quiet, config.quiet.unwrap());
|
||||
assert_eq!(opts.addresses, config.addresses.unwrap());
|
||||
assert_eq!(opts.greppable, config.greppable.unwrap());
|
||||
assert_eq!(opts.timeout, config.timeout.unwrap());
|
||||
assert_eq!(opts.command, config.command.unwrap());
|
||||
assert_eq!(opts.accessible, config.accessible.unwrap());
|
||||
@@ -318,41 +313,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn opts_merge_optional_arguments() {
|
||||
let mut opts = Opts {
|
||||
ips_or_hosts: vec![],
|
||||
ports: None,
|
||||
range: None,
|
||||
quiet: false,
|
||||
batch_size: 0,
|
||||
timeout: 0,
|
||||
ulimit: None,
|
||||
command: vec![],
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
|
||||
let config = Config {
|
||||
ips_or_hosts: None,
|
||||
ports: Some(vec![80, 403]),
|
||||
range: Some(PortRange {
|
||||
start: 1,
|
||||
end: 1_000,
|
||||
}),
|
||||
quiet: None,
|
||||
batch_size: None,
|
||||
timeout: None,
|
||||
no_nmap: Some(false),
|
||||
ulimit: Some(1_000),
|
||||
command: None,
|
||||
accessible: None,
|
||||
scan_order: None,
|
||||
};
|
||||
let mut opts = Opts::default();
|
||||
let mut config = Config::default();
|
||||
config.range = Some(PortRange {
|
||||
start: 1,
|
||||
end: 1_000,
|
||||
});
|
||||
config.ulimit = Some(1_000);
|
||||
|
||||
opts.merge_optional(&config);
|
||||
|
||||
assert_eq!(opts.ports, config.ports);
|
||||
assert_eq!(opts.range, config.range);
|
||||
assert_eq!(opts.ulimit, config.ulimit);
|
||||
}
|
||||
|
||||
+158
-177
@@ -11,13 +11,19 @@ use scanner::Scanner;
|
||||
mod port_strategy;
|
||||
use port_strategy::PortStrategy;
|
||||
|
||||
mod benchmark;
|
||||
use benchmark::{Benchmark, NamedTimer};
|
||||
|
||||
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::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::process::Command;
|
||||
use std::str::FromStr;
|
||||
@@ -39,22 +45,27 @@ extern crate log;
|
||||
/// If you're looking for the actual scanning, check out the module Scanner
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let mut benchmarks = Benchmark::init();
|
||||
let mut rustscan_bench = NamedTimer::start("RustScan");
|
||||
|
||||
let mut opts: Opts = Opts::read();
|
||||
let config = Config::read();
|
||||
opts.merge(&config);
|
||||
dbg!(&opts);
|
||||
|
||||
info!("Main() `opts` arguments are {:?}", opts);
|
||||
debug!("Main() `opts` arguments are {:?}", opts);
|
||||
|
||||
if !opts.quiet && !opts.accessible {
|
||||
print_opening();
|
||||
if !opts.greppable && !opts.accessible {
|
||||
print_opening(&opts);
|
||||
}
|
||||
|
||||
let ips: Vec<IpAddr> = parse_ips(&opts);
|
||||
let ips: Vec<IpAddr> = parse_addresses(&opts);
|
||||
|
||||
if ips.is_empty() {
|
||||
warning!("No IPs could be resolved, aborting scan.", false);
|
||||
warning!(
|
||||
"No IPs could be resolved, aborting scan.",
|
||||
opts.greppable,
|
||||
opts.accessible
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
@@ -65,11 +76,17 @@ fn main() {
|
||||
&ips,
|
||||
batch_size,
|
||||
Duration::from_millis(opts.timeout.into()),
|
||||
opts.quiet,
|
||||
opts.greppable,
|
||||
PortStrategy::pick(opts.range, opts.ports, opts.scan_order),
|
||||
opts.accessible,
|
||||
);
|
||||
debug!("Scanner finished building: {:?}", scanner);
|
||||
|
||||
let mut portscan_bench = NamedTimer::start("Portscan");
|
||||
let scan_result = block_on(scanner.run());
|
||||
portscan_bench.end();
|
||||
benchmarks.push(portscan_bench);
|
||||
|
||||
let mut ports_per_ip = HashMap::new();
|
||||
|
||||
for socket in scan_result {
|
||||
@@ -87,40 +104,42 @@ fn main() {
|
||||
// If we got here it means the IP was not found within the HashMap, this
|
||||
// means the scan couldn't find any open ports for it.
|
||||
|
||||
let x = format!("{} Looks like I didn't find any open ports for {:?}. This is usually caused by a high batch size.
|
||||
\n*I used {} batch size, consider lowering to {} with {} or a comfortable number for your system.
|
||||
let x = format!("Looks like I didn't find any open ports for {:?}. This is usually caused by a high batch size.
|
||||
\n*I used {} batch size, consider lowering it with {} or a comfortable number for your system.
|
||||
\n Alternatively, increase the timeout if your ping is high. Rustscan -t 2000 for 2000 milliseconds (2s) timeout.\n",
|
||||
"ERROR",
|
||||
ip,
|
||||
opts.batch_size,
|
||||
(opts.batch_size / 2).to_string(),
|
||||
"'rustscan -b <batch_size> <ip address>'");
|
||||
warning!(x, opts.quiet);
|
||||
warning!(x, opts.greppable, opts.accessible);
|
||||
}
|
||||
|
||||
let mut nmap_bench = NamedTimer::start("Nmap");
|
||||
for (ip, ports) in ports_per_ip.iter_mut() {
|
||||
let nmap_str_ports: Vec<String> = ports.into_iter().map(|port| port.to_string()).collect();
|
||||
|
||||
detail!("Starting Nmap", opts.quiet);
|
||||
|
||||
// nmap port style is 80,443. Comma separated with no spaces.
|
||||
let ports_str = nmap_str_ports.join(",");
|
||||
|
||||
// if quiet mode is on nmap should not be spawned
|
||||
if opts.quiet {
|
||||
println!("{}", ports_str);
|
||||
if opts.greppable || opts.no_nmap {
|
||||
println!("{} -> [{}]", &ip, ports_str);
|
||||
continue;
|
||||
}
|
||||
detail!("Starting Nmap", opts.greppable, opts.accessible);
|
||||
|
||||
let addr = 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, ip.is_ipv6());
|
||||
|
||||
output!(format!(
|
||||
"The Nmap command to be run is nmap {}\n",
|
||||
&nmap_args.join(" ")
|
||||
));
|
||||
output!(
|
||||
format!(
|
||||
"The Nmap command to be run is nmap {}\n",
|
||||
&nmap_args.join(" ")
|
||||
),
|
||||
opts.greppable.clone(),
|
||||
opts.accessible.clone()
|
||||
);
|
||||
|
||||
// Runs the nmap command and spawns it as a process.
|
||||
let mut child = Command::new("nmap")
|
||||
@@ -130,11 +149,19 @@ fn main() {
|
||||
|
||||
child.wait().expect("failed to wait on nmap process");
|
||||
}
|
||||
|
||||
// To use the runtime benchmark, run the process as: RUST_LOG=info ./rustscan
|
||||
nmap_bench.end();
|
||||
benchmarks.push(nmap_bench);
|
||||
rustscan_bench.end();
|
||||
benchmarks.push(rustscan_bench);
|
||||
debug!("Benchmarks raw {:?}", benchmarks);
|
||||
info!("{}", benchmarks.summary());
|
||||
}
|
||||
|
||||
/// Prints the opening title of RustScan
|
||||
fn print_opening() {
|
||||
info!("Printing opening");
|
||||
fn print_opening(opts: &Opts) {
|
||||
debug!("Printing opening");
|
||||
let s = r#".----. .-. .-. .----..---. .----. .---. .--. .-. .-.
|
||||
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
|
||||
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
|
||||
@@ -148,19 +175,17 @@ Faster Nmap scanning with Rust."#;
|
||||
println!("{}", info.gradient(Color::Yellow).bold());
|
||||
funny_opening!();
|
||||
|
||||
let config_path = match dirs::config_dir() {
|
||||
Some(mut path) => {
|
||||
path.push("rustscan");
|
||||
path.push("config.toml");
|
||||
path
|
||||
}
|
||||
None => panic!("Couldn't find config dir."),
|
||||
let mut home_dir = match dirs::home_dir() {
|
||||
Some(dir) => dir,
|
||||
None => panic!("Could not infer config file path."),
|
||||
};
|
||||
home_dir.push(".rustscan.toml");
|
||||
|
||||
detail!(format!(
|
||||
"{} {:?}",
|
||||
"The config file is expected to be at", config_path
|
||||
));
|
||||
detail!(
|
||||
format!("The config file is expected to be at {:?}", home_dir),
|
||||
opts.greppable,
|
||||
opts.accessible
|
||||
);
|
||||
}
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
fn build_nmap_arguments<'a>(
|
||||
@@ -183,18 +208,42 @@ fn build_nmap_arguments<'a>(
|
||||
arguments
|
||||
}
|
||||
|
||||
fn parse_ips(opts: &Opts) -> Vec<IpAddr> {
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
/// Parses an input file of IPs and uses those
|
||||
fn read_ips_from_file(ips: String) -> Result<Vec<std::net::IpAddr>, std::io::Error> {
|
||||
// if we cannot open it as a file, it is not a file so move on
|
||||
let file = File::open(ips)?;
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
let mut ips: Vec<std::net::IpAddr> = Vec::new();
|
||||
|
||||
for str_ip in reader.lines() {
|
||||
match IpAddr::from_str(&str_ip.unwrap()) {
|
||||
Ok(x) => ips.push(x),
|
||||
Err(y) => panic!("File does not contain valid IP address. Error at {}", y),
|
||||
}
|
||||
}
|
||||
Ok(ips)
|
||||
}
|
||||
|
||||
fn parse_addresses(opts: &Opts) -> Vec<IpAddr> {
|
||||
let mut ips: Vec<IpAddr> = 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()),
|
||||
_ => {
|
||||
let failed_to_resolve = format!("Host {:?} could not be resolved.", ip_or_host);
|
||||
warning!(failed_to_resolve, opts.quiet);
|
||||
}
|
||||
_ => match read_ips_from_file(ip_or_host.to_owned()) {
|
||||
Ok(x) => ips.extend(x),
|
||||
_ => {
|
||||
warning!(
|
||||
format!("Host {:?} could not be resolved.", ip_or_host),
|
||||
opts.greppable,
|
||||
opts.accessible
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -210,10 +259,17 @@ fn adjust_ulimit_size(opts: &Opts) -> rlimit::rlim {
|
||||
Ok(_) => {
|
||||
detail!(
|
||||
format!("Automatically increasing ulimit value to {}.", limit),
|
||||
opts.quiet
|
||||
opts.greppable,
|
||||
opts.accessible
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
warning!(
|
||||
"ERROR. Failed to set ulimit value.",
|
||||
opts.greppable,
|
||||
opts.accessible
|
||||
);
|
||||
}
|
||||
Err(_) => println!("{}", "ERROR. Failed to set ulimit value."),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +284,7 @@ fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u16 {
|
||||
// Adjust the batch size when the ulimit value is lower than the desired batch size
|
||||
if ulimit < batch_size {
|
||||
warning!("File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers",
|
||||
opts.quiet
|
||||
opts.greppable, opts.accessible
|
||||
);
|
||||
|
||||
// When the OS supports high file limits like 8000, but the user
|
||||
@@ -238,7 +294,7 @@ 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'. ");
|
||||
warning!("Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. ", opts.greppable, opts.accessible);
|
||||
info!("Halving batch_size because ulimit is smaller than average batch size");
|
||||
batch_size = ulimit / 2
|
||||
} else if ulimit > DEFAULT_FILE_DESCRIPTORS_LIMIT {
|
||||
@@ -251,10 +307,8 @@ fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u16 {
|
||||
// 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()) {
|
||||
detail!(format!(
|
||||
"File limit higher than batch size. Can increase speed by increasing batch size '-b {}'.",
|
||||
ulimit - 100
|
||||
), opts.quiet);
|
||||
detail!(format!("File limit higher than batch size. Can increase speed by increasing batch size '-b {}'.", ulimit - 100),
|
||||
opts.greppable, opts.accessible);
|
||||
}
|
||||
|
||||
batch_size as u16
|
||||
@@ -262,45 +316,22 @@ 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};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
let mut opts = Opts::default();
|
||||
opts.batch_size = 50_000;
|
||||
let batch_size = infer_batch_size(&opts, 120);
|
||||
|
||||
assert!(batch_size < 50_000);
|
||||
assert!(batch_size < opts.batch_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
let mut opts = Opts::default();
|
||||
opts.batch_size = 50_000;
|
||||
let batch_size = infer_batch_size(&opts, 9_000);
|
||||
|
||||
assert!(batch_size == 3_000);
|
||||
@@ -309,20 +340,8 @@ mod tests {
|
||||
fn batch_size_equals_ulimit_lowered() {
|
||||
// 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()],
|
||||
ports: None,
|
||||
range: None,
|
||||
quiet: true,
|
||||
batch_size: 50_000,
|
||||
timeout: 1_000,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
let mut opts = Opts::default();
|
||||
opts.batch_size = 50_000;
|
||||
let batch_size = infer_batch_size(&opts, 5_000);
|
||||
|
||||
assert!(batch_size == 4_900);
|
||||
@@ -330,112 +349,74 @@ mod tests {
|
||||
#[test]
|
||||
fn batch_size_adjusted_2000() {
|
||||
// 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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
let mut opts = Opts::default();
|
||||
opts.batch_size = 50_000;
|
||||
opts.ulimit = Some(2_000);
|
||||
let batch_size = adjust_ulimit_size(&opts);
|
||||
|
||||
assert!(batch_size == 2_000);
|
||||
}
|
||||
#[test]
|
||||
fn test_print_opening_no_panic() {
|
||||
let mut opts = Opts::default();
|
||||
opts.ulimit = Some(2_000);
|
||||
// print opening should not panic
|
||||
print_opening();
|
||||
print_opening(&opts);
|
||||
assert!(1 == 1);
|
||||
}
|
||||
#[test]
|
||||
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,
|
||||
ulimit: None,
|
||||
command: Vec::new(),
|
||||
accessible: true,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
fn test_high_ulimit_no_greppable_mode() {
|
||||
let mut opts = Opts::default();
|
||||
opts.batch_size = 10;
|
||||
opts.greppable = false;
|
||||
|
||||
infer_batch_size(&opts, 1_000_000);
|
||||
let batch_size = infer_batch_size(&opts, 1_000_000);
|
||||
|
||||
assert!(1 == 1);
|
||||
assert!(batch_size == opts.batch_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
let ips = parse_ips(&opts);
|
||||
fn parse_correct_addresses() {
|
||||
let mut opts = Opts::default();
|
||||
opts.addresses = vec!["127.0.0.1".to_owned(), "192.168.0.0/30".to_owned()];
|
||||
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() {
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
let ips = parse_ips(&opts);
|
||||
fn parse_correct_host_addresses() {
|
||||
let mut opts = Opts::default();
|
||||
opts.addresses = vec!["google.com".to_owned()];
|
||||
let ips = parse_addresses(&opts);
|
||||
|
||||
assert_eq!(1, ips.len());
|
||||
assert_eq!(ips.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
no_nmap: false,
|
||||
};
|
||||
let ips = parse_ips(&opts);
|
||||
fn parse_correct_and_incorrect_addresses() {
|
||||
let mut opts = Opts::default();
|
||||
opts.addresses = vec!["127.0.0.1".to_owned(), "im_wrong".to_owned()];
|
||||
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 mut opts = Opts::default();
|
||||
opts.addresses = vec!["im_wrong".to_owned(), "300.10.1.1".to_owned()];
|
||||
let ips = parse_addresses(&opts);
|
||||
|
||||
assert_eq!(ips.is_empty(), true);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use range_iterator::RangeIterator;
|
||||
///
|
||||
/// Right now all these options involve ranges, but in the future
|
||||
/// it will also contain custom lists of ports.
|
||||
#[derive(Debug)]
|
||||
pub enum PortStrategy {
|
||||
Manual(Vec<u16>),
|
||||
Serial(SerialRange),
|
||||
@@ -58,6 +59,7 @@ trait RangeOrder {
|
||||
|
||||
/// As the name implies SerialRange will always generate a vector in
|
||||
/// ascending order.
|
||||
#[derive(Debug)]
|
||||
pub struct SerialRange {
|
||||
start: u16,
|
||||
end: u16,
|
||||
@@ -71,6 +73,7 @@ impl RangeOrder for SerialRange {
|
||||
|
||||
/// As the name implies RandomRange will always generate a vector with
|
||||
/// a random order. This vector is built following the LCG algorithm.
|
||||
#[derive(Debug)]
|
||||
pub struct RandomRange {
|
||||
start: u16,
|
||||
end: u16,
|
||||
|
||||
@@ -1,476 +0,0 @@
|
||||
extern crate shell_words;
|
||||
|
||||
mod tui;
|
||||
|
||||
mod input;
|
||||
use input::{Config, Opts, PortRange, ScanOrder};
|
||||
|
||||
mod scanner;
|
||||
use scanner::Scanner;
|
||||
|
||||
mod port_strategy;
|
||||
use port_strategy::PortStrategy;
|
||||
|
||||
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;
|
||||
extern crate dirs;
|
||||
|
||||
// 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;
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
/// Faster Nmap scanning with Rust
|
||||
/// If you're looking for the actual scanning, check out the module Scanner
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let mut opts: Opts = Opts::read();
|
||||
let config = Config::read();
|
||||
opts.merge(&config);
|
||||
dbg!(&opts);
|
||||
|
||||
info!("Main() `opts` arguments are {:?}", opts);
|
||||
|
||||
if !opts.quiet && !opts.accessible {
|
||||
print_opening();
|
||||
}
|
||||
|
||||
let ips: Vec<IpAddr> = parse_ips(&opts);
|
||||
|
||||
if ips.is_empty() {
|
||||
warning!("No IPs could be resolved, aborting scan.", false);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let ulimit: rlimit::rlim = adjust_ulimit_size(&opts);
|
||||
let batch_size: u16 = infer_batch_size(&opts, ulimit);
|
||||
|
||||
let scanner = Scanner::new(
|
||||
&ips,
|
||||
batch_size,
|
||||
Duration::from_millis(opts.timeout.into()),
|
||||
opts.quiet,
|
||||
PortStrategy::pick(opts.range, opts.ports, opts.scan_order),
|
||||
);
|
||||
|
||||
let scan_result = block_on(scanner.run());
|
||||
let mut ports_per_ip = HashMap::new();
|
||||
|
||||
for socket in scan_result {
|
||||
ports_per_ip
|
||||
.entry(socket.ip())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(socket.port());
|
||||
}
|
||||
|
||||
for ip in ips {
|
||||
if ports_per_ip.contains_key(&ip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we got here it means the IP was not found within the HashMap, this
|
||||
// means the scan couldn't find any open ports for it.
|
||||
|
||||
let x = format!("{} Looks like I didn't find any open ports for {:?}. This is usually caused by a high batch size.
|
||||
\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 milliseconds (2s) timeout.\n",
|
||||
"ERROR",
|
||||
ip,
|
||||
opts.batch_size,
|
||||
(opts.batch_size / 2).to_string(),
|
||||
"'rustscan -b <batch_size> <ip address>'");
|
||||
warning!(x, opts.quiet);
|
||||
}
|
||||
|
||||
for (ip, ports) in ports_per_ip.iter_mut() {
|
||||
let nmap_str_ports: Vec<String> = ports.into_iter().map(|port| port.to_string()).collect();
|
||||
|
||||
// nmap port style is 80,443. Comma separated with no spaces.
|
||||
let ports_str = nmap_str_ports.join(",");
|
||||
|
||||
// if quiet mode is on nmap should not be spawned
|
||||
if opts.quiet {
|
||||
println!("{}", ports_str);
|
||||
continue;
|
||||
} else if opts.no_nmap {
|
||||
continue;
|
||||
} else {
|
||||
detail!("Starting Nmap", opts.quiet);
|
||||
}
|
||||
|
||||
let addr = 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, ip.is_ipv6());
|
||||
|
||||
output!(format!(
|
||||
"The Nmap command to be run is nmap {}\n",
|
||||
&nmap_args.join(" ")
|
||||
));
|
||||
|
||||
// Runs the nmap command and spawns it as a process.
|
||||
let mut child = Command::new("nmap")
|
||||
.args(&nmap_args)
|
||||
.spawn()
|
||||
.expect("failed to execute nmap process");
|
||||
|
||||
child.wait().expect("failed to wait on nmap process");
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the opening title of RustScan
|
||||
fn print_opening() {
|
||||
info!("Printing opening");
|
||||
let s = r#".----. .-. .-. .----..---. .----. .---. .--. .-. .-.
|
||||
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
|
||||
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
|
||||
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
|
||||
Faster Nmap scanning with Rust."#;
|
||||
println!("{}", s.gradient(Color::Green).bold());
|
||||
let info = r#"________________________________________
|
||||
: https://discord.gg/GFrQsGy :
|
||||
: https://github.com/RustScan/RustScan :
|
||||
--------------------------------------"#;
|
||||
println!("{}", info.gradient(Color::Yellow).bold());
|
||||
funny_opening!();
|
||||
|
||||
let config_path = match dirs::config_dir() {
|
||||
Some(mut path) => {
|
||||
path.push("rustscan");
|
||||
path.push("config.toml");
|
||||
path
|
||||
}
|
||||
None => panic!("Couldn't find config dir."),
|
||||
};
|
||||
|
||||
detail!(format!(
|
||||
"{} {:?}",
|
||||
"The config file is expected to be at", config_path
|
||||
));
|
||||
}
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
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("-vvv");
|
||||
|
||||
if is_ipv6 {
|
||||
arguments.push("-6");
|
||||
}
|
||||
|
||||
arguments.push("-p");
|
||||
arguments.push(ports);
|
||||
arguments.push(addr);
|
||||
|
||||
arguments
|
||||
}
|
||||
|
||||
fn parse_ips(opts: &Opts) -> Vec<IpAddr> {
|
||||
let mut ips: Vec<IpAddr> = Vec::new();
|
||||
|
||||
for ip_or_host in &opts.ips_or_hosts {
|
||||
match IpAddr::from_str(ip_or_host) {
|
||||
Ok(ip) => ips.push(ip),
|
||||
_ => match format!("{}:{}", &ip_or_host, 80).to_socket_addrs() {
|
||||
Ok(mut iter) => ips.push(iter.nth(0).unwrap().ip()),
|
||||
_ => {
|
||||
let failed_to_resolve = format!("Host {:?} could not be resolved.", ip_or_host);
|
||||
warning!(failed_to_resolve, opts.quiet);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
ips
|
||||
}
|
||||
|
||||
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(_) => {
|
||||
detail!(
|
||||
format!("Automatically increasing ulimit value to {}.", limit),
|
||||
opts.quiet
|
||||
);
|
||||
}
|
||||
Err(_) => println!("{}", "ERROR. Failed to set ulimit value."),
|
||||
}
|
||||
}
|
||||
|
||||
let (rlim, _) = getrlimit(Resource::NOFILE).unwrap();
|
||||
|
||||
rlim
|
||||
}
|
||||
|
||||
fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u16 {
|
||||
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 {
|
||||
warning!("File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers",
|
||||
opts.quiet
|
||||
);
|
||||
|
||||
// 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 < AVERAGE_BATCH_SIZE {
|
||||
// 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'. ");
|
||||
info!("Halving batch_size because ulimit is smaller than average batch size");
|
||||
batch_size = ulimit / 2
|
||||
} else if ulimit > DEFAULT_FILE_DESCRIPTORS_LIMIT {
|
||||
info!("Batch size is now average batch size");
|
||||
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()) {
|
||||
detail!(format!(
|
||||
"File limit higher than batch size. Can increase speed by increasing batch size '-b {}'.",
|
||||
ulimit - 100
|
||||
), opts.quiet);
|
||||
}
|
||||
|
||||
batch_size as u16
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{adjust_ulimit_size, infer_batch_size, parse_ips, print_opening, Opts, ScanOrder};
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
ignore_config: false,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
let batch_size = infer_batch_size(&opts, 120);
|
||||
|
||||
assert!(batch_size < 50_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
ignore_config: false,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
let batch_size = infer_batch_size(&opts, 9_000);
|
||||
|
||||
assert!(batch_size == 3_000);
|
||||
}
|
||||
#[test]
|
||||
fn batch_size_equals_ulimit_lowered() {
|
||||
// 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()],
|
||||
ports: None,
|
||||
range: None,
|
||||
quiet: true,
|
||||
batch_size: 50_000,
|
||||
timeout: 1_000,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
no_nmap: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
ignore_config: false,
|
||||
no_config: false,
|
||||
};
|
||||
let batch_size = infer_batch_size(&opts, 5_000);
|
||||
|
||||
assert!(batch_size == 4_900);
|
||||
}
|
||||
#[test]
|
||||
fn batch_size_adjusted_2000() {
|
||||
// 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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
ignore_config: false,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
let batch_size = adjust_ulimit_size(&opts);
|
||||
|
||||
assert!(batch_size == 2_000);
|
||||
}
|
||||
#[test]
|
||||
fn test_print_opening_no_panic() {
|
||||
// print opening should not panic
|
||||
print_opening();
|
||||
assert!(1 == 1);
|
||||
}
|
||||
#[test]
|
||||
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,
|
||||
ulimit: None,
|
||||
command: Vec::new(),
|
||||
accessible: true,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
ignore_config: false,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
|
||||
infer_batch_size(&opts, 1_000_000);
|
||||
|
||||
assert!(1 == 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
ignore_config: false,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
let ips = parse_ips(&opts);
|
||||
|
||||
assert_eq!(2, ips.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
ignore_config: false,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
let ips = parse_ips(&opts);
|
||||
|
||||
assert_eq!(1, ips.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
ulimit: Some(2_000),
|
||||
command: Vec::new(),
|
||||
accessible: false,
|
||||
scan_order: ScanOrder::Serial,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
ignore_config: false,
|
||||
};
|
||||
let ips = parse_ips(&opts);
|
||||
ignore_config: false,
|
||||
no_nmap: false,
|
||||
no_config: false,
|
||||
};
|
||||
let ips = parse_ips(&opts);
|
||||
|
||||
assert_eq!(0, ips.len());
|
||||
}
|
||||
}
|
||||
+54
-32
@@ -1,14 +1,17 @@
|
||||
use super::PortStrategy;
|
||||
|
||||
mod socket_iterator;
|
||||
use socket_iterator::SocketIterator;
|
||||
|
||||
use async_std::io;
|
||||
use async_std::net::TcpStream;
|
||||
use async_std::prelude::*;
|
||||
use colored::*;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
io::ErrorKind,
|
||||
net::{IpAddr, Shutdown, SocketAddr},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
/// The class for the scanner
|
||||
@@ -18,12 +21,14 @@ use std::{
|
||||
/// 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.
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
#[derive(Debug)]
|
||||
pub struct Scanner {
|
||||
ips: Vec<IpAddr>,
|
||||
batch_size: u16,
|
||||
timeout: Duration,
|
||||
quiet: bool,
|
||||
greppable: bool,
|
||||
port_strategy: PortStrategy,
|
||||
accessible: bool,
|
||||
}
|
||||
|
||||
impl Scanner {
|
||||
@@ -31,15 +36,17 @@ impl Scanner {
|
||||
ips: &[IpAddr],
|
||||
batch_size: u16,
|
||||
timeout: Duration,
|
||||
quiet: bool,
|
||||
greppable: bool,
|
||||
port_strategy: PortStrategy,
|
||||
accessible: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
batch_size,
|
||||
timeout,
|
||||
quiet,
|
||||
greppable,
|
||||
port_strategy,
|
||||
ips: ips.iter().map(|ip| ip.to_owned()).collect(),
|
||||
accessible,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,35 +55,35 @@ impl Scanner {
|
||||
/// Returns all open ports as Vec<u16>
|
||||
pub async fn run(&self) -> Vec<SocketAddr> {
|
||||
let ports: Vec<u16> = self.port_strategy.order();
|
||||
let batch_per_ip: usize = self.batch_size as usize / self.ips.len();
|
||||
let mut socket_iterator: SocketIterator = SocketIterator::new(&self.ips, &ports);
|
||||
let mut open_sockets: Vec<SocketAddr> = Vec::new();
|
||||
|
||||
for batch in ports.chunks(batch_per_ip) {
|
||||
let mut sockets = self.scan_ports(batch).await;
|
||||
open_sockets.append(&mut sockets);
|
||||
}
|
||||
|
||||
open_sockets
|
||||
}
|
||||
|
||||
/// Given a slice of sockets, scan them all.
|
||||
/// Returns a vector of open sockets.
|
||||
async fn scan_ports(&self, ports: &[u16]) -> Vec<SocketAddr> {
|
||||
let mut ftrs = FuturesUnordered::new();
|
||||
for port in ports {
|
||||
for ip in &self.ips {
|
||||
ftrs.push(self.scan_socket(SocketAddr::new(*ip, *port)));
|
||||
|
||||
for _ in 0..self.batch_size {
|
||||
if let Some(socket) = socket_iterator.next() {
|
||||
ftrs.push(self.scan_socket(socket));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut open_sockets: Vec<SocketAddr> = Vec::new();
|
||||
debug!("Start scanning sockets. \nBatch size {}\nNumber of ip-s {}\nNumber of ports {}\nTargets all together {} ",
|
||||
self.batch_size,
|
||||
self.ips.len(),
|
||||
&ports.len(),
|
||||
(self.ips.len() * &ports.len()));
|
||||
|
||||
while let Some(result) = ftrs.next().await {
|
||||
if let Some(socket) = socket_iterator.next() {
|
||||
ftrs.push(self.scan_socket(socket));
|
||||
}
|
||||
|
||||
match result {
|
||||
Ok(socket) => open_sockets.push(socket),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Open Sockets found: {:?}", &open_sockets);
|
||||
open_sockets
|
||||
}
|
||||
|
||||
@@ -95,20 +102,35 @@ impl Scanner {
|
||||
async fn scan_socket(&self, socket: SocketAddr) -> io::Result<SocketAddr> {
|
||||
match self.connect(socket).await {
|
||||
Ok(x) => {
|
||||
// match stream_result.shutdown(Shutdown::Both)
|
||||
info!("Shutting down stream");
|
||||
debug!(
|
||||
"Connection was successful, shutting down stream {}",
|
||||
&socket
|
||||
);
|
||||
match x.shutdown(Shutdown::Both) {
|
||||
Err(e) => debug!("Shutdown stream error {}", &e),
|
||||
_ => {}
|
||||
}
|
||||
if !self.quiet {
|
||||
println!("Open {}", socket.to_string().purple());
|
||||
if !self.greppable {
|
||||
if self.accessible {
|
||||
println!("Open {}", socket.to_string());
|
||||
} else {
|
||||
println!("Open {}", socket.to_string().purple());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(socket)
|
||||
}
|
||||
Err(e) => match e.kind() {
|
||||
ErrorKind::Other => {
|
||||
panic!("Too many open files. Please reduce batch size. The default is 5000. Try -b 2500.");
|
||||
if e.to_string().contains("No route to host")
|
||||
|| e.to_string().contains("Network is unreachable")
|
||||
{
|
||||
debug!("Socket connect error: {} {}", &e.to_string(), &socket);
|
||||
Err(io::Error::new(io::ErrorKind::Other, e.to_string()))
|
||||
} else {
|
||||
debug!("Socket connect error: {} {}", &e.to_string(), &socket);
|
||||
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())),
|
||||
},
|
||||
@@ -152,7 +174,7 @@ mod tests {
|
||||
end: 1_000,
|
||||
};
|
||||
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy, true);
|
||||
block_on(scanner.run());
|
||||
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
|
||||
assert_eq!(1, 1);
|
||||
@@ -166,7 +188,7 @@ mod tests {
|
||||
end: 1_000,
|
||||
};
|
||||
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy, true);
|
||||
block_on(scanner.run());
|
||||
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
|
||||
assert_eq!(1, 1);
|
||||
@@ -179,7 +201,7 @@ mod tests {
|
||||
end: 1_000,
|
||||
};
|
||||
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy, true);
|
||||
block_on(scanner.run());
|
||||
assert_eq!(1, 1);
|
||||
}
|
||||
@@ -191,7 +213,7 @@ mod tests {
|
||||
end: 445,
|
||||
};
|
||||
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy, true);
|
||||
block_on(scanner.run());
|
||||
assert_eq!(1, 1);
|
||||
}
|
||||
@@ -206,7 +228,7 @@ mod tests {
|
||||
end: 600,
|
||||
};
|
||||
let strategy = PortStrategy::pick(Some(range), None, ScanOrder::Random);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy);
|
||||
let scanner = Scanner::new(&addrs, 10, Duration::from_millis(100), true, strategy, true);
|
||||
block_on(scanner.run());
|
||||
assert_eq!(1, 1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
use itertools::{iproduct, Product};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
|
||||
pub struct SocketIterator<'s> {
|
||||
// product_it is a cartesian product iterator over
|
||||
// the slices of ports and IP addresses.
|
||||
//
|
||||
// The IP/port order is intentionally reversed here since we want
|
||||
// the itertools::iproduct! macro below to generate the pairs with
|
||||
// all the IPs for one port before moving on to the next one
|
||||
// ("hold the port, go through all the IPs, then advance the port...").
|
||||
// See also the comments in the iterator implementation for an example.
|
||||
product_it:
|
||||
Product<Box<std::slice::Iter<'s, u16>>, Box<std::slice::Iter<'s, std::net::IpAddr>>>,
|
||||
}
|
||||
|
||||
/// An iterator that receives a slice of IPs and ports and returns a Socket
|
||||
/// for each IP and port pair until all of these combinations are exhausted.
|
||||
/// The goal of this iterator is to go over every IP and port combination
|
||||
/// wihout generating a big memory footprint. The alternative would be
|
||||
/// generating a vector containing all these combinations.
|
||||
impl<'s> SocketIterator<'s> {
|
||||
pub fn new(ips: &'s [IpAddr], ports: &'s [u16]) -> Self {
|
||||
let ports_it = Box::new(ports.into_iter());
|
||||
let ips_it = Box::new(ips.into_iter());
|
||||
Self {
|
||||
product_it: iproduct!(ports_it, ips_it),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> Iterator for SocketIterator<'s> {
|
||||
type Item = SocketAddr;
|
||||
|
||||
/// Returns a socket based on the combination of one of the provided
|
||||
/// IPs and ports or None when these combinations are exhausted. Every
|
||||
/// IP will have the same port until a port is incremented.
|
||||
///
|
||||
/// let it = SocketIterator::new(&["127.0.0.1", "192.168.0.1"], &[80, 443]);
|
||||
/// it.next(); // 127.0.0.1:80
|
||||
/// it.next(); // 192.168.0.1:80
|
||||
/// it.next(); // 127.0.0.1:443
|
||||
/// it.next(); // 192.168.0.1:443
|
||||
/// it.next(); // None
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.product_it.next() {
|
||||
None => None,
|
||||
Some((port, ip)) => Some(SocketAddr::new(*ip, *port)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::SocketIterator;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
|
||||
#[test]
|
||||
fn goes_through_every_ip_port_combination() {
|
||||
let addrs = vec![
|
||||
"127.0.0.1".parse::<IpAddr>().unwrap(),
|
||||
"192.168.0.1".parse::<IpAddr>().unwrap(),
|
||||
];
|
||||
let ports: Vec<u16> = vec![22, 80, 443];
|
||||
let mut it = SocketIterator::new(&addrs, &ports);
|
||||
|
||||
assert_eq!(Some(SocketAddr::new(addrs[0], ports[0])), it.next());
|
||||
assert_eq!(Some(SocketAddr::new(addrs[1], ports[0])), it.next());
|
||||
assert_eq!(Some(SocketAddr::new(addrs[0], ports[1])), it.next());
|
||||
assert_eq!(Some(SocketAddr::new(addrs[1], ports[1])), it.next());
|
||||
assert_eq!(Some(SocketAddr::new(addrs[0], ports[2])), it.next());
|
||||
assert_eq!(Some(SocketAddr::new(addrs[1], ports[2])), it.next());
|
||||
assert_eq!(None, it.next());
|
||||
}
|
||||
}
|
||||
+30
-13
@@ -7,11 +7,16 @@ macro_rules! warning {
|
||||
use ansi_term::Colour::Red;
|
||||
println!("{} {}", Red.bold().paint("[!]"), $name);
|
||||
};
|
||||
// quiet mode
|
||||
($name:expr, $quiet:expr) => {
|
||||
($name:expr, $greppable:expr, $accessible:expr) => {
|
||||
use ansi_term::Colour::Red;
|
||||
if !$quiet {
|
||||
println!("{} {}", Red.bold().paint("[!]"), $name);
|
||||
// if not greppable then print, otherwise no else statement so do not print.
|
||||
if !$greppable {
|
||||
if $accessible {
|
||||
// Don't print the ascii art
|
||||
println!("{}", $name);
|
||||
} else {
|
||||
println!("{} {}", Red.bold().paint("[!]"), $name);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -22,26 +27,38 @@ macro_rules! detail {
|
||||
use ansi_term::Colour::Blue;
|
||||
println!("{} {}", Blue.bold().paint("[~]"), $name);
|
||||
};
|
||||
($name:expr, $quiet:expr) => {
|
||||
($name:expr, $greppable:expr, $accessible:expr) => {
|
||||
use ansi_term::Colour::Blue;
|
||||
if !$quiet {
|
||||
println!("{} {}", Blue.bold().paint("[~]"), $name);
|
||||
// if not greppable then print, otherwise no else statement so do not print.
|
||||
if !$greppable {
|
||||
if $accessible {
|
||||
// Don't print the ascii art
|
||||
println!("{}", $name);
|
||||
} else {
|
||||
println!("{} {}", Blue.bold().paint("[~]"), $name);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! output {
|
||||
($name:expr, $quiet:expr) => {
|
||||
use ansi_term::Colour::RGB;
|
||||
if !$quiet {
|
||||
println!("{} {}", RGB(0, 255, 9).bold().paint("[>]"), $name);
|
||||
}
|
||||
};
|
||||
($name:expr) => {
|
||||
use ansi_term::Colour::RGB;
|
||||
println!("{} {}", RGB(0, 255, 9).bold().paint("[>]"), $name);
|
||||
};
|
||||
($name:expr, $greppable:expr, $accessible:expr) => {
|
||||
use ansi_term::Colour::RGB;
|
||||
// if not greppable then print, otherwise no else statement so do not print.
|
||||
if !$greppable {
|
||||
if $accessible {
|
||||
// Don't print the ascii art
|
||||
println!("{}", $name);
|
||||
} else {
|
||||
println!("{} {}", RGB(0, 255, 9).bold().paint("[>]"), $name);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
Reference in new issue
Block a user