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..e0fbdbe11 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(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);