Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions libc-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ fn do_cc() {
{
cc::Build::new().file("src/sigrt.c").compile("sigrt");
}
if (target.contains("linux") && !target.contains("wasm32"))
|| target.contains("android")
|| target.contains("apple")
|| target.contains("dragonfly")
|| target.contains("emscripten")
|| target.contains("freebsd")
|| target.contains("fuschia")
|| target.contains("illumos")
|| target.contains("netbsd")
|| target.contains("openbsd")
|| target.contains("solaris")
{
cc::Build::new()
.file("src/icmp6_filter.c")
.compile("icmp6_filter");
}
}

fn do_ctest() {
Expand Down Expand Up @@ -269,6 +285,7 @@ fn test_apple(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"netinet6/in6_var.h",
"os/clock.h",
"os/lock.h",
Expand Down Expand Up @@ -494,6 +511,7 @@ fn test_openbsd(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"net/bpf.h",
"regex.h",
"resolv.h",
Expand Down Expand Up @@ -1027,6 +1045,7 @@ fn test_solarish(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"poll.h",
"port.h",
"pthread.h",
Expand Down Expand Up @@ -1322,6 +1341,7 @@ fn test_netbsd(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"poll.h",
"pthread.h",
"pwd.h",
Expand Down Expand Up @@ -1623,6 +1643,7 @@ fn test_dragonflybsd(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"poll.h",
"pthread.h",
"pthread_np.h",
Expand Down Expand Up @@ -2076,6 +2097,7 @@ fn test_android(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"netpacket/packet.h",
"poll.h",
"pthread.h",
Expand Down Expand Up @@ -2610,6 +2632,7 @@ fn test_freebsd(target: &str) {
"netinet/sctp.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"netinet6/in6_var.h",
"poll.h",
"pthread.h",
Expand Down Expand Up @@ -3256,6 +3279,7 @@ fn test_emscripten(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"netpacket/packet.h",
"poll.h",
"pthread.h",
Expand Down Expand Up @@ -3526,6 +3550,7 @@ fn test_neutrino(target: &str) {
"netinet/ip.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"netinet/ip_var.h",
"sys/poll.h",
"pthread.h",
Expand Down Expand Up @@ -3809,6 +3834,7 @@ fn test_vxworks(target: &str) {
"sys/mman.h",
"netinet/tcp.h",
"netinet/udp.h",
"netinet/icmp6.h",
"netinet/in.h",
"netinet6/in6.h",
"syslog.h",
Expand Down Expand Up @@ -4060,6 +4086,7 @@ fn test_linux(target: &str) {
"netinet/tcp.h",
"netinet/udp.h",
(gnu, "netiucv/iucv.h"),
"netinet/icmp6.h",
(l4re, "netpacket/packet.h"),
"poll.h",
"pthread.h",
Expand Down
1 change: 1 addition & 0 deletions libc-test/semver/unix.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ F_SETLKW
GRPQUOTA
HUPCL
ICANON
ICMP6_FILTER
ICRNL
IEXTEN
IFNAMSIZ
Expand Down
41 changes: 41 additions & 0 deletions libc-test/src/icmp6_filter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <stdbool.h>
#include <string.h>
#include <stdint.h>

typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
typedef uint32_t u_int32_t;

#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>

// Since the ICMP6_FILTER macros are macros instead of functions, they aren't
// available to FFI. libc must reimplement them, which is error-prone. This
// file provides FFI access to the actual macros so they can be tested against
// the Rust reimplementations.

bool icmp6_filter_willpass(uint8_t typ, const struct icmp6_filter *filt) {
return ICMP6_FILTER_WILLPASS(typ, filt);
}

bool icmp6_filter_willblock(uint8_t typ, const struct icmp6_filter *filt) {
return ICMP6_FILTER_WILLBLOCK(typ, filt);
}

void icmp6_filter_setpassall(struct icmp6_filter *filt) {
ICMP6_FILTER_SETPASSALL(filt);
}

void icmp6_filter_setblockall(struct icmp6_filter *filt) {
ICMP6_FILTER_SETBLOCKALL(filt);
}

void icmp6_filter_setpass(uint8_t typ, struct icmp6_filter *filt) {
ICMP6_FILTER_SETPASS(typ, filt);
}

void icmp6_filter_setblock(uint8_t typ, struct icmp6_filter *filt) {
ICMP6_FILTER_SETBLOCK(typ, filt);
}

115 changes: 115 additions & 0 deletions libc-test/tests/icmp6_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//! Compare libc's ICMP6_FILTER functions against the actual C macros, for
//! various inputs.

#[cfg(unix)]
mod t {

use std::mem;

use libc::{
self,
icmp6_filter,
};

extern "C" {
pub fn icmp6_filter_willpass(typ: u8, filt: *const icmp6_filter) -> bool;
pub fn icmp6_filter_willblock(typ: u8, filt: *const icmp6_filter) -> bool;
pub fn icmp6_filter_setpassall(filt: *mut icmp6_filter);
pub fn icmp6_filter_setblockall(filt: *mut icmp6_filter);
pub fn icmp6_filter_setpass(typ: u8, filt: *mut icmp6_filter);
pub fn icmp6_filter_setblock(typ: u8, filt: *mut icmp6_filter);
}

// Two ICMPv6 filters are equal if they agree on all ICMPv6 types
// There are only 255 types so we can be complete.
fn assert_filters_eq(filt1: &icmp6_filter, filt2: &icmp6_filter) {
for typ in 0..255 {
unsafe {
assert_eq!(
icmp6_filter_willpass(typ, filt1),
icmp6_filter_willpass(typ, filt2)
);
assert_eq!(
icmp6_filter_willblock(typ, filt1),
icmp6_filter_willblock(typ, filt2)
);
}
}
}

#[test]
fn test_icmp6_filter_setpassall() {
unsafe {
let mut filt1 = mem::zeroed::<icmp6_filter>();
let mut filt2 = mem::zeroed::<icmp6_filter>();
libc::ICMP6_FILTER_SETPASSALL(&mut filt1);
icmp6_filter_setpassall(&mut filt2);
assert_filters_eq(&filt1, &filt2);
}
}

#[test]
fn test_icmp6_filter_setblockall() {
unsafe {
let mut filt1 = mem::zeroed::<icmp6_filter>();
let mut filt2 = mem::zeroed::<icmp6_filter>();
libc::ICMP6_FILTER_SETBLOCKALL(&mut filt1);
icmp6_filter_setblockall(&mut filt2);
assert_filters_eq(&filt1, &filt2);
}
}

#[test]
fn test_icmp6_filter_setblock() {
for typ in 0..255 {
unsafe {
let mut filt1 = mem::zeroed::<icmp6_filter>();
let mut filt2 = mem::zeroed::<icmp6_filter>();
icmp6_filter_setpassall(&mut filt1);
icmp6_filter_setpassall(&mut filt2);
libc::ICMP6_FILTER_SETBLOCK(typ, &mut filt1);
icmp6_filter_setblock(typ, &mut filt2);
assert_filters_eq(&filt1, &filt2);
}
}
}

#[test]
fn test_icmp6_filter_setpass() {
for typ in 0..255 {
unsafe {
let mut filt1 = mem::zeroed::<icmp6_filter>();
let mut filt2 = mem::zeroed::<icmp6_filter>();
icmp6_filter_setblockall(&mut filt1);
icmp6_filter_setblockall(&mut filt2);
libc::ICMP6_FILTER_SETPASS(typ, &mut filt1);
icmp6_filter_setpass(typ, &mut filt2);
assert_filters_eq(&filt1, &filt2);
}
}
}

#[test]
fn test_icmp6_filter_willpass_willblock() {
unsafe {
let mut filt1 = mem::zeroed::<icmp6_filter>();
let mut filt2 = mem::zeroed::<icmp6_filter>();
icmp6_filter_setblockall(&mut filt1);
icmp6_filter_setblockall(&mut filt2);

let mut seed = 0xdeadbeefu32;
for _ in 0..255 {
seed = seed.wrapping_mul(0x915f77f5);
let typ = (seed >> 23) as u8;
if (seed >> 31) & 1 == 0 {
icmp6_filter_setblock(typ, &mut filt1);
libc::ICMP6_FILTER_SETBLOCK(typ, &mut filt2);
} else {
icmp6_filter_setpass(typ, &mut filt1);
libc::ICMP6_FILTER_SETPASS(typ, &mut filt2);
}
assert_filters_eq(&filt1, &filt2);
}
}
}
}
33 changes: 33 additions & 0 deletions src/unix/bsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ s! {
#[cfg(target_os = "dragonfly")]
pub machine: [c_char; 32],
}

pub struct icmp6_filter {
icmp6_filt: [u32; 8],
}
}

pub const LC_ALL: c_int = 0;
Expand Down Expand Up @@ -217,6 +221,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;

Expand Down Expand Up @@ -522,6 +527,34 @@ safe_f! {
pub const fn QCMD(cmd: c_int, type_: c_int) -> c_int {
(cmd << 8) | (type_ & 0x00ff)
}

pub const fn ICMP6_FILTER_WILLPASS(typ: u8, filt: &icmp6_filter) -> bool {
(filt.icmp6_filt[(typ >> 5) as usize] & (1 << (typ & 31))) != 0
}

pub const fn ICMP6_FILTER_WILLBLOCK(typ: u8, filt: &icmp6_filter) -> bool {
(filt.icmp6_filt[(typ >> 5) as usize] & (1 << (typ & 31))) == 0
}

pub fn ICMP6_FILTER_SETPASSALL(filt: &mut icmp6_filter) -> () {
for i in &mut filt.icmp6_filt {
*i = u32::MAX;
}
}

pub fn ICMP6_FILTER_SETBLOCKALL(filt: &mut icmp6_filter) -> () {
for i in &mut filt.icmp6_filt {
*i = 0;
}
}

pub fn ICMP6_FILTER_SETPASS(typ: u8, filt: &mut icmp6_filter) -> () {
filt.icmp6_filt[(typ >> 5) as usize] |= 1 << (typ & 31);
}

pub fn ICMP6_FILTER_SETBLOCK(typ: u8, filt: &mut icmp6_filter) -> () {
filt.icmp6_filt[(typ >> 5) as usize] &= !(1 << (typ & 31));
}
}

extern "C" {
Expand Down
34 changes: 34 additions & 0 deletions src/unix/linux_like/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ s! {
pub if_index: c_uint,
pub if_name: *mut c_char,
}

pub struct icmp6_filter {
icmp6_filt: [u32; 8],
}
}

cfg_if! {
Expand Down Expand Up @@ -985,6 +989,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;
Expand Down Expand Up @@ -1914,6 +1920,34 @@ safe_f! {
pub const fn KERNEL_VERSION(a: u32, b: u32, c: u32) -> u32 {
((a << 16) + (b << 8)) + if c > 255 { 255 } else { c }
}

pub const fn ICMP6_FILTER_WILLPASS(typ: u8, filt: &icmp6_filter) -> bool {
(filt.icmp6_filt[(typ >> 5) as usize] & (1 << (typ & 31))) == 0
}

pub const fn ICMP6_FILTER_WILLBLOCK(typ: u8, filt: &icmp6_filter) -> bool {
(filt.icmp6_filt[(typ >> 5) as usize] & (1 << (typ & 31))) != 0
}

pub fn ICMP6_FILTER_SETPASS(typ: u8, filt: &mut icmp6_filter) -> () {
filt.icmp6_filt[(typ >> 5) as usize] &= !(1 << (typ & 31));
}

pub fn ICMP6_FILTER_SETBLOCK(typ: u8, filt: &mut icmp6_filter) -> () {
filt.icmp6_filt[(typ >> 5) as usize] |= 1 << (typ & 31);
}

pub fn ICMP6_FILTER_SETPASSALL(filt: &mut icmp6_filter) -> () {
for i in &mut filt.icmp6_filt {
*i = 0;
}
}

pub fn ICMP6_FILTER_SETBLOCKALL(filt: &mut icmp6_filter) -> () {
for i in &mut filt.icmp6_filt {
*i = u32::MAX;
}
}
}

extern "C" {
Expand Down
Loading