From 4fc67a96791ef39aa919396f6a04547eeeb7b2db Mon Sep 17 00:00:00 2001 From: Boris N Date: Tue, 22 Apr 2025 01:32:04 +0200 Subject: [PATCH 1/2] Added bind_device_by_index_{v4,v6} and device_index_{v4,v6} for linux and android (#569) --- Cargo.toml | 2 +- src/sys/unix.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d0566282..a5fa1b66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ targets = [ features = ["all"] [target."cfg(unix)".dependencies] -libc = "0.2.171" +libc = "0.2.172" [target.'cfg(windows)'.dependencies.windows-sys] version = "0.52" diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 8e24f4e5..79df533c 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -24,6 +24,8 @@ use std::net::{Ipv4Addr, Ipv6Addr}; target_os = "watchos", target_os = "illumos", target_os = "solaris", + target_os = "linux", + target_os = "android", ) ))] use std::num::NonZeroU32; @@ -1820,7 +1822,7 @@ impl crate::Socket { .map(|_| ()) } - /// Sets the value for `IP_BOUND_IF` option on this socket. + /// Sets the value for `IP_BOUND_IF` or `SO_BINDTOIFINDEX` option on this socket. /// /// If a socket is bound to an interface, only packets received from that /// particular interface are processed by the socket. @@ -1840,14 +1842,38 @@ impl crate::Socket { target_os = "watchos", target_os = "illumos", target_os = "solaris", + target_os = "linux", + target_os = "android", ) ))] pub fn bind_device_by_index_v4(&self, interface: Option) -> io::Result<()> { let index = interface.map_or(0, NonZeroU32::get); - unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) } + + #[cfg(any( + target_os = "ios", + target_os = "visionos", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + target_os = "illumos", + target_os = "solaris", + ))] + unsafe { + setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) + } + + #[cfg(any(target_os = "linux", target_os = "android",))] + unsafe { + setsockopt( + self.as_raw(), + libc::SOL_SOCKET, + libc::SO_BINDTOIFINDEX, + index, + ) + } } - /// Sets the value for `IPV6_BOUND_IF` option on this socket. + /// Sets the value for `IPV6_BOUND_IF` or `SO_BINDTOIFINDEX` option on this socket. /// /// If a socket is bound to an interface, only packets received from that /// particular interface are processed by the socket. @@ -1867,11 +1893,35 @@ impl crate::Socket { target_os = "watchos", target_os = "illumos", target_os = "solaris", + target_os = "linux", + target_os = "android", ) ))] pub fn bind_device_by_index_v6(&self, interface: Option) -> io::Result<()> { let index = interface.map_or(0, NonZeroU32::get); - unsafe { setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index) } + + #[cfg(any( + target_os = "ios", + target_os = "visionos", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + target_os = "illumos", + target_os = "solaris", + ))] + unsafe { + setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index) + } + + #[cfg(any(target_os = "linux", target_os = "android",))] + unsafe { + setsockopt( + self.as_raw(), + libc::SOL_SOCKET, + libc::SO_BINDTOIFINDEX, + index, + ) + } } /// Gets the value for `IP_BOUND_IF` option on this socket, i.e. the index @@ -1889,11 +1939,28 @@ impl crate::Socket { target_os = "watchos", target_os = "illumos", target_os = "solaris", + target_os = "linux", + target_os = "android", ) ))] pub fn device_index_v4(&self) -> io::Result> { + #[cfg(any( + target_os = "ios", + target_os = "visionos", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + target_os = "illumos", + target_os = "solaris", + ))] let index = unsafe { getsockopt::(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? }; + + #[cfg(any(target_os = "linux", target_os = "android",))] + let index = unsafe { + getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)? + }; + Ok(NonZeroU32::new(index)) } @@ -1912,12 +1979,29 @@ impl crate::Socket { target_os = "watchos", target_os = "illumos", target_os = "solaris", + target_os = "linux", + target_os = "android", ) ))] pub fn device_index_v6(&self) -> io::Result> { + #[cfg(any( + target_os = "ios", + target_os = "visionos", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + target_os = "illumos", + target_os = "solaris", + ))] let index = unsafe { getsockopt::(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)? }; + + #[cfg(any(target_os = "linux", target_os = "android",))] + let index = unsafe { + getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)? + }; + Ok(NonZeroU32::new(index)) } From fee5eb84abd796921b1efe753e0174479306ad53 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Sat, 24 May 2025 11:07:08 +0200 Subject: [PATCH 2/2] Update get docs --- src/sys/unix.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 79df533c..0816d317 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -1924,8 +1924,8 @@ impl crate::Socket { } } - /// Gets the value for `IP_BOUND_IF` option on this socket, i.e. the index - /// for the interface to which the socket is bound. + /// Gets the value for `IP_BOUND_IF` or `SO_BINDTOIFINDEX` option on this + /// socket, i.e. the index for the interface to which the socket is bound. /// /// Returns `None` if the socket is not bound to any interface, otherwise /// returns an interface index. @@ -1964,8 +1964,8 @@ impl crate::Socket { Ok(NonZeroU32::new(index)) } - /// Gets the value for `IPV6_BOUND_IF` option on this socket, i.e. the index - /// for the interface to which the socket is bound. + /// Gets the value for `IPV6_BOUND_IF` or `SO_BINDTOIFINDEX` option on this + /// socket, i.e. the index for the interface to which the socket is bound. /// /// Returns `None` if the socket is not bound to any interface, otherwise /// returns an interface index.