diff --git a/src/cli.rs b/src/cli.rs index df95db5..28fd08c 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,8 +9,6 @@ use crate::hostmapper::localnet::get_localnet; name = "pentestkit", version = "0.1.0", about = "Welcome to PentestKit, High-performance pentest toolkit in Rust", - long_about = None, - propagate_version = true, arg_required_else_help = true )] pub struct Cli { @@ -77,27 +75,32 @@ pub struct Cli { short = 's', value_name = "TYPE", default_value = "T", - verbatim_doc_comment + verbatim_doc_comment, + requires = "target" )] pub scan_mode: String, + /// default is logger with info and errors | with it all the loggers work #[arg(short, long)] pub log: bool, - // threads number + /// threads number #[arg(short = 'c', long = "threads", default_value_t = 50)] pub threads: usize, - // extensions + /// extensions #[arg(short = 'x', long)] pub extensions: Option, + /// app gui #[arg(short = 'u', long, conflicts_with_all = ["target", "subnet", "header_url", "dir_url"])] pub gui: bool, + /// verify server name #[arg(short, long)] pub verify: bool, + /// localnet #[arg(long)] pub localnet: bool, } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 6fac778..42aca28 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -138,7 +138,7 @@ impl App for PentestApp { ui.horizontal(|ui| { ui.label("Threads:"); ui.add(egui::Slider::new(&mut cli.threads, 1..=500)); - ui.label("output file:"); + ui.label("|| 📂 Output file:"); let mut output = cli.output.clone().unwrap_or_default(); if ui.text_edit_singleline(&mut output).changed() { cli.output = Some(output); @@ -155,9 +155,6 @@ impl App for PentestApp { { let results_clone = self.results.clone(); let scanning_clone = self.is_scanning.clone(); - // let target_url = self.url.clone(); - // let output_path = cli.output.clone(); - // let active_module_clone = self.active_module; let cli_guard = cli; let target_url = self.url.clone(); @@ -177,8 +174,6 @@ impl App for PentestApp { *scanning_clone.lock() = true; *results_clone.lock() = "Initializing connection...\n".to_string(); - // ##################################### - let run_result = match active_module_clone { ActiveModule::HeaderGrabber => { headergrabber::run(&target_url, &output_path, Some(tx_clone)) @@ -276,7 +271,6 @@ fn render_ansi_text(ui: &mut egui::Ui, text: &str) { ui.horizontal_wrapped(|ui| { ui.spacing_mut().item_spacing.x = 0.0; // Remove space between characters for seamless color - // This regex finds ANSI codes like \x1b[31m or \x1b[0m let ansi_re = regex::Regex::new(r"\x1b\[([0-9;]*)m").unwrap(); let mut last_end = 0; diff --git a/src/hostmapper/mod.rs b/src/hostmapper/mod.rs index f889c53..ae5fbc8 100644 --- a/src/hostmapper/mod.rs +++ b/src/hostmapper/mod.rs @@ -1,19 +1,21 @@ -use crate::utils::preluad::*; +use std::net::Ipv4Addr; + use crate::println_tx; +use crate::utils::preluad::*; pub mod localnet; -/// Executes an asynchronous ICMP "Ping Sweep" across a specified IPv4 subnet. -/// -/// This function identifies live hosts by sending ICMP Echo Requests and waiting -/// for Echo Replies. It uses a `JoinSet` to manage concurrency and a `Semaphore` -/// to prevent overwhelming the local network stack. -/// -/// # Arguments -/// * `net` - The CIDR subnet to scan (e.g., 192.168.1.0/24). -/// * `threads` - Maximum number of simultaneous ping requests. -/// * `output_path` - Optional file path to save the list of live hosts. -/// * `tx_ui` - MPSC channel for sending real-time updates to the GUI/CLI. +// / Executes an asynchronous ICMP "Ping Sweep" across a specified IPv4 subnet. +// / +// / This function identifies live hosts by sending ICMP Echo Requests and waiting +// / for Echo Replies. It uses a `JoinSet` to manage concurrency and a `Semaphore` +// / to prevent overwhelming the local network stack. +// / +// / # Arguments +// / * `net` - The CIDR subnet to scan (e.g., 192.168.1.0/24). +// / * `threads` - Maximum number of simultaneous ping requests. +// / * `output_path` - Optional file path to save the list of live hosts. +// / * `tx_ui` - MPSC channel for sending real-time updates to the GUI/CLI. pub async fn run( net: Ipv4Net, threads: usize, @@ -29,7 +31,13 @@ pub async fn run( let client = Client::new(&Config::default())?; let client = Arc::new(client); - let pb: ProgressBar = ProgressBar::new(net.hosts().count() as u64); + let timeout_dur = Duration::from_millis(100); + let network_addr = net.network(); + let broadcast_addr = net.broadcast(); + let start = u32::from(network_addr); + let end = u32::from(broadcast_addr); + + let pb: ProgressBar = ProgressBar::new((end - start + 1) as u64); pb.set_style( ProgressStyle::default_bar() @@ -37,25 +45,20 @@ pub async fn run( .progress_chars("█▓▒░"), ); - for ip in net.hosts() { - while set.len() >= threads { - set.join_next().await; - } - let semaphore_clone = semaphore.clone(); + for i in start..=end { + let ip = Ipv4Addr::from(i); + let permit = semaphore.clone().acquire_owned().await.ok(); let tx_clone = tx.clone(); let client_clone = client.clone(); - // Generate a unique identifier for the ping based on the IP address. - // This helps the surge-ping client match replies to requests. - let ip_u32 = u32::from(ip); - let ident = (ip_u32 & 0xFFFF) as u16; + let ident = (i & 0xFFFF) as u16; let tx_ui_clone = tx_ui.clone(); let pb_clone = pb.clone(); set.spawn(async move { - let _permit = semaphore_clone.acquire_owned().await.ok(); + let _permit = permit; let mut pinger = client_clone.pinger(ip.into(), PingIdentifier(ident)).await; - pinger.timeout(Duration::from_millis(1000)); + pinger.timeout(timeout_dur); if let Result::Ok((_, duration)) = pinger.ping(PingSequence(0), &payload).await { let styled = format!( "{} {:<15} (up) in {:?}", diff --git a/src/tinyscanner/mod.rs b/src/tinyscanner/mod.rs index d6eaa86..58babec 100644 --- a/src/tinyscanner/mod.rs +++ b/src/tinyscanner/mod.rs @@ -1,9 +1,11 @@ +pub mod comman; pub mod dispatcher; pub mod scan_syn; -pub mod comman; - -use crate::{println_tx, utils::{TinyResult, preluad::*}}; +use crate::{ + println_tx, + utils::{TinyResult, preluad::*}, +}; /// The main entry point for the TinyScanner tool. /// @@ -136,22 +138,19 @@ fn process_sniffer_packet( state: &Arc>>, ) { let flags = packet.get_flags(); - if (flags & (TcpFlags::SYN | TcpFlags::ACK | TcpFlags::RST)) != 0 { + if (flags & TcpFlags::ACK) != 0 || (flags & TcpFlags::RST) != 0 { let my_random_port = packet.get_destination(); if let Some((_, tx_result)) = state.remove(&my_random_port) { - let status = if (flags & TcpFlags::SYN) != 0 && (flags & TcpFlags::ACK) != 0 { + let status = if (flags & TcpFlags::SYN) != 0 { "OPEN" - } else if (flags & TcpFlags::RST) != 0 { - "CLOSED" } else { - "FILTERED" + "CLOSED" }; let _ = tx_result.send(status); } } } - /// Collects scan results from the receiver channel and updates the UI progress bar. /// /// Returns a vector of formatted result strings. @@ -177,7 +176,10 @@ async fn collect_and_print_results( println_tx!(tx_ui, debug!, "Port {:<5} is {}", port, status.yellow()); } - results.push(TinyResult { port, state: status_upper }); + results.push(TinyResult { + port, + state: status_upper.split(" ").next().unwrap_or("").to_string(), + }); // results.push(format!("Port {:<5}: {}", port, status_upper)); if pb.position() == total as u64 { break; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 4adfb99..bed9bae 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -215,7 +215,8 @@ pub fn logger(cli: &Cli) { /// Launches the Eframe/Egui native window. /// This fulfills the 'GUI' requirement of the project using hardware acceleration. pub fn start_gui() -> Result<()> { - let options = eframe::NativeOptions::default(); + let mut options = eframe::NativeOptions::default(); + options.centered = true; eframe::run_native( "PentestKit", options,