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(windows)]
271
#[cfg_attr(test, automock)]
272
pub mod ffi_windows {
273
    use windows_sys::Win32::Foundation::HANDLE;
274

            
275
    use super::*;
276

            
277
    pub const WINPCAP_MINTOCOPY_DEFAULT: c_int = 16000;
278

            
279
    #[link(name = "wpcap")]
280
    extern "C" {
281
        pub fn pcap_setmintocopy(arg1: *mut pcap_t, arg2: c_int) -> c_int;
282
        pub fn pcap_getevent(p: *mut pcap_t) -> HANDLE;
283
        pub fn pcap_sendqueue_alloc(memsize: c_uint) -> *mut pcap_send_queue;
284
        pub fn pcap_sendqueue_destroy(queue: *mut pcap_send_queue);
285
        pub fn pcap_sendqueue_queue(
286
            queue: *mut pcap_send_queue,
287
            pkt_header: *const pcap_pkthdr,
288
            pkt_data: *const c_uchar,
289
        ) -> c_int;
290
        pub fn pcap_sendqueue_transmit(
291
            p: *mut pcap_t,
292
            queue: *mut pcap_send_queue,
293
            sync: c_int,
294
        ) -> c_uint;
295
    }
296
}
297

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

            
304
#[cfg(not(test))]
305
#[cfg(not(windows))]
306
pub use ffi_unix::*;
307

            
308
#[cfg(not(test))]
309
#[cfg(windows)]
310
pub use ffi_windows::*;
311

            
312
#[cfg(test)]
313
pub use mock_ffi::*;
314

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

            
319
#[cfg(test)]
320
#[cfg(windows)]
321
pub use mock_ffi_windows::*;
322

            
323
#[cfg(test)]
324
pub mod testmod {
325
    use std::{ffi::CString, sync::Mutex};
326

            
327
    use once_cell::sync::Lazy;
328

            
329
    use super::*;
330

            
331
    pub struct GeterrContext(__pcap_geterr::Context);
332

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

            
336
    pub fn as_pcap_t<T: ?Sized>(value: &mut T) -> *mut pcap_t {
337
        value as *mut T as *mut pcap_t
338
    }
339

            
340
    pub fn as_pcap_dumper_t<T: ?Sized>(value: &mut T) -> *mut pcap_dumper_t {
341
        value as *mut T as *mut pcap_dumper_t
342
    }
343

            
344
    pub fn geterr_expect(pcap: *mut pcap_t) -> GeterrContext {
345
        // Lock must be acquired by caller.
346
        assert!(RAWMTX.try_lock().is_err());
347

            
348
        let err = CString::new("oh oh").unwrap();
349
        let ctx = pcap_geterr_context();
350
        ctx.checkpoint();
351
        ctx.expect()
352
            .withf_st(move |arg1| *arg1 == pcap)
353
            .return_once_st(|_| err.into_raw());
354

            
355
        GeterrContext(ctx)
356
    }
357
}
358
// GRCOV_EXCL_STOP