1
// GRCOV_EXCL_START
2
#![allow(dead_code)]
3
#![allow(non_camel_case_types)]
4

            
5
use libc::{c_char, c_int, c_uchar, c_uint, c_ushort, sockaddr, timeval};
6

            
7
#[cfg(test)]
8
use mockall::automock;
9

            
10
pub const PCAP_IF_LOOPBACK: u32 = 0x00000001;
11
pub const PCAP_IF_UP: u32 = 0x00000002;
12
pub const PCAP_IF_RUNNING: u32 = 0x00000004;
13
pub const PCAP_IF_WIRELESS: u32 = 0x00000008;
14
pub const PCAP_IF_CONNECTION_STATUS: u32 = 0x00000030;
15
pub const PCAP_IF_CONNECTION_STATUS_UNKNOWN: u32 = 0x00000000;
16
pub const PCAP_IF_CONNECTION_STATUS_CONNECTED: u32 = 0x00000010;
17
pub const PCAP_IF_CONNECTION_STATUS_DISCONNECTED: u32 = 0x00000020;
18
pub const PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: u32 = 0x00000030;
19

            
20
#[repr(C)]
21
#[derive(Copy, Clone)]
22
pub 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)]
29
pub 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

            
36
pub enum pcap_t {}
37

            
38
pub enum pcap_dumper_t {}
39

            
40
#[repr(C)]
41
#[derive(Copy, Clone)]
42
pub 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

            
52
pub type pcap_direction_t = c_uint;
53

            
54
pub const PCAP_D_INOUT: pcap_direction_t = 0;
55
pub const PCAP_D_IN: pcap_direction_t = 1;
56
pub const PCAP_D_OUT: pcap_direction_t = 2;
57

            
58
#[repr(C)]
59
#[derive(Copy, Clone)]
60
pub 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)]
68
pub 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)]
76
pub 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)]
86
pub 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)]
97
pub 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.
105
pub 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)]
109
pub 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_close(arg1: *mut pcap_t);
128
        pub fn pcap_loop(
129
            arg1: *mut pcap_t,
130
            arg2: c_int,
131
            arg3: pcap_handler,
132
            arg4: *mut c_uchar,
133
        ) -> c_int;
134
        pub fn pcap_dispatch(
135
            arg1: *mut pcap_t,
136
            arg2: c_int,
137
            arg3: pcap_handler,
138
            arg4: *mut c_uchar,
139
        ) -> c_int;
140
        // pub fn pcap_next(arg1: *mut pcap_t, arg2: *mut pcap_pkthdr) -> *const c_uchar;
141
        pub fn pcap_next_ex(
142
            arg1: *mut pcap_t,
143
            arg2: *mut *mut pcap_pkthdr,
144
            arg3: *mut *const c_uchar,
145
        ) -> c_int;
146
        pub fn pcap_breakloop(arg1: *mut pcap_t);
147
        pub fn pcap_stats(arg1: *mut pcap_t, arg2: *mut pcap_stat) -> c_int;
148
        pub fn pcap_setfilter(arg1: *mut pcap_t, arg2: *mut bpf_program) -> c_int;
149
        pub fn pcap_setdirection(arg1: *mut pcap_t, arg2: pcap_direction_t) -> c_int;
150
        // pub fn pcap_getnonblock(arg1: *mut pcap_t, arg2: *mut c_char) -> c_int;
151
        pub fn pcap_setnonblock(arg1: *mut pcap_t, arg2: c_int, arg3: *mut c_char) -> c_int;
152
        pub fn pcap_sendpacket(arg1: *mut pcap_t, arg2: *const c_uchar, arg3: c_int) -> c_int;
153
        // pub fn pcap_statustostr(arg1: c_int) -> *const c_char;
154
        // pub fn pcap_strerror(arg1: c_int) -> *const c_char;
155
        pub fn pcap_geterr(arg1: *mut pcap_t) -> *mut c_char;
156
        // pub fn pcap_perror(arg1: *mut pcap_t, arg2: *mut c_char);
157
        pub fn pcap_compile(
158
            arg1: *mut pcap_t,
159
            arg2: *mut bpf_program,
160
            arg3: *const c_char,
161
            arg4: c_int,
162
            arg5: c_uint,
163
        ) -> c_int;
164
        // pub fn pcap_compile_nopcap(arg1: c_int, arg2: c_int, arg3: *mut bpf_program,
165
        //                            arg4: *const c_char, arg5: c_int, arg6: c_uint) -> c_int;
166
        pub fn pcap_freecode(arg1: *mut bpf_program);
167
        pub fn pcap_offline_filter(
168
            arg1: *const bpf_program,
169
            arg2: *const pcap_pkthdr,
170
            arg3: *const c_uchar,
171
        ) -> c_int;
172
        pub fn pcap_datalink(arg1: *mut pcap_t) -> c_int;
173
        // pub fn pcap_datalink_ext(arg1: *mut pcap_t) -> c_int;
