From 23f68464446a173b2736f4f134f088a3f370fbda Mon Sep 17 00:00:00 2001 From: Skye Soss Date: Fri, 30 Jan 2026 16:56:02 -0600 Subject: [PATCH] RFC 2292 struct and constant definitions This PR adds the icmp6_filter struct and constants as defined by RFC 2292 - Advanced Sockets API for IPv6. These constants are available for use in get/setsockopt on supported Unix platforms. The operations defined on the icmp6_filter struct are defined as C macros, so the implementations are not included here. See the RFC for definitions and use. --- libc-test/build.rs | 23 +++ src/unix/bsd/mod.rs | 1 + src/unix/linux_like/mod.rs | 2 + src/unix/mod.rs | 300 +++++++++++++++++++++++++++++++++++++ 4 files changed, 326 insertions(+) diff --git a/libc-test/build.rs b/libc-test/build.rs index 68b224c8b9972..2d320eaa45870 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -254,6 +254,8 @@ fn test_apple(target: &str) { "netinet/ip.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "netinet6/in6_var.h", "os/clock.h", "os/lock.h", @@ -449,6 +451,8 @@ fn test_openbsd(target: &str) { "netinet/ip.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "net/bpf.h", "regex.h", "resolv.h", @@ -867,6 +871,8 @@ fn test_redox(target: &str) { "netinet/in.h", "netinet/ip.h", "netinet/tcp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "poll.h", "pwd.h", "semaphore.h", @@ -945,6 +951,8 @@ fn test_solarish(target: &str) { "netinet/ip.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "poll.h", "port.h", "pthread.h", @@ -1229,6 +1237,8 @@ fn test_netbsd(target: &str) { "netinet/ip.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "poll.h", "pthread.h", "pwd.h", @@ -1518,6 +1528,8 @@ fn test_dragonflybsd(target: &str) { "netinet/ip.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "poll.h", "pthread.h", "pthread_np.h", @@ -1833,6 +1845,8 @@ fn test_android(target: &str) { "netinet/ip.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "netpacket/packet.h", "poll.h", "pthread.h", @@ -2352,6 +2366,8 @@ fn test_freebsd(target: &str) { "netinet/sctp.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "poll.h", "pthread.h", "pthread_np.h", @@ -2979,6 +2995,8 @@ fn test_emscripten(target: &str) { "netinet/ip.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", + "netinet/ip6.h", "netpacket/packet.h", "poll.h", "pthread.h", @@ -3247,6 +3265,8 @@ fn test_neutrino(target: &str) { "netinet/tcp.h", "netinet/udp.h", "netinet/ip_var.h", + "netinet/icmp6.h", + "netinet/ip6.h", "sys/poll.h", "pthread.h", "pwd.h", @@ -3750,8 +3770,10 @@ fn test_linux(target: &str) { "netdb.h", "netinet/in.h", "netinet/ip.h", + "netinet/ip6.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", (l4re, "netpacket/packet.h"), "poll.h", "pthread.h", @@ -5028,6 +5050,7 @@ fn test_haiku(target: &str) { "netinet/ip_var.h", "netinet/tcp.h", "netinet/udp.h", + "netinet/icmp6.h", "netinet6/in6.h", "nl_types.h", "null.h", diff --git a/src/unix/bsd/mod.rs b/src/unix/bsd/mod.rs index 37ef0f0d81ed1..4133f515e7a16 100644 --- a/src/unix/bsd/mod.rs +++ b/src/unix/bsd/mod.rs @@ -211,6 +211,7 @@ pub const IPV6_UNICAST_HOPS: c_int = 4; pub const IPV6_MULTICAST_IF: c_int = 9; pub const IPV6_MULTICAST_HOPS: c_int = 10; pub const IPV6_MULTICAST_LOOP: c_int = 11; +pub const ICMP6_FILTER: c_int = 18; pub const IPV6_V6ONLY: c_int = 27; pub const IPV6_DONTFRAG: c_int = 62; diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 30bad55e032f8..3f149dbe1af73 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -977,6 +977,8 @@ pub const IPV6_PMTUDISC_PROBE: c_int = 3; pub const IPV6_PMTUDISC_INTERFACE: c_int = 4; pub const IPV6_PMTUDISC_OMIT: c_int = 5; +pub const ICMP6_FILTER: c_int = 1; + pub const TCP_NODELAY: c_int = 1; pub const TCP_MAXSEG: c_int = 2; pub const TCP_CORK: c_int = 3; diff --git a/src/unix/mod.rs b/src/unix/mod.rs index 79c3ef8be2220..7ca751625bbd7 100644 --- a/src/unix/mod.rs +++ b/src/unix/mod.rs @@ -219,6 +219,231 @@ s! { pub struct in6_addr { pub s6_addr: [u8; 16], } + + pub struct ip6_hbh { + pub ip6h_nxt: u8, + pub ip6h_len: u8, + } + + pub struct ip6_dest { + pub ip6d_nxt: u8, + pub ip6d_len: u8, + } + + pub struct ip6_rthdr { + pub ip6r_nxt: u8, + pub ip6r_len: u8, + pub ip6r_type: u8, + pub ip6r_segleft: u8, + } + + #[cfg_attr( + any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + ), + repr(packed) + )] + #[cfg_attr(any(target_os = "linux", target_os = "emscripten"), repr(align(4)))] + pub struct ip6_rthdr0 { + pub ip6r0_nxt: u8, + pub ip6r0_len: u8, + pub ip6r0_type: u8, + pub ip6r0_segleft: u8, + #[cfg(not(any(target_os = "linux", target_os = "emscripten")))] + pub ip6r0_reserved: u32, + #[cfg(any(target_os = "linux", target_os = "emscripten"))] + pub ip6r0_reserved: u8, + #[cfg(any(target_os = "linux", target_os = "emscripten"))] + pub ip6r0_slmap: [u8; 3], + #[cfg(all(target_os = "linux", target_env = "gnu"))] + pub ip6r0_addr: [in6_addr; 0], + } + + #[cfg_attr( + any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + ), + repr(packed) + )] + pub struct ip6_frag { + ip6f_nxt: u8, + ip6f_reserved: u8, + ip6f_offlg: u16, + ip6f_ident: u32, + } + + pub struct icmp6_filter { + #[cfg(not(target_os = "solaris"))] + pub icmp6_filt: [u32; 8], + #[cfg(target_os = "solaris")] + pub __icmp6_filt: [u32; 8], + } + + #[cfg_attr( + any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + ), + repr(packed) + )] + #[cfg_attr( + not(any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + )), + repr(align(4)) + )] + pub struct icmp6_hdr { + pub icmp6_type: u8, + pub icmp6_code: u8, + pub icmp6_cksum: u16, + pub icmp6_data8: [u8; 4], + } + + #[cfg_attr( + any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + ), + repr(packed) + )] + pub struct nd_router_solicit { + pub nd_rs_hdr: icmp6_hdr, + } + + #[cfg_attr( + any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + ), + repr(packed) + )] + pub struct nd_router_advert { + pub nd_ra_hdr: icmp6_hdr, + pub nd_ra_reachable: u32, + pub nd_ra_retransmit: u32, + } + + // FIXME(unix): Allow in6_addr to have packed alignment, + // or ignore alignment requirement for libc structs + // on these platforms. + #[cfg(not(any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "macos" + )))] + pub struct nd_neighbor_solicit { + pub nd_ns_hdr: icmp6_hdr, + pub nd_ns_target: in6_addr, + } + + #[cfg(not(any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "macos" + )))] + pub struct nd_neighbor_advert { + pub nd_na_hdr: icmp6_hdr, + pub nd_na_target: in6_addr, + } + + #[cfg(not(any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "macos" + )))] + pub struct nd_redirect { + pub nd_rd_hdr: icmp6_hdr, + pub nd_rd_target: in6_addr, + pub nd_rd_dst: in6_addr, + } + + pub struct nd_opt_hdr { + pub nd_opt_type: u8, + pub nd_opt_len: u8, + } + + #[cfg(not(any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "macos" + )))] + pub struct nd_opt_prefix_info { + pub nd_opt_pi_type: u8, + pub nd_opt_pi_len: u8, + pub nd_opt_pi_prefix_len: u8, + pub nd_opt_pi_flags_reserved: u8, + pub nd_opt_pi_valid_time: u32, + pub nd_opt_pi_preferred_time: u32, + pub nd_opt_pi_reserved2: u32, + pub nd_opt_pi_prefix: in6_addr, + } + + #[cfg_attr( + any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + ), + repr(packed) + )] + pub struct nd_opt_rd_hdr { + pub nd_opt_rh_type: u8, + pub nd_opt_rh_len: u8, + pub nd_opt_rh_reserved1: u16, + pub nd_opt_rh_reserved2: u32, + } + + #[cfg_attr( + any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "macos" + ), + repr(packed) + )] + pub struct nd_opt_mtu { + pub nd_opt_mtu_type: u8, + pub nd_opt_mtu_len: u8, + pub nd_opt_mtu_reserved: u16, + pub nd_opt_mtu_mtu: u32, + } } s_no_extra_traits! { @@ -366,6 +591,81 @@ pub const ATF_PERM: c_int = 0x04; pub const ATF_PUBL: c_int = 0x08; pub const ATF_USETRAILERS: c_int = 0x10; +// IPv6 Extension Headers +cfg_if! { + if #[cfg(all(not(target_os = "android"), target_endian = "big"))] { + pub const IP6F_OFF_MASK: u16 = 0xfff8; + pub const IP6F_RESERVED_MASK: u16 = 0x0006; + pub const IP6F_MORE_FRAG: u16 = 0x0001; + } else if #[cfg(not(target_os = "android"))] { + pub const IP6F_OFF_MASK: u16 = 0xf8ff; + pub const IP6F_RESERVED_MASK: u16 = 0x0600; + pub const IP6F_MORE_FRAG: u16 = 0x0100; + } +} + +// ICMPv6 Type and Code Values +pub const ICMP6_DST_UNREACH: u8 = 1; +pub const ICMP6_PACKET_TOO_BIG: u8 = 2; +pub const ICMP6_TIME_EXCEEDED: u8 = 3; +pub const ICMP6_PARAM_PROB: u8 = 4; + +pub const ICMP6_INFOMSG_MASK: u8 = 0x80; + +pub const ICMP6_ECHO_REQUEST: u8 = 128; +pub const ICMP6_ECHO_REPLY: u8 = 129; + +cfg_if! { + if #[cfg(not(any(target_os = "linux", target_os = "emscripten")))] { + pub const ICMP6_MEMBERSHIP_QUERY: u8 = 130; + pub const ICMP6_MEMBERSHIP_REPORT: u8 = 131; + pub const ICMP6_MEMBERSHIP_REDUCTION: u8 = 132; + } +} + +pub const ICMP6_DST_UNREACH_NOROUTE: u8 = 0; +pub const ICMP6_DST_UNREACH_ADMIN: u8 = 1; +pub const ICMP6_DST_UNREACH_BEYONDSCOPE: u8 = 2; +pub const ICMP6_DST_UNREACH_ADDR: u8 = 3; +pub const ICMP6_DST_UNREACH_NOPORT: u8 = 4; + +pub const ICMP6_TIME_EXCEED_TRANSIT: u8 = 0; +pub const ICMP6_TIME_EXCEED_REASSEMBLY: u8 = 1; + +pub const ICMP6_PARAMPROB_HEADER: u8 = 0; +pub const ICMP6_PARAMPROB_NEXTHEADER: u8 = 1; +pub const ICMP6_PARAMPROB_OPTION: u8 = 2; + +// ICMPv6 Neighbor Discovery Type and Code Values +pub const ND_ROUTER_SOLICIT: u8 = 133; +pub const ND_ROUTER_ADVERT: u8 = 134; +pub const ND_NEIGHBOR_SOLICIT: u8 = 135; +pub const ND_NEIGHBOR_ADVERT: u8 = 136; +pub const ND_REDIRECT: u8 = 137; + +pub const ND_RA_FLAG_MANAGED: u8 = 0x80; +pub const ND_RA_FLAG_OTHER: u8 = 0x40; + +cfg_if! { + if #[cfg(target_endian = "big")] { + pub const ND_NA_FLAG_ROUTER: u32 = 0x80000000; + pub const ND_NA_FLAG_SOLICITED: u32 = 0x40000000; + pub const ND_NA_FLAG_OVERRIDE: u32 = 0x20000000; + } else { + pub const ND_NA_FLAG_ROUTER: u32 = 0x00000080; + pub const ND_NA_FLAG_SOLICITED: u32 = 0x00000040; + pub const ND_NA_FLAG_OVERRIDE: u32 = 0x00000020; + } +} + +pub const ND_OPT_SOURCE_LINKADDR: u8 = 1; +pub const ND_OPT_TARGET_LINKADDR: u8 = 2; +pub const ND_OPT_PREFIX_INFORMATION: u8 = 3; +pub const ND_OPT_REDIRECTED_HEADER: u8 = 4; +pub const ND_OPT_MTU: u8 = 5; +pub const ND_OPT_PI_FLAG_ONLINK: u8 = 0x80; +pub const ND_OPT_PI_FLAG_AUTO: u8 = 0x40; + cfg_if! { if #[cfg(any(target_os = "nto", target_os = "aix"))] { pub const FNM_PERIOD: c_int = 1 << 1;