Skip to content

Commit 4444d6d

Browse files
authored
Merge pull request #2 from dbcfd/bpf-support
Improve support for compiling bpf's via pcap_open_dead
2 parents 237a235 + eb3908a commit 4444d6d

File tree

6 files changed

+94
-14
lines changed

6 files changed

+94
-14
lines changed

src/bpf.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// Wrapper for bpf_program to ensure correct drops
2+
#[derive(Debug)]
3+
pub struct Bpf {
4+
inner: pcap_sys::bpf_program,
5+
}
6+
7+
impl Bpf {
8+
pub fn new(inner: pcap_sys::bpf_program) -> Bpf {
9+
Bpf {
10+
inner
11+
}
12+
}
13+
pub fn inner_mut(&mut self) -> &mut pcap_sys::bpf_program {
14+
&mut self.inner
15+
}
16+
}
17+
18+
impl Drop for Bpf {
19+
fn drop(&mut self) {
20+
unsafe {
21+
pcap_sys::pcap_freecode(&mut self.inner);
22+
}
23+
}
24+
}

src/errors.rs

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub enum Error {
3030
#[fail(cause)]
3131
error: failure::Error,
3232
},
33+
#[fail(display = "{}", msg)]
34+
Custom { msg: String },
3335
}
3436

3537
unsafe impl Sync for Error {}

src/handle.rs

+61-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use crate::{errors::Error, pcap_util, stats::Stats};
2+
use crate::bpf::Bpf;
23
use log::*;
3-
use std;
4+
use std::path::Path;
5+
use std::os::raw::c_int;
46

