Skip to content

Commit

Permalink
Migrate original_dst to socket.rs out of os specific files
Browse files Browse the repository at this point in the history
Signed-off-by: Keith Mattix II <[email protected]>
  • Loading branch information
keithmattix committed Sep 30, 2024
1 parent e29f621 commit 7a46f91
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 120 deletions.
151 changes: 150 additions & 1 deletion src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io::{self, Read, Write};
#[cfg(not(target_os = "redox"))]
Expand All @@ -19,6 +18,10 @@ use std::os::unix::io::{FromRawFd, IntoRawFd};
#[cfg(windows)]
use std::os::windows::io::{FromRawSocket, IntoRawSocket};
use std::time::Duration;
#[cfg(all(windows, feature = "all"))]
use windows_sys::Win32::Networking::WinSock::{
IP6T_SO_ORIGINAL_DST, SOCKET_ERROR, SOL_IP, SO_ORIGINAL_DST,
};

use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
#[cfg(all(unix, not(target_os = "redox")))]
Expand All @@ -27,6 +30,38 @@ use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
#[cfg(not(target_os = "redox"))]
use crate::{MaybeUninitSlice, MsgHdr, RecvFlags};

#[cfg(all(windows, feature = "all"))]
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
/// Helper macro to execute a system call that returns an `io::Result`.
macro_rules! syscall {
($fn: ident ( $($arg: expr),* $(,)* ), $err_test: path, $err_value: expr) => {{
#[allow(unused_unsafe)]
let res = unsafe { windows_sys::Win32::Networking::WinSock::$fn($($arg, )*) };
if $err_test(&res, &$err_value) {
Err(io::Error::last_os_error())
} else {
Ok(res)
}
}};
}

#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux",)
))]
/// Helper macro to execute a system call that returns an `io::Result`.
macro_rules! syscall {
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
#[allow(unused_unsafe)]
let res = unsafe { libc::$fn($($arg, )*) };
if res == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(res)
}
}};
}

/// Owned wrapper around a system socket.
///
/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix
Expand Down Expand Up @@ -2205,6 +2240,120 @@ impl Socket {
)
}
}

/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
///
/// This value contains the original destination IPv4 address of the connection
/// redirected using `iptables` `REDIRECT` or `TPROXY`.
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux",)
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux",)
)))
)]
pub fn original_dst(&self) -> io::Result<SockAddr> {
// Safety: `getsockopt` initialises the `SockAddr` for us.
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(getsockopt(
self.as_raw(),
libc::SOL_IP,
libc::SO_ORIGINAL_DST,
storage.cast(),
len
))
})
}
.map(|(_, addr)| addr)
}

/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
///
/// This value contains the original destination IPv6 address of the connection
/// redirected using `ip6tables` `REDIRECT` or `TPROXY`.
#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux",)))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux",))))
)]
pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
// Safety: `getsockopt` initialises the `SockAddr` for us.
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(getsockopt(
self.as_raw(),
libc::SOL_IPV6,
libc::IP6T_SO_ORIGINAL_DST,
storage.cast(),
len
))
})
}
.map(|(_, addr)| addr)
}

/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
/// Only valid for sockets in accepting mode.
///
/// Note: if using this function in a proxy context, you must query the
/// redirect records for this socket and set them on the outbound socket
/// created by your proxy in order for any OS level firewall rules to be
/// applied. Read more in the Windows bind and connect redirection
/// [documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/network/using-bind-or-connect-redirection).
#[cfg(all(windows, feature = "all"))]
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
pub fn original_dst(&self) -> io::Result<SockAddr> {
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(
getsockopt(
self.as_raw(),
SOL_IP as i32,
SO_ORIGINAL_DST as i32,
storage.cast(),
len,
),
PartialEq::eq,
SOCKET_ERROR
)
})
}
.map(|(_, addr)| addr)
}

