From 8884ea38ec80d838138070e941c080b0b573575a Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 7 Nov 2022 15:17:29 -0500 Subject: [PATCH 1/4] Added better support for unnamed unix socket addrs --- src/sys/socket/addr.rs | 29 +++++++++++++++++ test/sys/test_socket.rs | 71 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index c7b5f29eb6..f051d20547 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -885,6 +885,29 @@ impl UnixAddr { } } + /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. + pub fn new_unnamed() -> UnixAddr { + #[allow(unused)] + let mut ret = libc::sockaddr_un { + sun_family: AddressFamily::Unix as sa_family_t, + .. unsafe { mem::zeroed() } + }; + + let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); + + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + { + ret.sun_len = sun_len; + } + + unsafe { UnixAddr::from_raw_parts(ret, sun_len) } + } + /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` /// is the size of the valid portion of the struct, excluding any trailing /// NUL. @@ -941,6 +964,12 @@ impl UnixAddr { } } + /// Check if this address is an "unnamed" unix socket address. + #[inline] + pub fn is_unnamed(&self) -> bool { + matches!(self.kind(), UnixAddrKind::Unnamed) + } + /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` #[inline] pub fn path_len(&self) -> usize { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 7ab60ecc28..26ba9b2d0f 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -244,6 +244,22 @@ pub fn test_abstract_uds_addr() { assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0); } +// Test getting an unnamed address (without unix socket creation) +#[test] +pub fn test_unnamed_uds_addr() { + use crate::nix::sys::socket::SockaddrLike; + + let addr = UnixAddr::new_unnamed(); + + assert!(addr.is_unnamed()); + assert_eq!(addr.len(), 2); + assert!(addr.path().is_none()); + assert_eq!(addr.path_len(), 0); + + #[cfg(target_os = "linux")] + assert!(addr.as_abstract().is_none()); +} + #[test] pub fn test_getsockname() { use nix::sys::socket::bind; @@ -1484,7 +1500,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { // Test creating and using named unix domain sockets #[test] -pub fn test_unixdomain() { +pub fn test_named_unixdomain() { use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; use nix::sys::socket::{SockFlag, SockType}; use nix::unistd::{close, read, write}; @@ -1527,6 +1543,59 @@ pub fn test_unixdomain() { assert_eq!(&buf[..], b"hello"); } +// Test using unnamed unix domain addresses +#[test] +pub fn test_unnamed_unixdomain() { + use nix::sys::socket::{getsockname, socketpair}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::close; + + let (fd_1, fd_2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .expect("socketpair failed"); + + let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed"); + assert!(addr_1.is_unnamed()); + assert_eq!(addr_1, UnixAddr::new_unnamed()); + + close(fd_1).unwrap(); + close(fd_2).unwrap(); +} + +// Test creating and using unnamed unix domain addresses for autobinding sockets +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_unnamed_unixdomain_autobind() { + use nix::sys::socket::{bind, getsockname, socket}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::close; + + let fd = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the + // socket is autobound to an abstract address" + bind(fd, &UnixAddr::new_unnamed()).expect("bind failed"); + + let addr: UnixAddr = getsockname(fd).expect("getsockname failed"); + let addr = addr.as_abstract().unwrap(); + + // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2 + // (as of 2022-11) + assert_eq!(addr.len(), 5); + + close(fd).unwrap(); +} + // Test creating and using named system control sockets #[cfg(any(target_os = "macos", target_os = "ios"))] #[test] From 49bab984ee75391f37816eb722bbad9b7ae92b1c Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 7 Nov 2022 18:25:27 -0500 Subject: [PATCH 2/4] fixup! Added better support for unnamed unix socket addrs Make Linux-only --- src/sys/socket/addr.rs | 17 +++++------------ test/sys/test_socket.rs | 5 +++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index f051d20547..34138efcfb 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -886,25 +886,16 @@ impl UnixAddr { } /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn new_unnamed() -> UnixAddr { - #[allow(unused)] - let mut ret = libc::sockaddr_un { + let ret = libc::sockaddr_un { sun_family: AddressFamily::Unix as sa_family_t, .. unsafe { mem::zeroed() } }; let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - { - ret.sun_len = sun_len; - } - unsafe { UnixAddr::from_raw_parts(ret, sun_len) } } @@ -965,6 +956,8 @@ impl UnixAddr { } /// Check if this address is an "unnamed" unix socket address. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] #[inline] pub fn is_unnamed(&self) -> bool { matches!(self.kind(), UnixAddrKind::Unnamed) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 26ba9b2d0f..07ca4d3420 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -223,7 +223,7 @@ pub fn test_addr_equality_abstract() { } // Test getting/setting abstract addresses (without unix socket creation) -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] pub fn test_abstract_uds_addr() { let empty = String::new(); @@ -245,6 +245,7 @@ pub fn test_abstract_uds_addr() { } // Test getting an unnamed address (without unix socket creation) +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] pub fn test_unnamed_uds_addr() { use crate::nix::sys::socket::SockaddrLike; @@ -256,7 +257,6 @@ pub fn test_unnamed_uds_addr() { assert!(addr.path().is_none()); assert_eq!(addr.path_len(), 0); - #[cfg(target_os = "linux")] assert!(addr.as_abstract().is_none()); } @@ -1544,6 +1544,7 @@ pub fn test_named_unixdomain() { } // Test using unnamed unix domain addresses +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] pub fn test_unnamed_unixdomain() { use nix::sys::socket::{getsockname, socketpair}; From 500baa1633cb93a11b0b3998ab8075f66d7e6715 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 21 Nov 2022 12:10:34 -0500 Subject: [PATCH 3/4] fixup! Added better support for unnamed unix socket addrs Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2742cfb182..b2ae4b16a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1842](https://github.com/nix-rust/nix/pull/1842)) - Added `IP_TOS` `SO_PRIORITY` and `IPV6_TCLASS` sockopts for Linux ([#1853](https://github.com/nix-rust/nix/pull/1853)) +- Added `new_unnamed` and `is_unnamed` for `UnixAddr` on Linux and Android. + ([#1857](https://github.com/nix-rust/nix/pull/1857)) ### Changed From f6a22198a48b138f43abeb186ebe9f4ebb1af415 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 21 Nov 2022 12:11:43 -0500 Subject: [PATCH 4/4] fixup! Added better support for unnamed unix socket addrs Removed test assertion --- test/sys/test_socket.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 07ca4d3420..5adc77ed6b 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1561,7 +1561,6 @@ pub fn test_unnamed_unixdomain() { let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed"); assert!(addr_1.is_unnamed()); - assert_eq!(addr_1, UnixAddr::new_unnamed()); close(fd_1).unwrap(); close(fd_2).unwrap();