Skip to content

Commit ed8faff

Browse files
committed
Prove out that ORIGINAL_DST only works on listening sockets
Signed-off-by: keithmattix <[email protected]>
1 parent 94011b2 commit ed8faff

File tree

2 files changed

+59
-16
lines changed

2 files changed

+59
-16
lines changed

src/sys/windows.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ use std::{process, ptr, slice};
2121

2222
use windows_sys::Win32::Foundation::{SetHandleInformation, HANDLE, HANDLE_FLAG_INHERIT};
2323
#[cfg(feature = "all")]
24-
use windows_sys::Win32::Networking::WinSock::SO_PROTOCOL_INFOW;
24+
use windows_sys::Win32::Networking::WinSock::{SO_PROTOCOL_INFOW, SO_ORIGINAL_DST, IP6T_SO_ORIGINAL_DST, SOL_IP};
2525
use windows_sys::Win32::Networking::WinSock::{
2626
self, tcp_keepalive, FIONBIO, IN6_ADDR, IN6_ADDR_0, INVALID_SOCKET, IN_ADDR, IN_ADDR_0,
2727
POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, SD_BOTH, SD_RECEIVE, SD_SEND, SIO_KEEPALIVE_VALS,
2828
SOCKET_ERROR, WSABUF, WSAEMSGSIZE, WSAESHUTDOWN, WSAPOLLFD, WSAPROTOCOL_INFOW,
29-
WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED,
29+
WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED
3030
};
3131
use windows_sys::Win32::System::Threading::INFINITE;
3232

@@ -77,7 +77,7 @@ pub(crate) use windows_sys::Win32::Networking::WinSock::{
7777
IP_MREQ_SOURCE as IpMreqSource, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
7878
IP_RECVTOS, IP_TOS, IP_TTL, LINGER as linger, MSG_OOB, MSG_PEEK, SO_BROADCAST, SO_ERROR,
7979
SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF,
80-
SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, SO_ORIGINAL_DST, IP6T_SO_ORIGINAL_DST, SOL_IP
80+
SO_SNDTIMEO, SO_TYPE, TCP_NODELAY
8181
};
8282
pub(crate) const IPPROTO_IP: c_int = windows_sys::Win32::Networking::WinSock::IPPROTO_IP as c_int;
8383
pub(crate) const SOL_SOCKET: c_int = windows_sys::Win32::Networking::WinSock::SOL_SOCKET as c_int;
@@ -929,11 +929,22 @@ impl crate::Socket {
929929

930930
/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
931931
///
932+
#[cfg(feature = "all")]
933+
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
932934
pub fn original_dst(&self) -> io::Result<SockAddr> {
933-
// Safety: `getsockopt` initialises the `SockAddr` for us.
934935
unsafe {
935936
SockAddr::try_init(|storage, len| {
936-
getsockopt::<>(self.as_raw(), SOL_IP, SO_ORIGINAL_DST)
937+
syscall!(
938+
getsockopt(
939+
self.as_raw(),
940+
SOL_IP as i32,
941+
SO_ORIGINAL_DST as i32,
942+
storage.cast(),
943+
len,
944+
),
945+
PartialEq::eq,
946+
SOCKET_ERROR
947+
)
937948
})
938949
}
939950
.map(|(_, addr)| addr)
@@ -944,19 +955,11 @@ impl crate::Socket {
944955
#[cfg(feature = "all")]
945956
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
946957
pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
947-
// Safety: `getsockopt` initialises the `SockAddr` for us.
958+
use windows_sys::Win32::Networking::WinSock::SOL_IPV6;
959+
948960
unsafe {
949-
SockAddr::try_init(|storage, len| {
950-
syscall!(getsockopt(
951-
self.as_raw(),
952-
libc::SOL_IPV6,
953-
IP6T_SO_ORIGINAL_DST,
954-
storage.cast(),
955-
len
956-
))
957-
})
961+
getsockopt::<SockAddr>(self.as_raw(), SOL_IPV6 as i32, IP6T_SO_ORIGINAL_DST as i32)
958962
}
959-
.map(|(_, addr)| addr)
960963
}
961964

962965
/// Returns the [`Protocol`] of this socket by checking the `SO_PROTOCOL_INFOW`

tests/socket.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,46 @@ fn original_dst() {
16061606
}
16071607
}
16081608

1609+
#[test]
1610+
#[cfg(all(
1611+
feature = "all",
1612+
target_os = "windows"
1613+
))]
1614+
fn original_dst() {
1615+
use windows_sys::Win32::Networking::WinSock::SOMAXCONN;
1616+
1617+
1618+
let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP)).unwrap();
1619+
let addr = SocketAddr::from(([127, 0, 0, 1], 8000));
1620+
match socket.bind(&SockAddr::from(addr)) {
1621+
Ok(_) => {}
1622+
Err(err) => panic!("failed to bind socket: {}", err),
1623+
};
1624+
match socket.listen(SOMAXCONN as i32) {
1625+
Ok(_) => {}
1626+
Err(err) => panic!("failed to listen on socket: {}", err),
1627+
};
1628+
// Socket must be in an accepting state for SOL_IP and SO_ORIGINAL_DST
1629+
match socket.accept() {
1630+
Ok((socket, _)) => {
1631+
match socket.original_dst() {
1632+
Ok(addr) => {
1633+
println!("Original destination: {:?}", addr);
1634+
}
1635+
Err(err) => panic!("failed to get original destination: {}", err),
1636+
}
1637+
}
1638+
Err(err) => panic!("failed to accept connection: {}", err),
1639+
1640+
};
1641+
1642+
// let socket = Socket::new(Domain::IPV6, Type::STREAM, None).unwrap();
1643+
// match socket.original_dst() {
1644+
// Ok(_) => panic!("original_dst on non-redirected socket should fail"),
1645+
// Err(err) => assert_eq!(err.raw_os_error(), Some(SOCKET_ERROR)),
1646+
// }
1647+
}
1648+
16091649
#[test]
16101650
#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
16111651
fn original_dst_ipv6() {

0 commit comments

Comments
 (0)