From 68de29bc98eb2effd38c977e160417c0a7e99f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Nicola?= Date: Thu, 21 Nov 2024 13:23:28 +0100 Subject: [PATCH 1/3] Remove Socket::(set_)header_included_v6 on unsupported OS --- src/socket.rs | 24 ++++++++++++++++++++++-- tests/socket.rs | 12 +++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 8d517b47..3d9d44af 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -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"))))) @@ -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"))))) diff --git a/tests/socket.rs b/tests/socket.rs index 2300f0ed..c87ca0e0 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -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, From 33a98be5635c816a18b490f6d3888b667639c891 Mon Sep 17 00:00:00 2001 From: Keith Mattix II Date: Wed, 27 Nov 2024 10:12:04 -0600 Subject: [PATCH 2/3] Add support for original_dst for windows (#529) --- src/socket.rs | 42 ++++++++++++++++++++ src/sys/unix.rs | 97 ++++++++++++++++++++-------------------------- src/sys/windows.rs | 46 +++++++++++++++++++++- tests/socket.rs | 33 +++++++++++++--- 4 files changed, 154 insertions(+), 64 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 3d9d44af..4e41793c 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -2225,6 +2225,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 { + 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 { + sys::original_dst_ipv6(self.as_raw()) + } } impl Read for Socket { diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 3a898bc3..1451b1f4 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -1406,6 +1406,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 { + // 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 { + // 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. @@ -2402,62 +2443,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 { - // 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 { - // 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 diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 11f2b7b0..8cf27b53 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -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}; @@ -857,6 +859,46 @@ pub(crate) fn to_mreqn( } } +#[cfg(feature = "all")] +pub(crate) fn original_dst(socket: Socket) -> io::Result { + 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 { + 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 { // SAFETY: a `sockaddr_storage` of all zeros is valid. diff --git a/tests/socket.rs b/tests/socket.rs index c87ca0e0..0959ef39 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -1600,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), } } From 60d118fa4724f756c31944c86dc1ecd5dfc4c9b7 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Thu, 28 Nov 2024 11:03:56 +0100 Subject: [PATCH 3/3] Release v0.5.8 (#537) --- .github/workflows/main.yml | 6 ++++-- CHANGELOG.md | 9 +++++++++ Cargo.toml | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a1b10f4..7a5126d2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index b90e67c2..f416f22c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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` diff --git a/Cargo.toml b/Cargo.toml index 8ef85ebc..fbb7fea9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.5.7" +version = "0.5.8" authors = [ "Alex Crichton ", "Thomas de Zeeuw "