diff --git a/changelog/2611.added.md b/changelog/2611.added.md new file mode 100644 index 0000000000..b94114770c --- /dev/null +++ b/changelog/2611.added.md @@ -0,0 +1 @@ +Add `FilAttach` and `FilDetach` to socket::sockopt for Illumos diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index e26e327d78..98f656a0b9 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -2466,7 +2466,7 @@ pub trait GetSockOpt: Copy { /// Represents a socket option that can be set. pub trait SetSockOpt: Clone { - type Val; + type Val: ?Sized; /// Set the value of this socket option on the given socket. fn set(&self, fd: &F, val: &Self::Val) -> Result<()>; diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 11c3be9e13..10ed64cfc1 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -1,8 +1,8 @@ //! Socket options as used by `setsockopt` and `getsockopt`. -#[cfg(linux_android)] +#[cfg(any(linux_android, target_os = "illumos"))] use super::SetSockOpt; use crate::sys::time::TimeVal; -#[cfg(linux_android)] +#[cfg(any(linux_android, target_os = "illumos"))] use crate::{errno::Errno, Result}; use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; @@ -11,7 +11,7 @@ use std::ffi::CString; use std::ffi::{CStr, OsStr, OsString}; use std::mem::{self, MaybeUninit}; use std::os::unix::ffi::OsStrExt; -#[cfg(linux_android)] +#[cfg(any(linux_android, target_os = "illumos"))] use std::os::unix::io::{AsFd, AsRawFd}; // Constants @@ -1482,6 +1482,58 @@ impl SetSockOpt for TcpTlsRx { } } +#[cfg(target_os = "illumos")] +#[derive(Copy, Clone, Debug)] +/// Attach a named filter to this socket to be able to +/// defer when anough byte had been buffered by the kernel +pub struct FilterAttach; + +#[cfg(target_os = "illumos")] +impl SetSockOpt for FilterAttach { + type Val = OsStr; + + fn set(&self, fd: &F, val: &Self::Val) -> Result<()> { + if val.len() > libc::FILNAME_MAX as usize { + return Err(Errno::EINVAL); + } + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_FILTER, + libc::FIL_ATTACH, + val.as_bytes().as_ptr().cast(), + val.len() as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + +#[cfg(target_os = "illumos")] +#[derive(Copy, Clone, Debug)] +/// Detach a socket filter previously attached with FIL_ATTACH +pub struct FilterDetach; + +#[cfg(target_os = "illumos")] +impl SetSockOpt for FilterDetach { + type Val = OsStr; + + fn set(&self, fd: &F, val: &Self::Val) -> Result<()> { + if val.len() > libc::FILNAME_MAX as usize { + return Err(Errno::EINVAL); + } + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_FILTER, + libc::FIL_DETACH, + val.as_bytes().as_ptr().cast(), + val.len() as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} /* * * ===== Accessor helpers ===== @@ -1799,7 +1851,7 @@ pub struct SetOsString<'a> { val: &'a OsStr, } -#[cfg(any(target_os = "freebsd", linux_android))] +#[cfg(any(target_os = "freebsd", linux_android, target_os = "illumos"))] impl<'a> Set<'a, OsString> for SetOsString<'a> { fn new(val: &OsString) -> SetOsString { SetOsString { diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 42697ffa24..f96b450346 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -1168,3 +1168,26 @@ fn test_exclbind() { Err(Errno::EADDRINUSE) ); } + +#[cfg(target_os = "illumos")] +#[test] +fn test_solfilter() { + use nix::errno::Errno; + let s = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + let data = std::ffi::OsStr::new("httpf"); + let attach = sockopt::FilterAttach; + let detach = sockopt::FilterDetach; + + // These 2 options won't work unless the needed kernel module is installed: + // https://github.com/nix-rust/nix/pull/2611#issuecomment-2750237782 + // + // So we only test the binding here + assert_eq!(Err(Errno::ENOENT), setsockopt(&s, attach, data)); + assert_eq!(Err(Errno::ENOENT), setsockopt(&s, detach, data)); +}