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, }