44
55use crate :: alive_test:: AliveTestError ;
66use crate :: alive_test:: arp:: forge_arp_request;
7- use crate :: alive_test:: icmp:: { forge_icmp_v4, forge_icmp_v6, forge_neighbor_solicit} ;
7+ use crate :: alive_test:: icmp:: {
8+ forge_icmp_v4, forge_icmp_v6, forge_icmp_v6_for_host_discovery, forge_neighbor_solicit,
9+ } ;
810use crate :: nasl:: raw_ip_utils:: {
911 raw_ip_utils:: { FIX_IPV6_HEADER_LENGTH , send_v4_packet, send_v6_packet} ,
1012 tcp_ping:: { FILTER_PORT , forge_tcp_ping_ipv4, forge_tcp_ping_ipv6} ,
@@ -20,12 +22,14 @@ use pnet::packet::ip::IpNextHeaderProtocols;
2022use pnet:: packet:: ipv6:: Ipv6Packet ;
2123use pnet:: packet:: tcp:: TcpPacket ;
2224use std:: collections:: HashSet ;
25+ use std:: str:: FromStr ;
2326use std:: time:: Duration ;
2427use tokio:: sync:: mpsc:: { self , Receiver , Sender } ;
2528use tokio:: time:: sleep;
2629
2730use std:: net:: IpAddr ;
2831
32+ use cidr:: Ipv6Cidr ;
2933use pcap:: { Active , Capture , Inactive , PacketCodec , PacketStream } ;
3034use pnet:: packet:: {
3135 icmp:: { IcmpTypes , * } ,
@@ -45,7 +49,7 @@ const BITS_PER_BYTE: usize = 8;
4549
4650struct AliveTestCtlStop ;
4751
48- #[ derive( Clone ) ]
52+ #[ derive( Debug , Clone ) ]
4953struct AliveHostInfo {
5054 ip : String ,
5155 detectihttp_method : AliveTestMethods ,
@@ -142,13 +146,13 @@ fn process_ipv6_packet(packet: &[u8]) -> Result<Option<AliveHostInfo>, AliveTest
142146 . ok_or_else ( || {
143147 AliveTestError :: CreateIcmpPacketFromWrongBufferSize ( packet[ ..] . len ( ) as i64 )
144148 } ) ?;
145-
146149 let make_alive_host_ctl = |pkt : Ipv6Packet < ' _ > , method| {
147150 Ok ( Some ( AliveHostInfo {
148151 ip : pkt. get_source ( ) . to_string ( ) ,
149152 detectihttp_method : method,
150153 } ) )
151154 } ;
155+
152156 match icmp_pkt. get_icmpv6_type ( ) {
153157 Icmpv6Types :: EchoReply => return make_alive_host_ctl ( pkt, AliveTestMethods :: Icmp ) ,
154158 Icmpv6Types :: NeighborAdvert => return make_alive_host_ctl ( pkt, AliveTestMethods :: Arp ) ,
@@ -217,7 +221,7 @@ async fn capture_task(
217221 tokio:: select! {
218222 packet = stream. next( ) => { // packet is Option<Result<Box>>
219223 if let Some ( Ok ( data) ) = packet && let Ok ( Some ( alive_host) ) = process_packet( & data) {
220- tx_msg. send( alive_host) . await . unwrap( )
224+ tx_msg. send( alive_host) . await . unwrap( )
221225 }
222226 } ,
223227 ctl = rx_ctl. recv( ) => {
@@ -231,13 +235,51 @@ async fn capture_task(
231235 Ok ( ( ) )
232236}
233237
238+ fn get_host_discovery_ipv6_net (
239+ methods : & Vec < AliveTestMethods > ,
240+ target : & HashSet < String > ,
241+ ) -> Option < Result < Ipv6Cidr , AliveTestError > > {
242+ if methods. contains ( & AliveTestMethods :: HostDiscoveryIpv6 ) {
243+ if let Some ( t) = target. iter ( ) . next ( )
244+ && target. len ( ) == 1
245+ {
246+ return Some (
247+ Ipv6Cidr :: from_str ( t)
248+ . map_err ( |e| AliveTestError :: InvalidDestinationAddr ( e. to_string ( ) ) ) ,
249+ ) ;
250+ } else {
251+ tracing:: debug!( "Only one IPv6 network address is allowed for host discovery" ) ;
252+ return Some ( Err ( AliveTestError :: InvalidDestinationAddr (
253+ target. iter ( ) . next ( ) . unwrap ( ) . to_string ( ) ,
254+ ) ) ) ;
255+ }
256+ }
257+ None
258+ }
259+
234260async fn send_task (
235261 methods : Vec < AliveTestMethods > ,
236262 target : HashSet < String > ,
237263 timeout : u64 ,
238264 tx_ctl : Sender < AliveTestCtlStop > ,
239265) -> Result < ( ) , AliveTestError > {
240266 let mut count = 0 ;
267+ match get_host_discovery_ipv6_net ( & methods, & target) {
268+ Some ( Ok ( dst) ) => {
269+ let icmp = forge_icmp_v6_for_host_discovery ( dst) ?;
270+ send_v6_packet ( icmp) ?;
271+ tracing:: info!( "Started host discovery against {}" , dst) ;
272+ sleep ( Duration :: from_millis ( timeout) ) . await ;
273+ // Send only returns error if the receiver is closed, which only happens when it panics.
274+ tx_ctl. send ( AliveTestCtlStop ) . await . unwrap ( ) ;
275+ return Ok ( ( ) ) ;
276+ }
277+ Some ( Err ( e) ) => {
278+ tx_ctl. send ( AliveTestCtlStop ) . await . unwrap ( ) ;
279+ return Err ( e) ;
280+ }
281+ None => { }
282+ } ;
241283
242284 let target: HashSet < IpAddr > = target
243285 . into_iter ( )
@@ -358,14 +400,18 @@ impl Scanner {
358400 let capture_handle = tokio:: spawn ( capture_task ( capture_inactive, rx_ctl, tx_msg) ) ;
359401
360402 let timeout = self . timeout . unwrap_or ( ( DEFAULT_TIMEOUT * 1000 ) as u64 ) ;
361- let methods = self . methods . clone ( ) ;
362- let send_handle = tokio:: spawn ( send_task ( methods , trgt, timeout, tx_ctl) ) ;
403+ let methods_c = self . methods . clone ( ) ;
404+ let send_handle = tokio:: spawn ( send_task ( methods_c , trgt, timeout, tx_ctl) ) ;
363405
364406 while let Some ( alivehost) = rx_msg. recv ( ) . await {
365407 if self . target . contains ( & alivehost. ip ) && !alive. contains ( & alivehost. ip ) {
366408 alive. insert ( alivehost. ip . clone ( ) ) ;
367409 println ! ( "{} via {:?}" , & alivehost. ip, & alivehost. detectihttp_method) ;
368- }
410+ } else if let Some ( Ok ( dst) ) = get_host_discovery_ipv6_net ( & self . methods , & self . target )
411+ && dst. contains ( & alivehost. ip . parse :: < std:: net:: Ipv6Addr > ( ) . unwrap ( ) ) {
412+ alive. insert ( alivehost. ip . clone ( ) ) ;
413+ println ! ( "{} via {:?}" , & alivehost. ip, & alivehost. detectihttp_method) ;
414+ }
369415 }
370416
371417 send_handle. await . unwrap ( ) . unwrap ( ) ;
0 commit comments