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

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

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

            
10
// The values have never changed; libpcap has only ever appended to them, so a version that
11
// predates one of these never returns it.
12
pub const PCAP_WARNING: c_int = 1;
13
pub const PCAP_WARNING_PROMISC_NOTSUP: c_int = 2;
14
pub const PCAP_WARNING_TSTAMP_TYPE_NOTSUP: c_int = 3;
15

            
16
pub const PCAP_ERROR: c_int = -1;
17
pub const PCAP_ERROR_BREAK: c_int = -2;
18
pub const PCAP_ERROR_NOT_ACTIVATED: c_int = -3;
19
pub const PCAP_ERROR_ACTIVATED: c_int = -4;
20
pub const PCAP_ERROR_NO_SUCH_DEVICE: c_int = -5;
21
pub const PCAP_ERROR_RFMON_NOTSUP: c_int = -6;
22
pub const PCAP_ERROR_NOT_RFMON: c_int = -7;
23
pub const PCAP_ERROR_PERM_DENIED: c_int = -8;
24
pub const PCAP_ERROR_IFACE_NOT_UP: c_int = -9;
25
pub const PCAP_ERROR_CANTSET_TSTAMP_TYPE: c_int = -10;
26
pub const PCAP_ERROR_PROMISC_PERM_DENIED: c_int = -11;
27
pub const PCAP_ERROR_TSTAMP_PRECISION_NOTSUP: c_int = -12;
28
pub const PCAP_ERROR_CAPTURE_NOTSUP: c_int = -13;
29

            
30
pub const PCAP_IF_LOOPBACK: u32 = 0x00000001;
31
pub const PCAP_IF_UP: u32 = 0x00000002;
32
pub const PCAP_IF_RUNNING: u32 = 0x00000004;
33
pub const PCAP_IF_WIRELESS: u32 = 0x00000008;
34
pub const PCAP_IF_CONNECTION_STATUS: u32 = 0x00000030;
35
pub const PCAP_IF_CONNECTION_STATUS_UNKNOWN: u32 = 0x00000000;
36
pub const PCAP_IF_CONNECTION_STATUS_CONNECTED: u32 = 0x00000010;
37
pub const PCAP_IF_CONNECTION_STATUS_DISCONNECTED: u32 = 0x00000020;
38
pub const PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: u32 = 0x00000030;
39

            
40
pub const PCAP_CHAR_ENC_LOCAL: u32 = 0x00000000;
41
pub const PCAP_CHAR_ENC_UTF_8: u32 = 0x00000001;
42

            
43
#[repr(C)]
44
#[derive(Copy, Clone)]
45
pub struct bpf_program {
46
    pub bf_len: c_uint,
47
    pub bf_insns: *mut bpf_insn,
48
}
49

            
50
#[repr(C)]
51
#[derive(Copy, Clone)]
52
pub struct bpf_insn {
53
    pub code: c_ushort,
54
    pub jt: c_uchar,
55
    pub jf: c_uchar,
56
    pub k: c_uint,
57
}
58

            
59
pub enum pcap_t {}
60

            
61
pub enum pcap_dumper_t {}
62

            
63
#[repr(C)]
64
#[derive(Copy, Clone)]
65
pub struct pcap_file_header {
66
    pub magic: c_uint,
67
    pub version_major: c_ushort,
68
    pub version_minor: c_ushort,
69
    pub thiszone: c_int,
70
    pub sigfigs: c_uint,
71
    pub snaplen: c_uint,
72
    pub linktype: c_uint,
73
}
74

            
75
pub type pcap_direction_t = c_uint;
76

            
77
pub const PCAP_D_INOUT: pcap_direction_t = 0;
78
pub const PCAP_D_IN: pcap_direction_t = 1;
79
pub const PCAP_D_OUT: pcap_direction_t = 2;
80

            
81
#[repr(C)]
82
#[derive(Copy, Clone)]
83
pub struct pcap_pkthdr {
84
    pub ts: timeval,
85
    pub caplen: c_uint,
86
    pub len: c_uint,
87
}
88

            
89
#[repr(C)]
90
#[derive(Copy, Clone)]
91
pub struct pcap_stat {
92
    pub ps_recv: c_uint,
93
    pub ps_drop: c_uint,
94
    pub ps_ifdrop: c_uint,
95
}
96

            
97
#[repr(C)]
98
#[derive(Copy, Clone)]
99
pub struct pcap_if_t {
100
    pub next: *mut pcap_if_t,
101
    pub name: *mut c_char,
102
    pub description: *mut c_char,
103
    pub addresses: *mut pcap_addr_t,
104
    pub flags: c_uint,
105
}
106

            
107
#[repr(C)]
108
#[derive(Copy, Clone)]
109
pub struct pcap_addr_t {
110
    pub next: *mut pcap_addr_t,
111
    pub addr: *mut sockaddr,
112
    pub netmask: *mut sockaddr,
113
    pub broadaddr: *mut sockaddr,
114
    pub dstaddr: *mut sockaddr,
115
}
116

            
117
#[cfg(windows)]
118
#[repr(C)]
119
#[derive(Copy, Clone)]
120
pub struct pcap_send_queue {
121
    pub maxlen: c_uint,
122
    pub len: c_uint,
123
    pub buffer: *mut c_char,
124
}
125

            
126
// This is not Option<fn>, pcap functions do not check if the handler is null so it is wrong to
127
// pass them Option::<fn>::None.
128
pub type pcap_handler =
129
    extern "C" fn(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar) -> ();
