pcap/capture/
inactive.rs

1use std::mem;
2
3use crate::{
4    capture::{Active, Capture, Inactive},
5    device::Device,
6    raw, Error,
7};
8
9#[cfg(libpcap_1_5_0)]
10use crate::capture::Precision;
11
12impl Capture<Inactive> {
13    /// Opens a capture handle for a device. You can pass a `Device` or an `&str` device
14    /// name here. The handle is inactive, but can be activated via `.open()`.
15    ///
16    /// # Example
17    /// ```
18    /// use pcap::*;
19    ///
20    /// // Usage 1: Capture from a single owned device
21    /// let dev: Device = pcap::Device::lookup()
22    ///     .expect("device lookup failed")
23    ///     .expect("no device available");
24    /// let cap1 = Capture::from_device(dev);
25    ///
26    /// // Usage 2: Capture from an element of device list.
27    /// let list: Vec<Device> = pcap::Device::list().unwrap();
28    /// let cap2 = Capture::from_device(list[0].clone());
29    ///
30    /// // Usage 3: Capture from `&str` device name
31    /// let cap3 = Capture::from_device("eth0");
32    /// ```
33    pub fn from_device<D: Into<Device>>(device: D) -> Result<Capture<Inactive>, Error> {
34        let device: Device = device.into();
35        Capture::new_raw(Some(&device.name), |name, err| unsafe {
36            raw::pcap_create(name, err)
37        })
38    }
39
40    /// Activates an inactive capture created from `Capture::from_device()` or returns an error.
41    pub fn open(self) -> Result<Capture<Active>, Error> {
42        unsafe {
43            self.check_err(raw::pcap_activate(self.handle.as_ptr()) == 0)?;
44            Ok(mem::transmute::<Capture<Inactive>, Capture<Active>>(self))
45        }
46    }
47
48    /// Set the read timeout for the Capture. By default, this is 0, so it will block indefinitely.
49    pub fn timeout(self, ms: i32) -> Capture<Inactive> {
50        unsafe { raw::pcap_set_timeout(self.handle.as_ptr(), ms) };
51        self
52    }
53
54    /// Set the time stamp type to be used by a capture device.
55    #[cfg(libpcap_1_2_1)]
56    pub fn tstamp_type(self, tstamp_type: TimestampType) -> Capture<Inactive> {
57        unsafe { raw::pcap_set_tstamp_type(self.handle.as_ptr(), tstamp_type as _) };
58        self
59    }
60
61    /// Set promiscuous mode on or off. By default, this is off.
62    pub fn promisc(self, to: bool) -> Capture<Inactive> {
63        unsafe { raw::pcap_set_promisc(self.handle.as_ptr(), to as _) };
64        self
65    }
66
67    /// Set immediate mode on or off. By default, this is off.
68    ///
69    /// Note that in WinPcap immediate mode is set by passing a 0 argument to `min_to_copy`.
70    /// Immediate mode will be unset if `min_to_copy` is later called with a non-zero argument.
71    /// Immediate mode is unset by resetting `min_to_copy` to the WinPcap default possibly changing
72    /// a previously set value. When using `min_to_copy`, it is best to avoid `immediate_mode`.
73    #[cfg(any(libpcap_1_5_0, windows))]
74    pub fn immediate_mode(self, to: bool) -> Capture<Inactive> {
75        // Prior to 1.5.0 when `pcap_set_immediate_mode` was introduced, the necessary steps to set
76        // immediate mode were more complicated, depended on the OS, and in some configurations had
77        // to be set on an active capture. See
78        // https://www.tcpdump.org/manpages/pcap_set_immediate_mode.3pcap.html. Since we do not
79        // expect pre-1.5.0 version on unix systems in the wild, we simply ignore those cases.
80        #[cfg(libpcap_1_5_0)]
81        unsafe {
82            raw::pcap_set_immediate_mode(self.handle.as_ptr(), to as _)
83        };
84
85        // In WinPcap we use `pcap_setmintocopy` as it does not have `pcap_set_immediate_mode`.
86        #[cfg(all(windows, not(libpcap_1_5_0)))]
87        unsafe {
88            raw::pcap_setmintocopy(
89                self.handle.as_ptr(),
90                if to {
91                    0
92                } else {
93                    raw::WINPCAP_MINTOCOPY_DEFAULT
94                },
95            )
96        };
97
98        self
99    }
100
101    /// Set want_pktap to true or false. The default is maintained by libpcap.
102    #[cfg(all(libpcap_1_5_3, target_os = "macos"))]
103    pub fn want_pktap(self, to: bool) -> Capture<Inactive> {
104        unsafe { raw::pcap_set_want_pktap(self.handle.as_ptr(), to as _) };
105
106        self
107    }
108
109    /// Set rfmon mode on or off. The default is maintained by pcap.
110    #[cfg(not(windows))]
111    pub fn rfmon(self, to: bool) -> Capture<Inactive> {
112        unsafe { raw::pcap_set_rfmon(self.handle.as_ptr(), to as _) };
113        self
114    }
115
116    /// Set the buffer size for incoming packet data.
117    ///
118    /// The default is 1000000. This should always be larger than the snaplen.
119    pub fn buffer_size(self, to: i32) -> Capture<Inactive> {
120        unsafe { raw::pcap_set_buffer_size(self.handle.as_ptr(), to) };
121        self
122    }
123
124    /// Set the time stamp precision returned in captures.
125    #[cfg(libpcap_1_5_0)]
126    pub fn precision(self, precision: Precision) -> Capture<Inactive> {
127        unsafe { raw::pcap_set_tstamp_precision(self.handle.as_ptr(), precision as _) };
128        self
129    }
130
131    /// Set the snaplen size (the maximum length of a packet captured into the buffer).
132    /// Useful if you only want certain headers, but not the entire packet.
133    ///
134    /// The default is 65535.
135    pub fn snaplen(self, to: i32) -> Capture<Inactive> {
136        unsafe { raw::pcap_set_snaplen(self.handle.as_ptr(), to) };
137        self
138    }
139}
140
141#[repr(i32)]
142#[derive(Debug, PartialEq, Eq, Clone, Copy)]
143/// Timestamp types
144///
145/// Not all systems and interfaces will necessarily support all of these.
146///
147/// Note that time stamps synchronized with the system clock can go backwards, as the system clock
148/// can go backwards.  If a clock is not in sync with the system clock, that could be because the
149/// system clock isn't keeping accurate time, because the other clock isn't keeping accurate time,
150/// or both.
151///
152/// Note that host-provided time stamps generally correspond to the time when the time-stamping
153/// code sees the packet; this could be some unknown amount of time after the first or last bit of
154/// the packet is received by the network adapter, due to batching of interrupts for packet
155/// arrival, queueing delays, etc..
156pub enum TimestampType {
157    /// Timestamps are provided by the host machine, rather than by the capture device.
158    ///
159    /// The characteristics of the timestamp are unknown.
160    Host = 0,
161    /// A timestamp provided by the host machine that is low precision but relatively cheap to
162    /// fetch.
163    ///
164    /// This is normally done using the system clock, so it's normally synchronized with times
165    /// you'd fetch from system calls.
166    HostLowPrec = 1,
167    /// A timestamp provided by the host machine that is high precision. It might be more expensive
168    /// to fetch.
169    ///
170    /// The timestamp might or might not be synchronized with the system clock, and might have
171    /// problems with time stamps for packets received on different CPUs, depending on the
172    /// platform.
173    HostHighPrec = 2,
174    /// The timestamp is a high-precision time stamp supplied by the capture device.
175    ///
176    /// The timestamp is synchronized with the system clock.
177    Adapter = 3,
178    /// The timestamp is a high-precision time stamp supplied by the capture device.
179    ///
180    /// The timestamp is not synchronized with the system clock.
181    AdapterUnsynced = 4,
182}
183
184#[cfg(test)]
185mod tests {
186    use crate::{
187        capture::testmod::test_capture,
188        raw::testmod::{as_pcap_t, geterr_expect, RAWMTX},
189    };
190
191    use super::*;
192
193    #[test]
194    fn test_from_device() {
195        let _m = RAWMTX.lock();
196
197        let mut dummy: isize = 777;
198        let pcap = as_pcap_t(&mut dummy);
199
200        let ctx = raw::pcap_create_context();
201        ctx.expect().return_once_st(move |_, _| pcap);
202
203        let ctx = raw::pcap_close_context();
204        ctx.expect()
205            .withf_st(move |ptr| *ptr == pcap)
206            .return_once(|_| {});
207
208        let result = Capture::from_device("some_device");
209        assert!(result.is_ok());
210    }
211
212    #[test]
213    fn test_from_device_error() {
214        let _m = RAWMTX.lock();
215
216        let ctx = raw::pcap_create_context();
217        ctx.expect().return_once_st(|_, _| std::ptr::null_mut());
218
219        let result = Capture::from_device("some_device");
220        assert!(result.is_err());
221    }
222
223    #[test]
224    fn test_open() {
225        let _m = RAWMTX.lock();
226
227        let mut dummy: isize = 777;
228        let pcap = as_pcap_t(&mut dummy);
229
230        let test_capture = test_capture::<Inactive>(pcap);
231        let capture = test_capture.capture;
232
233        let ctx = raw::pcap_activate_context();
234        ctx.expect()
235            .withf_st(move |arg1| *arg1 == pcap)
236            .return_once(|_| 0);
237
238        let result = capture.open();
239        assert!(result.is_ok());
240    }
241
242    #[test]
243    fn test_open_error() {
244        let _m = RAWMTX.lock();
245
246        let mut dummy: isize = 777;
247        let pcap = as_pcap_t(&mut dummy);
248
249        let test_capture = test_capture::<Inactive>(pcap);
250        let capture = test_capture.capture;
251
252        let ctx = raw::pcap_activate_context();
253        ctx.expect()
254            .withf_st(move |arg1| *arg1 == pcap)
255            .return_once(|_| -1);
256
257        let _err = geterr_expect(pcap);
258
259        let result = capture.open();
260        assert!(result.is_err());
261    }
262
263    #[test]
264    fn test_timeout() {
265        let _m = RAWMTX.lock();
266
267        let mut dummy: isize = 777;
268        let pcap = as_pcap_t(&mut dummy);
269
270        let test_capture = test_capture::<Inactive>(pcap);
271        let capture = test_capture.capture;
272
273        let ctx = raw::pcap_set_timeout_context();
274        ctx.expect()
275            .withf_st(move |arg1, _| *arg1 == pcap)
276            .return_once(|_, _| 0);
277
278        let _capture = capture.timeout(5);
279    }
280
281    #[test]
282    #[cfg(libpcap_1_2_1)]
283    fn test_timstamp_type() {
284        let _m = RAWMTX.lock();
285
286        let mut dummy: isize = 777;
287        let pcap = as_pcap_t(&mut dummy);
288
289        let test_capture = test_capture::<Inactive>(pcap);
290        let capture = test_capture.capture;
291
292        let ctx = raw::pcap_set_tstamp_type_context();
293        ctx.expect()
294            .withf_st(move |arg1, _| *arg1 == pcap)
295            .return_once(|_, _| 0);
296
297        let _capture = capture.tstamp_type(TimestampType::Host);
298
299        // For code coverage of the derive line.
300        assert_ne!(TimestampType::Host, TimestampType::HostLowPrec);
301        assert_ne!(TimestampType::Host, TimestampType::HostHighPrec);
302    }
303
304    #[test]
305    fn test_promisc() {
306        let _m = RAWMTX.lock();
307
308        let mut dummy: isize = 777;
309        let pcap = as_pcap_t(&mut dummy);
310
311        let test_capture = test_capture::<Inactive>(pcap);
312        let capture = test_capture.capture;
313
314        let ctx = raw::pcap_set_promisc_context();
315        ctx.expect()
316            .withf_st(move |arg1, _| *arg1 == pcap)
317            .return_once(|_, _| 0);
318
319        let _capture = capture.promisc(true);
320    }
321
322    #[cfg(libpcap_1_5_0)]
323    struct ImmediateModeExpect(raw::__pcap_set_immediate_mode::Context);
324
325    #[cfg(all(windows, not(libpcap_1_5_0)))]
326    struct ImmediateModeExpect(raw::__pcap_setmintocopy::Context);
327
328    #[cfg(any(libpcap_1_5_0, windows))]
329    fn immediate_mode_expect(pcap: *mut raw::pcap_t) -> ImmediateModeExpect {
330        #[cfg(libpcap_1_5_0)]
331        {
332            let ctx = raw::pcap_set_immediate_mode_context();
333            ctx.checkpoint();
334            ctx.expect()
335                .withf_st(move |arg1, _| *arg1 == pcap)
336                .return_once(|_, _| 0);
337            ImmediateModeExpect(ctx)
338        }
339        #[cfg(all(windows, not(libpcap_1_5_0)))]
340        {
341            let ctx = raw::pcap_setmintocopy_context();
342            ctx.checkpoint();
343            ctx.expect()
344                .withf_st(move |arg1, _| *arg1 == pcap)
345                .return_once(|_, _| 0);
346            ImmediateModeExpect(ctx)
347        }
348    }
349
350    #[test]
351    #[cfg(any(libpcap_1_5_0, windows))]
352    fn test_immediate_mode() {
353        let _m = RAWMTX.lock();
354
355        let mut dummy: isize = 777;
356        let pcap = as_pcap_t(&mut dummy);
357
358        let test_capture = test_capture::<Inactive>(pcap);
359        let capture = test_capture.capture;
360
361        let _ctx = immediate_mode_expect(pcap);
362        let capture = capture.immediate_mode(true);
363
364        let _ctx = immediate_mode_expect(pcap);
365        let _capture = capture.immediate_mode(false);
366    }
367
368    #[test]
369    #[cfg(all(libpcap_1_5_3, target_os = "macos"))]
370    fn test_want_pktap() {
371        let _m = RAWMTX.lock();
372
373        let mut dummy: isize = 777;
374        let pcap = as_pcap_t(&mut dummy);
375
376        let test_capture = test_capture::<Inactive>(pcap);
377        let capture = test_capture.capture;
378
379        let ctx = raw::pcap_set_want_pktap_context();
380        ctx.expect()
381            .withf_st(move |arg1, _| *arg1 == pcap)
382            .return_once(|_, _| 0);
383        let _capture = capture.want_pktap(true);
384    }
385
386    #[test]
387    #[cfg(not(windows))]
388    fn test_rfmon() {
389        let _m = RAWMTX.lock();
390
391        let mut dummy: isize = 777;
392        let pcap = as_pcap_t(&mut dummy);
393
394        let test_capture = test_capture::<Inactive>(pcap);
395        let capture = test_capture.capture;
396
397        let ctx = raw::pcap_set_rfmon_context();
398        ctx.expect()
399            .withf_st(move |arg1, _| *arg1 == pcap)
400            .return_once(|_, _| 0);
401
402        let _capture = capture.rfmon(true);
403    }
404
405    #[test]
406    fn test_buffer_size() {
407        let _m = RAWMTX.lock();
408
409        let mut dummy: isize = 777;
410        let pcap = as_pcap_t(&mut dummy);
411
412        let test_capture = test_capture::<Inactive>(pcap);
413        let capture = test_capture.capture;
414
415        let ctx = raw::pcap_set_buffer_size_context();
416        ctx.expect()
417            .withf_st(move |arg1, _| *arg1 == pcap)
418            .return_once(|_, _| 0);
419
420        let _capture = capture.buffer_size(10);
421    }
422
423    #[test]
424    #[cfg(libpcap_1_5_0)]
425    fn test_precision() {
426        let _m = RAWMTX.lock();
427
428        let mut dummy: isize = 777;
429        let pcap = as_pcap_t(&mut dummy);
430
431        let test_capture = test_capture::<Inactive>(pcap);
432        let capture = test_capture.capture;
433
434        let ctx = raw::pcap_set_tstamp_precision_context();
435        ctx.expect()
436            .withf_st(move |arg1, _| *arg1 == pcap)
437            .return_once(|_, _| 0);
438
439        let _capture = capture.precision(Precision::Nano);
440    }
441
442    #[test]
443    fn test_snaplen() {
444        let _m = RAWMTX.lock();
445
446        let mut dummy: isize = 777;
447        let pcap = as_pcap_t(&mut dummy);
448
449        let test_capture = test_capture::<Inactive>(pcap);
450        let capture = test_capture.capture;
451
452        let ctx = raw::pcap_set_snaplen_context();
453        ctx.expect()
454            .withf_st(move |arg1, _| *arg1 == pcap)
455            .return_once(|_, _| 0);
456
457        let _capture = capture.snaplen(10);
458    }
459}