@@ -22,6 +22,7 @@ union Addr {
2222 inet : libc:: sockaddr_in ,
2323 inet6 : libc:: sockaddr_in6 ,
2424 unix : libc:: sockaddr_un ,
25+ netlink : libc:: sockaddr_nl ,
2526}
2627
2728// verify there are no larger fields larger than `libc::sockaddr_storage`
@@ -162,6 +163,34 @@ impl SockaddrStorage {
162163 unsafe { Self :: from_ptr ( ptr as * const MaybeUninit < u8 > , len) } . unwrap ( )
163164 }
164165
166+ /// If the socket address represents a valid netlink socket address (correct family and length),
167+ /// returns the netlink socket address.
168+ pub fn as_netlink ( & self ) -> Option < & nix:: sys:: socket:: NetlinkAddr > {
169+ if ( self . len as usize ) < std:: mem:: size_of :: < libc:: sockaddr_nl > ( ) {
170+ return None ;
171+ }
172+ if self . family ( ) != Some ( AddressFamily :: Netlink ) {
173+ return None ;
174+ }
175+
176+ // SAFETY: Assume that `nix::sys::socket::NetlinkAddr` is a transparent wrapper around a
177+ // `libc::sockaddr_nl`. Verify (as best we can) that this is true.
178+ assert_eq_size ! ( libc:: sockaddr_nl, nix:: sys:: socket:: NetlinkAddr ) ;
179+ assert_eq_align ! ( libc:: sockaddr_nl, nix:: sys:: socket:: NetlinkAddr ) ;
180+
181+ Some ( unsafe { & * ( & self . addr . netlink as * const _ as * const nix:: sys:: socket:: NetlinkAddr ) } )
182+ }
183+
184+ /// Get a new `SockaddrStorage` with a copy of the netlink socket address.
185+ pub fn from_netlink ( addr : & nix:: sys:: socket:: NetlinkAddr ) -> Self {
186+ // SAFETY: Assume that `nix::sys::socket::NetlinkAddr` is a transparent wrapper around a
187+ // `libc::sockaddr_nl`. Verify (as best we can) that this is true.
188+ assert_eq_size ! ( libc:: sockaddr_nl, nix:: sys:: socket:: NetlinkAddr ) ;
189+ assert_eq_align ! ( libc:: sockaddr_nl, nix:: sys:: socket:: NetlinkAddr ) ;
190+
191+ unsafe { Self :: from_ptr ( addr. as_ptr ( ) as * const MaybeUninit < u8 > , addr. len ( ) ) } . unwrap ( )
192+ }
193+
165194 /// A pointer to the socket address. Some bytes may be uninitialized.
166195 pub fn as_ptr ( & self ) -> ( * const MaybeUninit < u8 > , libc:: socklen_t ) {
167196 ( unsafe { & self . addr . slice } . as_ptr ( ) , self . len )
@@ -178,13 +207,15 @@ impl std::fmt::Debug for SockaddrStorage {
178207 let as_inet = self . as_inet ( ) ;
179208 let as_inet6 = self . as_inet6 ( ) ;
180209 let as_unix = self . as_unix ( ) ;
210+ let as_netlink = self . as_netlink ( ) ;
181211
182212 let as_inet = as_inet. map ( |x| x as & dyn std:: fmt:: Debug ) ;
183213 let as_inet6 = as_inet6. map ( |x| x as & dyn std:: fmt:: Debug ) ;
184214 let as_unix = as_unix. as_ref ( ) . map ( |x| x as & dyn std:: fmt:: Debug ) ;
215+ let as_netlink = as_netlink. as_ref ( ) . map ( |x| x as & dyn std:: fmt:: Debug ) ;
185216
186217 // find a representation that is not None
187- let options = [ as_inet, as_inet6, as_unix] ;
218+ let options = [ as_inet, as_inet6, as_unix, as_netlink ] ;
188219 let addr = options. into_iter ( ) . find_map ( std:: convert:: identity) ;
189220
190221 if let Some ( ref addr) = addr {
@@ -206,13 +237,15 @@ impl std::fmt::Display for SockaddrStorage {
206237 let as_inet = self . as_inet ( ) ;
207238 let as_inet6 = self . as_inet6 ( ) ;
208239 let as_unix = self . as_unix ( ) ;
240+ let as_netlink = self . as_netlink ( ) ;
209241
210242 let as_inet = as_inet. map ( |x| x as & dyn std:: fmt:: Display ) ;
211243 let as_inet6 = as_inet6. map ( |x| x as & dyn std:: fmt:: Display ) ;
212244 let as_unix = as_unix. as_ref ( ) . map ( |x| x as & dyn std:: fmt:: Display ) ;
245+ let as_netlink = as_netlink. as_ref ( ) . map ( |x| x as & dyn std:: fmt:: Display ) ;
213246
214247 // find a representation that is not None
215- let options = [ as_inet, as_inet6, as_unix] ;
248+ let options = [ as_inet, as_inet6, as_unix, as_netlink ] ;
216249 let addr = options. into_iter ( ) . find_map ( std:: convert:: identity) ;
217250
218251 if let Some ( ref addr) = addr {
@@ -259,6 +292,12 @@ impl From<std::net::SocketAddrV6> for SockaddrStorage {
259292 }
260293}
261294
295+ impl From < nix:: sys:: socket:: NetlinkAddr > for SockaddrStorage {
296+ fn from ( addr : nix:: sys:: socket:: NetlinkAddr ) -> Self {
297+ SockaddrStorage :: from_netlink ( & addr)
298+ }
299+ }
300+
262301/// A Unix socket address. Typically will be used as an owned address
263302/// `SockaddrUnix<libc::sockaddr_un>` or a borrowed address `SockaddrUnix<&libc::sockaddr_un>`, and
264303/// you can convert between them using methods such as [`as_ref`](Self::as_ref) or
@@ -529,6 +568,7 @@ mod tests {
529568 assert ! ( addr. as_inet( ) . is_some( ) ) ;
530569 assert ! ( addr. as_inet6( ) . is_none( ) ) ;
531570 assert ! ( addr. as_unix( ) . is_none( ) ) ;
571+ assert ! ( addr. as_netlink( ) . is_none( ) ) ;
532572 }
533573
534574 /// Convert from a `sockaddr_un` to a `SockaddrStorage`.
@@ -549,6 +589,27 @@ mod tests {
549589 assert ! ( addr. as_unix( ) . is_some( ) ) ;
550590 assert ! ( addr. as_inet( ) . is_none( ) ) ;
551591 assert ! ( addr. as_inet6( ) . is_none( ) ) ;
592+ assert ! ( addr. as_netlink( ) . is_none( ) ) ;
593+ }
594+
595+ /// Convert from a `sockaddr_nl` to a `SockaddrStorage`.
596+ #[ test]
597+ fn storage_from_netlink_ptr ( ) {
598+ let mut addr: libc:: sockaddr_nl = unsafe { std:: mem:: zeroed ( ) } ;
599+ addr. nl_family = libc:: AF_NETLINK as u16 ;
600+ addr. nl_pid = 0x38deb915 ;
601+ addr. nl_groups = 0xf229a8ea ;
602+
603+ let ptr = & addr as * const _ as * const MaybeUninit < u8 > ;
604+ let len = std:: mem:: size_of_val ( & addr) . try_into ( ) . unwrap ( ) ;
605+
606+ let addr = unsafe { SockaddrStorage :: from_ptr ( ptr, len) } . unwrap ( ) ;
607+
608+ assert_eq ! ( addr. family( ) , Some ( AddressFamily :: Netlink ) ) ;
609+ assert ! ( addr. as_netlink( ) . is_some( ) ) ;
610+ assert ! ( addr. as_inet( ) . is_none( ) ) ;
611+ assert ! ( addr. as_inet6( ) . is_none( ) ) ;
612+ assert ! ( addr. as_unix( ) . is_none( ) ) ;
552613 }
553614
554615 /// Convert from a `sockaddr_in` to a `SockaddrStorage` to a `SockaddrIn`.
@@ -588,6 +649,41 @@ mod tests {
588649 assert_eq ! ( u32 :: from_be( addr. sin_addr. s_addr) , addr_original. ip( ) ) ;
589650 }
590651
652+ /// Convert from a `sockaddr_nl` to a `SockaddrStorage` to a `NetlinkAddr`.
653+ #[ test]
654+ fn netlink_addr_from_libc ( ) {
655+ let mut addr_nl: libc:: sockaddr_nl = unsafe { std:: mem:: zeroed ( ) } ;
656+ addr_nl. nl_family = libc:: AF_NETLINK as u16 ;
657+ addr_nl. nl_pid = 0x38deb915 ;
658+ addr_nl. nl_groups = 0xf229a8ea ;
659+
660+ let ptr = & addr_nl as * const _ as * const MaybeUninit < u8 > ;
661+ let len = std:: mem:: size_of_val ( & addr_nl) . try_into ( ) . unwrap ( ) ;
662+
663+ let addr = unsafe { SockaddrStorage :: from_ptr ( ptr, len) } . unwrap ( ) ;
664+ let addr = addr. as_netlink ( ) . unwrap ( ) ;
665+
666+ assert_eq ! ( addr. pid( ) , u32 :: from_le( addr_nl. nl_pid) ) ;
667+ assert_eq ! ( addr. groups( ) , u32 :: from_le( addr_nl. nl_groups) ) ;
668+ }
669+
670+ /// Convert from a `NetlinkAddr` to a `SockaddrStorage` to a `sockaddr_nl`.
671+ #[ test]
672+ fn netlink_addr_to_libc ( ) {
673+ let addr_original = nix:: sys:: socket:: NetlinkAddr :: new ( 0x38deb915 , 0xf229a8ea ) ;
674+ let addr = SockaddrStorage :: from_netlink ( & addr_original) ;
675+
676+ let ( ptr, len) = addr. as_ptr ( ) ;
677+ let ptr = ptr as * const libc:: sockaddr_nl ;
678+ assert_eq ! ( len as usize , std:: mem:: size_of:: <libc:: sockaddr_nl>( ) ) ;
679+
680+ let addr = unsafe { ptr. as_ref ( ) } . unwrap ( ) ;
681+
682+ assert_eq ! ( addr. nl_family, libc:: AF_NETLINK as u16 ) ;
683+ assert_eq ! ( u32 :: from_le( addr. nl_pid) , addr_original. pid( ) ) ;
684+ assert_eq ! ( u32 :: from_le( addr. nl_groups) , addr_original. groups( ) ) ;
685+ }
686+
591687 /// Convert from a pathname `sockaddr_un` to a `SockaddrStorage` to a `SockaddrUnix`.
592688 #[ test]
593689 fn unix_addr_from_libc_to_path ( ) {
0 commit comments