From 0847062d37dd108f79affb6338ae69145da0d9c2 Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+kristof-mattei@users.noreply.github.com> Date: Sat, 17 Jan 2026 13:52:05 -0700 Subject: [PATCH 1/3] fix: allow to run tests locally against modified version of `netlink-sys` --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1c49c9e..0a195c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,10 @@ readme = "README.md" repository = "https://github.com/rust-netlink/netlink-sys" description = "netlink sockets, with optional integration with tokio" +# When running the examples against a local version of `netlink-sys` +# [patch.crates-io] +# netlink-sys = { path = "." } + [dependencies] bytes = "1.8" libc = "0.2.164" From 1ee8589b4161a1198d9655cad254713708846344 Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+kristof-mattei@users.noreply.github.com> Date: Sat, 17 Jan 2026 13:10:49 -0700 Subject: [PATCH 2/3] fix: none of these methods modify the socket, they merely modify the kernel's state and the buffer's state --- examples/audit_events_async_std.rs | 2 +- examples/audit_events_tokio.rs | 2 +- src/async_socket.rs | 10 ++++----- src/async_socket_ext.rs | 33 ++++++++++++++---------------- src/smol.rs | 28 ++++++++++++------------- src/tokio.rs | 10 ++++----- 6 files changed, 41 insertions(+), 44 deletions(-) diff --git a/examples/audit_events_async_std.rs b/examples/audit_events_async_std.rs index 2c899fc..c0fa30b 100644 --- a/examples/audit_events_async_std.rs +++ b/examples/audit_events_async_std.rs @@ -31,7 +31,7 @@ const AUDIT_STATUS_PID: u32 = 4; #[async_std::main] async fn main() { let kernel_unicast: SocketAddr = SocketAddr::new(0, 0); - let mut socket = SmolSocket::new(NETLINK_AUDIT).unwrap(); + let socket = SmolSocket::new(NETLINK_AUDIT).unwrap(); let mut status = StatusMessage::new(); status.enabled = 1; diff --git a/examples/audit_events_tokio.rs b/examples/audit_events_tokio.rs index 833e93b..51513f4 100644 --- a/examples/audit_events_tokio.rs +++ b/examples/audit_events_tokio.rs @@ -31,7 +31,7 @@ const AUDIT_STATUS_PID: u32 = 4; #[tokio::main] async fn main() -> Result<(), Box> { let kernel_unicast: SocketAddr = SocketAddr::new(0, 0); - let mut socket = TokioSocket::new(NETLINK_AUDIT).unwrap(); + let socket = TokioSocket::new(NETLINK_AUDIT).unwrap(); let mut status = StatusMessage::new(); status.enabled = 1; diff --git a/src/async_socket.rs b/src/async_socket.rs index 9ba3fc2..2dfcb35 100644 --- a/src/async_socket.rs +++ b/src/async_socket.rs @@ -20,14 +20,14 @@ pub trait AsyncSocket: Sized + Unpin { /// Polling wrapper for [`Socket::send`] fn poll_send( - &mut self, + &self, cx: &mut Context<'_>, buf: &[u8], ) -> Poll>; /// Polling wrapper for [`Socket::send_to`] fn poll_send_to( - &mut self, + &self, cx: &mut Context<'_>, buf: &[u8], addr: &SocketAddr, @@ -38,7 +38,7 @@ pub trait AsyncSocket: Sized + Unpin { /// Passes 0 for flags, and ignores the returned length (the buffer will /// have advanced by the amount read). fn poll_recv( - &mut self, + &self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> @@ -50,7 +50,7 @@ pub trait AsyncSocket: Sized + Unpin { /// Passes 0 for flags, and ignores the returned length - just returns the /// address (the buffer will have advanced by the amount read). fn poll_recv_from( - &mut self, + &self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> @@ -62,7 +62,7 @@ pub trait AsyncSocket: Sized + Unpin { /// Passes 0 for flags, and ignores the returned length - just returns the /// address (the buffer will have advanced by the amount read). fn poll_recv_from_full( - &mut self, + &self, cx: &mut Context<'_>, ) -> Poll, SocketAddr)>>; } diff --git a/src/async_socket_ext.rs b/src/async_socket_ext.rs index bf18ded..b629411 100644 --- a/src/async_socket_ext.rs +++ b/src/async_socket_ext.rs @@ -13,14 +13,14 @@ use crate::{AsyncSocket, SocketAddr}; /// /// Provides awaitable variants of the poll functions from [`AsyncSocket`]. pub trait AsyncSocketExt: AsyncSocket { - /// `async fn send(&mut self, buf: &[u8]) -> io::Result` - fn send<'a, 'b>(&'a mut self, buf: &'b [u8]) -> PollSend<'a, 'b, Self> { + /// `async fn send(&self, buf: &[u8]) -> io::Result` + fn send<'a, 'b>(&'a self, buf: &'b [u8]) -> PollSend<'a, 'b, Self> { PollSend { socket: self, buf } } - /// `async fn send(&mut self, buf: &[u8]) -> io::Result` + /// `async fn send(&self, buf: &[u8]) -> io::Result` fn send_to<'a, 'b>( - &'a mut self, + &'a self, buf: &'b [u8], addr: &'b SocketAddr, ) -> PollSendTo<'a, 'b, Self> { @@ -31,20 +31,17 @@ pub trait AsyncSocketExt: AsyncSocket { } } - /// `async fn recv(&mut self, buf: &mut [u8]) -> io::Result<()>` - fn recv<'a, 'b, B>( - &'a mut self, - buf: &'b mut B, - ) -> PollRecv<'a, 'b, Self, B> + /// `async fn recv(&self, buf: &mut [u8]) -> io::Result<()>` + fn recv<'a, 'b, B>(&'a self, buf: &'b mut B) -> PollRecv<'a, 'b, Self, B> where B: bytes::BufMut, { PollRecv { socket: self, buf } } - /// `async fn recv(&mut self, buf: &mut [u8]) -> io::Result` + /// `async fn recv(&self, buf: &mut [u8]) -> io::Result` fn recv_from<'a, 'b, B>( - &'a mut self, + &'a self, buf: &'b mut B, ) -> PollRecvFrom<'a, 'b, Self, B> where @@ -53,9 +50,9 @@ pub trait AsyncSocketExt: AsyncSocket { PollRecvFrom { socket: self, buf } } - /// `async fn recrecv_from_full(&mut self) -> io::Result<(Vec, + /// `async fn recrecv_from_full(&self) -> io::Result<(Vec, /// SocketAddr)>` - fn recv_from_full(&mut self) -> PollRecvFromFull<'_, Self> { + fn recv_from_full(&self) -> PollRecvFromFull<'_, Self> { PollRecvFromFull { socket: self } } } @@ -63,7 +60,7 @@ pub trait AsyncSocketExt: AsyncSocket { impl AsyncSocketExt for S {} pub struct PollSend<'a, 'b, S> { - socket: &'a mut S, + socket: &'a S, buf: &'b [u8], } @@ -80,7 +77,7 @@ where } pub struct PollSendTo<'a, 'b, S> { - socket: &'a mut S, + socket: &'a S, buf: &'b [u8], addr: &'b SocketAddr, } @@ -98,7 +95,7 @@ where } pub struct PollRecv<'a, 'b, S, B> { - socket: &'a mut S, + socket: &'a S, buf: &'b mut B, } @@ -116,7 +113,7 @@ where } pub struct PollRecvFrom<'a, 'b, S, B> { - socket: &'a mut S, + socket: &'a S, buf: &'b mut B, } @@ -134,7 +131,7 @@ where } pub struct PollRecvFromFull<'a, S> { - socket: &'a mut S, + socket: &'a S, } impl Future for PollRecvFromFull<'_, S> diff --git a/src/smol.rs b/src/smol.rs index 5a12ce4..f905a18 100644 --- a/src/smol.rs +++ b/src/smol.rs @@ -42,12 +42,12 @@ impl AsFd for SmolSocket { // replicate this in these poll functions: impl SmolSocket { fn poll_write_with( - &mut self, + &self, cx: &mut Context<'_>, mut op: F, ) -> Poll> where - F: FnMut(&mut Self) -> io::Result, + F: FnMut(&Self) -> io::Result, { loop { match op(self) { @@ -60,12 +60,12 @@ impl SmolSocket { } fn poll_read_with( - &mut self, + &self, cx: &mut Context<'_>, mut op: F, ) -> Poll> where - F: FnMut(&mut Self) -> io::Result, + F: FnMut(&Self) -> io::Result, { loop { match op(self) { @@ -94,24 +94,24 @@ impl AsyncSocket for SmolSocket { } fn poll_send( - &mut self, + &self, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - self.poll_write_with(cx, |this| this.socket_mut().send(buf, 0)) + self.poll_write_with(cx, |this| this.socket_ref().send(buf, 0)) } fn poll_send_to( - &mut self, + &self, cx: &mut Context<'_>, buf: &[u8], addr: &SocketAddr, ) -> Poll> { - self.poll_write_with(cx, |this| this.socket_mut().send_to(buf, addr, 0)) + self.poll_write_with(cx, |this| this.socket_ref().send_to(buf, addr, 0)) } fn poll_recv( - &mut self, + &self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> @@ -119,12 +119,12 @@ impl AsyncSocket for SmolSocket { B: bytes::BufMut, { self.poll_read_with(cx, |this| { - this.socket_mut().recv(buf, 0).map(|_len| ()) + this.socket_ref().recv(buf, 0).map(|_len| ()) }) } fn poll_recv_from( - &mut self, + &self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> @@ -132,16 +132,16 @@ impl AsyncSocket for SmolSocket { B: bytes::BufMut, { self.poll_read_with(cx, |this| { - let x = this.socket_mut().recv_from(buf, 0); + let x = this.socket_ref().recv_from(buf, 0); trace!("poll_recv_from: {:?}", x); x.map(|(_len, addr)| addr) }) } fn poll_recv_from_full( - &mut self, + &self, cx: &mut Context<'_>, ) -> Poll, SocketAddr)>> { - self.poll_read_with(cx, |this| this.socket_mut().recv_from_full()) + self.poll_read_with(cx, |this| this.socket_ref().recv_from_full()) } } diff --git a/src/tokio.rs b/src/tokio.rs index d5fadb4..ff3c5f2 100644 --- a/src/tokio.rs +++ b/src/tokio.rs @@ -46,7 +46,7 @@ impl AsyncSocket for TokioSocket { } fn poll_send( - &mut self, + &self, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { @@ -66,7 +66,7 @@ impl AsyncSocket for TokioSocket { } fn poll_send_to( - &mut self, + &self, cx: &mut Context<'_>, buf: &[u8], addr: &SocketAddr, @@ -82,7 +82,7 @@ impl AsyncSocket for TokioSocket { } fn poll_recv( - &mut self, + &self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> @@ -104,7 +104,7 @@ impl AsyncSocket for TokioSocket { } fn poll_recv_from( - &mut self, + &self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> @@ -130,7 +130,7 @@ impl AsyncSocket for TokioSocket { } fn poll_recv_from_full( - &mut self, + &self, cx: &mut Context<'_>, ) -> Poll, SocketAddr)>> { loop { From 91777b64d8df9b84635d1912bb8cbb65ebd43c7d Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+kristof-mattei@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:10:44 -0700 Subject: [PATCH 3/3] fix: none of these methods modify the socket, they merely modify the kernel's state --- src/socket.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 9b63959..f73b90c 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -410,7 +410,7 @@ impl Socket { Ok(res as usize) } - pub fn set_pktinfo(&mut self, value: bool) -> Result<()> { + pub fn set_pktinfo(&self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), @@ -429,7 +429,7 @@ impl Socket { Ok(res == 1) } - pub fn add_membership(&mut self, group: u32) -> Result<()> { + pub fn add_membership(&self, group: u32) -> Result<()> { setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, @@ -438,7 +438,7 @@ impl Socket { ) } - pub fn drop_membership(&mut self, group: u32) -> Result<()> { + pub fn drop_membership(&self, group: u32) -> Result<()> { setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, @@ -457,7 +457,7 @@ impl Socket { /// `NETLINK_BROADCAST_ERROR` (since Linux 2.6.30). When not set, /// `netlink_broadcast()` only reports `ESRCH` errors and silently /// ignore `NOBUFS` errors. - pub fn set_broadcast_error(&mut self, value: bool) -> Result<()> { + pub fn set_broadcast_error(&self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), @@ -478,7 +478,7 @@ impl Socket { /// `NETLINK_NO_ENOBUFS` (since Linux 2.6.30). This flag can be used by /// unicast and broadcast listeners to avoid receiving `ENOBUFS` errors. - pub fn set_no_enobufs(&mut self, value: bool) -> Result<()> { + pub fn set_no_enobufs(&self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), @@ -502,7 +502,7 @@ impl Socket { /// have an nsid assigned into the network namespace where the socket /// has been opened. The nsid is sent to user space via an ancillary /// data. - pub fn set_listen_all_namespaces(&mut self, value: bool) -> Result<()> { + pub fn set_listen_all_namespaces(&self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), @@ -527,7 +527,7 @@ impl Socket { /// The netlink message header is still included, so the user can /// guess from the sequence number which message triggered the /// acknowledgment. - pub fn set_cap_ack(&mut self, value: bool) -> Result<()> { + pub fn set_cap_ack(&self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), @@ -549,7 +549,7 @@ impl Socket { /// `NETLINK_EXT_ACK` /// Extended ACK controls reporting of additional error/warning TLVs in /// NLMSG_ERROR and NLMSG_DONE messages. - pub fn set_ext_ack(&mut self, value: bool) -> Result<()> { + pub fn set_ext_ack(&self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), @@ -697,7 +697,7 @@ mod test { #[test] fn options() { - let mut sock = Socket::new(NETLINK_ROUTE).unwrap(); + let sock = Socket::new(NETLINK_ROUTE).unwrap(); sock.set_cap_ack(true).unwrap(); assert!(sock.get_cap_ack().unwrap());