7+
/// Wrapper around a pcap_t handle to indicate live or offline capture, and allow the handle to
8+
/// be interrupted to stop capture.
59
#[derive(Clone)]
610
pub struct Handle {
711
handle: *mut pcap_sys::pcap_t,
@@ -17,6 +21,7 @@ impl Handle {
1721
self.live_capture
1822
}
1923

24+
/// Create a live capture from a string representing an interface
2025
pub fn live_capture(iface: &str) -> Result<std::sync::Arc<Handle>, Error> {
2126
let device_str = std::ffi::CString::new(iface).map_err(Error::Ffi)?;
2227

@@ -43,7 +48,13 @@ impl Handle {
4348
r
4449
}
4550

46-
pub fn file_capture(path: &str) -> Result<std::sync::Arc<Handle>, Error> {
51+
/// Create an offline capture from a path to a file
52+
pub fn file_capture<P: AsRef<Path>>(path: P) -> Result<std::sync::Arc<Handle>, Error> {
53+
let path = if let Some(s) = path.as_ref().to_str() {
54+
s
55+
} else {
56+
return Err(Error::Custom { msg: format!("Invalid path: {:?}", path.as_ref()) })
57+
};
4758
let device_str = std::ffi::CString::new(path).map_err(Error::Ffi)?;
4859

4960
let errbuf = ([0i8; 256]).as_mut_ptr();
@@ -69,6 +80,23 @@ impl Handle {
6980
r
7081
}
7182

83+
/// Create a dead handle, typically used for compiling bpf's
84+
pub fn dead(linktype: i32, snaplen: i32) -> Result<std::sync::Arc<Handle>, Error> {
85+
let h = unsafe { pcap_sys::pcap_open_dead(linktype as c_int, snaplen as c_int) };
86+
if h.is_null() {
87+
error!("Failed to create dead handle");
88+
Err(Error::Custom { msg: "Could not create dead handle".to_owned() })
89+
} else {
90+
info!("Dead handle created");
91+
let handle = std::sync::Arc::new(Handle {
92+
handle: h,
93+
live_capture: false,
94+
interrupted: std::sync::Arc::new(std::sync::Mutex::new(false))
95+
});
96+
Ok(handle)
97+
}
98+
}
99+
72100
pub fn lookup() -> Result<std::sync::Arc<Handle>, Error> {
73101
let errbuf = ([0i8; 256]).as_mut_ptr();
74102
let dev = unsafe { pcap_sys::pcap_lookupdev(errbuf) };
@@ -138,10 +166,10 @@ impl Handle {
138166
}
139167
}
140168

141-
pub fn set_bpf(
169+
pub fn compile_bpf(
142170
&self,
143-
bpf: &String,
144-
) -> Result<&Self, Error> {
171+
bpf: &str,
172+
) -> Result<Bpf, Error> {
145173
let mut bpf_program = pcap_sys::bpf_program {
146174
bf_len: 0,
147175
bf_insns: std::ptr::null_mut(),
@@ -161,10 +189,16 @@ impl Handle {
161189
return Err(pcap_util::convert_libpcap_error(self.handle));
162190
}
163191

164-
let ret_code = unsafe { pcap_sys::pcap_setfilter(self.handle, &mut bpf_program) };
165-
unsafe {
166-
pcap_sys::pcap_freecode(&mut bpf_program);
167-
}
192+
Ok(Bpf::new(bpf_program))
193+
}
194+
195+
pub fn set_bpf(
196+
&self,
197+
bpf: Bpf,
198+
) -> Result<&Self, Error> {
199+
let mut bpf = bpf;
200+
201+
let ret_code = unsafe { pcap_sys::pcap_setfilter(self.handle, bpf.inner_mut()) };
168202
if ret_code != 0 {
169203
return Err(pcap_util::convert_libpcap_error(self.handle));
170204
}
@@ -259,4 +293,22 @@ mod tests {
259293

260294
assert!(handle.is_ok());
261295
}
296+
#[test]
297+
fn open_dead() {
298+
let _ = env_logger::try_init();
299+
300+
let handle = Handle::dead(0, 0);
301+
302+
assert!(handle.is_ok());
303+
}
304+
#[test]
305+
fn bpf_compile() {
306+
let _ = env_logger::try_init();
307+
308+
let handle = Handle::dead(0, 1555).expect("Could not create dead handle");
309+
310+
let bpf = handle.compile_bpf("(not (net 192.168.0.0/16 and port 443)) and (not (host 192.1.2.3 and port 443))");
311+
312+
assert!(bpf.is_ok(), "{:?}", bpf);
313+
}
262314
}

src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(dead_code, unused_imports)]
2-
#![feature(ptr_internals, test, async_await, await_macro)]
3-
2+
#![feature(ptr_internals, test, async_await)]
3+
pub mod bpf;
44
pub mod config;
55
pub mod errors;
66
pub mod handle;
@@ -71,7 +71,7 @@ async fn next_packets(
7171
debug!("No packets read, delaying to retry");
7272

7373
let f = tokio_timer::sleep(delay).compat();
74-
if let Err(e) = await!(f) {
74+
if let Err(e) = f.await {
7575
error!("Failed to delay: {:?}", e);
7676
}
7777
} else {

src/provider.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ impl PacketProvider {
3737
.activate()?;
3838

3939
if let Some(bpf) = config.bpf() {
40+
let bpf = handle.compile_bpf(bpf)?;
4041
handle.set_bpf(bpf)?;
4142
}
4243
}
@@ -64,7 +65,7 @@ mod tests {
6465
let mut provider = provider;
6566
let mut agg = 0;
6667
loop {
67-
if let Some(p) = await!(provider.next_packets()) {
68+
if let Some(p) = provider.next_packets().await {
6869
agg += p.len();
6970
} else {
7071
break;
@@ -88,7 +89,7 @@ mod tests {
8889

8990
let packet_provider =
9091
PacketProvider::new(Config::default(), std::sync::Arc::clone(&handle)).expect("Failed to build");
91-
let fut_packets: std::pin::Pin<Box<std::future::Future<Output = usize> + Send>> =
92+
let fut_packets: std::pin::Pin<Box<dyn std::future::Future<Output = usize> + Send>> =
9293
get_packets(packet_provider).boxed();
9394
let packets = futures::executor::block_on(fut_packets);
9495

src/stream.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ impl PacketStream {
2929
.activate()?;
3030

3131
if let Some(bpf) = config.bpf() {
32+
let bpf = handle.compile_bpf(bpf)?;
3233
handle.set_bpf(bpf)?;
3334
}
3435
}

0 commit comments

Comments
 (0)