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
};
12

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

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

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

            
21
/// Phantom type representing an active capture handle.
22
pub 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.
26
pub 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.
31
pub 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.
37
pub trait Activated: State {}
38

            
39
impl Activated for Active {}
40

            
41
impl Activated for Offline {}
42

            
43
impl 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.
49
pub trait State {}
50

            
51
impl State for Inactive {}
52

            
53
impl State for Active {}
54

            
55
impl State for Offline {}
56

            
57
impl 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
/// ```
91
pub 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.
100
unsafe impl<T: State + ?Sized> Send for Capture<T> {}
101

            
102
impl<T: State + ?Sized> From<NonNull<raw::pcap_t>> for Capture<T> {
103
169
    fn from(handle: NonNull<raw::pcap_t>) -> Self {
104
169
        Capture {
105
169
            nonblock: false,
106
169
            handle,
107
169
            _marker: PhantomData,
108
169
        }
109
169
    }
110
}
111

            
112
impl<T: State + ?Sized> Capture<T> {
113
38
    fn new_raw<F>(path: Option<&str>, func: F) -> Result<Capture<T>, Error>
114
38
    where
115
38
        F: FnOnce(*const libc::c_char, *mut libc::c_char) -> *mut raw::pcap_t,
116
38
    {
117
38
        Error::with_errbuf(|err| {
118
38
            let handle = match path {
119
6
                None => func(ptr::null(), err),
120
32
                Some(path) => {
121
32
                    let path = CString::new(path)?;
122
32
                    func(path.as_ptr(), err)
123
                }
124
            };
125
            Ok(Capture::from(
126
38
                NonNull::<raw::pcap_t>::new(handle).ok_or_else(|| unsafe { Error::new(err) })?,
127
            ))
128
38
        })
129
38
    }
130

            
131
12
    pub fn is_nonblock(&self) -> bool {
132
12
        self.nonblock
133
12
    }
134

            
135
6
    pub fn as_ptr(&self) -> *mut raw::pcap_t {
136
6
        self.handle.as_ptr()
137
6
    }
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
78
    fn check_err(&self, success: bool) -> Result<(), Error> {
169
78
        if success {
170
52
            Ok(())
171
        } else {
172
26
            Err(self.get_err())
173
        }
174
78
    }
175

            
176
32
    fn get_err(&self) -> Error {
177
32
        unsafe { Error::new(raw::pcap_geterr(self.handle.as_ptr())) }
178
32
    }
179
}
180

            
181
impl<T: State + ?Sized> Drop for Capture<T> {
182
148
    fn drop(&mut self) {
183
148
        unsafe { raw::pcap_close(self.handle.as_ptr()) }
184
148
    }
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.
193
pub 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)]
202
pub 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)]
231
mod 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
}