130

            
131
#[cfg_attr(test, automock)]
132
pub mod ffi {
133
    use libc::FILE;
134

            
135
    use super::*;
136

            
137
    unsafe extern "C" {
138
        // [OBSOLETE] pub fn pcap_lookupdev(arg1: *mut c_char) -> *mut c_char;
139
        // pub fn pcap_lookupnet(arg1: *const c_char, arg2: *mut c_uint, arg3: *mut c_uint,
140
        //                       arg4: *mut c_char) -> c_int;
141
        pub fn pcap_create(arg1: *const c_char, arg2: *mut c_char) -> *mut pcap_t;
142
        pub fn pcap_set_snaplen(arg1: *mut pcap_t, arg2: c_int) -> c_int;
143
        pub fn pcap_set_promisc(arg1: *mut pcap_t, arg2: c_int) -> c_int;
144
        // pub fn pcap_can_set_rfmon(arg1: *mut pcap_t) -> c_int;
145
        pub fn pcap_set_timeout(arg1: *mut pcap_t, arg2: c_int) -> c_int;
146
        pub fn pcap_set_buffer_size(arg1: *mut pcap_t, arg2: c_int) -> c_int;
147
        pub fn pcap_activate(arg1: *mut pcap_t) -> c_int;
148
        // pub fn pcap_open_live(arg1: *const c_char, arg2: c_int, arg3: c_int, arg4: c_int,
149
        //                       arg5: *mut c_char) -> *mut pcap_t;
150
        pub fn pcap_open_dead(arg1: c_int, arg2: c_int) -> *mut pcap_t;
151
        pub fn pcap_open_offline(arg1: *const c_char, arg2: *mut c_char) -> *mut pcap_t;
152
        pub fn pcap_close(arg1: *mut pcap_t);
153
        pub fn pcap_loop(
154
            arg1: *mut pcap_t,
155
            arg2: c_int,
156
            arg3: pcap_handler,
157
            arg4: *mut c_uchar,
158
        ) -> c_int;
159
        pub fn pcap_dispatch(
160
            arg1: *mut pcap_t,
161
            arg2: c_int,
162
            arg3: pcap_handler,
163
            arg4: *mut c_uchar,
164
        ) -> c_int;
165
        // pub fn pcap_next(arg1: *mut pcap_t, arg2: *mut pcap_pkthdr) -> *const c_uchar;
166
        pub fn pcap_next_ex(
167
            arg1: *mut pcap_t,
168
            arg2: *mut *mut pcap_pkthdr,
169
            arg3: *mut *const c_uchar,
170
        ) -> c_int;
171
        pub fn pcap_breakloop(arg1: *mut pcap_t);
172
        pub fn pcap_stats(arg1: *mut pcap_t, arg2: *mut pcap_stat) -> c_int;
173
        pub fn pcap_setfilter(arg1: *mut pcap_t, arg2: *mut bpf_program) -> c_int;
174
        pub fn pcap_setdirection(arg1: *mut pcap_t, arg2: pcap_direction_t) -> c_int;
175
        // pub fn pcap_getnonblock(arg1: *mut pcap_t, arg2: *mut c_char) -> c_int;
176
        pub fn pcap_setnonblock(arg1: *mut pcap_t, arg2: c_int, arg3: *mut c_char) -> c_int;
177
        pub fn pcap_sendpacket(arg1: *mut pcap_t, arg2: *const c_uchar, arg3: c_int) -> c_int;
178
        // pub fn pcap_statustostr(arg1: c_int) -> *const c_char;
179
        // pub fn pcap_strerror(arg1: c_int) -> *const c_char;
180
        pub fn pcap_geterr(arg1: *mut pcap_t) -> *mut c_char;
181
        // pub fn pcap_perror(arg1: *mut pcap_t, arg2: *mut c_char);
182
        pub fn pcap_compile(
183
            arg1: *mut pcap_t,
184
            arg2: *mut bpf_program,
185
            arg3: *const c_char,
186
            arg4: c_int,
187
            arg5: c_uint,
188
        ) -> c_int;
189
        // pub fn pcap_compile_nopcap(arg1: c_int, arg2: c_int, arg3: *mut bpf_program,
190
        //                            arg4: *const c_char, arg5: c_int, arg6: c_uint) -> c_int;
191
        pub fn pcap_freecode(arg1: *mut bpf_program);
192
        pub fn pcap_offline_filter(
193
            arg1: *const bpf_program,
194
            arg2: *const pcap_pkthdr,
195
            arg3: *const c_uchar,
196
        ) -> c_int;
197
        pub fn pcap_datalink(arg1: *mut pcap_t) -> c_int;
198
        // pub fn pcap_datalink_ext(arg1: *mut pcap_t) -> c_int;
199
        pub fn pcap_list_datalinks(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int;
200
        pub fn pcap_set_datalink(arg1: *mut pcap_t, arg2: c_int) -> c_int;
201
        pub fn pcap_free_datalinks(arg1: *mut c_int);
202
        pub fn pcap_datalink_name_to_val(arg1: *const c_char) -> c_int;
203
        pub fn pcap_datalink_val_to_name(arg1: c_int) -> *const c_char;
204
        pub fn pcap_datalink_val_to_description(arg1: c_int) -> *const c_char;
205
        pub fn pcap_snapshot(arg1: *mut pcap_t) -> c_int;
206
        // pub fn pcap_is_swapped(arg1: *mut pcap_t) -> c_int;
207
        pub fn pcap_major_version(arg1: *mut pcap_t) -> c_int;
208
        pub fn pcap_minor_version(arg1: *mut pcap_t) -> c_int;
209
        // The one FILE * entry point that is not a macro on Windows. What it points at belongs
210
        // to whichever C runtime libpcap was linked against, so only ever compare it to null.
211
        pub fn pcap_file(arg1: *mut pcap_t) -> *mut FILE;
212
        pub fn pcap_fileno(arg1: *mut pcap_t) -> c_int;
213
        pub fn pcap_dump_open(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t;
214
        pub fn pcap_dump_ftell(arg1: *mut pcap_dumper_t) -> c_long;
215
        pub fn pcap_dump_flush(arg1: *mut pcap_dumper_t) -> c_int;
216
        pub fn pcap_dump_close(arg1: *mut pcap_dumper_t);
217
        pub fn pcap_dump(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar);
218
        pub fn pcap_findalldevs(arg1: *mut *mut pcap_if_t, arg2: *mut c_char) -> c_int;
219
        pub fn pcap_freealldevs(arg1: *mut pcap_if_t);
220
        // pub fn pcap_lib_version() -> *const c_char;
221
        // pub fn bpf_image(arg1: *const bpf_insn, arg2: c_int) -> *mut c_char;
222
        // pub fn bpf_dump(arg1: *const bpf_program, arg2: c_int);
223
    }
224

            
225
    #[cfg(libpcap_1_2_1)]
226
    unsafe extern "C" {
227
        // pub fn pcap_free_tstamp_types(arg1: *mut c_int) -> ();
228
        // pub fn pcap_list_tstamp_types(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int;
229
        // pub fn pcap_tstamp_type_name_to_val(arg1: *const c_char) -> c_int;
230
        // pub fn pcap_tstamp_type_val_to_description(arg1: c_int) -> *const c_char;
231
        // pub fn pcap_tstamp_type_val_to_name(arg1: c_int) -> *const c_char;
232
        pub fn pcap_set_tstamp_type(arg1: *mut pcap_t, arg2: c_int) -> c_int;
233
    }
234

            
235
    #[cfg(libpcap_1_5_0)]
236
    unsafe extern "C" {
237
        // pub fn pcap_get_tstamp_precision(arg1: *mut pcap_t) -> c_int;
238
        pub fn pcap_open_dead_with_tstamp_precision(
239
            arg1: c_int,
240
            arg2: c_int,
241
            arg3: c_uint,
242
        ) -> *mut pcap_t;
243
        pub fn pcap_open_offline_with_tstamp_precision(
244
            arg1: *const c_char,
245
            arg2: c_uint,
246
            arg3: *mut c_char,
247
        ) -> *mut pcap_t;
248
        pub fn pcap_set_immediate_mode(arg1: *mut pcap_t, arg2: c_int) -> c_int;
249
        pub fn pcap_set_tstamp_precision(arg1: *mut pcap_t, arg2: c_int) -> c_int;
250
    }
251

            
252
    #[cfg(libpcap_1_7_2)]
253
    unsafe extern "C" {
254
        pub fn pcap_dump_open_append(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t;
255
    }
256

            
257
    #[cfg(libpcap_1_9_0)]
258
    unsafe extern "C" {
259
        // pcap_bufsize
260
        // pcap_createsrcstr
261
        pub fn pcap_dump_ftell64(arg1: *mut pcap_dumper_t) -> i64;
262
        // pcap_findalldevs_ex
263
        // pcap_get_required_select_timeout
264
        // pcap_open
265
        // pcap_parsesrcstr
266
        // pcap_remoteact_accept
267
        // pcap_remoteact_cleanup
268
        // pcap_remoteact_close
269
        // pcap_remoteact_list
270
        // pcap_set_protocol_linux
271
        // pcap_setsampling
272
    }
273

            
274
    #[cfg(libpcap_1_9_1)]
275
    unsafe extern "C" {
276
        // pcap_datalink_val_to_description_or_dlt
277
    }
278

            
279
    #[cfg(libpcap_1_10_0)]
280
    unsafe extern "C" {
281
        pub fn pcap_init(arg1: c_uint, arg2: *mut c_char) -> c_int;
282
        // pcap_remoteact_accept_ex
283
    }
284
}
285

            
286
#[cfg(not(windows))]
287
#[cfg_attr(test, automock)]
288
pub mod ffi_unix {
289
    use libc::FILE;
290

            
291
    use super::*;
292

            
293
    #[link(name = "pcap")]
294
    unsafe extern "C" {
295
        // pub fn pcap_inject(arg1: *mut pcap_t, arg2: *const c_void, arg3: size_t) -> c_int;
296
        pub fn pcap_set_rfmon(arg1: *mut pcap_t, arg2: c_int) -> c_int;
297
        pub fn pcap_get_selectable_fd(arg1: *mut pcap_t) -> c_int;
298
        // wpcap exports no FILE * entry points: libpcap may be linked against a different C
299
        // runtime than its caller. On Windows pcap.h defines these names as macros that pull
300
        // the OS handle out of the FILE * and call pcap_hopen_offline()/pcap_dump_hopen().
301
        pub fn pcap_fopen_offline(arg1: *mut FILE, arg2: *mut c_char) -> *mut pcap_t;
302
        pub fn pcap_dump_fopen(arg1: *mut pcap_t, fp: *mut FILE) -> *mut pcap_dumper_t;
303
        // wpcap does export this one, but the FILE * it hands back belongs to the C runtime
304
        // wpcap was linked against, which is not necessarily the caller's, so it is no more
305
        // usable on Windows than the entry points above.
306
        pub fn pcap_dump_file(arg1: *mut pcap_dumper_t) -> *mut FILE;
307
    }
308

            
309
    #[cfg(libpcap_1_5_0)]
310
    #[link(name = "pcap")]
311
    unsafe extern "C" {
312
        pub fn pcap_fopen_offline_with_tstamp_precision(
313
            arg1: *mut FILE,
314
            arg2: c_uint,
315
            arg3: *mut c_char,
316
        ) -> *mut pcap_t;
317
    }
318
}
319

            
320
#[cfg(target_os = "macos")]
321
#[cfg_attr(test, automock)]
322
pub mod ffi_macos {
323
    use super::*;
324

            
325
    #[cfg(libpcap_1_5_3)]
326
    unsafe extern "C" {
327
        pub fn pcap_set_want_pktap(arg1: *mut pcap_t, arg2: c_int) -> c_int;
328
    }
329
}
330

            
331
#[cfg(windows)]
332
#[cfg_attr(test, automock)]
333
pub mod ffi_windows {
334
    use windows_sys::Win32::Foundation::HANDLE;
335

            
336
    use super::*;
337

            
338
    pub const WINPCAP_MINTOCOPY_DEFAULT: c_int = 16000;
339

            
340
    #[link(name = "wpcap")]
341
    unsafe extern "C" {
342
        pub fn pcap_setmintocopy(arg1: *mut pcap_t, arg2: c_int) -> c_int;
343
        pub fn pcap_getevent(p: *mut pcap_t) -> HANDLE;
344
        pub fn pcap_sendqueue_alloc(memsize: c_uint) -> *mut pcap_send_queue;
345
        pub fn pcap_sendqueue_destroy(queue: *mut pcap_send_queue);
346
        pub fn pcap_sendqueue_queue(
347
            queue: *mut pcap_send_queue,
348
            pkt_header: *const pcap_pkthdr,
349
            pkt_data: *const c_uchar,
350
        ) -> c_int;
351
        pub fn pcap_sendqueue_transmit(
352
            p: *mut pcap_t,
353
            queue: *mut pcap_send_queue,
354
            sync: c_int,
355
        ) -> c_uint;
356
    }
357
}
358

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

            
365
#[cfg(not(test))]
366
#[cfg(not(windows))]
367
pub use ffi_unix::*;
368

            
369
#[cfg(not(test))]
370
#[cfg(target_os = "macos")]
371
pub use ffi_macos::*;
372

            
373
#[cfg(not(test))]
374
#[cfg(windows)]
375
pub use ffi_windows::*;
376

            
377
#[cfg(test)]
378
pub use mock_ffi::*;
379

            
380
#[cfg(test)]
381
#[cfg(not(windows))]
382
pub use mock_ffi_unix::*;
383

            
384
#[cfg(test)]
385
#[cfg(target_os = "macos")]
386
pub use mock_ffi_macos::*;
387

            
388
#[cfg(test)]
389
#[cfg(windows)]
390
pub use mock_ffi_windows::*;
391

            
392
#[cfg(test)]
393
pub mod testmod {
394
    use std::{ffi::CString, sync::Mutex};
395

            
396
    use once_cell::sync::Lazy;
397

            
398
    use super::*;
399

            
400
    pub struct GeterrContext(__pcap_geterr::Context);
401

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

            
405
    pub fn as_pcap_t<T: ?Sized>(value: &mut T) -> *mut pcap_t {
406
        value as *mut T as *mut pcap_t
407
    }
408

            
409
    pub fn as_pcap_dumper_t<T: ?Sized>(value: &mut T) -> *mut pcap_dumper_t {
410
        value as *mut T as *mut pcap_dumper_t
411
    }
412

            
413
    pub fn as_file<T: ?Sized>(value: &mut T) -> *mut libc::FILE {
414
        value as *mut T as *mut libc::FILE
415
    }
416

            
417
    pub fn geterr_expect(pcap: *mut pcap_t) -> GeterrContext {
418
        // Lock must be acquired by caller.
419
        assert!(RAWMTX.try_lock().is_err());
420

            
421
        let err = CString::new("oh oh").unwrap();
422
        let ctx = pcap_geterr_context();
423
        ctx.checkpoint();
424
        ctx.expect()
425
            .withf_st(move |arg1| *arg1 == pcap)
426
            .return_once_st(|_| err.into_raw());
427

            
428
        GeterrContext(ctx)
429
    }
430
}
431
// GRCOV_EXCL_STOP