Skip to content

Commit

Permalink
Merge branch 'rust-lang:master' into ipv6_incl_header
Browse files Browse the repository at this point in the history
  • Loading branch information
andreybuchinskiy authored Nov 30, 2024
2 parents 7e18497 + 60d118f commit 74fd9f4
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 70 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ jobs:
- aarch64-apple-darwin
- aarch64-apple-ios
- aarch64-apple-tvos
- aarch64-apple-visionos
# Broken, see https://github.com/rust-lang/socket2/issues/538.
#- aarch64-apple-visionos
- aarch64-apple-watchos
- aarch64-linux-android
- aarch64-unknown-freebsd
Expand All @@ -74,7 +75,8 @@ jobs:
- armv7-linux-androideabi
- armv7-sony-vita-newlibeabihf
- i686-linux-android
- i686-unknown-hurd-gnu
# Broken, see https://github.com/rust-lang/socket2/issues/539.
#- i686-unknown-hurd-gnu
- i686-unknown-linux-gnu
- sparcv9-sun-solaris
- x86_64-apple-darwin
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# 0.5.8

* Added `Socket::(set_)header_included_v4` and
`Socket::(set_)header_included_v6`
(https://github.com/rust-lang/socket2/pull/518).
* Added support for `Socket::original_dst` and
`Socket::original_dst_ipv6` on Windows
(https://github.com/rust-lang/socket2/pull/529).

# 0.5.7

* Added `Socket::(set_)passcred`
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "socket2"
version = "0.5.7"
version = "0.5.8"
authors = [
"Alex Crichton <alex@alexcrichton.com>",
"Thomas de Zeeuw <thomasdezeeuw@gmail.com>"
Expand Down
66 changes: 64 additions & 2 deletions src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1682,7 +1682,17 @@ impl Socket {
/// For more information about this option, see [`set_header_included`].
///
/// [`set_header_included`]: Socket::set_header_included
#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd"
))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
Expand All @@ -1706,7 +1716,17 @@ impl Socket {
any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
allow(rustdoc::broken_intra_doc_links)
)]
#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd"
))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
Expand Down Expand Up @@ -2235,6 +2255,48 @@ impl Socket {
)
}
}

/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows",
)
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows",
)
)))
)]
pub fn original_dst(&self) -> io::Result<SockAddr> {
sys::original_dst(self.as_raw())
}

/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "linux", target_os = "windows")
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(target_os = "android", target_os = "linux", target_os = "windows")
)))
)]
pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
sys::original_dst_ipv6(self.as_raw())
}
}

impl Read for Socket {
Expand Down
97 changes: 41 additions & 56 deletions src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,47 @@ pub(crate) const fn to_mreqn(
}
}

#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
))]
pub(crate) fn original_dst(fd: Socket) -> io::Result<SockAddr> {
// Safety: `getsockopt` initialises the `SockAddr` for us.
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(getsockopt(
fd,
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")))]
pub(crate) fn original_dst_ipv6(fd: Socket) -> io::Result<SockAddr> {
// Safety: `getsockopt` initialises the `SockAddr` for us.
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(getsockopt(
fd,
libc::SOL_IPV6,
libc::IP6T_SO_ORIGINAL_DST,
storage.cast(),
len
))
})
}
.map(|(_, addr)| addr)
}

/// Unix only API.
impl crate::Socket {
/// Accept a new incoming connection from this listener.
Expand Down Expand Up @@ -2416,62 +2457,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
46 changes: 44 additions & 2 deletions src/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ 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 @@ -857,6 +859,46 @@ pub(crate) fn to_mreqn(
}
}

#[cfg(feature = "all")]
pub(crate) fn original_dst(socket: Socket) -> io::Result<SockAddr> {
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(
getsockopt(
socket,
SOL_IP as i32,
SO_ORIGINAL_DST as i32,
storage.cast(),
len,
),
PartialEq::eq,
SOCKET_ERROR
)
})
}
.map(|(_, addr)| addr)
}

#[cfg(feature = "all")]
pub(crate) fn original_dst_ipv6(socket: Socket) -> io::Result<SockAddr> {
unsafe {
SockAddr::try_init(|storage, len| {
syscall!(
getsockopt(
socket,
SOL_IP as i32,
IP6T_SO_ORIGINAL_DST as i32,
storage.cast(),
len,
),
PartialEq::eq,
SOCKET_ERROR
)
})
}
.map(|(_, addr)| addr)
}

#[allow(unsafe_op_in_unsafe_fn)]
pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
// SAFETY: a `sockaddr_storage` of all zeros is valid.
Expand Down
45 changes: 38 additions & 7 deletions tests/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1564,7 +1564,17 @@ fn header_included() {
}

#[test]
#[cfg(all(feature = "all", not(target_os = "redox")))]
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd"
))
))]
fn header_included_ipv6() {
let socket = match Socket::new(Domain::IPV6, Type::RAW, None) {
Ok(socket) => socket,
Expand All @@ -1590,36 +1600,57 @@ fn header_included_ipv6() {
#[test]
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows"
)
))]
fn original_dst() {
let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
#[cfg(not(target_os = "windows"))]
let expected = Some(libc::ENOENT);
#[cfg(target_os = "windows")]
let expected = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL);

match socket.original_dst() {
Ok(_) => panic!("original_dst on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), Some(libc::ENOENT)),
Err(err) => assert_eq!(err.raw_os_error(), expected),
}

let socket = Socket::new(Domain::IPV6, Type::STREAM, None).unwrap();
match socket.original_dst() {
Ok(_) => panic!("original_dst on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), Some(libc::ENOENT)),
Err(err) => assert_eq!(err.raw_os_error(), expected),
}
}

#[test]
#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
))]
fn original_dst_ipv6() {
let socket = Socket::new(Domain::IPV6, Type::STREAM, None).unwrap();
#[cfg(not(target_os = "windows"))]
let expected = Some(libc::ENOENT);
#[cfg(target_os = "windows")]
let expected = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL);
#[cfg(not(target_os = "windows"))]
let expected_v4 = Some(libc::EOPNOTSUPP);
#[cfg(target_os = "windows")]
let expected_v4 = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL);
match socket.original_dst_ipv6() {
Ok(_) => panic!("original_dst_ipv6 on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), Some(libc::ENOENT)),
Err(err) => assert_eq!(err.raw_os_error(), expected),
}

// Not supported on IPv4 socket.
let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
match socket.original_dst_ipv6() {
Ok(_) => panic!("original_dst_ipv6 on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), Some(libc::EOPNOTSUPP)),
Err(err) => assert_eq!(err.raw_os_error(), expected_v4),
}
}

Expand Down

0 comments on commit 74fd9f4

Please sign in to comment.