pcap/
raw.rs

1// GRCOV_EXCL_START
2#![allow(dead_code)]
3#![allow(non_camel_case_types)]
4
5use libc::{c_char, c_int, c_uchar, c_uint, c_ushort, sockaddr, timeval, FILE};
6
7#[cfg(test)]
8use mockall::automock;
9
10pub const PCAP_IF_LOOPBACK: u32 = 0x00000001;
11pub const PCAP_IF_UP: u32 = 0x00000002;
12pub const PCAP_IF_RUNNING: u32 = 0x00000004;
13pub const PCAP_IF_WIRELESS: u32 = 0x00000008;
14pub const PCAP_IF_CONNECTION_STATUS: u32 = 0x00000030;
15pub const PCAP_IF_CONNECTION_STATUS_UNKNOWN: u32 = 0x00000000;
16pub const PCAP_IF_CONNECTION_STATUS_CONNECTED: u32 = 0x00000010;
17pub const PCAP_IF_CONNECTION_STATUS_DISCONNECTED: u32 = 0x00000020;
18pub const PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: u32 = 0x00000030;
19
20#[repr(C)]
21#[derive(Copy, Clone)]
22pub struct bpf_program {
23    pub bf_len: c_uint,
24    pub bf_insns: *mut bpf_insn,
25}
26
27#[repr(C)]
28#[derive(Copy, Clone)]
29pub struct bpf_insn {
30    pub code: c_ushort,
31    pub jt: c_uchar,
32    pub jf: c_uchar,
33    pub k: c_uint,
34}
35
36pub enum pcap_t {}
37
38pub enum pcap_dumper_t {}
39
40#[repr(C)]
41#[derive(Copy, Clone)]
42pub struct pcap_file_header {
43    pub magic: c_uint,
44    pub version_major: c_ushort,
45    pub version_minor: c_ushort,
46    pub thiszone: c_int,
47    pub sigfigs: c_uint,
48    pub snaplen: c_uint,
49    pub linktype: c_uint,
50}
51
52pub type pcap_direction_t = c_uint;
53
54pub const PCAP_D_INOUT: pcap_direction_t = 0;
55pub const PCAP_D_IN: pcap_direction_t = 1;
56pub const PCAP_D_OUT: pcap_direction_t = 2;
57
58#[repr(C)]
59#[derive(Copy, Clone)]
60pub struct pcap_pkthdr {
61    pub ts: timeval,
62    pub caplen: c_uint,
63    pub len: c_uint,
64}
65
66#[repr(C)]
67#[derive(Copy, Clone)]
68pub struct pcap_stat {
69    pub ps_recv: c_uint,
70    pub ps_drop: c_uint,
71    pub ps_ifdrop: c_uint,
72}
73
74#[repr(C)]
75#[derive(Copy, Clone)]
76pub struct pcap_if_t {
77    pub next: *mut pcap_if_t,
78    pub name: *mut c_char,
79    pub description: *mut c_char,
80    pub addresses: *mut pcap_addr_t,
81    pub flags: c_uint,
82}
83
84#[repr(C)]
85#[derive(Copy, Clone)]
86pub struct pcap_addr_t {
87    pub next: *mut pcap_addr_t,
88    pub addr: *mut sockaddr,
89    pub netmask: *mut sockaddr,
90    pub broadaddr: *mut sockaddr,
91    pub dstaddr: *mut sockaddr,
92}
93
94#[cfg(windows)]
95#[repr(C)]
96#[derive(Copy, Clone)]
97pub struct pcap_send_queue {
98    pub maxlen: c_uint,
99    pub len: c_uint,
100    pub buffer: *mut c_char,
101}
102
103// This is not Option<fn>, pcap functions do not check if the handler is null so it is wrong to
104// pass them Option::<fn>::None.
105pub type pcap_handler =
106    extern "C" fn(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar) -> ();
107
108#[cfg_attr(test, automock)]
109pub mod ffi {
110    use super::*;
111
112    extern "C" {
113        // [OBSOLETE] pub fn pcap_lookupdev(arg1: *mut c_char) -> *mut c_char;
114        // pub fn pcap_lookupnet(arg1: *const c_char, arg2: *mut c_uint, arg3: *mut c_uint,
115        //                       arg4: *mut c_char) -> c_int;
116        pub fn pcap_create(arg1: *const c_char, arg2: *mut c_char) -> *mut pcap_t;
117        pub fn pcap_set_snaplen(arg1: *mut pcap_t, arg2: c_int) -> c_int;
118        pub fn pcap_set_promisc(arg1: *mut pcap_t, arg2: c_int) -> c_int;
119        // pub fn pcap_can_set_rfmon(arg1: *mut pcap_t) -> c_int;
120        pub fn pcap_set_timeout(arg1: *mut pcap_t, arg2: c_int) -> c_int;
121        pub fn pcap_set_buffer_size(arg1: *mut pcap_t, arg2: c_int) -> c_int;
122        pub fn pcap_activate(arg1: *mut pcap_t) -> c_int;
123        // pub fn pcap_open_live(arg1: *const c_char, arg2: c_int, arg3: c_int, arg4: c_int,
124        //                       arg5: *mut c_char) -> *mut pcap_t;
125        pub fn pcap_open_dead(arg1: c_int, arg2: c_int) -> *mut pcap_t;
126        pub fn pcap_open_offline(arg1: *const c_char, arg2: *mut c_char) -> *mut pcap_t;
127        pub fn pcap_fopen_offline(arg1: *mut FILE, arg2: *mut c_char) -> *mut pcap_t;
128        pub fn pcap_close(arg1: *mut pcap_t);
129        pub fn pcap_loop(
130            arg1: *mut pcap_t,
131            arg2: c_int,
132            arg3: pcap_handler,
133            arg4: *mut c_uchar,
134        ) -> c_int;
135        // pub fn pcap_dispatch(arg1: *mut pcap_t, arg2: c_int, arg3: pcap_handler,
136        //                      arg4: *mut c_uchar)-> c_int;
137        // pub fn pcap_next(arg1: *mut pcap_t, arg2: *mut pcap_pkthdr) -> *const c_uchar;
138        pub fn pcap_next_ex(
139            arg1: *mut pcap_t,
140            arg2: *mut *mut pcap_pkthdr,
141            arg3: *mut *const c_uchar,
142        ) -> c_int;
143        pub fn pcap_breakloop(arg1: *mut pcap_t);
144        pub fn pcap_stats(arg1: *mut pcap_t, arg2: *mut pcap_stat) -> c_int;
145        pub fn pcap_setfilter(arg1: *mut pcap_t, arg2: *mut bpf_program) -> c_int;
146        pub fn pcap_setdirection(arg1: *mut pcap_t, arg2: pcap_direction_t) -> c_int;
147        // pub fn pcap_getnonblock(arg1: *mut pcap_t, arg2: *mut c_char) -> c_int;
148        pub fn pcap_setnonblock(arg1: *mut pcap_t, arg2: c_int, arg3: *mut c_char) -> c_int;
149        pub fn pcap_sendpacket(arg1: *mut pcap_t, arg2: *const c_uchar, arg3: c_int) -> c_int;
150        // pub fn pcap_statustostr(arg1: c_int) -> *const c_char;
151        // pub fn pcap_strerror(arg1: c_int) -> *const c_char;
152        pub fn pcap_geterr(arg1: *mut pcap_t) -> *mut c_char;
153        // pub fn pcap_perror(arg1: *mut pcap_t, arg2: *mut c_char);
154        pub fn pcap_compile(
155            arg1: *mut pcap_t,
156            arg2: *mut bpf_program,
157            arg3: *const c_char,
158            arg4: c_int,
159            arg5: c_uint,
160        ) -> c_int;
161        // pub fn pcap_compile_nopcap(arg1: c_int, arg2: c_int, arg3: *mut bpf_program,
162        //                            arg4: *const c_char, arg5: c_int, arg6: c_uint) -> c_int;
163        pub fn pcap_freecode(arg1: *mut bpf_program);
164        pub fn pcap_offline_filter(
165            arg1: *const bpf_program,
166            arg2: *const pcap_pkthdr,
167            arg3: *const c_uchar,
168        ) -> c_int;
169        pub fn pcap_datalink(arg1: *mut pcap_t) -> c_int;
170        // pub fn pcap_datalink_ext(arg1: *mut pcap_t) -> c_int;
171        pub fn pcap_list_datalinks(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int;
172        pub fn pcap_set_datalink(arg1: *mut pcap_t, arg2: c_int) -> c_int;
173        pub fn pcap_free_datalinks(arg1: *mut c_int);
174        pub fn pcap_datalink_name_to_val(arg1: *const c_char) -> c_int;
175        pub fn pcap_datalink_val_to_name(arg1: c_int) -> *const c_char;
176        pub fn pcap_datalink_val_to_description(arg1: c_int) -> *const c_char;
177        // pub fn pcap_snapshot(arg1: *mut pcap_t) -> c_int;
178        // pub fn pcap_is_swapped(arg1: *mut pcap_t) -> c_int;
179        pub fn pcap_major_version(arg1: *mut pcap_t) -> c_int;
180        pub fn pcap_minor_version(arg1: *mut pcap_t) -> c_int;
181        // pub fn pcap_file(arg1: *mut pcap_t) -> *mut FILE;
182        pub fn pcap_fileno(arg1: *mut pcap_t) -> c_int;
183        pub fn pcap_dump_open(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t;
184        pub fn pcap_dump_fopen(arg1: *mut pcap_t, fp: *mut FILE) -> *mut pcap_dumper_t;
185        // pub fn pcap_dump_file(arg1: *mut pcap_dumper_t) -> *mut FILE;
186        // pub fn pcap_dump_ftell(arg1: *mut pcap_dumper_t) -> c_long;
187        pub fn pcap_dump_flush(arg1: *mut pcap_dumper_t) -> c_int;
188        pub fn pcap_dump_close(arg1: *mut pcap_dumper_t);
189        pub fn pcap_dump(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar);
190        pub fn pcap_findalldevs(arg1: *mut *mut pcap_if_t, arg2: *mut c_char) -> c_int;
191        pub fn pcap_freealldevs(arg1: *mut pcap_if_t);
192        // pub fn pcap_lib_version() -> *const c_char;
193        // pub fn bpf_image(arg1: *const bpf_insn, arg2: c_int) -> *mut c_char;
194        // pub fn bpf_dump(arg1: *const bpf_program, arg2: c_int);
195        pub fn pcap_get_selectable_fd(arg1: *mut pcap_t) -> c_int;
196    }
197
198    #[cfg(libpcap_1_2_1)]
199    extern "C" {
200        // pub fn pcap_free_tstamp_types(arg1: *mut c_int) -> ();
201        // pub fn pcap_list_tstamp_types(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int;
202        // pub fn pcap_tstamp_type_name_to_val(arg1: *const c_char) -> c_int;
203        // pub fn pcap_tstamp_type_val_to_description(arg1: c_int) -> *const c_char;
204        // pub fn pcap_tstamp_type_val_to_name(arg1: c_int) -> *const c_char;
205        pub fn pcap_set_tstamp_type(arg1: *mut pcap_t, arg2: c_int) -> c_int;
206    }
207
208    #[cfg(libpcap_1_5_0)]
209    extern "C" {
210        pub fn pcap_fopen_offline_with_tstamp_precision(
211            arg1: *mut FILE,
212            arg2: c_uint,
213            arg3: *mut c_char,
214        ) -> *mut pcap_t;
215        // pub fn pcap_get_tstamp_precision(arg1: *mut pcap_t) -> c_int;
216        pub fn pcap_open_dead_with_tstamp_precision(
217            arg1: c_int,
218            arg2: c_int,
219            arg3: c_uint,
220        ) -> *mut pcap_t;
221        pub fn pcap_open_offline_with_tstamp_precision(
222            arg1: *const c_char,
223            arg2: c_uint,
224            arg3: *mut c_char,
225        ) -> *mut pcap_t;
226        pub fn pcap_set_immediate_mode(arg1: *mut pcap_t, arg2: c_int) -> c_int;
227        pub fn pcap_set_tstamp_precision(arg1: *mut pcap_t, arg2: c_int) -> c_int;
228    }
229
230    #[cfg(libpcap_1_7_2)]
231    extern "C" {
232        pub fn pcap_dump_open_append(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t;
233    }
234
235    #[cfg(libpcap_1_9_0)]
236    extern "C" {
237        // pcap_bufsize
238        // pcap_createsrcstr
239        // pcap_dump_ftell64
240        // pcap_findalldevs_ex
241        // pcap_get_required_select_timeout
242        // pcap_open
243        // pcap_parsesrcstr
244        // pcap_remoteact_accept
245        // pcap_remoteact_cleanup
246        // pcap_remoteact_close
247        // pcap_remoteact_list
248        // pcap_set_protocol_linux
249        // pcap_setsampling
250    }
251
252    #[cfg(libpcap_1_9_1)]
253    extern "C" {
254        // pcap_datalink_val_to_description_or_dlt
255    }
256}
257
258#[cfg(not(windows))]
259#[cfg_attr(test, automock)]
260pub mod ffi_unix {
261    use super::*;
262
263    #[link(name = "pcap")]
264    extern "C" {
265        // pub fn pcap_inject(arg1: *mut pcap_t, arg2: *const c_void, arg3: size_t) -> c_int;
266        pub fn pcap_set_rfmon(arg1: *mut pcap_t, arg2: c_int) -> c_int;
267    }
268}
269
270#[cfg(target_os = "macos")]
271#[cfg_attr(test, automock)]
272pub mod ffi_macos {
273    use super::*;
274
275    #[cfg(libpcap_1_5_3)]
276    extern "C" {
277        pub fn pcap_set_want_pktap(arg1: *mut pcap_t, arg2: c_int) -> c_int;
278    }
279}
280
281#[cfg(windows)]
282#[cfg_attr(test, automock)]
283pub mod ffi_windows {
284    use windows_sys::Win32::Foundation::HANDLE;
285
286    use super::*;
287
288    pub const WINPCAP_MINTOCOPY_DEFAULT: c_int = 16000;
289
290    #[link(name = "wpcap")]
291    extern "C" {
292        pub fn pcap_setmintocopy(arg1: *mut pcap_t, arg2: c_int) -> c_int;
293        pub fn pcap_getevent(p: *mut pcap_t) -> HANDLE;
294        pub fn pcap_sendqueue_alloc(memsize: c_uint) -> *mut pcap_send_queue;
295        pub fn pcap_sendqueue_destroy(queue: *mut pcap_send_queue);
296        pub fn pcap_sendqueue_queue(
297            queue: *mut pcap_send_queue,
298            pkt_header: *const pcap_pkthdr,
299            pkt_data: *const c_uchar,
300        ) -> c_int;
301        pub fn pcap_sendqueue_transmit(
302            p: *mut pcap_t,
303            queue: *mut pcap_send_queue,
304            sync: c_int,
305        ) -> c_uint;
306    }
307}
308
309// The conventional solution is to use `mockall_double`. However, automock's requirement for an
310// inner module would require changing the imports in all the files using this module. This approach
311// allows all the other modules to keep using the `raw` module as before.
312#[cfg(not(test))]
313pub use ffi::*;
314
315#[cfg(not(test))]
316#[cfg(not(windows))]
317pub use ffi_unix::*;
318
319#[cfg(not(test))]
320#[cfg(target_os = "macos")]
321pub use ffi_macos::*;
322
323#[cfg(not(test))]
324#[cfg(windows)]
325pub use ffi_windows::*;
326
327#[cfg(test)]
328pub use mock_ffi::*;
329
330#[cfg(test)]
331#[cfg(not(windows))]
332pub use mock_ffi_unix::*;
333
334#[cfg(test)]
335#[cfg(target_os = "macos")]
336pub use mock_ffi_macos::*;
337
338#[cfg(test)]
339#[cfg(windows)]
340pub use mock_ffi_windows::*;
341
342#[cfg(test)]
343pub mod testmod {
344    use std::{ffi::CString, sync::Mutex};
345
346    use once_cell::sync::Lazy;
347
348    use super::*;
349
350    pub struct GeterrContext(__pcap_geterr::Context);
351
352    // Must be acquired by any test using mock FFI.
353    pub static RAWMTX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
354
355    pub fn as_pcap_t<T: ?Sized>(value: &mut T) -> *mut pcap_t {
356        value as *mut T as *mut pcap_t
357    }
358
359    pub fn as_pcap_dumper_t<T: ?Sized>(value: &mut T) -> *mut pcap_dumper_t {
360        value as *mut T as *mut pcap_dumper_t
361    }
362
363    pub fn geterr_expect(pcap: *mut pcap_t) -> GeterrContext {
364        // Lock must be acquired by caller.
365        assert!(RAWMTX.try_lock().is_err());
366
367        let err = CString::new("oh oh").unwrap();
368        let ctx = pcap_geterr_context();
369        ctx.checkpoint();
370        ctx.expect()
371            .withf_st(move |arg1| *arg1 == pcap)
372            .return_once_st(|_| err.into_raw());
373
374        GeterrContext(ctx)
375    }
376}
377// GRCOV_EXCL_STOP