1use std::collections::HashSet;
7use std::net::Ipv4Addr;
8use std::sync::{Arc, Mutex};
9use std::time::Duration;
10use tokio::sync::mpsc::{self, channel, Sender};
11use tokio::task::JoinHandle;
12use tokio_util::sync::CancellationToken;
13
14use crate::backend::{BackendConfig, BackendFactory, BackendType};
15use crate::error::AppResult;
16use crate::event::Event;
17use crate::event::ScannerEvent;
18use crate::interface_utils;
19use crate::utils::recover_or_log;
20
21#[cfg(feature = "ebpf-backend")]
22use crate::backend::EbpfBackendFactory;
23use crate::backend::PnetBackendFactory;
24
25mod arp_scanner;
27pub mod arp_validator;
28mod dns_resolver;
29mod gateway;
30pub mod packet_processor;
32pub mod tasks;
33
34pub enum ScannerInputEvent {
36 StartScanning,
37}
38
39pub struct Scanner {
44 scanner_input_tx: Sender<ScannerInputEvent>,
45 scanner_outputs: Sender<Event>,
46 interface_name: String,
47 cancel_token: CancellationToken,
48 task_handles: Vec<JoinHandle<()>>,
49 local_ips: HashSet<Ipv4Addr>,
50 discovered_hosts: Arc<Mutex<HashSet<Ipv4Addr>>>,
51 arp_validator: Arc<Mutex<arp_validator::ArpValidator>>,
53 gateway_ip: Option<Ipv4Addr>,
55}
56
57impl Scanner {
58 pub fn new(
68 scanner_outputs: mpsc::Sender<Event>,
69 interface_name: String,
70 backend_type: BackendType,
71 ) -> AppResult<Self> {
72 let backend_factory: Box<dyn BackendFactory> = match backend_type {
73 BackendType::Pnet => Box::new(PnetBackendFactory),
74 #[cfg(feature = "ebpf-backend")]
75 BackendType::Ebpf => Box::new(EbpfBackendFactory),
76 #[cfg(not(feature = "ebpf-backend"))]
77 BackendType::Ebpf => {
78 return Err("eBPF backend not compiled in. Enable 'ebpf-backend' feature.".into())
79 }
80 };
81 let backend_config = BackendConfig::new(interface_name.clone());
82 let (packet_source, packet_sink) = backend_factory
83 .create(backend_config)
84 .map_err(|e| format!("Failed to create backend: {}", e))?;
85
86 if let Err(e) = scanner_outputs.try_send(Event::Scanner(
87 crate::event::ScannerEvent::InterfaceName(interface_name.clone()),
88 )) {
89 return Err(format!("Failed to send interface name event: {}", e).into());
90 }
91
92 const SCANNER_INPUT_CAPACITY: usize = 100;
93 let (scanner_input_tx, scanner_input_rx) =
94 channel::<ScannerInputEvent>(SCANNER_INPUT_CAPACITY);
95 let cancel_token = CancellationToken::new();
96
97 let local_ips: HashSet<Ipv4Addr> = pnet_datalink::interfaces()
99 .iter()
100 .filter(|nif| {
101 interface_utils::is_interface_active(nif)
102 && interface_utils::interface_matches(nif, &interface_name)
103 })
104 .flat_map(interface_utils::get_interface_ipv4_addrs)
105 .collect();
106
107 let mut scanner = Self {
108 scanner_outputs,
109 scanner_input_tx,
110 interface_name,
111 cancel_token,
112 task_handles: Vec::new(),
113 local_ips,
114 discovered_hosts: Arc::new(Mutex::new(HashSet::new())),
115 arp_validator: Arc::new(Mutex::new(arp_validator::ArpValidator::new(
119 Duration::from_secs(15),
120 ))),
121 gateway_ip: gateway::detect_default_gateway(),
123 };
124
125 if let Some(gw) = scanner.gateway_ip {
127 tracing::info!("Detected default gateway: {}", gw);
128 } else {
129 tracing::info!("No default gateway detected (may be expected in some environments)");
130 }
131
132 for local_ip in &scanner.local_ips {
135 let local_host = crate::host::Host {
136 ipv4: *local_ip,
137 mac: crate::types::MacAddr::default(),
138 hostname: None,
139 time: chrono::Local::now(),
140 speed: None,
141 };
142 if let Err(e) = scanner
143 .scanner_outputs
144 .try_send(Event::Scanner(ScannerEvent::HostFound(local_host)))
145 {
146 tracing::warn!(
147 "Failed to send HostFound event for local IP {}: {}",
148 local_ip,
149 e
150 );
151 }
152 }
153
154 let listener_handles = tasks::start_listening(
156 packet_source,
157 scanner.scanner_outputs.clone(),
158 scanner.local_ips.clone(),
159 scanner.discovered_hosts.clone(),
160 Arc::clone(&scanner.arp_validator),
161 scanner.gateway_ip,
162 scanner.cancel_token.clone(),
163 );
164 scanner.task_handles.extend(listener_handles);
165
166 let tx_handle = tasks::start_tx_worker(
167 scanner_input_rx,
168 packet_sink,
169 scanner.interface_name.clone(),
170 scanner.scanner_outputs.clone(),
171 Arc::clone(&scanner.arp_validator),
172 scanner.cancel_token.clone(),
173 );
174 scanner.task_handles.push(tx_handle);
175
176 Ok(scanner)
177 }
178
179 pub fn send_arp_packets(&self) {
184 if let Err(e) = self
185 .scanner_input_tx
186 .try_send(ScannerInputEvent::StartScanning)
187 {
188 tracing::error!("Failed to send StartScanning event: {}", e);
189 }
190 }
191
192 pub fn gateway_ip(&self) -> Option<Ipv4Addr> {
196 self.gateway_ip
197 }
198
199 pub fn local_ips(&self) -> &HashSet<Ipv4Addr> {
203 &self.local_ips
204 }
205
206 pub fn remove_discovered_hosts(&self, ips: &[Ipv4Addr]) {
213 let mut discovered =
214 recover_or_log(self.discovered_hosts.lock(), "remove_discovered_hosts");
215 for ip in ips {
216 discovered.remove(ip);
217 }
218 }
219}
220
221impl Drop for Scanner {
222 fn drop(&mut self) {
223 tracing::debug!("Scanner::drop() called, cancelling background tasks");
224 self.cancel_token.cancel();
225 for handle in self.task_handles.drain(..) {
227 handle.abort();
228 }
229 }
230}