extern crate libc;
pub use hwaddr::*;
mod hwaddr;
pub use message::*;
mod message;
type NflogHandle = *const libc::c_void;
type NflogGroupHandle = *const libc::c_void;
pub type NflogCallback = fn (&Message) -> ();
type NflogCCallback = extern "C" fn (*const libc::c_void, *const libc::c_void, *const libc::c_void, *const libc::c_void );
#[link(name = "netfilter_log")]
extern {
fn nflog_open() -> NflogHandle;
fn nflog_close(qh: NflogHandle);
fn nflog_bind_pf (qh: NflogHandle, pf: libc::c_int) -> libc::c_int;
fn nflog_unbind_pf (qh: NflogHandle, pf: libc::c_int) -> libc::c_int;
fn nflog_fd (h: NflogHandle) -> libc::c_int;
fn nflog_bind_group (qh: NflogHandle, num: u16) -> NflogGroupHandle;
fn nflog_unbind_group (gh: NflogGroupHandle) -> libc::c_int;
fn nflog_set_mode (gh: NflogGroupHandle, mode: u8, range: u32) -> libc::c_int;
fn nflog_set_timeout (gh: NflogGroupHandle, timeout: u32) -> libc::c_int;
fn nflog_set_qthresh (gh: NflogGroupHandle, qthresh: u32) -> libc::c_int;
fn nflog_set_nlbufsiz (gh: NflogGroupHandle, nlbufsiz: u32) -> libc::c_int;
fn nflog_set_flags (gh: NflogGroupHandle, flags: u16) -> libc::c_int;
fn nflog_callback_register(gh: NflogGroupHandle, cb: NflogCCallback, data: *mut libc::c_void);
fn nflog_handle_packet(qh: NflogHandle, buf: *mut libc::c_void, rc: libc::c_int) -> libc::c_int;
}
pub enum CopyMode {
CopyNone,
CopyMeta,
CopyPacket,
}
const NFULNL_COPY_NONE : u8 = 0x00;
const NFULNL_COPY_META : u8 = 0x01;
const NFULNL_COPY_PACKET : u8 = 0x02;
pub enum CfgFlags {
CfgFlagsSeq,
CfgFlagsSeqGlobal,
}
const NFULNL_CFG_F_SEQ : u16 = 0x0001;
const NFULNL_CFG_F_SEQ_GLOBAL : u16 = 0x0001;
pub struct Queue {
qh : NflogHandle,
gh : NflogGroupHandle,
cb : Option<NflogCallback>,
}
impl Queue {
pub fn new() -> Queue {
return Queue {
qh : std::ptr::null_mut(),
gh : std::ptr::null_mut(),
cb: None,
};
}
pub fn open(&mut self) {
self.qh = unsafe { nflog_open() };
}
pub fn close(&mut self) {
assert!(!self.qh.is_null());
unsafe { nflog_close(self.qh) };
self.qh = std::ptr::null_mut();
}
pub fn bind(&self, pf: libc::c_int) -> i32 {
assert!(!self.qh.is_null());
return unsafe { nflog_bind_pf(self.qh,pf) };
}
pub fn unbind(&self, pf: libc::c_int) -> i32 {
assert!(!self.qh.is_null());
return unsafe { nflog_unbind_pf(self.qh,pf) }
}
pub fn fd(&self) -> i32 {
assert!(!self.qh.is_null());
return unsafe { nflog_fd(self.qh) }
}
pub fn bind_group(&mut self, num: u16) {
assert!(!self.qh.is_null());
self.gh = unsafe { nflog_bind_group(self.qh,num) }
}
pub fn unbind_group(&mut self) {
assert!(!self.gh.is_null());
unsafe { nflog_unbind_group(self.gh); }
self.gh = std::ptr::null_mut();
}
pub fn set_mode(&self, mode: CopyMode, range: u32) {
assert!(!self.gh.is_null());
let c_mode = match mode {
CopyMode::CopyNone => NFULNL_COPY_NONE,
CopyMode::CopyMeta => NFULNL_COPY_META,
CopyMode::CopyPacket => NFULNL_COPY_PACKET,
};
unsafe { nflog_set_mode(self.gh, c_mode, range); }
}
pub fn set_timeout(&self, timeout: u32) {
assert!(!self.gh.is_null());
unsafe { nflog_set_timeout(self.gh, timeout); }
}
pub fn set_qthresh(&self, qthresh: u32) {
assert!(!self.gh.is_null());
unsafe { nflog_set_qthresh(self.gh, qthresh); }
}
pub fn set_nlbufsiz(&self, nlbufsiz: u32) {
assert!(!self.gh.is_null());
unsafe { nflog_set_nlbufsiz(self.gh, nlbufsiz); }
}
pub fn set_flags(&self, flags: CfgFlags) {
assert!(!self.gh.is_null());
let c_flags : u16 = match flags {
CfgFlags::CfgFlagsSeq => NFULNL_CFG_F_SEQ,
CfgFlags::CfgFlagsSeqGlobal => NFULNL_CFG_F_SEQ_GLOBAL,
};
unsafe { nflog_set_flags(self.gh, c_flags); }
}
pub fn set_callback(&mut self, cb: NflogCallback) {
self.cb = Some(cb);
let self_ptr = unsafe { std::mem::transmute(&*self) };
unsafe { nflog_callback_register(self.gh, real_callback, self_ptr); };
}
pub fn run_loop(&self) {
assert!(!self.gh.is_null());
let fd = self.fd();
let mut buf : [u8;65536] = [0;65536];
let buf_ptr = buf.as_mut_ptr() as *mut libc::c_void;
let buf_len = buf.len() as libc::size_t;
loop {
let rc = unsafe { libc::recv(fd,buf_ptr,buf_len,0) };
if rc < 0 { panic!("error in recv()"); };
let rv = unsafe { nflog_handle_packet(self.qh, buf_ptr, rc as libc::c_int) };
if rv < 0 { println!("error in nflog_handle_packet()"); }; }
}
}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn real_callback(_g: *const libc::c_void, _nfmsg: *const libc::c_void, nfad: *const libc::c_void, data: *const libc::c_void ) {
let raw : *mut Queue = unsafe { std::mem::transmute(data) };
let ref mut q = unsafe { &*raw };
let mut msg = Message::new (nfad);
match q.cb {
None => panic!("no callback registered"),
Some(callback) => {
callback(&mut msg);
},
}
}
#[cfg(test)]
mod tests {
extern crate libc;
#[test]
fn nflog_open() {
let mut q = ::Queue::new();
q.open();
let raw = q.qh as *const i32;
println!("nfq_open: 0x{:x}", unsafe{*raw});
assert!(!q.qh.is_null());
q.close();
}
#[test]
#[ignore]
fn nflog_bind() {
let mut q = ::Queue::new();
q.open();
let raw = q.qh as *const i32;
println!("nfq_open: 0x{:x}", unsafe{*raw});
assert!(!q.qh.is_null());
let rc = q.bind(libc::AF_INET);
println!("q.bind: {}", rc);
assert!(q.bind(libc::AF_INET) == 0);
q.close();
}
}