forked from lclarkmichalek/libnetfilter_queue
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathhandle.rs
More file actions
133 lines (118 loc) · 4.23 KB
/
handle.rs
File metadata and controls
133 lines (118 loc) · 4.23 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
//! The handle into NFQueue for library setup.
//!
//! Analagous to <http://netfilter.org/projects/libnetfilter_queue/doxygen/group__LibrarySetup.html>
use libc::*;
use std::mem;
use error;
use error::*;
use queue::{Queue, PacketHandler};
use message::Payload;
use lock::NFQ_LOCK as LOCK;
use errno::errno;
use ffi::*;
/// Protocol Family
///
/// NFQueue will only deal with IP, so only those families are made available.
#[derive(Clone,Copy)]
pub enum ProtocolFamily {
/// IPv4 Address Family
INET = AF_INET as isize,
/// IPv6 Address Family
INET6 = AF_INET6 as isize
}
/// A handle into NFQueue
///
/// This is needed for library setup.
pub struct Handle {
ptr: *mut nfq_handle
}
impl Drop for Handle {
fn drop(&mut self) {
let ret = unsafe { nfq_close(self.ptr) };
if ret != 0 {
panic!("Failed to close NFQHandle");
}
}
}
impl Handle {
/// Open a new handle to NFQueue
///
/// This tells the kernel that userspace queuing will be handled for the selected protocol.
pub fn new() -> Result<Handle, Error> {
let _lock = LOCK.lock().unwrap();
let ptr = unsafe { nfq_open() };
if ptr.is_null() {
Err(error(Reason::OpenHandle, "Failed to allocate handle", None))
} else {
Ok(Handle{ ptr: ptr })
}
}
/// Bind the handle to a `ProtocolFamily`
pub fn bind(&mut self, proto: ProtocolFamily) -> Result<(), Error> {
let _lock = LOCK.lock().unwrap();
unsafe { nfq_unbind_pf(self.ptr, proto as u16) };
let res = unsafe { nfq_bind_pf(self.ptr, proto as u16) };
if res < 0 {
Err(error(Reason::Bind, "Failed to bind handle", Some(res)))
} else {
Ok(())
}
}
/// Unbind the handle from a `ProtocolFamily`
///
/// This should usually be avoided, as it may attach other programs from the `ProtocolFamily`.
pub fn unbind(&mut self, proto: ProtocolFamily) -> Result<(), Error> {
let _lock = LOCK.lock().unwrap();
let res = unsafe { nfq_unbind_pf(self.ptr, proto as u16) };
if res < 0 {
Err(error(Reason::Unbind, "Failed to unbind handle", Some(res)))
} else {
Ok(())
}
}
/// Create a new Queue
pub fn queue<F: PacketHandler>(&mut self,
queue_number: u16,
handler: F) -> Result<Box<Queue<F>>, Error> {
Queue::new(self.ptr, queue_number, handler)
}
/// Start listening using any attached queues
///
/// This will only listen on queues attached with `queue_builder`.
/// `length` determines the amount of a packet to grab from the queue at a time, in bits.
/// If you are using `queue::Queue::CopyMode(SIZE)` it must match `SIZE`.
pub fn start(&mut self, length: u16) -> Result<(), Error> {
unsafe {
// TODO: Get rid of malloc
let buffer: *mut c_void = malloc(length as usize);
if buffer.is_null() {
panic!("Failed to allocate packet buffer");
}
let fd = nfq_fd(self.ptr);
loop {
match recv(fd, buffer, length as usize, 0) {
rv if rv >=0 => {
nfq_handle_packet(self.ptr, buffer as *mut c_char, length as i32);
},
_ => {
free(buffer as *mut c_void);
let e = errno();
// trim() because as_str() is unstable
let err = error::error(error::Reason::GetPayload, format!("{}", e).trim(), Some(e.0 as i32));
return Err(err)
}
}
}
}
}
/// Start listening using any attached queues
///
/// This will only listen on queues attached with `queue_builder`.
/// This fn behaves like `start` except that `length` is determined by the size_of the type, `P`.
/// For example, to parse `IPHeader`, use `start_sized<IPHeader>()`.
pub fn start_sized<P: Payload>(&mut self) -> Result<(), Error> {
let bytes = mem::size_of::<P>() as u16;
// netlink header (128 bits) + payload
self.start(128 + bytes * 8)
}
}