From 3611d7913cdd12b59b21d133ea9d564c89cf35b7 Mon Sep 17 00:00:00 2001 From: Boris Astardzhiev Date: Wed, 27 Mar 2024 17:49:41 +0200 Subject: [PATCH 1/2] For linux users: Add sendmsg ancillary IPV6_PKTINFO option which allows user to specify outgoing source IP address and interface index. This complements the sendmsg_v6 where the destination IP address can also be set. --- src/net/send_recv/msg.rs | 32 ++++++++++++++++++++++++++++++++ src/net/types.rs | 15 +++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/net/send_recv/msg.rs b/src/net/send_recv/msg.rs index 8b81c8d8f..040de22d8 100644 --- a/src/net/send_recv/msg.rs +++ b/src/net/send_recv/msg.rs @@ -6,6 +6,8 @@ use crate::backend::{self, c}; use crate::fd::{AsFd, BorrowedFd, OwnedFd}; use crate::io::{self, IoSlice, IoSliceMut}; #[cfg(linux_kernel)] +use crate::net::Ipv6PktInfo; +#[cfg(linux_kernel)] use crate::net::UCred; use core::iter::FusedIterator; @@ -58,6 +60,11 @@ macro_rules! cmsg_space { $len * ::core::mem::size_of::<$crate::net::UCred>(), ) }; + (Ipv6PktInfo) => { + $crate::net::__cmsg_space( + ::core::mem::size_of::<$crate::net::Ipv6PktInfo>(), + ) + }; // Combo Rules ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{ @@ -86,6 +93,11 @@ macro_rules! cmsg_aligned_space { $len * ::core::mem::size_of::<$crate::net::UCred>(), ) }; + (Ipv6PktInfo) => { + $crate::net::__cmsg_aligned_space( + ::core::mem::size_of::<$crate::net::Ipv6PktInfo>(), + ) + }; // Combo Rules ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{ @@ -129,6 +141,10 @@ pub enum SendAncillaryMessage<'slice, 'fd> { #[cfg(linux_kernel)] #[doc(alias = "SCM_CREDENTIAL")] ScmCredentials(UCred), + /// IPv6 option to specify source address and outgoing interface index + #[cfg(linux_kernel)] + #[doc(alias = "IPV6_PKTINFO")] + Ipv6PktInfo(Ipv6PktInfo), } impl SendAncillaryMessage<'_, '_> { @@ -140,6 +156,8 @@ impl SendAncillaryMessage<'_, '_> { Self::ScmRights(slice) => cmsg_space!(ScmRights(slice.len())), #[cfg(linux_kernel)] Self::ScmCredentials(_) => cmsg_space!(ScmCredentials(1)), + #[cfg(linux_kernel)] + Self::Ipv6PktInfo(_) => cmsg_space!(Ipv6PktInfo), } } } @@ -278,6 +296,20 @@ impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> { }; self.push_ancillary(ucred_bytes, c::SOL_SOCKET as _, c::SCM_CREDENTIALS as _) } + #[cfg(linux_kernel)] + SendAncillaryMessage::Ipv6PktInfo(ipv6_pktinfo) => { + let ipv6_pktinfo_bytes = unsafe { + slice::from_raw_parts( + addr_of!(ipv6_pktinfo).cast::(), + size_of_val(&ipv6_pktinfo), + ) + }; + self.push_ancillary( + ipv6_pktinfo_bytes, + c::IPPROTO_IPV6 as _, + linux_raw_sys::net::IPV6_PKTINFO as _, + ) + } } } diff --git a/src/net/types.rs b/src/net/types.rs index 14345a213..fd403ec88 100644 --- a/src/net/types.rs +++ b/src/net/types.rs @@ -1750,6 +1750,19 @@ pub struct UCred { pub gid: crate::ugid::Gid, } +/// The IPV6_PKTINFO option enables the application to provide the following pieces of information: +/// [`the source IP address for an outgoing packet`] and +/// [`the outgoing interface for a packet`]. +#[cfg(linux_kernel)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(C)] +pub struct Ipv6PktInfo { + /// Source address + pub ipi6_addr: crate::net::Ipv6Addr, + /// Interface index + pub if_index: u32, +} + #[test] fn test_sizes() { use crate::backend::c; @@ -1779,6 +1792,8 @@ fn test_sizes() { #[cfg(linux_kernel)] assert_eq_size!(UCred, libc::ucred); + #[cfg(linux_kernel)] + assert_eq_size!(Ipv6PktInfo, libc::in6_pktinfo); #[cfg(target_os = "linux")] assert_eq_size!(super::xdp::XdpUmemReg, c::xdp_umem_reg); From 0f6fdf990c782a6612d63f4a712ce454e5b8726b Mon Sep 17 00:00:00 2001 From: Boris Astardzhiev Date: Thu, 28 Mar 2024 09:42:24 +0200 Subject: [PATCH 2/2] Fix CI: Don't derive Debug for Ipv6PktInfo --- src/net/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/types.rs b/src/net/types.rs index fd403ec88..e0fbdbe11 100644 --- a/src/net/types.rs +++ b/src/net/types.rs @@ -1754,7 +1754,7 @@ pub struct UCred { /// [`the source IP address for an outgoing packet`] and /// [`the outgoing interface for a packet`]. #[cfg(linux_kernel)] -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Clone, Copy, Eq, PartialEq, Hash)] #[repr(C)] pub struct Ipv6PktInfo { /// Source address