Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<String>,

/// 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,
}
Expand Down
8 changes: 1 addition & 7 deletions src/gui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
Expand All @@ -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))
Expand Down Expand Up @@ -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;
Expand Down
51 changes: 27 additions & 24 deletions src/hostmapper/mod.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -29,33 +31,34 @@ 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()
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len}")?
.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 {:?}",
Expand Down
22 changes: 12 additions & 10 deletions src/tinyscanner/mod.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand Down Expand Up @@ -136,22 +138,19 @@ fn process_sniffer_packet(
state: &Arc<DashMap<u16, oneshot::Sender<&'static str>>>,
) {
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.
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading