Skip to content

Commit d2c15de

Browse files
authored
Don't assume memory layout of std::net::SocketAddr
Fixes #120
1 parent 99da5c2 commit d2c15de

File tree

2 files changed

+129
-42
lines changed

2 files changed

+129
-42
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"]
2121

2222
[target."cfg(any(unix, target_os = \"redox\"))".dependencies]
2323
cfg-if = "0.1.6"
24-
libc = "0.2.66"
24+
libc = { version = "0.2.66", features = ["align"] }
2525

2626
[target."cfg(target_os = \"redox\")".dependencies]
2727
redox_syscall = "0.1.38"

src/sockaddr.rs

+128-41
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
use std::fmt;
22
use std::mem::{self, MaybeUninit};
3-
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
3+
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
44
use std::ptr;
55

66
#[cfg(any(unix, target_os = "redox"))]
77
use libc::{
8-
sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
9-
AF_INET6,
8+
in6_addr, in_addr, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage,
9+
socklen_t, AF_INET, AF_INET6,
1010
};
1111
#[cfg(windows)]
12+
use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR as in6_addr};
13+
#[cfg(windows)]
14+
use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR as in_addr};
15+
#[cfg(windows)]
1216
use winapi::shared::ws2def::{
1317
ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr,
1418
SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage,
1519
};
1620
#[cfg(windows)]
17-
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
21+
use winapi::shared::ws2ipdef::{SOCKADDR_IN6_LH_u, SOCKADDR_IN6_LH as sockaddr_in6};
1822
#[cfg(windows)]
1923
use winapi::um::ws2tcpip::socklen_t;
2024

@@ -43,17 +47,17 @@ impl fmt::Debug for SockAddr {
4347
impl SockAddr {
4448
/// Constructs a `SockAddr` from its raw components.
4549
pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr {
46-
let mut storage = MaybeUninit::<sockaddr_storage>::uninit();
50+
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
4751
ptr::copy_nonoverlapping(
4852
addr as *const _ as *const u8,
49-
&mut storage as *mut _ as *mut u8,
53+
storage.as_mut_ptr() as *mut u8,
5054
len as usize,
5155
);
5256

5357
SockAddr {
5458
// This is safe as we written the address to `storage` above.
5559
storage: storage.assume_init(),
56-
len: len,
60+
len,
5761
}
5862
}
5963

@@ -120,33 +124,60 @@ impl SockAddr {
120124
}
121125
}
122126

123-
unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> {
124-
if self.storage.ss_family != family {
125-
return None;
126-
}
127-
128-
Some(mem::transmute_copy(&self.storage))
129-
}
130-
131127
/// Returns this address as a `SocketAddrV4` if it is in the `AF_INET`
132128
/// family.
133129
pub fn as_inet(&self) -> Option<SocketAddrV4> {
134-
unsafe { self.as_(AF_INET as sa_family_t) }
130+
match self.as_std() {
131+
Some(SocketAddr::V4(addr)) => Some(addr),
132+
_ => None,
133+
}
135134
}
136135

137136
/// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6`
138137
/// family.
139138
pub fn as_inet6(&self) -> Option<SocketAddrV6> {
140-
unsafe { self.as_(AF_INET6 as sa_family_t) }
139+
match self.as_std() {
140+
Some(SocketAddr::V6(addr)) => Some(addr),
141+
_ => None,
142+
}
141143
}
142144

143145
/// Returns this address as a `SocketAddr` if it is in the `AF_INET`
144146
/// or `AF_INET6` family, otherwise returns `None`.
145147
pub fn as_std(&self) -> Option<SocketAddr> {
146-
if let Some(addr) = self.as_inet() {
147-
Some(SocketAddr::V4(addr))
148-
} else if let Some(addr) = self.as_inet6() {
149-
Some(SocketAddr::V6(addr))
148+
if self.storage.ss_family == AF_INET as sa_family_t {
149+
// Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
150+
let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) };
151+
152+
#[cfg(unix)]
153+
let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
154+
#[cfg(windows)]
155+
let ip = {
156+
let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() };
157+
Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4])
158+
};
159+
let port = u16::from_be(addr.sin_port);
160+
Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
161+
} else if self.storage.ss_family == AF_INET6 as sa_family_t {
162+
// Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
163+
let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) };
164+
165+
#[cfg(unix)]
166+
let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
167+
#[cfg(windows)]
168+
let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() });
169+
let port = u16::from_be(addr.sin6_port);
170+
Some(SocketAddr::V6(SocketAddrV6::new(
171+
ip,
172+
port,
173+
addr.sin6_flowinfo,
174+
#[cfg(unix)]
175+
addr.sin6_scope_id,
176+
#[cfg(windows)]
177+
unsafe {
178+
*addr.u.sin6_scope_id()
179+
},
180+
)))
150181
} else {
151182
None
152183
}
@@ -168,34 +199,90 @@ impl SockAddr {
168199
}
169200
}
170201

