use std::os::fd::BorrowedFd;
use crate::config::BpfFilter;
use crate::error::Error;
use crate::sockopt::raw_setsockopt;
const BPF_MAXINSNS: usize = 4096;
pub(crate) fn attach_bpf_filter(fd: BorrowedFd<'_>, filter: &BpfFilter) -> Result<(), Error> {
if filter.is_empty() {
return Err(Error::Config("BPF filter has no instructions".into()));
}
if filter.len() > BPF_MAXINSNS {
return Err(Error::Config(format!(
"BPF filter has {} instructions (max {})",
filter.len(),
BPF_MAXINSNS
)));
}
let prog = libc::sock_fprog {
len: filter.len() as u16,
filter: filter.instructions().as_ptr() as *mut libc::sock_filter,
};
raw_setsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_ATTACH_FILTER,
&prog,
"SO_ATTACH_FILTER",
)
}
pub(crate) fn attach_ebpf_socket_filter(
sock: BorrowedFd<'_>,
prog: BorrowedFd<'_>,
) -> Result<(), Error> {
use std::os::fd::AsRawFd;
let prog_raw: libc::c_int = prog.as_raw_fd();
raw_setsockopt(
sock,
libc::SOL_SOCKET,
libc::SO_ATTACH_BPF,
&prog_raw,
"SO_ATTACH_BPF",
)
}
pub(crate) fn detach_bpf_filter(fd: BorrowedFd<'_>) -> Result<(), Error> {
let val: libc::c_int = 0;
raw_setsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_DETACH_FILTER,
&val,
"SO_DETACH_FILTER",
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::BpfInsn;
#[test]
fn empty_filter_rejected() {
let filter = BpfFilter::new(vec![]);
assert!(filter.is_empty());
}
#[test]
fn oversized_filter_rejected() {
let insns: Vec<BpfInsn> = (0..BPF_MAXINSNS + 1)
.map(|_| BpfInsn {
code: 0x06,
jt: 0,
jf: 0,
k: 0,
})
.collect();
let filter = BpfFilter::new(insns);
assert!(filter.len() > BPF_MAXINSNS);
}
}