nflog/lib.rs
1//! Netfilter NFLOG high-level bindings
2//!
3//! libnetfilter_log is a userspace library providing interface to packets that
4//! have been logged by the kernel packet filter. It is is part of a system that
5//! deprecates the old syslog/dmesg based packet logging.
6//!
7//! libnetfilter_log homepage is: http://netfilter.org/projects/libnetfilter_log/
8//!
9//! **Using NFLOG requires root privileges, or the `CAP_NET_ADMIN` capability**
10//!
11//! The code is available on [Github](https://github.com/chifflier/nflog-rs)
12//!
13//! # Example
14//!
15//! ```rust,ignore
16//! extern crate libc;
17//! extern crate nflog;
18//! use std::fmt::Write;
19//!
20//! fn callback(msg: &nflog::Message) {
21//! println!(" -> msg: {}", msg);
22//! // this will send an error if there is no uid (for ex. incoming packets)
23//! println!(" -> uid: {}, gid: {}", msg.get_uid().unwrap(), msg.get_gid().unwrap());
24//! println!(" -> prefix: {}", msg.get_prefix().unwrap());
25//! println!(" -> seq: {}", msg.get_seq().unwrap_or(0xffff));
26//!
27//! let payload_data = msg.get_payload();
28//! let mut s = String::new();
29//! for &byte in payload_data {
30//! write!(&mut s, "{:X} ", byte).unwrap();
31//! }
32//! println!("{}", s);
33//!
34//! println!("XML\n{}", msg.as_xml_str(&[nflog::XMLFormatFlags::XmlAll]).unwrap());
35//!
36//! }
37//!
38//! fn main() {
39//! let mut q = nflog::Queue::new();
40//!
41//! q.open();
42//!
43//! let rc = q.bind(libc::AF_INET);
44//! assert!(rc == 0);
45//!
46//! q.bind_group(0);
47//!
48//! q.set_mode(nflog::CopyMode::CopyPacket, 0xffff);
49//! q.set_flags(nflog::CfgFlags::CfgFlagsSeq);
50//!
51//! q.set_callback(callback);
52//! q.run_loop();
53//!
54//! q.close();
55//! }
56//! ```
57
58
59extern crate libc;
60
61pub use hwaddr::*;
62mod hwaddr;
63
64pub use message::*;
65mod message;
66
67type NflogHandle = *const libc::c_void;
68type NflogGroupHandle = *const libc::c_void;
69
70/// Prototype for the callback function, triggered when a packet is received
71pub type NflogCallback = fn (&Message) -> ();
72
73type NflogCCallback = extern "C" fn (*const libc::c_void, *const libc::c_void, *const libc::c_void, *const libc::c_void );
74
75#[link(name = "netfilter_log")]
76extern {
77 // library setup
78 fn nflog_open() -> NflogHandle;
79 fn nflog_close(qh: NflogHandle);
80 fn nflog_bind_pf (qh: NflogHandle, pf: libc::c_int) -> libc::c_int;
81 fn nflog_unbind_pf (qh: NflogHandle, pf: libc::c_int) -> libc::c_int;
82
83 // group handling
84 fn nflog_fd (h: NflogHandle) -> libc::c_int;
85 fn nflog_bind_group (qh: NflogHandle, num: u16) -> NflogGroupHandle;
86 fn nflog_unbind_group (gh: NflogGroupHandle) -> libc::c_int;
87 fn nflog_set_mode (gh: NflogGroupHandle, mode: u8, range: u32) -> libc::c_int;
88 fn nflog_set_timeout (gh: NflogGroupHandle, timeout: u32) -> libc::c_int;
89 fn nflog_set_qthresh (gh: NflogGroupHandle, qthresh: u32) -> libc::c_int;
90 fn nflog_set_nlbufsiz (gh: NflogGroupHandle, nlbufsiz: u32) -> libc::c_int;
91 fn nflog_set_flags (gh: NflogGroupHandle, flags: u16) -> libc::c_int;
92
93 // callback-related functions
94 fn nflog_callback_register(gh: NflogGroupHandle, cb: NflogCCallback, data: *mut libc::c_void);
95 fn nflog_handle_packet(qh: NflogHandle, buf: *mut libc::c_void, rc: libc::c_int) -> libc::c_int;
96}
97
98
99
100
101/// Copy modes
102pub enum CopyMode {
103 /// Do not copy packet contents nor metadata
104 CopyNone,
105 /// Copy only packet metadata, not payload
106 CopyMeta,
107 /// Copy packet metadata and not payload
108 CopyPacket,
109}
110const NFULNL_COPY_NONE : u8 = 0x00;
111const NFULNL_COPY_META : u8 = 0x01;
112const NFULNL_COPY_PACKET : u8 = 0x02;
113
114/// Configuration Flags
115pub enum CfgFlags {
116 CfgFlagsSeq,
117 CfgFlagsSeqGlobal,
118}
119const NFULNL_CFG_F_SEQ : u16 = 0x0001;
120const NFULNL_CFG_F_SEQ_GLOBAL : u16 = 0x0001;
121
122
123/// Opaque struct `Queue`: abstracts an NFLOG queue
124pub struct Queue {
125 qh : NflogHandle,
126 gh : NflogGroupHandle,
127 cb : Option<NflogCallback>,
128}
129
130
131impl Queue {
132 /// Creates a new, uninitialized, `Queue`.
133 pub fn new() -> Queue {
134 return Queue {
135 qh : std::ptr::null_mut(),
136 gh : std::ptr::null_mut(),
137 cb: None,
138 };
139 }
140
141 /// Opens a NFLOG handler
142 ///
143 /// This function obtains a netfilter log connection handle. When you are
144 /// finished with the handle returned by this function, you should destroy it
145 /// by calling `close()`.
146 /// A new netlink connection is obtained internally
147 /// and associated with the log connection handle returned.
148 pub fn open(&mut self) {
149 self.qh = unsafe { nflog_open() };
150 }
151
152 /// Closes a NFLOG handler
153 ///
154 /// This function closes the nflog handler and free associated resources.
155 pub fn close(&mut self) {
156 assert!(!self.qh.is_null());
157 unsafe { nflog_close(self.qh) };
158 self.qh = std::ptr::null_mut();
159 }
160
161 /// Bind a nflog handler to a given protocol family
162 ///
163 /// Binds the given log connection handle to process packets belonging to
164 /// the given protocol family (ie. `PF_INET`, `PF_INET6`, etc).
165 ///
166 /// Arguments
167 ///
168 /// * `pf` - Protocol family (usually `AF_INET` or `AF_INET6`)
169 ///
170 /// Remarks:
171 ///
172 /// **Requires root privileges**
173 pub fn bind(&self, pf: libc::c_int) -> i32 {
174 assert!(!self.qh.is_null());
175 return unsafe { nflog_bind_pf(self.qh,pf) };
176 }
177
178 /// Unbinds the nflog handler from a protocol family
179 ///
180 /// Unbinds the given nflog handle from processing packets belonging to the
181 /// given protocol family.
182 ///
183 /// Arguments
184 ///
185 /// * `pf` - Protocol family (usually `AF_INET` or `AF_INET6`)
186 ///
187 /// Remarks:
188 ///
189 /// **Requires root privileges**
190 pub fn unbind(&self, pf: libc::c_int) -> i32 {
191 assert!(!self.qh.is_null());
192 return unsafe { nflog_unbind_pf(self.qh,pf) }
193 }
194
195 /// Returns the C file descriptor associated with the nflog handler
196 ///
197 /// This function returns a file descriptor that can be used for
198 /// communication over the netlink connection associated with the given log
199 /// connection handle.
200 pub fn fd(&self) -> i32 {
201 assert!(!self.qh.is_null());
202 return unsafe { nflog_fd(self.qh) }
203 }
204
205 /// Binds a new handle to a specific group number.
206 ///
207 /// Arguments:
208 ///
209 /// * `num` - The number of the group to bind to
210 pub fn bind_group(&mut self, num: u16) {
211 assert!(!self.qh.is_null());
212 self.gh = unsafe { nflog_bind_group(self.qh,num) }
213 }
214
215 /// Unbinds a group handle
216 ///
217 /// Arguments:
218 ///
219 /// * `num` - The number of the group to unbind to
220 pub fn unbind_group(&mut self) {
221 assert!(!self.gh.is_null());
222 unsafe { nflog_unbind_group(self.gh); }
223 self.gh = std::ptr::null_mut();
224 }
225
226 /// Set the amount of packet data that nflog copies to userspace
227 ///
228 /// Arguments:
229 ///
230 /// * `mode` - The part of the packet that we are interested in
231 /// * `range` - Size of the packet that we want to get
232 ///
233 /// `mode` can be one of:
234 ///
235 /// * `NFULNL_COPY_NONE` - do not copy any data
236 /// * `NFULNL_COPY_META` - copy only packet metadata
237 /// * `NFULNL_COPY_PACKET` - copy entire packet
238 pub fn set_mode(&self, mode: CopyMode, range: u32) {
239 assert!(!self.gh.is_null());
240 let c_mode = match mode {
241 CopyMode::CopyNone => NFULNL_COPY_NONE,
242 CopyMode::CopyMeta => NFULNL_COPY_META,
243 CopyMode::CopyPacket => NFULNL_COPY_PACKET,
244 };
245 unsafe { nflog_set_mode(self.gh, c_mode, range); }
246 }
247
248 /// Sets the maximum time to push log buffer for this group
249 ///
250 /// Arguments:
251 ///
252 /// * `timeout` - Time to wait until the log buffer is pushed to userspace
253 ///
254 /// This function allows to set the maximum time that nflog waits until it
255 /// pushes the log buffer to userspace if no new logged packets have occured.
256 ///
257 /// Basically, nflog implements a buffer to reduce the computational cost of
258 /// delivering the log message to userspace.
259 pub fn set_timeout(&self, timeout: u32) {
260 assert!(!self.gh.is_null());
261 unsafe { nflog_set_timeout(self.gh, timeout); }
262 }
263
264 /// Sets the maximum amount of logs in buffer for this group
265 ///
266 /// Arguments:
267 ///
268 /// * `qthresh` - Maximum number of log entries
269 ///
270 /// This function determines the maximum number of log entries in the
271 /// buffer until it is pushed to userspace.
272 pub fn set_qthresh(&self, qthresh: u32) {
273 assert!(!self.gh.is_null());
274 unsafe { nflog_set_qthresh(self.gh, qthresh); }
275 }
276
277 /// Sets the size of the nflog buffer for this group
278 ///
279 /// Arguments:
280 ///
281 /// * `nlbufsiz` - Size of the nflog buffer
282 ///
283 /// This function sets the size (in bytes) of the buffer that is used to
284 /// stack log messages in nflog.
285 pub fn set_nlbufsiz(&self, nlbufsiz: u32) {
286 assert!(!self.gh.is_null());
287 unsafe { nflog_set_nlbufsiz(self.gh, nlbufsiz); }
288 }
289
290 /// Sets the nflog flags for this group
291 ///
292 /// Arguments:
293 ///
294 /// * `flags` - Flags that you want to set
295 ///
296 /// There are two existing flags:
297 ///
298 /// * `NFULNL_CFG_F_SEQ`: This enables local nflog sequence numbering.
299 /// * `NFULNL_CFG_F_SEQ_GLOBAL`: This enables global nflog sequence numbering.
300 pub fn set_flags(&self, flags: CfgFlags) {
301 assert!(!self.gh.is_null());
302 let c_flags : u16 = match flags {
303 CfgFlags::CfgFlagsSeq => NFULNL_CFG_F_SEQ,
304 CfgFlags::CfgFlagsSeqGlobal => NFULNL_CFG_F_SEQ_GLOBAL,
305 };
306 unsafe { nflog_set_flags(self.gh, c_flags); }
307 }
308
309
310 /// Registers the callback triggered when a packet is received
311 pub fn set_callback(&mut self, cb: NflogCallback) {
312 self.cb = Some(cb);
313 let self_ptr = unsafe { std::mem::transmute(&*self) };
314 unsafe { nflog_callback_register(self.gh, real_callback, self_ptr); };
315 }
316
317 /// Runs an infinite loop, waiting for packets and triggering the callback.
318 pub fn run_loop(&self) {
319 assert!(!self.gh.is_null());
320
321 let fd = self.fd();
322 let mut buf : [u8;65536] = [0;65536];
323 let buf_ptr = buf.as_mut_ptr() as *mut libc::c_void;
324 let buf_len = buf.len() as libc::size_t;
325
326 loop {
327 let rc = unsafe { libc::recv(fd,buf_ptr,buf_len,0) };
328 if rc < 0 { panic!("error in recv()"); };
329
330 let rv = unsafe { nflog_handle_packet(self.qh, buf_ptr, rc as libc::c_int) };
331 if rv < 0 { println!("error in nflog_handle_packet()"); }; // not critical
332 }
333 }
334}
335
336#[doc(hidden)]
337#[no_mangle]
338pub 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 ) {
339 let raw : *mut Queue = unsafe { std::mem::transmute(data) };
340
341 let ref mut q = unsafe { &*raw };
342 let mut msg = Message::new (nfad);
343
344 match q.cb {
345 None => panic!("no callback registered"),
346 Some(callback) => {
347 callback(&mut msg);
348 },
349 }
350}
351
352
353
354#[cfg(test)]
355mod tests {
356
357 extern crate libc;
358
359 #[test]
360 fn nflog_open() {
361 let mut q = ::Queue::new();
362
363 q.open();
364
365 let raw = q.qh as *const i32;
366 println!("nfq_open: 0x{:x}", unsafe{*raw});
367
368 assert!(!q.qh.is_null());
369
370 q.close();
371 }
372
373 #[test]
374 #[ignore]
375 fn nflog_bind() {
376 let mut q = ::Queue::new();
377
378 q.open();
379
380 let raw = q.qh as *const i32;
381 println!("nfq_open: 0x{:x}", unsafe{*raw});
382
383 assert!(!q.qh.is_null());
384
385 let rc = q.bind(libc::AF_INET);
386 println!("q.bind: {}", rc);
387 assert!(q.bind(libc::AF_INET) == 0);
388
389 q.close();
390 }
391}