From 10ebf4531b1cb322d7874bd23170c7ca513aca26 Mon Sep 17 00:00:00 2001 From: Jean Pierre Dudey Date: Fri, 8 May 2020 14:36:09 -0500 Subject: [PATCH] Add SO_BINDTODEVICE sockopt This is available only on Linux as far I know, [socket(7)](https://linux.die.net/man/7/socket) has some information about the `SO_BINDTODEVICE` sockopt. In simple words it binds a socket to an specific network device (specified as an string like "wlo1", "eth0", etc.), to only process packets from that device. Signed-off-by: Jean Pierre Dudey --- CHANGELOG.md | 2 ++ src/sys/socket/sockopt.rs | 2 ++ test/sys/test_sockopt.rs | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9c28b4a90..a7f82e64f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). (#[1208](https://github.com/nix-rust/nix/pull/1208)) - Added support for `SCM_CREDS` messages (`UnixCredentials`) on FreeBSD/DragonFly (#[1216](https://github.com/nix-rust/nix/pull/1216)) +- Added `BindToDevice` socket option (sockopt) on Linux + (#[1233](https://github.com/nix-rust/nix/pull/1233)) ### Changed - Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201)) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index d0ef4b6540..698d05f63f 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -259,6 +259,8 @@ sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usiz sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize); sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType); sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); +#[cfg(target_os = "linux")] +sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index c4860c0d61..6e325e5948 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -51,3 +51,26 @@ fn test_tcp_congestion() { val ); } + +#[test] +#[cfg(target_os = "linux")] +fn test_bindtodevice() { + use nix::Error; + use nix::errno::Errno; + + let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); + + let val = getsockopt(fd, sockopt::BindToDevice).unwrap(); + match setsockopt(fd, sockopt::BindToDevice, &val) { + // SO_BINDTODEVICE requires root, ignore the error as this could break + // the CI. + Err(Error::Sys(Errno::EPERM)) => (), + Err(e) => panic!("{}", e), + Ok(()) => (), + } + + assert_eq!( + getsockopt(fd, sockopt::BindToDevice).unwrap(), + val + ); +}