Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax assertions in sockaddr_storage_to_addr to match the documentation. #1486

Merged
merged 1 commit into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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