I develop penetration testing tools, and I'm still new to rust. but I need some help with getting my application to run asynchronously.
I'm trying to make an application that will read a file line by line and for every line it will use one of the available threads(depending on how many the USER has decided to allocate) to run the vulnerability scan.(I've already written that part and it works fine)
the main issue Im having is that the application will check the same url multiple times on different threads(obv check the same url for the same vulnerability several times isnt very helpful)
I've attached a video basically showing what the application did before hand.(and yes I know that background notepad document is c#. im basing my app off of somebody elses code.)
I have tried almost everything from different threading crates to rewriting the entire thing. I think its more of a logical error where I am just not able to wrap my head around what I actually need to do. so any explanation as to what i need to do would be helpful.
ps I can send full src if that is needed to get me to figure this out. ive been working for 4 days non stop.
full source:
use regex::{self, Regex};
use std::fs::File;
use std::io::{self, BufRead, Read, Split};
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
println!("how many threads: ");
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("failed to read input");
let threads: i32 = input.trim().parse::<i32>().unwrap();
let mut handles = vec![];
let counter = Arc::new(Mutex::new(0));
for _ in 0..threads {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
if let Ok(lines) = read_lines("./urls.txt") {
for line in lines {
if let Ok(ip) = line {
let mut total: i32 = 0;
let s_slice: &str = &*ip;
let re = Regex::new("\"/(.*)").unwrap();
let ip = re.replace_all(s_slice, "/adminer.php").to_string();
let response = reqwest::blocking::get(&ip).unwrap().text().unwrap();
let document = scraper::Html::parse_document(&response);
let title_selector = scraper::Selector::parse("span.version").unwrap();
let versions = document.select(&title_selector).map(|x| x.inner_html());
// versions.for_each(|ip| println!("{ip} | Is vulnerable: xxx, total: {total}"));
for version in versions {
let version2: i32 = version.replace(".", "").parse().unwrap();
if version2 < 463 {
total += 1;
println!(
"Url: {} | {} | is vulnerable: True | total: {}",
&ip, version2, total
);
} else {
println!(
"Url: {} | {} | is vulnerable: False | total: {total}",
&ip, version2
);
}
}
}
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
return;
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}