socket::sockopt adding SOL_FILTER level options for illumos.#2611
socket::sockopt adding SOL_FILTER level options for illumos.#2611SteveLauC merged 3 commits intonix-rust:masterfrom
Conversation
Respectively FIL_ATTACH/FIL_DETACH to bind/unbind a filter to a socket to for example delay connection acceptance until data (datafilt) is received.
| SetOnly, | ||
| libc::SOL_FILTER, | ||
| libc::FIL_ATTACH, | ||
| SetOsString<'static> |
There was a problem hiding this comment.
I am thinking if this 'static lifetime would be too restrictive? I do not see a way to specify lifetime parameter using the macro, maybe we can implement the nix::sys::socket::SetSockOpt trait manually?
f3c875b to
366ca97
Compare
| type Val = [u8; libc::FILNAME_MAX as usize]; | ||
|
|
||
| fn set<F: AsFd>(&self, fd: &F, val: &[u8; libc::FILNAME_MAX as usize]) -> Result<()> { | ||
| unsafe { | ||
| let res = libc::setsockopt( | ||
| fd.as_fd().as_raw_fd(), | ||
| libc::SOL_FILTER, | ||
| libc::FIL_ATTACH, | ||
| val.as_ptr().cast(), | ||
| val.len() as libc::socklen_t, |
There was a problem hiding this comment.
We are passing the whole buffer to the syscall, is this something expected?
BTW, the below code should mirror the original implementation:
#[derive(Clone)]
pub struct FilterAttach<'a> {
_marker: std::marker::PhantomData<&'a ()>
}
impl<'a> FilterAttach<'a> {
pub fn new() -> Self {
Self {
_marker: std::marker::PhantomData,
}
}
}
impl<'a> SetSockOpt for FilterAttach<'a> {
type Val = &'a OsStr;
fn set<F: std::os::unix::prelude::AsFd>(&self, fd: &F, val: &Self::Val) -> nix::Result<()> {
unsafe {
let res = libc::setsockopt(
fd.as_fd().as_raw_fd(),
libc::SOL_FILTER,
libc::FIL_ATTACH,
val.as_ptr().cast(),
val.len() as libc::socklen_t,
);
Errno::result(res).map(drop)
}
}
}915fcf8 to
21690ce
Compare
|
|
||
| #[cfg(target_os = "illumos")] | ||
| #[cfg(feature = "net")] | ||
| const FILNAME_MAX: usize = 32; |
There was a problem hiding this comment.
Please use the constant from the libc crate:)
There was a problem hiding this comment.
yes I tried to avoid the cast ;) but ok
|
Can we have tests for this? |
thing is you need to register the filter(s) in the system prior otherwise it will fail (No such file or directory) e.g. |
21690ce to
92f249d
Compare
Having a test that would fail is also acceptable as we only test the binding/interface, not the libc/kernel implementation |
b09e24b to
410d712
Compare
|
Hi, I just realized that the /// Represents a socket option that can be set.
pub trait SetSockOpt: Clone {
- type Val: Sized;
+ type Val: ?Sized;
/// Set the value of this socket option on the given socket.Then, our socket option impl can be: #[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<F: AsFd>(&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<F: AsFd>(&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)
}
}
}Note that I removed your use of Then, in our tests, note that I documented the reason why we accept #[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::FilAttach;
let detach = sockopt::FilterDetach;
// These 2 options won't work unless the needed kernel model 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));
} |
69a1c8e to
6d5e426
Compare
Respectively FIL_ATTACH/FIL_DETACH to bind/unbind a filter to a socket to for example delay connection acceptance until data (datafilt) is received.