#![allow(
non_snake_case,
non_camel_case_types,
non_upper_case_globals,
unused,
deref_nullptr
)]
include!(concat!(env!("OUT_DIR"), "/cnproc_bindings.rs"));
#[repr(C, align(4))] pub struct nlmsghdr_aligned<T>(pub T);
#[repr(C)]
pub struct nlcn_msg<T> {
pub nl_hdr: nlmsghdr_aligned<libc::nlmsghdr>,
pub cn_msg: T,
}
macro_rules! bpf_jump {
($code: expr, $k: expr, $jt: expr, $jf: expr) => {
sock_filter {
code: $code as libc::c_ushort,
jt: $jt,
jf: $jf,
k: $k as libc::c_uint,
}
};
}
macro_rules! bpf_stmt {
($code: expr, $k: expr) => {
sock_filter {
code: $code as libc::c_ushort,
jt: 0,
jf: 0,
k: $k as libc::c_uint,
}
};
}
#[inline]
const fn nlmsg_align(len: usize) -> usize {
(len + NLMSG_ALIGNTO as usize - 1) & !(NLMSG_ALIGNTO as usize - 1)
}
#[inline]
const fn nlmsg_hdrlen() -> usize {
nlmsg_align(std::mem::size_of::<nlmsghdr>())
}
#[inline]
pub const fn nlmsg_length(len: usize) -> usize {
len + nlmsg_hdrlen()
}
#[cfg(test)]
mod tests {
use std::mem::offset_of;
use super::*;
impl PartialEq for sock_filter {
fn eq(&self, other: &Self) -> bool {
self.code == other.code
&& self.jt == other.jt
&& self.jf == other.jf
&& self.k == other.k
}
}
#[test]
fn bpf_jump_expansion() {
assert_eq!(
sock_filter {
code: 1 | 2,
jt: 3,
jf: 4,
k: 5
},
bpf_jump!(1 | 2, 5, 3, 4)
);
}
#[test]
fn bpf_stmt_expansion() {
assert_eq!(
sock_filter {
code: 1 | 2,
jt: 0,
jf: 0,
k: 3
},
bpf_stmt!(1 | 2, 3)
);
}
#[test]
fn nlmsg_length_value() {
assert_eq!(16, nlmsg_length(0));
assert_eq!(24, nlmsg_length(8));
}
#[test]
fn filter_array_macros() {
let data = [
sock_filter {
code: (BPF_JMP | BPF_JEQ | BPF_K) as libc::c_ushort,
jt: 0,
jf: 0,
k: offset_of!(nlmsghdr, nlmsg_pid) as libc::c_uint,
},
sock_filter {
code: (BPF_JMP | BPF_JEQ | BPF_K) as libc::c_ushort,
jt: 1,
jf: 0,
k: c_uint::to_be(CN_IDX_PROC),
},
];
let filter = [
bpf_stmt!(BPF_JMP | BPF_JEQ | BPF_K, offset_of!(nlmsghdr, nlmsg_pid)),
bpf_jump!(BPF_JMP | BPF_JEQ | BPF_K, c_uint::to_be(CN_IDX_PROC), 1, 0),
];
assert_eq!(data, filter);
}
}