Skip to content

Commit

Permalink
Merge #1486
Browse files Browse the repository at this point in the history
1486: Relax assertions in sockaddr_storage_to_addr to match the documentation. r=asomers a=khuey

Fixes #1479

Co-authored-by: Kyle Huey <[email protected]>
  • Loading branch information
bors[bot] and khuey authored Aug 18, 2021
2 parents 5ed5bb6 + d133d3d commit 5fe5142
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
8 changes: 4 additions & 4 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1780,21 +1780,21 @@ pub fn sockaddr_storage_to_addr(
addr: &sockaddr_storage,
len: usize) -> Result<SockAddr> {

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

match c_int::from(addr.ss_family) {
libc::AF_INET => {
assert_eq!(len as usize, mem::size_of::<sockaddr_in>());
assert!(len as usize >= mem::size_of::<sockaddr_in>());
let sin = unsafe {
*(addr as *const sockaddr_storage as *const sockaddr_in)
};
Ok(SockAddr::Inet(InetAddr::V4(sin)))
}
libc::AF_INET6 => {
assert_eq!(len as usize, mem::size_of::<sockaddr_in6>());
assert!(len as usize >= mem::size_of::<sockaddr_in6>());
let sin6 = unsafe {
*(addr as *const _ as *const sockaddr_in6)
};
Expand All @@ -1810,10 +1810,10 @@ pub fn sockaddr_storage_to_addr(
#[cfg(any(target_os = "android", target_os = "linux"))]
libc::AF_PACKET => {
use libc::sockaddr_ll;
// Don't assert anything about the size.
// Apparently the Linux kernel can return smaller sizes when
// the value in the last element of sockaddr_ll (`sll_addr`) is
// smaller than the declared size of that field
assert!(len as usize <= mem::size_of::<sockaddr_ll>());
let sll = unsafe {
*(addr as *const _ as *const sockaddr_ll)
};
Expand Down
56 changes: 53 additions & 3 deletions test/sys/test_socket.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname};
use nix::sys::socket::{AddressFamily, InetAddr, SockAddr, UnixAddr, getsockname, sockaddr, sockaddr_in6, sockaddr_storage_to_addr};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::mem::{self, MaybeUninit};
use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6};
use std::os::unix::io::RawFd;
use std::path::Path;
use std::slice;
use std::str::FromStr;
use libc::c_char;
use libc::{c_char, sockaddr_storage};
#[cfg(any(target_os = "linux", target_os= "android"))]
use crate::*;

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

#[test]
pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() {
let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
let addr = InetAddr::from_std(&actual);
let sockaddr = SockAddr::new_inet(addr);

let (storage, ffi_size) = {
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
let storage_ptr = storage.as_mut_ptr().cast::<sockaddr>();
let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
assert_eq!(mem::size_of::<sockaddr>(), ffi_size as usize);
unsafe {
storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1);
(storage.assume_init(), ffi_size)
}
};

let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
assert_eq!(from_storage, sockaddr);
let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()).unwrap();
assert_eq!(from_storage, sockaddr);
}

#[test]
pub fn test_inetv6_addr_to_sock_addr() {
let port: u16 = 3000;
Expand All @@ -54,6 +78,33 @@ pub fn test_inetv6_addr_to_sock_addr() {

assert_eq!(actual, addr.to_std());
}
#[test]
pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() {
let port: u16 = 3000;
let flowinfo: u32 = 1;
let scope_id: u32 = 2;
let ip: Ipv6Addr = "fe80::1".parse().unwrap();

let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
let addr = InetAddr::from_std(&actual);
let sockaddr = SockAddr::new_inet(addr);

let (storage, ffi_size) = {
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
let storage_ptr = storage.as_mut_ptr().cast::<sockaddr_in6>();
let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
assert_eq!(mem::size_of::<sockaddr_in6>(), ffi_size as usize);
unsafe {
storage_ptr.copy_from_nonoverlapping((ffi_ptr as *const sockaddr).cast::<sockaddr_in6>(), 1);
(storage.assume_init(), ffi_size)
}
};

let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
assert_eq!(from_storage, sockaddr);
let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()).unwrap();
assert_eq!(from_storage, sockaddr);
}

#[test]
pub fn test_path_to_sock_addr() {
Expand Down Expand Up @@ -1169,7 +1220,6 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr
use std::io;
use std::io::Write;
use nix::ifaddrs::getifaddrs;
use nix::sys::socket::SockAddr;
use nix::net::if_::*;

let addrs = match getifaddrs() {
Expand Down

0 comments on commit 5fe5142

Please sign in to comment.