diff --git a/README.md b/README.md
index bfac2d3..f944ade 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
# Portnut
TODO
-* Allow multiple threads hitting on the same port
+* Read the answer and count the number of answers received.
+* Make a distributed version that allows stressing from multiple computers at the same time
Portnut is a tcp port scanner / stresser.
@@ -15,13 +16,11 @@ TCP/8080 => REJECT
TCP/22 => REJECT
#First scan the ports, and stress the available ones.
-justine@portnut > echo "My payload" | target/release/portnut -a 127.0.0.1 -p 22,8080 -w 3 -s
-Scanning 127.0.0.1
-TCP/22 => REJECT
+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...
+Stressing 127.0.0.1 using 100 concurrent threads per port for 30s
```
@@ -33,11 +32,13 @@ A simple TCP port scanner / stresser. If stressing, you can pass a payload via a
Usage: portnut [OPTIONS] --address
Options:
- -a, --address IP address to scan
- -t, --timeout Timeout for each connection in seconds [default: 1]
- -w, --wait Number of milliseconds to wait in between scans when scanning OR duration of stress when stress testing (in seconds) [default: 30]
- -p, --ports ... Ports to stress / scan, separated by commas (22,80)
- -s, --stress Set this flag to stress the ports instead of scanning them
- -h, --help Print help
- -V, --version Print version
+ -a, --address IP address to scan
+ -t, --timeout Timeout for each connection in seconds [default: 1]
+ -w, --wait Number of milliseconds to wait in between scans when scanning OR duration of stress when stress testing (in seconds) [default: 30]
+ -p, --ports ... Ports to stress / scan, separated by commas (22,80)
+ -s, --stress Set this flag to stress the ports instead of scanning them
+ -c, --cthreads How many threads per port when stressing (Concurrent Threads) [default: 5]
+ -h, --help Print help
+ -V, --version Print version
+
```
diff --git a/src/main.rs b/src/main.rs
index eb6f7c2..e867fd3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,6 +13,7 @@ fn main() -> std::io::Result<()> {
let timeout = Duration::from_secs(args.timeout);
let sleep = Duration::from_millis(args.wait);
let ports = args.ports;
+ let threads = args.cthreads;
//Reading the payload from stdin (if applicable)
let mut payload = String::new();
@@ -25,7 +26,7 @@ fn main() -> std::io::Result<()> {
}
if args.stress {
- tcp_stress(payload, address, timeout, sleep, ports)?;
+ tcp_stress(payload, address, timeout, sleep, ports, threads)?;
} else {
tcp_scan(address, timeout, sleep, ports)?;
}
@@ -59,36 +60,42 @@ fn tcp_scan(address: String, timeout: Duration, sleep: Duration, ports: Vec
///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) -> std::io::Result<()> {
+fn tcp_stress(payload: String, address: String, timeout: Duration, interval: Duration, ports: Vec, threads: u32) -> std::io::Result<()> {
let mut handles = vec![];
for port in ports {
tcp_scan(address.clone(), timeout, interval, vec![port])?;
- let add = address.clone();
- let pay = payload.clone();
- let int = interval * 1000;
- let end_time = Instant::now() + int;
+ 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::().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(_) => (),
+ handles.push(thread::spawn( move || {
+ let socket = format!("{}:{}", &add, &port);
+ let socket = socket.parse::().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...\n");
+ println!("\nStressing {} using {} concurrent threads per port for {:?} \n", address, threads, interval * 1000);
for handle in handles {
let _ = handle.join();
}
@@ -116,4 +123,8 @@ struct Args {
///Set this flag to stress the ports instead of scanning them
#[arg(long, short, action, default_value_t = false)]
stress: bool,
+ ///How many threads per port when stressing
+ ///(Concurrent Threads)
+ #[arg(short, long, default_value_t = 5)]
+ cthreads: u32,
}