Skip to content

Commit a00e696

Browse files
committed
Windows: Make converting SOCKADDR -> SocketAddr safe
1 parent 75cdea2 commit a00e696

File tree

1 file changed

+18
-13
lines changed

1 file changed

+18
-13
lines changed

src/sys/windows/tcp.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::io;
22
use std::mem::size_of;
3-
use std::net::{self, SocketAddr, SocketAddrV4, SocketAddrV6};
3+
use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
44
use std::time::Duration;
55
use std::convert::TryInto;
66
use std::os::windows::io::FromRawSocket;
77
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.
88

99
use winapi::ctypes::{c_char, c_int, c_ushort};
10-
use winapi::shared::ws2def::{SOCKADDR_STORAGE, AF_INET, SOCKADDR_IN};
10+
use winapi::shared::ws2def::{SOCKADDR_STORAGE, AF_INET, AF_INET6, SOCKADDR_IN};
1111
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH;
1212

1313
use winapi::shared::minwindef::{BOOL, TRUE, FALSE};
@@ -108,28 +108,33 @@ pub(crate) fn get_reuseaddr(socket: TcpSocket) -> io::Result<bool> {
108108
}
109109

110110
pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result<SocketAddr> {
111-
let mut addr: SOCKADDR_STORAGE = unsafe { std::mem::zeroed() };
112-
let mut length = std::mem::size_of_val(&addr) as c_int;
111+
let mut storage: SOCKADDR_STORAGE = unsafe { std::mem::zeroed() };
112+
let mut length = std::mem::size_of_val(&storage) as c_int;
113113

114114
match unsafe { getsockname(
115115
socket,
116-
&mut addr as *mut _ as *mut _,
116+
&mut storage as *mut _ as *mut _,
117117
&mut length
118118
) } {
119119
SOCKET_ERROR => Err(io::Error::last_os_error()),
120120
_ => {
121-
let storage: *const SOCKADDR_STORAGE = (&addr) as *const _;
122-
if addr.ss_family as c_int == AF_INET {
123-
let sock_addr : SocketAddrV4 = unsafe { *(storage as *const SOCKADDR_IN as *const _) };
124-
Ok(sock_addr.into())
121+
if storage.ss_family as c_int == AF_INET {
122+
let addr: &SOCKADDR_IN = unsafe { &*(&storage as *const _ as *const SOCKADDR_IN) };
123+
let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() };
124+
let ip = Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]);
125+
let port = u16::from_be(addr.sin_port);
126+
Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
127+
} else if storage.ss_family as c_int == AF_INET6 {
128+
let addr: &SOCKADDR_IN6_LH = unsafe { &*(&storage as *const _ as *const SOCKADDR_IN6_LH) };
129+
let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() });
130+
let port = u16::from_be(addr.sin6_port);
131+
let scope_id = unsafe { *addr.u.sin6_scope_id() };
132+
Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, addr.sin6_flowinfo, scope_id)))
125133
} else {
126-
let sock_addr : SocketAddrV6 = unsafe { *(storage as *const SOCKADDR_IN6_LH as *const _) };
127-
Ok(sock_addr.into())
134+
panic!("Invalid ss_family");
128135
}
129136
},
130137
}
131-
132-
133138
}
134139

135140
pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {

0 commit comments

Comments
 (0)