Skip to content

Commit 772f3c1

Browse files
committed
convert libc sockaddr to SocketAddr explicitly
SocketAddr may not have the same layout as libc, rust-lang/rust#78802 - fixes #462 - ref tokio-rs/mio#1388, rust-lang/socket2#120
1 parent bf409c2 commit 772f3c1

File tree

6 files changed

+156
-189
lines changed

6 files changed

+156
-189
lines changed

crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs

+38-32
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ use std::{
44
ffi::CString,
55
io::{self, Error, ErrorKind},
66
mem,
7-
net::{SocketAddr, SocketAddrV4, SocketAddrV6},
7+
net::SocketAddr,
88
ptr,
99
};
1010

1111
use lazy_static::lazy_static;
1212
use log::trace;
13-
use socket2::Protocol;
14-
15-
use crate::sys::sockaddr_to_std;
13+
use socket2::{Protocol, SockAddr};
1614

1715
mod ffi {
1816
use cfg_if::cfg_if;
@@ -161,7 +159,8 @@ impl PacketFilter {
161159
SocketAddr::V4(ref v4) => {
162160
pnl.af = libc::AF_INET as libc::sa_family_t;
163161

164-
let sockaddr: *const libc::sockaddr_in = v4 as *const SocketAddrV4 as *const _;
162+
let sockaddr = SockAddr::from(*v4);
163+
let sockaddr = sockaddr.as_ptr() as *const libc::sockaddr_in;
165164

166165
let addr: *const libc::in_addr = &((*sockaddr).sin_addr) as *const _;
167166
let port: libc::in_port_t = (*sockaddr).sin_port;
@@ -172,7 +171,8 @@ impl PacketFilter {
172171
SocketAddr::V6(ref v6) => {
173172
pnl.af = libc::AF_INET6 as libc::sa_family_t;
174173

175-
let sockaddr: *const libc::sockaddr_in6 = v6 as *const SocketAddrV6 as *const _;
174+
let sockaddr = SockAddr::from(*v6);
175+
let sockaddr = sockaddr.as_ptr() as *const libc::sockaddr_in6;
176176

177177
let addr: *const libc::in6_addr = &((*sockaddr).sin6_addr) as *const _;
178178
let port: libc::in_port_t = (*sockaddr).sin6_port;
@@ -188,7 +188,8 @@ impl PacketFilter {
188188
return Err(Error::new(ErrorKind::InvalidInput, "client addr must be ipv4"));
189189
}
190190

191-
let sockaddr: *const libc::sockaddr_in = v4 as *const SocketAddrV4 as *const _;
191+
let sockaddr = SockAddr::from(*v4);
192+
let sockaddr = sockaddr.as_ptr() as *const libc::sockaddr_in;
192193

193194
let addr: *const libc::in_addr = &((*sockaddr).sin_addr) as *const _;
194195
let port: libc::in_port_t = (*sockaddr).sin_port;
@@ -201,7 +202,8 @@ impl PacketFilter {
201202
return Err(Error::new(ErrorKind::InvalidInput, "client addr must be ipv6"));
202203
}
203204

204-
let sockaddr: *const libc::sockaddr_in6 = v6 as *const SocketAddrV6 as *const _;
205+
let sockaddr = SockAddr::from(*v6);
206+
let sockaddr = sockaddr.as_ptr() as *const libc::sockaddr_in6;
205207

206208
let addr: *const libc::in6_addr = &((*sockaddr).sin6_addr) as *const _;
207209
let port: libc::in_port_t = (*sockaddr).sin6_port;
@@ -222,31 +224,35 @@ impl PacketFilter {
222224
return Err(nerr);
223225
}
224226

225-
let mut dst_addr: libc::sockaddr_storage = mem::zeroed();
226-
227-
if pnl.af == libc::AF_INET as libc::sa_family_t {
228-
let dst_addr: &mut libc::sockaddr_in = &mut *(&mut dst_addr as *mut _ as *mut _);
229-
dst_addr.sin_family = pnl.af;
230-
dst_addr.sin_port = pnl.rdport();
231-
ptr::copy_nonoverlapping(
232-
&pnl.rdaddr.pfa.v4,
233-
&mut dst_addr.sin_addr,
234-
mem::size_of_val(&pnl.rdaddr.pfa.v4),
235-
);
236-
} else if pnl.af == libc::AF_INET6 as libc::sa_family_t {
237-
let dst_addr: &mut libc::sockaddr_in6 = &mut *(&mut dst_addr as *mut _ as *mut _);
238-
dst_addr.sin6_family = pnl.af;
239-
dst_addr.sin6_port = pnl.rdport();
240-
ptr::copy_nonoverlapping(
241-
&pnl.rdaddr.pfa.v6,
242-
&mut dst_addr.sin6_addr,
243-
mem::size_of_val(&pnl.rdaddr.pfa.v6),
244-
);
245-
} else {
246-
unreachable!("sockaddr should be either ipv4 or ipv6");
247-
}
227+
let (_, dst_addr) = SockAddr::init(|dst_addr, addr_len| {
228+
if pnl.af == libc::AF_INET as libc::sa_family_t {
229+
let dst_addr: &mut libc::sockaddr_in = &mut *(dst_addr as *mut _);
230+
dst_addr.sin_family = pnl.af;
231+
dst_addr.sin_port = pnl.rdport();
232+
ptr::copy_nonoverlapping(
233+
&pnl.rdaddr.pfa.v4,
234+
&mut dst_addr.sin_addr,
235+
mem::size_of_val(&pnl.rdaddr.pfa.v4),
236+
);
237+
*addr_len = mem::size_of_val(&pnl.rdaddr.pfa.v4) as libc::socklen_t;
238+
} else if pnl.af == libc::AF_INET6 as libc::sa_family_t {
239+
let dst_addr: &mut libc::sockaddr_in6 = &mut *(dst_addr as *mut _);
240+
dst_addr.sin6_family = pnl.af;
241+
dst_addr.sin6_port = pnl.rdport();
242+
ptr::copy_nonoverlapping(
243+
&pnl.rdaddr.pfa.v6,
244+
&mut dst_addr.sin6_addr,
245+
mem::size_of_val(&pnl.rdaddr.pfa.v6),
246+
);
247+
*addr_len = mem::size_of_val(&pnl.rdaddr.pfa.v6) as libc::socklen_t;
248+
} else {
249+
unreachable!("sockaddr should be either ipv4 or ipv6");
250+
}
251+
252+
Ok(())
253+
})?;
248254

249-
sockaddr_to_std(&dst_addr)
255+
Ok(dst_addr.as_socket().expect("SocketAddr"))
250256
}
251257
}
252258
}

crates/shadowsocks-service/src/local/redir/tcprelay/sys/unix/linux.rs

+30-30
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use std::{
66
};
77

88
use async_trait::async_trait;
9+
use socket2::SockAddr;
910
use tokio::net::{TcpListener, TcpSocket, TcpStream};
1011

1112
use crate::{
1213
config::RedirType,
1314
local::redir::redir_ext::{TcpListenerRedirExt, TcpStreamRedirExt},
14-
sys::sockaddr_to_std,
1515
};
1616

1717
#[async_trait]
@@ -51,41 +51,41 @@ fn get_original_destination_addr(s: &TcpStream) -> io::Result<SocketAddr> {
5151
let fd = s.as_raw_fd();
5252

5353
unsafe {
54-
let mut target_addr: libc::sockaddr_storage = mem::zeroed();
55-
let mut target_addr_len = mem::size_of_val(&target_addr) as libc::socklen_t;
56-
57-
match s.local_addr()? {
58-
SocketAddr::V4(..) => {
59-
let ret = libc::getsockopt(
60-
fd,
61-
libc::SOL_IP,
62-
libc::SO_ORIGINAL_DST,
63-
&mut target_addr as *mut _ as *mut _,
64-
&mut target_addr_len,
65-
);
66-
if ret != 0 {
67-
let err = Error::last_os_error();
68-
return Err(err);
54+
let (_, target_addr) = SockAddr::init(|target_addr, target_addr_len| {
55+
match s.local_addr()? {
56+
SocketAddr::V4(..) => {
57+
let ret = libc::getsockopt(
58+
fd,
59+
libc::SOL_IP,
60+
libc::SO_ORIGINAL_DST,
61+
target_addr as *mut _,
62+
target_addr_len, // libc::socklen_t
63+
);
64+
if ret != 0 {
65+
let err = Error::last_os_error();
66+
return Err(err);
67+
}
6968
}
70-
}
71-
SocketAddr::V6(..) => {
72-
let ret = libc::getsockopt(
73-
fd,
74-
libc::SOL_IPV6,
75-
libc::IP6T_SO_ORIGINAL_DST,
76-
&mut target_addr as *mut _ as *mut _,
77-
&mut target_addr_len,
78-
);
69+
SocketAddr::V6(..) => {
70+
let ret = libc::getsockopt(
71+
fd,
72+
libc::SOL_IPV6,
73+
libc::IP6T_SO_ORIGINAL_DST,
74+
target_addr as *mut _,
75+
target_addr_len, // libc::socklen_t
76+
);
7977

80-
if ret != 0 {
81-
let err = Error::last_os_error();
82-
return Err(err);
78+
if ret != 0 {
79+
let err = Error::last_os_error();
80+
return Err(err);
81+
}
8382
}
8483
}
85-
}
84+
Ok(())
85+
})?;
8686

8787
// Convert sockaddr_storage to SocketAddr
88-
sockaddr_to_std(&target_addr)
88+
Ok(target_addr.as_socket().expect("SocketAddr"))
8989
}
9090
}
9191

crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs

+40-40
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use tokio::io::unix::AsyncFd;
1515
use crate::{
1616
config::RedirType,
1717
local::redir::redir_ext::{RedirSocketOpts, UdpSocketRedirExt},
18-
sys::sockaddr_to_std,
1918
};
2019

2120
pub fn check_support_tproxy() -> io::Result<()> {
@@ -186,45 +185,44 @@ fn set_socket_before_bind(addr: &SocketAddr, socket: &Socket) -> io::Result<()>
186185
Ok(())
187186
}
188187

189-
fn get_destination_addr(msg: &libc::msghdr) -> Option<libc::sockaddr_storage> {
188+
fn get_destination_addr(msg: &libc::msghdr) -> io::Result<SocketAddr> {
190189
// https://www.freebsd.org/cgi/man.cgi?ip(4)
191190
//
192191
// Called `recvmsg` with `IP_ORIGDSTADDR` set
193192

194193
unsafe {
195-
let mut cmsg: *mut libc::cmsghdr = libc::CMSG_FIRSTHDR(msg);
196-
while !cmsg.is_null() {
197-
let rcmsg = &*cmsg;
198-
match (rcmsg.cmsg_level, rcmsg.cmsg_type) {
199-
(libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
200-
let mut dst_addr: libc::sockaddr_storage = mem::zeroed();
201-
202-
ptr::copy(
203-
libc::CMSG_DATA(cmsg),
204-
&mut dst_addr as *mut _ as *mut _,
205-
mem::size_of::<libc::sockaddr_in>(),
206-
);
207-
208-
return Some(dst_addr);
194+
let (_, addr) = SockAddr::init(|dst_addr, dst_addr_len| {
195+
let mut cmsg: *mut libc::cmsghdr = libc::CMSG_FIRSTHDR(msg);
196+
while !cmsg.is_null() {
197+
let rcmsg = &*cmsg;
198+
match (rcmsg.cmsg_level, rcmsg.cmsg_type) {
199+
(libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
200+
ptr::copy_nonoverlapping(libc::CMSG_DATA(cmsg), dst_addr, mem::size_of::<libc::sockaddr_in>());
201+
*dst_addr_len = mem::size_of::<libc::sockaddr_in>() as libc::socklen_t;
202+
203+
return Ok(());
204+
}
205+
(libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
206+
ptr::copy_nonoverlapping(
207+
libc::CMSG_DATA(cmsg),
208+
dst_addr as *mut _,
209+
mem::size_of::<libc::sockaddr_in6>(),
210+
);
211+
*dst_addr_len = mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t;
212+
213+
return Ok(());
214+
}
215+
_ => {}
209216
}
210-
(libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
211-
let mut dst_addr: libc::sockaddr_storage = mem::zeroed();
217+
cmsg = libc::CMSG_NXTHDR(msg, cmsg);
218+
}
212219

213-
ptr::copy(
214-
libc::CMSG_DATA(cmsg),
215-
&mut dst_addr as *mut _ as *mut _,
216-
mem::size_of::<libc::sockaddr_in6>(),
217-
);
220+
let err = Error::new(ErrorKind::InvalidData, "missing destination address in msghdr");
221+
Err(err)
222+
})?;
218223

219-
return Some(dst_addr);
220-
}
221-
_ => {}
222-
}
223-
cmsg = libc::CMSG_NXTHDR(msg, cmsg);
224-
}
224+
Ok(addr.as_socket().expect("SocketAddr"))
225225
}
226-
227-
None
228226
}
229227

230228
fn recv_dest_from(socket: &UdpSocket, buf: &mut [u8]) -> io::Result<(usize, SocketAddr, SocketAddr)> {
@@ -252,14 +250,16 @@ fn recv_dest_from(socket: &UdpSocket, buf: &mut [u8]) -> io::Result<(usize, Sock
252250
return Err(Error::last_os_error());
253251
}
254252

255-
let dst_addr = match get_destination_addr(&msg) {
256-
None => {
257-
let err = Error::new(ErrorKind::InvalidData, "missing destination address in msghdr");
258-
return Err(err);
259-
}
260-
Some(d) => d,
261-
};
262-
263-
Ok((ret as usize, sockaddr_to_std(&src_addr)?, sockaddr_to_std(&dst_addr)?))
253+
let (_, src_saddr) = SockAddr::init(|a, l| {
254+
ptr::copy_nonoverlapping(msg.msg_name, a, msg.msg_namelen as usize);
255+
*l = msg.msg_namelen;
256+
Ok(())
257+
})?;
258+
259+
Ok((
260+
ret as usize,
261+
src_saddr.as_socket().expect("SocketAddr"),
262+
get_destination_addr(&msg)?,
263+
))
264264
}
265265
}

0 commit comments

Comments
 (0)