sniffglue/
sniff.rs

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 {}