Skip to content

Commit d133d3d

Browse files
committed
Relax assertions in sockaddr_storage_to_addr to match the documentation.
Fixes #1479
1 parent 5ed5bb6 commit d133d3d

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

src/sys/socket/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,21 +1780,21 @@ pub fn sockaddr_storage_to_addr(
17801780
addr: &sockaddr_storage,
17811781
len: usize) -> Result<SockAddr> {
17821782

1783-
assert!(len <= mem::size_of::<sockaddr_un>());
1783+
assert!(len <= mem::size_of::<sockaddr_storage>());
17841784
if len < mem::size_of_val(&addr.ss_family) {
17851785
return Err(Error::from(Errno::ENOTCONN));
17861786
}
17871787

17881788
match c_int::from(addr.ss_family) {
17891789
libc::AF_INET => {
1790-
assert_eq!(len as usize, mem::size_of::<sockaddr_in>());
1790+
assert!(len as usize >= mem::size_of::<sockaddr_in>());
17911791
let sin = unsafe {
17921792
*(addr as *const sockaddr_storage as *const sockaddr_in)
17931793
};
17941794
Ok(SockAddr::Inet(InetAddr::V4(sin)))
17951795
}
17961796
libc::AF_INET6 => {
1797-
assert_eq!(len as usize, mem::size_of::<sockaddr_in6>());
1797+
assert!(len as usize >= mem::size_of::<sockaddr_in6>());
17981798
let sin6 = unsafe {
17991799
*(addr as *const _ as *const sockaddr_in6)
18001800
};
@@ -1810,10 +1810,10 @@ pub fn sockaddr_storage_to_addr(
18101810
#[cfg(any(target_os = "android", target_os = "linux"))]
18111811
libc::AF_PACKET => {
18121812
use libc::sockaddr_ll;
1813+
// Don't assert anything about the size.
18131814
// Apparently the Linux kernel can return smaller sizes when
18141815
// the value in the last element of sockaddr_ll (`sll_addr`) is
18151816
// smaller than the declared size of that field
1816-
assert!(len as usize <= mem::size_of::<sockaddr_ll>());
18171817
let sll = unsafe {
18181818
*(addr as *const _ as *const sockaddr_ll)
18191819
};

test/sys/test_socket.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname};
1+
use nix::sys::socket::{AddressFamily, InetAddr, SockAddr, UnixAddr, getsockname, sockaddr, sockaddr_in6, sockaddr_storage_to_addr};
22
use std::collections::hash_map::DefaultHasher;
33
use std::hash::{Hash, Hasher};
4+
use std::mem::{self, MaybeUninit};
45
use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6};
56
use std::os::unix::io::RawFd;
67
use std::path::Path;
78
use std::slice;
89
use std::str::FromStr;
9-
use libc::c_char;
10+
use libc::{c_char, sockaddr_storage};
1011
#[cfg(any(target_os = "linux", target_os= "android"))]
1112
use crate::*;
1213

@@ -33,6 +34,29 @@ pub fn test_inetv4_addr_to_sock_addr() {
3334
assert_eq!(actual, inet);
3435
}
3536

37+
#[test]
38+
pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() {
39+
let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
40+
let addr = InetAddr::from_std(&actual);
41+
let sockaddr = SockAddr::new_inet(addr);
42+
43+
let (storage, ffi_size) = {
44+
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
45+
let storage_ptr = storage.as_mut_ptr().cast::<sockaddr>();
46+
let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
47+
assert_eq!(mem::size_of::<sockaddr>(), ffi_size as usize);
48+
unsafe {
49+
storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1);
50+
(storage.assume_init(), ffi_size)
51+
}
52+
};
53+
54+
let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
55+
assert_eq!(from_storage, sockaddr);
56+
let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()).unwrap();
57+
assert_eq!(from_storage, sockaddr);
58+
}
59+
3660
#[test]
3761
pub fn test_inetv6_addr_to_sock_addr() {
3862
let port: u16 = 3000;
@@ -54,6 +78,33 @@ pub fn test_inetv6_addr_to_sock_addr() {
5478

5579
assert_eq!(actual, addr.to_std());
5680
}
81+
#[test]
82+
pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() {
83+
let port: u16 = 3000;
84+
let flowinfo: u32 = 1;
85+
let scope_id: u32 = 2;
86+
let ip: Ipv6Addr = "fe80::1".parse().unwrap();
87+
88+
let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
89+
let addr = InetAddr::from_std(&actual);
90+
let sockaddr = SockAddr::new_inet(addr);
91+
92+
let (storage, ffi_size) = {
93+
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
94+
let storage_ptr = storage.as_mut_ptr().cast::<sockaddr_in6>();
95+
let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
96+
assert_eq!(mem::size_of::<sockaddr_in6>(), ffi_size as usize);
97+
unsafe {
98+
storage_ptr.copy_from_nonoverlapping((ffi_ptr as *const sockaddr).cast::<sockaddr_in6>(), 1);
99+
(storage.assume_init(), ffi_size)
100+
}
101+
};
102+
103+
let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
104+
assert_eq!(from_storage, sockaddr);
105+
let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()).unwrap();
106+
assert_eq!(from_storage, sockaddr);
107+
}
57108

58109
#[test]
59110
pub fn test_path_to_sock_addr() {
@@ -1169,7 +1220,6 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr
11691220
use std::io;
11701221
use std::io::Write;
11711222
use nix::ifaddrs::getifaddrs;
1172-
use nix::sys::socket::SockAddr;
11731223
use nix::net::if_::*;
11741224

11751225
let addrs = match getifaddrs() {

0 commit comments

Comments
 (0)