@@ -42,11 +42,45 @@ cfg_if! {
42
42
}
43
43
}
44
44
45
+ /// Workaround a bug in XNU where netmasks will always have the wrong size in
46
+ /// the sa_len field due to the kernel ignoring trailing zeroes in the future
47
+ /// when setting the field. See https://github.com/nix-rust/nix/issues/1709#issuecomment-1199304470
48
+ ///
49
+ /// To fix this, we overwrite sa_len to have the known (static) value of the
50
+ /// structure.
51
+ fn workaround_xnu_bug ( info : & libc:: ifaddrs ) {
52
+ if info. ifa_netmask . is_null ( ) {
53
+ return
54
+ }
55
+ let family = unsafe {
56
+ ( * info. ifa_netmask ) . sa_family
57
+ } ;
58
+
59
+ let fixup_size = match i32:: from ( family) {
60
+ libc:: AF_INET => Some ( std:: mem:: size_of :: < libc:: sockaddr_in > ( ) ) ,
61
+ libc:: AF_INET6 => Some ( std:: mem:: size_of :: < libc:: sockaddr_in6 > ( ) ) ,
62
+ _ => None
63
+ } ;
64
+
65
+ if let Some ( fixup_size) = fixup_size {
66
+ assert ! ( fixup_size < u8 :: MAX . into( ) ) ;
67
+ let sock = info. ifa_netmask as * mut libc:: sockaddr ;
68
+ unsafe {
69
+ if ( * sock) . sa_len < fixup_size as u8 {
70
+ ( * sock) . sa_len = fixup_size as u8 ;
71
+ }
72
+ }
73
+ }
74
+ }
75
+
45
76
impl InterfaceAddress {
46
77
/// Create an `InterfaceAddress` from the libc struct.
47
78
fn from_libc_ifaddrs ( info : & libc:: ifaddrs ) -> InterfaceAddress {
48
79
let ifname = unsafe { ffi:: CStr :: from_ptr ( info. ifa_name ) } ;
49
80
let address = unsafe { SockaddrStorage :: from_raw ( info. ifa_addr , None ) } ;
81
+ if cfg ! ( target_os = "macos" ) {
82
+ workaround_xnu_bug ( info)
83
+ }
50
84
let netmask = unsafe { SockaddrStorage :: from_raw ( info. ifa_netmask , None ) } ;
51
85
let mut addr = InterfaceAddress {
52
86
interface_name : ifname. to_string_lossy ( ) . to_string ( ) ,
@@ -144,4 +178,21 @@ mod tests {
144
178
fn test_getifaddrs ( ) {
145
179
let _ = getifaddrs ( ) ;
146
180
}
181
+
182
+ #[ test]
183
+ fn test_getifaddrs_netmask_correct ( ) {
184
+ let addrs = getifaddrs ( ) . unwrap ( ) ;
185
+ for iface in addrs {
186
+ let sock = if let Some ( sock) = iface. netmask {
187
+ sock
188
+ } else {
189
+ continue
190
+ } ;
191
+ if sock. family ( ) == Some ( crate :: sys:: socket:: AddressFamily :: Inet ) {
192
+ let _ = sock. as_sockaddr_in ( ) . unwrap ( ) ;
193
+ return ;
194
+ }
195
+ }
196
+ panic ! ( "No address?" ) ;
197
+ }
147
198
}
0 commit comments