tcp_scanner/
lib.rs

1use tokio::net::TcpStream;
2use tokio::time::{timeout, Duration};
3use futures::stream::FuturesUnordered;
4use futures::StreamExt;
5use std::ops::RangeInclusive;
6
7
8/// Returns true if the port is open; else false
9pub async fn scan_port(ip: &str, port: u16, timeout_ms: u64) -> bool {
10    let addr = format!("{}:{}", ip, port);
11    match timeout(Duration::from_millis(timeout_ms), TcpStream::connect(&addr)).await {
12        Ok(Ok(_)) => true,
13        _ => false,
14    }
15}
16
17
18/// Returns a list of the ports that are open
19pub async fn scan_ports_list(ip: &str, ports: &[u16], timeout_ms: u64) -> Vec<u16> {
20    let mut open_ports = Vec::new();
21    let mut tasks = FuturesUnordered::new();
22
23    let ip_loc = ip.to_string();
24
25    for &port in ports {
26        let ip = ip_loc.clone();
27        tasks.push(async move {
28            if scan_port(&ip, port, timeout_ms).await {
29                Some(port)
30            } else {
31                None
32            }
33        });
34    }
35
36    while let Some(result) = tasks.next().await {
37        if let Some(port) = result {
38            open_ports.push(port);
39        }
40    }
41    open_ports
42}
43
44
45/// Returns a list of the ports that are open
46pub async fn scan_ports_range(ip: &str, range: RangeInclusive<u16>, timeout_ms: u64) -> Vec<u16> {
47    let mut open_ports = Vec::new();
48    let mut tasks = FuturesUnordered::new();
49
50    let ip_loc = ip.to_string();
51
52    for port in range {
53        let ip = ip_loc.clone();
54        tasks.push(async move {
55            if scan_port(&ip, port, timeout_ms).await {
56                Some(port)
57            } else {
58                None
59            }
60        });
61    }
62
63    while let Some(result) = tasks.next().await {
64        if let Some(port) = result {
65            open_ports.push(port);
66        }
67    }
68    open_ports
69
70}