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}