From 2783715269d56a0020160179c0f2ba883d12d874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 14 Nov 2020 09:56:21 +0100 Subject: [PATCH 1/4] Safely convert SocketAddr into raw SOCKADDR Do not rely on the memory layout of std::net::SocketAddrV* --- src/net.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/src/net.rs b/src/net.rs index f3d1930..95ee93a 100644 --- a/src/net.rs +++ b/src/net.rs @@ -13,6 +13,8 @@ use std::os::windows::prelude::*; use net2::TcpBuilder; use winapi::*; +use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR}; +use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR}; use ws2_32::*; /// A type to represent a buffer in which a socket address will be stored. @@ -478,13 +480,63 @@ fn cvt(i: c_int, size: DWORD) -> io::Result> { } } -fn socket_addr_to_ptrs(addr: &SocketAddr) -> (*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 + } +} + +fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { match *addr { SocketAddr::V4(ref a) => { - (a as *const _ as *const _, mem::size_of::() as c_int) + let sin_addr = unsafe { + let mut s_un = mem::zeroed::(); + *s_un.S_addr_mut() = u32::from_ne_bytes(a.ip().octets()); + IN_ADDR { S_un: s_un } + }; + + let sockaddr_in = SOCKADDR_IN { + sin_family: AF_INET as ADDRESS_FAMILY, + sin_port: a.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 a) => { - (a as *const _ as *const _, mem::size_of::() as c_int) + let sin6_addr = unsafe { + let mut u = mem::zeroed::(); + *u.Byte_mut() = a.ip().octets(); + IN6_ADDR { u } + }; + let u = unsafe { + let mut u = mem::zeroed::(); + *u.sin6_scope_id_mut() = a.scope_id(); + u + }; + + let sockaddr_in6 = SOCKADDR_IN6_LH { + sin6_family: AF_INET6 as ADDRESS_FAMILY, + sin6_port: a.port().to_be(), + sin6_addr, + sin6_flowinfo: a.flowinfo(), + u, + }; + + let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; + (sockaddr, mem::size_of::() as c_int) } } } @@ -643,7 +695,7 @@ unsafe fn connect_overlapped(socket: SOCKET, let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); let mut bytes_sent: DWORD = 0; - let r = connect_ex(socket, addr_buf, addr_len, + let r = connect_ex(socket, addr_buf.as_ptr(), addr_len, buf.as_ptr() as *mut _, buf.len() as u32, &mut bytes_sent, overlapped); @@ -694,7 +746,7 @@ impl UdpSocketExt for UdpSocket { let mut sent_bytes = 0; let r = WSASendTo(self.as_raw_socket(), &mut buf, 1, &mut sent_bytes, 0, - addr_buf as *const _, addr_len, + addr_buf.as_ptr() as *const _, addr_len, overlapped, None); cvt(r, sent_bytes) } From 27b77cc870b922d305015841978b581ceb18e3b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 14 Nov 2020 10:42:25 +0100 Subject: [PATCH 2/4] Adapt to winapi 0.2 --- src/net.rs | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/src/net.rs b/src/net.rs index 95ee93a..fd1092b 100644 --- a/src/net.rs +++ b/src/net.rs @@ -13,8 +13,9 @@ use std::os::windows::prelude::*; use net2::TcpBuilder; use winapi::*; -use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR}; -use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR}; +use winapi::inaddr::IN_ADDR; +use winapi::ws2def::SOCKADDR_IN; +use winapi::ws2ipdef::{in6_addr, sockaddr_in6}; use ws2_32::*; /// A type to represent a buffer in which a socket address will be stored. @@ -487,7 +488,7 @@ fn cvt(i: c_int, size: DWORD) -> io::Result> { #[repr(C)] pub(crate) union SocketAddrCRepr { v4: SOCKADDR_IN, - v6: SOCKADDR_IN6_LH, + v6: sockaddr_in6, } impl SocketAddrCRepr { @@ -499,16 +500,10 @@ impl SocketAddrCRepr { fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { match *addr { SocketAddr::V4(ref a) => { - let sin_addr = unsafe { - let mut s_un = mem::zeroed::(); - *s_un.S_addr_mut() = u32::from_ne_bytes(a.ip().octets()); - IN_ADDR { S_un: s_un } - }; - let sockaddr_in = SOCKADDR_IN { sin_family: AF_INET as ADDRESS_FAMILY, sin_port: a.port().to_be(), - sin_addr, + sin_addr: IN_ADDR { S_un: u32::from_ne_bytes(a.ip().octets()) }, sin_zero: [0; 8], }; @@ -516,27 +511,16 @@ fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { (sockaddr, mem::size_of::() as c_int) } SocketAddr::V6(ref a) => { - let sin6_addr = unsafe { - let mut u = mem::zeroed::(); - *u.Byte_mut() = a.ip().octets(); - IN6_ADDR { u } - }; - let u = unsafe { - let mut u = mem::zeroed::(); - *u.sin6_scope_id_mut() = a.scope_id(); - u - }; - - let sockaddr_in6 = SOCKADDR_IN6_LH { - sin6_family: AF_INET6 as ADDRESS_FAMILY, + let sockaddr_in6 = sockaddr_in6 { + sin6_family: AF_INET6 as i16, sin6_port: a.port().to_be(), - sin6_addr, + sin6_addr: in6_addr { s6_addr: a.ip().octets() }, sin6_flowinfo: a.flowinfo(), - u, + sin6_scope_id: a.scope_id(), }; let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; - (sockaddr, mem::size_of::() as c_int) + (sockaddr, mem::size_of::() as c_int) } } } From 3e217e34994923c4ef99aa3209aa9448b9e8b798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 27 Nov 2020 22:56:32 +0100 Subject: [PATCH 3/4] Bump net2 dep to 0.2.36 without invalid SocketAddr convertion --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6e42523..927e249 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ abstractions. winapi = "0.2" kernel32-sys = "0.2" ws2_32-sys = "0.2" -net2 = { version = "0.2.5", default-features = false } +net2 = { version = "0.2.36", default-features = false } [dev-dependencies] rand = "0.3" From ca8db5365495d6da42b2f26f2062fb5e12b6c329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 27 Nov 2020 23:19:00 +0100 Subject: [PATCH 4/4] Stop using from_ne_bytes to be compatible with Rust < 1.32.0 --- src/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net.rs b/src/net.rs index fd1092b..5c6eb45 100644 --- a/src/net.rs +++ b/src/net.rs @@ -503,7 +503,7 @@ fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { let sockaddr_in = SOCKADDR_IN { sin_family: AF_INET as ADDRESS_FAMILY, sin_port: a.port().to_be(), - sin_addr: IN_ADDR { S_un: u32::from_ne_bytes(a.ip().octets()) }, + sin_addr: IN_ADDR { S_un: u32::from(*a.ip()).to_be() }, sin_zero: [0; 8], };