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, FILE};
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_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)]
260
pub 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)]
272
pub 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)]
283
pub 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))]
313
pub use ffi::*;
314

            
315
#[cfg(not(test))]
316
#[cfg(not(windows))]
317
pub use ffi_unix::*;
318

            
319
#[cfg(not(test))]
320
#[cfg(target_os = "macos")]
321
pub use ffi_macos::*;
322

            
323
#[cfg(not(test))]
324
#[cfg(windows)]
325
pub use ffi_windows::*;
326

            
327
#[cfg(test)]
328
pub use mock_ffi::*;
329

            
330
#[cfg(test)]
331
#[cfg(not(windows))]
332
pub use mock_ffi_unix::*;
333

            
334
#[cfg(test)]
335
#[cfg(target_os = "macos")]
336
pub use mock_ffi_macos::*;
337

            
338
#[cfg(test)]
339
#[cfg(windows)]
340
pub use mock_ffi_windows::*;
341

            
342
#[cfg(test)]
343
pub 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