pcap/capture/
mod.rs

1pub mod activated;
2pub mod inactive;
3#[cfg(all(not(windows), feature = "capture-stream"))]
4#[cfg_attr(docsrs, doc(cfg(all(not(windows), feature = "capture-stream"))))]
5pub mod selectable;
6
7use std::{
8    ffi::CString,
9    marker::PhantomData,
10    ptr::{self, NonNull},
11};
12
13#[cfg(windows)]
14use windows_sys::Win32::Foundation::HANDLE;
15
16use crate::{raw, Error};
17
18/// Phantom type representing an inactive capture handle.
19pub enum Inactive {}
20
21/// Phantom type representing an active capture handle.
22pub enum Active {}
23
24/// Phantom type representing an offline capture handle, from a pcap dump file.
25/// Implements `Activated` because it behaves nearly the same as a live handle.
26pub enum Offline {}
27
28/// Phantom type representing a dead capture handle.  This can be use to create
29/// new save files that are not generated from an active capture.
30/// Implements `Activated` because it behaves nearly the same as a live handle.
31pub enum Dead {}
32
33/// `Capture`s can be in different states at different times, and in these states they
34/// may or may not have particular capabilities. This trait is implemented by phantom
35/// types which allows us to punt these invariants to the type system to avoid runtime
36/// errors.
37pub trait Activated: State {}
38
39impl Activated for Active {}
40
41impl Activated for Offline {}
42
43impl Activated for Dead {}
44
45/// `Capture`s can be in different states at different times, and in these states they
46/// may or may not have particular capabilities. This trait is implemented by phantom
47/// types which allows us to punt these invariants to the type system to avoid runtime
48/// errors.
49pub trait State {}
50
51impl State for Inactive {}
52
53impl State for Active {}
54
55impl State for Offline {}
56
57impl State for Dead {}
58
59/// This is a pcap capture handle which is an abstraction over the `pcap_t` provided by pcap.
60/// There are many ways to instantiate and interact with a pcap handle, so phantom types are
61/// used to express these behaviors.
62///
63/// **`Capture<Inactive>`** is created via `Capture::from_device()`. This handle is inactive,
64/// so you cannot (yet) obtain packets from it. However, you can configure things like the
65/// buffer size, snaplen, timeout, and promiscuity before you activate it.
66///
67/// **`Capture<Active>`** is created by calling `.open()` on a `Capture<Inactive>`. This
68/// activates the capture handle, allowing you to get packets with `.next_packet()` or apply filters
69/// with `.filter()`.
70///
71/// **`Capture<Offline>`** is created via `Capture::from_file()`. This allows you to read a
72/// pcap format dump file as if you were opening an interface -- very useful for testing or
73/// analysis.
74///
75/// **`Capture<Dead>`** is created via `Capture::dead()`. This allows you to create a pcap
76/// format dump file without needing an active capture.
77///
78/// # Example:
79///
80/// ```no_run
81/// # use pcap::{Capture, Device};
82/// let mut cap = Capture::from_device(Device::lookup().unwrap().unwrap()) // open the "default" interface
83///               .unwrap() // assume the device exists and we are authorized to open it
84///               .open() // activate the handle
85///               .unwrap(); // assume activation worked
86///
87/// while let Ok(packet) = cap.next_packet() {
88///     println!("received packet! {:?}", packet);
89/// }
90/// ```
91pub struct Capture<T: State + ?Sized> {
92    nonblock: bool,
93    handle: NonNull<raw::pcap_t>,
94    _marker: PhantomData<T>,
95}
96
97// A Capture is safe to Send as it encapsulates the entire lifetime of `raw::pcap_t *`, but it is
98// not safe to Sync as libpcap does not promise thread-safe access to the same `raw::pcap_t *` from
99// multiple threads.
100unsafe impl<T: State + ?Sized> Send for Capture<T> {}
101
102impl<T: State + ?Sized> From<NonNull<raw::pcap_t>> for Capture<T> {
103    fn from(handle: NonNull<raw::pcap_t>) -> Self {
104        Capture {
105            nonblock: false,
106            handle,
107            _marker: PhantomData,
108        }
109    }
110}
111
112impl<T: State + ?Sized> Capture<T> {
113    fn new_raw<F>(path: Option<&str>, func: F) -> Result<Capture<T>, Error>
114    where
115        F: FnOnce(*const libc::c_char, *mut libc::c_char) -> *mut raw::pcap_t,
116    {
117        Error::with_errbuf(|err| {
118            let handle = match path {
119                None => func(ptr::null(), err),
120                Some(path) => {
121                    let path = CString::new(path)?;
122                    func(path.as_ptr(), err)
123                }
124            };
125            Ok(Capture::from(
126                NonNull::<raw::pcap_t>::new(handle).ok_or_else(|| unsafe { Error::new(err) })?,
127            ))
128        })
129    }
130
131    pub fn is_nonblock(&self) -> bool {
132        self.nonblock
133    }
134
135    pub fn as_ptr(&self) -> *mut raw::pcap_t {
136        self.handle.as_ptr()
137    }
138
139    /// Set the minumum amount of data received by the kernel in a single call.
140    ///
141    /// Note that this value is set to 0 when the capture is set to immediate mode. You should not
142    /// call `min_to_copy` on captures in immediate mode if you want them to stay in immediate mode.
143    #[cfg(windows)]
144    pub fn min_to_copy(self, to: i32) -> Capture<T> {
145        unsafe {
146            raw::pcap_setmintocopy(self.handle.as_ptr(), to as _);
147        }
148        self
149    }
150
151    /// Get handle to the Capture context's internal Win32 event semaphore.
152    ///
153    /// Setting this event will cause a blocking capture call to unblock and return.
154    ///
155    /// # Example
156    /// The _winevt_ example demonstrates how to use the event semaphore to send command requests
157    /// to a capture loop running in a separate thread.
158    ///
159    /// # Safety
160    ///
161    /// The caller must ensure that the `Capture` context outlives the returned `HANDLE` since it is
162    /// a kernel object owned by the `Capture`'s pcap context.
163    #[cfg(windows)]
164    pub unsafe fn get_event(&self) -> HANDLE {
165        raw::pcap_getevent(self.handle.as_ptr())
166    }
167
168    fn check_err(&self, success: bool) -> Result<(), Error> {
169        if success {
170            Ok(())
171        } else {
172            Err(self.get_err())
173        }
174    }
175
176    fn get_err(&self) -> Error {
177        unsafe { Error::new(raw::pcap_geterr(self.handle.as_ptr())) }
178    }
179}
180
181impl<T: State + ?Sized> Drop for Capture<T> {
182    fn drop(&mut self) {
183        unsafe { raw::pcap_close(self.handle.as_ptr()) }
184    }
185}
186
187#[repr(u32)]
188#[derive(Debug, PartialEq, Eq, Clone, Copy)]
189/// Timestamp resolution types
190///
191/// Not all systems and interfaces will necessarily support all of these resolutions when doing
192/// live captures; all of them can be requested when reading a safefile.
193pub enum Precision {
194    /// Use timestamps with microsecond precision. This is the default.
195    Micro = 0,
196    /// Use timestamps with nanosecond precision.
197    Nano = 1,
198}
199
200// GRCOV_EXCL_START
201#[cfg(test)]
202pub mod testmod {
203    use raw::testmod::RAWMTX;
204
205    use super::*;
206
207    pub struct TestCapture<T: State + ?Sized> {
208        pub capture: Capture<T>,
209        _close_ctx: raw::__pcap_close::Context,
210    }
211
212    pub fn test_capture<T: State + ?Sized>(pcap: *mut raw::pcap_t) -> TestCapture<T> {
213        // Lock must be acquired by caller.
214        assert!(RAWMTX.try_lock().is_err());
215
216        let ctx = raw::pcap_close_context();
217        ctx.checkpoint();
218        ctx.expect()
219            .withf_st(move |ptr| *ptr == pcap)
220            .return_once(|_| {});
221
222        TestCapture {
223            capture: Capture::<T>::from(NonNull::new(pcap).unwrap()),
224            _close_ctx: ctx,
225        }
226    }
227}
228// GRCOV_EXCL_STOP
229
230#[cfg(test)]
231mod tests {
232    use crate::{
233        capture::testmod::test_capture,
234        raw::testmod::{as_pcap_t, RAWMTX},
235    };
236
237    use super::*;
238
239    #[test]
240    fn test_capture_getters() {
241        let _m = RAWMTX.lock();
242
243        let mut dummy: isize = 777;
244        let pcap = as_pcap_t(&mut dummy);
245
246        let test_capture = test_capture::<Active>(pcap);
247        let capture = test_capture.capture;
248
249        assert!(!capture.is_nonblock());
250        assert_eq!(capture.as_ptr(), capture.handle.as_ptr());
251    }
252
253    #[test]
254    #[cfg(windows)]
255    fn test_min_to_copy() {
256        let _m = RAWMTX.lock();
257
258        let mut dummy: isize = 777;
259        let pcap = as_pcap_t(&mut dummy);
260
261        let test_capture = test_capture::<Active>(pcap);
262        let capture = test_capture.capture;
263
264        let ctx = raw::pcap_setmintocopy_context();
265        ctx.expect()
266            .withf_st(move |arg1, _| *arg1 == pcap)
267            .return_once(|_, _| 0);
268
269        let _capture = capture.min_to_copy(5);
270    }
271
272    #[test]
273    #[cfg(windows)]
274    fn test_get_event() {
275        let _m = RAWMTX.lock();
276
277        let mut dummy: isize = 777;
278        let pcap = as_pcap_t(&mut dummy);
279
280        let test_capture = test_capture::<Active>(pcap);
281        let capture = test_capture.capture;
282
283        let ctx = raw::pcap_getevent_context();
284        ctx.expect()
285            .withf_st(move |arg1| *arg1 == pcap)
286            .return_once(|_| 5);
287
288        let handle = unsafe { capture.get_event() };
289        assert_eq!(handle, 5);
290    }
291
292    #[test]
293    fn test_precision() {
294        assert_ne!(Precision::Micro, Precision::Nano);
295    }
296}