/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
/// Only valid for sockets in accepting mode.
///
/// Note: if using this function in a proxy context, you must query the
/// redirect records for this socket and set them on the outbound socket
/// created by your proxy in order for any OS level firewall rules to be
/// applied. Read more in the Windows bind and connect redirection
/// [documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/network/using-bind-or-connect-redirection).
#[cfg(all(windows, feature = "all"))]
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(
getsockopt(
self.as_raw(),
SOL_IP as i32,
IP6T_SO_ORIGINAL_DST as i32,
storage.cast(),
len,
),
PartialEq::eq,
SOCKET_ERROR
)
})
}
.map(|(_, addr)| addr)
}
}

impl Read for Socket {
Expand Down
56 changes: 0 additions & 56 deletions src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2402,62 +2402,6 @@ impl crate::Socket {
}
}

/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
///
/// This value contains the original destination IPv4 address of the connection
/// redirected using `iptables` `REDIRECT` or `TPROXY`.
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
)))
)]
pub fn original_dst(&self) -> io::Result<SockAddr> {
// Safety: `getsockopt` initialises the `SockAddr` for us.
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(getsockopt(
self.as_raw(),
libc::SOL_IP,
libc::SO_ORIGINAL_DST,
storage.cast(),
len
))
})
}
.map(|(_, addr)| addr)
}

/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
///
/// This value contains the original destination IPv6 address of the connection
/// redirected using `ip6tables` `REDIRECT` or `TPROXY`.
#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
)]
pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
// Safety: `getsockopt` initialises the `SockAddr` for us.
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(getsockopt(
self.as_raw(),
libc::SOL_IPV6,
libc::IP6T_SO_ORIGINAL_DST,
storage.cast(),
len
))
})
}
.map(|(_, addr)| addr)
}

/// Copies data between a `file` and this socket using the `sendfile(2)`
/// system call. Because this copying is done within the kernel,
/// `sendfile()` is more efficient than the combination of `read(2)` and
Expand Down
64 changes: 2 additions & 62 deletions src/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,14 @@ use std::time::{Duration, Instant};
use std::{process, ptr, slice};

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

use crate::{MsgHdr, RecvFlags, SockAddr, TcpKeepalive, Type};
Expand Down Expand Up @@ -929,64 +927,6 @@ impl crate::Socket {
}
}

/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
/// Only valid for sockets in accepting mode.
///
/// Note: if using this function in a proxy context, you must query the
/// redirect records for this socket and set them on the outbound socket
/// created by your proxy in order for any OS level firewall rules to be
/// applied. Read more in the Windows bind and connect redirection
/// [documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/network/using-bind-or-connect-redirection).
#[cfg(feature = "all")]
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
pub fn original_dst(&self) -> io::Result<SockAddr> {
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(
getsockopt(
self.as_raw(),
SOL_IP as i32,
SO_ORIGINAL_DST as i32,
storage.cast(),
len,
),
PartialEq::eq,
SOCKET_ERROR
)
})
}
.map(|(_, addr)| addr)
}

/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
/// Only valid for sockets in accepting mode.
///
/// Note: if using this function in a proxy context, you must query the
/// redirect records for this socket and set them on the outbound socket
/// created by your proxy in order for any OS level firewall rules to be
/// applied. Read more in the Windows bind and connect redirection
/// [documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/network/using-bind-or-connect-redirection).
#[cfg(feature = "all")]
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(
getsockopt(
self.as_raw(),
SOL_IP as i32,
IP6T_SO_ORIGINAL_DST as i32,
storage.cast(),
len,
),
PartialEq::eq,
SOCKET_ERROR
)
})
}
.map(|(_, addr)| addr)
}

/// Returns the [`Protocol`] of this socket by checking the `SO_PROTOCOL_INFOW`
/// option on this socket.
///
Expand Down
2 changes: 1 addition & 1 deletion tests/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ fn unix_sockets_supported() -> bool {
Ok(_) => {}
Err(err)
if err.raw_os_error()
== Some(windows_sys::Win32::Networking::WinSock::WSAEAFNOSUPPORT as i32) =>
== Some(windows_sys::Win32::Networking::WinSock::WSAEAFNOSUPPORT) =>
{
return false;
}
Expand Down

0 comments on commit 7a46f91

Please sign in to comment.