Added http mode and results
All checks were successful
Rust-build / build (push) Successful in 2m39s
All checks were successful
Rust-build / build (push) Successful in 2m39s
This commit is contained in:
73
src/http.rs
Normal file
73
src/http.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use std::thread;
|
||||
use reqwest;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::sync::mpsc;
|
||||
|
||||
use crate::results::*;
|
||||
|
||||
fn print_results(res: Vec<StressResult>) {
|
||||
let myres = ListOfResults { results: res };
|
||||
myres.show_ratio();
|
||||
println!("\tMean answer time : {:?}", myres.get_mean_time());
|
||||
}
|
||||
|
||||
pub fn http_stress(url: String, interval: Duration, sleep: Duration, threads: u32) -> 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();
|
||||
|
||||
|
||||
|
||||
handles.push(thread::spawn( move || {
|
||||
loop {
|
||||
if Instant::now() >= end_time { break; }
|
||||
|
||||
let b4 = Instant::now();
|
||||
let resp = reqwest::blocking::get(add.clone());
|
||||
let time = Instant::now() - b4;
|
||||
match resp {
|
||||
Ok(_) => {
|
||||
let myres = StressResult { time: time, thread: i, ok: true };
|
||||
let _ = tx2.send(myres);
|
||||
//println!("Got an answer for {} in {:?} in thread {}", add, time, i);
|
||||
},
|
||||
Err(_) => {
|
||||
let myres = StressResult { time: time, thread: i, ok: false };
|
||||
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);
|
||||
}
|
||||
print_results(res);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
48
src/main.rs
48
src/main.rs
@ -8,12 +8,18 @@ mod tcp;
|
||||
use tcp::tcp_scan;
|
||||
use tcp::tcp_stress;
|
||||
|
||||
mod http;
|
||||
use http::http_stress;
|
||||
|
||||
mod results;
|
||||
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let args = Args::parse();
|
||||
let address = args.address;
|
||||
let timeout = Duration::from_secs(args.timeout);
|
||||
let sleep = Duration::from_millis(args.wait);
|
||||
let duration = Duration::from_secs(args.duration);
|
||||
let ports = handle_ports(args.ports.clone(), &args.range);
|
||||
let threads = args.cthreads;
|
||||
|
||||
@ -29,13 +35,23 @@ fn main() -> std::io::Result<()> {
|
||||
payload = "SAKAMOTO".to_string();
|
||||
}
|
||||
|
||||
if args.stress {
|
||||
tcp_stress(payload, address, timeout, sleep, ports, threads)?;
|
||||
} else {
|
||||
tcp_scan(address, timeout, sleep, ports)?;
|
||||
match args.mode.as_str() {
|
||||
"tcpstress" => {
|
||||
tcp_stress(payload, address, timeout, duration, ports, threads)?;
|
||||
return Ok(());
|
||||
}
|
||||
"tcpscan" => {
|
||||
tcp_scan(address, timeout, sleep, ports)?;
|
||||
return Ok(());
|
||||
}
|
||||
"httpstress" => {
|
||||
http_stress(address, duration, sleep, threads)?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
panic!("Mode unkown ! See the help.");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
//Returns a correct list of ports, according to range.
|
||||
@ -65,25 +81,33 @@ fn print_banner() {
|
||||
for line in lines {
|
||||
println!("{}", line);
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
|
||||
///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 or hostname to scan
|
||||
///Mode of use : either tcpstress, tcpscan or httpstress
|
||||
mode: String,
|
||||
///IP address or hostname to scan - or url if using http
|
||||
#[arg(short, long)]
|
||||
address: String,
|
||||
///Timeout for each connection in seconds
|
||||
#[arg(short, long, default_value_t = 1)]
|
||||
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)]
|
||||
|
66
src/results.rs
Normal file
66
src/results.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use std::time::Duration;
|
||||
|
||||
///Is implemented for Stress test results.
|
||||
pub trait IsAResult {
|
||||
///A way to return the ratio of hits to nohits (eg: "45% of our requests were answered" or
|
||||
///smth)
|
||||
fn show_ratio(&self);
|
||||
///Return the mean hit time as a Duration
|
||||
fn get_mean_time(&self) -> Duration;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StressResult {
|
||||
///How long did it take
|
||||
pub time: Duration,
|
||||
///What thread are we from
|
||||
pub thread: u32,
|
||||
///Did we get an answer
|
||||
pub ok: bool,
|
||||
}
|
||||
|
||||
pub struct ListOfResults {
|
||||
pub results: Vec<StressResult>,
|
||||
}
|
||||
|
||||
|
||||
impl IsAResult for ListOfResults {
|
||||
fn show_ratio(&self) {
|
||||
let mut ok: u64 = 0;
|
||||
let mut nok: u64 = 0;
|
||||
for r in &self.results {
|
||||
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!("\tGot {}% of OK", compute );
|
||||
}
|
||||
|
||||
fn get_mean_time(&self) -> Duration {
|
||||
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;
|
||||
Duration::from_millis(restime.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn print_results(res: Vec<StressResult>) {
|
||||
let myres = ListOfResults { results: res };
|
||||
myres.show_ratio();
|
||||
println!("\tMean answer time : {:?}", myres.get_mean_time());
|
||||
}
|
33
src/tcp.rs
33
src/tcp.rs
@ -3,6 +3,9 @@ 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.
|
||||
@ -44,16 +47,19 @@ fn resolve_add(host: &str, port: &u32) -> SocketAddr {
|
||||
///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 {
|
||||
tcp_scan(address.clone(), timeout, interval, vec![port])?;
|
||||
tcp_scan(address.clone(), timeout, Duration::from_millis(100), vec![port])?;
|
||||
let mut threads_left = threads;
|
||||
let tx2 = tx.clone();
|
||||
|
||||
loop {
|
||||
let add = address.clone();
|
||||
let pay = payload.clone();
|
||||
let int = interval * 1000;
|
||||
let int = interval;
|
||||
let end_time = Instant::now() + int;
|
||||
let tx3 = tx2.clone();
|
||||
//pay.push_str("\r\n");
|
||||
|
||||
|
||||
@ -62,6 +68,8 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
||||
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
|
||||
@ -78,11 +86,19 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
||||
println!("Read {} bytes for port {} -> {}", count, &port, answer);
|
||||
}
|
||||
|
||||
let time = Instant::now() - b4;
|
||||
let myres = StressResult { time: time, thread: port.clone(), ok: true };
|
||||
let _ = tx3.send(myres);
|
||||
|
||||
//Sleeping
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
|
||||
},
|
||||
Err(_) => (),
|
||||
Err(_) => {
|
||||
let time = Instant::now() - b4;
|
||||
let myres = StressResult { time: time, thread: port.clone(), ok: false };
|
||||
let _ = tx3.send(myres);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
@ -90,10 +106,19 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
||||
if threads_left == 0 { break; }
|
||||
}
|
||||
}
|
||||
println!("\nStressing {} using {} concurrent threads per port for {:?} \n", address, threads, interval * 1000);
|
||||
drop(tx);
|
||||
println!("\nStressing {} 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);
|
||||
}
|
||||
print_results(res);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user