From a790f9935ab0f74f28d24507c19b7ac0ad0e3b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 10:05:22 +0100 Subject: [PATCH 01/12] Don't assume memory layout of std::net::SocketAddr --- src/sys/unix/net.rs | 80 +++++++++++++++++++++++++++++++++++---------- src/sys/unix/tcp.rs | 4 +-- src/sys/unix/udp.rs | 2 +- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index e7fc6fc5f..f4d3fe5c0 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -1,4 +1,4 @@ -use std::net::SocketAddr; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; pub(crate) fn new_ip_socket( addr: SocketAddr, @@ -64,32 +64,76 @@ pub(crate) fn new_socket( socket } -pub(crate) fn socket_addr(addr: &SocketAddr) -> (*const libc::sockaddr, libc::socklen_t) { - use std::mem::size_of_val; +/// A type with the same memory layout as `libc::sockaddr`. Used in converting Rust level +/// SocketAddr* types into their system representation. The benefit of this specific +/// type over using `libc::sockaddr_storage` is that this type is exactly as large as it +/// needs to be and not a lot larger. And it can be initialized cleaner from Rust. +#[repr(C)] +pub(crate) union SocketAddrCRepr { + v4: libc::sockaddr_in, + v6: libc::sockaddr_in6, +} + +impl SocketAddrCRepr { + pub fn as_ptr(&self) -> *const libc::sockaddr { + self as *const _ as *const libc::sockaddr + } +} + +/// Converts a Rust `SocketAddr` into the system representation. +pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) { + use std::mem; match addr { - SocketAddr::V4(ref addr) => ( - addr as *const _ as *const libc::sockaddr, - size_of_val(addr) as libc::socklen_t, - ), - SocketAddr::V6(ref addr) => ( - addr as *const _ as *const libc::sockaddr, - size_of_val(addr) as libc::socklen_t, - ), + SocketAddr::V4(ref a) => { + // `s_addr` is stored as BE on all machine and the array is in BE order. + // So the native endian conversion method is used so that it's never swapped. + let sin_addr = libc::in_addr { s_addr: u32::from_ne_bytes(a.ip().octets()) }; + + let sockaddr_in = libc::sockaddr_in { + sin_family: libc::AF_INET as libc::sa_family_t, + sin_port: a.port().to_be(), + sin_addr, + ..unsafe { mem::zeroed() } + }; + + let sockaddr = SocketAddrCRepr { v4: sockaddr_in }; + (sockaddr, mem::size_of::() as libc::socklen_t) + } + SocketAddr::V6(ref a) => { + let sockaddr_in6 = libc::sockaddr_in6 { + sin6_family: libc::AF_INET6 as libc::sa_family_t, + sin6_port: a.port().to_be(), + sin6_addr: libc::in6_addr { s6_addr: a.ip().octets() }, + sin6_flowinfo: a.flowinfo(), + sin6_scope_id: a.scope_id(), + ..unsafe { mem::zeroed() } + }; + + let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; + (sockaddr, mem::size_of::() as libc::socklen_t) + } } } -/// `storage` must be initialised to `sockaddr_in` or `sockaddr_in6`. +/// Converts a `libc::sockaddr` compatible struct into a native Rust `SocketAddr`. +/// SAFETY: `storage` must be initialised to `sockaddr_in` or `sockaddr_in6`. pub(crate) unsafe fn to_socket_addr( storage: *const libc::sockaddr_storage, ) -> std::io::Result { match (*storage).ss_family as libc::c_int { - libc::AF_INET => Ok(SocketAddr::V4( - *(storage as *const libc::sockaddr_in as *const _), - )), - libc::AF_INET6 => Ok(SocketAddr::V6( - *(storage as *const libc::sockaddr_in6 as *const _), - )), + libc::AF_INET => { + let addr: &libc::sockaddr_in = &*(storage as *const libc::sockaddr_in); + let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()); + let port = u16::from_be(addr.sin_port); + Ok(SocketAddr::V4(SocketAddrV4::new(ip, port))) + }, + libc::AF_INET6 => { + let addr: &libc::sockaddr_in6 = &*(storage as *const libc::sockaddr_in6); + let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr); + let port = u16::from_be(addr.sin6_port); + Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, addr.sin6_flowinfo, addr.sin6_scope_id))) + }, _ => Err(std::io::ErrorKind::InvalidInput.into()), } } diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs index 8d5f5aa5c..911b019ae 100644 --- a/src/sys/unix/tcp.rs +++ b/src/sys/unix/tcp.rs @@ -20,14 +20,14 @@ pub(crate) fn new_v6_socket() -> io::Result { pub(crate) fn bind(socket: TcpSocket, addr: SocketAddr) -> io::Result<()> { let (raw_addr, raw_addr_length) = socket_addr(&addr); - syscall!(bind(socket, raw_addr, raw_addr_length))?; + syscall!(bind(socket, raw_addr.as_ptr(), raw_addr_length))?; Ok(()) } pub(crate) fn connect(socket: TcpSocket, addr: SocketAddr) -> io::Result { let (raw_addr, raw_addr_length) = socket_addr(&addr); - match syscall!(connect(socket, raw_addr, raw_addr_length)) { + match syscall!(connect(socket, raw_addr.as_ptr(), raw_addr_length)) { Err(err) if err.raw_os_error() != Some(libc::EINPROGRESS) => { Err(err) } diff --git a/src/sys/unix/udp.rs b/src/sys/unix/udp.rs index 947a60af2..e9c4d4cd2 100644 --- a/src/sys/unix/udp.rs +++ b/src/sys/unix/udp.rs @@ -11,7 +11,7 @@ pub fn bind(addr: SocketAddr) -> io::Result { socket.and_then(|socket| { let (raw_addr, raw_addr_length) = socket_addr(&addr); - syscall!(bind(socket, raw_addr, raw_addr_length)) + syscall!(bind(socket, raw_addr.as_ptr(), raw_addr_length)) .map_err(|err| { // Close the socket if we hit an error, ignoring the error // from closing since we can't pass back two errors. From 6c47b150f6ca6063fcdd94de5ed0e79bbc437e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 18:43:40 +0100 Subject: [PATCH 02/12] Remove mem::zeroed() in favor of explicitly initializing fields --- src/sys/unix/net.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index f4d3fe5c0..a24f29d2d 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -94,7 +94,7 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ sin_family: libc::AF_INET as libc::sa_family_t, sin_port: a.port().to_be(), sin_addr, - ..unsafe { mem::zeroed() } + sin_zero: [0; 8], }; let sockaddr = SocketAddrCRepr { v4: sockaddr_in }; @@ -107,7 +107,15 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ sin6_addr: libc::in6_addr { s6_addr: a.ip().octets() }, sin6_flowinfo: a.flowinfo(), sin6_scope_id: a.scope_id(), - ..unsafe { mem::zeroed() } + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin6_len: 0, }; let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; From 036cc9ac307b104147054815d107beba78d5bfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 18:49:04 +0100 Subject: [PATCH 03/12] Move import to top of file --- src/sys/unix/net.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index a24f29d2d..0b1d1c5de 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -1,3 +1,4 @@ +use std::mem; use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; pub(crate) fn new_ip_socket( @@ -82,8 +83,6 @@ impl SocketAddrCRepr { /// Converts a Rust `SocketAddr` into the system representation. pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) { - use std::mem; - match addr { SocketAddr::V4(ref a) => { // `s_addr` is stored as BE on all machine and the array is in BE order. From 2c08872e0658a63a8e7ba29828c86adce10db75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 18:49:28 +0100 Subject: [PATCH 04/12] Add proper safety documentation to to_socket_addr --- src/sys/unix/net.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index 0b1d1c5de..dd6ccfa6e 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -124,18 +124,24 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ } /// Converts a `libc::sockaddr` compatible struct into a native Rust `SocketAddr`. -/// SAFETY: `storage` must be initialised to `sockaddr_in` or `sockaddr_in6`. +/// +/// # Safety +/// +/// `storage` must have the `ss_family` field correctly initialized. +/// `storage` must be initialised to a `sockaddr_in` or `sockaddr_in6`. pub(crate) unsafe fn to_socket_addr( storage: *const libc::sockaddr_storage, ) -> std::io::Result { match (*storage).ss_family as libc::c_int { libc::AF_INET => { + // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in. let addr: &libc::sockaddr_in = &*(storage as *const libc::sockaddr_in); let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()); let port = u16::from_be(addr.sin_port); Ok(SocketAddr::V4(SocketAddrV4::new(ip, port))) }, libc::AF_INET6 => { + // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6. let addr: &libc::sockaddr_in6 = &*(storage as *const libc::sockaddr_in6); let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr); let port = u16::from_be(addr.sin6_port); From f0ef9940ce5c9a725eb3d64601dcaa1e6a1010e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 19:00:17 +0100 Subject: [PATCH 05/12] Add sin_len to sockaddr_in --- src/sys/unix/net.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index dd6ccfa6e..5183bda31 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -94,6 +94,15 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ sin_port: a.port().to_be(), sin_addr, sin_zero: [0; 8], + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin_len: 0, }; let sockaddr = SocketAddrCRepr { v4: sockaddr_in }; From 022a89dd13b43b7f36653508b092112833d212f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 19:41:05 +0100 Subject: [PATCH 06/12] Initialize __sin6_src_id on solarish --- src/sys/unix/net.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index 5183bda31..a3b517b65 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -124,6 +124,8 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ target_os = "openbsd" ))] sin6_len: 0, + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + __sin6_src_id: 0, }; let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; From 102b62993f717d2b71897834678029e897ea077f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 19:41:20 +0100 Subject: [PATCH 07/12] Make SocketAddrCRepr::as_ptr a pub(crate) --- src/sys/unix/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index a3b517b65..77886bd14 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -76,7 +76,7 @@ pub(crate) union SocketAddrCRepr { } impl SocketAddrCRepr { - pub fn as_ptr(&self) -> *const libc::sockaddr { + pub(crate) fn as_ptr(&self) -> *const libc::sockaddr { self as *const _ as *const libc::sockaddr } } From 75cdea2c14c81678dbecdfba67c8b75c583b1cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 20:16:39 +0100 Subject: [PATCH 08/12] Windows: Don't assume memory layout of std::net::SocketAddr --- src/sys/windows/net.rs | 60 ++++++++++++++++++++++++++++++++++-------- src/sys/windows/tcp.rs | 4 +-- src/sys/windows/udp.rs | 2 +- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/sys/windows/net.rs b/src/sys/windows/net.rs index 1eb9fc24e..39a94ff96 100644 --- a/src/sys/windows/net.rs +++ b/src/sys/windows/net.rs @@ -1,10 +1,13 @@ use std::io; -use std::mem::size_of_val; +use std::mem; use std::net::SocketAddr; use std::sync::Once; use winapi::ctypes::c_int; -use winapi::shared::ws2def::SOCKADDR; +use winapi::shared::inaddr::IN_ADDR; +use winapi::shared::in6addr::IN6_ADDR; +use winapi::shared::ws2def::{AF_INET, AF_INET6, ADDRESS_FAMILY, SOCKADDR, SOCKADDR_IN}; +use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH; use winapi::um::winsock2::{ioctlsocket, socket, FIONBIO, INVALID_SOCKET, SOCKET}; /// Initialise the network stack for Windows. @@ -41,15 +44,50 @@ pub(crate) fn new_socket(domain: c_int, socket_type: c_int) -> io::Result (*const SOCKADDR, c_int) { +/// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level +/// SocketAddr* types into their system representation. The benefit of this specific +/// type over using `SOCKADDR_STORAGE` is that this type is exactly as large as it +/// needs to be and not a lot larger. And it can be initialized cleaner from Rust. +#[repr(C)] +pub(crate) union SocketAddrCRepr { + v4: SOCKADDR_IN, + v6: SOCKADDR_IN6_LH, +} + +impl SocketAddrCRepr { + pub(crate) fn as_ptr(&self) -> *const SOCKADDR { + self as *const _ as *const SOCKADDR + } +} + +pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { match addr { - SocketAddr::V4(ref addr) => ( - addr as *const _ as *const SOCKADDR, - size_of_val(addr) as c_int, - ), - SocketAddr::V6(ref addr) => ( - addr as *const _ as *const SOCKADDR, - size_of_val(addr) as c_int, - ), + SocketAddr::V4(ref addr) => { + // `s_addr` is stored as BE on all machine and the array is in BE order. + // So the native endian conversion method is used so that it's never swapped. + let sin_addr = IN_ADDR { S_un: unsafe { mem::transmute(u32::from_ne_bytes(addr.ip().octets())) } }; + + let sockaddr_in = SOCKADDR_IN { + sin_family: AF_INET as ADDRESS_FAMILY, + sin_port: addr.port().to_be(), + sin_addr, + sin_zero: [0; 8], + }; + + let sockaddr = SocketAddrCRepr { v4: sockaddr_in }; + (sockaddr, mem::size_of::() as c_int) + }, + SocketAddr::V6(ref addr) => { + let sockaddr_in6 = SOCKADDR_IN6_LH { + sin6_family: AF_INET6 as ADDRESS_FAMILY, + sin6_port: addr.port().to_be(), + sin6_addr: IN6_ADDR { u: unsafe { mem::transmute(addr.ip().octets()) } }, + sin6_flowinfo: addr.flowinfo(), + u: unsafe { mem::transmute(addr.scope_id()) }, + }; + + let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; + (sockaddr, mem::size_of::() as c_int) + } } } diff --git a/src/sys/windows/tcp.rs b/src/sys/windows/tcp.rs index e14f1c8bd..c4c63d60f 100644 --- a/src/sys/windows/tcp.rs +++ b/src/sys/windows/tcp.rs @@ -35,7 +35,7 @@ pub(crate) fn bind(socket: TcpSocket, addr: SocketAddr) -> io::Result<()> { let (raw_addr, raw_addr_length) = socket_addr(&addr); syscall!( - bind(socket, raw_addr, raw_addr_length), + bind(socket, raw_addr.as_ptr(), raw_addr_length), PartialEq::eq, SOCKET_ERROR )?; @@ -48,7 +48,7 @@ pub(crate) fn connect(socket: TcpSocket, addr: SocketAddr) -> io::Result io::Result { new_ip_socket(addr, SOCK_DGRAM).and_then(|socket| { let (raw_addr, raw_addr_length) = socket_addr(&addr); syscall!( - win_bind(socket, raw_addr, raw_addr_length,), + win_bind(socket, raw_addr.as_ptr(), raw_addr_length,), PartialEq::eq, SOCKET_ERROR ) From b6f89d6331fe5091e8eaedba441c1889c2c964ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 21:04:05 +0100 Subject: [PATCH 09/12] Windows: Make converting SOCKADDR -> SocketAddr safe --- src/sys/windows/tcp.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/sys/windows/tcp.rs b/src/sys/windows/tcp.rs index c4c63d60f..5a267b8a1 100644 --- a/src/sys/windows/tcp.rs +++ b/src/sys/windows/tcp.rs @@ -1,13 +1,13 @@ use std::io; use std::mem::size_of; -use std::net::{self, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::time::Duration; use std::convert::TryInto; use std::os::windows::io::FromRawSocket; use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64. use winapi::ctypes::{c_char, c_int, c_ushort}; -use winapi::shared::ws2def::{SOCKADDR_STORAGE, AF_INET, SOCKADDR_IN}; +use winapi::shared::ws2def::{SOCKADDR_STORAGE, AF_INET, AF_INET6, SOCKADDR_IN}; use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH; use winapi::shared::minwindef::{BOOL, TRUE, FALSE}; @@ -108,28 +108,35 @@ pub(crate) fn get_reuseaddr(socket: TcpSocket) -> io::Result { } pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result { - let mut addr: SOCKADDR_STORAGE = unsafe { std::mem::zeroed() }; - let mut length = std::mem::size_of_val(&addr) as c_int; + let mut storage: SOCKADDR_STORAGE = unsafe { std::mem::zeroed() }; + let mut length = std::mem::size_of_val(&storage) as c_int; match unsafe { getsockname( socket, - &mut addr as *mut _ as *mut _, + &mut storage as *mut _ as *mut _, &mut length ) } { SOCKET_ERROR => Err(io::Error::last_os_error()), _ => { - let storage: *const SOCKADDR_STORAGE = (&addr) as *const _; - if addr.ss_family as c_int == AF_INET { - let sock_addr : SocketAddrV4 = unsafe { *(storage as *const SOCKADDR_IN as *const _) }; - Ok(sock_addr.into()) + if storage.ss_family as c_int == AF_INET { + // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in. + let addr: &SOCKADDR_IN = unsafe { &*(&storage as *const _ as *const SOCKADDR_IN) }; + let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() }; + let ip = Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]); + let port = u16::from_be(addr.sin_port); + Ok(SocketAddr::V4(SocketAddrV4::new(ip, port))) + } else if storage.ss_family as c_int == AF_INET6 { + // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6. + let addr: &SOCKADDR_IN6_LH = unsafe { &*(&storage as *const _ as *const SOCKADDR_IN6_LH) }; + let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() }); + let port = u16::from_be(addr.sin6_port); + let scope_id = unsafe { *addr.u.sin6_scope_id() }; + Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, addr.sin6_flowinfo, scope_id))) } else { - let sock_addr : SocketAddrV6 = unsafe { *(storage as *const SOCKADDR_IN6_LH as *const _) }; - Ok(sock_addr.into()) + panic!("Invalid ss_family"); } }, } - - } pub(crate) fn set_linger(socket: TcpSocket, dur: Option) -> io::Result<()> { From ba9a2f9a810cea096d186a4bad7763e1ba8369ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 11:24:55 +0100 Subject: [PATCH 10/12] Replace panic with error value --- src/sys/windows/tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/windows/tcp.rs b/src/sys/windows/tcp.rs index 5a267b8a1..f66ffbcd2 100644 --- a/src/sys/windows/tcp.rs +++ b/src/sys/windows/tcp.rs @@ -133,7 +133,7 @@ pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result { let scope_id = unsafe { *addr.u.sin6_scope_id() }; Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, addr.sin6_flowinfo, scope_id))) } else { - panic!("Invalid ss_family"); + Err(std::io::ErrorKind::InvalidInput.into()) } }, } From 382626671c1e4134820df60d993582483a03d63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 11:58:30 +0100 Subject: [PATCH 11/12] Replace transmuting with better winapi union handling --- src/sys/windows/net.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/sys/windows/net.rs b/src/sys/windows/net.rs index 39a94ff96..2de98fa70 100644 --- a/src/sys/windows/net.rs +++ b/src/sys/windows/net.rs @@ -4,10 +4,10 @@ use std::net::SocketAddr; use std::sync::Once; use winapi::ctypes::c_int; -use winapi::shared::inaddr::IN_ADDR; -use winapi::shared::in6addr::IN6_ADDR; +use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR}; +use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR}; use winapi::shared::ws2def::{AF_INET, AF_INET6, ADDRESS_FAMILY, SOCKADDR, SOCKADDR_IN}; -use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH; +use winapi::shared::ws2ipdef::{SOCKADDR_IN6_LH, SOCKADDR_IN6_LH_u}; use winapi::um::winsock2::{ioctlsocket, socket, FIONBIO, INVALID_SOCKET, SOCKET}; /// Initialise the network stack for Windows. @@ -65,7 +65,11 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { SocketAddr::V4(ref addr) => { // `s_addr` is stored as BE on all machine and the array is in BE order. // So the native endian conversion method is used so that it's never swapped. - let sin_addr = IN_ADDR { S_un: unsafe { mem::transmute(u32::from_ne_bytes(addr.ip().octets())) } }; + let sin_addr = unsafe { + let mut s_un = mem::zeroed::(); + *s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets()); + IN_ADDR { S_un: s_un } + }; let sockaddr_in = SOCKADDR_IN { sin_family: AF_INET as ADDRESS_FAMILY, @@ -78,12 +82,23 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { (sockaddr, mem::size_of::() as c_int) }, SocketAddr::V6(ref addr) => { + let sin6_addr = unsafe { + let mut u = mem::zeroed::(); + *u.Byte_mut() = addr.ip().octets(); + IN6_ADDR { u } + }; + let u = unsafe { + let mut u = mem::zeroed::(); + *u.sin6_scope_id_mut() = addr.scope_id(); + u + }; + let sockaddr_in6 = SOCKADDR_IN6_LH { sin6_family: AF_INET6 as ADDRESS_FAMILY, sin6_port: addr.port().to_be(), - sin6_addr: IN6_ADDR { u: unsafe { mem::transmute(addr.ip().octets()) } }, + sin6_addr, sin6_flowinfo: addr.flowinfo(), - u: unsafe { mem::transmute(addr.scope_id()) }, + u, }; let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; From 8d3ed77d300b07e086b5cd4253dbde4cf5b40780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 12:06:57 +0100 Subject: [PATCH 12/12] More consistent naming --- src/sys/unix/net.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index 77886bd14..ce9a7fb65 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -84,14 +84,14 @@ impl SocketAddrCRepr { /// Converts a Rust `SocketAddr` into the system representation. pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) { match addr { - SocketAddr::V4(ref a) => { + SocketAddr::V4(ref addr) => { // `s_addr` is stored as BE on all machine and the array is in BE order. // So the native endian conversion method is used so that it's never swapped. - let sin_addr = libc::in_addr { s_addr: u32::from_ne_bytes(a.ip().octets()) }; + let sin_addr = libc::in_addr { s_addr: u32::from_ne_bytes(addr.ip().octets()) }; let sockaddr_in = libc::sockaddr_in { sin_family: libc::AF_INET as libc::sa_family_t, - sin_port: a.port().to_be(), + sin_port: addr.port().to_be(), sin_addr, sin_zero: [0; 8], #[cfg(any( @@ -108,13 +108,13 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ let sockaddr = SocketAddrCRepr { v4: sockaddr_in }; (sockaddr, mem::size_of::() as libc::socklen_t) } - SocketAddr::V6(ref a) => { + SocketAddr::V6(ref addr) => { let sockaddr_in6 = libc::sockaddr_in6 { sin6_family: libc::AF_INET6 as libc::sa_family_t, - sin6_port: a.port().to_be(), - sin6_addr: libc::in6_addr { s6_addr: a.ip().octets() }, - sin6_flowinfo: a.flowinfo(), - sin6_scope_id: a.scope_id(), + sin6_port: addr.port().to_be(), + sin6_addr: libc::in6_addr { s6_addr: addr.ip().octets() }, + sin6_flowinfo: addr.flowinfo(), + sin6_scope_id: addr.scope_id(), #[cfg(any( target_os = "dragonfly", target_os = "freebsd",