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

            
6
use std::{
7
    ffi::CString,
8
    marker::PhantomData,
9
    ptr::{self, NonNull},
10
};
11

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

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

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

            
20
/// Phantom type representing an active capture handle.
21
pub enum Active {}
22

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

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

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

            
38
impl Activated for Active {}
39

            
40
impl Activated for Offline {}
41

            
42
impl Activated for Dead {}
43

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

            
50
impl State for Inactive {}
51

            
52
impl State for Active {}
53

            
54
impl State for Offline {}
55

            
56
impl State for Dead {}
57

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

            
96
// A Capture is safe to Send as it encapsulates the entire lifetime of `raw::pcap_t *`, but it is
97
// not safe to Sync as libpcap does not promise thread-safe access to the same `raw::pcap_t *` from
98
// multiple threads.
99
unsafe impl<T: State + ?Sized> Send for Capture<T> {}
100

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

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

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

            
134
6
    pub fn as_ptr(&self) -> *mut raw::pcap_t {
135
6
        self.handle.as_ptr()
136
6
    }
137

            
138
    /// Set the minumum amount of data received by the kernel in a single call.
139
    ///
140
    /// Note that this value is set to 0 when the capture is set to immediate mode. You should not
141
    /// call `min_to_copy` on captures in immediate mode if you want them to stay in immediate mode.
142
    #[cfg(windows)]
143
    pub fn min_to_copy(self, to: i32) -> Capture<T> {
144
        unsafe {
145
            raw::pcap_setmintocopy(self.handle.as_ptr(), to as _);
146
        }
147
        self
148
    }
149

            
150
    /// Get handle to the Capture context's internal Win32 event semaphore.
151
    ///
152
    /// # Safety
153
    ///
154
    /// The caller must ensure that the `Capture` context outlives the returned `HANDLE` since it is
155
    /// a kernel object owned by the `Capture`'s pcap context.
156
    #[cfg(windows)]
157
    pub unsafe fn get_event(&self) -> HANDLE {
158
        raw::pcap_getevent(self.handle.as_ptr())
159
    }
160

            
161
78
    fn check_err(&self, success: bool) -> Result<(), Error> {
162
78
        if success {
163
52
            Ok(())
164
        } else {
165
26
            Err(self.get_err())
166
        }
167
78
    }
168

            
169
32
    fn get_err(&self) -> Error {
170
32
        unsafe { Error::new(raw::pcap_geterr(self.handle.as_ptr())) }
171
32
    }
172
}
173

            
174
impl<T: State + ?Sized> Drop for Capture<T> {
175
148
    fn drop(&mut self) {
176
148
        unsafe { raw::pcap_close(self.handle.as_ptr()) }
177
148
    }
178
}
179

            
180
#[repr(u32)]
181
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
182
/// Timestamp resolution types
183
///
184
/// Not all systems and interfaces will necessarily support all of these resolutions when doing
185
/// live captures; all of them can be requested when reading a safefile.
186
pub enum Precision {
187
    /// Use timestamps with microsecond precision. This is the default.
188
    Micro = 0,
189
    /// Use timestamps with nanosecond precision.
190
    Nano = 1,
191
}
192

            
193
// GRCOV_EXCL_START
194
#[cfg(test)]
195
pub mod testmod {
196
    use raw::testmod::RAWMTX;
197

            
198
    use super::*;
199

            
200
    pub struct TestCapture<T: State + ?Sized> {
201
        pub capture: Capture<T>,
202
        _close_ctx: raw::__pcap_close::Context,
203
    }
204

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

            
209
        let ctx = raw::pcap_close_context();
210
        ctx.checkpoint();
211
        ctx.expect()
212
            .withf_st(move |ptr| *ptr == pcap)
213
            .return_once(|_| {});
214

            
215
        TestCapture {
216
            capture: Capture::<T>::from(NonNull::new(pcap).unwrap()),
217
            _close_ctx: ctx,
218
        }
219
    }
220
}
221
// GRCOV_EXCL_STOP
222

            
223
#[cfg(test)]
224
mod tests {
225
    use crate::{
226
        capture::testmod::test_capture,
227
        raw::testmod::{as_pcap_t, RAWMTX},
228
    };
229

            
230
    use super::*;
231

            
232
    #[test]
233
    fn test_capture_getters() {
234
        let _m = RAWMTX.lock();
235

            
236
        let mut dummy: isize = 777;
237
        let pcap = as_pcap_t(&mut dummy);
238

            
239
        let test_capture = test_capture::<Active>(pcap);
240
        let capture = test_capture.capture;
241

            
242
        assert!(!capture.is_nonblock());
243
        assert_eq!(capture.as_ptr(), capture.handle.as_ptr());
244
    }
245

            
246
    #[test]
247
    #[cfg(windows)]
248
    fn test_min_to_copy() {
249
        let _m = RAWMTX.lock();
250

            
251
        let mut dummy: isize = 777;
252
        let pcap = as_pcap_t(&mut dummy);
253

            
254
        let test_capture = test_capture::<Active>(pcap);
255
        let capture = test_capture.capture;
256

            
257
        let ctx = raw::pcap_setmintocopy_context();
258
        ctx.expect()
259
            .withf_st(move |arg1, _| *arg1 == pcap)
260
            .return_once(|_, _| 0);
261

            
262
        let _capture = capture.min_to_copy(5);
263
    }
264

            
265
    #[test]
266
    #[cfg(windows)]
267
    fn test_get_event() {
268
        let _m = RAWMTX.lock();
269

            
270
        let mut dummy: isize = 777;
271
        let pcap = as_pcap_t(&mut dummy);
272

            
273
        let test_capture = test_capture::<Active>(pcap);
274
        let capture = test_capture.capture;
275

            
276
        let ctx = raw::pcap_getevent_context();
277
        ctx.expect()
278
            .withf_st(move |arg1| *arg1 == pcap)
279
            .return_once(|_| 5);
280

            
281
        let handle = unsafe { capture.get_event() };
282
        assert_eq!(handle, 5);
283
    }
284

            
285
    #[test]
286
    fn test_precision() {
287
        assert_ne!(Precision::Micro, Precision::Nano);
288
    }
289
}