tcp-scanner 0.1.0

A very simplistic port scanner
Documentation
use tokio::net::TcpStream;
use tokio::time::{timeout, Duration};
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use std::ops::RangeInclusive;


/// Returns true if the port is open; else false
pub async fn scan_port(ip: &str, port: u16, timeout_ms: u64) -> bool {
    let addr = format!("{}:{}", ip, port);
    match timeout(Duration::from_millis(timeout_ms), TcpStream::connect(&addr)).await {
        Ok(Ok(_)) => true,
        _ => false,
    }
}


/// Returns a list of the ports that are open
pub async fn scan_ports_list(ip: &str, ports: &[u16], timeout_ms: u64) -> Vec<u16> {
    let mut open_ports = Vec::new();
    let mut tasks = FuturesUnordered::new();

    let ip_loc = ip.to_string();

    for &port in ports {
        let ip = ip_loc.clone();
        tasks.push(async move {
            if scan_port(&ip, port, timeout_ms).await {
                Some(port)
            } else {
                None
            }
        });
    }

    while let Some(result) = tasks.next().await {
        if let Some(port) = result {
            open_ports.push(port);
        }
    }
    open_ports
}


/// Returns a list of the ports that are open
pub async fn scan_ports_range(ip: &str, range: RangeInclusive<u16>, timeout_ms: u64) -> Vec<u16> {
    let mut open_ports = Vec::new();
    let mut tasks = FuturesUnordered::new();

    let ip_loc = ip.to_string();

    for port in range {
        let ip = ip_loc.clone();
        tasks.push(async move {
            if scan_port(&ip, port, timeout_ms).await {
                Some(port)
            } else {
                None
            }
        });
    }

    while let Some(result) = tasks.next().await {
        if let Some(port) = result {
            open_ports.push(port);
        }
    }
    open_ports

}