171-
// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6
172-
173-
// check to make sure that the sizes at least match up
174-
fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) {
175-
unsafe {
176-
mem::transmute::<SocketAddrV4, sockaddr_in>(v4);
177-
mem::transmute::<SocketAddrV6, sockaddr_in6>(v6);
178-
}
179-
}
180-
181202
impl From<SocketAddrV4> for SockAddr {
182203
fn from(addr: SocketAddrV4) -> SockAddr {
183-
unsafe {
184-
SockAddr::from_raw_parts(
185-
&addr as *const _ as *const _,
186-
mem::size_of::<SocketAddrV4>() as socklen_t,
187-
)
204+
#[cfg(unix)]
205+
let sin_addr = in_addr {
206+
s_addr: u32::from_ne_bytes(addr.ip().octets()),
207+
};
208+
#[cfg(windows)]
209+
let sin_addr = unsafe {
210+
let mut s_un = mem::zeroed::<in_addr_S_un>();
211+
*s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets());
212+
in_addr { S_un: s_un }
213+
};
214+
215+
let sockaddr_in = sockaddr_in {
216+
sin_family: AF_INET as sa_family_t,
217+
sin_port: addr.port().to_be(),
218+
sin_addr,
219+
sin_zero: [0; 8],
220+
#[cfg(any(
221+
target_os = "dragonfly",
222+
target_os = "freebsd",
223+
target_os = "ios",
224+
target_os = "macos",
225+
target_os = "netbsd",
226+
target_os = "openbsd"
227+
))]
228+
sin_len: 0,
229+
};
230+
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
231+
// Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage`
232+
unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) };
233+
SockAddr {
234+
storage: unsafe { storage.assume_init() },
235+
len: mem::size_of::<sockaddr_in>() as socklen_t,
188236
}
189237
}
190238
}
191239

192240
impl From<SocketAddrV6> for SockAddr {
193241
fn from(addr: SocketAddrV6) -> SockAddr {
194-
unsafe {
195-
SockAddr::from_raw_parts(
196-
&addr as *const _ as *const _,
197-
mem::size_of::<SocketAddrV6>() as socklen_t,
198-
)
242+
#[cfg(unix)]
243+
let sin6_addr = in6_addr {
244+
s6_addr: addr.ip().octets(),
245+
};
246+
#[cfg(windows)]
247+
let sin6_addr = unsafe {
248+
let mut u = mem::zeroed::<in6_addr_u>();
249+
*u.Byte_mut() = addr.ip().octets();
250+
in6_addr { u }
251+
};
252+
#[cfg(windows)]
253+
let u = unsafe {
254+
let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>();
255+
*u.sin6_scope_id_mut() = addr.scope_id();
256+
u
257+
};
258+
259+
let sockaddr_in6 = sockaddr_in6 {
260+
sin6_family: AF_INET6 as sa_family_t,
261+
sin6_port: addr.port().to_be(),
262+
sin6_addr,
263+
sin6_flowinfo: addr.flowinfo(),
264+
#[cfg(unix)]
265+
sin6_scope_id: addr.scope_id(),
266+
#[cfg(windows)]
267+
u,
268+
#[cfg(any(
269+
target_os = "dragonfly",
270+
target_os = "freebsd",
271+
target_os = "ios",
272+
target_os = "macos",
273+
target_os = "netbsd",
274+
target_os = "openbsd"
275+
))]
276+
sin6_len: 0,
277+
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
278+
__sin6_src_id: 0,
279+
};
280+
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
281+
// Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage`
282+
unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) };
283+
SockAddr {
284+
storage: unsafe { storage.assume_init() },
285+
len: mem::size_of::<sockaddr_in6>() as socklen_t,
199286
}
200287
}
201288
}

0 commit comments

Comments
 (0)