This commit is contained in:
@ -47,4 +47,3 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --release
|
run: cargo build --release
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ Portnut is a port stressing / scanning multithreaded utility. It can handle raw
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
* Make a distributed version that allows stressing from multiple computers at the same time
|
* Make a distributed version that allows stressing from multiple computers at the same time
|
||||||
* When TCP stress testing, show results for each port.
|
|
||||||
* Return more stats (low 1%, high 1%)
|
* Return more stats (low 1%, high 1%)
|
||||||
* Automated releases
|
* Automated releases
|
||||||
|
|
||||||
|
15
src/http.rs
15
src/http.rs
@ -5,12 +5,6 @@ use std::sync::mpsc;
|
|||||||
|
|
||||||
use crate::results::*;
|
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<()> {
|
pub fn http_stress(url: String, interval: Duration, sleep: Duration, threads: u32) -> std::io::Result<()> {
|
||||||
|
|
||||||
let mut handles = vec![];
|
let mut handles = vec![];
|
||||||
@ -18,7 +12,7 @@ pub fn http_stress(url: String, interval: Duration, sleep: Duration, threads: u3
|
|||||||
|
|
||||||
println!("Threads starting their {:?} run...", interval);
|
println!("Threads starting their {:?} run...", interval);
|
||||||
|
|
||||||
for i in 0..=threads {
|
for _i in 0..=threads {
|
||||||
let add = url.clone();
|
let add = url.clone();
|
||||||
let end_time = Instant::now() + interval;
|
let end_time = Instant::now() + interval;
|
||||||
let wait = sleep.clone();
|
let wait = sleep.clone();
|
||||||
@ -35,12 +29,12 @@ pub fn http_stress(url: String, interval: Duration, sleep: Duration, threads: u3
|
|||||||
let time = Instant::now() - b4;
|
let time = Instant::now() - b4;
|
||||||
match resp {
|
match resp {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let myres = StressResult { time: time, thread: i, ok: true };
|
let myres = StressResult { time: time, ok: true, rtype: ResType::Http };
|
||||||
let _ = tx2.send(myres);
|
let _ = tx2.send(myres);
|
||||||
//println!("Got an answer for {} in {:?} in thread {}", add, time, i);
|
//println!("Got an answer for {} in {:?} in thread {}", add, time, i);
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let myres = StressResult { time: time, thread: i, ok: false };
|
let myres = StressResult { time: time, ok: false, rtype: ResType::Http };
|
||||||
let _ = tx2.send(myres);
|
let _ = tx2.send(myres);
|
||||||
//println!("No answer for {} after {:?} in thread {}", add, time, i);
|
//println!("No answer for {} after {:?} in thread {}", add, time, i);
|
||||||
},
|
},
|
||||||
@ -63,7 +57,8 @@ pub fn http_stress(url: String, interval: Duration, sleep: Duration, threads: u3
|
|||||||
for r in rx.try_iter() {
|
for r in rx.try_iter() {
|
||||||
res.push(r);
|
res.push(r);
|
||||||
}
|
}
|
||||||
print_results(res);
|
let lres = ListOfResults { results: res, restype: ResType::Http };
|
||||||
|
lres.show_info();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,14 +37,17 @@ fn main() -> std::io::Result<()> {
|
|||||||
|
|
||||||
match args.mode.as_str() {
|
match args.mode.as_str() {
|
||||||
"tcpstress" => {
|
"tcpstress" => {
|
||||||
|
println!("===== TCP STRESS TEST =====");
|
||||||
tcp_stress(payload, address, timeout, duration, ports, threads)?;
|
tcp_stress(payload, address, timeout, duration, ports, threads)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
"tcpscan" => {
|
"tcpscan" => {
|
||||||
|
println!("===== TCP SCAN =====");
|
||||||
tcp_scan(address, timeout, sleep, ports)?;
|
tcp_scan(address, timeout, sleep, ports)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
"httpstress" => {
|
"httpstress" => {
|
||||||
|
println!("===== HTTP STRESS TEST =====");
|
||||||
http_stress(address, duration, sleep, threads)?;
|
http_stress(address, duration, sleep, threads)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,32 @@
|
|||||||
use std::time::Duration;
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StressResult {
|
pub struct StressResult {
|
||||||
///How long did it take
|
///How long did it take
|
||||||
pub time: Duration,
|
pub time: Duration,
|
||||||
///What thread are we from
|
|
||||||
pub thread: u32,
|
|
||||||
///Did we get an answer
|
///Did we get an answer
|
||||||
pub ok: bool,
|
pub ok: bool,
|
||||||
|
pub rtype: ResType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ResType {
|
||||||
|
Tcp(u32),
|
||||||
|
Http,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct ListOfResults {
|
pub struct ListOfResults {
|
||||||
pub results: Vec<StressResult>,
|
pub results: Vec<StressResult>,
|
||||||
|
pub restype: ResType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ListOfResults {
|
||||||
impl IsAResult for ListOfResults {
|
fn compute_ratio(&self) {
|
||||||
fn show_ratio(&self) {
|
|
||||||
let mut ok: u64 = 0;
|
let mut ok: u64 = 0;
|
||||||
let mut nok: u64 = 0;
|
let mut nok: u64 = 0;
|
||||||
for r in &self.results {
|
for r in self.results.clone() {
|
||||||
if r.ok == true {
|
if r.ok == true {
|
||||||
*&mut ok += 1;
|
*&mut ok += 1;
|
||||||
} else {
|
} else {
|
||||||
@ -39,10 +37,60 @@ impl IsAResult for ListOfResults {
|
|||||||
println!("TOTAL {}\n\tOK {}\n\tNOK {}", compute, ok, nok);
|
println!("TOTAL {}\n\tOK {}\n\tNOK {}", compute, ok, nok);
|
||||||
if compute < 1 { compute = 1; }
|
if compute < 1 { compute = 1; }
|
||||||
compute = ok * 100 / compute;
|
compute = ok * 100 / compute;
|
||||||
println!("\tGot {}% of OK", compute );
|
println!("Got {}% of OK\n", compute );
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mean_time(&self) -> Duration {
|
///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 total: u128 = 0;
|
||||||
let mut acc: u128 = 0;
|
let mut acc: u128 = 0;
|
||||||
|
|
||||||
@ -54,13 +102,10 @@ impl IsAResult for ListOfResults {
|
|||||||
}
|
}
|
||||||
if total == 0 { total += 1 };
|
if total == 0 { total += 1 };
|
||||||
let restime = acc / total;
|
let restime = acc / total;
|
||||||
Duration::from_millis(restime.try_into().unwrap())
|
println!("Average response time : {:?}", 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());
|
|
||||||
}
|
|
||||||
|
11
src/tcp.rs
11
src/tcp.rs
@ -50,7 +50,6 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
|||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
for port in ports {
|
for port in ports {
|
||||||
tcp_scan(address.clone(), timeout, Duration::from_millis(100), vec![port])?;
|
|
||||||
let mut threads_left = threads;
|
let mut threads_left = threads;
|
||||||
let tx2 = tx.clone();
|
let tx2 = tx.clone();
|
||||||
|
|
||||||
@ -87,7 +86,7 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
|||||||
}
|
}
|
||||||
|
|
||||||
let time = Instant::now() - b4;
|
let time = Instant::now() - b4;
|
||||||
let myres = StressResult { time: time, thread: port.clone(), ok: true };
|
let myres = StressResult { time: time, ok: true, rtype: ResType::Tcp(port.clone()) };
|
||||||
let _ = tx3.send(myres);
|
let _ = tx3.send(myres);
|
||||||
|
|
||||||
//Sleeping
|
//Sleeping
|
||||||
@ -96,7 +95,7 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
|||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let time = Instant::now() - b4;
|
let time = Instant::now() - b4;
|
||||||
let myres = StressResult { time: time, thread: port.clone(), ok: false };
|
let myres = StressResult { time: time, ok: false, rtype: ResType::Tcp(port.clone()) };
|
||||||
let _ = tx3.send(myres);
|
let _ = tx3.send(myres);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +106,7 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(tx);
|
drop(tx);
|
||||||
println!("\nStressing {} using {} concurrent threads per port for {:?} \n", address, threads, interval);
|
println!("Stressing {} using {} concurrent threads per port for {:?} \n", address, threads, interval);
|
||||||
|
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
let _ = handle.join();
|
let _ = handle.join();
|
||||||
@ -117,7 +116,9 @@ pub fn tcp_stress(payload: String, address: String, timeout: Duration, interval:
|
|||||||
for r in rx.try_iter() {
|
for r in rx.try_iter() {
|
||||||
res.push(r);
|
res.push(r);
|
||||||
}
|
}
|
||||||
print_results(res);
|
let listofres = ListOfResults { results: res, restype: ResType::Tcp(1) };
|
||||||
|
listofres.show_info();
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user