From 1d82bfbb8bcdf2ad860fe860398bb32a014df57a Mon Sep 17 00:00:00 2001 From: "Zach N." Date: Fri, 19 Jan 2024 09:44:34 -0800 Subject: [PATCH] Add support for dynamic loading of windows dll --- Cargo.toml | 5 +- build.rs | 2 +- src/dynamic_win_raw.rs | 395 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 90 +++++----- src/raw.rs | 106 +---------- src/raw_common.rs | 99 +++++++++++ src/sendqueue.rs | 11 +- 7 files changed, 559 insertions(+), 149 deletions(-) create mode 100644 src/dynamic_win_raw.rs create mode 100644 src/raw_common.rs diff --git a/Cargo.toml b/Cargo.toml index fd9d0368d..36a77ccef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,11 @@ gat-std = { version = "0.1.1", optional = true } # and these libraries would truncate the min support Rust version (MSRV) tun-tap = { version = "0.1.3", optional = true } etherparse = { version = "0.13.0", optional = true } +libloading = "0.8" [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.36.1", features = ["Win32_Foundation", "Win32_Networking_WinSock"] } +once_cell = "1.19" [dev-dependencies] tempdir = "0.3" @@ -34,7 +36,7 @@ tempdir = "0.3" eui48 = "1.1" [build-dependencies] -libloading = "0.6" +libloading = "0.8" regex = "1" pkg-config = "0.3" @@ -44,6 +46,7 @@ pkg-config = "0.3" capture-stream = ["tokio", "futures"] tap-tests = ["tun-tap", "etherparse"] lending-iter = ["gat-std"] +dynamic-load = [] # an empty feature to detect if '--all-features' was set all-features = [] diff --git a/build.rs b/build.rs index 478bbc68d..b80190a0e 100644 --- a/build.rs +++ b/build.rs @@ -99,7 +99,7 @@ fn get_libpcap_version(libdirpath: Option) -> Result *mut pcap_t; +type PcapSetSnaplen = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapSetPromisc = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapSetTimeout = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapSetBufferSize = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapActivate = unsafe extern "C" fn(arg1: *mut pcap_t) -> c_int; +type PcapOpenDead = unsafe extern "C" fn(arg1: c_int, arg2: c_int) -> *mut pcap_t; +type PcapOpenOffline = unsafe extern "C" fn(arg1: *const c_char, arg2: *mut c_char) -> *mut pcap_t; +type PcapFopenOffline = unsafe extern "C" fn(arg1: *mut FILE, arg2: *mut c_char) -> *mut pcap_t; +type PcapClose = unsafe extern "C" fn(arg1: *mut pcap_t); +type PcapNextEx = unsafe extern "C" fn( + arg1: *mut pcap_t, + arg2: *mut *mut pcap_pkthdr, + arg3: *mut *const c_uchar, +) -> c_int; +type PcapStats = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: *mut pcap_stat) -> c_int; +type PcapSetfilter = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: *mut bpf_program) -> c_int; +type PcapSetdirection = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: pcap_direction_t) -> c_int; +type PcapSetnonblock = + unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int, arg3: *mut c_char) -> c_int; +type PcapSendpacket = + unsafe extern "C" fn(arg1: *mut pcap_t, arg2: *const c_uchar, arg3: c_int) -> c_int; +type PcapGeterr = unsafe extern "C" fn(arg1: *mut pcap_t) -> *mut c_char; +type PcapCompile = unsafe extern "C" fn( + arg1: *mut pcap_t, + arg2: *mut bpf_program, + arg3: *const c_char, + arg4: c_int, + arg5: c_uint, +) -> c_int; +type PcapFreecode = unsafe extern "C" fn(arg1: *mut bpf_program); +type PcapOfflineFilter = unsafe extern "C" fn( + arg1: *const bpf_program, + arg2: *const pcap_pkthdr, + arg3: *const c_uchar, +) -> c_int; +type PcapDatalink = unsafe extern "C" fn(arg1: *mut pcap_t) -> c_int; +type PcapListDatalinks = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int; +type PcapSetDatalink = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapFreeDatalinks = unsafe extern "C" fn(arg1: *mut c_int); +type PcapDatalinkNameToVal = unsafe extern "C" fn(arg1: *const c_char) -> c_int; +type PcapDatalinkValToName = unsafe extern "C" fn(arg1: c_int) -> *const c_char; +type PcapDatalinkValToDescription = unsafe extern "C" fn(arg1: c_int) -> *const c_char; +type PcapMajorVersion = unsafe extern "C" fn(arg1: *mut pcap_t) -> c_int; +type PcapMinorVersion = unsafe extern "C" fn(arg1: *mut pcap_t) -> c_int; +type PcapFileno = unsafe extern "C" fn(arg1: *mut pcap_t) -> c_int; +type PcapDumpOpen = + unsafe extern "C" fn(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t; +type PcapDumpFopen = unsafe extern "C" fn(arg1: *mut pcap_t, fp: *mut FILE) -> *mut pcap_dumper_t; +type PcapDumpFlush = unsafe extern "C" fn(arg1: *mut pcap_dumper_t) -> c_int; +type PcapDumpClose = unsafe extern "C" fn(arg1: *mut pcap_dumper_t); +type PcapDump = + unsafe extern "C" fn(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar); +type PcapFindalldevs = unsafe extern "C" fn(arg1: *mut *mut pcap_if_t, arg2: *mut c_char) -> c_int; +type PcapFreealldevs = unsafe extern "C" fn(arg1: *mut pcap_if_t); +type PcapGetSelectableFd = unsafe extern "C" fn(arg1: *mut pcap_t) -> c_int; +type PcapSetTstampType = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapFopenOfflineWithTstampPrecision = + unsafe extern "C" fn(arg1: *mut FILE, arg2: c_uint, arg3: *mut c_char) -> *mut pcap_t; +type PcapOpenDeadWithTstampPrecision = + unsafe extern "C" fn(arg1: c_int, arg2: c_int, arg3: c_uint) -> *mut pcap_t; +type PcapOpenOfflineWithTstampPrecision = + unsafe extern "C" fn(arg1: *const c_char, arg2: c_uint, arg3: *mut c_char) -> *mut pcap_t; +type PcapSetImmediateMode = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapSetTstampPrecision = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapDumpOpenAppend = + unsafe extern "C" fn(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t; +type PcapSetmintocopy = unsafe extern "C" fn(arg1: *mut pcap_t, arg2: c_int) -> c_int; +type PcapGetEvent = unsafe extern "C" fn(p: *mut pcap_t) -> HANDLE; +type PcapSendqueueAlloc = unsafe extern "C" fn(memsize: c_uint) -> *mut pcap_send_queue; +type PcapSendqueueDestroy = unsafe extern "C" fn(queue: *mut pcap_send_queue); +type PcapSendqueueQueue = unsafe extern "C" fn( + queue: *mut pcap_send_queue, + pkt_header: *const pcap_pkthdr, + pkt_data: *const c_uchar, +) -> c_int; +type PcapSendqueueTransmit = + unsafe extern "C" fn(p: *mut pcap_t, queue: *mut pcap_send_queue, sync: c_int) -> c_uint; + +static mut LIBRARY: Lazy = Lazy::new(|| { + unsafe { load_library() } +}); + +unsafe fn load_library() -> Library { + let mut libfile = PathBuf::from("wpcap.dll"); + + let libdirpath = if let Ok(libdir) = env::var("LIBPCAP_LIBDIR") { + Some(PathBuf::from(&libdir)) + } else { + None + }; + + if let Some(libdir) = libdirpath { + libfile = libdir.join(libfile); + } + + Library::new(libfile).unwrap() +} + +pub unsafe fn pcap_create(arg1: *const c_char, arg2: *mut c_char) -> *mut pcap_t { + let func = LIBRARY.get::(b"pcap_create").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_set_snaplen(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY.get::(b"pcap_set_snaplen").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_set_promisc(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY.get::(b"pcap_set_promisc").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_set_timeout(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY.get::(b"pcap_set_timeout").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_set_buffer_size(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY + .get::(b"pcap_set_buffer_size") + .unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_activate(arg1: *mut pcap_t) -> c_int { + let func = LIBRARY.get::(b"pcap_activate").unwrap(); + func(arg1) +} +pub unsafe fn pcap_open_dead(arg1: c_int, arg2: c_int) -> *mut pcap_t { + let func = LIBRARY.get::(b"pcap_open_dead").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_open_offline(arg1: *const c_char, arg2: *mut c_char) -> *mut pcap_t { + let func = LIBRARY.get::(b"pcap_open_offline").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_fopen_offline(arg1: *mut FILE, arg2: *mut c_char) -> *mut pcap_t { + let func = LIBRARY.get::(b"pcap_fopen_offline").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_close(arg1: *mut pcap_t) { + let func = LIBRARY.get::(b"pcap_close").unwrap(); + func(arg1) +} +pub unsafe fn pcap_next_ex( + arg1: *mut pcap_t, + arg2: *mut *mut pcap_pkthdr, + arg3: *mut *const c_uchar, +) -> c_int { + let func = LIBRARY.get::(b"pcap_next_ex").unwrap(); + func(arg1, arg2, arg3) +} +pub unsafe fn pcap_stats(arg1: *mut pcap_t, arg2: *mut pcap_stat) -> c_int { + let func = LIBRARY.get::(b"pcap_stats").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_setfilter(arg1: *mut pcap_t, arg2: *mut bpf_program) -> c_int { + let func = LIBRARY.get::(b"pcap_setfilter").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_setdirection(arg1: *mut pcap_t, arg2: pcap_direction_t) -> c_int { + let func = LIBRARY.get::(b"pcap_setdirection").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_setnonblock(arg1: *mut pcap_t, arg2: c_int, arg3: *mut c_char) -> c_int { + let func = LIBRARY.get::(b"pcap_setnonblock").unwrap(); + func(arg1, arg2, arg3) +} +pub unsafe fn pcap_sendpacket(arg1: *mut pcap_t, arg2: *const c_uchar, arg3: c_int) -> c_int { + let func = LIBRARY.get::(b"pcap_sendpacket").unwrap(); + func(arg1, arg2, arg3) +} +pub unsafe fn pcap_geterr(arg1: *mut pcap_t) -> *mut c_char { + let func = LIBRARY.get::(b"pcap_geterr").unwrap(); + func(arg1) +} +pub unsafe fn pcap_compile( + arg1: *mut pcap_t, + arg2: *mut bpf_program, + arg3: *const c_char, + arg4: c_int, + arg5: c_uint, +) -> c_int { + let func = LIBRARY.get::(b"pcap_compile").unwrap(); + func(arg1, arg2, arg3, arg4, arg5) +} +pub unsafe fn pcap_freecode(arg1: *mut bpf_program) { + let func = LIBRARY.get::(b"pcap_freecode").unwrap(); + func(arg1) +} +pub unsafe fn pcap_offline_filter( + arg1: *const bpf_program, + arg2: *const pcap_pkthdr, + arg3: *const c_uchar, +) -> c_int { + let func = LIBRARY + .get::(b"pcap_offline_filter") + .unwrap(); + func(arg1, arg2, arg3) +} +pub unsafe fn pcap_datalink(arg1: *mut pcap_t) -> c_int { + let func = LIBRARY.get::(b"pcap_datalink").unwrap(); + func(arg1) +} +pub unsafe fn pcap_list_datalinks(arg1: *mut pcap_t, arg2: *mut *mut c_int) -> c_int { + let func = LIBRARY + .get::(b"pcap_list_datalinks") + .unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_set_datalink(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY.get::(b"pcap_set_datalink").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_free_datalinks(arg1: *mut c_int) { + let func = LIBRARY + .get::(b"pcap_free_datalinks") + .unwrap(); + func(arg1) +} +pub unsafe fn pcap_datalink_name_to_val(arg1: *const c_char) -> c_int { + let func = LIBRARY + .get::(b"pcap_datalink_name_to_val") + .unwrap(); + func(arg1) +} +pub unsafe fn pcap_datalink_val_to_name(arg1: c_int) -> *const c_char { + let func = LIBRARY + .get::(b"pcap_datalink_val_to_name") + .unwrap(); + func(arg1) +} +pub unsafe fn pcap_datalink_val_to_description(arg1: c_int) -> *const c_char { + let func = LIBRARY + .get::(b"pcap_datalink_val_to_description") + .unwrap(); + func(arg1) +} +pub unsafe fn pcap_major_version(arg1: *mut pcap_t) -> c_int { + let func = LIBRARY.get::(b"pcap_major_version").unwrap(); + func(arg1) +} +pub unsafe fn pcap_minor_version(arg1: *mut pcap_t) -> c_int { + let func = LIBRARY.get::(b"pcap_minor_version").unwrap(); + func(arg1) +} +pub unsafe fn pcap_fileno(arg1: *mut pcap_t) -> c_int { + let func = LIBRARY.get::(b"pcap_fileno").unwrap(); + func(arg1) +} +pub unsafe fn pcap_dump_open(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t { + let func = LIBRARY.get::(b"pcap_dump_open").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_dump_fopen(arg1: *mut pcap_t, fp: *mut FILE) -> *mut pcap_dumper_t { + let func = LIBRARY.get::(b"pcap_dump_fopen").unwrap(); + func(arg1, fp) +} +pub unsafe fn pcap_dump_flush(arg1: *mut pcap_dumper_t) -> c_int { + let func = LIBRARY.get::(b"pcap_dump_flush").unwrap(); + func(arg1) +} +pub unsafe fn pcap_dump_close(arg1: *mut pcap_dumper_t) { + let func = LIBRARY.get::(b"pcap_dump_close").unwrap(); + func(arg1) +} +pub unsafe fn pcap_dump(arg1: *mut c_uchar, arg2: *const pcap_pkthdr, arg3: *const c_uchar) { + let func = LIBRARY.get::(b"pcap_dump").unwrap(); + func(arg1, arg2, arg3) +} +pub unsafe fn pcap_findalldevs(arg1: *mut *mut pcap_if_t, arg2: *mut c_char) -> c_int { + let func = LIBRARY.get::(b"pcap_findalldevs").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_freealldevs(arg1: *mut pcap_if_t) { + let func = LIBRARY.get::(b"pcap_freealldevs").unwrap(); + func(arg1) +} +pub unsafe fn pcap_get_selectable_fd(arg1: *mut pcap_t) -> c_int { + let func = LIBRARY + .get::(b"pcap_get_selectable_fd") + .unwrap(); + func(arg1) +} + +#[cfg(libpcap_1_2_1)] +pub fn pcap_set_tstamp_type(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY + .get::(b"pcap_set_tstamp_type") + .unwrap(); + func(arg1, arg2) +} + +#[cfg(libpcap_1_5_0)] +pub fn pcap_fopen_offline_with_tstamp_precision( + arg1: *mut FILE, + arg2: c_uint, + arg3: *mut c_char, +) -> *mut pcap_t { + let func = LIBRARY + .get::(b"pcap_fopen_offline_with_tstamp_precision") + .unwrap(); + func(arg1, arg2, arg3) +} +#[cfg(libpcap_1_5_0)] +pub fn pcap_open_dead_with_tstamp_precision(arg1: c_int, arg2: c_int, arg3: c_uint) -> *mut pcap_t { + let func = LIBRARY + .get::(b"pcap_open_dead_with_tstamp_precision") + .unwrap(); + func(arg1, arg2, arg3) +} +#[cfg(libpcap_1_5_0)] +pub fn pcap_open_offline_with_tstamp_precision( + arg1: *const c_char, + arg2: c_uint, + arg3: *mut c_char, +) -> *mut pcap_t { + let func = LIBRARY + .get::(b"pcap_open_offline_with_tstamp_precision") + .unwrap(); + func(arg1, arg2, arg3) +} +#[cfg(libpcap_1_5_0)] +pub fn pcap_set_immediate_mode(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY + .get::(b"pcap_set_immediate_mode") + .unwrap(); + func(arg1, arg2) +} +#[cfg(libpcap_1_5_0)] +pub fn pcap_set_tstamp_precision(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY + .get::(b"pcap_set_tstamp_precision") + .unwrap(); + func(arg1, arg2) +} + +#[cfg(libpcap_1_7_2)] +pub fn pcap_dump_open_append(arg1: *mut pcap_t, arg2: *const c_char) -> *mut pcap_dumper_t { + let func = LIBRARY + .get::(b"pcap_dump_open_append") + .unwrap(); + func(arg1, arg2) +} + +pub unsafe fn pcap_setmintocopy(arg1: *mut pcap_t, arg2: c_int) -> c_int { + let func = LIBRARY.get::(b"pcap_setmintocopy").unwrap(); + func(arg1, arg2) +} +pub unsafe fn pcap_getevent(p: *mut pcap_t) -> HANDLE { + let func = LIBRARY.get::(b"pcap_getevent").unwrap(); + func(p) +} +pub unsafe fn pcap_sendqueue_alloc(memsize: c_uint) -> *mut pcap_send_queue { + let func = LIBRARY + .get::(b"pcap_sendqueue_alloc") + .unwrap(); + func(memsize) +} +pub unsafe fn pcap_sendqueue_destroy(queue: *mut pcap_send_queue) { + let func = LIBRARY + .get::(b"pcap_sendqueue_destroy") + .unwrap(); + func(queue) +} +pub unsafe fn pcap_sendqueue_queue( + queue: *mut pcap_send_queue, + pkt_header: *const pcap_pkthdr, + pkt_data: *const c_uchar, +) -> c_int { + let func = LIBRARY + .get::(b"pcap_sendqueue_queue") + .unwrap(); + func(queue, pkt_header, pkt_data) +} +pub unsafe fn pcap_sendqueue_transmit( + p: *mut pcap_t, + queue: *mut pcap_send_queue, + sync: c_int, +) -> c_uint { + let func = LIBRARY + .get::(b"pcap_sendqueue_transmit") + .unwrap(); + func(p, queue, sync) +} diff --git a/src/lib.rs b/src/lib.rs index 201418f46..f946583a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,9 +80,13 @@ use windows_sys::Win32::Networking::WinSock::{AF_INET, AF_INET6, SOCKADDR_IN, SO #[cfg(target_os = "windows")] use windows_sys::Win32::Foundation::HANDLE; - +#[cfg(all(target_os = "windows", feature = "dynamic-load"))] +mod dynamic_win_raw; +#[cfg(any(not(windows), not(feature = "dynamic-load")))] mod raw; -#[cfg(windows)] +mod raw_common; +#[cfg(all(target_os = "windows", feature = "dynamic-load"))] +use dynamic_win_raw as raw; pub mod sendqueue; #[cfg(feature = "capture-stream")] mod stream; @@ -213,14 +217,14 @@ bitflags! { /// Network device flags. pub struct IfFlags: u32 { /// Set if the device is a loopback interface - const LOOPBACK = raw::PCAP_IF_LOOPBACK; + const LOOPBACK = raw_common::PCAP_IF_LOOPBACK; /// Set if the device is up - const UP = raw::PCAP_IF_UP; + const UP = raw_common::PCAP_IF_UP; /// Set if the device is running - const RUNNING = raw::PCAP_IF_RUNNING; + const RUNNING = raw_common::PCAP_IF_RUNNING; /// Set if the device is a wireless interface; this includes IrDA as well as radio-based /// networks such as IEEE 802.15.4 and IEEE 802.11, so it doesn't just mean Wi-Fi - const WIRELESS = raw::PCAP_IF_WIRELESS; + const WIRELESS = raw_common::PCAP_IF_WIRELESS; } } @@ -247,11 +251,11 @@ pub enum ConnectionStatus { impl From for ConnectionStatus { fn from(flags: u32) -> Self { - match flags & raw::PCAP_IF_CONNECTION_STATUS { - raw::PCAP_IF_CONNECTION_STATUS_UNKNOWN => ConnectionStatus::Unknown, - raw::PCAP_IF_CONNECTION_STATUS_CONNECTED => ConnectionStatus::Connected, - raw::PCAP_IF_CONNECTION_STATUS_DISCONNECTED => ConnectionStatus::Disconnected, - raw::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE => ConnectionStatus::NotApplicable, + match flags & raw_common::PCAP_IF_CONNECTION_STATUS { + raw_common::PCAP_IF_CONNECTION_STATUS_UNKNOWN => ConnectionStatus::Unknown, + raw_common::PCAP_IF_CONNECTION_STATUS_CONNECTED => ConnectionStatus::Connected, + raw_common::PCAP_IF_CONNECTION_STATUS_DISCONNECTED => ConnectionStatus::Disconnected, + raw_common::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE => ConnectionStatus::NotApplicable, // DeviceFlags::CONNECTION_STATUS should be a 2-bit mask which means that the four // values should cover all the possibilities. _ => unreachable!(), @@ -368,10 +372,10 @@ impl Device { unsafe fn with_all_devs(func: F) -> Result where - F: FnOnce(*mut raw::pcap_if_t) -> Result, + F: FnOnce(*mut raw_common::pcap_if_t) -> Result, { let all_devs = with_errbuf(|err| { - let mut all_devs: *mut raw::pcap_if_t = ptr::null_mut(); + let mut all_devs: *mut raw_common::pcap_if_t = ptr::null_mut(); if raw::pcap_findalldevs(&mut all_devs, err) != 0 { return Err(Error::new(err)); } @@ -389,10 +393,10 @@ impl From<&str> for Device { } } -impl TryFrom<&raw::pcap_if_t> for Device { +impl TryFrom<&raw_common::pcap_if_t> for Device { type Error = Error; - fn try_from(dev: &raw::pcap_if_t) -> Result { + fn try_from(dev: &raw_common::pcap_if_t) -> Result { Ok(Device::new( unsafe { cstr_to_string(dev.name)?.ok_or(InvalidString)? }, unsafe { cstr_to_string(dev.description)? }, @@ -416,7 +420,7 @@ pub struct Address { } impl Address { - unsafe fn new_vec(mut ptr: *const raw::pcap_addr_t) -> Vec
{ + unsafe fn new_vec(mut ptr: *const raw_common::pcap_addr_t) -> Vec
{ let mut vec = Vec::new(); while !ptr.is_null() { if let Some(addr) = Address::new(ptr) { @@ -427,7 +431,7 @@ impl Address { vec } - unsafe fn new(ptr: *const raw::pcap_addr_t) -> Option
{ + unsafe fn new(ptr: *const raw_common::pcap_addr_t) -> Option
{ Self::convert_sockaddr((*ptr).addr).map(|addr| Address { addr, netmask: Self::convert_sockaddr((*ptr).netmask), @@ -816,7 +820,7 @@ impl State for Dead {} /// ``` pub struct Capture { nonblock: bool, - handle: NonNull, + handle: NonNull, _marker: PhantomData, } @@ -825,8 +829,8 @@ pub struct Capture { // multiple threads. unsafe impl Send for Capture {} -impl From> for Capture { - fn from(handle: NonNull) -> Self { +impl From> for Capture { + fn from(handle: NonNull) -> Self { Capture { nonblock: false, handle, @@ -838,7 +842,7 @@ impl From> for Capture { impl Capture { fn new_raw(path: Option<&str>, func: F) -> Result, Error> where - F: FnOnce(*const libc::c_char, *mut libc::c_char) -> *mut raw::pcap_t, + F: FnOnce(*const libc::c_char, *mut libc::c_char) -> *mut raw_common::pcap_t, { with_errbuf(|err| { let handle = match path { @@ -849,7 +853,8 @@ impl Capture { } }; Ok(Capture::from( - NonNull::::new(handle).ok_or_else(|| unsafe { Error::new(err) })?, + NonNull::::new(handle) + .ok_or_else(|| unsafe { Error::new(err) })?, )) }) } @@ -1003,11 +1008,11 @@ pub type TstampType = TimestampType; /// The direction of packets to be captured. Use with `Capture::direction`. pub enum Direction { /// Capture packets received by or sent by the device. This is the default. - InOut = raw::PCAP_D_INOUT, + InOut = raw_common::PCAP_D_INOUT, /// Only capture packets received by the device. - In = raw::PCAP_D_IN, + In = raw_common::PCAP_D_IN, /// Only capture packets sent by the device. - Out = raw::PCAP_D_OUT, + Out = raw_common::PCAP_D_OUT, } impl Capture { @@ -1093,7 +1098,7 @@ impl Capture { if to { 0 } else { - raw::WINPCAP_MINTOCOPY_DEFAULT + raw_common::WINPCAP_MINTOCOPY_DEFAULT }, ) }; @@ -1168,7 +1173,7 @@ impl Capture { /// configurations. pub fn savefile>(&self, path: P) -> Result { let name = CString::new(path.as_ref().to_str().unwrap())?; - let handle_opt = NonNull::::new(unsafe { + let handle_opt = NonNull::::new(unsafe { raw::pcap_dump_open(self.handle.as_ptr(), name.as_ptr()) }); let handle = self @@ -1235,7 +1240,7 @@ impl Capture { /// you probably want to minimize the time between calls to next_packet() method. pub fn next_packet(&mut self) -> Result, Error> { unsafe { - let mut header: *mut raw::pcap_pkthdr = ptr::null_mut(); + let mut header: *mut raw_common::pcap_pkthdr = ptr::null_mut(); let mut packet: *const libc::c_uchar = ptr::null(); let retcode = raw::pcap_next_ex(self.handle.as_ptr(), &mut header, &mut packet); self.check_err(retcode != -1)?; // -1 => an error occured while reading the packet @@ -1243,7 +1248,7 @@ impl Capture { i if i >= 1 => { // packet was read without issue Ok(Packet::new( - &*(&*header as *const raw::pcap_pkthdr as *const PacketHeader), + &*(&*header as *const raw_common::pcap_pkthdr as *const PacketHeader), slice::from_raw_parts(packet, (*header).caplen as _), )) } @@ -1292,7 +1297,7 @@ impl Capture { pub fn filter(&mut self, program: &str, optimize: bool) -> Result<(), Error> { let program = CString::new(program)?; unsafe { - let mut bpf_program: raw::bpf_program = mem::zeroed(); + let mut bpf_program: raw_common::bpf_program = mem::zeroed(); let ret = raw::pcap_compile( self.handle.as_ptr(), &mut bpf_program, @@ -1314,7 +1319,7 @@ impl Capture { /// how packet statistics are calculated. pub fn stats(&mut self) -> Result { unsafe { - let mut stats: raw::pcap_stat = mem::zeroed(); + let mut stats: raw_common::pcap_stat = mem::zeroed(); self.check_err(raw::pcap_stats(self.handle.as_ptr(), &mut stats) != -1) .map(|_| Stat::new(stats.ps_recv, stats.ps_drop, stats.ps_ifdrop)) } @@ -1348,7 +1353,7 @@ impl Capture { pub fn dead(linktype: Linktype) -> Result, Error> { let handle = unsafe { raw::pcap_open_dead(linktype.0, 65535) }; Ok(Capture::from( - NonNull::::new(handle).ok_or(InsufficientMemory)?, + NonNull::::new(handle).ok_or(InsufficientMemory)?, )) } @@ -1371,7 +1376,7 @@ impl Capture { let program = CString::new(program).unwrap(); unsafe { - let mut bpf_program: raw::bpf_program = mem::zeroed(); + let mut bpf_program: raw_common::bpf_program = mem::zeroed(); if -1 == raw::pcap_compile( self.handle.as_ptr(), @@ -1437,7 +1442,7 @@ impl From> for Capture { /// Abstraction for writing pcap savefiles, which can be read afterwards via `Capture::from_file()`. pub struct Savefile { - handle: NonNull, + handle: NonNull, } // Just like a Capture, a Savefile is safe to Send as it encapsulates the entire lifetime of @@ -1451,7 +1456,7 @@ impl Savefile { unsafe { raw::pcap_dump( self.handle.as_ptr() as _, - &*(packet.header as *const PacketHeader as *const raw::pcap_pkthdr), + &*(packet.header as *const PacketHeader as *const raw_common::pcap_pkthdr), packet.data.as_ptr(), ); } @@ -1467,8 +1472,8 @@ impl Savefile { } } -impl From> for Savefile { - fn from(handle: NonNull) -> Self { +impl From> for Savefile { + fn from(handle: NonNull) -> Self { Savefile { handle } } } @@ -1513,18 +1518,21 @@ where #[test] fn test_struct_size() { use std::mem::size_of; - assert_eq!(size_of::(), size_of::()); + assert_eq!( + size_of::(), + size_of::() + ); } #[repr(transparent)] -pub struct BpfInstruction(raw::bpf_insn); +pub struct BpfInstruction(raw_common::bpf_insn); #[repr(transparent)] -pub struct BpfProgram(raw::bpf_program); +pub struct BpfProgram(raw_common::bpf_program); impl BpfProgram { /// checks whether a filter matches a packet pub fn filter(&self, buf: &[u8]) -> bool { - let header: raw::pcap_pkthdr = raw::pcap_pkthdr { + let header: raw_common::pcap_pkthdr = raw_common::pcap_pkthdr { ts: libc::timeval { tv_sec: 0, tv_usec: 0, diff --git a/src/raw.rs b/src/raw.rs index 6188184ae..278046fda 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -1,107 +1,14 @@ #![allow(dead_code)] -#![allow(non_camel_case_types)] -use libc::{c_char, c_int, c_uchar, c_uint, c_ushort, sockaddr, timeval, FILE}; +use libc::{c_char, c_int, c_uchar, c_uint, FILE}; +use crate::raw_common::{ + bpf_program, pcap_direction_t, pcap_dumper_t, pcap_if_t, pcap_pkthdr, pcap_send_queue, + pcap_stat, pcap_t, +}; #[cfg(windows)] use windows_sys::Win32::Foundation::HANDLE; -pub const PCAP_IF_LOOPBACK: u32 = 0x00000001; -pub const PCAP_IF_UP: u32 = 0x00000002; -pub const PCAP_IF_RUNNING: u32 = 0x00000004; -pub const PCAP_IF_WIRELESS: u32 = 0x00000008; -pub const PCAP_IF_CONNECTION_STATUS: u32 = 0x00000030; -pub const PCAP_IF_CONNECTION_STATUS_UNKNOWN: u32 = 0x00000000; -pub const PCAP_IF_CONNECTION_STATUS_CONNECTED: u32 = 0x00000010; -pub const PCAP_IF_CONNECTION_STATUS_DISCONNECTED: u32 = 0x00000020; -pub const PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: u32 = 0x00000030; - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct bpf_program { - pub bf_len: c_uint, - pub bf_insns: *mut bpf_insn, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct bpf_insn { - pub code: c_ushort, - pub jt: c_uchar, - pub jf: c_uchar, - pub k: c_uint, -} - -pub enum pcap_t {} - -pub enum pcap_dumper_t {} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct pcap_file_header { - pub magic: c_uint, - pub version_major: c_ushort, - pub version_minor: c_ushort, - pub thiszone: c_int, - pub sigfigs: c_uint, - pub snaplen: c_uint, - pub linktype: c_uint, -} - -pub type pcap_direction_t = c_uint; - -pub const PCAP_D_INOUT: pcap_direction_t = 0; -pub const PCAP_D_IN: pcap_direction_t = 1; -pub const PCAP_D_OUT: pcap_direction_t = 2; - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct pcap_pkthdr { - pub ts: timeval, - pub caplen: c_uint, - pub len: c_uint, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct pcap_stat { - pub ps_recv: c_uint, - pub ps_drop: c_uint, - pub ps_ifdrop: c_uint, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct pcap_if_t { - pub next: *mut pcap_if_t, - pub name: *mut c_char, - pub description: *mut c_char, - pub addresses: *mut pcap_addr_t, - pub flags: c_uint, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct pcap_addr_t { - pub next: *mut pcap_addr_t, - pub addr: *mut sockaddr, - pub netmask: *mut sockaddr, - pub broadaddr: *mut sockaddr, - pub dstaddr: *mut sockaddr, -} - -#[cfg(windows)] -#[repr(C)] -#[derive(Copy, Clone)] -pub struct pcap_send_queue { - pub maxlen: c_uint, - pub len: c_uint, - pub buffer: *mut c_char, -} - -pub type pcap_handler = - Option ()>; - extern "C" { // [OBSOLETE] pub fn pcap_lookupdev(arg1: *mut c_char) -> *mut c_char; // pub fn pcap_lookupnet(arg1: *const c_char, arg2: *mut c_uint, arg3: *mut c_uint, @@ -243,9 +150,6 @@ extern "C" { // pcap_datalink_val_to_description_or_dlt } -#[cfg(windows)] -pub const WINPCAP_MINTOCOPY_DEFAULT: c_int = 16000; - #[cfg(windows)] #[link(name = "wpcap")] extern "C" { diff --git a/src/raw_common.rs b/src/raw_common.rs new file mode 100644 index 000000000..2454632b0 --- /dev/null +++ b/src/raw_common.rs @@ -0,0 +1,99 @@ +#![allow(non_camel_case_types)] + +use libc::{c_char, c_int, c_uchar, c_uint, c_ushort, sockaddr, timeval}; + +pub const PCAP_IF_LOOPBACK: u32 = 0x00000001; +pub const PCAP_IF_UP: u32 = 0x00000002; +pub const PCAP_IF_RUNNING: u32 = 0x00000004; +pub const PCAP_IF_WIRELESS: u32 = 0x00000008; +pub const PCAP_IF_CONNECTION_STATUS: u32 = 0x00000030; +pub const PCAP_IF_CONNECTION_STATUS_UNKNOWN: u32 = 0x00000000; +pub const PCAP_IF_CONNECTION_STATUS_CONNECTED: u32 = 0x00000010; +pub const PCAP_IF_CONNECTION_STATUS_DISCONNECTED: u32 = 0x00000020; +pub const PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: u32 = 0x00000030; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct bpf_program { + pub bf_len: c_uint, + pub bf_insns: *mut bpf_insn, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct bpf_insn { + pub code: c_ushort, + pub jt: c_uchar, + pub jf: c_uchar, + pub k: c_uint, +} + +pub enum pcap_t {} + +pub enum pcap_dumper_t {} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct pcap_file_header { + pub magic: c_uint, + pub version_major: c_ushort, + pub version_minor: c_ushort, + pub thiszone: c_int, + pub sigfigs: c_uint, + pub snaplen: c_uint, + pub linktype: c_uint, +} + +pub type pcap_direction_t = c_uint; + +pub const PCAP_D_INOUT: pcap_direction_t = 0; +pub const PCAP_D_IN: pcap_direction_t = 1; +pub const PCAP_D_OUT: pcap_direction_t = 2; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct pcap_pkthdr { + pub ts: timeval, + pub caplen: c_uint, + pub len: c_uint, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct pcap_stat { + pub ps_recv: c_uint, + pub ps_drop: c_uint, + pub ps_ifdrop: c_uint, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct pcap_if_t { + pub next: *mut pcap_if_t, + pub name: *mut c_char, + pub description: *mut c_char, + pub addresses: *mut pcap_addr_t, + pub flags: c_uint, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct pcap_addr_t { + pub next: *mut pcap_addr_t, + pub addr: *mut sockaddr, + pub netmask: *mut sockaddr, + pub broadaddr: *mut sockaddr, + pub dstaddr: *mut sockaddr, +} + +#[cfg(windows)] +#[repr(C)] +#[derive(Copy, Clone)] +pub struct pcap_send_queue { + pub maxlen: c_uint, + pub len: c_uint, + pub buffer: *mut c_char, +} + +#[cfg(windows)] +pub const WINPCAP_MINTOCOPY_DEFAULT: c_int = 16000; diff --git a/src/sendqueue.rs b/src/sendqueue.rs index 3359fee3b..3d2265a76 100644 --- a/src/sendqueue.rs +++ b/src/sendqueue.rs @@ -10,10 +10,11 @@ use std::io::IoSlice; use std::ptr::NonNull; use crate::raw; +use crate::raw_common; use crate::Error; use crate::{Active, Capture}; -pub struct SendQueue(NonNull); +pub struct SendQueue(NonNull); pub enum SendSync { Off = 0, @@ -21,8 +22,8 @@ pub enum SendSync { } #[inline] -fn make_pkthdr(ts: Option, len: u32) -> raw::pcap_pkthdr { - raw::pcap_pkthdr { +fn make_pkthdr(ts: Option, len: u32) -> raw_common::pcap_pkthdr { + raw_common::pcap_pkthdr { ts: if let Some(ts) = ts { libc::timeval { // tv_sec is currently i32 in libc when building for Windows @@ -112,7 +113,7 @@ impl SendQueue { // Note: It is assumed that len cannot exceed maxlen. This invariant must be upheld by // all methods implemented by SendQueue. let remain = (self.maxlen() - self.len()) as usize; - let need = std::mem::size_of::() + pktsize; + let need = std::mem::size_of::() + pktsize; if remain < need { return Err(Error::BufferOverflow); } @@ -134,7 +135,7 @@ impl SendQueue { let mut wbuf = unsafe { sqbuf.offset(bufoffs) }; // Copy packet header into the sendqueue's buffer - let mut lastlen = std::mem::size_of::(); + let mut lastlen = std::mem::size_of::(); unsafe { std::ptr::copy_nonoverlapping(rawhdr, wbuf, lastlen); }