Skip to content

Commit 79f04fb

Browse files
Merge #1857
1857: Add better support for unnamed unix socket addrs r=asomers a=stevenengler This adds the following 2 functions/methods: `UnixAddr::new_unnamed` and `UnixAddr::is_unnamed`. Closes #1585 unix(7) on Linux: > unnamed: A stream socket that has not been bound to a pathname using bind(2) has no name. Likewise, the two sockets created by socketpair(2) are unnamed. When the address of an unnamed socket is returned, its length is `sizeof(sa_family_t)`, and `sun_path` should not be inspected. **Edit:** This currently isn't working on BSD, but I see why. Will fix it shortly. Co-authored-by: Steven Engler <opara@cs.georgetown.edu>
2 parents 9ea1493 + f6a2219 commit 79f04fb

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
3434
([#1842](https://github.com/nix-rust/nix/pull/1842))
3535
- Added `IP_TOS` `SO_PRIORITY` and `IPV6_TCLASS` sockopts for Linux
3636
([#1853](https://github.com/nix-rust/nix/pull/1853))
37+
- Added `new_unnamed` and `is_unnamed` for `UnixAddr` on Linux and Android.
38+
([#1857](https://github.com/nix-rust/nix/pull/1857))
3739

3840
### Changed
3941

src/sys/socket/addr.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,20 @@ impl UnixAddr {
885885
}
886886
}
887887

888+
/// Create a new `sockaddr_un` representing an "unnamed" unix socket address.
889+
#[cfg(any(target_os = "android", target_os = "linux"))]
890+
#[cfg_attr(docsrs, doc(cfg(all())))]
891+
pub fn new_unnamed() -> UnixAddr {
892+
let ret = libc::sockaddr_un {
893+
sun_family: AddressFamily::Unix as sa_family_t,
894+
.. unsafe { mem::zeroed() }
895+
};
896+
897+
let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap();
898+
899+
unsafe { UnixAddr::from_raw_parts(ret, sun_len) }
900+
}
901+
888902
/// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len`
889903
/// is the size of the valid portion of the struct, excluding any trailing
890904
/// NUL.
@@ -941,6 +955,14 @@ impl UnixAddr {
941955
}
942956
}
943957

958+
/// Check if this address is an "unnamed" unix socket address.
959+
#[cfg(any(target_os = "android", target_os = "linux"))]
960+
#[cfg_attr(docsrs, doc(cfg(all())))]
961+
#[inline]
962+
pub fn is_unnamed(&self) -> bool {
963+
matches!(self.kind(), UnixAddrKind::Unnamed)
964+
}
965+
944966
/// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
945967
#[inline]
946968
pub fn path_len(&self) -> usize {

test/sys/test_socket.rs

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ pub fn test_addr_equality_abstract() {
223223
}
224224

225225
// Test getting/setting abstract addresses (without unix socket creation)
226-
#[cfg(target_os = "linux")]
226+
#[cfg(any(target_os = "android", target_os = "linux"))]
227227
#[test]
228228
pub fn test_abstract_uds_addr() {
229229
let empty = String::new();
@@ -244,6 +244,22 @@ pub fn test_abstract_uds_addr() {
244244
assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0);
245245
}
246246

247+
// Test getting an unnamed address (without unix socket creation)
248+
#[cfg(any(target_os = "android", target_os = "linux"))]
249+
#[test]
250+
pub fn test_unnamed_uds_addr() {
251+
use crate::nix::sys::socket::SockaddrLike;
252+
253+
let addr = UnixAddr::new_unnamed();
254+
255+
assert!(addr.is_unnamed());
256+
assert_eq!(addr.len(), 2);
257+
assert!(addr.path().is_none());
258+
assert_eq!(addr.path_len(), 0);
259+
260+
assert!(addr.as_abstract().is_none());
261+
}
262+
247263
#[test]
248264
pub fn test_getsockname() {
249265
use nix::sys::socket::bind;
@@ -1484,7 +1500,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
14841500

14851501
// Test creating and using named unix domain sockets
14861502
#[test]
1487-
pub fn test_unixdomain() {
1503+
pub fn test_named_unixdomain() {
14881504
use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr};
14891505
use nix::sys::socket::{SockFlag, SockType};
14901506
use nix::unistd::{close, read, write};
@@ -1527,6 +1543,59 @@ pub fn test_unixdomain() {
15271543
assert_eq!(&buf[..], b"hello");
15281544
}
15291545

1546+
// Test using unnamed unix domain addresses
1547+
#[cfg(any(target_os = "android", target_os = "linux"))]
1548+
#[test]
1549+
pub fn test_unnamed_unixdomain() {
1550+
use nix::sys::socket::{getsockname, socketpair};
1551+
use nix::sys::socket::{SockFlag, SockType};
1552+
use nix::unistd::close;
1553+
1554+
let (fd_1, fd_2) = socketpair(
1555+
AddressFamily::Unix,
1556+
SockType::Stream,
1557+
None,
1558+
SockFlag::empty(),
1559+
)
1560+
.expect("socketpair failed");
1561+
1562+
let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed");
1563+
assert!(addr_1.is_unnamed());
1564+
1565+
close(fd_1).unwrap();
1566+
close(fd_2).unwrap();
1567+
}
1568+
1569+
// Test creating and using unnamed unix domain addresses for autobinding sockets
1570+
#[cfg(any(target_os = "android", target_os = "linux"))]
1571+
#[test]
1572+
pub fn test_unnamed_unixdomain_autobind() {
1573+
use nix::sys::socket::{bind, getsockname, socket};
1574+
use nix::sys::socket::{SockFlag, SockType};
1575+
use nix::unistd::close;
1576+
1577+
let fd = socket(
1578+
AddressFamily::Unix,
1579+
SockType::Stream,
1580+
SockFlag::empty(),
1581+
None,
1582+
)
1583+
.expect("socket failed");
1584+
1585+
// unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the
1586+
// socket is autobound to an abstract address"
1587+
bind(fd, &UnixAddr::new_unnamed()).expect("bind failed");
1588+
1589+
let addr: UnixAddr = getsockname(fd).expect("getsockname failed");
1590+
let addr = addr.as_abstract().unwrap();
1591+
1592+
// changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2
1593+
// (as of 2022-11)
1594+
assert_eq!(addr.len(), 5);
1595+
1596+
close(fd).unwrap();
1597+
}
1598+
15301599
// Test creating and using named system control sockets
15311600
#[cfg(any(target_os = "macos", target_os = "ios"))]
15321601
#[test]

0 commit comments

Comments
 (0)