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()),
    }
}