From 2440729ab5be458aad70ad724330a84ff209c476 Mon Sep 17 00:00:00 2001 From: Skye Soss Date: Tue, 10 Feb 2026 13:00:12 -0600 Subject: [PATCH] Add `ip(v6)_checksum` socket options --- src/backend/libc/net/sockopt.rs | 36 +++++++++++++++++ src/backend/linux_raw/c.rs | 6 +-- src/backend/linux_raw/net/sockopt.rs | 20 ++++++++++ src/net/sockopt.rs | 60 ++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/backend/libc/net/sockopt.rs b/src/backend/libc/net/sockopt.rs index 0a8541461..32ffac7f5 100644 --- a/src/backend/libc/net/sockopt.rs +++ b/src/backend/libc/net/sockopt.rs @@ -873,6 +873,42 @@ pub(crate) fn ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result { getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool) } +#[cfg(any(linux_like, target_os = "cygwin", target_os = "fuchsia",))] +#[inline] +pub(crate) fn set_ip_checksum(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IP_CHECKSUM, value) +} + +#[cfg(any(linux_like, target_os = "cygwin", target_os = "fuchsia",))] +#[inline] +pub(crate) fn ip_checksum(fd: BorrowedFd<'_>) -> io::Result { + getsockopt(fd, c::IPPROTO_IP, c::IP_CHECKSUM) +} + +#[cfg(any( + apple, + linux_like, + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", +))] +#[inline] +pub(crate) fn set_ipv6_checksum(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_CHECKSUM, value) +} + +#[cfg(any( + apple, + linux_like, + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", +))] +#[inline] +pub(crate) fn ipv6_checksum(fd: BorrowedFd<'_>) -> io::Result { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_CHECKSUM) +} + #[cfg(any(linux_kernel, target_os = "fuchsia"))] #[inline] pub(crate) fn ip_original_dst(fd: BorrowedFd<'_>) -> io::Result { diff --git a/src/backend/linux_raw/c.rs b/src/backend/linux_raw/c.rs index 762cdd479..df779a589 100644 --- a/src/backend/linux_raw/c.rs +++ b/src/backend/linux_raw/c.rs @@ -86,12 +86,12 @@ pub(crate) use linux_raw_sys::{ AF_LLC, AF_NETBEUI, AF_NETLINK, AF_NETROM, AF_PACKET, AF_PHONET, AF_PPPOX, AF_RDS, AF_ROSE, AF_RXRPC, AF_SECURITY, AF_SNA, AF_TIPC, AF_UNIX, AF_UNSPEC, AF_VSOCK, AF_WANPIPE, AF_X25, AF_XDP, IP6T_SO_ORIGINAL_DST, IPPROTO_FRAGMENT, IPPROTO_ICMPV6, IPPROTO_MH, - IPPROTO_ROUTING, IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_FREEBIND, + IPPROTO_ROUTING, IPV6_ADD_MEMBERSHIP, IPV6_CHECKSUM, IPV6_DROP_MEMBERSHIP, IPV6_FREEBIND, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_LOOP, IPV6_PMTUDISC_DO, IPV6_PMTUDISC_DONT, IPV6_PMTUDISC_INTERFACE, IPV6_PMTUDISC_OMIT, IPV6_PMTUDISC_PROBE, IPV6_PMTUDISC_WANT, IPV6_RECVTCLASS, IPV6_TCLASS, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, - IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, IP_FREEBIND, - IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_PMTUDISC_DO, IP_PMTUDISC_DONT, + IP_ADD_SOURCE_MEMBERSHIP, IP_CHECKSUM, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, + IP_FREEBIND, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_PMTUDISC_DO, IP_PMTUDISC_DONT, IP_PMTUDISC_INTERFACE, IP_PMTUDISC_OMIT, IP_PMTUDISC_PROBE, IP_PMTUDISC_WANT, IP_RECVTOS, IP_TOS, IP_TTL, MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_CTRUNC, MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR, MSG_ERRQUEUE, MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, diff --git a/src/backend/linux_raw/net/sockopt.rs b/src/backend/linux_raw/net/sockopt.rs index 85c65b085..2f08f0dfe 100644 --- a/src/backend/linux_raw/net/sockopt.rs +++ b/src/backend/linux_raw/net/sockopt.rs @@ -724,6 +724,26 @@ pub(crate) fn ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result { getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool) } +#[inline] +pub(crate) fn set_ip_checksum(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IP_CHECKSUM, value) +} + +#[inline] +pub(crate) fn ip_checksum(fd: BorrowedFd<'_>) -> io::Result { + getsockopt(fd, c::IPPROTO_IP, c::IP_CHECKSUM) +} + +#[inline] +pub(crate) fn set_ipv6_checksum(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_CHECKSUM, value) +} + +#[inline] +pub(crate) fn ipv6_checksum(fd: BorrowedFd<'_>) -> io::Result { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_CHECKSUM) +} + #[inline] pub(crate) fn ip_original_dst(fd: BorrowedFd<'_>) -> io::Result { let level = c::IPPROTO_IP; diff --git a/src/net/sockopt.rs b/src/net/sockopt.rs index 796a114be..984e2f0d0 100644 --- a/src/net/sockopt.rs +++ b/src/net/sockopt.rs @@ -1359,6 +1359,66 @@ pub fn ipv6_freebind(fd: Fd) -> io::Result { backend::net::sockopt::ipv6_freebind(fd.as_fd()) } +/// `setsockopt(fd, IPPROTO_IP, IP_CHECKSUM, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any(linux_like, target_os = "cygwin", target_os = "fuchsia",))] +#[inline] +#[doc(alias = "IP_CHECKSUM")] +pub fn set_ip_checksum(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_ip_checksum(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_CHECKSUM)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any(linux_like, target_os = "cygwin", target_os = "fuchsia",))] +#[inline] +#[doc(alias = "IP_CHECKSUM")] +pub fn ip_checksum(fd: Fd) -> io::Result { + backend::net::sockopt::ip_checksum(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any( + apple, + linux_like, + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", +))] +#[inline] +#[doc(alias = "IPV6_CHECKSUM")] +pub fn set_ipv6_checksum(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_ipv6_checksum(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any( + apple, + linux_like, + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", +))] +#[inline] +#[doc(alias = "IPV6_CHECKSUM")] +pub fn ipv6_checksum(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_checksum(fd.as_fd()) +} + /// `getsockopt(fd, IPPROTO_IP, SO_ORIGINAL_DST)` /// /// Even though this corresponds to a `SO_*` constant, it is an `IPPROTO_IP`