Compare commits

...
29 Commits
Author SHA1 Message Date
Autumn (Bee) 5328bfc8b0 2.2.3 (#581) 2024-05-01 15:49:36 +01:00
dependabot[bot] 2340f94a81 Bump actions/upload-artifact from 4.3.2 to 4.3.3 (#578)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.2 to 4.3.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4.3.2...v4.3.3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-27 10:21:23 +01:00
dependabot[bot] dcc558cb43 Bump rustls from 0.21.10 to 0.21.11 (#574)
Bumps [rustls](https://github.com/rustls/rustls) from 0.21.10 to 0.21.11.
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.21.10...v/0.21.11)

---
updated-dependencies:
- dependency-name: rustls
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-21 08:28:38 +01:00
Autumn (Bee) bb2973049c Remove docker build from PRs (#573) 2024-04-21 08:28:05 +01:00
dependabot[bot] a26ea80036 Bump actions/upload-artifact from 4.3.1 to 4.3.2 (#571)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.1 to 4.3.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4.3.1...v4.3.2)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 16:36:46 +01:00
toofooboo 2643a1d5e1 chore: remove repetitive word (#572)
Signed-off-by: toofooboo <[email protected]>
2024-04-19 16:36:34 +01:00
Roger G. Coram b9337d8267 refactor: make RustScan additionally a library (#562)
* refactor: make RustScan additionally a library

- add `lib.rs` (permitted as per
  [_Packages and Crates_](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)).
- refactor `main.rs` to reference the library.
- update module references as required.

* doc: correct documentation issues

- fix some failing doc-tests.
- amend formatting causing misinterpretation as code-samples.
- mark some examples as
  [`compile_fail`](https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html#attributes)
  as there's no immediate way to instantiate the required `struct`.

* docs: add basic module documentation

- add lib-level docs. including a minimal example.
- add minimal, headline information for each module.
2024-04-14 10:09:21 +01:00
dependabot[bot] e4a097c7dc Bump Swatinem/rust-cache from 1 to 2 (#563)
Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from 1 to 2.
- [Release notes](https://github.com/swatinem/rust-cache/releases)
- [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md)
- [Commits](https://github.com/swatinem/rust-cache/compare/v1...v2)

---
updated-dependencies:
- dependency-name: Swatinem/rust-cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-11 17:58:18 +01:00
dependabot[bot] 15290b2275 Bump actions/download-artifact from 2 to 4 (#564)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 2 to 4.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-11 17:58:06 +01:00
dependabot[bot] 6993fb2037 Bump mislav/bump-homebrew-formula-action from 1 to 3 (#565)
Bumps [mislav/bump-homebrew-formula-action](https://github.com/mislav/bump-homebrew-formula-action) from 1 to 3.
- [Release notes](https://github.com/mislav/bump-homebrew-formula-action/releases)
- [Commits](https://github.com/mislav/bump-homebrew-formula-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: mislav/bump-homebrew-formula-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-11 17:57:55 +01:00
dependabot[bot] a311726486 Bump actions/setup-python from 4 to 5 (#566)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-11 17:57:42 +01:00
dependabot[bot] 030e9708f9 Bump actions/upload-artifact from 2.2.4 to 4.3.1 (#567)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2.2.4 to 4.3.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2.2.4...v4.3.1)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-11 17:57:31 +01:00
Juan Calderon-Perez 7f80dd1678 Upgrade Alpine to 3.19.x (#373)
* Update Dockerfile

Upgrade alpine to 3.13, add ca-certificates and bind-tools.

* Add github/docker to dependabot. Update some of the actions

* Skip Registry login for Pull Requests
2024-04-11 17:19:58 +01:00
Ben (CMNatic) f5a587accf Merge pull request #561 from PsypherPunk/update-docker-workflow
build: update Docker workflow trigger
2024-04-10 19:49:26 +01:00
PsypherPunk 1da08dcb9a build: update Docker workflow trigger
remove the `v` prefix from the triggering tag.
2024-04-10 13:24:55 +01:00
Ben (CMNatic) 6ca22d697c Update Docker Runner (#560) 2024-04-10 10:29:19 +01:00
nullandAutumn ac38ca591d Fixed #527 (#537)
* Fixed #527

* Update mod.rs

---------

Co-authored-by: Autumn (Bee) <[email protected]>
2024-04-10 09:31:48 +01:00
Roger G. Coram f2d9a2e1fa Update release workflow (#559)
* build: remove explicit strip steps

- update `Cargo.toml` to
  [`strip`](https://doc.rust-lang.org/cargo/reference/profiles.html#strip)
  as part of the release profile.
- remove explicit `strip` steps from the release workflow.
- update step name to better reflect `git config` changes.

* build: remove prefix from expected tags

- remove the `v` prefix from the triggering tag (all previous tags lack this).
- update tag-deriving steps to better reflect the expected tag pattern.
- update tag-deriving steps to be consistent in how `GITHUB_REF` is parsed.

* build: make build/OS checks generic

- update GitHub Actions conditions to use
  [`contains`](https://docs.github.com/en/actions/learn-github-actions/expressions#contains)
  to match _all_ related builds.
- update shell conditions to accommodate the same.
2024-04-10 09:13:06 +01:00
Lokendra Singh Rawat e3c05afabb minor change in help section (#318)
Changed this : 
For things like --script '(safe and vuln)' enclose it in quotations marks \"'(safe and vuln)'\"")
to:
For things like --script '(safe and vuln)' enclose it in quotations marks \"'(safe and vuln)'\"
2024-04-10 07:23:31 +01:00
c466e0641e fix help message (#319) (#330)
Co-authored-by: Bee <[email protected]>
Co-authored-by: Autumn (Bee) <[email protected]>
2024-04-10 07:22:38 +01:00
dependabot[bot] 331efa5011 Bump text_placeholder from 0.4.1 to 0.5.0 (#558)
Bumps [text_placeholder](https://github.com/bernardoamc/text-placeholder) from 0.4.1 to 0.5.0.
- [Commits](https://github.com/bernardoamc/text-placeholder/commits)

---
updated-dependencies:
- dependency-name: text_placeholder
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-10 07:16:56 +01:00
dependabot[bot] fa1ddc9bba Bump colored from 2.0.0 to 2.1.0 (#557)
Bumps [colored](https://github.com/mackwic/colored) from 2.0.0 to 2.1.0.
- [Release notes](https://github.com/mackwic/colored/releases)
- [Changelog](https://github.com/colored-rs/colored/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mackwic/colored/compare/v2.0.0...v2.1.0)

---
updated-dependencies:
- dependency-name: colored
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-10 07:16:23 +01:00
Wuelfhis AsuajeandWuelfhis Asuaje 170f57c0a3 First attempt enabling exclude port list capability Issue #530 (#534)
* First attempt enabling exclude port list capability

* disabling a not desired println! used for debugging purpose

* fixing small typo:  dbg! by debug!

* adding emtpy commit to make CI/CD pass

* running cargo fmt and removing a TODO comment

* Actually running cargo fmt without check LoL

* fixed some clippy error

* fixing one more cargo clippy complain

---------

Co-authored-by: Wuelfhis Asuaje <[email protected]>
2024-04-10 07:15:43 +01:00
dependabot[bot] 6b6b2f267c Bump text_placeholder from 0.4.0 to 0.4.1 (#552)
Bumps [text_placeholder](https://github.com/bernardoamc/text-placeholder) from 0.4.0 to 0.4.1.
- [Commits](https://github.com/bernardoamc/text-placeholder/commits)

---
updated-dependencies:
- dependency-name: text_placeholder
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-09 08:20:02 +01:00
dependabot[bot] 2287965c5c Bump trust-dns-resolver from 0.21.2 to 0.23.2 (#554)
Bumps [trust-dns-resolver](https://github.com/bluejekyll/trust-dns) from 0.21.2 to 0.23.2.
- [Release notes](https://github.com/bluejekyll/trust-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/v0.23.2/CHANGELOG.md)
- [Commits](https://github.com/bluejekyll/trust-dns/compare/v0.21.2...v0.23.2)

---
updated-dependencies:
- dependency-name: trust-dns-resolver
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-09 08:19:38 +01:00
Roger G. Coram 1ec8ab412e feat(build): add GitHub Action to make release (#427)
* build: move cargo-deb to main release workflow

* build: use absolute paths for deb package

* build: remove Docker builder for deb files

as [requested](https://github.com/RustScan/RustScan/pull/427#issuecomment-2041374743).
2024-04-09 08:19:01 +01:00
Maximiliano Molina 598b5dfd10 fix port range to include end (#518)
* fix port range to include end

* empty

Signed-off-by: Maximiliano Molina <[email protected]>

---------

Signed-off-by: Maximiliano Molina <[email protected]>
2024-04-07 08:10:39 +01:00
fabianbees 1a5ff5bb4b initialize errors HashSet without high initial capacity (#532)
fixes:
- #447
- #523
2024-04-07 08:10:26 +01:00
Jeremiah Gleason 10b3f82bb7 Added more funny quotes. (#526) 2024-04-06 21:58:59 +01:00
20 changed files with 1149 additions and 645 deletions

No files matched your search

+8
View File
@@ -1,5 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: cargo
directory: "/"
schedule:
+6 -6
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
@@ -22,7 +22,7 @@ jobs:
toolchain: stable
override: true
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- name: Run cargo check
uses: actions-rs/cargo@v1
@@ -38,7 +38,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
@@ -47,7 +47,7 @@ jobs:
toolchain: ${{ matrix.rust }}
override: true
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- name: Run cargo test
uses: actions-rs/cargo@v1
@@ -59,7 +59,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
submodules: true
@@ -71,7 +71,7 @@ jobs:
override: true
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- name: Run cargo fmt
uses: actions-rs/cargo@v1
+8 -16
View File
@@ -3,18 +3,9 @@ name: Publish Docker image
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+.[0-9]+'
release:
types: [published]
pull_request:
branches:
- master
paths:
- 'Dockerfile'
- 'Cargo.toml'
- 'Cargo.lock'
- 'contributing.Dockerfile'
- '.github/workflows/docker.yml'
jobs:
push_to_registry:
@@ -22,23 +13,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v2
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
password: ${{ secrets.DOCKER_PASSWORD }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKERHUB_USERNAME }}
username: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: rustscan/rustscan
flavor: latest=true
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
push: ${{ contains(fromJson('["push", "release"]'), github.event_name) }} # Publish to docker registry only on push event or new release.
+39 -24
View File
@@ -2,7 +2,7 @@ name: Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches:
- master
@@ -59,8 +59,8 @@ jobs:
# target: i686-pc-windows-msvc
steps:
- name: Strip release binary (linux and macos)
if: matrix.build == 'x86_64-windows' # Windows is missing some dependencies
- name: Set Git config. (windows only)
if: contains(matrix.build, 'windows') # Windows is missing some dependencies
run: |
git config --global pack.windowMemory "100m"
git config --global pack.packSizeLimit "100m"
@@ -68,13 +68,13 @@ jobs:
git config --global pack.deltaCacheSize "512m"
- name: Install python 3.10 for windows
if: matrix.build == 'x86_64-windows' # Windows is missing some dependencies
uses: actions/setup-python@v4
if: contains(matrix.build, 'windows') # Windows is missing some dependencies
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Checkout sources
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
submodules: true
@@ -100,28 +100,37 @@ jobs:
command: build
args: --release --locked --target ${{ matrix.target }}
- name: Strip release binary (linux and macos)
if: matrix.build == 'x86_64-linux' || matrix.build == 'x86_64-macos'
run: strip "target/${{ matrix.target }}/release/$BIN_NAME"
- name: Strip release binary (arm)
if: matrix.build == 'aarch64-linux'
- name: Calculate tag name
if: contains(matrix.build, 'linux')
run: |
docker run --rm -v \
"$PWD/target:/target:Z" \
rustembedded/cross:${{ matrix.target }} \
aarch64-linux-gnu-strip \
/target/${{ matrix.target }}/release/$BIN_NAME
name=dev
if [[ ${GITHUB_REF} =~ refs/tags/[0-9]+.[0-9]+.[0-9]+ ]]; then
name=${GITHUB_REF#refs/tags/}
fi
echo ::set-output name=val::$name
echo TAG=$name >> $GITHUB_ENV
id: tagname
- name: Build deb package (linux only)
if: contains(matrix.build, 'linux')
run: |
cargo install cargo-deb
cargo deb --target ${{ matrix.target }} --deb-version ${TAG}
- name: Build archive
shell: bash
run: |
mkdir dist
if [ "${{ matrix.os }}" = "windows-2019" ]; then
if [[ "${{ matrix.build }}" =~ "windows" ]]; then
cp "target/${{ matrix.target }}/release/$BIN_NAME.exe" "dist/"
else
cp "target/${{ matrix.target }}/release/$BIN_NAME" "dist/"
fi
- uses: actions/[email protected]
if [[ "${{ matrix.build }}" =~ "linux" ]]; then
cp "target/${{ matrix.target }}/debian/rustscan_${TAG}_amd64.deb" "dist/"
fi
- uses: actions/[email protected]
with:
name: bins-${{ matrix.build }}
path: dist
@@ -133,11 +142,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
submodules: false
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v4
# with:
# path: dist
# - run: ls -al ./dist
@@ -146,8 +155,8 @@ jobs:
- name: Calculate tag name
run: |
name=dev
if [[ $GITHUB_REF == refs/tags/v* ]]; then
name=${GITHUB_REF:10}
if [[ ${GITHUB_REF} =~ refs/tags/[0-9]+.[0-9]+.[0-9]+ ]]; then
name=${GITHUB_REF#refs/tags/}
fi
echo ::set-output name=val::$name
echo TAG=$name >> $GITHUB_ENV
@@ -171,12 +180,18 @@ jobs:
# cp LICENSE README.md tmp/$pkgname
mv bins-$platform/$BIN_NAME$exe tmp/$pkgname
chmod +x tmp/$pkgname/$BIN_NAME$exe
if [[ $platform =~ "linux" ]]; then
mv "bins-$platform/rustscan_${TAG}_amd64.deb" dist/
fi
if [ "$exe" = "" ]; then
tar cJf dist/$pkgname.tar.xz -C tmp $pkgname
else
(cd tmp && 7z a -r ../dist/$pkgname.zip $pkgname)
fi
done
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
@@ -190,7 +205,7 @@ jobs:
id: extract-version
run: |
printf "::set-output name=%s::%s\n" tag-name "${GITHUB_REF#refs/tags/}"
- uses: mislav/bump-homebrew-formula-action@v1
- uses: mislav/bump-homebrew-formula-action@v3
with:
formula-path: ${{env.PROJECT_NAME}}.rb
homebrew-tap: ${{ env.BREW_TAP }}
+2
View File
@@ -120,3 +120,5 @@ fabric.properties
.idea/*
.idea
.idea*
settings.json
Generated
+826 -432
View File
File diff suppressed because it is too large. Load diff
+6 -6
View File
@@ -1,6 +1,6 @@
[package]
name = "rustscan"
version = "2.1.1"
version = "2.2.3"
authors = ["Autumn <[email protected]>"]
edition = "2018"
description = "Faster Nmap Scanning with Rust"
@@ -17,12 +17,11 @@ exclude = [
]
[dependencies]
colored = "2.0.0"
colored = "2.1.0"
structopt = "0.3.20"
async-std = "1.7.0"
futures = "0.3"
rlimit = "0.8.3"
shell-words = "1.0.0"
log = "0.4.0"
env_logger = "0.8.2"
dirs = "3.0.1"
@@ -35,10 +34,10 @@ serde = "1.0.124"
serde_derive = "1.0.116"
cidr-utils = "0.5.1"
itertools = "0.9.0"
trust-dns-resolver = { version = "0.21.1", features = ["dns-over-rustls"] }
trust-dns-resolver = { version = "0.23.2", features = ["dns-over-rustls"] }
anyhow = "1.0.40"
subprocess = "0.2.6"
text_placeholder = { version = "0.4", features = ["struct_context"] }
text_placeholder = { version = "0.5", features = ["struct_context"] }
[dev-dependencies]
wait-timeout = "0.2"
@@ -50,8 +49,9 @@ section = "rust"
[profile.release]
lto = true
panic = 'abort'
strip = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "rustscan"
path = "src/main.rs"
path = "src/main.rs"
+7 -2
View File
@@ -1,3 +1,4 @@
# Build Stage
FROM rust:alpine as builder
LABEL maintainer="RustScan <https://github.com/RustScan>"
RUN apk add --no-cache build-base
@@ -8,13 +9,17 @@ COPY Cargo.toml Cargo.lock ./
COPY src/ src/
RUN cargo build --release
FROM alpine:3.17
# Release Stage
FROM alpine:3.19.1 as release
LABEL author="Hydragyrum <https://github.com/Hydragyrum>"
LABEL author="LeoFVO <https://github.com/LeoFVO>"
RUN addgroup -S rustscan && \
adduser -S -G rustscan rustscan && \
ulimit -n 100000 && \
apk add --no-cache nmap nmap-scripts wget
apk add --no-cache nmap nmap-scripts wget ca-certificates bind-tools
USER rustscan
COPY --from=builder /app/rustscan/target/release/rustscan /usr/local/bin/rustscan
ENTRYPOINT [ "/usr/local/bin/rustscan" ]
-20
View File
@@ -1,20 +0,0 @@
FROM rust:latest
RUN git clone https://github.com/brandonskerritt/RustScan
WORKDIR "/RustScan"
RUN git pull --force
RUN cargo install cargo-deb
RUN apt update -y && apt upgrade -y
RUN apt install libc6-dev-i386 -y
RUN git clone --depth=1 https://github.com/raspberrypi/tools /raspberrypi-tools
ENV PATH=/raspberrypi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/:$PATH
ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
RUN mkdir /root/.cargo
RUN echo "[target.arm-unknown-linux-gnueabihf]" >> /root/.cargo/config
RUN echo "strip = { path = \"arm-linux-gnueabihf-strip\" }" >> /root/.cargo/config
RUN echo "objcopy = { path = \"arm-linux-gnueabihf-objcopy\" }" >> /root/.cargo/config
COPY ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
cd /RustScan
git pull --force
#amd64
cargo deb
#arm64
rustup target add arm-unknown-linux-gnueabihf
cargo deb --target=arm-unknown-linux-gnueabihf
#i386
rustup target add i686-unknown-linux-gnu
cargo deb --target=i686-unknown-linux-gnu
find target/ -name \*.deb -exec cp {} /debs \;
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
docker build -t rustscan-builder . || exit
# This creates a volume which binds your currentdirectory/debs to
# the location where the deb files get spat out in the container.
# You don't need to worry about it. Just chmod +x run.sh && ./run.sh and
# you'll get yer .deb file in a few minutes. It runs faster after you've used it the first time.
docker run -v "$(pwd)/debs:/debs" rustscan-builder
+8 -3
View File
@@ -1,15 +1,20 @@
//! Provides functionality to capture timing information for scans.
//!
//! # Usage
//! ```
//!
//! ```rust
//! // Initiate Benchmark vector
//! # use rustscan::benchmark::{Benchmark, NamedTimer};
//! # use log::info;
//! let mut bm = Benchmark::init();
//! // Start named timer with name
//! let mut example_bench = NamedTimer::start("Example Bench");
//! // Stop named timer
//! example_bench.stop();
//! example_bench.end();
//! // Add named timer to Benchmarks
//! bm.push(example_bench);
//! // Print Benchmark Summary
//! info!({}, bm.summary());
//! info!("{}", bm.summary());
//! ```
use std::time::Instant;
+34 -25
View File
@@ -1,3 +1,4 @@
//! Provides a means to read, parse and hold configuration options for scans.
use serde_derive::Deserialize;
use std::collections::HashMap;
use std::fs;
@@ -135,11 +136,15 @@ pub struct Opts {
/// The Script arguments to run.
/// To use the argument -A, end RustScan's args with '-- -A'.
/// Example: 'rustscan -T 1500 -a 127.0.0.1 -- -A -sC'.
/// Example: 'rustscan -t 1500 -a 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)'\"")
/// For things like --script '(safe and vuln)' enclose it in quotations marks \"'(safe and vuln)'\"
#[structopt(last = true)]
pub command: Vec<String>,
/// A list of comma separated ports to be excluded from scanning. Example: 80,443,8080.
#[structopt(short, long, use_delimiter = true)]
pub exclude_ports: Option<Vec<u16>>,
}
#[cfg(not(tarpaulin_include))]
@@ -203,7 +208,30 @@ impl Opts {
self.ports = Some(ports);
}
merge_optional!(range, ulimit);
merge_optional!(range, ulimit, exclude_ports);
}
}
impl Default for Opts {
fn default() -> Self {
Self {
addresses: vec![],
ports: None,
range: None,
greppable: true,
batch_size: 0,
timeout: 0,
tries: 0,
ulimit: None,
command: vec![],
accessible: false,
scan_order: ScanOrder::Serial,
no_config: true,
top: false,
scripts: ScriptsRequired::Default,
config_path: None,
exclude_ports: None,
}
}
}
@@ -225,6 +253,7 @@ pub struct Config {
scan_order: Option<ScanOrder>,
command: Option<Vec<String>>,
scripts: Option<ScriptsRequired>,
exclude_ports: Option<Vec<u16>>,
}
#[cfg(not(tarpaulin_include))]
@@ -239,6 +268,7 @@ impl Config {
/// ports = [80, 443, 8080]
/// greppable = true
/// scan_order: "Serial"
/// exclude_ports = [8080, 9090, 80]
///
pub fn read(custom_config_path: Option<PathBuf>) -> Self {
let mut content = String::new();
@@ -289,28 +319,7 @@ mod tests {
accessible: Some(true),
scan_order: Some(ScanOrder::Random),
scripts: None,
}
}
}
impl Opts {
pub fn default() -> Self {
Self {
addresses: vec![],
ports: None,
range: None,
greppable: true,
batch_size: 0,
timeout: 0,
tries: 0,
ulimit: None,
command: vec![],
accessible: false,
scan_order: ScanOrder::Serial,
no_config: true,
top: false,
scripts: ScriptsRequired::Default,
config_path: None,
exclude_ports: None,
}
}
}
+53
View File
@@ -0,0 +1,53 @@
//! This crate exposes the internal functionality of the
//! [RustScan](https://rustscan.github.io/RustScan) port scanner.
//!
//! ## Example: perform a scan against localhost
//!
//! The core scanning behaviour is managed by
//! [`Scanner`](crate::scanner::Scanner) which in turn requires a
//! [`PortStrategy`](crate::port_strategy::PortStrategy):
//!
//! ```rust
//! use async_std::task::block_on;
//! use std::{net::IpAddr, time::Duration};
//!
//! use rustscan::input::{PortRange, ScanOrder};
//! use rustscan::port_strategy::PortStrategy;
//! use rustscan::scanner::Scanner;
//!
//! fn main() {
//! let addrs = vec!["127.0.0.1".parse::<IpAddr>().unwrap()];
//! let range = PortRange {
//! start: 1,
//! end: 1_000,
//! };
//! let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
//! let scanner = Scanner::new(
//! &addrs,
//! 10,
//! Duration::from_millis(100),
//! 1,
//! true,
//! strategy,
//! true,
//! vec![9000],
//! );
//!
//! let scan_result = block_on(scanner.run());
//!
//! println!("{:?}", scan_result);
//! }
//! ```
#![allow(clippy::needless_doctest_main)]
pub mod tui;
pub mod input;
pub mod scanner;
pub mod port_strategy;
pub mod benchmark;
pub mod scripts;
+13 -22
View File
@@ -2,24 +2,12 @@
#![warn(clippy::pedantic)]
#![allow(clippy::doc_markdown, clippy::if_not_else, clippy::non_ascii_literal)]
extern crate shell_words;
mod tui;
mod input;
use input::{Config, Opts, PortRange, ScanOrder, ScriptsRequired};
mod scanner;
use scanner::Scanner;
mod port_strategy;
use port_strategy::PortStrategy;
mod benchmark;
use benchmark::{Benchmark, NamedTimer};
mod scripts;
use scripts::{init_scripts, Script, ScriptFile};
use rustscan::benchmark::{Benchmark, NamedTimer};
use rustscan::input::{self, Config, Opts, ScriptsRequired};
use rustscan::port_strategy::PortStrategy;
use rustscan::scanner::Scanner;
use rustscan::scripts::{init_scripts, Script, ScriptFile};
use rustscan::{detail, funny_opening, output, warning};
use cidr_utils::cidr::IpCidr;
use colorful::{Color, Colorful};
@@ -98,6 +86,9 @@ fn main() {
#[cfg(not(unix))]
let batch_size: u16 = AVERAGE_BATCH_SIZE;
// Added by wasuaje - 01/26/2024:
// exclude_ports is an exclusion port list
//
let scanner = Scanner::new(
&ips,
batch_size,
@@ -106,6 +97,7 @@ fn main() {
opts.greppable,
PortStrategy::pick(&opts.range, opts.ports, opts.scan_order),
opts.accessible,
opts.exclude_ports.unwrap_or_default(),
);
debug!("Scanner finished building: {:?}", scanner);
@@ -284,7 +276,7 @@ fn parse_addresses(input: &Opts) -> Vec<IpAddr> {
ips
}
/// Given a string, parse it as an host, IP address, or CIDR.
/// Given a string, parse it as a host, IP address, or CIDR.
/// This allows us to pass files as hosts or cidr or IPs easily
/// Call this every time you have a possible IP_or_host
fn parse_address(address: &str, resolver: &Resolver) -> Vec<IpAddr> {
@@ -405,9 +397,8 @@ fn infer_batch_size(opts: &Opts, ulimit: u64) -> u16 {
#[cfg(test)]
mod tests {
#[cfg(unix)]
use crate::{adjust_ulimit_size, infer_batch_size};
use crate::{parse_addresses, print_opening, Opts};
use super::{adjust_ulimit_size, infer_batch_size};
use super::{parse_addresses, print_opening, Opts};
use std::net::Ipv4Addr;
#[test]
+6 -5
View File
@@ -1,5 +1,6 @@
//! Provides a means to hold configuration options specifically for port scanning.
mod range_iterator;
use super::{PortRange, ScanOrder};
use crate::input::{PortRange, ScanOrder};
use rand::seq::SliceRandom;
use rand::thread_rng;
use range_iterator::RangeIterator;
@@ -67,7 +68,7 @@ pub struct SerialRange {
impl RangeOrder for SerialRange {
fn generate(&self) -> Vec<u16> {
(self.start..self.end).collect()
(self.start..=self.end).collect()
}
}
@@ -97,14 +98,14 @@ impl RangeOrder for RandomRange {
#[cfg(test)]
mod tests {
use super::PortStrategy;
use crate::{PortRange, ScanOrder};
use crate::input::{PortRange, ScanOrder};
#[test]
fn serial_strategy_with_range() {
let range = PortRange { start: 1, end: 100 };
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Serial);
let result = strategy.order();
let expected_range = (1..100).into_iter().collect::<Vec<u16>>();
let expected_range = (1..=100).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
}
#[test]
@@ -112,7 +113,7 @@ mod tests {
let range = PortRange { start: 1, end: 100 };
let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random);
let mut result = strategy.order();
let expected_range = (1..100).into_iter().collect::<Vec<u16>>();
let expected_range = (1..=100).into_iter().collect::<Vec<u16>>();
assert_ne!(expected_range, result);
result.sort_unstable();
+7 -7
View File
@@ -15,14 +15,14 @@ pub struct RangeIterator {
///
/// For more information: <https://en.wikipedia.org/wiki/Linear_congruential_generator>
impl RangeIterator {
/// Receives the the start and end of a range and normalize
/// Receives the start and end of a range and normalize
/// these values before selecting a coprime for the end of the range
/// which will server as the step for the algorithm.
///
/// For example, the range `1000-2500` will be normalized to `0-1500`
/// before going through the algorithm.
pub fn new(start: u32, end: u32) -> Self {
let normalized_end = end - start;
let normalized_end = end - start + 1;
let step = pick_random_coprime(normalized_end);
// Randomly choose a number within the range to be the first
@@ -103,23 +103,23 @@ mod tests {
#[test]
fn range_iterator_iterates_through_the_entire_range() {
let result = generate_sorted_range(1, 10);
let expected_range = (1..10).into_iter().collect::<Vec<u16>>();
let expected_range = (1..=10).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
let result = generate_sorted_range(1, 100);
let expected_range = (1..100).into_iter().collect::<Vec<u16>>();
let expected_range = (1..=100).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
let result = generate_sorted_range(1, 1000);
let expected_range = (1..1000).into_iter().collect::<Vec<u16>>();
let expected_range = (1..=1000).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
let result = generate_sorted_range(1, 65_535);
let expected_range = (1..65_535).into_iter().collect::<Vec<u16>>();
let expected_range = (1..=65_535).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
let result = generate_sorted_range(1000, 2000);
let expected_range = (1000..2000).into_iter().collect::<Vec<u16>>();
let expected_range = (1000..=2000).into_iter().collect::<Vec<u16>>();
assert_eq!(expected_range, result);
}
+42 -15
View File
@@ -1,4 +1,6 @@
use super::PortStrategy;
//! Core functionality for actual scanning behaviour.
use crate::port_strategy::PortStrategy;
use log::debug;
mod socket_iterator;
use socket_iterator::SocketIterator;
@@ -21,6 +23,8 @@ use std::{
/// batch_size is how many ports at a time should be scanned
/// Timeout is the time RustScan should wait before declaring a port closed. As datatype Duration.
/// greppable is whether or not RustScan should print things, or wait until the end to print only the ip and open ports.
/// Added by wasuaje - 01/26/2024:
/// exclude_ports is an exclusion port list
#[cfg(not(tarpaulin_include))]
#[derive(Debug)]
pub struct Scanner {
@@ -31,8 +35,11 @@ pub struct Scanner {
greppable: bool,
port_strategy: PortStrategy,
accessible: bool,
exclude_ports: Vec<u16>,
}
// Allowing too many arguments for clippy.
#[allow(clippy::too_many_arguments)]
impl Scanner {
pub fn new(
ips: &[IpAddr],
@@ -42,6 +49,7 @@ impl Scanner {
greppable: bool,
port_strategy: PortStrategy,
accessible: bool,
exclude_ports: Vec<u16>,
) -> Self {
Self {
batch_size,
@@ -51,18 +59,27 @@ impl Scanner {
port_strategy,
ips: ips.iter().map(ToOwned::to_owned).collect(),
accessible,
exclude_ports,
}
}
/// Runs scan_range with chunk sizes
/// If you want to run RustScan normally, this is the entry point used
/// Returns all open ports as Vec<u16>
/// Returns all open ports as `Vec<u16>`
/// Added by wasuaje - 01/26/2024:
/// Filtering port against exclude port list
pub async fn run(&self) -> Vec<SocketAddr> {
let ports: Vec<u16> = self.port_strategy.order();
let ports: Vec<u16> = self
.port_strategy
.order()
.iter()
.filter(|&port| !self.exclude_ports.contains(port))
.copied()
.collect();
let mut socket_iterator: SocketIterator = SocketIterator::new(&self.ips, &ports);
let mut open_sockets: Vec<SocketAddr> = Vec::new();
let mut ftrs = FuturesUnordered::new();
let mut errors: HashSet<String> = HashSet::with_capacity(self.ips.len() * 1000);
let mut errors: HashSet<String> = HashSet::new();
for _ in 0..self.batch_size {
if let Some(socket) = socket_iterator.next() {
@@ -72,7 +89,7 @@ impl Scanner {
}
}
debug!("Start scanning sockets. \nBatch size {}\nNumber of ip-s {}\nNumber of ports {}\nTargets all together {} ",
debug!("Start scanning sockets. \nBatch size {}\nNumber of ip-s {}\nNumber of ports {}\nTargets all together {} ",
self.batch_size,
self.ips.len(),
&ports.len(),
@@ -100,14 +117,16 @@ impl Scanner {
/// Given a socket, scan it self.tries times.
/// Turns the address into a SocketAddr
/// Deals with the <result> type
/// Deals with the `<result>` type
/// If it experiences error ErrorKind::Other then too many files are open and it Panics!
/// Else any other error, it returns the error in Result as a string
/// If no errors occur, it returns the port number in Result to signify the port is open.
/// This function mainly deals with the logic of Results handling.
/// # Example
///
/// self.scan_socket(socket)
/// ```compile_fail
/// scanner.scan_socket(socket)
/// ```
///
/// Note: `self` must contain `self.ip`.
async fn scan_socket(&self, socket: SocketAddr) -> io::Result<SocketAddr> {
@@ -153,13 +172,16 @@ impl Scanner {
/// Performs the connection to the socket with timeout
/// # Example
///
/// let port: u16 = 80
/// // ip is an IpAddr type
/// let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// let socket = SocketAddr::new(ip, port);
/// self.connect(socket)
/// // returns Result which is either Ok(stream) for port is open, or Er for port is closed.
/// // Timeout occurs after self.timeout seconds
/// ```compile_fail
/// # use std::net::{IpAddr, Ipv6Addr, SocketAddr};
/// let port: u16 = 80;
/// // ip is an IpAddr type
/// let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// let socket = SocketAddr::new(ip, port);
/// scanner.connect(socket);
/// // returns Result which is either Ok(stream) for port is open, or Er for port is closed.
/// // Timeout occurs after self.timeout seconds
/// ```
///
async fn connect(&self, socket: SocketAddr) -> io::Result<TcpStream> {
let stream = io::timeout(
@@ -174,7 +196,7 @@ impl Scanner {
#[cfg(test)]
mod tests {
use super::*;
use crate::{PortRange, ScanOrder};
use crate::input::{PortRange, ScanOrder};
use async_std::task::block_on;
use std::{net::IpAddr, time::Duration};
@@ -195,6 +217,7 @@ mod tests {
true,
strategy,
true,
vec![9000],
);
block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
@@ -217,6 +240,7 @@ mod tests {
true,
strategy,
true,
vec![9000],
);
block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
@@ -238,6 +262,7 @@ mod tests {
true,
strategy,
true,
vec![9000],
);
block_on(scanner.run());
assert_eq!(1, 1);
@@ -258,6 +283,7 @@ mod tests {
true,
strategy,
true,
vec![9000],
);
block_on(scanner.run());
assert_eq!(1, 1);
@@ -281,6 +307,7 @@ mod tests {
true,
strategy,
true,
vec![9000],
);
block_on(scanner.run());
assert_eq!(1, 1);
+65 -36
View File
@@ -1,52 +1,83 @@
//! Scripting engine to run scripts based on tags.
//! Scripting Engine to run scripts based on tags.
//!
//! This module serves to filter and run the scripts selected by the user.
//!
//! A new commandline and configuration file option was added.
//!
//! --scripts
//! ## `--scripts`
//!
//! default
//! This is the default behavior, like as it was from the beginning of RustScan.
//! The user do not have to chose anything for this. This is the only script embedded in RustScan running as default.
//! ### `default`
//!
//! none
//! The user have to use the --scripts none commandline argument or scripts = "none" in the config file.
//! None of the scripts will run, this replaces the removed --no-nmap option.
//! This is the default behavior, like as it was from the beginning of RustScan.
//!
//! custom
//! The user have to use the --scripts custom commandline argument or scripts = "custom" in the config file.
//! Rustscan will look for the script configuration file in the user's home dir: home_dir/.rustscan_scripts.toml
//! The config file have 3 optional fields, tag, developer and port. Just the tag field will be used forther in the process.
//! RustScan will also look for available scripts in the user's home dir: home_dir/.rustscan_scripts
//! and will try to read all the files, and parse them into a vector of ScriptFiles.
//! Filtering on tags means the tags found in the rustscan_scripts.toml file will also have to be present in the Scriptfile,
//! otherwise the script will not be selected.
//! All of the rustscan_script.toml tags have to be present at minimum in a Scriptfile to get selected, but can be also more.
//! The user do not have to chose anything for this. This is the only script
//! embedded in RustScan running as default.
//!
//! ### `none`
//!
//! The user have to use the `--scripts none` commandline argument or `scripts =
//! "none"` in the config file.
//!
//! None of the scripts will run, this replaces the removed `--no-nmap` option.
//!
//! ### `custom`
//!
//! The user have to use the `--scripts custom` commandline argument or
//! `scripts = "custom"` in the config file.
//!
//! RustScan will look for the script configuration file in the user's home
//! dir: `home_dir/.rustscan_scripts.toml`
//!
//! The config file have 3 optional fields: `tag`, `developer` and `port`. Just
//! the `tag` field will be used forther in the process.
//!
//! RustScan will also look for available scripts in the user's home dir:
//! `home_dir/.rustscan_scripts` and will try to read all the files, and parse
//! them into a vector of [`ScriptFile`].
//!
//! Filtering on tags means the tags found in the `rustscan_scripts.toml` file
//! will also have to be present in the [`ScriptFile`], otherwise the script
//! will not be selected.
//!
//! All of the `rustscan_script.toml` tags have to be present at minimum in a
//! [`ScriptFile`] to get selected, but can be also more.
//!
//! Config file example:
//! fixtures/test_rustscan_scripts.toml
//!
//! - `fixtures/test_rustscan_scripts.toml`
//!
//! Script file examples:
//! fixtures/test_script.py
//! fixtures/test_script.pl
//! fixtures/test_script.sh
//! fixtures/test_script.txt
//!
//! call_format in script files can be of 2 variants.
//! One is where all of the possible tags {{script}} {{ip}} {{port}} are there.
//! The {{script}} part will be replaced with the scriptfile full path gathered while parsing available scripts.
//! The {{ip}} part will be replaced with the ip we got from the scan.
//! The {{port}} part will be reaplced with the ports separated with the ports_separator found in the script file
//! - `fixtures/test_script.py`
//! - `fixtures/test_script.pl`
//! - `fixtures/test_script.sh`
//! - `fixtures/test_script.txt`
//!
//! And when there is only {{ip}} and {{port}} is in the format, only those will be replaced with the arguments from the scan.
//! This makes it easy to run a system installed command like nmap, and give any kind of arguments to it.
//! `call_format` in script files can be of 2 variants:
//!
//! If the format is different, the script will be silently discarded and will not run. With the Debug option it's possible to see where it goes wrong.
//! One is where all of the possible tags `{{script}}`, `{{ip}}` and `{{port}}`
//! are there.
//!
//! - The `{{script}}` part will be replaced with the scriptfile full path
//! gathered while parsing available scripts.
//! - The `{{ip}}` part will be replaced with the ip we got from the scan.
//! - The `{{port}}` part will be reaplced with the ports separated with the
//! `ports_separator` found in the script file
//!
//! And when there is only `{{ip}}` and `{{port}}` is in the format, only those
//! will be replaced with the arguments from the scan.
//!
//! This makes it easy to run a system installed command like `nmap`, and give
//! any kind of arguments to it.
//!
//! If the format is different, the script will be silently discarded and will
//! not run. With the `Debug` option it's possible to see where it goes wrong.
#![allow(clippy::module_name_repetitions)]
use crate::input::ScriptsRequired;
use anyhow::{anyhow, Result};
use log::debug;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashSet;
use std::convert::TryInto;
@@ -233,16 +264,14 @@ impl Script {
}
debug!("\nScript format to run {}", to_run);
let arguments = shell_words::split(&to_run).expect("Failed to parse script arguments");
execute_script(arguments)
execute_script(&to_run)
}
}
#[cfg(not(tarpaulin_include))]
fn execute_script(mut arguments: Vec<String>) -> Result<String> {
debug!("\nScript arguments vec: {:?}", &arguments);
let process = Exec::cmd(arguments.remove(0)).args(&arguments);
fn execute_script(script: &str) -> Result<String> {
debug!("\nScript arguments {}", script);
let process = Exec::shell(script);
match process.capture() {
Ok(c) => {
let es = match c.exit_status {
+19 -1
View File
@@ -1,6 +1,7 @@
//! Utilities for terminal output during scanning.
/// Terminal User Interface Module for RustScan
/// Defines macros to use
#[macro_export]
macro_rules! warning {
($name:expr) => {
@@ -75,6 +76,23 @@ macro_rules! funny_opening {
"Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan",
"😵 https://admin.tryhackme.com",
"0day was here ♥",
"I don't always scan ports, but when I do, I prefer RustScan.",
"RustScan: Where scanning meets swagging. 😎",
"To scan or not to scan? That is the question.",
"RustScan: Because guessing isn't hacking.",
"Scanning ports like it's my full-time job. Wait, it is.",
"Open ports, closed hearts.",
"I scanned my computer so many times, it thinks we're dating.",
"Port scanning: Making networking exciting since... whenever.",
"You miss 100% of the ports you don't scan. - RustScan",
"Breaking and entering... into the world of open ports.",
"TCP handshake? More like a friendly high-five!",
"Scanning ports: The virtual equivalent of knocking on doors.",
"RustScan: Making sure 'closed' isn't just a state of mind.",
"Port scanning: Because every port has a story to tell.",
"I scanned ports so fast, even my computer was surprised.",
"RustScan: Where '404 Not Found' meets '200 OK'.",
"RustScan: Exploring the digital landscape, one IP at a time.",
];
let random_quote = quotes.choose(&mut rand::thread_rng()).unwrap();