1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
use libc::{c_int, c_ushort, c_void, setsockopt, socklen_t, SOL_SOCKET}; use std::io::Error; use std::mem::{forget, size_of_val}; use std::os::unix::io::RawFd; use std::ptr::null; #[repr(C)] #[derive(Debug)] pub struct Op { code: u16, jt: u8, jf: u8, k: u32, } impl Op { pub fn new(code: u16, jt: u8, jf: u8, k: u32) -> Op { Op { code: code, jt: jt, jf: jf, k: k, } } } #[repr(C)] #[derive(Debug)] pub struct Prog { len: c_ushort, filter: *mut Op, } impl Prog { pub fn new(ops: Vec<Op>) -> Prog { let mut ops = ops.into_boxed_slice(); let len = ops.len(); let ptr = ops.as_mut_ptr(); forget(ops); Prog { len: len as _, filter: ptr, } } } impl Drop for Prog { fn drop(&mut self) { unsafe { let len = self.len as usize; let ptr = self.filter; Vec::from_raw_parts(ptr, len, len); } } } const SO_ATTACH_FILTER: c_int = 26; const SO_DETACH_FILTER: c_int = 27; const SO_LOCK_FILTER: c_int = 44; #[macro_export] macro_rules! bpfprog { ($count:expr, $($code:tt $jt:tt $jf:tt $k:tt),*) => { { let mut ops = Vec::with_capacity($count); $(ops.push(bpf::Op::new($code, $jt, $jf, $k));)* bpf::Prog::new(ops) } } } pub fn attach_filter(fd: RawFd, prog: Prog) -> Result<(), Error> { match unsafe { setsockopt( fd as c_int, SOL_SOCKET, SO_ATTACH_FILTER, &prog as *const _ as *const c_void, size_of_val(&prog) as socklen_t, ) } { 0 => Ok(()), _ => Err(Error::last_os_error()), } } pub fn detach_filter(fd: RawFd) -> Result<(), Error> { match unsafe { setsockopt(fd as c_int, SOL_SOCKET, SO_DETACH_FILTER, null(), 0) } { 0 => Ok(()), _ => Err(Error::last_os_error()), } } pub fn lock_filter(fd: RawFd) -> Result<(), Error> { let one: c_int = 1; match unsafe { setsockopt( fd as c_int, SOL_SOCKET, SO_LOCK_FILTER, &one as *const _ as *const c_void, size_of_val(&one) as socklen_t, ) } { 0 => Ok(()), _ => Err(Error::last_os_error()), } }