1use crate::errors::*;
2use std::ffi::CString;
3use std::ffi::CStr;
4
5pub struct Cap {
6 handle: *mut pcap_sys::pcap,
7}
8
9pub struct Config {
10 pub promisc: bool,
11 pub immediate_mode: bool,
12}
13
14pub fn open(dev: &str, config: &Config) -> Result<Cap> {
15 let mut errbuf = [0; pcap_sys::PCAP_ERRBUF_SIZE as usize];
16 let dev = CString::new(dev).unwrap();
17 let handle = unsafe { pcap_sys::pcap_create(dev.as_ptr(), errbuf.as_mut_ptr()) };
18
19 if handle.is_null() {
20 let err = unsafe { CStr::from_ptr(errbuf.as_ptr()) };
21 bail!("Failed to open interface: {}", err.to_str()?);
22 }
23
24 if config.promisc {
25 unsafe { pcap_sys::pcap_set_promisc(handle, 1) };
26 }
27
28 if config.immediate_mode {
29 unsafe { pcap_sys::pcap_set_immediate_mode(handle, 1) };
30 }
31
32 let ret = unsafe { pcap_sys::pcap_activate(handle) };
33 if ret != 0 {
34 let err = unsafe { pcap_sys::pcap_geterr(handle) };
35 let err = unsafe { CStr::from_ptr(err) };
36 bail!("Failed to activate interface: {}", err.to_str()?);
37 }
38
39 Ok(Cap {
40 handle,
41 })
42}
43
44pub fn open_file(path: &str) -> Result<Cap> {
45 let mut errbuf = [0; pcap_sys::PCAP_ERRBUF_SIZE as usize];
46 let path = CString::new(path).unwrap();
47 let handle = unsafe { pcap_sys::pcap_open_offline(path.as_ptr(), errbuf.as_mut_ptr()) };
48
49 if handle.is_null() {
50 let err = unsafe { CStr::from_ptr(errbuf.as_ptr()) };
51 bail!("Failed to open file: {}", err.to_str()?);
52 }
53
54 Ok(Cap {
55 handle,
56 })
57}
58
59pub fn default_interface() -> Result<String> {
60 let mut errbuf = [0; pcap_sys::PCAP_ERRBUF_SIZE as usize];
61
62 let dev = unsafe { pcap_sys::pcap_lookupdev(errbuf.as_mut_ptr()) };
63 if dev.is_null() {
64 let err = unsafe { CStr::from_ptr(errbuf.as_ptr()) };
65 bail!("Failed to find interface: {}", err.to_str()?);
66 }
67
68 let dev = unsafe { CStr::from_ptr(dev) };
69 Ok(dev.to_str()?.to_owned())
70}
71
72impl Cap {
73 pub fn datalink(&self) -> i32 {
74 unsafe { pcap_sys::pcap_datalink(self.handle) }
75 }
76
77 pub fn next_pkt(&mut self) -> Result<Option<Packet>> {
78 use std::mem::MaybeUninit;
79
80 let mut header = MaybeUninit::<*mut pcap_sys::pcap_pkthdr>::uninit();
81 let mut packet = MaybeUninit::<*const libc::c_uchar>::uninit();
82
83 let retcode = unsafe { pcap_sys::pcap_next_ex(self.handle, header.as_mut_ptr(), packet.as_mut_ptr()) };
84
85 match retcode {
86 i if i >= 1 => {
87 let header = unsafe { header.assume_init() };
88 let packet = unsafe { packet.assume_init() };
89
90 use std::slice;
91 let packet = unsafe { slice::from_raw_parts(packet, (*header).caplen as _) };
92
93 Ok(Some(Packet {
94 data: packet.to_vec(),
95 }))
96 },
97 0 => bail!("timeout expired"),
98 pcap_sys::PCAP_ERROR_BREAK => Ok(None),
99 _ => unreachable!(),
100 }
101 }
102}
103
104impl Drop for Cap {
105 fn drop(&mut self) {
106 unsafe { pcap_sys::pcap_close(self.handle) };
107 }
108}
109
110pub struct Packet {
111 pub data: Vec<u8>,
112}
113
114unsafe impl Send for Cap {}