Skip to content

Commit 2783715

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

File tree

1 file changed

+57
-5
lines changed

1 file changed

+57
-5
lines changed

Diff for: src/net.rs

+57-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use std::os::windows::prelude::*;
1313

1414
use net2::TcpBuilder;
1515
use winapi::*;
16+
use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR};
17+
use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR};
1618
use ws2_32::*;
1719

1820
/// 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<Option<usize>> {
478480
}
479481
}
480482

481-
fn socket_addr_to_ptrs(addr: &SocketAddr) -> (*const SOCKADDR, c_int) {
483+
/// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level
484+
/// SocketAddr* types into their system representation. The benefit of this specific
485+
/// type over using `SOCKADDR_STORAGE` is that this type is exactly as large as it
486+
/// needs to be and not a lot larger. And it can be initialized cleaner from Rust.
487+
#[repr(C)]
488+
pub(crate) union SocketAddrCRepr {
489+
v4: SOCKADDR_IN,
490+
v6: SOCKADDR_IN6_LH,
491+
}
492+
493+
impl SocketAddrCRepr {
494+
pub(crate) fn as_ptr(&self) -> *const SOCKADDR {
495+
self as *const _ as *const SOCKADDR
496+
}
497+
}
498+
499+
fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) {
482500
match *addr {
483501
SocketAddr::V4(ref a) => {
484-
(a as *const _ as *const _, mem::size_of::<SOCKADDR_IN>() as c_int)
502+
let sin_addr = unsafe {
503+
let mut s_un = mem::zeroed::<in_addr_S_un>();
504+
*s_un.S_addr_mut() = u32::from_ne_bytes(a.ip().octets());
505+
IN_ADDR { S_un: s_un }
506+
};
507+
508+
let sockaddr_in = SOCKADDR_IN {
509+
sin_family: AF_INET as ADDRESS_FAMILY,
510+
sin_port: a.port().to_be(),
511+
sin_addr,
512+
sin_zero: [0; 8],
513+
};
514+
515+
let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
516+
(sockaddr, mem::size_of::<SOCKADDR_IN>() as c_int)
485517
}
486518
SocketAddr::V6(ref a) => {
487-
(a as *const _ as *const _, mem::size_of::<sockaddr_in6>() as c_int)
519+
let sin6_addr = unsafe {
520+
let mut u = mem::zeroed::<in6_addr_u>();
521+
*u.Byte_mut() = a.ip().octets();
522+
IN6_ADDR { u }
523+
};
524+
let u = unsafe {
525+
let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>();
526+
*u.sin6_scope_id_mut() = a.scope_id();
527+
u
528+
};
529+
530+
let sockaddr_in6 = SOCKADDR_IN6_LH {
531+
sin6_family: AF_INET6 as ADDRESS_FAMILY,
532+
sin6_port: a.port().to_be(),
533+
sin6_addr,
534+
sin6_flowinfo: a.flowinfo(),
535+
u,
536+
};
537+
538+
let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
539+
(sockaddr, mem::size_of::<SOCKADDR_IN6_LH>() as c_int)
488540
}
489541
}
490542
}
@@ -643,7 +695,7 @@ unsafe fn connect_overlapped(socket: SOCKET,
643695

644696
let (addr_buf, addr_len) = socket_addr_to_ptrs(addr);
645697
let mut bytes_sent: DWORD = 0;
646-
let r = connect_ex(socket, addr_buf, addr_len,
698+
let r = connect_ex(socket, addr_buf.as_ptr(), addr_len,
647699
buf.as_ptr() as *mut _,
648700
buf.len() as u32,
649701
&mut bytes_sent, overlapped);
@@ -694,7 +746,7 @@ impl UdpSocketExt for UdpSocket {
694746
let mut sent_bytes = 0;
695747
let r = WSASendTo(self.as_raw_socket(), &mut buf, 1,
696748
&mut sent_bytes, 0,
697-
addr_buf as *const _, addr_len,
749+
addr_buf.as_ptr() as *const _, addr_len,
698750
overlapped, None);
699751
cvt(r, sent_bytes)
700752
}

0 commit comments

Comments
 (0)