174
        pub fn pcap_list_datalinks(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int;
175
        pub fn pcap_set_datalink(arg1: *mut pcap_t, arg2: c_int) -> c_int;
176
        pub fn pcap_free_datalinks(arg1: *mut c_int);
177
        pub fn pcap_datalink_name_to_val(arg1: *const c_char) -> c_int;
178
        pub fn pcap_datalink_val_to_name(arg1: c_int) -> *const c_char;
179
        pub fn pcap_datalink_val_to_description(arg1: c_int) -> *const c_char;
180
        // pub fn pcap_snapshot(arg1: *mut pcap_t) -> c_int;
181
        // pub fn pcap_is_swapped(arg1: *mut pcap_t) -> c_int;
182
        pub fn pcap_major_version(arg1: *mut pcap_t) -> c_int;
183
        pub fn pcap_minor_version(arg1: *mut pcap_t) -> c_int;
184
        // pub fn pcap_file(arg1: *mut pcap_t) -> *mut FILE;
185
        pub fn pcap_fileno(arg1: *mut pcap_t) -> c_int;
186
        pub fn pcap_dump_open(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t;
187
        // pub fn pcap_dump_file(arg1: *mut pcap_dumper_t) -> *mut FILE;
188
        // pub fn pcap_dump_ftell(arg1: *mut pcap_dumper_t) -> c_long;
189
        pub fn pcap_dump_flush(arg1: *mut pcap_dumper_t) -> c_int;
190
        pub fn pcap_dump_close(arg1: *mut pcap_dumper_t);
191
        pub fn pcap_dump(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar);
192
        pub fn pcap_findalldevs(arg1: *mut *mut pcap_if_t, arg2: *mut c_char) -> c_int;
193
        pub fn pcap_freealldevs(arg1: *mut pcap_if_t);
194
        // pub fn pcap_lib_version() -> *const c_char;
195
        // pub fn bpf_image(arg1: *const bpf_insn, arg2: c_int) -> *mut c_char;
196
        // pub fn bpf_dump(arg1: *const bpf_program, arg2: c_int);
197
    }
198

            
199
    #[cfg(libpcap_1_2_1)]
200
    extern "C" {
201
        // pub fn pcap_free_tstamp_types(arg1: *mut c_int) -> ();
202
        // pub fn pcap_list_tstamp_types(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int;
203
        // pub fn pcap_tstamp_type_name_to_val(arg1: *const c_char) -> c_int;
204
        // pub fn pcap_tstamp_type_val_to_description(arg1: c_int) -> *const c_char;
205
        // pub fn pcap_tstamp_type_val_to_name(arg1: c_int) -> *const c_char;
206
        pub fn pcap_set_tstamp_type(arg1: *mut pcap_t, arg2: c_int) -> c_int;
207
    }
208

            
209
    #[cfg(libpcap_1_5_0)]
210
    extern "C" {
211
        // pub fn pcap_get_tstamp_precision(arg1: *mut pcap_t) -> c_int;
212
        pub fn pcap_open_dead_with_tstamp_precision(
213
            arg1: c_int,
214
            arg2: c_int,
215
            arg3: c_uint,
216
        ) -> *mut pcap_t;
217
        pub fn pcap_open_offline_with_tstamp_precision(
218
            arg1: *const c_char,
219
            arg2: c_uint,
220
            arg3: *mut c_char,
221
        ) -> *mut pcap_t;
222
        pub fn pcap_set_immediate_mode(arg1: *mut pcap_t, arg2: c_int) -> c_int;
223
        pub fn pcap_set_tstamp_precision(arg1: *mut pcap_t, arg2: c_int) -> c_int;
224
    }
225

            
226
    #[cfg(libpcap_1_7_2)]
227
    extern "C" {
228
        pub fn pcap_dump_open_append(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t;
229
    }
230

            
231
    #[cfg(libpcap_1_9_0)]
232
    extern "C" {
233
        // pcap_bufsize
234
        // pcap_createsrcstr
235
        // pcap_dump_ftell64
236
        // pcap_findalldevs_ex
237
        // pcap_get_required_select_timeout
238
        // pcap_open
239
        // pcap_parsesrcstr
240
        // pcap_remoteact_accept
241
        // pcap_remoteact_cleanup
242
        // pcap_remoteact_close
243
        // pcap_remoteact_list
244
        // pcap_set_protocol_linux
245
        // pcap_setsampling
246
    }
247

            
248
    #[cfg(libpcap_1_9_1)]
249
    extern "C" {
250
        // pcap_datalink_val_to_description_or_dlt
251
    }
252

            
253
    #[cfg(libpcap_1_10_0)]
254
    extern "C" {
255
        // pcap_init
256
        // pcap_remoteact_accept_ex
257
    }
258
}
259

            
260
#[cfg(not(windows))]
261
#[cfg_attr(test, automock)]
262
pub mod ffi_unix {
263
    use libc::FILE;
264

            
265
    use super::*;
266

            
267
    #[link(name = "pcap")]
268
    extern "C" {
269
        // pub fn pcap_inject(arg1: *mut pcap_t, arg2: *const c_void, arg3: size_t) -> c_int;
270
        pub fn pcap_set_rfmon(arg1: *mut pcap_t, arg2: c_int) -> c_int;
271
        pub fn pcap_get_selectable_fd(arg1: *mut pcap_t) -> c_int;
272
        // wpcap exports no FILE * entry points: libpcap may be linked against a different C
273
        // runtime than its caller. On Windows pcap.h defines these names as macros that pull
274
        // the OS handle out of the FILE * and call pcap_hopen_offline()/pcap_dump_hopen().
275
        pub fn pcap_fopen_offline(arg1: *mut FILE, arg2: *mut c_char) -> *mut pcap_t;
276
        pub fn pcap_dump_fopen(arg1: *mut pcap_t, fp: *mut FILE) -> *mut pcap_dumper_t;
277
    }
278

            
279
    #[cfg(libpcap_1_5_0)]
280
    #[link(name = "pcap")]
281
    extern "C" {
282
        pub fn pcap_fopen_offline_with_tstamp_precision(
283
            arg1: *mut FILE,
284
            arg2: c_uint,
285
            arg3: *mut c_char,
286
        ) -> *mut pcap_t;
287
    }
288
}
289

            
290
#[cfg(target_os = "macos")]
291
#[cfg_attr(test, automock)]
292
pub mod ffi_macos {
293
    use super::*;
294

            
295
    #[cfg(libpcap_1_5_3)]
296
    extern "C" {
297
        pub fn pcap_set_want_pktap(arg1: *mut pcap_t, arg2: c_int) -> c_int;
298
    }
299
}
300

            
301
#[cfg(windows)]
302
#[cfg_attr(test, automock)]
303
pub mod ffi_windows {
304
    use windows_sys::Win32::Foundation::HANDLE;
305

            
306
    use super::*;
307

            
308
    pub const WINPCAP_MINTOCOPY_DEFAULT: c_int = 16000;
309

            
310
    #[link(name = "wpcap")]
311
    extern "C" {
312
        pub fn pcap_setmintocopy(arg1: *mut pcap_t, arg2: c_int) -> c_int;
313
        pub fn pcap_getevent(p: *mut pcap_t) -> HANDLE;
314
        pub fn pcap_sendqueue_alloc(memsize: c_uint) -> *mut pcap_send_queue;
315
        pub fn pcap_sendqueue_destroy(queue: *mut pcap_send_queue);
316
        pub fn pcap_sendqueue_queue(
317
            queue: *mut pcap_send_queue,
318
            pkt_header: *const pcap_pkthdr,
319
            pkt_data: *const c_uchar,
320
        ) -> c_int;
321
        pub fn pcap_sendqueue_transmit(
322
            p: *mut pcap_t,
323
            queue: *mut pcap_send_queue,
324
            sync: c_int,
325
        ) -> c_uint;
326
    }
327
}
328

            
329
// The conventional solution is to use `mockall_double`. However, automock's requirement for an
330
// inner module would require changing the imports in all the files using this module. This approach
331
// allows all the other modules to keep using the `raw` module as before.
332
#[cfg(not(test))]
333
pub use ffi::*;
334

            
335
#[cfg(not(test))]
336
#[cfg(not(windows))]
337
pub use ffi_unix::*;
338

            
339
#[cfg(not(test))]
340
#[cfg(target_os = "macos")]
341
pub use ffi_macos::*;
342

            
343
#[cfg(not(test))]
344
#[cfg(windows)]
345
pub use ffi_windows::*;
346

            
347
#[cfg(test)]
348
pub use mock_ffi::*;
349

            
350
#[cfg(test)]
351
#[cfg(not(windows))]
352
pub use mock_ffi_unix::*;
353

            
354
#[cfg(test)]
355
#[cfg(target_os = "macos")]
356
pub use mock_ffi_macos::*;
357

            
358
#[cfg(test)]
359
#[cfg(windows)]
360
pub use mock_ffi_windows::*;
361

            
362
#[cfg(test)]
363
pub mod testmod {
364
    use std::{ffi::CString, sync::Mutex};
365

            
366
    use once_cell::sync::Lazy;
367

            
368
    use super::*;
369

            
370
    pub struct GeterrContext(__pcap_geterr::Context);
371

            
372
    // Must be acquired by any test using mock FFI.
373
    pub static RAWMTX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
374

            
375
    pub fn as_pcap_t<T: ?Sized>(value: &mut T) -> *mut pcap_t {
376
        value as *mut T as *mut pcap_t
377
    }
378

            
379
    pub fn as_pcap_dumper_t<T: ?Sized>(value: &mut T) -> *mut pcap_dumper_t {
380
        value as *mut T as *mut pcap_dumper_t
381
    }
382

            
383
    pub fn geterr_expect(pcap: *mut pcap_t) -> GeterrContext {
384
        // Lock must be acquired by caller.
385
        assert!(RAWMTX.try_lock().is_err());
386

            
387
        let err = CString::new("oh oh").unwrap();
388
        let ctx = pcap_geterr_context();
389
        ctx.checkpoint();
390
        ctx.expect()
391
            .withf_st(move |arg1| *arg1 == pcap)
392
            .return_once_st(|_| err.into_raw());
393

            
394
        GeterrContext(ctx)
395
    }
396
}
397
// GRCOV_EXCL_STOP