summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Engler <opara@cs.georgetown.edu>2022-11-07 15:17:29 -0500
committerSteven Engler <opara@cs.georgetown.edu>2022-11-21 12:03:11 -0500
commit8884ea38ec80d838138070e941c080b0b573575a (patch)
treeb926ab0b59900c90af4364531e59e90fb098d525
parent33b5f928ea8e691c89d4b7242d44bdb2c1a62167 (diff)
downloadnix-8884ea38ec80d838138070e941c080b0b573575a.zip
Added better support for unnamed unix socket addrs
-rw-r--r--src/sys/socket/addr.rs29
-rw-r--r--test/sys/test_socket.rs71
2 files changed, 99 insertions, 1 deletions
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index c7b5f29e..f051d205 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 7ab60ecc..26ba9b2d 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<u8>) {
// 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]