1
pub mod activated;
2
pub mod inactive;
3
#[cfg(all(not(windows), feature = "capture-stream"))]
4
#[cfg_attr(docsrs, doc(cfg(all(not(windows), feature = "capture-stream"))))]
5
pub mod selectable;
6

            
7
use std::{
8
    ffi::CString,
9
    marker::PhantomData,
10
    ptr::{self, NonNull},
11
    sync::Arc,
12
};
13

            
14
#[cfg(windows)]
15
use windows_sys::Win32::Foundation::HANDLE;
16

            
17
use crate::{raw, Error};
18

            
19
/// Phantom type representing an inactive capture handle.
20
pub enum Inactive {}
21

            
22
/// Phantom type representing an active capture handle.
23
pub enum Active {}
24

            
25
/// Phantom type representing an offline capture handle, from a pcap dump file.
26
/// Implements `Activated` because it behaves nearly the same as a live handle.
27
pub enum Offline {}
28

            
29
/// Phantom type representing a dead capture handle.  This can be use to create
30
/// new save files that are not generated from an active capture.
31
/// Implements `Activated` because it behaves nearly the same as a live handle.
32
pub enum Dead {}
33

            
34
/// `Capture`s can be in different states at different times, and in these states they
35
/// may or may not have particular capabilities. This trait is implemented by phantom
36
/// types which allows us to punt these invariants to the type system to avoid runtime
37
/// errors.
38
pub trait Activated: State {}
39

            
40
impl Activated for Active {}
41

            
42
impl Activated for Offline {}
43

            
44
impl Activated for Dead {}
45

            
46
/// `Capture`s can be in different states at different times, and in these states they
47
/// may or may not have particular capabilities. This trait is implemented by phantom
48
/// types which allows us to punt these invariants to the type system to avoid runtime
49
/// errors.
50
pub trait State {}
51

            
52
impl State for Inactive {}
53

            
54
impl State for Active {}
55

            
56
impl State for Offline {}
57

            
58
impl State for Dead {}
59

            
60
/// This is a pcap capture handle which is an abstraction over the `pcap_t` provided by pcap.
61
/// There are many ways to instantiate and interact with a pcap handle, so phantom types are
62
/// used to express these behaviors.
63
///
64
/// **`Capture<Inactive>`** is created via `Capture::from_device()`. This handle is inactive,
65
/// so you cannot (yet) obtain packets from it. However, you can configure things like the
66
/// buffer size, snaplen, timeout, and promiscuity before you activate it.
67
///
68
/// **`Capture<Active>`** is created by calling `.open()` on a `Capture<Inactive>`. This
69
/// activates the capture handle, allowing you to get packets with `.next_packet()` or apply filters
70
/// with `.filter()`.
71
///
72
/// **`Capture<Offline>`** is created via `Capture::from_file()`. This allows you to read a
73
/// pcap format dump file as if you were opening an interface -- very useful for testing or
74
/// analysis.
75
///
76
/// **`Capture<Dead>`** is created via `Capture::dead()`. This allows you to create a pcap
77
/// format dump file without needing an active capture.
78
///
79
/// # Example:
80
///
81
/// ```no_run
82
/// # use pcap::{Capture, Device};
83
/// let mut cap = Capture::from_device(Device::lookup().unwrap().unwrap()) // open the "default" interface
84
///               .unwrap() // assume the device exists and we are authorized to open it
85
///               .open() // activate the handle
86
///               .unwrap(); // assume activation worked
87
///
88
/// while let Ok(packet) = cap.next_packet() {
89
///     println!("received packet! {:?}", packet);
90
/// }
91
/// ```
92
pub struct Capture<T: State + ?Sized> {
93
    nonblock: bool,
94
    handle: Arc<PcapHandle>,
95
    _marker: PhantomData<T>,
96
}
97

            
98
struct PcapHandle {
99
    handle: NonNull<raw::pcap_t>,
100
}
101

            
102
impl PcapHandle {
103
649
    fn as_ptr(&self) -> *mut raw::pcap_t {
104
649
        self.handle.as_ptr()
105
649
    }
106
}
107

            
108
// `PcapHandle` is safe to Send as it encapsulates the entire lifetime of `raw::pcap_t *`
109
// `PcapHandle` is only Sync under special circumstances when used in thread-safe functions such as
110
// the `pcap_breakloop` function. The Sync correctness is left to the wrapping structure to provide.
111
unsafe impl Send for PcapHandle {}
112

            
113
impl Drop for PcapHandle {
114
171
    fn drop(&mut self) {
115
171
        unsafe { raw::pcap_close(self.handle.as_ptr()) }
116
171
    }
117
}
118

            
119
unsafe impl<T: State + ?Sized> Send for Capture<T> {}
120

            
121
// `Capture` is not safe to implement Sync as the libpcap functions it uses are not promised to have
122
// thread-safe access to the same `raw::pcap_t *` from multiple threads.
123
#[allow(clippy::arc_with_non_send_sync)]
124
impl<T: State + ?Sized> From<NonNull<raw::pcap_t>> for Capture<T> {
125
171
    fn from(handle: NonNull<raw::pcap_t>) -> Self {
126
171
        Capture {
127
171
            nonblock: false,
128
171
            handle: Arc::new(PcapHandle { handle }),
129
171
            _marker: PhantomData,
130
171
        }
131
171
    }
132
}
133

            
134
impl<T: State + ?Sized> Capture<T> {
135
38
    fn new_raw<F>(path: Option<&str>, func: F) -> Result<Capture<T>, Error>
136
38
    where
137
38
        F: FnOnce(*const libc::c_char, *mut libc::c_char) -> *mut raw::pcap_t,
138
    {
139
38
        Error::with_errbuf(|err| {
140
38
            let handle = match path {
141
6
                None => func(ptr::null(), err),
142
32
                Some(path) => {
143
32
                    let path = CString::new(path)?;
144
32
                    func(path.as_ptr(), err)
145
                }
146
            };
147
36
            Ok(Capture::from(
148
38
                NonNull::<raw::pcap_t>::new(handle).ok_or_else(|| unsafe { Error::new(err) })?,
149
            ))
150
38
        })
151
38
    }
152

            
153
12
    pub fn is_nonblock(&self) -> bool {
154
12
        self.nonblock
155
12
    }
156

            
157
6
    pub fn as_ptr(&self) -> *mut raw::pcap_t {
158
6
        self.handle.as_ptr()
159
6
    }
160

            
161
    /// Set the minumum amount of data received by the kernel in a single call.
162
    ///
163
    /// Note that this value is set to 0 when the capture is set to immediate mode. You should not
164
    /// call `min_to_copy` on captures in immediate mode if you want them to stay in immediate mode.
165
    #[cfg(windows)]
166
    pub fn min_to_copy(self, to: i32) -> Capture<T> {
167
        unsafe {
168
            raw::pcap_setmintocopy(self.handle.as_ptr(), to as _);
169
        }
170
        self
171
    }
172

            
173
    /// Get handle to the Capture context's internal Win32 event semaphore.
174
    ///
175
    /// Setting this event will cause a blocking capture call to unblock and return.
176
    ///
177
    /// # Example
178
    /// The _winevt_ example demonstrates how to use the event semaphore to send command requests
179
    /// to a capture loop running in a separate thread.
180
    ///
181
    /// # Safety
182
    ///
183
    /// The caller must ensure that the `Capture` context outlives the returned `HANDLE` since it is
184
    /// a kernel object owned by the `Capture`'s pcap context.
185
    #[cfg(windows)]
186
    pub unsafe fn get_event(&self) -> HANDLE {
187
        raw::pcap_getevent(self.handle.as_ptr())
188
    }
189

            
190
78
    fn check_err(&self, success: bool) -> Result<(), Error> {
191
78
        if success {
192
52
            Ok(())
193
        } else {
194
26
            Err(self.get_err())
195
        }
196
78
    }
197

            
198
32
    fn get_err(&self) -> Error {
199
32
        unsafe { Error::new(raw::pcap_geterr(self.handle.as_ptr())) }
200
32
    }
201
}
202

            
203
#[repr(u32)]
204
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
205
/// Timestamp resolution types
206
///
207
/// Not all systems and interfaces will necessarily support all of these resolutions when doing
208
/// live captures; all of them can be requested when reading a safefile.
209
pub enum Precision {
210
    /// Use timestamps with microsecond precision. This is the default.
211
    Micro = 0,
212
    /// Use timestamps with nanosecond precision.
213
    Nano = 1,
214
}
215

            
216
// GRCOV_EXCL_START
217
#[cfg(test)]
218
pub mod testmod {
219
    use raw::testmod::RAWMTX;
220

            
221
    use super::*;
222

            
223
    pub struct TestCapture<T: State + ?Sized> {
224
        pub capture: Capture<T>,
225
        _close_ctx: raw::__pcap_close::Context,
226
    }
227

            
228
    pub fn test_capture<T: State + ?Sized>(pcap: *mut raw::pcap_t) -> TestCapture<T> {
229
        // Lock must be acquired by caller.
230
        assert!(RAWMTX.try_lock().is_err());
231

            
232
        let ctx = raw::pcap_close_context();
233
        ctx.checkpoint();
234
        ctx.expect()
235
            .withf_st(move |ptr| *ptr == pcap)
236
            .return_once(|_| {});
237

            
238
        TestCapture {
239
            capture: Capture::<T>::from(NonNull::new(pcap).unwrap()),
240
            _close_ctx: ctx,
241
        }
242
    }
243
}
244
// GRCOV_EXCL_STOP
245

            
246
#[cfg(test)]
247
mod tests {
248
    use crate::{
249
        capture::testmod::test_capture,
250
        raw::testmod::{as_pcap_t, RAWMTX},
251
    };
252

            
253
    use super::*;
254

            
255
    #[test]
256
    fn test_capture_getters() {
257
        let _m = RAWMTX.lock();
258

            
259
        let mut dummy: isize = 777;
260
        let pcap = as_pcap_t(&mut dummy);
261

            
262
        let test_capture = test_capture::<Active>(pcap);
263
        let capture = test_capture.capture;
264

            
265
        assert!(!capture.is_nonblock());
266
        assert_eq!(capture.as_ptr(), capture.handle.as_ptr());
267
    }
268

            
269
    #[test]
270
    #[cfg(windows)]
271
    fn test_min_to_copy() {
272
        let _m = RAWMTX.lock();
273

            
274
        let mut dummy: isize = 777;
275
        let pcap = as_pcap_t(&mut dummy);
276

            
277
        let test_capture = test_capture::<Active>(pcap);
278
        let capture = test_capture.capture;
279

            
280
        let ctx = raw::pcap_setmintocopy_context();
281
        ctx.expect()
282
            .withf_st(move |arg1, _| *arg1 == pcap)
283
            .return_once(|_, _| 0);
284

            
285
        let _capture = capture.min_to_copy(5);
286
    }
287

            
288
    #[test]
289
    #[cfg(windows)]
290
    fn test_get_event() {
291
        let _m = RAWMTX.lock();
292

            
293
        let mut dummy: isize = 777;
294
        let pcap = as_pcap_t(&mut dummy);
295

            
296
        let test_capture = test_capture::<Active>(pcap);
297
        let capture = test_capture.capture;
298

            
299
        let ctx = raw::pcap_getevent_context();
300
        ctx.expect()
301
            .withf_st(move |arg1| *arg1 == pcap)
302
            .return_once(|_| 5);
303

            
304
        let handle = unsafe { capture.get_event() };
305
        assert_eq!(handle, 5);
306
    }
307

            
308
    #[test]
309
    fn test_precision() {
310
        assert_ne!(Precision::Micro, Precision::Nano);
311
    }
312
}