diff --git a/Cargo.toml b/Cargo.toml index edaa941..df10a51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" clap = { version = "4.5.4", features = ["derive"] } dns-lookup = "2.0.4" futures = "0.3.32" +indicatif = "0.18.4" reqwest = { version = "0.12.4", features = ["blocking"] } tokio = { version = "1.52.3", features = ["full"] } trust-dns-resolver = "0.23.2" diff --git a/src/main.rs b/src/main.rs index cabe945..685bea1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ use clap::Parser; use futures::{stream, StreamExt}; +use indicatif::ProgressBar; +use indicatif::ProgressStyle; use reqwest::{self, StatusCode}; use std::fs::File; use std::io::BufWriter; @@ -44,7 +46,7 @@ struct Args { ///input file full of domains formatted to one domain per line. #[arg(short, long)] - domainfile: Option, + indomainfile: Option, } async fn try_sub( @@ -53,6 +55,7 @@ async fn try_sub( tx: Sender, output: bool, resolver: Arc, + pb: Arc, ) { let mut ips = Vec::new(); if let Ok(ipv4s) = resolver.ipv4_lookup(&domain).await { @@ -93,11 +96,12 @@ async fn try_sub( eprintln!("error sending output! {}", e); } } - println!("{} {}", domain, ips.join(", ")); + pb.println(&format!("{} {}", domain, ips.join(", "))); } + pb.inc(1); } -async fn try_dir(url: String, tx: Sender, output: bool) { +async fn try_dir(url: String, tx: Sender, output: bool, pb: Arc) { let resp_stat = reqwest::get(&encode(&url).to_string()).await; if resp_stat.is_ok() { let resp = resp_stat.unwrap().status(); @@ -111,7 +115,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::ACCEPTED => { if output { @@ -122,7 +126,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::CONTINUE => { if output { @@ -133,7 +137,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::CREATED => { if output { @@ -144,7 +148,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::FOUND => { if output { @@ -155,7 +159,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::IM_A_TEAPOT => { if output { @@ -166,7 +170,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("And what a beautiful teapot you are {}", url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::MOVED_PERMANENTLY => { if output { @@ -177,7 +181,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::PERMANENT_REDIRECT => { if output { @@ -188,7 +192,7 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } StatusCode::TEMPORARY_REDIRECT => { if output { @@ -199,11 +203,12 @@ async fn try_dir(url: String, tx: Sender, output: bool) { eprintln!("error sending output! {}", e); } } - println!("{} {}", resp, url); + pb.println(&format!("{} {}", resp, url)); } _ => (), } } + pb.inc(1); } #[tokio::main] @@ -298,7 +303,7 @@ async fn main() { }); } } - if let Some(domain_file) = args.domainfile { + if let Some(domain_file) = args.indomainfile { if let Ok(domain_string) = fs::read_to_string(domain_file) { domain_string.lines().into_iter().for_each(|domain| { targets.push(domain.to_string()); @@ -366,8 +371,8 @@ async fn main() { } } println!("INFO:::loading targets, and wordlists...:::"); - let urls_len = dirs_to_try.len(); - let domains_len = subs_to_try.len(); + let urls_len = dirs_to_try.len() as u64; + let domains_len = subs_to_try.len() as u64; println!( "INFO:::DONE!, {} URLS to try, and {} subdomains to try:::", &urls_len, &domains_len @@ -432,13 +437,22 @@ async fn main() { println!("INFO:::results will be printed to console and not saved...:::"); } }); + let total = urls_len + domains_len; + let pb = Arc::new(ProgressBar::new(total)); + pb.set_style( + ProgressStyle::with_template("[{elapsed_precise}] {bar:40.orange/red} {pos}/{len} ({eta})") + .unwrap(), + ); let resolver = TokioAsyncResolver::tokio(ResolverConfig::default(), opts); let resolver = Arc::new(resolver); + pb.println("starting..."); + pb.force_draw(); let dir_stream = stream::iter(dirs_to_try.into_iter().map(|url| { + let pb = pb.clone(); let tx = tx.clone(); let output = output.clone(); async move { - try_dir(url, tx, output).await; + try_dir(url, tx, output, pb).await; } })); let sub_stream = stream::iter(subs_to_try.into_iter().map(|sub| { @@ -446,8 +460,9 @@ async fn main() { let output = output.clone(); let wc = wild_card_results.clone(); let resolver = resolver.clone(); + let pb = pb.clone(); async move { - try_sub(sub, wc, tx, output, resolver.clone()).await; + try_sub(sub, wc, tx, output, resolver.clone(), pb).await; } })); @@ -461,11 +476,12 @@ async fn main() { .buffer_unordered(concurrency) .collect::>() .await; - println!("INFO:::enumeration finished!:::"); + pb.println("INFO:::enumeration finished!:::"); if output { - println!("INFO:::waiting for output writer to finish...:::"); + pb.println("INFO:::waiting for output writer to finish...:::"); tx.send(OutputMessage::Shutdown).await.unwrap(); } write_handler.await.unwrap(); - println!("INFO:::done bruteforcing, happy hunting!:::"); + pb.println("INFO:::done bruteforcing, happy hunting!:::"); + pb.finish_with_message("Done!"); }