extern crate libc;
use hwaddr::*;
use std;
type NfqueueData = *const libc::c_void;
pub struct Message {
qqh : *const libc::c_void,
nfad : NfqueueData,
id : u32,
}
#[derive(Debug)]
pub enum NfqueueError {
NoSuchAttribute,
}
#[derive(Clone)]
pub enum Verdict {
Drop,
Accept,
Stolen,
Queue,
Repeat,
Stop,
}
const NF_DROP : u32 = 0x0000;
const NF_ACCEPT : u32 = 0x0001;
const NF_STOLEN : u32 = 0x0002;
const NF_QUEUE : u32 = 0x0003;
const NF_REPEAT : u32 = 0x0004;
const NF_STOP : u32 = 0x0005;
fn u32_of_verdict(v: Verdict) -> u32 {
match v {
Verdict::Drop => NF_DROP,
Verdict::Accept => NF_ACCEPT,
Verdict::Stolen => NF_STOLEN,
Verdict::Queue => NF_QUEUE,
Verdict::Repeat => NF_REPEAT,
Verdict::Stop => NF_STOP,
}
}
pub enum XMLFormatFlags {
XmlHw,
XmlMark,
XmlDev,
XmlPhysDev,
XmlPayload,
XmlTime,
XmlAll,
}
const NFQ_XML_HW : u32 = (1 << 0);
const NFQ_XML_MARK : u32 = (1 << 1);
const NFQ_XML_DEV : u32 = (1 << 2);
const NFQ_XML_PHYSDEV : u32 = (1 << 3);
const NFQ_XML_PAYLOAD : u32 = (1 << 4);
const NFQ_XML_TIME : u32 = (1 << 5);
const NFQ_XML_ALL : u32 = (!0u32);
#[repr(C)]
struct NfMsgPacketHw {
pub hw_addrlen : u16,
pub _pad : u16,
pub hw_addr : [u8;8],
}
#[repr(C)]
pub struct NfMsgPacketHdr {
pub packet_id : u32,
pub hw_protocol : u16,
pub hook : u8,
}
#[link(name = "netfilter_queue")]
extern {
fn nfq_set_verdict2(qqh: *const libc::c_void, id: u32, verdict: u32, mark: u32, data_len: u32, data: *const libc::c_uchar);
fn nfq_get_msg_packet_hdr(nfad: NfqueueData) -> *const libc::c_void;
fn nfq_get_nfmark (nfad: NfqueueData) -> u32;
fn nfq_get_timestamp (nfad: NfqueueData, tv: *mut libc::timeval) -> u32;
fn nfq_get_indev (nfad: NfqueueData) -> u32;
fn nfq_get_physindev (nfad: NfqueueData) -> u32;
fn nfq_get_outdev (nfad: NfqueueData) -> u32;
fn nfq_get_physoutdev (nfad: NfqueueData) -> u32;
fn nfq_get_packet_hw (nfad: NfqueueData) -> *const NfMsgPacketHw;
fn nfq_get_payload (nfad: NfqueueData, data: &*mut libc::c_void) -> libc::c_int;
fn nfq_snprintf_xml (buf: *mut u8, rem: libc::size_t, tb: NfqueueData, flags: libc::c_uint) -> libc::c_int;
}
impl Message {
#[doc(hidden)]
pub fn new(qqh: *const libc::c_void, nfad: *const libc::c_void) -> Message {
let msg_hdr = unsafe { nfq_get_msg_packet_hdr(nfad) as *const NfMsgPacketHdr };
assert!(!msg_hdr.is_null());
let id = u32::from_be( unsafe{(*msg_hdr).packet_id} );
Message {
qqh : qqh,
nfad: nfad,
id : id,
}
}
pub fn get_id(&self) -> u32 {
self.id
}
pub fn get_nfmark(&self) -> u32 {
return unsafe { nfq_get_nfmark(self.nfad) };
}
pub fn get_timestamp(&self) -> Result<libc::timeval,NfqueueError> {
let mut tv = libc::timeval {
tv_sec: 0,
tv_usec: 0,
};
let rc = unsafe { nfq_get_timestamp(self.nfad,&mut tv) };
match rc {
0 => Ok(tv),
_ => Err(NfqueueError::NoSuchAttribute),
}
}
pub fn get_indev(&self) -> u32 {
return unsafe { nfq_get_indev(self.nfad) };
}
pub fn get_physindev(&self) -> u32 {
return unsafe { nfq_get_physindev(self.nfad) };
}
pub fn get_outdev(&self) -> u32 {
return unsafe { nfq_get_outdev(self.nfad) };
}
pub fn get_physoutdev(&self) -> u32 {
return unsafe { nfq_get_physoutdev(self.nfad) };
}
pub fn get_packet_hw<'a>(&'a self) -> Result<HwAddr<'a>,NfqueueError> {
let c_hw = unsafe { nfq_get_packet_hw(self.nfad) };
if c_hw == std::ptr::null() {
return Err(NfqueueError::NoSuchAttribute);
}
let c_len = u16::from_be(unsafe{(*c_hw).hw_addrlen}) as usize;
match c_len {
0 => Err(NfqueueError::NoSuchAttribute),
_ => Ok( HwAddr::new(unsafe{&((*c_hw).hw_addr)[0..c_len]})),
}
}
pub fn set_verdict(&self, verdict: Verdict) {
assert!(!self.qqh.is_null());
let c_verdict = u32_of_verdict(verdict);
unsafe { nfq_set_verdict2(self.qqh, self.id, c_verdict, 0, 0, std::ptr::null_mut()) };
}
pub fn set_verdict_mark(&self, verdict: Verdict, mark: u32) {
assert!(!self.qqh.is_null());
let c_verdict = u32_of_verdict(verdict);
unsafe { nfq_set_verdict2(self.qqh, self.id, c_verdict, mark, 0, std::ptr::null_mut()) };
}
pub fn set_verdict_full(&self, verdict: Verdict, mark: u32, data: &[u8]) {
assert!(!self.qqh.is_null());
let c_verdict = u32_of_verdict(verdict);
let data_ptr = data.as_ptr() as *const libc::c_uchar;
let data_len = data.len() as u32;
unsafe { nfq_set_verdict2(self.qqh, self.id, c_verdict, mark, data_len, data_ptr) };
}
pub fn get_payload<'a>(&'a self) -> &'a [u8] {
let c_ptr = std::ptr::null_mut();
let payload_len = unsafe { nfq_get_payload(self.nfad, &c_ptr) };
let payload : &[u8] = unsafe { std::slice::from_raw_parts(c_ptr as *mut u8, payload_len as usize) };
return payload;
}
pub fn as_xml_str(&self, flags: &[XMLFormatFlags]) -> Result<String,std::str::Utf8Error> {
let mut buf : [u8;65536] = [0;65536];
let buf_ptr = buf.as_mut_ptr() as *mut libc::c_uchar;
let buf_len = buf.len() as libc::size_t;
let xml_flags = flags.iter().map(|flag| {
match *flag {
XMLFormatFlags::XmlHw => NFQ_XML_HW,
XMLFormatFlags::XmlMark => NFQ_XML_MARK,
XMLFormatFlags::XmlDev => NFQ_XML_DEV,
XMLFormatFlags::XmlPhysDev => NFQ_XML_PHYSDEV,
XMLFormatFlags::XmlPayload => NFQ_XML_PAYLOAD,
XMLFormatFlags::XmlTime => NFQ_XML_TIME,
XMLFormatFlags::XmlAll => NFQ_XML_ALL,
}
}).fold(0u32, |acc, i| acc | i);
let rc = unsafe { nfq_snprintf_xml(buf_ptr, buf_len, self.nfad, xml_flags) };
if rc < 0 { panic!("nfq_snprintf_xml"); }
match std::str::from_utf8(&buf) {
Ok(v) => Ok(v.to_string()),
Err(e) => Err(e),
}
}
}
use std::fmt;
use std::fmt::Write;
impl fmt::Display for Message {
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
let payload_data = self.get_payload();
let mut s = String::new();
for &byte in payload_data {
write!(&mut s, "{:X} ", byte).unwrap();
}
write!(out, "{}", s)
}
}