Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
befd6c862b | ||
95d726987f | |||
|
75f2ae0655 | ||
|
dc2854faad | ||
|
3db7162612 | ||
|
c51d855d9c | ||
|
3a34230b0a | ||
|
04198fb28e | ||
|
dd430b1b2c | ||
53c405b7a6 | |||
|
c4462fcbca | ||
|
5476327560 | ||
|
8f08f1784c | ||
|
b5457c34ac | ||
|
4b5f095a9b | ||
|
237e46bc5d | ||
|
78c1fe3f09 | ||
|
5378d6b105 | ||
|
96ad617804 | ||
|
2c8ef69905 | ||
|
4edb7b08ab | ||
|
1ecfb86efe | ||
|
47f6e1c206 | ||
|
13d725769c | ||
|
38cbe9aa56 | ||
|
c96027578a | ||
86e099f4cd |
@ -18,6 +18,13 @@ steps:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- cargo build --release
|
||||
- rustup target add x86_64-pc-windows-gnu
|
||||
- rustup toolchain install stable-x86_64-pc-windows-gnu
|
||||
- apt update
|
||||
- apt install -yy mingw-w64
|
||||
- cargo build --target x86_64-pc-windows-gnu --release
|
||||
environment:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
when:
|
||||
event:
|
||||
include:
|
||||
@ -25,6 +32,7 @@ steps:
|
||||
|
||||
- name: create-release
|
||||
image: plugins/gitea-release:latest
|
||||
custom_dns: [ 9.9.9.9 ]
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: gitea_api
|
||||
@ -32,6 +40,7 @@ steps:
|
||||
note: This is an automated release
|
||||
files:
|
||||
- ./target/release/portnut
|
||||
- ./target/x86_64-pc-windows-gnu/release/portnut.exe
|
||||
when:
|
||||
event:
|
||||
include:
|
||||
|
57
.gitea/workflows/build.yml
Normal file
57
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,57 @@
|
||||
name: Rust-build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
|
||||
- name: Check-out
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install stable toolchain
|
||||
uses: https://github.com/actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- name: Run cargo check
|
||||
uses: https://github.com/actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
|
||||
- name: Test
|
||||
run: cargo test
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: gitea.squi.fr
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
env:
|
||||
ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: gitea.squi.fr/justine/portnut:latest
|
754
Cargo.lock
generated
754
Cargo.lock
generated
@ -2,6 +2,21 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.2"
|
||||
@ -71,18 +86,63 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.3.11"
|
||||
@ -130,6 +190,15 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
@ -151,12 +220,118 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.25",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
@ -178,6 +353,104 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"hyper",
|
||||
"rustls",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
||||
|
||||
[[package]]
|
||||
name = "ipnetwork"
|
||||
version = "0.20.0"
|
||||
@ -198,6 +471,21 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
@ -210,24 +498,93 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "no-std-net"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pnet"
|
||||
version = "0.33.0"
|
||||
@ -321,11 +678,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "portnut"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"clap",
|
||||
"pnet",
|
||||
"reqwest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -375,6 +733,66 @@ version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.4"
|
||||
@ -388,12 +806,107 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b19faa85ecb5197342b54f987b142fb3e30d0c90da40f80ef4fa9a726e6676ed"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"rustls-webpki",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@ -422,18 +935,248 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||
dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.25",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.25",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.22.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
|
||||
dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -521,3 +1264,12 @@ name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "portnut"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -9,3 +9,4 @@ edition = "2021"
|
||||
atty = "0.2.14"
|
||||
clap = { version = "4.3.11", features = ["derive"] }
|
||||
pnet = "0.33.0"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "rustls-tls"] }
|
||||
|
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
FROM rust:slim-buster AS builder
|
||||
RUN mkdir -p /opt/portnut
|
||||
COPY --chown=root --chmod=0755 ./src /opt/portnut/src
|
||||
COPY --chown=root --chmod=0755 ./Cargo.toml /opt/portnut/Cargo.toml
|
||||
RUN apt update
|
||||
#RUN apt install libssl-dev openssl pkg-config -y
|
||||
WORKDIR /opt/portnut
|
||||
RUN cargo build --release
|
||||
RUN cp target/release/portnut /bin/portnut
|
||||
|
||||
FROM debian:stable-slim
|
||||
WORKDIR /opt/
|
||||
COPY --from=builder /opt/portnut/target/release/portnut .
|
||||
ENTRYPOINT ["/opt/portnut"]
|
||||
CMD [ "" ]
|
109
README.md
109
README.md
@ -1,47 +1,122 @@
|
||||
# Portnut
|
||||
|
||||
[](http://drone.sq.lan/Rust/Portnut)
|
||||
Portnut is a port stressing / scanning multithreaded utility. It can handle raw TCP and HTTP.
|
||||
|
||||
TODO
|
||||
* Read the answer and count the number of answers received.
|
||||
# TODO
|
||||
* Make a distributed version that allows stressing from multiple computers at the same time
|
||||
* Make drone work
|
||||
* Return more stats (low 1%, high 1%)
|
||||
|
||||
# Install
|
||||
Go to the releases page and download the latest version.
|
||||
Give it execution rights and simply launch it.
|
||||
|
||||
# Building
|
||||
|
||||
Prerequisite to building reqwest:
|
||||
> apt install libssl-dev
|
||||
|
||||
# Usage
|
||||
|
||||
Portnut is a tcp port scanner / stresser.
|
||||
|
||||
The scanning function simply tries to connect to the tcp ports given.
|
||||
The stressing function sends a payload every 10 milliseconds, to every ports given at the same time. The payload can be passed via a pipe (optionnal).
|
||||
|
||||
## Scan
|
||||
```
|
||||
1637 justine@portnut > target/release/portnut -a 127.0.0.1 -w 3 -p 8080,22
|
||||
Scanning 127.0.0.1
|
||||
TCP/8080 => REJECT
|
||||
TCP/22 => REJECT
|
||||
2347 justine > portnut tcpscan -a 127.0.0.1 -p 8080,8090
|
||||
____ ____ ____ _______ ____ ________
|
||||
/ __ \/ __ \/ __ \/_ __/ | / / / / /_ __/
|
||||
/ /_/ / / / / /_/ / / / / |/ / / / / / /
|
||||
/ ____/ /_/ / _, _/ / / / /| / /_/ / / /
|
||||
/_/ \____/_/ |_| /_/ /_/ |_/\____/ /_/
|
||||
|
||||
Scanning 127.0.0.1
|
||||
TCP/8080 => ACCEPT
|
||||
TCP/8090 => REJECT
|
||||
2351 justine > portnut tcpscan -a 127.0.0.1 -p 8080,8090 --range
|
||||
____ ____ ____ _______ ____ ________
|
||||
/ __ \/ __ \/ __ \/_ __/ | / / / / /_ __/
|
||||
/ /_/ / / / / /_/ / / / / |/ / / / / / /
|
||||
/ ____/ /_/ / _, _/ / / / /| / /_/ / / /
|
||||
/_/ \____/_/ |_| /_/ /_/ |_/\____/ /_/
|
||||
|
||||
Scanning 127.0.0.1
|
||||
TCP/8080 => ACCEPT
|
||||
TCP/8081 => REJECT
|
||||
TCP/8082 => REJECT
|
||||
TCP/8083 => REJECT
|
||||
TCP/8084 => REJECT
|
||||
TCP/8085 => REJECT
|
||||
TCP/8086 => REJECT
|
||||
TCP/8087 => REJECT
|
||||
TCP/8088 => REJECT
|
||||
TCP/8089 => REJECT
|
||||
```
|
||||
|
||||
## TCP Stress
|
||||
TCP Stress can be applied to a port, a list of port, or a range of port.
|
||||
Stressing allows sending a payload (via -p/--payload or via a pipe), sending, and waiting for an answer.
|
||||
```
|
||||
2356 justine > portnut tcpstress -a 127.0.0.1 -p 8080 -d 2
|
||||
____ ____ ____ _______ ____ ________
|
||||
/ __ \/ __ \/ __ \/_ __/ | / / / / /_ __/
|
||||
/ /_/ / / / / /_/ / / / / |/ / / / / / /
|
||||
/ ____/ /_/ / _, _/ / / / /| / /_/ / / /
|
||||
/_/ \____/_/ |_| /_/ /_/ |_/\____/ /_/
|
||||
|
||||
#First scan the ports, and stress the available ones.
|
||||
1738 justine@portnut > echo "GET / HTTP/1.1" | target/release/portnut -a 127.0.0.1 -p 8080 -w 30 -s -c 100
|
||||
Scanning 127.0.0.1
|
||||
TCP/8080 => ACCEPT
|
||||
|
||||
Stressing 127.0.0.1 using 100 concurrent threads per port for 30s
|
||||
Stressing 127.0.0.1 using 5 concurrent threads per port for 2s
|
||||
|
||||
TOTAL 20
|
||||
OK 20
|
||||
NOK 0
|
||||
Got 100% of OK
|
||||
Mean answer time : 512ms
|
||||
```
|
||||
|
||||
## HTTP Stress
|
||||
HTTP stress performs a GET on the given address.
|
||||
|
||||
```
|
||||
1257 justine > portnut httpstress -a http://localhost:8080 --duration 5
|
||||
____ ____ ____ _______ ____ ________
|
||||
/ __ \/ __ \/ __ \/_ __/ | / / / / /_ __/
|
||||
/ /_/ / / / / /_/ / / / / |/ / / / / / /
|
||||
/ ____/ /_/ / _, _/ / / / /| / /_/ / / /
|
||||
/_/ \____/_/ |_| /_/ /_/ |_/\____/ /_/
|
||||
|
||||
Threads starting their 5s run...
|
||||
over !
|
||||
TOTAL 809
|
||||
OK 809
|
||||
NOK 0
|
||||
Got 100% of OK
|
||||
Mean answer time : 5ms
|
||||
```
|
||||
|
||||
## More ?
|
||||
|
||||
See the help :
|
||||
```
|
||||
1648 justine@portnut > target/release/portnut -h
|
||||
A simple TCP port scanner / stresser. If stressing, you can pass a payload via a pipe
|
||||
A simple TCP/HTTP port scanner / stresser. If stressing, you can pass a payload via a pipe
|
||||
|
||||
Usage: portnut [OPTIONS] --address <ADDRESS>
|
||||
Usage: portnut [OPTIONS] --address <ADDRESS> --ports <PORTS>... <MODE>
|
||||
|
||||
Arguments:
|
||||
<MODE> Mode of use : either tcpstress, tcpscan or httpstress
|
||||
|
||||
Options:
|
||||
-a, --address <ADDRESS> IP address to scan
|
||||
-a, --address <ADDRESS> IP address or hostname to scan - or url if using http
|
||||
-t, --timeout <TIMEOUT> Timeout for each connection in seconds [default: 1]
|
||||
-w, --wait <WAIT> Number of milliseconds to wait in between scans when scanning OR duration of stress when stress testing (in seconds) [default: 30]
|
||||
-w, --wait <WAIT> Number of milliseconds to wait in between scans or requests [default: 30]
|
||||
-d, --duration <DURATION> Duration of tcp stress test in seconds, default 30 [default: 30]
|
||||
-p, --ports <PORTS>... Ports to stress / scan, separated by commas (22,80)
|
||||
-r, --range Set this flag to treat the ports as a range rather than a list
|
||||
-s, --stress Set this flag to stress the ports instead of scanning them
|
||||
-c, --cthreads <CTHREADS> How many threads per port when stressing (Concurrent Threads) [default: 5]
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
|
||||
```
|
||||
|
70
src/http.rs
Normal file
70
src/http.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use std::thread;
|
||||
use reqwest;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::sync::mpsc;
|
||||
|
||||
use crate::results::*;
|
||||
|
||||
pub fn http_stress(url: String, interval: Duration, sleep: Duration, threads: u32, timeout: Duration) -> std::io::Result<()> {
|
||||
|
||||
let mut handles = vec![];
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
println!("Threads starting their {:?} run...", interval);
|
||||
|
||||
for _i in 0..=threads {
|
||||
let add = url.clone();
|
||||
let end_time = Instant::now() + interval;
|
||||
let wait = sleep.clone();
|
||||
let tx2 = tx.clone();
|
||||
let delay = timeout.clone();
|
||||
|
||||
|
||||
|
||||
handles.push(thread::spawn( move || {
|
||||
loop {
|
||||
if Instant::now() >= end_time { break; }
|
||||
|
||||
let b4 = Instant::now();
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let resp = client.get(add.clone()).timeout(delay).send();
|
||||
let time = Instant::now() - b4;
|
||||
match resp {
|
||||
Ok(_) => {
|
||||
let myres = StressResult { time: time, ok: true, rtype: ResType::Http };
|
||||
let _ = tx2.send(myres);
|
||||
//println!("Got an answer for {} in {:?} in thread {}", add, time, i);
|
||||
},
|
||||
Err(_) => {
|
||||
let myres = StressResult { time: time, ok: false, rtype: ResType::Http };
|
||||
let _ = tx2.send(myres);
|
||||
//println!("No answer for {} after {:?} in thread {}", add, time, i);
|
||||
},
|
||||
}
|
||||
thread::sleep(wait);
|
||||
}
|
||||
drop(tx2);
|
||||
}));
|
||||
}
|
||||
drop(tx);
|
||||
|
||||
for handle in handles {
|
||||
let _ = handle.join();
|
||||
}
|
||||
println!("over !");
|
||||
|
||||
//Showing Results
|
||||
//Somehow iterating over never ends
|
||||
let mut res: Vec<StressResult> = vec![];
|
||||
for r in rx.try_iter() {
|
||||
res.push(r);
|
||||
}
|
||||
let lres = ListOfResults { results: res, restype: ResType::Http };
|
||||
lres.show_info();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
155
src/main.rs
155
src/main.rs
@ -1,10 +1,17 @@
|
||||
use clap::Parser;
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, Read};
|
||||
use std::net::{SocketAddr, TcpStream};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::thread;
|
||||
use atty::Stream;
|
||||
use std::time::{Duration};
|
||||
|
||||
mod tcp;
|
||||
|
||||
use tcp::tcp_scan;
|
||||
use tcp::tcp_stress;
|
||||
|
||||
mod http;
|
||||
use http::http_stress;
|
||||
|
||||
mod results;
|
||||
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
@ -12,8 +19,11 @@ fn main() -> std::io::Result<()> {
|
||||
let address = args.address;
|
||||
let timeout = Duration::from_secs(args.timeout);
|
||||
let sleep = Duration::from_millis(args.wait);
|
||||
let ports = args.ports;
|
||||
let duration = Duration::from_secs(args.duration);
|
||||
let ports = handle_ports(args.ports.clone(), &args.range);
|
||||
let threads = args.cthreads;
|
||||
|
||||
print_banner();
|
||||
|
||||
//Reading the payload from stdin (if applicable)
|
||||
let mut payload = String::new();
|
||||
@ -25,101 +35,88 @@ fn main() -> std::io::Result<()> {
|
||||
payload = "SAKAMOTO".to_string();
|
||||
}
|
||||
|
||||
if args.stress {
|
||||
tcp_stress(payload, address, timeout, sleep, ports, threads)?;
|
||||
match args.mode.as_str() {
|
||||
"tcpstress" => {
|
||||
println!("===== TCP STRESS TEST =====");
|
||||
tcp_stress(payload, address, timeout, duration, ports, threads)?;
|
||||
return Ok(());
|
||||
}
|
||||
"tcpscan" => {
|
||||
println!("===== TCP SCAN =====");
|
||||
tcp_scan(address, timeout, sleep, ports)?;
|
||||
return Ok(());
|
||||
}
|
||||
"httpstress" => {
|
||||
println!("===== HTTP STRESS TEST =====");
|
||||
http_stress(address, duration, sleep, threads, timeout)?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
panic!("Mode unkown ! See the help.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Returns a correct list of ports, according to range.
|
||||
//If range is true, we send a range of ports. Otherwise
|
||||
//we send the original back
|
||||
fn handle_ports(ports: Vec<u32>, range: &bool) -> Vec<u32> {
|
||||
if *range {
|
||||
if ports.iter().count() != 2 {
|
||||
panic!("A range must be given only a start and an end value.");
|
||||
}
|
||||
let ret: Vec<u32> = (ports[0]..ports[1]).collect();
|
||||
ret
|
||||
} else {
|
||||
tcp_scan(address, timeout, sleep, ports)?;
|
||||
ports
|
||||
}
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
///Scan the ports on address by attempting a tcp connection.
|
||||
fn tcp_scan(address: String, timeout: Duration, sleep: Duration, ports: Vec<u32>) -> std::io::Result<()> {
|
||||
println!("Scanning {}", address);
|
||||
fn print_banner() {
|
||||
let lines = [
|
||||
" ____ ____ ____ _______ ____ ________",
|
||||
" / __ \\/ __ \\/ __ \\/_ __/ | / / / / /_ __/",
|
||||
" / /_/ / / / / /_/ / / / / |/ / / / / / / ",
|
||||
" / ____/ /_/ / _, _/ / / / /| / /_/ / / / ",
|
||||
"/_/ \\____/_/ |_| /_/ /_/ |_/\\____/ /_/ ",
|
||||
];
|
||||
|
||||
for i in ports {
|
||||
let socket = format!("{}:{}", &address, i);
|
||||
let socket = socket.parse::<SocketAddr>().unwrap();
|
||||
match TcpStream::connect_timeout(&socket, timeout) {
|
||||
Ok(mut s) => {
|
||||
println!("TCP/{} => ACCEPT", i);
|
||||
s.write(b"Some padding")?;
|
||||
}
|
||||
Err(_) => {
|
||||
println!("TCP/{} => REJECT", i);
|
||||
}
|
||||
}
|
||||
|
||||
thread::sleep(sleep.clone());
|
||||
//stream.write(b"Some great padding")?;
|
||||
//stream.read(&mut [0; 128])?;
|
||||
for line in lines {
|
||||
println!("{}", line);
|
||||
}
|
||||
Ok(())
|
||||
println!("");
|
||||
}
|
||||
|
||||
///Try to stress the remote machine by attempting to every given port at once and sending random
|
||||
///data
|
||||
fn tcp_stress(payload: String, address: String, timeout: Duration, interval: Duration, ports: Vec<u32>, threads: u32) -> std::io::Result<()> {
|
||||
let mut handles = vec![];
|
||||
|
||||
for port in ports {
|
||||
tcp_scan(address.clone(), timeout, interval, vec![port])?;
|
||||
let mut threads_left = threads;
|
||||
|
||||
loop {
|
||||
let add = address.clone();
|
||||
let pay = payload.clone();
|
||||
let int = interval * 1000;
|
||||
let end_time = Instant::now() + int;
|
||||
|
||||
|
||||
handles.push(thread::spawn( move || {
|
||||
let socket = format!("{}:{}", &add, &port);
|
||||
let socket = socket.parse::<SocketAddr>().unwrap();
|
||||
loop {
|
||||
//Check if it is time to stop
|
||||
if Instant::now() >= end_time { break; }
|
||||
match TcpStream::connect_timeout(&socket, timeout) {
|
||||
Ok(mut s) => {
|
||||
s.write(pay.as_bytes()).unwrap();
|
||||
s.flush().unwrap();
|
||||
//s.read(&mut [0; 128]).unwrap();
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
},
|
||||
Err(_) => (),
|
||||
}
|
||||
}
|
||||
}));
|
||||
*&mut threads_left -=1;
|
||||
if threads_left == 0 { break; }
|
||||
}
|
||||
}
|
||||
println!("\nStressing {} using {} concurrent threads per port for {:?} \n", address, threads, interval * 1000);
|
||||
for handle in handles {
|
||||
let _ = handle.join();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///A simple TCP port scanner / stresser.
|
||||
///A simple TCP/HTTP port scanner / stresser.
|
||||
///If stressing, you can pass a payload via a pipe.
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(author = "Squip", version, long_about = None)]
|
||||
struct Args {
|
||||
///IP address to scan
|
||||
///Mode of use : either tcpstress, tcpscan or httpstress
|
||||
mode: String,
|
||||
///IP address or hostname to scan - or url if using http
|
||||
///ex of address : 127.0.0.1
|
||||
///ex of url : http://example.org
|
||||
#[arg(short, long)]
|
||||
address: String,
|
||||
///Timeout for each connection in seconds
|
||||
#[arg(short, long, default_value_t = 1)]
|
||||
///Timeout for each connection in seconds, default 30
|
||||
#[arg(short, long, default_value_t = 30)]
|
||||
timeout: u64,
|
||||
///Number of milliseconds to wait in between scans when scanning
|
||||
///OR duration of stress when stress testing (in seconds)
|
||||
///Number of milliseconds to wait in between scans or requests
|
||||
#[arg(short, long, default_value_t = 30)]
|
||||
wait: u64,
|
||||
///Duration of tcp stress test in seconds, default 30
|
||||
#[arg(short, long, default_value_t = 30)]
|
||||
duration: u64,
|
||||
///Ports to stress / scan, separated by commas (22,80)
|
||||
#[arg(short, long, value_parser, num_args=1.., value_delimiter=',')]
|
||||
#[arg(short, long, value_parser, num_args=0.., value_delimiter=',')]
|
||||
ports: Vec<u32>,
|
||||
///Set this flag to treat the ports as a range rather than a list
|
||||
#[arg(long, short, action, default_value_t = false)]
|
||||
range: bool,
|
||||
///Set this flag to stress the ports instead of scanning them
|
||||
#[arg(long, short, action, default_value_t = false)]
|
||||
stress: bool,
|
||||
|
111
src/results.rs
Normal file
111
src/results.rs
Normal file
@ -0,0 +1,111 @@
|
||||
use std::time::Duration;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StressResult {
|
||||
///How long did it take
|
||||
pub time: Duration,
|
||||
///Did we get an answer
|
||||
pub ok: bool,
|
||||
pub rtype: ResType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ResType {
|
||||
Tcp(u32),
|
||||
Http,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ListOfResults {
|
||||
pub results: Vec<StressResult>,
|
||||
pub restype: ResType,
|
||||
}
|
||||
|
||||
impl ListOfResults {
|
||||
fn compute_ratio(&self) {
|
||||
let mut ok: u64 = 0;
|
||||
let mut nok: u64 = 0;
|
||||
for r in self.results.clone() {
|
||||
if r.ok == true {
|
||||
*&mut ok += 1;
|
||||
} else {
|
||||
*&mut nok += 1;
|
||||
}
|
||||
}
|
||||
let mut compute = ok + nok;
|
||||
println!("TOTAL {}\n\tOK {}\n\tNOK {}", compute, ok, nok);
|
||||
if compute < 1 { compute = 1; }
|
||||
compute = ok * 100 / compute;
|
||||
println!("Got {}% of OK\n", compute );
|
||||
}
|
||||
|
||||
///Get the different TCP ports from the results
|
||||
fn get_ports(&self) -> Vec<u32> {
|
||||
let mut ports = vec![];
|
||||
|
||||
for r in &self.results {
|
||||
match r.rtype {
|
||||
ResType::Tcp(p) => {
|
||||
if !ports.contains(&p) {
|
||||
ports.push(p);
|
||||
}
|
||||
},
|
||||
ResType::Http => (),
|
||||
}
|
||||
}
|
||||
ports
|
||||
}
|
||||
|
||||
///Show info, by port if we are in TCP mode
|
||||
pub fn show_info(&self) {
|
||||
|
||||
println!("\n===== RESULTS =====");
|
||||
|
||||
match &self.restype {
|
||||
ResType::Tcp(_) => {
|
||||
let ports = self.get_ports();
|
||||
|
||||
for port in ports {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for res in &self.results {
|
||||
match res.rtype {
|
||||
ResType::Tcp(v) => {
|
||||
if v == port { *&mut results.push(res.clone()); }
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
let list = ListOfResults { results: results, restype: ResType::Tcp(1) };
|
||||
println!("=====> PORT {}", port);
|
||||
list.show_mean_time();
|
||||
list.compute_ratio();
|
||||
}
|
||||
},
|
||||
ResType::Http => {
|
||||
self.show_mean_time();
|
||||
self.compute_ratio();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn show_mean_time(&self) {
|
||||
let mut total: u128 = 0;
|
||||
let mut acc: u128 = 0;
|
||||
|
||||
for i in &self.results {
|
||||
if i.ok {
|
||||
*&mut total += 1;
|
||||
*&mut acc += i.time.as_millis();
|
||||
}
|
||||
}
|
||||
if total == 0 { total += 1 };
|
||||
let restime = acc / total;
|
||||
println!("Average response time : {:?}", Duration::from_millis(restime.try_into().unwrap()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
126
src/tcp.rs
Normal file
126
src/tcp.rs
Normal file
@ -0,0 +1,126 @@
|
||||
use std::io::prelude::*;
|
||||
use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::thread;
|
||||
use std::io::BufReader;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use crate::results::*;
|
||||
|
||||
|
||||
///Scan the ports on address by attempting a tcp connection.
|
||||
pub fn tcp_scan(address: String, timeout: Duration, sleep: Duration, ports: Vec<u32>) -> std::io::Result<()> {
|
||||
println!("Scanning {}", address);
|
||||
|
||||
for i in ports {
|
||||
let socket = resolve_add(&address.as_str(), &i);
|
||||
match TcpStream::connect_timeout(&socket, timeout) {
|
||||
Ok(_) => {
|
||||
println!("TCP/{} => ACCEPT", i);
|
||||
//s.write(b"Some padding")?;
|
||||
}
|
||||
Err(_) => {
|
||||
println!("TCP/{} => REJECT", i);
|
||||
}
|
||||
}
|
||||
|
||||
thread::sleep(sleep.clone());
|
||||
//stream.write(b"Some great padding")?;
|
||||
//stream.read(&mut [0; 128])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///Takes either an hostname or an IP address and port, and resolve to a socket address.
|
||||
///DNS recordings can lead to multiple entries : we take the first one.
|
||||
fn resolve_add(host: &str, port: &u32) -> SocketAddr {
|
||||
let details = format!("{}:{}", host, port);
|
||||
let server: Vec<_> = details
|
||||
.to_socket_addrs()
|
||||
.expect("Can't resolve your address")
|
||||
.collect();
|
||||
return server[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
///Try to stress the remote machine by attempting to every given port at once and sending payload
|
||||
pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval: Duration, ports: Vec<u32>, threads: u32) -> std::io::Result<()> {
|
||||
let mut handles = vec![];
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
for port in ports {
|
||||
let mut threads_left = threads;
|
||||
let tx2 = tx.clone();
|
||||
|
||||
loop {
|
||||
let add = address.clone();
|
||||
let pay = payload.clone();
|
||||
let int = interval;
|
||||
let end_time = Instant::now() + int;
|
||||
let tx3 = tx2.clone();
|
||||
//pay.push_str("\r\n");
|
||||
|
||||
|
||||
handles.push(thread::spawn( move || {
|
||||
let socket = resolve_add(&add.as_str(), &port);
|
||||
loop {
|
||||
//Check if it is time to stop
|
||||
if Instant::now() >= end_time { break; }
|
||||
|
||||
let b4 = Instant::now();
|
||||
match TcpStream::connect_timeout(&socket, timeout) {
|
||||
Ok(mut s) => {
|
||||
//Remote port answers
|
||||
//Writing
|
||||
s.write_all(pay.as_bytes()).unwrap();
|
||||
s.flush().unwrap();
|
||||
|
||||
//Reading
|
||||
s.set_read_timeout(Some(Duration::from_millis(500))).unwrap();
|
||||
let mut reader = BufReader::new(s.try_clone().unwrap());
|
||||
let mut answer = String::new();
|
||||
let count = reader.read_line(&mut answer).unwrap_or(0);
|
||||
if count > 0 {
|
||||
println!("Read {} bytes for port {} -> {}", count, &port, answer);
|
||||
}
|
||||
|
||||
let time = Instant::now() - b4;
|
||||
let myres = StressResult { time: time, ok: true, rtype: ResType::Tcp(port.clone()) };
|
||||
let _ = tx3.send(myres);
|
||||
|
||||
//Sleeping
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
|
||||
},
|
||||
Err(_) => {
|
||||
let time = Instant::now() - b4;
|
||||
let myres = StressResult { time: time, ok: false, rtype: ResType::Tcp(port.clone()) };
|
||||
let _ = tx3.send(myres);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
*&mut threads_left -=1;
|
||||
if threads_left == 0 { break; }
|
||||
}
|
||||
}
|
||||
drop(tx);
|
||||
println!("Stressing {} using {} concurrent threads per port for {:?} \n", address, threads, interval);
|
||||
|
||||
for handle in handles {
|
||||
let _ = handle.join();
|
||||
}
|
||||
|
||||
let mut res: Vec<StressResult> = vec![];
|
||||
for r in rx.try_iter() {
|
||||
res.push(r);
|
||||
}
|
||||
let listofres = ListOfResults { results: res, restype: ResType::Tcp(1) };
|
||||
listofres.show_info();
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user