@@ -3,7 +3,7 @@ use crate::daemon::discovery::service::base::{
33} ;
44use crate :: daemon:: discovery:: types:: base:: { DiscoveryCriticalError , DiscoverySessionUpdate } ;
55use crate :: daemon:: utils:: scanner:: {
6- arp_scan_host, scan_endpoints, scan_tcp_ports, scan_udp_ports,
6+ arp_scan_host, can_arp_scan , scan_endpoints, scan_tcp_ports, scan_udp_ports,
77} ;
88use crate :: server:: discovery:: r#impl:: types:: { DiscoveryType , HostNamingFallback } ;
99use crate :: server:: hosts:: r#impl:: {
@@ -195,14 +195,21 @@ impl DiscoveryRunner<NetworkScanDiscovery> {
195195 . map ( |p| p. number ( ) )
196196 . collect ( ) ;
197197
198- // Partition IPs by whether their subnet is interfaced
199- let ( interfaced_ips, non_interfaced_ips) : ( Vec < _ > , Vec < _ > ) =
198+ // Check ARP capability once before partitioning
199+ let arp_available = can_arp_scan ( ) ;
200+
201+ // Partition IPs - only use ARP path if we have capability
202+ let ( interfaced_ips, non_interfaced_ips) : ( Vec < _ > , Vec < _ > ) = if arp_available {
200203 all_ips_with_subnets. into_iter ( ) . partition ( |( _, subnet) | {
201204 subnet_cidr_to_mac
202205 . get ( & subnet. base . cidr )
203206 . and_then ( |m| * m)
204207 . is_some ( )
205- } ) ;
208+ } )
209+ } else {
210+ // No ARP capability - treat all as non-interfaced (port scan only)
211+ ( Vec :: new ( ) , all_ips_with_subnets)
212+ } ;
206213
207214 // =============================================================
208215 // PHASE 1: Responsiveness check (0-50%)
@@ -374,45 +381,46 @@ impl DiscoveryRunner<NetworkScanDiscovery> {
374381
375382 let phase2_batches_done = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
376383
384+ // In scan_and_process_hosts, box the deep scan futures
377385 let results = stream:: iter ( responsive_hosts)
378- . map ( |( ip, subnet, mac, phase1_ports) | {
379- let cancel = cancel. clone ( ) ;
380- let gateway_ips = gateway_ips. clone ( ) ;
381- let phase2_batches_done = phase2_batches_done. clone ( ) ;
382-
383- async move {
384- let result = self
385- . deep_scan_host ( DeepScanParams {
386- ip,
387- subnet : & subnet,
388- mac,
389- phase1_ports,
390- cancel,
391- port_scan_batch_size : ports_per_host_batch,
392- gateway_ips : & gateway_ips,
393- batches_done : & phase2_batches_done,
394- total_batches,
395- } )
396- . await ;
397-
398- match result {
399- Ok ( Some ( host) ) => Some ( host) ,
400- Ok ( None ) => None ,
401- Err ( e) => {
402- if DiscoveryCriticalError :: is_critical_error ( e. to_string ( ) ) {
403- tracing:: error!( ip = %ip, error = %e, "Critical error in deep scan" ) ;
404- } else {
405- tracing:: warn!( ip = %ip, error = %e, "Deep scan failed" ) ;
406- }
407- None
386+ . map ( |( ip, subnet, mac, phase1_ports) | {
387+ let cancel = cancel. clone ( ) ;
388+ let gateway_ips = gateway_ips. clone ( ) ;
389+ let batches_done = phase2_batches_done. clone ( ) ;
390+
391+ Box :: pin ( async move {
392+ let result = self
393+ . deep_scan_host ( DeepScanParams {
394+ ip,
395+ subnet : & subnet,
396+ mac,
397+ phase1_ports,
398+ cancel,
399+ port_scan_batch_size : ports_per_host_batch,
400+ gateway_ips : & gateway_ips,
401+ batches_done : & batches_done,
402+ total_batches,
403+ } )
404+ . await ;
405+
406+ match result {
407+ Ok ( Some ( host) ) => Some ( host) ,
408+ Ok ( None ) => None ,
409+ Err ( e) => {
410+ if DiscoveryCriticalError :: is_critical_error ( e. to_string ( ) ) {
411+ tracing:: error!( ip = %ip, error = %e, "Critical error in deep scan" ) ;
412+ } else {
413+ tracing:: warn!( ip = %ip, error = %e, "Deep scan failed" ) ;
408414 }
415+ None
409416 }
410417 }
411418 } )
412- . buffer_unordered ( deep_scan_concurrency)
413- . filter_map ( |x| async { x } )
414- . collect :: < Vec < Host > > ( )
415- . await ;
419+ } )
420+ . buffer_unordered ( deep_scan_concurrency)
421+ . filter_map ( |x| async { x } )
422+ . collect :: < Vec < Host > > ( )
423+ . await ;
416424
417425 self . report_discovery_update ( DiscoverySessionUpdate :: scanning ( 100 ) )
418426 . await ?;
@@ -513,7 +521,7 @@ impl DiscoveryRunner<NetworkScanDiscovery> {
513521 all_tcp_ports. extend ( open_ports) ;
514522
515523 let done = batches_done. fetch_add ( 1 , Ordering :: Relaxed ) + 1 ;
516- let pct = ( 50 + done * 50 / total_batches. max ( 1 ) ) as u8 ;
524+ let pct = ( 50 + done * 40 / total_batches. max ( 1 ) ) as u8 ; // 50-90%
517525 let _ = self . report_scanning_progress ( pct) . await ;
518526 }
519527
@@ -539,6 +547,9 @@ impl DiscoveryRunner<NetworkScanDiscovery> {
539547 . await ?;
540548 open_ports. extend ( udp_ports) ;
541549
550+ self . report_discovery_update ( DiscoverySessionUpdate :: scanning ( 95 ) )
551+ . await ?;
552+
542553 let mut ports_to_check = open_ports. clone ( ) ;
543554 let endpoint_only_ports = Service :: endpoint_only_ports ( ) ;
544555 ports_to_check. extend ( endpoint_only_ports) ;
@@ -554,6 +565,9 @@ impl DiscoveryRunner<NetworkScanDiscovery> {
554565 )
555566 . await ?;
556567
568+ self . report_discovery_update ( DiscoverySessionUpdate :: scanning ( 98 ) )
569+ . await ?;
570+
557571 for endpoint_response in & endpoint_responses {
558572 let port = endpoint_response. endpoint . port_base ;
559573 if !open_ports. contains ( & port) {
0 commit comments