Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ name = "nfqueue"
version = "0.9.1"
authors = [ "Pierre Chifflier <[email protected]>" ]

build = "src/generation/generate_bindings.rs"

[build-dependencies]
bindgen = "^0.26"

[dependencies]
libc = "^0.2"

[dev_dependencies]
[dev-dependencies]
pnet = "0.17.1"
17 changes: 7 additions & 10 deletions examples/nfq-example.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extern crate nfqueue;
extern crate libc;
extern crate nfqueue;

struct State {
count: u32,
Expand All @@ -11,7 +11,7 @@ impl State {
}
}

fn queue_callback(msg: &nfqueue::Message, state:&mut State) {
fn queue_callback(msg: nfqueue::Message, state:&mut State) -> i32 {
println!("Packet received [id: 0x{:x}]\n", msg.get_id());

println!(" -> msg: {}", msg);
Expand All @@ -21,27 +21,24 @@ fn queue_callback(msg: &nfqueue::Message, state:&mut State) {
state.count += 1;
println!("count: {}", state.count);

msg.set_verdict(nfqueue::Verdict::Accept);
msg.set_verdict(nfqueue::Verdict::Accept)
}

fn main() {
let mut q = nfqueue::Queue::new(State::new());
println!("nfqueue example program: print packets metadata and accept packets");

q.open();
q.unbind(libc::AF_INET); // ignore result, failure is not critical here
let protocol_family = libc::AF_INET as u16;

q.open();
q.unbind(protocol_family); // ignore result, failure is not critical here

let rc = q.bind(libc::AF_INET);
let rc = q.bind(protocol_family);
assert!(rc == 0);

q.create_queue(0, queue_callback);
q.set_mode(nfqueue::CopyMode::CopyPacket, 0xffff);


q.run_loop();



q.close();
}
17 changes: 7 additions & 10 deletions examples/nfq-parse.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Some code borrowed from https://github.com/libpnet/libpnet/blob/master/examples/packetdump.rs

extern crate nfqueue;
extern crate libc;
extern crate nfqueue;

use std::net::IpAddr;

Expand Down Expand Up @@ -134,7 +134,7 @@ fn handle_transport_protocol(id: u32, source: IpAddr, destination: IpAddr, proto
}
}

fn queue_callback(msg: &nfqueue::Message, state: &mut State) {
fn queue_callback(msg: nfqueue::Message, state: &mut State) -> i32 {
println!("\n---");
println!("Packet received [id: 0x{:x}]\n", msg.get_id());

Expand All @@ -153,27 +153,24 @@ fn queue_callback(msg: &nfqueue::Message, state: &mut State) {
None => println!("Malformed IPv4 packet"),
}

msg.set_verdict(nfqueue::Verdict::Accept);
msg.set_verdict(nfqueue::Verdict::Accept)
}

fn main() {
let mut q = nfqueue::Queue::new(State::new());
println!("nfqueue example program: parse packet protocol layers and accept packet");

q.open();
q.unbind(libc::AF_INET); // ignore result, failure is not critical here
let protocol_family = libc::AF_INET as u16;

q.open();
q.unbind(protocol_family); // ignore result, failure is not critical here

let rc = q.bind(libc::AF_INET);
let rc = q.bind(protocol_family);
assert!(rc == 0);

q.create_queue(0, queue_callback);
q.set_mode(nfqueue::CopyMode::CopyPacket, 0xffff);


q.run_loop();



q.close();
}
5 changes: 5 additions & 0 deletions src/bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
27 changes: 27 additions & 0 deletions src/generation/generate_bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {

// Tell cargo to tell rustc to link the netfilter_queue shared library
println!("cargo:rustc-link-lib=netfilter_queue");

let bindings = bindgen::Builder::default()
.header("src/generation/wrapper.h")
// White listings became necessary as I needed to included <stdint> in wrapper.h to
// define the default integer types like uint32_t. I think I miss something but I
// couldn't grab it.
.whitelisted_type("(nfq|NFQ)_.*")
.whitelisted_function("(nfq|NFQ)_.*")
.whitelisted_var("(nfq|NFQ)_.*")
.constified_enum(".*")
.generate()
.expect("Unable to generate bindings");

let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
2 changes: 2 additions & 0 deletions src/generation/wrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include <stdint.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
114 changes: 49 additions & 65 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,51 @@
//! ```rust,ignore
//! extern crate libc;
//! extern crate nfqueue;
//! use std::fmt::Write;
//!
//! fn callback(msg: &nfqueue::Message) {
//! println!(" -> msg: {}", msg);
//! struct State {
//! count: u32,
//! }
//!
//! let payload_data = msg.get_payload();
//! let mut s = String::new();
//! for &byte in payload_data {
//! write!(&mut s, "{:X} ", byte).unwrap();
//! impl State {
//! pub fn new() -> State {
//! State{ count:0 }
//! }
//! println!("{}", s);
//! }
//!
//! fn queue_callback(msg: nfqueue::Message, state:&mut State) -> i32 {
//! println!("Packet received [id: 0x{:x}]\n", msg.get_id());
//!
//! println!(" -> msg: {}", msg);
//!
//! println!("XML\n{}", msg.as_xml_str(&[nfqueue::XMLFormatFlags::XmlAll]).unwrap());
//!
//! msg.set_verdict(nfqueue::Verdict::Accept);
//! state.count += 1;
//! println!("count: {}", state.count);
//!
//! msg.set_verdict(nfqueue::Verdict::Accept)
//! }
//!
//! fn main() {
//! let mut q = nfqueue::Queue::new();
//! let mut q = nfqueue::Queue::new(State::new());
//! println!("nfqueue example program: print packets metadata and accept packets");
//!
//! let protocol_family = libc::AF_INET as u16;
//!
//! q.open();
//! q.unbind(protocol_family); // ignore result, failure is not critical here
//!
//! let rc = q.bind(libc::AF_INET);
//! let rc = q.bind(protocol_family);
//! assert!(rc == 0);
//!
//! q.create_queue(0, callback);
//! q.create_queue(0, queue_callback);
//! q.set_mode(nfqueue::CopyMode::CopyPacket, 0xffff);
//!
//! q.set_callback(callback);
//! q.run_loop();
//!
//! q.close();
//! }
//!
//! ```


extern crate libc;

pub use hwaddr::*;
Expand All @@ -62,31 +71,8 @@ mod hwaddr;
pub use message::*;
mod message;

type NfqueueHandle = *const libc::c_void;
type NfqueueQueueHandle = *const libc::c_void;

/// Prototype for the callback function, triggered when a packet is received
pub type NfqueueCallback = fn (&Message) -> ();

type NfqueueCCallback = extern "C" fn (*const libc::c_void, *const libc::c_void, *const libc::c_void, *const libc::c_void );


#[link(name = "netfilter_queue")]
extern {
// library setup
fn nfq_open() -> NfqueueHandle;
fn nfq_close(qh: NfqueueHandle);
fn nfq_bind_pf (qh: NfqueueHandle, pf: libc::c_int) -> libc::c_int;
fn nfq_unbind_pf (qh: NfqueueHandle, pf: libc::c_int) -> libc::c_int;

// queue handling
fn nfq_fd (h: NfqueueHandle) -> libc::c_int;
fn nfq_create_queue(qh: NfqueueHandle, num: u16, cb: NfqueueCCallback, data: *mut libc::c_void) -> NfqueueQueueHandle;
fn nfq_destroy_queue(qh: NfqueueHandle) -> libc::c_int;
fn nfq_handle_packet(qh: NfqueueHandle, buf: *mut libc::c_void, rc: libc::c_int) -> libc::c_int;
fn nfq_set_mode (gh: NfqueueQueueHandle, mode: u8, range: u32) -> libc::c_int;
fn nfq_set_queuelen (gh: NfqueueQueueHandle, queuelen: u32) -> libc::c_int;
}
pub use bindings::*;
mod bindings;

/// Copy modes
pub enum CopyMode {
Expand All @@ -104,9 +90,9 @@ const NFQNL_COPY_PACKET : u8 = 0x02;

/// Opaque struct `Queue`: abstracts an NFLOG queue
pub struct Queue<T> {
qh : NfqueueHandle,
qqh : NfqueueQueueHandle,
cb : Option<fn (&Message, &mut T) -> ()>,
qh : *mut nfq_handle,
qqh : *mut nfq_q_handle,
cb : Option<fn (Message, &mut T) -> i32>,
data: T,
}

Expand Down Expand Up @@ -154,7 +140,7 @@ impl <T: Send> Queue<T> {
/// Remarks:
///
/// **Requires root privileges**
pub fn bind(&self, pf: libc::c_int) -> i32 {
pub fn bind(&self, pf: libc::c_ushort) -> i32 {
assert!(!self.qh.is_null());
return unsafe { nfq_bind_pf(self.qh,pf) };
}
Expand All @@ -171,7 +157,7 @@ impl <T: Send> Queue<T> {
/// Remarks:
///
/// **Requires root privileges**
pub fn unbind(&self, pf: libc::c_int) -> i32 {
pub fn unbind(&self, pf: libc::c_ushort) -> i32 {
assert!(!self.qh.is_null());
return unsafe { nfq_unbind_pf(self.qh,pf) }
}
Expand All @@ -197,12 +183,14 @@ impl <T: Send> Queue<T> {
///
/// * `num`: the number of the queue to bind to
/// * `cb`: callback function to call for each queued packet
pub fn create_queue(&mut self, num: u16, cb: fn(&Message, &mut T)) {
pub fn create_queue(&mut self, num: u16, cb: fn(Message, &mut T) -> i32) -> bool {
assert!(!self.qh.is_null());
assert!(self.qqh.is_null());
let self_ptr = unsafe { std::mem::transmute(&*self) };
self.cb = Some(cb);
self.qqh = unsafe { nfq_create_queue(self.qh, num, real_callback::<T>, self_ptr) };
self.qqh = unsafe { nfq_create_queue(self.qh, num, Some(real_callback::<T>), self_ptr) };

!self.qqh.is_null()
}

/// Destroys a group handle
Expand Down Expand Up @@ -247,9 +235,9 @@ impl <T: Send> Queue<T> {
/// Sets the size of the queue in kernel. This fixes the maximum number of
/// packets the kernel will store before internally before dropping upcoming
/// packets
pub fn set_queuelen(&self, queuelen: u32) {
pub fn set_queue_maxlen(&self, queuelen: u32) -> i32 {
assert!(!self.qqh.is_null());
unsafe { nfq_set_queuelen(self.qqh, queuelen); }
unsafe { nfq_set_queue_maxlen(self.qqh, queuelen) }
}

/// Runs an infinite loop, waiting for packets and triggering the callback.
Expand All @@ -260,11 +248,11 @@ impl <T: Send> Queue<T> {

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_ptr = buf.as_mut_ptr() as *mut libc::c_char;
let buf_len = buf.len() as libc::size_t;

loop {
let rc = unsafe { libc::recv(fd,buf_ptr,buf_len,0) };
let rc = unsafe { libc::recv(fd, buf_ptr as *mut libc::c_void, buf_len, 0) };
if rc < 0 { panic!("error in recv()"); };

let rv = unsafe { nfq_handle_packet(self.qh, buf_ptr, rc as libc::c_int) };
Expand All @@ -274,30 +262,21 @@ impl <T: Send> Queue<T> {

}



#[doc(hidden)]
extern "C" fn real_callback<T>(qqh: *const libc::c_void, _nfmsg: *const libc::c_void, nfad: *const libc::c_void, data: *const libc::c_void ) {
extern "C" fn real_callback<T>(qqh: *mut nfq_q_handle, _nfmsg: *mut nfgenmsg, nfad: *mut nfq_data, data: *mut std::os::raw::c_void) -> i32 {
let raw : *mut Queue<T> = unsafe { std::mem::transmute(data) };

let ref mut q = unsafe { &mut *raw };
let mut msg = Message::new (qqh, nfad);
let msg = Message::new (qqh, nfad);

match q.cb {
None => panic!("no callback registered"),
Some(callback) => {
callback(&mut msg, &mut q.data);
callback(msg, &mut q.data)
},
}
}








#[cfg(test)]
mod tests {

Expand All @@ -317,6 +296,9 @@ mod tests {
q.close();
}

// Can't run this test by default as we do should not have enough rights.
// You need to enable it manually to run it via `cargo test` after you ensured that the program
// will have the right capabilities.
#[test]
#[ignore]
fn nfqueue_bind() {
Expand All @@ -329,9 +311,11 @@ mod tests {

assert!(!q.qh.is_null());

let rc = q.bind(libc::AF_INET);
let protocol_family = libc::AF_INET as u16;
let rc = q.bind(protocol_family);

println!("q.bind: {}", rc);
assert!(q.bind(libc::AF_INET) == 0);
assert!(q.bind(protocol_family) == 0);

q.close();
}
Expand Down
Loading