Skip to content

Commit 813a329

Browse files
committed
Safely convert SocketAddr into raw SOCKADDR
Do not rely on the memory layout of std::net::SocketAddrV*
1 parent 38583a6 commit 813a329

File tree

1 file changed

+61
-11
lines changed

1 file changed

+61
-11
lines changed

src/net.rs

+61-11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use std::sync::atomic::{AtomicUsize, Ordering};
1313

1414
use winapi::ctypes::*;
1515
use winapi::shared::guiddef::*;
16+
use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR};
17+
use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR};
1618
use winapi::shared::minwindef::*;
1719
use winapi::shared::minwindef::{FALSE, TRUE};
1820
use winapi::shared::ntdef::*;
@@ -456,16 +458,64 @@ fn cvt(i: c_int, size: DWORD) -> io::Result<Option<usize>> {
456458
}
457459
}
458460

459-
fn socket_addr_to_ptrs(addr: &SocketAddr) -> (*const SOCKADDR, c_int) {
461+
/// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level
462+
/// SocketAddr* types into their system representation. The benefit of this specific
463+
/// type over using `SOCKADDR_STORAGE` is that this type is exactly as large as it
464+
/// needs to be and not a lot larger. And it can be initialized cleaner from Rust.
465+
#[repr(C)]
466+
pub(crate) union SocketAddrCRepr {
467+
v4: SOCKADDR_IN,
468+
v6: SOCKADDR_IN6_LH,
469+
}
470+
471+
impl SocketAddrCRepr {
472+
pub(crate) fn as_ptr(&self) -> *const SOCKADDR {
473+
self as *const _ as *const SOCKADDR
474+
}
475+
}
476+
477+
fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) {
460478
match *addr {
461-
SocketAddr::V4(ref a) => (
462-
a as *const _ as *const _,
463-
mem::size_of::<SOCKADDR_IN>() as c_int,
464-
),
465-
SocketAddr::V6(ref a) => (
466-
a as *const _ as *const _,
467-
mem::size_of::<SOCKADDR_IN6_LH>() as c_int,
468-
),
479+
SocketAddr::V4(ref a) => {
480+
let sin_addr = unsafe {
481+
let mut s_un = mem::zeroed::<in_addr_S_un>();
482+
*s_un.S_addr_mut() = u32::from_ne_bytes(a.ip().octets());
483+
IN_ADDR { S_un: s_un }
484+
};
485+
486+
let sockaddr_in = SOCKADDR_IN {
487+
sin_family: AF_INET as ADDRESS_FAMILY,
488+
sin_port: a.port().to_be(),
489+
sin_addr,
490+
sin_zero: [0; 8],
491+
};
492+
493+
let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
494+
(sockaddr, mem::size_of::<SOCKADDR_IN>() as c_int)
495+
}
496+
SocketAddr::V6(ref a) => {
497+
let sin6_addr = unsafe {
498+
let mut u = mem::zeroed::<in6_addr_u>();
499+
*u.Byte_mut() = a.ip().octets();
500+
IN6_ADDR { u }
501+
};
502+
let u = unsafe {
503+
let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>();
504+
*u.sin6_scope_id_mut() = a.scope_id();
505+
u
506+
};
507+
508+
let sockaddr_in6 = SOCKADDR_IN6_LH {
509+
sin6_family: AF_INET6 as ADDRESS_FAMILY,
510+
sin6_port: a.port().to_be(),
511+
sin6_addr,
512+
sin6_flowinfo: a.flowinfo(),
513+
u,
514+
};
515+
516+
let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
517+
(sockaddr, mem::size_of::<SOCKADDR_IN6_LH>() as c_int)
518+
}
469519
}
470520
}
471521

@@ -650,7 +700,7 @@ unsafe fn connect_overlapped(
650700
let mut bytes_sent: DWORD = 0;
651701
let r = connect_ex(
652702
socket,
653-
addr_buf,
703+
addr_buf.as_ptr(),
654704
addr_len,
655705
buf.as_ptr() as *mut _,
656706
buf.len() as u32,
@@ -723,7 +773,7 @@ impl UdpSocketExt for UdpSocket {
723773
1,
724774
&mut sent_bytes,
725775
0,
726-
addr_buf as *const _,
776+
addr_buf.as_ptr() as *const _,
727777
addr_len,
728778
overlapped,
729779
None,

0 commit comments

Comments
 (0)