forked from lclarkmichalek/libnetfilter_queue
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathmod.rs
More file actions
171 lines (147 loc) · 5.36 KB
/
mod.rs
File metadata and controls
171 lines (147 loc) · 5.36 KB
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! Queue handling
//!
//! The queue handle and callback,
//! analagous to <http://netfilter.org/projects/libnetfilter_queue/doxygen/group__Queue.html>
mod verdict;
use libc::*;
use std::mem;
use std::ptr::null;
use error::*;
use util::*;
use message::{Message, Payload};
pub use self::verdict::{Verdict, QueueHandle};
use lock::NFQ_LOCK as LOCK;
use ffi::*;
const NFQNL_COPY_NONE: u8 = 0;
const NFQNL_COPY_META: u8 = 1;
const NFQNL_COPY_PACKET: u8 = 2;
/// The amount of data to be copied to userspace for each packet queued.
pub enum CopyMode {
/// None
None,
/// Packet metadata only
Metadata,
/// If you copy the packet, you must also specify the size of the packet to copy
Packet(u16)
}
extern fn queue_callback<F: PacketHandler>(qh: *mut nfq_q_handle,
nfmsg: *mut nfgenmsg,
nfad: *mut nfq_data,
cdata: *mut c_void) -> c_int {
let queue_ptr: *mut Queue<F> = unsafe { mem::transmute(cdata) };
let queue: &mut Queue<F> = unsafe { as_mut(&queue_ptr).unwrap() };
let message = Message::new(nfmsg, nfad);
queue.callback.handle(QueueHandle::new(qh), message.as_ref()) as c_int
}
/// A handle to an NFQueue queue and its data.
///
/// This is used to set queue-specific settings, such as copy-mode and max-length.
/// It is bundled with callback metadata specific to this instance,
/// making it fatter than `QueueHandle`.
///
/// `QueueHandle` should be used within packet-handling for `Sync` operations.
pub struct Queue<F: PacketHandler> {
ptr: *mut nfq_q_handle,
callback: F
}
impl<F: PacketHandler> Drop for Queue<F> {
fn drop(&mut self) {
let ret = unsafe { nfq_destroy_queue(self.ptr) };
if ret != 0 {
panic!("Failed to destroy nfq queue");
}
}
}
impl<F: PacketHandler> Queue<F> {
#[doc(hidden)]
pub fn new(handle: *mut nfq_handle,
queue_number: u16,
packet_handler: F) -> Result<Box<Queue<F>>, Error> {
let _lock = LOCK.lock().unwrap();
let nfq_ptr: *const nfq_q_handle = null();
let mut queue: Box<Queue<F>> = Box::new(Queue {
ptr: nfq_ptr as *mut nfq_q_handle, // set after nfq_create_queue
callback: packet_handler,
});
let queue_ptr: *mut Queue<F> = &mut *queue;
let ptr = unsafe {
nfq_create_queue(handle,
queue_number,
queue_callback::<F>,
mem::transmute(queue_ptr))
};
if ptr.is_null() {
return Err(error(Reason::CreateQueue, "Failed to create queue", None));
} else {
queue.ptr = ptr;
}
Ok(queue)
}
/// Set the copy-mode for this queue
pub fn set_mode(&mut self, mode: CopyMode) -> Result<(), Error> {
let copy_mode = match mode {
CopyMode::None => NFQNL_COPY_NONE,
CopyMode::Metadata => NFQNL_COPY_META,
CopyMode::Packet(_) => NFQNL_COPY_PACKET
};
let range = match mode {
CopyMode::Packet(r) => r,
_ => 0
} as u32;
let res = unsafe { nfq_set_mode(self.ptr, copy_mode, range) };
if res != 0 {
Err(error(Reason::SetQueueMode, "Failed to set queue mode", Some(res)))
} else {
Ok(())
}
}
/// Set the copy-mode to Packet for the size of the given struct
///
/// This fn behaves like `set_mode` except that packet size is determined by the size of the type, `P`.
/// For example, to copy enough to parse `IPHeader`, use `set_mode_sized::<IPHeader>()`.
pub fn set_mode_sized<P: Payload>(&mut self) -> Result<(), Error> {
let bytes = mem::size_of::<P>() as u16;
self.set_mode(CopyMode::Packet(bytes * 8))
}
/// Set the max-length for this queue
///
/// Once `length` packets are enqueued, packets will be dropped until enqueued packets are processed.
pub fn set_max_length(&mut self, length: u32) -> Result<(), Error> {
let res = unsafe { nfq_set_queue_maxlen(self.ptr, length) };
if res != 0 {
Err(error(Reason::SetQueueMaxlen, "Failed to set queue maxlen", Some(res)))
} else {
Ok(())
}
}
}
/// Invoked to handle packets from the queue
pub trait PacketHandler {
/// Handle a packet from the queue
///
/// `Verdict`s must be set using the `set_verdict` fn.
fn handle(&mut self, hq: QueueHandle, message: Result<&Message, &Error>) -> i32;
}
/// An abstraction over `PacketHandler` for simple handling that needs only a `Verdict`
pub trait VerdictHandler {
/// Handle a packet from the queue
///
/// Only properly formed `Message`s will be passed to this fn.
fn decide(&mut self, message: &Message) -> Verdict;
}
#[allow(non_snake_case)]
impl<V> PacketHandler for V where V: VerdictHandler {
fn handle(&mut self, hq: QueueHandle, message: Result<&Message, &Error>) -> i32 {
let NULL: *const c_uchar = null();
match message {
Ok(m) => { let _ = Verdict::set_verdict(hq, m.header.id(), self.decide(m), 0, NULL); },
Err(_) => ()
}
0
}
}
impl<F> VerdictHandler for F where F: FnMut(&Message) -> Verdict {
fn decide(&mut self, message: &Message) -> Verdict {
self(message)
}
}