1use crate::error::Result;
2use crate::ping::{PingResult, PingScanner};
3use crate::scan::{PortResult, PortScanner};
4use serde::Serialize;
5use std::net::IpAddr;
6
7#[derive(Debug, Clone, Serialize)]
8pub struct InspectResult {
9 pub host: String,
10 pub ip: Option<IpAddr>,
11 pub ping: Option<PingResult>,
12 pub ports: Vec<PortResult>,
13 pub open_ports: Vec<PortResult>,
14 pub hostname: Option<String>,
15}
16
17pub struct InspectEngine {
18 ping: PingScanner,
19 scan: PortScanner,
20 ping_timeout_ms: u64,
21 scan_timeout_ms: u64,
22 dns_timeout_ms: u64,
23}
24
25impl InspectEngine {
26 pub fn new(concurrency: usize) -> Self {
27 Self::new_with_timeouts(
28 concurrency,
29 crate::DEFAULT_PING_TIMEOUT_MS,
30 crate::DEFAULT_SCAN_TIMEOUT_MS,
31 crate::DEFAULT_DNS_TIMEOUT_MS,
32 )
33 }
34
35 pub fn new_with_timeouts(
36 concurrency: usize,
37 ping_timeout_ms: u64,
38 scan_timeout_ms: u64,
39 dns_timeout_ms: u64,
40 ) -> Self {
41 let concurrency = concurrency.clamp(1, crate::MAX_CONCURRENCY);
42 Self {
43 ping: PingScanner::new(concurrency),
44 scan: PortScanner::new(concurrency),
45 ping_timeout_ms: ping_timeout_ms.max(1),
46 scan_timeout_ms: scan_timeout_ms.max(1),
47 dns_timeout_ms: dns_timeout_ms.max(1),
48 }
49 }
50
51 pub async fn inspect(&self, host: String, ports: Vec<u16>) -> Result<InspectResult> {
52 if !ports.is_empty() {
57 crate::validate_ports(&ports)?;
58 }
59
60 let ip_for_scan =
61 crate::ops::resolve_host_ip_with_timeout(&host, self.dns_timeout_ms).await?;
62
63 let ping_fut = self.ping.ping(ip_for_scan, self.ping_timeout_ms);
66 let scan_fut = self
67 .scan
68 .scan_host(ip_for_scan, ports, self.scan_timeout_ms);
69 let hostname_fut =
70 crate::dns::reverse_lookup_best_effort_timeout(ip_for_scan, self.dns_timeout_ms);
71
72 let (ping_res, ports_res, hostname) = tokio::join!(ping_fut, scan_fut, hostname_fut);
73
74 let ports = ports_res?;
75 let open_ports = ports.iter().filter(|p| p.open).cloned().collect();
76
77 Ok(InspectResult {
78 host,
79 ip: Some(ip_for_scan),
80 ping: Some(ping_res),
81 ports,
82 open_ports,
83 hostname,
84 })
85 }
86}