turboscan 0.1.4

A fast and reliable Rust-based port scanner CLI.
use dns_lookup::lookup_host;
use indicatif::{ProgressBar, ProgressStyle};
use std::io::ErrorKind;
use std::net::{IpAddr, SocketAddr, TcpStream};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use threadpool::ThreadPool;

const SOCKET_TIMEOUT_DEFAUT: Duration = Duration::from_secs(1);

pub fn scan_for_ports(host: String, start_port: u16, end_port: u16, concurrency: usize) {
    let ip_opt = lookup_host(&host)
        .ok()
        .and_then(|ips| ips.into_iter().next())
        .or_else(|| {
            println!("Error: Failed to lookup host or no IP address found.");
            None
        });

    if ip_opt.is_none() {
        return;
    }

    let ip = ip_opt.unwrap();
    println!("Target IP:: {:?} \n", ip);

    let queue_size = (end_port - start_port + 1) as usize;

    let pb = ProgressBar::new(queue_size as u64)
        .with_style(
            ProgressStyle::with_template(
                "{prefix:.yellow.bold} {msg:.cyan.dim} [{elapsed_precise:.green}] {wide_bar:.cyan/blue} {pos:>7}/{len:7}",
            )
            .unwrap()
            .progress_chars("=> "),
        )
    .with_prefix("⚡️TurboScan")
    .with_message("Scanning ports...");

    let num_threads = concurrency;
    let pool = ThreadPool::new(num_threads);

    let discovered_ports: Arc<Mutex<Vec<u16>>> = Arc::new(Mutex::new(Vec::new()));

    for port in start_port..=end_port {
        let pb = pb.clone();
        let discovered_ports = Arc::clone(&discovered_ports);

        pool.execute(move || {
            portscan(port, ip, discovered_ports);
            pb.inc(1);
        });
    }

    pool.join();
    pb.finish();

    let values = discovered_ports.lock().unwrap();
    println!("Discovered ports: {:?}", *values);
}

fn portscan(port: u16, target_ip: IpAddr, discovered_ports: Arc<Mutex<Vec<u16>>>) {
    let addr = SocketAddr::new(target_ip, port);

    match TcpStream::connect_timeout(&addr, SOCKET_TIMEOUT_DEFAUT) {
        Ok(_stream) => {
            // println!("Port {} is open", port);
            let mut values = discovered_ports.lock().unwrap();
            values.push(port);
        }
        Err(ref e) if e.kind() == ErrorKind::ConnectionRefused => (),
        Err(ref e) if e.kind() == ErrorKind::TimedOut => (),
        Err(e) => eprintln!("Error: P: {}, {:?}", port, e),
    }
}