@@ -344,24 +344,35 @@ impl<T: Fn(ReachabilityFlags) + Sync + Send> NetworkReachabilityCallbackContext<
344
344
/// libc::sockaddr_in6, depending on the passed in standard library SocketAddr.
345
345
fn to_c_sockaddr ( addr : SocketAddr ) -> Box < libc:: sockaddr > {
346
346
let ptr = match addr {
347
+ // See reference conversion from socket2:
348
+ // https://github.com/rust-lang/socket2/blob/3a938932829ea6ee3025d2d7a86c7b095c76e6c3/src/sockaddr.rs#L277-L287
349
+ // https://github.com/rust-lang/socket2/blob/3a938932829ea6ee3025d2d7a86c7b095c76e6c3/src/sys/unix.rs#L1356-L1363
347
350
SocketAddr :: V4 ( addr) => Box :: into_raw ( Box :: new ( libc:: sockaddr_in {
348
351
sin_len : std:: mem:: size_of :: < libc:: sockaddr_in > ( ) as u8 ,
349
- sin_family : libc:: AF_INET as u8 ,
350
- sin_port : addr. port ( ) ,
351
- sin_addr : libc:: in_addr {
352
- s_addr : u32:: from ( * addr. ip ( ) ) ,
352
+ sin_family : libc:: AF_INET as libc:: sa_family_t ,
353
+ sin_port : addr. port ( ) . to_be ( ) ,
354
+ sin_addr : {
355
+ // `s_addr` is stored as BE on all machines, and the array is in BE order.
356
+ // So the native endian conversion method is used so that it's never
357
+ // swapped.
358
+ libc:: in_addr {
359
+ s_addr : u32:: from_ne_bytes ( addr. ip ( ) . octets ( ) ) ,
360
+ }
353
361
} ,
354
- sin_zero : [ 0i8 ; 8 ] ,
362
+ sin_zero : Default :: default ( ) ,
355
363
} ) ) as * mut c_void ,
364
+ // See reference conversion from socket2:
365
+ // https://github.com/rust-lang/socket2/blob/3a938932829ea6ee3025d2d7a86c7b095c76e6c3/src/sockaddr.rs#L314-L331
366
+ // https://github.com/rust-lang/socket2/blob/3a938932829ea6ee3025d2d7a86c7b095c76e6c3/src/sys/unix.rs#L1369-L1373
356
367
SocketAddr :: V6 ( addr) => Box :: into_raw ( Box :: new ( libc:: sockaddr_in6 {
357
368
sin6_len : std:: mem:: size_of :: < libc:: sockaddr_in6 > ( ) as u8 ,
358
- sin6_family : libc:: AF_INET6 as u8 ,
359
- sin6_port : addr. port ( ) ,
360
- sin6_flowinfo : 0 ,
369
+ sin6_family : libc:: AF_INET6 as libc :: sa_family_t ,
370
+ sin6_port : addr. port ( ) . to_be ( ) ,
371
+ sin6_flowinfo : addr . flowinfo ( ) ,
361
372
sin6_addr : libc:: in6_addr {
362
373
s6_addr : addr. ip ( ) . octets ( ) ,
363
374
} ,
364
- sin6_scope_id : 0 ,
375
+ sin6_scope_id : addr . scope_id ( ) ,
365
376
} ) ) as * mut c_void ,
366
377
} ;
367
378
@@ -373,7 +384,10 @@ mod test {
373
384
use super :: * ;
374
385
375
386
use core_foundation:: runloop:: { kCFRunLoopCommonModes, CFRunLoop } ;
376
- use std:: ffi:: CString ;
387
+ use std:: {
388
+ ffi:: CString ,
389
+ net:: { Ipv4Addr , Ipv6Addr } ,
390
+ } ;
377
391
378
392
#[ test]
379
393
fn test_network_reachability_from_addr ( ) {
@@ -434,6 +448,38 @@ mod test {
434
448
}
435
449
}
436
450
451
+ #[ test]
452
+ fn test_sockaddr_local_to_dns_google_pair_reachability ( ) {
453
+ let sockaddrs = [
454
+ "[2001:4860:4860::8844]:443" . parse :: < SocketAddr > ( ) . unwrap ( ) ,
455
+ "8.8.4.4:443" . parse ( ) . unwrap ( ) ,
456
+ ] ;
457
+ for remote_addr in sockaddrs {
458
+ match std:: net:: TcpStream :: connect ( remote_addr) {
459
+ Err ( _) => {
460
+ let local_addr = if remote_addr. is_ipv4 ( ) {
461
+ SocketAddr :: new ( Ipv4Addr :: UNSPECIFIED . into ( ) , 0 )
462
+ } else {
463
+ SocketAddr :: new ( Ipv6Addr :: UNSPECIFIED . into ( ) , 0 )
464
+ } ;
465
+ let reachability =
466
+ SCNetworkReachability :: from_addr_pair ( local_addr, remote_addr) ;
467
+ let reachability_flags = reachability. reachability ( ) . unwrap ( ) ;
468
+ // Verify that not established tcp connection path is reported as not reachable.
469
+ assert ! ( !reachability_flags. contains( ReachabilityFlags :: REACHABLE ) ) ;
470
+ }
471
+ Ok ( tcp) => {
472
+ let local = tcp. local_addr ( ) . unwrap ( ) ;
473
+ let remote = tcp. peer_addr ( ) . unwrap ( ) ;
474
+ let reachability = SCNetworkReachability :: from_addr_pair ( local, remote) ;
475
+ let reachability_flags = reachability. reachability ( ) . unwrap ( ) ;
476
+ // Verify established tcp connection path is reported as reachable.
477
+ assert ! ( reachability_flags. contains( ReachabilityFlags :: REACHABLE ) ) ;
478
+ }
479
+ }
480
+ }
481
+ }
482
+
437
483
#[ test]
438
484
fn test_reachability_ref_from_host ( ) {
439
485
let valid_inputs = vec ! [ "example.com" , "host-in-local-network" , "en0" ] ;
0 commit comments