diff --git a/CHANGELOG.md b/CHANGELOG.md index 552320254e..5ccbe81bb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1302](https://github.com/nix-rust/nix/pull/1302)) - Added `ptrace::interrupt` method for platforms that support `PTRACE_INTERRUPT` (#[1422](https://github.com/nix-rust/nix/pull/1422)) +- Added `IP6T_SO_ORIGINAL_DST` sockopt. + (#[1490](https://github.com/nix-rust/nix/pull/1490)) ### Changed diff --git a/README.md b/README.md index 5031b02e5e..5c900a447b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Rust bindings to *nix APIs [![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix) -[![crates.io](https://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix) +[![crates.io](https://img.shields.io/crates/v/nix.svg)](https://crates.io/crates/nix) [Documentation (Releases)](https://docs.rs/nix/) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 733bd6608b..f701a7312a 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1780,21 +1780,21 @@ pub fn sockaddr_storage_to_addr( addr: &sockaddr_storage, len: usize) -> Result { - assert!(len <= mem::size_of::()); + assert!(len <= mem::size_of::()); 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::()); + assert!(len as usize >= mem::size_of::()); 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::()); + assert!(len as usize >= mem::size_of::()); let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; @@ -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::()); let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 82df7f87d1..ca8fb1a0f2 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -283,6 +283,8 @@ sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!(GetOnly, Ip6tOriginalDst, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6); sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); #[cfg(all(target_os = "linux"))] sockopt_impl!(Both, ReceiveTimestampns, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool); diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 5471afe3d8..c43d0672ec 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -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::*; @@ -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::::zeroed(); + let storage_ptr = storage.as_mut_ptr().cast::(); + let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); + assert_eq!(mem::size_of::(), 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::()).unwrap(); + assert_eq!(from_storage, sockaddr); +} + #[test] pub fn test_inetv6_addr_to_sock_addr() { let port: u16 = 3000; @@ -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::::zeroed(); + let storage_ptr = storage.as_mut_ptr().cast::(); + let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); + assert_eq!(mem::size_of::(), ffi_size as usize); + unsafe { + storage_ptr.copy_from_nonoverlapping((ffi_ptr as *const sockaddr).cast::(), 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::()).unwrap(); + assert_eq!(from_storage, sockaddr); +} #[test] pub fn test_path_to_sock_addr() { @@ -1169,7 +1220,6 @@ fn loopback_address(family: AddressFamily) -> Option