From 1abce8dbd9866ef027409c90bbd5c717f7102811 Mon Sep 17 00:00:00 2001 From: Nathaniel Date: Tue, 10 Sep 2024 21:47:22 -0400 Subject: [PATCH] Fix CI breaks --- .github/workflows/full_ci.yaml | 4 +- ci/install-rust.sh | 31 +---- ci/run.sh | 8 +- rscap/Cargo.toml | 2 +- rscap/RELEASE_NOTES.md | 4 + rscap/src/bpf.rs | 211 ++++++++++++++-------------- rscap/src/dlpi.rs | 6 +- rscap/src/filter.rs | 7 +- rscap/src/lib.rs | 51 ++++--- rscap/src/linux.rs | 240 ++++++++++++++++++++++++++++++- rscap/src/linux/addr.rs | 33 ++++- rscap/src/linux/l2.rs | 248 +++++++++++++++------------------ rscap/src/linux/l3.rs | 246 ++++++++++++++------------------ rscap/src/linux/l4.rs | 25 ++-- rscap/src/linux/mapped.rs | 84 ++++++----- rscap/src/linux/prelude.rs | 3 +- rscap/src/linux/sndrcv.rs | 1 - rscap/src/npcap.rs | 95 ++++++++----- rscap/src/npcap/dll.rs | 43 +++--- rscap/src/npcap/dll/dlopen.rs | 172 +++++++++++++++-------- rscap/src/npcap/dll/link.rs | 141 ++++++++++--------- rscap/src/pktmon.rs | 3 +- 22 files changed, 984 insertions(+), 674 deletions(-) diff --git a/.github/workflows/full_ci.yaml b/.github/workflows/full_ci.yaml index 58b43f9..04ebb8f 100644 --- a/.github/workflows/full_ci.yaml +++ b/.github/workflows/full_ci.yaml @@ -1,6 +1,8 @@ name: full CI on: + push: + branches: [ "main" ] merge_group: pull_request: types: [opened, synchronize, reopened] @@ -56,7 +58,7 @@ jobs: build_channels_windows: name: Build Channels Windows - runs-on: windows-2022 + runs-on: windows-2019 env: OS: windows strategy: diff --git a/ci/install-rust.sh b/ci/install-rust.sh index 9b3b008..c62b079 100755 --- a/ci/install-rust.sh +++ b/ci/install-rust.sh @@ -32,30 +32,13 @@ if [ -n "$INSTALL_RUST_SRC" ]; then fi if [ "$OS" = "windows" ]; then - if [ "$ARCH_BITS" = "i686" ]; then - echo "Install MinGW32" - choco install mingw --x86 --force - fi - - echo "Find GCC libraries" - gcc -print-search-dirs - /usr/bin/find "C:\ProgramData\Chocolatey" -name "crt2*" - /usr/bin/find "C:\ProgramData\Chocolatey" -name "dllcrt2*" - /usr/bin/find "C:\ProgramData\Chocolatey" -name "libmsvcrt*" - - if [ -n "$ARCH_BITS" ]; then - echo "Fix MinGW" - for i in crt2.o dllcrt2.o libmingwex.a libmsvcrt.a ; do - cp -f "/C/ProgramData/Chocolatey/lib/mingw/tools/install/mingw$ARCH_BITS/$ARCH-w64-mingw32/lib/$i" "$(rustc --print sysroot)/lib/rustlib/$TARGET/lib" - done - fi - - # Install Wintun - echo "Install Wintun" - curl.exe -o wintun.zip https://www.wintun.net/builds/wintun-0.14.1.zip - powershell.exe -NoP -NonI -Command "Expand-Archive './wintun.zip' './'" - cp -f "./wintun/bin/amd64/wintun.dll" "./" - rm -rf "./wintun" + # Install Npcap + curl.exe -o "C:/npcap-sdk.zip" "https://npcap.com/dist/npcap-sdk-0.zip" + powershell.exe -NoP -NonI -Command "Expand-Archive -LiteralPath C:/npcap-sdk.zip -DestinationPath C:/" + cp "C:/npcap-sdk/Lib/x64/Packet.lib" "C:/Packet.lib" + cp "C:/npcap-sdk/Lib/x64/Packet.lib" "./Packet.lib" + curl.exe -o "C:/npcap.exe" "https://github.com/nmap/npcap/releases/download/v0.80/npcap-0.80.exe" + C:/npcap.exe "/S" fi echo "Query rust and cargo versions" diff --git a/ci/run.sh b/ci/run.sh index c332147..ebd293a 100755 --- a/ci/run.sh +++ b/ci/run.sh @@ -27,13 +27,11 @@ done case "${OS}" in windows*) - cargo test --features wintun - - cargo test --features wintun-runtime + cargo test - cargo test --features tapwin6 + cargo test --features npcap - cargo test --features tapwin6-runtime + cargo test --features npcap-runtime ;; *) # No extra features in any platform other than windows diff --git a/rscap/Cargo.toml b/rscap/Cargo.toml index 85ff97f..b7732a0 100644 --- a/rscap/Cargo.toml +++ b/rscap/Cargo.toml @@ -38,4 +38,4 @@ dlopen2_derive = { version = "0.4" } pkts-common = { version = "0.1.0" } [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.59", features = ["Win32","Win32_Networking", "Win32_Networking_WinSock", "Win32_System", "Win32_System_IO", "Win32_System_Kernel", "Win32_System_Threading"] } +windows-sys = { version = "0.59", features = ["Win32_Networking_WinSock", "Win32_NetworkManagement_IpHelper", "Win32_System_IO", "Win32_System_Kernel", "Win32_System_Threading"] } diff --git a/rscap/RELEASE_NOTES.md b/rscap/RELEASE_NOTES.md index 087685f..175a4e0 100644 --- a/rscap/RELEASE_NOTES.md +++ b/rscap/RELEASE_NOTES.md @@ -1,5 +1,9 @@ # Release History: +* 0.2.0 (2024-09-09) + - Split out `rscap` and `pkts` into separate crates + - Introduce CI pipeline + * 0.1.1 (2023-03-23) - Cleanup of unstable/unused APIs diff --git a/rscap/src/bpf.rs b/rscap/src/bpf.rs index a67be7b..1288920 100644 --- a/rscap/src/bpf.rs +++ b/rscap/src/bpf.rs @@ -10,19 +10,19 @@ //! (BSD/MacOS) Berkeley Packet Filter (BPF) packet capture and transmission interface (see `filter` //! for cross-platform BPF filtering utilities). -//! -//! +//! +//! use core::{mem, slice}; use std::ffi::{CStr, CString}; +use std::os::fd::RawFd; use std::sync::atomic::{AtomicU32, Ordering}; use std::{array, io, ptr}; -use std::os::fd::RawFd; +use crate::filter::PacketStatistics; use crate::Interface; -use crate::filter::BpfStatistics; -const BPF_PATH: &CStr = c"/dev/bpf"; +const BPF_PATH: &[u8] = b"/dev/bpf\0"; /// `L2Socket::new()` will only iterate through up to this many BPF device names before failing. const MAX_OPEN_BPF: u32 = 1024; @@ -68,19 +68,19 @@ pub struct bpf_ts { bt_frac: u64, } -const BIOCFLUSH: libc::c_ulong = 0x20004268; -const BIOCPROMISC: libc::c_ulong = 0x20004269; -const BIOCGDLT: libc::c_ulong = 0x4004426a; -const BIOCGBLEN: libc::c_ulong = 0x40044266; -const BIOCSBLEN: libc::c_ulong = 0xc0044266; -const BIOCVERSION: libc::c_ulong = 0x40044271; -const BIOCGETIF: libc::c_ulong = 0x4020426b; -const BIOCSETIF: libc::c_ulong = 0x8020426c; -const BIOCGSTATS: libc::c_ulong = 0x4008426f; +const BIOCFLUSH: libc::c_ulong = 0x20004268; +const BIOCPROMISC: libc::c_ulong = 0x20004269; +const BIOCGDLT: libc::c_ulong = 0x4004426a; +const BIOCGBLEN: libc::c_ulong = 0x40044266; +const BIOCSBLEN: libc::c_ulong = 0xc0044266; +const BIOCVERSION: libc::c_ulong = 0x40044271; +const BIOCGETIF: libc::c_ulong = 0x4020426b; +const BIOCSETIF: libc::c_ulong = 0x8020426c; +const BIOCGSTATS: libc::c_ulong = 0x4008426f; const BIOCIMMEDIATE: libc::c_ulong = 0x80044270; -const BIOCSETZBUF: libc::c_ulong = 0x80184281; -const BIOCFEEDBACK: libc::c_ulong = 0x8004427c; -const BIOCLOCK: libc::c_ulong = 0x2000427a; +const BIOCSETZBUF: libc::c_ulong = 0x80184281; +const BIOCFEEDBACK: libc::c_ulong = 0x8004427c; +const BIOCLOCK: libc::c_ulong = 0x2000427a; const BPF_ALIGNMENT: usize = mem::size_of::(); #[allow(non_snake_case)] @@ -139,7 +139,12 @@ pub enum LinkType { PppBsdos = 14, #[cfg(target_os = "netbsd")] Hippi = 15, - #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "macos", target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "netbsd", + target_os = "macos", + target_os = "openbsd" + ))] Pfsync = 18, AtmClip = 19, RedbackSmartedge = 32, @@ -157,7 +162,7 @@ pub enum LinkType { Enc = 13, #[cfg(not(target_os = "openbsd"))] Enc = 109, - #[cfg(target_os = "netbsd")] + #[cfg(target_os = "netbsd")] Hdlc = 16, #[cfg(not(target_os = "netbsd"))] Hdlc = 112, @@ -210,7 +215,7 @@ impl ReceiveIndex { *self = match self { ReceiveIndex::FirstBlock(_) => ReceiveIndex::SecondBlock(0), ReceiveIndex::SecondBlock(_) => ReceiveIndex::FirstBlock(0), - } + } } } @@ -226,16 +231,14 @@ impl L2Socket { SocketAccess::WriteOnly => libc::O_WRONLY, }; - let mut fd = unsafe { libc::open(BPF_PATH.as_ptr(), mode) }; + let mut fd = unsafe { libc::open(BPF_PATH.as_ptr() as *const i8, mode) }; if fd >= 0 { - return Ok(L2Socket { - fd, - }) + return Ok(L2Socket { fd }); } - let errno = unsafe { *libc::__errno_location() }; + let errno = unsafe { *libc::__error() }; if errno != libc::ENOENT { - return Err(io::Error::from_raw_os_error(errno)) + return Err(io::Error::from_raw_os_error(errno)); } // `/dev/bpf` isn't available--try `/dev/bpfX` @@ -244,57 +247,57 @@ impl L2Socket { let device = CString::new(format!("/dev/bpf{}", dev_idx).into_bytes()).unwrap(); fd = unsafe { libc::open(device.as_ptr(), mode) }; if fd >= 0 { - return Ok(L2Socket { - fd, - }) + return Ok(L2Socket { fd }); } - let errno = unsafe { *libc::__errno_location() }; + let errno = unsafe { *libc::__error() }; if errno != libc::EBUSY { - break // Device wasn't in use, but some other error occurred--return + break; // Device wasn't in use, but some other error occurred--return } } - + Err(io::Error::last_os_error()) } pub fn bpf_version(&self) -> io::Result { - let mut version = bpf_version { - major: 0, - minor: 0, + let mut version = bpf_version { major: 0, minor: 0 }; + + let res = unsafe { + libc::ioctl( + self.fd, + BIOCVERSION, + ptr::addr_of_mut!(version) as *mut libc::c_char, + ) }; - - let res = unsafe { libc::ioctl(self.fd, BIOCVERSION, ptr::addr_of_mut!(version) as *mut libc::c_char) }; match res { 0 => Ok(BpfVersion { major: version.major, minor: version.minor, }), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), - + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Returns the maximum byte length of packets received by the socket. - /// + /// /// Any packet exceeding this length will be truncated to fit within the frame. pub fn frame_len(&self) -> io::Result { let mut frame_len: libc::c_uint = 0; let res = unsafe { libc::ioctl(self.fd, BIOCGBLEN, ptr::addr_of_mut!(frame_len)) }; match res { 0.. => Ok(frame_len), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Sets the maximum byte length of packets received by the socket. - /// + /// /// Any packet exceeding this length will be truncated to fit within the frame. pub fn set_frame_len(&self, mut frame_len: u32) -> io::Result<()> { let res = unsafe { libc::ioctl(self.fd, BIOCSBLEN, ptr::addr_of_mut!(frame_len)) }; match res { 0.. => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } @@ -304,7 +307,7 @@ impl L2Socket { let res = unsafe { libc::ioctl(self.fd, BIOCGDLT, ptr::addr_of_mut!(linktype)) }; match res { 0.. => Ok(linktype), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } @@ -317,7 +320,7 @@ impl L2Socket { let res = unsafe { libc::ioctl(self.fd, BIOCPROMISC) }; match res { 0.. => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } @@ -326,27 +329,28 @@ impl L2Socket { let res = unsafe { libc::ioctl(self.fd, BIOCFLUSH) }; match res { 0.. => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Binds the device to the given interface, enabling it to receive packets from that interface. pub fn bind(&self, iface: Interface) -> io::Result<()> { - let name = iface.name_raw()?; + let name = iface.name_raw(); let mut ifreq = libc::ifreq { ifr_name: array::from_fn(|i| if i < name.len() { name[i] as i8 } else { 0i8 }), ifr_ifru: libc::__c_anonymous_ifr_ifru { ifru_addr: libc::sockaddr { sa_family: 0, + sa_len: 0, sa_data: [0i8; 14], - } + }, }, }; let res = unsafe { libc::ioctl(self.fd, BIOCSETIF, ptr::addr_of_mut!(ifreq)) }; match res { 0 => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } @@ -357,20 +361,23 @@ impl L2Socket { ifr_ifru: libc::__c_anonymous_ifr_ifru { ifru_addr: libc::sockaddr { sa_family: 0, + sa_len: 0, sa_data: [0i8; 14], - } + }, }, }; let res = unsafe { libc::ioctl(self.fd, BIOCGETIF, ptr::addr_of_mut!(ifreq)) }; match res { - 0 => Ok(Interface::new(unsafe { CStr::from_ptr(ifreq.ifr_name.as_ptr()) })?), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + 0 => Ok(Interface::new(unsafe { + CStr::from_ptr(ifreq.ifr_name.as_ptr()) + })?), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Returns statistics on packets received and dropped by the socket. - pub fn stats(&self) -> io::Result { + pub fn stats(&self) -> io::Result { let mut stats = bpf_stat { bs_recv: 0, bs_drop: 0, @@ -378,66 +385,54 @@ impl L2Socket { let res = unsafe { libc::ioctl(self.fd, BIOCGSTATS, ptr::addr_of_mut!(stats)) }; match res { - 0.. => Ok(BpfStatistics { + 0.. => Ok(PacketStatistics { received: stats.bs_recv, dropped: stats.bs_drop, }), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Sets the socket to return immediately on packet reception. pub fn set_immediate(&self, immediate: bool) -> io::Result<()> { - let mut immediate: libc::c_uint = if immediate { - 1 - } else { - 0 - }; + let mut immediate: libc::c_uint = if immediate { 1 } else { 0 }; let res = unsafe { libc::ioctl(self.fd, BIOCIMMEDIATE, ptr::addr_of_mut!(immediate)) }; match res { 0.. => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Enables or disables nonblocking I/O for the given socket. - /// + /// /// When enabled, calls to [`send()`](Self::send) or [`recv()`](Self::recv) will return an error /// of kind [`io::ErrorKind::WouldBlock`] if the socket is unable to immediately send or receive /// a packet. pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking: libc::c_int = if nonblocking { - 1 - } else { - 0 - }; + let mut nonblocking: libc::c_int = if nonblocking { 1 } else { 0 }; let res = unsafe { libc::ioctl(self.fd, libc::FIONBIO, ptr::addr_of_mut!(nonblocking)) }; match res { 0.. => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Enables or disables capture of packets that are specifically sent out by the socket via /// `send()`[Self::send]. - /// + /// /// When enabled, injected link-layer packets sent via [`send()`](Self::send) will appear in /// subsequent calls to [`recv()`](Self::recv). - /// + /// /// This option is set to disabled by default. pub fn set_feedback(&self, allow_feedback: bool) -> io::Result<()> { - let mut allow_feedback: libc::c_int = if allow_feedback { - 1 - } else { - 0 - }; + let mut allow_feedback: libc::c_int = if allow_feedback { 1 } else { 0 }; let res = unsafe { libc::ioctl(self.fd, BIOCFEEDBACK, ptr::addr_of_mut!(allow_feedback)) }; match res { 0.. => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } @@ -446,16 +441,22 @@ impl L2Socket { let res = unsafe { libc::ioctl(self.fd, BIOCLOCK) }; match res { 0.. => Ok(()), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Send a link-layer packet on the interface bound to the given socket. pub fn send(&self, packet: &[u8]) -> io::Result { - let res = unsafe { libc::write(self.fd, packet.as_ptr() as *const libc::c_void, packet.len()) }; + let res = unsafe { + libc::write( + self.fd, + packet.as_ptr() as *const libc::c_void, + packet.len(), + ) + }; match res { 0.. => Ok(res as usize), - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } @@ -465,16 +466,17 @@ impl L2Socket { match res { 0.. => { let data = &mut buf[..res as usize]; - RxFrameIter { - rem: data, - }.next().ok_or(io::Error::new(io::ErrorKind::InvalidData, "recv() returned corrupt frame--insufficient buffer length?")) - }, - _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })), + RxFrameIter { rem: data }.next().ok_or(io::Error::new( + io::ErrorKind::InvalidData, + "recv() returned corrupt frame--insufficient buffer length?", + )) + } + _ => Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })), } } /// Enable memory-mapped I/O for incoming packets. - /// + /// /// In the event of failure, the consumed `L2Socket` will automatically be closed. pub fn packet_rx_ring(self, buffer_size: usize) -> io::Result { let flags = libc::MAP_ANONYMOUS; // MAP_ANONYMOUS initializes contents to zero. @@ -482,15 +484,15 @@ impl L2Socket { let ringbuf = unsafe { libc::mmap(ptr::null_mut(), buffer_size * 2, prot, flags, -1, 0) }; if ringbuf == libc::MAP_FAILED { - let errno = unsafe { *libc::__errno_location() }; + let errno = unsafe { *libc::__error() }; // Clean up socket unsafe { libc::close(self.fd) }; - return Err(io::Error::from_raw_os_error(errno)) + return Err(io::Error::from_raw_os_error(errno)); } let mut req = bpf_zbuf { bz_bufa: ringbuf, - bz_bufb: unsafe { ringbuf.byte_add(buffer_size) }, + bz_bufb: unsafe { (ringbuf as *mut u8).add(buffer_size) as *mut libc::c_void }, bz_buflen: buffer_size, }; @@ -507,9 +509,9 @@ impl L2Socket { unsafe { libc::close(self.fd) }; unsafe { libc::munmap(ringbuf, buffer_size * 2) }; - Err(io::Error::from_raw_os_error(unsafe { *libc::__errno_location() })) + Err(io::Error::from_raw_os_error(unsafe { *libc::__error() })) } - } + } } } @@ -531,7 +533,7 @@ impl L2RxMappedSocket { pub fn rx_ring(&mut self) -> RxRing<'_> { RxRing { block_1: self.raw, - block_2: unsafe { self.raw.byte_add(self.buflen) }, + block_2: unsafe { (self.raw as *mut u8).add(self.buflen) as *mut libc::c_void }, recv_idx: &mut self.recv_idx, } } @@ -544,12 +546,17 @@ impl L2RxMappedSocket { pub fn mapped_recv(&mut self) -> Option> { let (raw, block_idx) = match self.recv_idx { ReceiveIndex::FirstBlock(i) => (self.raw, i), - ReceiveIndex::SecondBlock(i) => unsafe { (self.raw.byte_add(self.buflen), i) }, + ReceiveIndex::SecondBlock(i) => unsafe { + ( + (self.raw as *mut u8).add(self.buflen) as *mut libc::c_void, + i, + ) + }, }; let data = unsafe { RxBlock::block_parts(raw)?.1 }; let mut iter = RxFrameIter { - rem: &mut data[block_idx..] + rem: &mut data[block_idx..], }; let prev_len = iter.rem.len(); @@ -611,7 +618,7 @@ pub struct RxBlock<'a> { impl<'a> RxBlock<'a> { unsafe fn block_parts(buf: *mut libc::c_void) -> Option<(&'a mut BpfHeader, &'a mut [u8])> { let header = &mut *(buf as *mut BpfHeader); - let buf_start = buf.byte_add(mem::size_of::()) as *mut u8; + let buf_start = (buf as *mut u8).add(mem::size_of::()); let user_gen = header.bzh_user_gen.load(Ordering::Acquire); let kernel_gen = header.bzh_kernel_gen.load(Ordering::Acquire); @@ -626,9 +633,7 @@ impl<'a> RxBlock<'a> { #[inline] pub fn frames(&'a mut self) -> RxFrameIter<'a> { - RxFrameIter { - rem: self.data, - } + RxFrameIter { rem: self.data } } pub fn mark_read(self) { @@ -645,7 +650,9 @@ impl<'a> RxBlock<'a> { // Mark the block as ready to be written to by the kernel let kernel_gen = self.header.bzh_kernel_gen.load(Ordering::Acquire); - self.header.bzh_user_gen.store(kernel_gen, Ordering::Release); + self.header + .bzh_user_gen + .store(kernel_gen, Ordering::Release); } } @@ -655,10 +662,10 @@ pub struct RxFrameIter<'a> { impl<'a> Iterator for RxFrameIter<'a> { type Item = RxFrame<'a>; - + fn next(&mut self) -> Option { if self.rem.len() < mem::size_of::() { - return None + return None; } let hdr_bytes = &self.rem[..mem::size_of::()]; @@ -675,13 +682,13 @@ impl<'a> Iterator for RxFrameIter<'a> { let padding = padded_len - unpadded_len; if self.rem.len() < padded_len { - return None + return None; } let rem = mem::replace(&mut self.rem, &mut []); let rem = &mut rem[offset_to_start..]; let (pkt, rem) = rem.split_at_mut(caplen); - + self.rem = rem.get_mut(padding..).unwrap_or(&mut []); Some(RxFrame { data: pkt, diff --git a/rscap/src/dlpi.rs b/rscap/src/dlpi.rs index a63a14c..e579a32 100644 --- a/rscap/src/dlpi.rs +++ b/rscap/src/dlpi.rs @@ -9,7 +9,5 @@ // except according to those terms. //! (Solaris/Illumos) Data Link Provider Interface (DLPI) raw mode packet capture and transmission. -//! -//! - - +//! +//! diff --git a/rscap/src/filter.rs b/rscap/src/filter.rs index 608ac9d..cb6f235 100644 --- a/rscap/src/filter.rs +++ b/rscap/src/filter.rs @@ -1,9 +1,6 @@ - - //! Cross-platform packet filtering utilities. -//! -//! - +//! +//! #[derive(Clone, Debug)] pub struct PacketStatistics { diff --git a/rscap/src/lib.rs b/rscap/src/lib.rs index 87e91e3..90992c3 100644 --- a/rscap/src/lib.rs +++ b/rscap/src/lib.rs @@ -9,19 +9,28 @@ // except according to those terms. //! Rust packet capture and manipulation utilities. -//! -//! +//! +//! use std::ffi::CStr; use std::io; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] -pub mod bsd; -#[cfg(target_os = "linux")] -pub mod linux; +#[cfg(target_os = "windows")] +use windows_sys::Win32::NetworkManagement::IpHelper::MAX_ADAPTER_NAME; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +pub mod bpf; #[cfg(any(target_os = "illumos", target_os = "solaris"))] pub mod dlpi; pub mod filter; +#[cfg(target_os = "linux")] +pub mod linux; #[cfg(all(target_os = "windows", feature = "npcap"))] pub mod npcap; #[cfg(target_os = "windows")] @@ -30,8 +39,7 @@ pub mod pktmon; #[cfg(not(target_os = "windows"))] const INTERNAL_MAX_INTERFACE_NAME_LEN: usize = libc::IF_NAMESIZE - 1; #[cfg(target_os = "windows")] -const INTERNAL_MAX_INTERFACE_NAME_LEN: usize = MAX_ADAPTER_NAME_LEN - 1; - +const INTERNAL_MAX_INTERFACE_NAME_LEN: usize = MAX_ADAPTER_NAME as usize - 1; // pub use pkts::*; @@ -56,10 +64,10 @@ pub struct Interface { } impl Interface { - const ANY: &'static CStr = c"any"; + const ANY: &[u8] = b"any\0"; /// The maximum length (in bytes) that an interface name can be. - /// + /// /// Note that this value is platform-dependent. It determines the size of the buffer used for /// storing the interface name in an `Interface` instance, so the size of an `Interface` is /// likewise platform-dependent. @@ -68,7 +76,7 @@ impl Interface { /// A special catch-all interface identifier that specifies all operational interfaces. pub fn any() -> io::Result { let mut name = [0u8; Self::MAX_INTERFACE_NAME_LEN + 1]; - name[..Self::ANY.to_bytes().len()].copy_from_slice(Self::ANY.to_bytes()); + name[..Self::ANY.len()].copy_from_slice(Self::ANY); Ok(Self { name, @@ -95,8 +103,6 @@ impl Interface { /// Find all available interfaces on the given machine. pub fn find_all() -> io::Result> { - - todo!() } @@ -123,7 +129,10 @@ impl Interface { let mut name = [0u8; Self::MAX_INTERFACE_NAME_LEN + 1]; name[..if_name.len()].copy_from_slice(if_name); - let interface = Interface { name, is_catchall: false, }; + let interface = Interface { + name, + is_catchall: false, + }; // If we can, check to see if the interface is valid #[cfg(not(target_os = "windows"))] @@ -142,7 +151,7 @@ impl Interface { pub fn from_index(if_index: u32) -> io::Result { // TODO: do systems other than Linux actually consider '0' to be a catchall? if if_index == 0 { - return Self::any() + return Self::any(); } let mut name = [0u8; Self::MAX_INTERFACE_NAME_LEN + 1]; @@ -151,7 +160,7 @@ impl Interface { _ => Ok(Self { name, is_catchall: false, - }) + }), } } @@ -175,14 +184,20 @@ impl Interface { /// Otherwise, a returned error indicates that [`Interface`] does not correspond to a valid /// interface. pub fn name(&self) -> &CStr { - CStr::from_bytes_until_nul(&self.name).unwrap() + unsafe { CStr::from_ptr(self.name.as_ptr() as *const i8) } } /// Returns the raw byte name associated with the given interface. /// /// The returned byte slice contains a single null-terminating character at the end of the slice. pub fn name_raw(&self) -> &[u8] { - let end = self.name.iter().enumerate().find(|(_, c)| **c == b'\0').unwrap().0; + let end = self + .name + .iter() + .enumerate() + .find(|(_, c)| **c == b'\0') + .unwrap() + .0; &self.name[..end + 1] } } diff --git a/rscap/src/linux.rs b/rscap/src/linux.rs index 93b19bb..1b8084c 100644 --- a/rscap/src/linux.rs +++ b/rscap/src/linux.rs @@ -21,11 +21,247 @@ pub mod addr; pub mod l2; pub mod l3; pub mod l4; -#[cfg(feature = "libcfull")] pub mod mapped; -pub mod sndrcv; #[doc(hidden)] pub mod prelude; +pub mod sndrcv; + +// Temporarily used until they are merged into libc: + +pub(crate) const PACKET_HOST: libc::c_uchar = 0; +pub(crate) const PACKET_BROADCAST: libc::c_uchar = 1; +pub(crate) const PACKET_MULTICAST: libc::c_uchar = 2; +pub(crate) const PACKET_OTHERHOST: libc::c_uchar = 3; +pub(crate) const PACKET_OUTGOING: libc::c_uchar = 4; +pub(crate) const PACKET_LOOPBACK: libc::c_uchar = 5; +pub(crate) const PACKET_USER: libc::c_uchar = 6; +pub(crate) const PACKET_KERNEL: libc::c_uchar = 7; + +pub(crate) const PACKET_RX_RING: libc::c_int = 5; +pub(crate) const PACKET_STATISTICS: libc::c_int = 6; +pub(crate) const PACKET_AUXDATA: libc::c_int = 8; +pub(crate) const PACKET_VERSION: libc::c_int = 10; +pub(crate) const PACKET_RESERVE: libc::c_int = 12; +pub(crate) const PACKET_TX_RING: libc::c_int = 13; +pub(crate) const PACKET_LOSS: libc::c_int = 14; +pub(crate) const PACKET_TIMESTAMP: libc::c_int = 17; +pub(crate) const PACKET_FANOUT: libc::c_int = 18; +pub(crate) const PACKET_QDISC_BYPASS: libc::c_int = 20; + +pub(crate) const PACKET_FANOUT_HASH: libc::c_uint = 0; +pub(crate) const PACKET_FANOUT_LB: libc::c_uint = 1; +pub(crate) const PACKET_FANOUT_CPU: libc::c_uint = 2; +pub(crate) const PACKET_FANOUT_ROLLOVER: libc::c_uint = 3; +pub(crate) const PACKET_FANOUT_RND: libc::c_uint = 4; +pub(crate) const PACKET_FANOUT_QM: libc::c_uint = 5; +pub(crate) const PACKET_FANOUT_CBPF: libc::c_uint = 6; +pub(crate) const PACKET_FANOUT_EBPF: libc::c_uint = 7; +pub(crate) const PACKET_FANOUT_FLAG_ROLLOVER: libc::c_uint = 0x1000; +pub(crate) const PACKET_FANOUT_FLAG_UNIQUEID: libc::c_uint = 0x2000; +pub(crate) const PACKET_FANOUT_FLAG_DEFRAG: libc::c_uint = 0x8000; + +pub(crate) const TP_STATUS_KERNEL: libc::__u32 = 0; +pub(crate) const TP_STATUS_USER: libc::__u32 = 1 << 0; +pub(crate) const TP_STATUS_COPY: libc::__u32 = 1 << 1; +pub(crate) const TP_STATUS_LOSING: libc::__u32 = 1 << 2; +pub(crate) const TP_STATUS_CSUMNOTREADY: libc::__u32 = 1 << 3; +pub(crate) const TP_STATUS_VLAN_VALID: libc::__u32 = 1 << 4; +pub(crate) const TP_STATUS_BLK_TMO: libc::__u32 = 1 << 5; +pub(crate) const TP_STATUS_VLAN_TPID_VALID: libc::__u32 = 1 << 6; +pub(crate) const TP_STATUS_CSUM_VALID: libc::__u32 = 1 << 7; + +pub(crate) const TP_STATUS_AVAILABLE: libc::__u32 = 0; +pub(crate) const TP_STATUS_SEND_REQUEST: libc::__u32 = 1 << 0; +pub(crate) const TP_STATUS_SENDING: libc::__u32 = 1 << 1; +pub(crate) const TP_STATUS_WRONG_FORMAT: libc::__u32 = 1 << 2; + +pub(crate) const TP_STATUS_TS_SOFTWARE: libc::__u32 = 1 << 29; +pub(crate) const TP_STATUS_TS_SYS_HARDWARE: libc::__u32 = 1 << 30; +pub(crate) const TP_STATUS_TS_RAW_HARDWARE: libc::__u32 = 1 << 31; + +pub(crate) const TP_FT_REQ_FILL_RXHASH: libc::__u32 = 1; + +pub(crate) const TPACKET_ALIGNMENT: usize = 16; + +#[repr(align(8))] +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket_rollover_stats { + pub tp_all: libc::__u64, + pub tp_huge: libc::__u64, + pub tp_failed: libc::__u64, +} + +#[repr(align(8))] +#[repr(C)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy)] +pub struct tpacket_hdr_v1 { + pub block_status: libc::__u32, + pub num_pkts: libc::__u32, + pub offset_to_first_pkt: libc::__u32, + pub blk_len: libc::__u32, + pub seq_num: libc::__u64, + pub ts_first_pkt: tpacket_bd_ts, + pub ts_last_pkt: tpacket_bd_ts, +} + +#[repr(u32)] +#[allow(non_camel_case_types)] +pub enum tpacket_versions { + TPACKET_V1, + TPACKET_V2, + TPACKET_V3, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct fanout_args { + #[cfg(target_endian = "little")] + pub id: libc::__u16, + pub type_flags: libc::__u16, + #[cfg(target_endian = "big")] + pub id: libc::__u16, + pub max_num_members: libc::__u32, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct sockaddr_pkt { + pub spkt_family: libc::c_ushort, + pub spkt_device: [libc::c_uchar; 14], + pub spkt_protocol: libc::c_ushort, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket_auxdata { + pub tp_status: libc::__u32, + pub tp_len: libc::__u32, + pub tp_snaplen: libc::__u32, + pub tp_mac: libc::__u16, + pub tp_net: libc::__u16, + pub tp_vlan_tci: libc::__u16, + pub tp_vlan_tpid: libc::__u16, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket_hdr { + pub tp_status: libc::c_ulong, + pub tp_len: libc::c_uint, + pub tp_snaplen: libc::c_uint, + pub tp_mac: libc::c_ushort, + pub tp_net: libc::c_ushort, + pub tp_sec: libc::c_uint, + pub tp_usec: libc::c_uint, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket_hdr_variant1 { + pub tp_rxhash: libc::__u32, + pub tp_vlan_tci: libc::__u32, + pub tp_vlan_tpid: libc::__u16, + pub tp_padding: libc::__u16, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket2_hdr { + pub tp_status: libc::__u32, + pub tp_len: libc::__u32, + pub tp_snaplen: libc::__u32, + pub tp_mac: libc::__u16, + pub tp_net: libc::__u16, + pub tp_sec: libc::__u32, + pub tp_nsec: libc::__u32, + pub tp_vlan_tci: libc::__u16, + pub tp_vlan_tpid: libc::__u16, + pub tp_padding: [libc::__u8; 4], +} + +#[repr(C)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy)] +pub struct tpacket_req { + pub tp_block_size: libc::c_uint, + pub tp_block_nr: libc::c_uint, + pub tp_frame_size: libc::c_uint, + pub tp_frame_nr: libc::c_uint, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy)] +pub struct tpacket_req3 { + pub tp_block_size: libc::c_uint, + pub tp_block_nr: libc::c_uint, + pub tp_frame_size: libc::c_uint, + pub tp_frame_nr: libc::c_uint, + pub tp_retire_blk_tov: libc::c_uint, + pub tp_sizeof_priv: libc::c_uint, + pub tp_feature_req_word: libc::c_uint, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket_stats { + pub tp_packets: libc::c_uint, + pub tp_drops: libc::c_uint, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket_stats_v3 { + pub tp_packets: libc::c_uint, + pub tp_drops: libc::c_uint, + pub tp_freeze_q_cnt: libc::c_uint, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket3_hdr { + pub tp_next_offset: libc::__u32, + pub tp_sec: libc::__u32, + pub tp_nsec: libc::__u32, + pub tp_snaplen: libc::__u32, + pub tp_len: libc::__u32, + pub tp_status: libc::__u32, + pub tp_mac: libc::__u16, + pub tp_net: libc::__u16, + pub hv1: tpacket_hdr_variant1, + pub tp_padding: [libc::__u8; 8], +} + +#[repr(C)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy)] +pub struct tpacket_bd_ts { + pub ts_sec: libc::c_uint, + pub ts_usec: libc::c_uint, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub union tpacket_req_u { + pub req: tpacket_req, + pub req3: tpacket_req3, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub union tpacket_bd_header_u { + pub bh1: tpacket_hdr_v1, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct tpacket_block_desc { + pub version: libc::__u32, + pub offset_to_priv: libc::__u32, + pub hdr: tpacket_bd_header_u, +} // What kind of sockets does Linux support? // diff --git a/rscap/src/linux/addr.rs b/rscap/src/linux/addr.rs index c160418..b02fc52 100644 --- a/rscap/src/linux/addr.rs +++ b/rscap/src/linux/addr.rs @@ -15,9 +15,9 @@ //! address types for each link-layer protocol available. A generalized type of all of these possible //! protocols is additionally made available as [`L2AddrAny`]. -use std::{array, io}; use std::fmt::{Debug, Display}; use std::str::FromStr; +use std::{array, io}; use crate::Interface; @@ -239,15 +239,28 @@ impl TryFrom for L2AddrIp { #[inline] fn try_from(value: libc::sockaddr_ll) -> Result { if value.sll_family != libc::AF_PACKET as u16 { - return Err(io::Error::new(io::ErrorKind::Unsupported, "unrecognized address family (not AF_PACKET)")) + return Err(io::Error::new( + io::ErrorKind::Unsupported, + "unrecognized address family (not AF_PACKET)", + )); } if value.sll_protocol != libc::ETH_P_IP as u16 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, format!("sockaddr link-layer protocol did not match type (expected {}, was {})", libc::ETH_P_IP as u16, value.sll_protocol))); + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!( + "sockaddr link-layer protocol did not match type (expected {}, was {})", + libc::ETH_P_IP as u16, + value.sll_protocol + ), + )); } if value.sll_halen != 6 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid sockaddr link-layer address length")) + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "invalid sockaddr link-layer address length", + )); } let addr: [u8; 6] = array::from_fn(|i| value.sll_addr[i]); @@ -356,12 +369,20 @@ impl TryFrom for L2AddrUnspec { fn try_from(value: libc::sockaddr_ll) -> Result { if value.sll_family != libc::AF_PACKET as u16 { - return Err(io::Error::new(io::ErrorKind::Unsupported, "unrecognized address family (not AF_PACKET)")); + return Err(io::Error::new( + io::ErrorKind::Unsupported, + "unrecognized address family (not AF_PACKET)", + )); } let mut addr = Buffer::new(); match value.sll_addr.get(..value.sll_halen as usize) { - None => return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid sockaddr link-layer address length")), + None => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "invalid sockaddr link-layer address length", + )) + } Some(s) => addr.append(s), } diff --git a/rscap/src/linux/l2.rs b/rscap/src/linux/l2.rs index 4580ebb..7172e5d 100644 --- a/rscap/src/linux/l2.rs +++ b/rscap/src/linux/l2.rs @@ -14,13 +14,11 @@ use std::{io, mem, os::fd::AsRawFd, ptr}; use super::addr::{L2Addr, L2AddrAny}; -#[cfg(feature = "libcfull")] use super::mapped::{ BlockConfig, FrameIndex, OsiLayer, PacketRxRing, PacketTxRing, RxFrame, TxFrame, TxFrameVariant, }; -#[cfg(feature = "libcfull")] -use super::{FanoutAlgorithm, PacketStatistics, RxTimestamping, TxTimestamping}; -#[cfg(feature = "libcfull")] +use super::{FanoutAlgorithm, RxTimestamping, TxTimestamping}; + use crate::filter::PacketStatistics; /// A socket that exchanges packets at the link-layer. @@ -104,7 +102,6 @@ impl L2Socket { /// kernel will not be buffering packets originating from the socket). /// /// This option is disabled (`false`) by default. - #[cfg(feature = "libcfull")] pub fn set_qdisc_bypass(&self, bypass: bool) -> io::Result<()> { let bypass_req = if bypass { 1u32 } else { 0u32 }; @@ -112,7 +109,7 @@ impl L2Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_QDISC_BYPASS, + crate::linux::PACKET_QDISC_BYPASS, ptr::addr_of!(bypass_req) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -128,31 +125,30 @@ impl L2Socket { /// Packet statistics include [`packets_seen`](PacketStatistics::packets_seen) and /// [`packets_dropped`](PacketStatistics::packets_dropped); both of these counters are reset /// each time `packet_stats()` is called. - #[cfg(feature = "libcfull")] pub fn packet_stats(&self) -> io::Result { - let mut stats = libc::tpacket_stats { + let mut stats = crate::linux::tpacket_stats { tp_packets: 0, tp_drops: 0, }; - let mut stats_len = mem::size_of::() as u32; + let mut stats_len = mem::size_of::() as u32; if unsafe { libc::getsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_STATISTICS, + crate::linux::PACKET_STATISTICS, ptr::addr_of_mut!(stats) as *mut libc::c_void, ptr::addr_of_mut!(stats_len), ) != 0 } { return Err(io::Error::last_os_error()); } - debug_assert!(stats_len == mem::size_of::() as u32); + debug_assert!(stats_len == mem::size_of::() as u32); Ok(PacketStatistics { - packets_seen: stats.tp_packets as usize, - packets_dropped: stats.tp_drops as usize, + received: stats.tp_packets, + dropped: stats.tp_drops, }) } @@ -204,7 +200,6 @@ impl L2Socket { /// `ERANGE` - the requested packets cannot be timestamped by hardware. /// /// `EINVAL` - hardware timestamping is not supported by the network card. - #[cfg(feature = "libcfull")] fn set_timestamp_method(&self, tx: TxTimestamping, rx: RxTimestamping) -> io::Result<()> { if tx == TxTimestamping::Hardware || rx == RxTimestamping::Hardware { let mut hwtstamp_config = libc::hwtstamp_config { @@ -226,7 +221,7 @@ impl L2Socket { let mut if_name = [0i8; libc::IF_NAMESIZE]; let if_name_ptr = if_name.as_mut_ptr(); - let res = unsafe { libc::if_indextoname(addr.interface().index(), if_name_ptr) }; + let res = unsafe { libc::if_indextoname(addr.interface().index()?, if_name_ptr) }; if res.is_null() { return Err(io::Error::last_os_error()); } @@ -258,9 +253,9 @@ impl L2Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_TIMESTAMP, + crate::linux::PACKET_TIMESTAMP, ptr::addr_of!(timestamp_req) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -314,7 +309,6 @@ impl L2Socket { /// fanout group (e.g. to ensure [`FanoutAlgorithm::Hash`] works despite fragmentation) /// - `rollover` causes packets to be sent to a different socket than originally decided /// by `fan_alg` if the original socket is backlogged with packets. - #[cfg(feature = "libcfull")] pub fn set_fanout( &self, group_id: u16, @@ -323,29 +317,29 @@ impl L2Socket { rollover: bool, ) -> io::Result<()> { let mut opt = match fan_alg { - FanoutAlgorithm::Cpu => libc::PACKET_FANOUT_CPU, - FanoutAlgorithm::Hash => libc::PACKET_FANOUT_HASH, - FanoutAlgorithm::QueueMapping => libc::PACKET_FANOUT_QM, - FanoutAlgorithm::Random => libc::PACKET_FANOUT_RND, - FanoutAlgorithm::Rollover => libc::PACKET_FANOUT_ROLLOVER, - FanoutAlgorithm::RoundRobin => libc::PACKET_FANOUT_LB, + FanoutAlgorithm::Cpu => crate::linux::PACKET_FANOUT_CPU, + FanoutAlgorithm::Hash => crate::linux::PACKET_FANOUT_HASH, + FanoutAlgorithm::QueueMapping => crate::linux::PACKET_FANOUT_QM, + FanoutAlgorithm::Random => crate::linux::PACKET_FANOUT_RND, + FanoutAlgorithm::Rollover => crate::linux::PACKET_FANOUT_ROLLOVER, + FanoutAlgorithm::RoundRobin => crate::linux::PACKET_FANOUT_LB, }; opt |= (group_id as u32) << 16; if defrag { - opt |= libc::PACKET_FANOUT_FLAG_DEFRAG; + opt |= crate::linux::PACKET_FANOUT_FLAG_DEFRAG; } if rollover { - opt |= libc::PACKET_FANOUT_FLAG_ROLLOVER; + opt |= crate::linux::PACKET_FANOUT_FLAG_ROLLOVER; } if unsafe { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_FANOUT, + crate::linux::PACKET_FANOUT, ptr::addr_of!(opt) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -450,16 +444,15 @@ impl L2Socket { } /// Sets the PACKET_VERSION socket option to TPACKET_V3. - #[cfg(feature = "libcfull")] fn set_tpacket_v3_opt(&self) -> io::Result<()> { - let pkt_version_3 = libc::tpacket_versions::TPACKET_V3; + let pkt_version_3 = crate::linux::tpacket_versions::TPACKET_V3; if unsafe { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_VERSION, + crate::linux::PACKET_VERSION, ptr::addr_of!(pkt_version_3) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -469,9 +462,8 @@ impl L2Socket { } /// Sets the PACKET_TX_RING socket option. - #[cfg(feature = "libcfull")] fn set_tx_ring_opt(&self, config: BlockConfig) -> io::Result<()> { - let req_tx = libc::tpacket_req3 { + let req_tx = crate::linux::tpacket_req3 { tp_block_size: config.block_size(), tp_block_nr: config.block_cnt(), tp_frame_size: config.frame_size(), @@ -485,9 +477,9 @@ impl L2Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_TX_RING, + crate::linux::PACKET_TX_RING, ptr::addr_of!(req_tx) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -497,7 +489,6 @@ impl L2Socket { } /// Sets the PACKET_RX_RING socket option. - #[cfg(feature = "libcfull")] fn set_rx_ring_opt( &self, config: BlockConfig, @@ -508,7 +499,7 @@ impl L2Socket { timeout = Some(1); // Prevent user from accidentally selecting kernel default } - let req_rx = libc::tpacket_req3 { + let req_rx = crate::linux::tpacket_req3 { tp_block_size: config.block_size(), tp_block_nr: config.block_cnt(), tp_frame_size: config.frame_size(), @@ -522,9 +513,9 @@ impl L2Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_RX_RING, + crate::linux::PACKET_RX_RING, ptr::addr_of!(req_rx) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -536,7 +527,6 @@ impl L2Socket { /// Memory-map the packet's TX/RX ring buffers to enable zero-copy packet exchange. /// /// On error, the consumed [`L2Socket`] will be closed. - #[cfg(feature = "libcfull")] fn mmap_socket( &self, config: BlockConfig, @@ -573,7 +563,6 @@ impl L2Socket { /// NOTE: some performance issues have been noted when TX_RING sockets are used in blocking mode (see /// [here](https://stackoverflow.com/questions/43193889/sending-data-with-packet-mmap-and-packet-tx-ring-is-slower-than-normal-withou)). /// It is recommended that the socket be set as nonblocking before calling `packet_ring`. - #[cfg(feature = "libcfull")] pub fn packet_ring( self, config: BlockConfig, @@ -593,12 +582,8 @@ impl L2Socket { ) }; - let tx_ring = unsafe { - PacketTxRing::new( - (mapping as *mut u8).add(config.map_length()), - config, - ) - }; + let tx_ring = + unsafe { PacketTxRing::new((mapping as *mut u8).add(config.map_length()), config) }; // This will immediately wrap around to the first packet due to `frame_offset: None` let start_frame = FrameIndex { @@ -625,18 +610,12 @@ impl L2Socket { /// In past kernel versions, some performance issues have been noted when TX_RING sockets are /// used in blocking mode (see [here](https://stackoverflow.com/questions/43193889/sending-data-with-packet-mmap-and-packet-tx-ring-is-slower-than-normal-withou)). /// It is recommended that the socket be set as nonblocking before calling `packet_tx_ring`. - #[cfg(feature = "libcfull")] pub fn packet_tx_ring(self, config: BlockConfig) -> io::Result { self.set_tpacket_v3_opt()?; self.set_tx_ring_opt(config)?; let mapping = self.mmap_socket(config, false)?; - let tx_ring = unsafe { - PacketTxRing::new( - mapping as *mut u8, - config, - ) - }; + let tx_ring = unsafe { PacketTxRing::new(mapping as *mut u8, config) }; // This will immediately wrap around to the first packet due to `frame_offset: None` let start_frame = FrameIndex { @@ -657,7 +636,6 @@ impl L2Socket { /// Enables zero-copy packet reception for the socket. /// /// On error, the consumed `L2Socket` will be closed. - #[cfg(feature = "libcfull")] pub fn packet_rx_ring( self, config: BlockConfig, @@ -705,7 +683,6 @@ impl AsRawFd for L2Socket { } /// A link-layer socket with zero-copy packet transmission and reception. -#[cfg(feature = "libcfull")] pub struct L2MappedSocket { socket: L2Socket, rx_ring: PacketRxRing, @@ -717,7 +694,6 @@ pub struct L2MappedSocket { tx_full: bool, } -#[cfg(feature = "libcfull")] impl L2MappedSocket { /// Bind the link-layer socket to a particular protocol/address and interface and begin /// receiving packets. @@ -751,7 +727,7 @@ impl L2MappedSocket { libc::setsockopt( self.socket.fd, libc::SOL_PACKET, - libc::PACKET_RESERVE, + crate::linux::PACKET_RESERVE, ptr::addr_of!(amount) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -841,7 +817,7 @@ impl L2MappedSocket { } /// Sends a datagram over the socket. On success, returns the number of bytes written. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L2Socket::send()`]. If you are looking to send a memory-mapped packet, use /// [`mapped_send()`](L2MappedSocket::mapped_send()) instead. @@ -883,7 +859,7 @@ impl L2MappedSocket { } /// Receive a datagram from the socket. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L2Socket::recv()`]. If you are looking to receive a memory-mapped packet, use /// [`mapped_recv()`](L2MappedSocket::mapped_recv()) instead. @@ -910,6 +886,40 @@ impl L2MappedSocket { Some(rx_frame) } + // + // # Examples + // + // ``` + // use std::{thread, time::Duration}; + // use rscap::linux::prelude::*; + // use rscap::linux::mapped::TxFrameVariant; + // + // let mut sock = L2Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?)?; + // sock.manual_tx_status(true); + // let mut sending = 0; + // let mut malformed = 0; + // for _ in 0..5 { + // let mut tx_frame = sock.mapped_send().unwrap(); + // tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed + // tx_frame.send(11); + // sending += 1; + // } + // + // while sending > 0 { + // match sock.tx_status() { + // TxFrameVariant::Available(_) => sending -= 1, + // TxFrameVariant::WrongFormat(pkt) => { + // println!("Malformed packet: {:?}", pkt.data()); + // malformed += 1; + // sending -= 1; + // } + // TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), + // } + // } + // + // assert!(malformed == 5); + // ``` + /// Checks the status of previously-sent packets in the order they were sent. /// /// By default, or when `manual_tx_status` is set to `false`, this method will only return the @@ -927,38 +937,6 @@ impl L2MappedSocket { /// [`TxFrameVariant::WrongFormat`], the kernel has rejected the packet, and the count of pending /// packets should be decremented. The contents of the packet can be retrieved from the /// [`InvalidTxFrame`](super::mapped::InvalidTxFrame) if desired. - /// - /// # Examples - /// - /// ``` - /// use std::{thread, time::Duration}; - /// use rscap::linux::prelude::*; - /// - /// let mut sock = L2Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?); - /// sock.manual_tx_status(true); - /// let mut sending = 0; - /// let mut malformed = 0; - /// for _ in 0..5 { - /// let mut tx_frame = sock.mapped_send().unwrap(); - /// tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed - /// tx_frame.send(11); - /// sending += 1; - /// } - /// - /// while sending > 0 { - /// match sock.tx_status() { - /// TxFrameVariant::Available(_) => sending -= 1, - /// TxFrameVariant::WrongFormat(pkt) => { - /// println!("Malformed packet: {:?}", pkt.data()); - /// malformed += 1; - /// sending -= 1; - /// } - /// TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), - /// } - /// } - /// - /// assert!(malformed == 5); - /// ``` #[inline] pub fn tx_status(&mut self) -> TxFrameVariant<'_> { let (frame_variant, next_tx) = self.tx_ring.next_frame(self.last_checked_tx); @@ -976,7 +954,6 @@ impl L2MappedSocket { } } -#[cfg(feature = "libcfull")] impl Drop for L2MappedSocket { fn drop(&mut self) { unsafe { @@ -989,7 +966,6 @@ impl Drop for L2MappedSocket { } } -#[cfg(feature = "libcfull")] impl AsRawFd for L2MappedSocket { #[inline] fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { @@ -998,7 +974,6 @@ impl AsRawFd for L2MappedSocket { } /// A link-layer socket with zero-copy packet transmission. -#[cfg(feature = "libcfull")] pub struct L2TxMappedSocket { socket: L2Socket, tx_ring: PacketTxRing, @@ -1008,7 +983,6 @@ pub struct L2TxMappedSocket { tx_full: bool, } -#[cfg(feature = "libcfull")] impl L2TxMappedSocket { /// Bind the link-layer socket to a particular protocol/address and interface and begin /// receiving packets. @@ -1066,7 +1040,7 @@ impl L2TxMappedSocket { } /// Receive a datagram from the socket. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L2Socket::recv()`]. If you are looking to receive a memory-mapped packet, use /// [`L2MappedSocket::mapped_recv()`] instead. @@ -1078,7 +1052,7 @@ impl L2TxMappedSocket { } /// Sends a datagram over the socket. On success, returns the number of bytes written. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L2Socket::send()`]. If you are looking to send a memory-mapped packet, use /// [`mapped_send()`](L2MappedSocket::mapped_send()) instead. @@ -1134,6 +1108,40 @@ impl L2TxMappedSocket { self.manual_tx_status = manual; } + // + // # Examples + // + // ``` + // use std::{thread, time::Duration}; + // use rscap::linux::prelude::*; + // use rscap::linux::mapped::TxFrameVariant; + // + // let mut sock = L2Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?)?; + // sock.manual_tx_status(true); + // let mut sending = 0; + // let mut malformed = 0; + // for _ in 0..5 { + // let mut tx_frame = sock.mapped_send().unwrap(); + // tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed + // tx_frame.send(11); + // sending += 1; + // } + // + // while sending > 0 { + // match sock.tx_status() { + // TxFrameVariant::Available(_) => sending -= 1, + // TxFrameVariant::WrongFormat(pkt) => { + // println!("Malformed packet: {:?}", pkt.data()); + // malformed += 1; + // sending -= 1; + // } + // TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), + // } + // } + // + // assert!(malformed == 5); + // ``` + /// Checks the status of previously-sent packets in the order they were sent. /// /// By default, or when [`set_tx_status()`](Self::set_tx_status()) is set to `false`, this @@ -1151,38 +1159,6 @@ impl L2TxMappedSocket { /// [`TxFrameVariant::WrongFormat`], the kernel has rejected the packet, and the count of /// pending packets should be decremented. The contents of the packet can be retrieved from the /// encapsulated [`InvalidTxFrame`](super::mapped::InvalidTxFrame) if desired. - /// - /// # Examples - /// - /// ``` - /// use std::{thread, time::Duration}; - /// use rscap::linux::prelude::*; - /// - /// let mut sock = L2Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?); - /// sock.manual_tx_status(true); - /// let mut sending = 0; - /// let mut malformed = 0; - /// for _ in 0..5 { - /// let mut tx_frame = sock.mapped_send().unwrap(); - /// tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed - /// tx_frame.send(11); - /// sending += 1; - /// } - /// - /// while sending > 0 { - /// match sock.tx_status() { - /// TxFrameVariant::Available(_) => sending -= 1, - /// TxFrameVariant::WrongFormat(pkt) => { - /// println!("Malformed packet: {:?}", pkt.data()); - /// malformed += 1; - /// sending -= 1; - /// } - /// TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), - /// } - /// } - /// - /// assert!(malformed == 5); - /// ``` #[inline] pub fn tx_status(&mut self) -> TxFrameVariant<'_> { let (frame_variant, next_tx) = self.tx_ring.next_frame(self.last_checked_tx); @@ -1200,7 +1176,6 @@ impl L2TxMappedSocket { } } -#[cfg(feature = "libcfull")] impl Drop for L2TxMappedSocket { fn drop(&mut self) { unsafe { @@ -1213,7 +1188,6 @@ impl Drop for L2TxMappedSocket { } } -#[cfg(feature = "libcfull")] impl AsRawFd for L2TxMappedSocket { #[inline] fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { @@ -1222,14 +1196,12 @@ impl AsRawFd for L2TxMappedSocket { } /// A link-layer socket with zero-copy packet reception. -#[cfg(feature = "libcfull")] pub struct L2RxMappedSocket { socket: L2Socket, rx_ring: PacketRxRing, next_rx: FrameIndex, } -#[cfg(feature = "libcfull")] impl L2RxMappedSocket { /// Bind the link-layer socket to a particular protocol/address and interface and begin /// receiving packets. @@ -1273,7 +1245,7 @@ impl L2RxMappedSocket { libc::setsockopt( self.socket.fd, libc::SOL_PACKET, - libc::PACKET_RESERVE, + crate::linux::PACKET_RESERVE, ptr::addr_of!(amount) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -1329,7 +1301,7 @@ impl L2RxMappedSocket { } /// Sends a datagram over the socket. On success, returns the number of bytes written. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L2Socket::send()`]. If you are looking to send a memory-mapped packet, use /// [`L2MappedSocket::mapped_send()`] instead. @@ -1341,7 +1313,7 @@ impl L2RxMappedSocket { } /// Receive a datagram from the socket. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L2Socket::recv()`]. If you are looking to receive a memory-mapped packet, use /// [`mapped_recv()`](L2MappedSocket::mapped_recv()) instead. @@ -1364,7 +1336,6 @@ impl L2RxMappedSocket { } } -#[cfg(feature = "libcfull")] impl Drop for L2RxMappedSocket { fn drop(&mut self) { unsafe { @@ -1377,7 +1348,6 @@ impl Drop for L2RxMappedSocket { } } -#[cfg(feature = "libcfull")] impl AsRawFd for L2RxMappedSocket { #[inline] fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { diff --git a/rscap/src/linux/l3.rs b/rscap/src/linux/l3.rs index a422113..f3c5c21 100644 --- a/rscap/src/linux/l3.rs +++ b/rscap/src/linux/l3.rs @@ -14,12 +14,12 @@ use std::{io, mem, os::fd::AsRawFd, ptr}; use super::addr::{L2Addr, L2AddrAny}; -#[cfg(feature = "libcfull")] use super::mapped::{ BlockConfig, FrameIndex, OsiLayer, PacketRxRing, PacketTxRing, RxFrame, TxFrame, TxFrameVariant, }; -#[cfg(feature = "libcfull")] -use super::{FanoutAlgorithm, PacketStatistics, RxTimestamping, TxTimestamping}; +use super::{FanoutAlgorithm, RxTimestamping, TxTimestamping}; + +use crate::filter::PacketStatistics; /// A socket that exchanges packets at the network layer. /// @@ -102,7 +102,6 @@ impl L3Socket { /// kernel will not be buffering packets originating from the socket). /// /// This option is disabled (`false`) by default. - #[cfg(feature = "libcfull")] pub fn set_qdisc_bypass(&self, bypass: bool) -> io::Result<()> { let bypass_req = if bypass { 1u32 } else { 0u32 }; @@ -110,7 +109,7 @@ impl L3Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_QDISC_BYPASS, + crate::linux::PACKET_QDISC_BYPASS, ptr::addr_of!(bypass_req) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -126,31 +125,30 @@ impl L3Socket { /// Packet statistics include [`packets_seen`](PacketStatistics::packets_seen) and /// [`packets_dropped`](PacketStatistics::packets_dropped); both of these counters are reset /// each time `packet_stats()` is called. - #[cfg(feature = "libcfull")] pub fn packet_stats(&self) -> io::Result { - let mut stats = libc::tpacket_stats { + let mut stats = crate::linux::tpacket_stats { tp_packets: 0, tp_drops: 0, }; - let mut stats_len = mem::size_of::() as u32; + let mut stats_len = mem::size_of::() as u32; if unsafe { libc::getsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_STATISTICS, + crate::linux::PACKET_STATISTICS, ptr::addr_of_mut!(stats) as *mut libc::c_void, ptr::addr_of_mut!(stats_len), ) != 0 } { return Err(io::Error::last_os_error()); } - debug_assert!(stats_len == mem::size_of::() as u32); + debug_assert!(stats_len == mem::size_of::() as u32); Ok(PacketStatistics { - packets_seen: stats.tp_packets as usize, - packets_dropped: stats.tp_drops as usize, + received: stats.tp_packets, + dropped: stats.tp_drops, }) } @@ -201,7 +199,6 @@ impl L3Socket { /// `ERANGE` - the requested packets cannot be timestamped by hardware. /// /// `EINVAL` - hardware timestamping is not supported by the network card. - #[cfg(feature = "libcfull")] fn set_timestamp_method(&self, tx: TxTimestamping, rx: RxTimestamping) -> io::Result<()> { if tx == TxTimestamping::Hardware || rx == RxTimestamping::Hardware { let mut hwtstamp_config = libc::hwtstamp_config { @@ -223,7 +220,7 @@ impl L3Socket { let mut if_name = [0i8; libc::IF_NAMESIZE]; let if_name_ptr = if_name.as_mut_ptr(); - let res = unsafe { libc::if_indextoname(addr.interface().index(), if_name_ptr) }; + let res = unsafe { libc::if_indextoname(addr.interface().index()?, if_name_ptr) }; if res.is_null() { return Err(io::Error::last_os_error()); } @@ -255,9 +252,9 @@ impl L3Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_TIMESTAMP, + crate::linux::PACKET_TIMESTAMP, ptr::addr_of!(timestamp_req) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -311,7 +308,6 @@ impl L3Socket { /// fanout group (e.g. to ensure [`FanoutAlgorithm::Hash`] works despite fragmentation) /// - `rollover` causes packets to be sent to a different socket than originally decided /// by `fan_alg` if the original socket is backlogged with packets. - #[cfg(feature = "libcfull")] pub fn set_fanout( &self, group_id: u16, @@ -320,29 +316,29 @@ impl L3Socket { rollover: bool, ) -> io::Result<()> { let mut opt = match fan_alg { - FanoutAlgorithm::Cpu => libc::PACKET_FANOUT_CPU, - FanoutAlgorithm::Hash => libc::PACKET_FANOUT_HASH, - FanoutAlgorithm::QueueMapping => libc::PACKET_FANOUT_QM, - FanoutAlgorithm::Random => libc::PACKET_FANOUT_RND, - FanoutAlgorithm::Rollover => libc::PACKET_FANOUT_ROLLOVER, - FanoutAlgorithm::RoundRobin => libc::PACKET_FANOUT_LB, + FanoutAlgorithm::Cpu => crate::linux::PACKET_FANOUT_CPU, + FanoutAlgorithm::Hash => crate::linux::PACKET_FANOUT_HASH, + FanoutAlgorithm::QueueMapping => crate::linux::PACKET_FANOUT_QM, + FanoutAlgorithm::Random => crate::linux::PACKET_FANOUT_RND, + FanoutAlgorithm::Rollover => crate::linux::PACKET_FANOUT_ROLLOVER, + FanoutAlgorithm::RoundRobin => crate::linux::PACKET_FANOUT_LB, }; opt |= (group_id as u32) << 16; if defrag { - opt |= libc::PACKET_FANOUT_FLAG_DEFRAG; + opt |= crate::linux::PACKET_FANOUT_FLAG_DEFRAG; } if rollover { - opt |= libc::PACKET_FANOUT_FLAG_ROLLOVER; + opt |= crate::linux::PACKET_FANOUT_FLAG_ROLLOVER; } if unsafe { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_FANOUT, + crate::linux::PACKET_FANOUT, ptr::addr_of!(opt) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -445,16 +441,15 @@ impl L3Socket { } /// Sets the PACKET_VERSION socket option to TPACKET_V3. - #[cfg(feature = "libcfull")] fn set_tpacket_v3_opt(&self) -> io::Result<()> { - let pkt_version_3 = libc::tpacket_versions::TPACKET_V3; + let pkt_version_3 = crate::linux::tpacket_versions::TPACKET_V3; if unsafe { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_VERSION, + crate::linux::PACKET_VERSION, ptr::addr_of!(pkt_version_3) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -464,9 +459,8 @@ impl L3Socket { } /// Sets the PACKET_TX_RING socket option. - #[cfg(feature = "libcfull")] fn set_tx_ring_opt(&self, config: BlockConfig) -> io::Result<()> { - let req_tx = libc::tpacket_req3 { + let req_tx = crate::linux::tpacket_req3 { tp_block_size: config.block_size(), tp_block_nr: config.block_cnt(), tp_frame_size: config.frame_size(), @@ -480,9 +474,9 @@ impl L3Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_TX_RING, + crate::linux::PACKET_TX_RING, ptr::addr_of!(req_tx) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -492,7 +486,6 @@ impl L3Socket { } /// Sets the PACKET_RX_RING socket option. - #[cfg(feature = "libcfull")] fn set_rx_ring_opt( &self, config: BlockConfig, @@ -503,7 +496,7 @@ impl L3Socket { timeout = Some(1); // Prevent user from accidentally selecting kernel default } - let req_rx = libc::tpacket_req3 { + let req_rx = crate::linux::tpacket_req3 { tp_block_size: config.block_size(), tp_block_nr: config.block_cnt(), tp_frame_size: config.frame_size(), @@ -517,9 +510,9 @@ impl L3Socket { libc::setsockopt( self.fd, libc::SOL_PACKET, - libc::PACKET_RX_RING, + crate::linux::PACKET_RX_RING, ptr::addr_of!(req_rx) as *const libc::c_void, - mem::size_of::() as u32, + mem::size_of::() as u32, ) != 0 } { return Err(io::Error::last_os_error()); @@ -531,7 +524,6 @@ impl L3Socket { /// Memory-map the packet's TX/RX ring buffers to enable zero-copy packet exchange. /// /// On error, the consumed [`L3Socket`] will be closed. - #[cfg(feature = "libcfull")] fn mmap_socket( &self, config: BlockConfig, @@ -568,7 +560,6 @@ impl L3Socket { /// NOTE: some performance issues have been noted when TX_RING sockets are used in blocking mode (see /// [here](https://stackoverflow.com/questions/43193889/sending-data-with-packet-mmap-and-packet-tx-ring-is-slower-than-normal-withou)). /// It is recommended that the socket be set as nonblocking before calling `packet_ring`. - #[cfg(feature = "libcfull")] pub fn packet_ring( self, config: BlockConfig, @@ -588,12 +579,8 @@ impl L3Socket { ) }; - let tx_ring = unsafe { - PacketTxRing::new( - (mapping as *mut u8).add(config.map_length()), - config, - ) - }; + let tx_ring = + unsafe { PacketTxRing::new((mapping as *mut u8).add(config.map_length()), config) }; // This will immediately wrap around to the first packet due to `frame_offset: None` let start_frame = FrameIndex { @@ -620,18 +607,12 @@ impl L3Socket { /// In past kernel versions, some performance issues have been noted when TX_RING sockets are /// used in blocking mode (see [here](https://stackoverflow.com/questions/43193889/sending-data-with-packet-mmap-and-packet-tx-ring-is-slower-than-normal-withou)). /// It is recommended that the socket be set as nonblocking before calling `packet_tx_ring`. - #[cfg(feature = "libcfull")] pub fn packet_tx_ring(self, config: BlockConfig) -> io::Result { self.set_tpacket_v3_opt()?; self.set_tx_ring_opt(config)?; let mapping = self.mmap_socket(config, false)?; - let tx_ring = unsafe { - PacketTxRing::new( - mapping as *mut u8, - config, - ) - }; + let tx_ring = unsafe { PacketTxRing::new(mapping as *mut u8, config) }; // This will immediately wrap around to the first packet due to `frame_offset: None` let start_frame = FrameIndex { @@ -652,7 +633,6 @@ impl L3Socket { /// Enables zero-copy packet reception for the socket. /// /// On error, the consumed `L3Socket` will be closed. - #[cfg(feature = "libcfull")] pub fn packet_rx_ring( self, config: BlockConfig, @@ -700,7 +680,6 @@ impl AsRawFd for L3Socket { } /// A network-layer socket with zero-copy packet transmission and reception. -#[cfg(feature = "libcfull")] pub struct L3MappedSocket { socket: L3Socket, rx_ring: PacketRxRing, @@ -712,7 +691,6 @@ pub struct L3MappedSocket { tx_full: bool, } -#[cfg(feature = "libcfull")] impl L3MappedSocket { /// Bind the network-layer socket to a particular protocol/address and interface and begin /// receiving packets. @@ -744,7 +722,7 @@ impl L3MappedSocket { libc::setsockopt( self.socket.fd, libc::SOL_PACKET, - libc::PACKET_RESERVE, + crate::linux::PACKET_RESERVE, ptr::addr_of!(amount) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -833,7 +811,7 @@ impl L3MappedSocket { /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L3Socket::send()`]. If you are looking to send a memory-mapped packet, use /// [`mapped_send()`](L3MappedSocket::mapped_send()) instead. - /// + /// /// This method will fail if the socket has not been bound to an [`L2Addr`] (i.e., via /// [`bind()`](L3MappedSocket::bind())). pub fn send(&self, buf: &[u8]) -> io::Result { @@ -841,7 +819,7 @@ impl L3MappedSocket { } /// Receive a datagram from the socket. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L3Socket::recv()`]. If you are looking to receive a memory-mapped packet, use /// [`L3MappedSocket::mapped_recv()`] instead. @@ -881,6 +859,39 @@ impl L3MappedSocket { Some(frame) } + // + // # Examples + // + // ``` + // use std::{thread, time::Duration}; + // use rscap::linux::prelude::*; + // + // let mut sock = L3Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?); + // sock.manual_tx_status(true); + // let mut sending = 0; + // let mut malformed = 0; + // for _ in 0..5 { + // let mut tx_frame = sock.mapped_send().unwrap(); + // tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed + // tx_frame.send(11); + // sending += 1; + // } + // + // while sending > 0 { + // match sock.tx_status() { + // TxFrameVariant::Available(_) => sending -= 1, + // TxFrameVariant::WrongFormat(pkt) => { + // println!("Malformed packet: {:?}", pkt.data()); + // malformed += 1; + // sending -= 1; + // } + // TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), + // } + // } + // + // assert!(malformed == 5); + // ``` + /// Checks the status of previously-sent packets in the order they were sent. /// /// By default, or when `manual_tx_status` is set to `false`, this method will only return the @@ -898,38 +909,6 @@ impl L3MappedSocket { /// [`TxFrameVariant::WrongFormat`], the kernel has rejected the packet, and the count of pending /// packets should be decremented. The contents of the packet can be retrieved from the /// [`InvalidTxFrame`](super::mapped::InvalidTxFrame) if desired. - /// - /// # Examples - /// - /// ``` - /// use std::{thread, time::Duration}; - /// use rscap::linux::prelude::*; - /// - /// let mut sock = L3Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?); - /// sock.manual_tx_status(true); - /// let mut sending = 0; - /// let mut malformed = 0; - /// for _ in 0..5 { - /// let mut tx_frame = sock.mapped_send().unwrap(); - /// tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed - /// tx_frame.send(11); - /// sending += 1; - /// } - /// - /// while sending > 0 { - /// match sock.tx_status() { - /// TxFrameVariant::Available(_) => sending -= 1, - /// TxFrameVariant::WrongFormat(pkt) => { - /// println!("Malformed packet: {:?}", pkt.data()); - /// malformed += 1; - /// sending -= 1; - /// } - /// TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), - /// } - /// } - /// - /// assert!(malformed == 5); - /// ``` pub fn tx_status(&mut self) -> TxFrameVariant<'_> { let (frame_variant, next_tx) = self.tx_ring.next_frame(self.last_checked_tx); @@ -961,7 +940,6 @@ impl L3MappedSocket { } } -#[cfg(feature = "libcfull")] impl Drop for L3MappedSocket { fn drop(&mut self) { unsafe { @@ -974,7 +952,6 @@ impl Drop for L3MappedSocket { } } -#[cfg(feature = "libcfull")] impl AsRawFd for L3MappedSocket { #[inline] fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { @@ -983,7 +960,6 @@ impl AsRawFd for L3MappedSocket { } /// A network-layer socket with zero-copy packet transmission. -#[cfg(feature = "libcfull")] pub struct L3TxMappedSocket { socket: L3Socket, tx_ring: PacketTxRing, @@ -993,7 +969,6 @@ pub struct L3TxMappedSocket { tx_full: bool, } -#[cfg(feature = "libcfull")] impl L3TxMappedSocket { /// Bind the network-layer socket to a particular protocol/address and interface and begin /// receiving packets. @@ -1046,7 +1021,7 @@ impl L3TxMappedSocket { } /// Receive a datagram from the socket. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L3Socket::recv()`]. If you are looking to receive a memory-mapped packet, use /// [`mapped_recv()`](L3MappedSocket::mapped_recv()) instead. @@ -1058,7 +1033,7 @@ impl L3TxMappedSocket { } /// Sends a datagram over the socket. On success, returns the number of bytes written. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L3Socket::send()`]. If you are looking to send a memory-mapped packet, use /// [`mapped_send()`](L3MappedSocket::mapped_send()) instead. @@ -1113,6 +1088,39 @@ impl L3TxMappedSocket { self.manual_tx_status = manual; } + // + // # Examples + // + // ``` + // use std::{thread, time::Duration}; + // use rscap::linux::prelude::*; + // + // let mut sock = L3Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?); + // sock.manual_tx_status(true); + // let mut sending = 0; + // let mut malformed = 0; + // for _ in 0..5 { + // let mut tx_frame = sock.mapped_send().unwrap(); + // tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed + // tx_frame.send(11); + // sending += 1; + // } + // + // while sending > 0 { + // match sock.tx_status() { + // TxFrameVariant::Available(_) => sending -= 1, + // TxFrameVariant::WrongFormat(pkt) => { + // println!("Malformed packet: {:?}", pkt.data()); + // malformed += 1; + // sending -= 1; + // } + // TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), + // } + // } + // + // assert!(malformed == 5); + // ``` + /// Checks the status of previously-sent packets in the order they were sent. /// /// By default, or when [`set_tx_status()`](Self::set_tx_status()) is set to `false`, this @@ -1130,38 +1138,6 @@ impl L3TxMappedSocket { /// [`TxFrameVariant::WrongFormat`], the kernel has rejected the packet, and the count of /// pending packets should be decremented. The contents of the packet can be retrieved from the /// encapsulated [`InvalidTxFrame`](super::mapped::InvalidTxFrame) if desired. - /// - /// # Examples - /// - /// ``` - /// use std::{thread, time::Duration}; - /// use rscap::linux::prelude::*; - /// - /// let mut sock = L3Socket::new()?.packet_tx_ring(BlockConfig::new(65536, 16, 8192)?); - /// sock.manual_tx_status(true); - /// let mut sending = 0; - /// let mut malformed = 0; - /// for _ in 0..5 { - /// let mut tx_frame = sock.mapped_send().unwrap(); - /// tx_frame.data()[0..11].copy_from_slice(b"hello world"); // This will obviously be malformed - /// tx_frame.send(11); - /// sending += 1; - /// } - /// - /// while sending > 0 { - /// match sock.tx_status() { - /// TxFrameVariant::Available(_) => sending -= 1, - /// TxFrameVariant::WrongFormat(pkt) => { - /// println!("Malformed packet: {:?}", pkt.data()); - /// malformed += 1; - /// sending -= 1; - /// } - /// TxFrameVariant::SendRequest | TxFrameVariant::Sending => thread::sleep(Duration::from_millis(50)), - /// } - /// } - /// - /// assert!(malformed == 5); - /// ``` pub fn tx_status(&mut self) -> TxFrameVariant<'_> { let (frame_variant, next_tx) = self.tx_ring.next_frame(self.last_checked_tx); @@ -1178,7 +1154,6 @@ impl L3TxMappedSocket { } } -#[cfg(feature = "libcfull")] impl Drop for L3TxMappedSocket { fn drop(&mut self) { unsafe { @@ -1191,7 +1166,6 @@ impl Drop for L3TxMappedSocket { } } -#[cfg(feature = "libcfull")] impl AsRawFd for L3TxMappedSocket { #[inline] fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { @@ -1200,14 +1174,12 @@ impl AsRawFd for L3TxMappedSocket { } /// A network-layer socket with zero-copy packet reception. -#[cfg(feature = "libcfull")] pub struct L3RxMappedSocket { socket: L3Socket, rx_ring: PacketRxRing, next_rx: FrameIndex, } -#[cfg(feature = "libcfull")] impl L3RxMappedSocket { /// Bind the network-layer socket to a particular protocol/address and interface and begin /// receiving packets. @@ -1248,7 +1220,7 @@ impl L3RxMappedSocket { libc::setsockopt( self.socket.fd, libc::SOL_PACKET, - libc::PACKET_RESERVE, + crate::linux::PACKET_RESERVE, ptr::addr_of!(amount) as *const libc::c_void, mem::size_of::() as u32, ) != 0 @@ -1305,7 +1277,7 @@ impl L3RxMappedSocket { /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L3Socket::send()`]. If you are looking to send a memory-mapped packet, use /// [`L3MappedSocket::mapped_send()`] instead. - /// + /// /// This method will fail if the socket has not been bound to an [`L2Addr`] (i.e., via /// [`bind()`](L3TxMappedSocket::bind())). pub fn send(&self, buf: &[u8]) -> io::Result { @@ -1313,7 +1285,7 @@ impl L3RxMappedSocket { } /// Receive a datagram from the socket. - /// + /// /// NOTE: this method DOES NOT employ memory-mapped I/O and is functionally equivalent /// to [`L3Socket::recv()`]. If you are looking to receive a memory-mapped packet, use /// [`mapped_recv()`](L3MappedSocket::mapped_recv()) instead. @@ -1335,7 +1307,6 @@ impl L3RxMappedSocket { } } -#[cfg(feature = "libcfull")] impl Drop for L3RxMappedSocket { fn drop(&mut self) { unsafe { @@ -1348,7 +1319,6 @@ impl Drop for L3RxMappedSocket { } } -#[cfg(feature = "libcfull")] impl AsRawFd for L3RxMappedSocket { #[inline] fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { diff --git a/rscap/src/linux/l4.rs b/rscap/src/linux/l4.rs index 57d4d4d..dbed048 100644 --- a/rscap/src/linux/l4.rs +++ b/rscap/src/linux/l4.rs @@ -61,7 +61,10 @@ impl L4Socket { L4Protocol::Udp => libc::IPPROTO_UDP, L4Protocol::Custom(protocol) => { if protocol == libc::IPPROTO_RAW as u8 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, "IPPROTO_RAW not supported for L4Socket")) + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "IPPROTO_RAW not supported for L4Socket", + )); } protocol as i32 } @@ -125,12 +128,17 @@ impl L4Socket { } /// Send a datagram to the specified IPv4 address. - pub fn send_to(&self, buf: &[u8], rem_addr: SocketAddrV4, flags: SendFlags) -> io::Result { + pub fn send_to( + &self, + buf: &[u8], + rem_addr: SocketAddrV4, + flags: SendFlags, + ) -> io::Result { let sockaddr = libc::sockaddr_in { sin_family: libc::AF_INET as u16, sin_port: rem_addr.port(), sin_addr: libc::in_addr { - s_addr: rem_addr.ip().to_bits(), + s_addr: u32::from_be_bytes(rem_addr.ip().octets()), // TODO: endianness? }, sin_zero: [0u8; 8], }; @@ -157,9 +165,7 @@ impl L4Socket { let sockaddr = libc::sockaddr_in { sin_family: libc::AF_INET as u16, sin_port: 0, - sin_addr: libc::in_addr { - s_addr: 0, - }, + sin_addr: libc::in_addr { s_addr: 0 }, sin_zero: [0u8; 8], }; @@ -177,9 +183,12 @@ impl L4Socket { } { ..=-1 => Err(io::Error::last_os_error()), recvd => { - let rem_addr = SocketAddrV4::new(Ipv4Addr::from_bits(sockaddr.sin_addr.s_addr), sockaddr.sin_port); + let rem_addr = SocketAddrV4::new( + Ipv4Addr::from(sockaddr.sin_addr.s_addr.to_be_bytes()), // TODO: endianness? + sockaddr.sin_port, + ); Ok((recvd as usize, rem_addr)) - }, + } } } } diff --git a/rscap/src/linux/mapped.rs b/rscap/src/linux/mapped.rs index 805a5cf..492407f 100644 --- a/rscap/src/linux/mapped.rs +++ b/rscap/src/linux/mapped.rs @@ -9,7 +9,7 @@ // except according to those terms. //! Structures used for memory-mapped packet sockets. -//! +//! //! These structures transparently perform the necessary `setsockopt(PACKET_RX_RING)` and `mmap()` //! procedures to enable zero-copy transmission and reception of packets over a socket. @@ -149,27 +149,23 @@ pub struct PacketTxRing { impl PacketTxRing { /// Constructs a new `PacketTxRing` instance from a raw memory-mapped segment and configuration. - pub(crate) unsafe fn new( - ring_start: *mut u8, - config: BlockConfig, - - ) -> Self { + pub(crate) unsafe fn new(ring_start: *mut u8, config: BlockConfig) -> Self { let frame_size = config.frame_size as usize; let block_cnt = config.block_cnt as usize; let block_size = config.block_size as usize; - debug_assert!(block_size >= mem::size_of::()); + debug_assert!(block_size >= mem::size_of::()); let mut blocks = Vec::new(); for i in 0..block_cnt { let block_slice = slice::from_raw_parts_mut(ring_start.add(block_size * i), block_size); let (description_bytes, block_slice) = - block_slice.split_at_mut(mem::size_of::()); + block_slice.split_at_mut(mem::size_of::()); // SAFETY: each block must begin with an initialized tpacket_block_desc let block_description = unsafe { - (description_bytes.as_mut_ptr() as *mut libc::tpacket_block_desc) + (description_bytes.as_mut_ptr() as *mut crate::linux::tpacket_block_desc) .as_mut() .unwrap() }; @@ -238,14 +234,14 @@ impl PacketTxRing { /// An individual block in a reception-oriented ring buffer. pub struct PacketTxBlock { - description: &'static mut libc::tpacket_block_desc, + description: &'static mut crate::linux::tpacket_block_desc, frames: &'static mut [u8], frame_size: usize, } impl PacketTxBlock { #[inline] - fn block_header(&self) -> &libc::tpacket_hdr_v1 { + fn block_header(&self) -> &crate::linux::tpacket_hdr_v1 { // SAFETY: the `tpacket_bd_hdr_u` union has only one variant, so this access is memory-safe. unsafe { &self.description.hdr.bh1 } } @@ -283,7 +279,7 @@ pub struct PacketTxFrameIter<'a> { impl<'a> PacketTxFrameIter<'a> { /// Retrieves the next available transmission frame (or `None` if no frames remain). - /// + /// /// The behavior of `next_frame()` depends on the variant of the returned transmission frame: /// - [`TxFrameVariant::Available`] causes the iterator to move its index to the next available /// frame; a subsequent call to `next_frame()` will return a frame from the next contiguous @@ -318,11 +314,11 @@ impl<'a> PacketTxFrameIter<'a> { let curr_frame_data = &mut frames[offset..]; - let (header_data, rem) = - curr_frame_data.split_at_mut(tpacket_align(mem::size_of::())); + let (header_data, rem) = curr_frame_data + .split_at_mut(tpacket_align(mem::size_of::())); // SAFETY: tpacket3_header must be present at this data offset let header = unsafe { - (header_data.as_mut_ptr() as *mut libc::tpacket3_hdr) + (header_data.as_mut_ptr() as *mut crate::linux::tpacket3_hdr) .as_mut() .unwrap() }; @@ -340,15 +336,15 @@ impl<'a> PacketTxFrameIter<'a> { let packet = &mut rem[..frame_end]; let frame_variant = match header.tp_status { - libc::TP_STATUS_AVAILABLE => { + crate::linux::TP_STATUS_AVAILABLE => { header.tp_next_offset = 0; header.tp_len = 0; header.tp_snaplen = 0; TxFrameVariant::Available(TxFrame { header, packet }) } - libc::TP_STATUS_SEND_REQUEST => TxFrameVariant::SendRequest, - libc::TP_STATUS_SENDING => TxFrameVariant::Sending, - libc::TP_STATUS_WRONG_FORMAT => { + crate::linux::TP_STATUS_SEND_REQUEST => TxFrameVariant::SendRequest, + crate::linux::TP_STATUS_SENDING => TxFrameVariant::Sending, + crate::linux::TP_STATUS_WRONG_FORMAT => { TxFrameVariant::WrongFormat(InvalidTxFrame { header, packet }) } _ => TxFrameVariant::WrongFormat(InvalidTxFrame { header, packet }), @@ -359,7 +355,7 @@ impl<'a> PacketTxFrameIter<'a> { } /// An individual transmission frame. -/// +/// /// The variant represents the state of the frame _at the time the frame is accessed_. The kernel /// may modify the underlying state of a [`SendRequest`](TxFrameVariant::SendRequest) or /// [`Sending`](TxFrameVariant::Sending) frame at any time, so they should not be relied on as an @@ -378,7 +374,7 @@ pub enum TxFrameVariant<'a> { /// A transmission frame capable of conveying a single packet. pub struct TxFrame<'a> { - header: &'a mut libc::tpacket3_hdr, + header: &'a mut crate::linux::tpacket3_hdr, packet: &'a mut [u8], } @@ -403,7 +399,7 @@ impl TxFrame<'_> { self.header.tp_len = packet_length; self.header.tp_snaplen = packet_length; - self.header.tp_status = libc::TP_STATUS_SEND_REQUEST; + self.header.tp_status = crate::linux::TP_STATUS_SEND_REQUEST; } } @@ -412,7 +408,7 @@ impl TxFrame<'_> { /// When dropped, this structure will mark its frame as available for use in subsequent packet /// transmissions. pub struct InvalidTxFrame<'a> { - header: &'a mut libc::tpacket3_hdr, + header: &'a mut crate::linux::tpacket3_hdr, packet: &'a mut [u8], } @@ -428,7 +424,7 @@ impl Drop for InvalidTxFrame<'_> { fn drop(&mut self) { self.header.tp_len = 0; self.header.tp_snaplen = 0; - self.header.tp_status = libc::TP_STATUS_AVAILABLE; + self.header.tp_status = crate::linux::TP_STATUS_AVAILABLE; } } @@ -460,18 +456,18 @@ impl PacketRxRing { let block_cnt = config.block_cnt as usize; let block_size = config.block_size as usize; - debug_assert!(frame_size >= mem::size_of::()); + debug_assert!(frame_size >= mem::size_of::()); let mut blocks = Vec::new(); for i in 0..block_cnt { let block_slice = slice::from_raw_parts_mut(ring_start.add(block_size * i), block_size); let (description_bytes, block_slice) = - block_slice.split_at_mut(mem::size_of::()); + block_slice.split_at_mut(mem::size_of::()); // SAFETY: each block must begin with an initialized tpacket_block_desc let block_description = unsafe { - (description_bytes.as_mut_ptr() as *mut libc::tpacket_block_desc) + (description_bytes.as_mut_ptr() as *mut crate::linux::tpacket_block_desc) .as_mut() .unwrap() }; @@ -479,7 +475,7 @@ impl PacketRxRing { debug_assert!(block_description.version == 1); let priv_offset = block_description.offset_to_priv as usize - - mem::size_of::(); + - mem::size_of::(); let first_frame_offset = unsafe { block_description.hdr.bh1.offset_to_first_pkt as usize }; @@ -533,7 +529,7 @@ impl PacketRxRing { None => { let block_index = (index.blocks_index + 1) % self.blocks.len(); let block = &mut self.blocks[index.blocks_index]; - if (block.block_header().block_status & libc::TP_STATUS_USER) == 0 { + if (block.block_header().block_status & crate::linux::TP_STATUS_USER) == 0 { return None; // No data from the next block is ready to be read yet } @@ -566,7 +562,7 @@ impl PacketRxRing { /// An individual block in a reception-orieented ring buffer. pub struct PacketRxBlock { - description: &'static mut libc::tpacket_block_desc, + description: &'static mut crate::linux::tpacket_block_desc, priv_data: &'static mut [u8], frames: &'static mut [u8], osi_layer: OsiLayer, @@ -574,7 +570,7 @@ pub struct PacketRxBlock { impl PacketRxBlock { #[inline] - fn block_header(&self) -> &libc::tpacket_hdr_v1 { + fn block_header(&self) -> &crate::linux::tpacket_hdr_v1 { // SAFETY: the `tpacket_bd_hdr_u` union has only one variant, so this access is memory-safe. unsafe { &self.description.hdr.bh1 } } @@ -590,7 +586,7 @@ impl PacketRxBlock { /// The availability status of the block. #[inline] pub fn status(&self) -> PacketRxStatus { - if (self.block_header().block_status & libc::TP_STATUS_USER) != 0 { + if (self.block_header().block_status & crate::linux::TP_STATUS_USER) != 0 { PacketRxStatus::User } else { PacketRxStatus::Kernel @@ -663,16 +659,16 @@ impl<'a> PacketRxFrameIter<'a> { // This, combined with the current frame shift and the packet header and sockaddr shifts, gives us our final adjusted offset value let full_offset = init_offset + curr_offset - + tpacket_align(mem::size_of::()) + + tpacket_align(mem::size_of::()) + mem::size_of::(); let curr_frame_data = &mut frames[curr_offset..]; - let (header_data, rem) = - curr_frame_data.split_at_mut(tpacket_align(mem::size_of::())); + let (header_data, rem) = curr_frame_data + .split_at_mut(tpacket_align(mem::size_of::())); // SAFETY: tpacket3_header must be present at this data offset let header = unsafe { - (header_data.as_mut_ptr() as *mut libc::tpacket3_hdr) + (header_data.as_mut_ptr() as *mut crate::linux::tpacket3_hdr) .as_mut() .unwrap() }; @@ -715,7 +711,7 @@ impl<'a> PacketRxFrameIter<'a> { /// A reception frame capable of conveying a single packet. pub struct RxFrame<'a> { - header: &'a mut libc::tpacket3_hdr, + header: &'a mut crate::linux::tpacket3_hdr, sockaddr: &'a mut libc::sockaddr_ll, padding: &'a mut [u8], packet: &'a mut [u8], @@ -763,14 +759,14 @@ impl RxFrame<'_> { /// Note that this flag is only set if `set_copy_thresh()` has been enabled for the socket. #[inline] pub fn is_copied(&self) -> bool { - (self.header.tp_status & libc::TP_STATUS_COPY) != 0 + (self.header.tp_status & crate::linux::TP_STATUS_COPY) != 0 } /// Indicates there have been dropped packets since the last call to `packet_statistics()` was made /// on the socket. #[inline] pub fn dropped_packets(&self) -> bool { - (self.header.tp_status & libc::TP_STATUS_LOSING) != 0 + (self.header.tp_status & crate::linux::TP_STATUS_LOSING) != 0 } /// Indicates that the packet's Internet/Transport-layer checksums will be done in hardware (and @@ -779,7 +775,7 @@ impl RxFrame<'_> { /// This option is applicable to outgoing IP packets when checksum offloading is enabled. #[inline] pub fn offloaded_checksum(&self) -> bool { - (self.header.tp_status & libc::TP_STATUS_CSUMNOTREADY) != 0 + (self.header.tp_status & crate::linux::TP_STATUS_CSUMNOTREADY) != 0 } /// Indicates that at least the transport header checksum has been validated by the operating system. @@ -789,13 +785,13 @@ impl RxFrame<'_> { /// and determined to be valid or invalid in userspace. #[inline] pub fn checksum_valid(&self) -> bool { - (self.header.tp_status & libc::TP_STATUS_CSUM_VALID) != 0 + (self.header.tp_status & crate::linux::TP_STATUS_CSUM_VALID) != 0 } /// The VLAN TCI value associated with the packet, if such a value exists. #[inline] pub fn vlan_tci(&self) -> Option { - if (self.header.tp_status & libc::TP_STATUS_VLAN_VALID) != 0 { + if (self.header.tp_status & crate::linux::TP_STATUS_VLAN_VALID) != 0 { Some(self.header.hv1.tp_vlan_tci) } else { None @@ -805,7 +801,7 @@ impl RxFrame<'_> { /// The VLAN TPID value associated with the packet, if such a value exists. #[inline] pub fn vlan_tpid(&self) -> Option { - if (self.header.tp_status & libc::TP_STATUS_VLAN_TPID_VALID) != 0 { + if (self.header.tp_status & crate::linux::TP_STATUS_VLAN_TPID_VALID) != 0 { Some(self.header.hv1.tp_vlan_tpid) } else { None @@ -828,5 +824,5 @@ impl RxFrame<'_> { const fn tpacket_align(len: usize) -> usize { // identical to libc::TPACKET_ALIGN(), but const and safe - (len + libc::TPACKET_ALIGNMENT - 1) & !(libc::TPACKET_ALIGNMENT - 1) + (len + crate::linux::TPACKET_ALIGNMENT - 1) & !(crate::linux::TPACKET_ALIGNMENT - 1) } diff --git a/rscap/src/linux/prelude.rs b/rscap/src/linux/prelude.rs index 133e944..a933676 100644 --- a/rscap/src/linux/prelude.rs +++ b/rscap/src/linux/prelude.rs @@ -12,8 +12,7 @@ pub use super::addr::{L2Addr, L2AddrAny, L2AddrIp, L2AddrUnspec}; pub use super::l2::L2Socket; -#[cfg(feature = "libcfull")] pub use super::l2::{L2MappedSocket, L2RxMappedSocket, L2TxMappedSocket}; pub use super::{FanoutAlgorithm, RxTimestamping, TxTimestamping}; -pub use crate::Interface; pub use crate::filter::PacketStatistics; +pub use crate::Interface; diff --git a/rscap/src/linux/sndrcv.rs b/rscap/src/linux/sndrcv.rs index cab1533..0761784 100644 --- a/rscap/src/linux/sndrcv.rs +++ b/rscap/src/linux/sndrcv.rs @@ -1,4 +1,3 @@ - use bitflags::bitflags; bitflags! { diff --git a/rscap/src/npcap.rs b/rscap/src/npcap.rs index 1e9555c..e4e36ff 100644 --- a/rscap/src/npcap.rs +++ b/rscap/src/npcap.rs @@ -9,7 +9,7 @@ // except according to those terms. //! (Windows) npcap packet capture and transmission interface. -//! +//! // RSCAP_NPCAP_PATH: // C:\Windows\System32\Npcap\Packet.dll @@ -23,12 +23,14 @@ use std::mem::MaybeUninit; use std::ptr::{self, NonNull}; use windows_sys::Win32::Foundation::{GetLastError, ERROR_ACCESS_DENIED, ERROR_BAD_UNIT}; -use windows_sys::Win32::Networking::WinSock::{WSACleanup, WSAStartup, WSADATA, WSAEPROCLIM, WSASYSNOTREADY, WSAVERNOTSUPPORTED}; +use windows_sys::Win32::Networking::WinSock::{ + WSACleanup, WSAStartup, WSADATA, WSAEPROCLIM, WSASYSNOTREADY, WSAVERNOTSUPPORTED, +}; use dll::{Adapter, BpfStat, Npcap, PACKET_MODE_CAPT, PACKET_MODE_STAT}; -use crate::Interface; use crate::filter::PacketStatistics; +use crate::Interface; const WSA_VERSION: u16 = 0x0202; @@ -46,11 +48,11 @@ pub struct NpcapError { impl NpcapError { pub fn new(kind: NpcapErrorKind, error: E) -> Self - where + where E: Into>, { Self { - kind, + kind, error: Some(error.into()), } } @@ -132,18 +134,28 @@ impl L2Socket { WSASYSNOTREADY => return Err(NpcapErrorKind::NetworkNotReady.into()), WSAVERNOTSUPPORTED => return Err(NpcapErrorKind::UnsupportedSystem.into()), WSAEPROCLIM => return Err(NpcapErrorKind::ProcessLimit.into()), - e => return Err(NpcapError::new(NpcapErrorKind::Internal, format!("WSAStartup() returned error value {}", e))), + e => { + return Err(NpcapError::new( + NpcapErrorKind::Internal, + format!("WSAStartup() returned error value {}", e), + )) + } } } let npcap = Npcap::new()?; let adapter = match NonNull::new(npcap.open_adapter(iface.name())) { - None => return Err(match unsafe { GetLastError() } { - ERROR_BAD_UNIT => NpcapErrorKind::InvalidInterface.into(), - ERROR_ACCESS_DENIED => NpcapErrorKind::PermissionDenied.into(), - e => NpcapError::new(NpcapErrorKind::Internal, format!("unspecified error {} in opening npcap adapter", e)), - }), + None => { + return Err(match unsafe { GetLastError() } { + ERROR_BAD_UNIT => NpcapErrorKind::InvalidInterface.into(), + ERROR_ACCESS_DENIED => NpcapErrorKind::PermissionDenied.into(), + e => NpcapError::new( + NpcapErrorKind::Internal, + format!("unspecified error {} in opening npcap adapter", e), + ), + }) + } Some(p) => p, }; @@ -159,7 +171,7 @@ impl L2Socket { } /// Retrieves the name of the npcap driver. - /// + /// /// As Winpcap uses a very similar API to npcap, this function is useful in disambiguating /// the one from the other. #[inline] @@ -187,7 +199,10 @@ impl L2Socket { match self.npcap.set_monitor_mode(self.iface.name(), enabled) { 1 => Ok(()), 0 => Err(NpcapErrorKind::UnsupportedMode.into()), - error => Err(NpcapError::new(NpcapErrorKind::OperationFailed, format!("setting monitor mode failed with error {}", error))), + error => Err(NpcapError::new( + NpcapErrorKind::OperationFailed, + format!("setting monitor mode failed with error {}", error), + )), } } @@ -199,39 +214,54 @@ impl L2Socket { bs_capt: 0, }; - match self.npcap.get_stats_ex(unsafe { self.adapter.as_mut() }, &mut stat) { + match self + .npcap + .get_stats_ex(unsafe { self.adapter.as_mut() }, &mut stat) + { true => Ok(PacketStatistics { received: stat.bs_recv, dropped: stat.bs_drop, }), - false => Err(NpcapErrorKind::OperationFailed.into()) + false => Err(NpcapErrorKind::OperationFailed.into()), } } /// Sets the size of the buffer used by the npcap driver to queue packets for the socket. pub fn set_driver_buffer(&mut self, buffer_size: usize) -> Result<(), NpcapError> { - let buffer_size = libc::c_int::try_from(buffer_size).map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?; - match self.npcap.set_buff(unsafe { self.adapter.as_mut() }, buffer_size) { + let buffer_size = libc::c_int::try_from(buffer_size) + .map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?; + match self + .npcap + .set_buff(unsafe { self.adapter.as_mut() }, buffer_size) + { true => Ok(()), - false => Err(NpcapErrorKind::OperationFailed.into()) + false => Err(NpcapErrorKind::OperationFailed.into()), } } /// Defines the minimum amount of data npcap driver that will cause a `recv()` to return. pub fn set_min_to_copy(&mut self, copy_bytes: usize) -> Result<(), NpcapError> { - let copy_bytes = libc::c_int::try_from(copy_bytes).map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?; - match self.npcap.set_min_to_copy(unsafe { self.adapter.as_mut() }, copy_bytes) { + let copy_bytes = libc::c_int::try_from(copy_bytes) + .map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?; + match self + .npcap + .set_min_to_copy(unsafe { self.adapter.as_mut() }, copy_bytes) + { true => Ok(()), - false => Err(NpcapErrorKind::OperationFailed.into()) + false => Err(NpcapErrorKind::OperationFailed.into()), } } /// Configures the number of times a packet written to the interface via `send()` will b /// repeated. pub fn set_repeat_send(&mut self, num_repeats: u32) -> Result<(), NpcapError> { - let num_repeats = libc::c_int::try_from(num_repeats).map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?; - - match self.npcap.set_num_writes(unsafe { self.adapter.as_mut() }, num_repeats) { + let num_repeats = libc::c_int::try_from(num_repeats) + .map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?; + + match self + .npcap + .set_num_writes(unsafe { self.adapter.as_mut() }, num_repeats) + { true => Ok(()), false => Err(NpcapErrorKind::OperationFailed.into()), } @@ -239,7 +269,7 @@ impl L2Socket { /* /// Sets the capture mode of the interface. - /// + /// /// By default, the capture mode is set to `NpcapMode::Capture`. pub fn set_mode(&self, mode: NpcapMode) -> Result<(), NpcapError> { let mode_int = match mode { @@ -255,18 +285,22 @@ impl L2Socket { */ /// Sets the value of the read timeout associated with the socket. - /// + /// /// `timeout` indicates how long the socket will wait to receive a packet before returning. pub fn set_timeout(&mut self, timeout: NpcapTimeout) -> Result<(), NpcapError> { let timeout = match timeout { NpcapTimeout::None => -1, NpcapTimeout::Immediate => 0, - NpcapTimeout::Milliseconds(ms) => libc::c_int::try_from(ms).map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?, + NpcapTimeout::Milliseconds(ms) => libc::c_int::try_from(ms) + .map_err(|_| NpcapError::from(NpcapErrorKind::InvalidValue))?, }; - match self.npcap.set_read_timeout(unsafe { self.adapter.as_mut() }, timeout) { + match self + .npcap + .set_read_timeout(unsafe { self.adapter.as_mut() }, timeout) + { true => Ok(()), - false => Err(NpcapErrorKind::OperationFailed.into()) + false => Err(NpcapErrorKind::OperationFailed.into()), } } @@ -281,11 +315,8 @@ impl L2Socket { impl Drop for L2Socket { fn drop(&mut self) { - - unsafe { WSACleanup(); } } } - diff --git a/rscap/src/npcap/dll.rs b/rscap/src/npcap/dll.rs index 7f7d47b..67576e7 100644 --- a/rscap/src/npcap/dll.rs +++ b/rscap/src/npcap/dll.rs @@ -8,16 +8,20 @@ pub use dlopen::Npcap; #[cfg(feature = "npcap-require")] pub use link::Npcap; +use windows_sys::Win32::Networking::WinSock::SOCKADDR_STORAGE; + use std::mem; -pub const PACKET_MODE_CAPT: libc::c_int = 0x00; -pub const PACKET_MODE_STAT: libc::c_int = 0x01; -pub const PACKET_MODE_MON: libc::c_int = 0x02; -pub const PACKET_MODE_DUMP: libc::c_int = 0x10; +pub const PACKET_MODE_CAPT: libc::c_int = 0x00; +pub const PACKET_MODE_STAT: libc::c_int = 0x01; +pub const PACKET_MODE_MON: libc::c_int = 0x02; +pub const PACKET_MODE_DUMP: libc::c_int = 0x10; pub const PACKET_MODE_STAT_DUMP: libc::c_int = PACKET_MODE_DUMP | PACKET_MODE_STAT; pub const PACKET_ALIGNMENT: usize = mem::size_of::(); -pub const fn packet_wordalign(x: usize) -> usize { (x + (PACKET_ALIGNMENT - 1)) & !(PACKET_ALIGNMENT - 1) } +pub const fn packet_wordalign(x: usize) -> usize { + (x + (PACKET_ALIGNMENT - 1)) & !(PACKET_ALIGNMENT - 1) +} pub const NDIS_MEDIUM_NULL: i32 = -1; pub const NDIS_MEDIUM_CHDLC: i32 = -2; @@ -42,7 +46,6 @@ pub const ADAPTER_DESC_LENGTH: usize = 128; pub const MAX_MAC_ADDR_LENGTH: usize = 8; pub const MAX_NETWORK_ADDRESSES: usize = 16; - pub const INFO_FLAG_NDIS_ADAPTER: libc::c_int = 0; pub const INFO_FLAG_NDISWAN_ADAPTER: libc::c_int = 1; pub const INFO_FLAG_DAG_CARD: libc::c_int = 2; @@ -99,9 +102,9 @@ pub struct DumpBpfHdr { #[repr(C)] pub struct NpfIfAddr { - pub ip_address: libc::sockaddr_storage, - pub subnet_mask: libc::sockaddr_storage, - pub broadcast: libc::sockaddr_storage, + pub ip_address: SOCKADDR_STORAGE, + pub subnet_mask: SOCKADDR_STORAGE, + pub broadcast: SOCKADDR_STORAGE, } #[repr(C)] @@ -138,21 +141,21 @@ pub struct PacketOidData { pub struct WanAdapter { pub h_capture_blob: *const libc::c_void, // HBLOB pub critical_section: windows_sys::Win32::System::Threading::CRITICAL_SECTION, - pub buffer: *mut libc::c_uchar, // PUCHAR - pub c: libc::c_ulong, // DWORD - pub p: libc::c_ulong, // DWORD - pub free: libc::c_ulong, // DWORD - pub size: libc::c_ulong, // DWORD - pub dropped: libc::c_ulong, // DWORD - pub accepted: libc::c_ulong, // DWORD - pub received: libc::c_ulong, // DWORD - pub min_to_copy: libc::c_ulong, // DWORD + pub buffer: *mut libc::c_uchar, // PUCHAR + pub c: libc::c_ulong, // DWORD + pub p: libc::c_ulong, // DWORD + pub free: libc::c_ulong, // DWORD + pub size: libc::c_ulong, // DWORD + pub dropped: libc::c_ulong, // DWORD + pub accepted: libc::c_ulong, // DWORD + pub received: libc::c_ulong, // DWORD + pub min_to_copy: libc::c_ulong, // DWORD pub read_timeout: libc::c_ulong, // DWORD pub h_read_event: libc::c_ulong, // DWORD pub fileter_code: *mut BpfInsn, pub mode: libc::c_ulong, // DWORD - pub nbytes: i64, // LARGE_INTEGER, - pub npackets: i64, // LARGE_INTEGER, + pub nbytes: i64, // LARGE_INTEGER, + pub npackets: i64, // LARGE_INTEGER, // ifdef have buggy tme support // mem_ex: MEM_TYPE, // tme: TME_CORE, diff --git a/rscap/src/npcap/dll/dlopen.rs b/rscap/src/npcap/dll/dlopen.rs index fbd0c69..daf2c8f 100644 --- a/rscap/src/npcap/dll/dlopen.rs +++ b/rscap/src/npcap/dll/dlopen.rs @@ -1,8 +1,8 @@ #![allow(non_snake_case)] use std::ffi::CStr; -use std::ptr::NonNull; use std::ptr; +use std::ptr::NonNull; use dlopen2::wrapper::{Container, WrapperApi}; use windows_sys::Win32::Foundation::{BOOL, BOOLEAN, HANDLE}; @@ -23,33 +23,59 @@ struct NpcapApi { PacketGetDriverVersion: unsafe extern "C" fn() -> windows_sys::core::PCSTR, PacketGetDriverName: unsafe extern "C" fn() -> windows_sys::core::PCSTR, PacketSetMinToCopy: unsafe extern "C" fn(adapter: *mut Adapter, nbytes: libc::c_int) -> BOOLEAN, - PacketSetNumWrites: unsafe extern "C" fn(adapter: *mut Adapter, nwrites: libc::c_int) -> BOOLEAN, + PacketSetNumWrites: + unsafe extern "C" fn(adapter: *mut Adapter, nwrites: libc::c_int) -> BOOLEAN, PacketSetMode: unsafe extern "C" fn(adapter: *mut Adapter, mode: libc::c_int) -> BOOLEAN, - PacketSetReadTimeout: unsafe extern "C" fn(adapter: *mut Adapter, timeout: libc::c_int) -> BOOLEAN, + PacketSetReadTimeout: + unsafe extern "C" fn(adapter: *mut Adapter, timeout: libc::c_int) -> BOOLEAN, PacketSetBpf: unsafe extern "C" fn(adapter: *mut Adapter, fp: *const BpfProgram) -> BOOLEAN, - PacketSetLoopbackBehavior: unsafe extern "C" fn(adapter: *mut Adapter, behavior: libc::c_uint) -> BOOLEAN, - PacketSetTimestampMode: unsafe extern "C" fn(adapter: *mut Adapter, mode: libc::c_ulong) -> BOOLEAN, - PacketGetTimestampModes: unsafe extern "C" fn(adapter: *mut Adapter, p_modes: *mut libc::c_ulong) -> BOOLEAN, - PacketSetSnaplen: unsafe extern "C" fn(adapter: *mut Adapter, snaplen: libc::c_int) -> libc::c_int, + PacketSetLoopbackBehavior: + unsafe extern "C" fn(adapter: *mut Adapter, behavior: libc::c_uint) -> BOOLEAN, + PacketSetTimestampMode: + unsafe extern "C" fn(adapter: *mut Adapter, mode: libc::c_ulong) -> BOOLEAN, + PacketGetTimestampModes: + unsafe extern "C" fn(adapter: *mut Adapter, p_modes: *mut libc::c_ulong) -> BOOLEAN, + PacketSetSnaplen: + unsafe extern "C" fn(adapter: *mut Adapter, snaplen: libc::c_int) -> libc::c_int, PacketGetStats: unsafe extern "C" fn(adapter: *mut Adapter, stats: *mut BpfStat) -> BOOLEAN, PacketGetStatsEx: unsafe extern "C" fn(adapter: *mut Adapter, stats: *mut BpfStat) -> BOOLEAN, PacketSetBuff: unsafe extern "C" fn(adapter: *mut Adapter, dim: libc::c_int) -> BOOLEAN, PacketGetNetType: unsafe extern "C" fn(adapter: *mut Adapter, ty: *mut NetType) -> BOOLEAN, PacketIsLoopbackAdapter: unsafe extern "C" fn(adapter_name: *const libc::c_char) -> BOOLEAN, - PacketIsMonitorModeSupported: unsafe extern "C" fn(adapter_name: *const libc::c_char) -> libc::c_int, - PacketSetMonitorMode: unsafe extern "C" fn(adapter_name: *const libc::c_char, mode: libc::c_int) -> libc::c_int, + PacketIsMonitorModeSupported: + unsafe extern "C" fn(adapter_name: *const libc::c_char) -> libc::c_int, + PacketSetMonitorMode: + unsafe extern "C" fn(adapter_name: *const libc::c_char, mode: libc::c_int) -> libc::c_int, PacketGetMonitorMode: unsafe extern "C" fn(adapter_name: *const libc::c_char) -> libc::c_int, PacketOpenAdapter: unsafe extern "C" fn(adapter_name: *const libc::c_char) -> *mut Adapter, - PacketSendPacket: unsafe extern "C" fn(adapter: *mut Adapter, packet: *mut Packet, sync: BOOLEAN) -> BOOLEAN, - PacketSendPackets: unsafe extern "C" fn(adapter: *mut Adapter, packet_buf: *mut libc::c_void, size: libc::c_ulong, sync: BOOLEAN) -> libc::c_int, + PacketSendPacket: + unsafe extern "C" fn(adapter: *mut Adapter, packet: *mut Packet, sync: BOOLEAN) -> BOOLEAN, + PacketSendPackets: unsafe extern "C" fn( + adapter: *mut Adapter, + packet_buf: *mut libc::c_void, + size: libc::c_ulong, + sync: BOOLEAN, + ) -> libc::c_int, PacketAllocatePacket: unsafe extern "C" fn() -> *mut Packet, - PacketInitPacket: unsafe extern "C" fn(packet: *mut Packet, buffer: *mut libc::c_void, length: libc::c_uint), + PacketInitPacket: + unsafe extern "C" fn(packet: *mut Packet, buffer: *mut libc::c_void, length: libc::c_uint), PacketFreePacket: unsafe extern "C" fn(packet: *mut Packet), - PacketReceivePacket: unsafe extern "C" fn(adapter: *mut Adapter, packet: *mut Packet, sync: BOOLEAN) -> BOOLEAN, - PacketSetHwFilter: unsafe extern "C" fn(adapter: *mut Adapter, filter: libc::c_ulong) -> BOOLEAN, - PacketGetAdapterNames: unsafe extern "C" fn(buf: *mut libc::c_char, buf_size: *mut libc::c_ulong), - PacketGetNetInfoEx: unsafe extern "C" fn(adapter: *mut Adapter, buffer: *mut NpfIfAddr, n_entries: *mut libc::c_long) -> BOOLEAN, - PacketRequest: unsafe extern "C" fn(adapter: *mut Adapter, set: BOOLEAN, oid_data: *mut PacketOidData) -> BOOLEAN, + PacketReceivePacket: + unsafe extern "C" fn(adapter: *mut Adapter, packet: *mut Packet, sync: BOOLEAN) -> BOOLEAN, + PacketSetHwFilter: + unsafe extern "C" fn(adapter: *mut Adapter, filter: libc::c_ulong) -> BOOLEAN, + PacketGetAdapterNames: + unsafe extern "C" fn(buf: *mut libc::c_char, buf_size: *mut libc::c_ulong), + PacketGetNetInfoEx: unsafe extern "C" fn( + adapter: *mut Adapter, + buffer: *mut NpfIfAddr, + n_entries: *mut libc::c_long, + ) -> BOOLEAN, + PacketRequest: unsafe extern "C" fn( + adapter: *mut Adapter, + set: BOOLEAN, + oid_data: *mut PacketOidData, + ) -> BOOLEAN, PacketGetReadEvent: unsafe extern "C" fn(adapter: *mut Adapter) -> HANDLE, // PacketSetDumpName, PacketSetDumpLimits and PacketIsDumpEnded are deprecated PacketStopDriver: unsafe extern "C" fn() -> BOOL, @@ -66,10 +92,19 @@ impl Npcap { Ok(Self { container: Container::load("Packet.dll").map_err(|e| match e { dlopen2::Error::NullCharacter(_) => unreachable!(), - dlopen2::Error::OpeningLibraryError(e) => NpcapError::new(NpcapErrorKind::DllNotFound, e), - dlopen2::Error::SymbolGettingError(e) => NpcapError::new(NpcapErrorKind::MissingDllSymbol, e), - dlopen2::Error::NullSymbol => NpcapError::new(NpcapErrorKind::MissingDllSymbol, "the value of a resolved dll symbol was null"), - dlopen2::Error::AddrNotMatchingDll(e) => NpcapError::new(NpcapErrorKind::DllNotFound, e), + dlopen2::Error::OpeningLibraryError(e) => { + NpcapError::new(NpcapErrorKind::DllNotFound, e) + } + dlopen2::Error::SymbolGettingError(e) => { + NpcapError::new(NpcapErrorKind::MissingDllSymbol, e) + } + dlopen2::Error::NullSymbol => NpcapError::new( + NpcapErrorKind::MissingDllSymbol, + "the value of a resolved dll symbol was null", + ), + dlopen2::Error::AddrNotMatchingDll(e) => { + NpcapError::new(NpcapErrorKind::DllNotFound, e) + } })?, }) } @@ -112,7 +147,10 @@ impl Npcap { } pub fn set_bpf(&self, adapter: &mut Adapter, program: &BpfProgram) -> bool { - match unsafe { self.container.PacketSetBpf(adapter, ptr::from_ref(program)) } { + match unsafe { + self.container + .PacketSetBpf(adapter, program as *const BpfProgram) + } { 0 => false, _ => true, } @@ -147,14 +185,20 @@ impl Npcap { } pub fn get_stats(&self, adapter: &mut Adapter, stats: &mut BpfStat) -> bool { - match unsafe { self.container.PacketGetStats(adapter, ptr::from_mut(stats)) } { + match unsafe { + self.container + .PacketGetStats(adapter, stats as *mut BpfStat) + } { 0 => false, _ => true, } } pub fn get_stats_ex(&self, adapter: &mut Adapter, stats: &mut BpfStat) -> bool { - match unsafe { self.container.PacketGetStatsEx(adapter, ptr::from_mut(stats)) } { + match unsafe { + self.container + .PacketGetStatsEx(adapter, stats as *mut BpfStat) + } { 0 => false, _ => true, } @@ -168,14 +212,17 @@ impl Npcap { } pub fn get_net_type(&self, adapter: &mut Adapter, ty: &mut NetType) -> bool { - match unsafe { self.container.PacketGetNetType(adapter, ptr::from_mut(ty)) } { + match unsafe { self.container.PacketGetNetType(adapter, ty as *mut NetType) } { 0 => false, _ => true, } } pub fn is_loopback_adapter(&self, adapter_name: &CStr) -> bool { - match unsafe { self.container.PacketIsLoopbackAdapter(adapter_name.as_ptr()) } { + match unsafe { + self.container + .PacketIsLoopbackAdapter(adapter_name.as_ptr()) + } { 0 => false, _ => true, } @@ -183,30 +230,31 @@ impl Npcap { pub fn is_monitor_mode_supported(&self, adapter_name: &CStr) -> libc::c_int { unsafe { - self.container.PacketIsMonitorModeSupported(adapter_name.as_ptr()) + self.container + .PacketIsMonitorModeSupported(adapter_name.as_ptr()) } } pub fn set_monitor_mode(&self, adapter_name: &CStr, mode: libc::c_int) -> libc::c_int { unsafe { - self.container.PacketSetMonitorMode(adapter_name.as_ptr(), mode) + self.container + .PacketSetMonitorMode(adapter_name.as_ptr(), mode) } } pub fn get_monitor_mode(&self, adapter_name: &CStr) -> libc::c_int { - unsafe { - self.container.PacketGetMonitorMode(adapter_name.as_ptr()) - } + unsafe { self.container.PacketGetMonitorMode(adapter_name.as_ptr()) } } pub fn open_adapter(&self, adapter_name: &CStr) -> *mut Adapter { - unsafe { - self.container.PacketOpenAdapter(adapter_name.as_ptr()) - } + unsafe { self.container.PacketOpenAdapter(adapter_name.as_ptr()) } } pub fn send_packet(&self, adapter: &mut Adapter, packet: &mut Packet) -> bool { - match unsafe { self.container.PacketSendPacket(adapter, ptr::from_mut(packet), 1) } { + match unsafe { + self.container + .PacketSendPacket(adapter, packet as *mut Packet, 1) + } { 0 => false, _ => true, } @@ -214,18 +262,17 @@ impl Npcap { pub fn send_packets(&self, adapter: &mut Adapter, packets: &mut [Packet]) -> libc::c_int { let packets_ptr = packets.as_mut_ptr() as *mut libc::c_void; - let packets_len = packets.len() as u64; + let packets_len = packets.len() as u32; // TODO: does this set the correct length? unsafe { - self.container.PacketSendPackets(adapter, packets_ptr, packets_len, 1) + self.container + .PacketSendPackets(adapter, packets_ptr, packets_len, 1) } } pub fn allocate_packet(&self) -> *mut Packet { - unsafe { - self.container.PacketAllocatePacket() - } + unsafe { self.container.PacketAllocatePacket() } } pub fn init_packet(&self, packet: &mut Packet, buffer: NonNull, buflen: usize) { @@ -233,18 +280,20 @@ impl Npcap { let buffer_len = buflen as libc::c_uint; unsafe { - self.container.PacketInitPacket(packet, buffer_ptr, buffer_len) + self.container + .PacketInitPacket(packet, buffer_ptr, buffer_len) } } pub fn free_packet(&self, packet: &mut Packet) { - unsafe { - self.container.PacketFreePacket(packet) - } + unsafe { self.container.PacketFreePacket(packet) } } pub fn receive_packet(&self, adapter: &mut Adapter, packet: &mut Packet) -> bool { - match unsafe { self.container.PacketReceivePacket(adapter, ptr::from_mut(packet), 1) } { + match unsafe { + self.container + .PacketReceivePacket(adapter, packet as *mut Packet, 1) + } { 0 => false, _ => true, } @@ -259,24 +308,35 @@ impl Npcap { pub fn get_adapter_names(&self, buf: &mut [u8], len: &mut libc::c_ulong) { let buf_ptr = buf.as_mut_ptr() as *mut libc::c_char; - let buflen_ptr = ptr::from_mut(len); + let buflen_ptr = len as *mut libc::c_ulong; - unsafe { - self.container.PacketGetAdapterNames(buf_ptr, buflen_ptr) - } + unsafe { self.container.PacketGetAdapterNames(buf_ptr, buflen_ptr) } } - pub fn get_net_info_ex(&self, adapter: &mut Adapter, addrs: &mut [NpfIfAddr], entries: &mut libc::c_long) -> bool { + pub fn get_net_info_ex( + &self, + adapter: &mut Adapter, + addrs: &mut [NpfIfAddr], + entries: &mut libc::c_long, + ) -> bool { let addrs_ptr = addrs.as_mut_ptr(); - let entries_ptr = ptr::from_mut(entries); + let entries_ptr = entries as *mut libc::c_long; - match unsafe { self.container.PacketGetNetInfoEx(adapter, addrs_ptr, entries_ptr) } { + match unsafe { + self.container + .PacketGetNetInfoEx(adapter, addrs_ptr, entries_ptr) + } { 0 => false, _ => true, } } - pub fn get_request(&self, adapter: &mut Adapter, set: bool, oid_data: &mut PacketOidData) -> bool { + pub fn get_request( + &self, + adapter: &mut Adapter, + set: bool, + oid_data: &mut PacketOidData, + ) -> bool { let set = match set { true => 1, false => 0, @@ -289,9 +349,7 @@ impl Npcap { } pub fn get_read_event(&self, adapter: &mut Adapter) -> HANDLE { - unsafe { - self.container.PacketGetReadEvent(adapter) - } + unsafe { self.container.PacketGetReadEvent(adapter) } } pub fn stop_driver(&self) -> bool { @@ -312,5 +370,3 @@ impl Npcap { self.container.PacketCloseAdapter(adapter) } } - - diff --git a/rscap/src/npcap/dll/link.rs b/rscap/src/npcap/dll/link.rs index 0033f21..8f25a7a 100644 --- a/rscap/src/npcap/dll/link.rs +++ b/rscap/src/npcap/dll/link.rs @@ -1,6 +1,9 @@ #![allow(non_snake_case)] -use std::{ffi::CStr, ptr::{self, NonNull}}; +use std::{ + ffi::CStr, + ptr::{self, NonNull}, +}; use windows_sys::Win32::Foundation::{BOOL, BOOLEAN, HANDLE}; @@ -51,7 +54,12 @@ extern "C" { fn PacketSendPacket(adapter: *mut Adapter, packet: *mut Packet, sync: BOOLEAN) -> BOOLEAN; - fn PacketSendPackets(adapter: *mut Adapter, packet_buf: *mut libc::c_void, size: libc::c_ulong, sync: BOOLEAN) -> libc::c_int; + fn PacketSendPackets( + adapter: *mut Adapter, + packet_buf: *mut libc::c_void, + size: libc::c_ulong, + sync: BOOLEAN, + ) -> libc::c_int; fn PacketAllocatePacket() -> *mut Packet; @@ -65,7 +73,11 @@ extern "C" { fn PacketGetAdapterNames(buf: *mut libc::c_char, buf_size: *mut libc::c_ulong); - fn PacketGetNetInfoEx(adapter: *mut Adapter, buffer: *mut NpfIfAddr, n_entries: *mut libc::c_long) -> BOOLEAN; + fn PacketGetNetInfoEx( + adapter: *mut Adapter, + buffer: *mut NpfIfAddr, + n_entries: *mut libc::c_long, + ) -> BOOLEAN; fn PacketRequest(adapter: *mut Adapter, set: BOOLEAN, oid_data: *mut PacketOidData) -> BOOLEAN; @@ -110,7 +122,7 @@ impl Npcap { } pub fn set_num_writes(&self, adapter: &mut Adapter, nwrites: libc::c_int) -> bool { - unsafe { + unsafe { match PacketSetNumWrites(adapter, nwrites) { 0 => false, _ => true, @@ -119,7 +131,7 @@ impl Npcap { } pub fn set_mode(&self, adapter: &mut Adapter, mode: libc::c_int) -> bool { - unsafe { + unsafe { match PacketSetMode(adapter, mode) { 0 => false, _ => true, @@ -128,7 +140,7 @@ impl Npcap { } pub fn set_read_timeout(&self, adapter: &mut Adapter, timeout: libc::c_int) -> bool { - unsafe { + unsafe { match PacketSetReadTimeout(adapter, timeout) { 0 => false, _ => true, @@ -137,8 +149,8 @@ impl Npcap { } pub fn set_bpf(&self, adapter: &mut Adapter, program: &BpfProgram) -> bool { - unsafe { - match PacketSetBpf(adapter, ptr::from_ref(program)) { + unsafe { + match PacketSetBpf(adapter, program as *const BpfProgram) { 0 => false, _ => true, } @@ -146,7 +158,7 @@ impl Npcap { } pub fn set_loopback_behavior(&self, adapter: &mut Adapter, behavior: libc::c_uint) -> bool { - unsafe { + unsafe { match PacketSetLoopbackBehavior(adapter, behavior) { 0 => false, _ => true, @@ -155,7 +167,7 @@ impl Npcap { } pub fn set_timestamp_mode(&self, adapter: &mut Adapter, mode: libc::c_ulong) -> bool { - unsafe { + unsafe { match PacketSetTimestampMode(adapter, mode) { 0 => false, _ => true, @@ -164,7 +176,7 @@ impl Npcap { } pub fn get_timestamp_modes(&self, adapter: &mut Adapter, modes: *mut libc::c_ulong) -> bool { - unsafe { + unsafe { match PacketGetTimestampModes(adapter, modes) { 0 => false, _ => true, @@ -173,7 +185,7 @@ impl Npcap { } pub fn set_snaplen(&self, adapter: &mut Adapter, snaplen: libc::c_int) -> bool { - unsafe { + unsafe { match PacketSetSnaplen(adapter, snaplen) { 0 => false, _ => true, @@ -182,8 +194,8 @@ impl Npcap { } pub fn get_stats(&self, adapter: &mut Adapter, stats: &mut BpfStat) -> bool { - unsafe { - match PacketGetStats(adapter, ptr::from_mut(stats)) { + unsafe { + match PacketGetStats(adapter, stats as *mut BpfStat) { 0 => false, _ => true, } @@ -191,8 +203,8 @@ impl Npcap { } pub fn get_stats_ex(&self, adapter: &mut Adapter, stats: &mut BpfStat) -> bool { - unsafe { - match PacketGetStatsEx(adapter, ptr::from_mut(stats)) { + unsafe { + match PacketGetStatsEx(adapter, stats as *mut BpfStat) { 0 => false, _ => true, } @@ -200,7 +212,7 @@ impl Npcap { } pub fn set_buff(&self, adapter: &mut Adapter, dim: libc::c_int) -> bool { - unsafe { + unsafe { match PacketSetBuff(adapter, dim) { 0 => false, _ => true, @@ -209,8 +221,8 @@ impl Npcap { } pub fn get_net_type(&self, adapter: &mut Adapter, ty: &mut NetType) -> bool { - unsafe { - match PacketGetNetType(adapter, ptr::from_mut(ty)) { + unsafe { + match PacketGetNetType(adapter, ty as *mut NetType) { 0 => false, _ => true, } @@ -218,7 +230,7 @@ impl Npcap { } pub fn is_loopback_adapter(&self, adapter_name: &CStr) -> bool { - unsafe { + unsafe { match PacketIsLoopbackAdapter(adapter_name.as_ptr()) { 0 => false, _ => true, @@ -227,33 +239,25 @@ impl Npcap { } pub fn is_monitor_mode_supported(&self, adapter_name: &CStr) -> libc::c_int { - unsafe { - PacketIsMonitorModeSupported(adapter_name.as_ptr()) - } + unsafe { PacketIsMonitorModeSupported(adapter_name.as_ptr()) } } // TODO: adapter_name might be a *mut c_char, not *const pub fn set_monitor_mode(&self, adapter_name: &CStr, mode: libc::c_int) -> libc::c_int { - unsafe { - PacketSetMonitorMode(adapter_name.as_ptr(), mode) - } + unsafe { PacketSetMonitorMode(adapter_name.as_ptr(), mode) } } pub fn get_monitor_mode(&self, adapter_name: &CStr) -> libc::c_int { - unsafe { - PacketGetMonitorMode(adapter_name.as_ptr()) - } + unsafe { PacketGetMonitorMode(adapter_name.as_ptr()) } } pub fn open_adapter(&self, adapter_name: &CStr) -> *mut Adapter { - unsafe { - PacketOpenAdapter(adapter_name.as_ptr()) - } + unsafe { PacketOpenAdapter(adapter_name.as_ptr()) } } pub fn send_packet(&self, adapter: &mut Adapter, packet: &mut Packet) -> bool { - unsafe { - match PacketSendPacket(adapter, ptr::from_mut(packet), 1) { + unsafe { + match PacketSendPacket(adapter, packet as *mut Packet, 1) { 0 => false, _ => true, } @@ -262,31 +266,36 @@ impl Npcap { pub fn send_packets(&self, adapter: &mut Adapter, packets: &mut [Packet]) -> libc::c_int { // TODO: does this set the correct length? - unsafe { - PacketSendPackets(adapter, packets.as_mut_ptr() as *mut libc::c_void, packets.len() as u64, 1) + unsafe { + PacketSendPackets( + adapter, + packets.as_mut_ptr() as *mut libc::c_void, + packets.len() as u64, + 1, + ) } } pub fn allocate_packet(&self) -> *mut Packet { - unsafe { - PacketAllocatePacket() - } + unsafe { PacketAllocatePacket() } } pub fn init_packet(packet: &mut Packet, buffer: NonNull, buflen: usize) { unsafe { - PacketInitPacket(packet, buffer.as_ptr() as &mut libc::c_void, buflen as libc::c_uint) + PacketInitPacket( + packet, + buffer.as_ptr() as &mut libc::c_void, + buflen as libc::c_uint, + ) } } pub fn free_packet(&self, packet: &mut Packet) { - unsafe { - PacketFreePacket(packet) - } + unsafe { PacketFreePacket(packet) } } pub fn receive_packet(&self, adapter: &mut Adapter, packet: &mut Packet) -> bool { - unsafe { + unsafe { match PacketReceivePacket(adapter, packet, 1) { 0 => false, _ => true, @@ -295,7 +304,7 @@ impl Npcap { } pub fn set_hw_filter(&self, adapter: &mut Adapter, filter: libc::c_ulong) -> bool { - unsafe { + unsafe { match PacketSetHwFilter(adapter, filter) { 0 => false, _ => true, @@ -304,28 +313,41 @@ impl Npcap { } pub fn get_adapter_names(&self, buf: &mut [u8], len: &mut libc::c_ulong) { - unsafe { - PacketGetAdapterNames(buf.as_mut_ptr() as *mut libc::c_char, ptr::from_mut(len)) + unsafe { + PacketGetAdapterNames( + buf.as_mut_ptr() as *mut libc::c_char, + len as *mut libc::c_ulong, + ) } } - pub fn get_net_info_ex(&self, adapter: &mut Adapter, addrs: &mut [NpfIfAddr], entries: &mut libc::c_long) -> bool { - unsafe { - match PacketGetNetInfoEx(adapter, addrs.as_mut_ptr(), ptr::from_mut(entries)) { + pub fn get_net_info_ex( + &self, + adapter: &mut Adapter, + addrs: &mut [NpfIfAddr], + entries: &mut libc::c_long, + ) -> bool { + unsafe { + match PacketGetNetInfoEx(adapter, addrs.as_mut_ptr(), entries as *mut libc::c_long) { 0 => false, _ => true, } } } - pub fn get_request(&self, adapter: &mut Adapter, set: bool, oid_data: &mut PacketOidData) -> bool { + pub fn get_request( + &self, + adapter: &mut Adapter, + set: bool, + oid_data: &mut PacketOidData, + ) -> bool { let set = match set { true => 1, false => 0, }; - unsafe { - match PacketRequest(adapter, set, ptr::from_mut(oid_data)) { + unsafe { + match PacketRequest(adapter, set, oid_data as *mut PacketOidData) { 0 => false, _ => true, } @@ -333,13 +355,11 @@ impl Npcap { } pub fn get_read_event(&self, adapter: &mut Adapter) -> HANDLE { - unsafe { - PacketGetReadEvent(adapter) - } + unsafe { PacketGetReadEvent(adapter) } } pub fn stop_driver(&self) -> bool { - unsafe { + unsafe { match PacketStopDriver() { 0 => false, _ => true, @@ -348,7 +368,7 @@ impl Npcap { } pub fn stop_driver_60(&self) -> bool { - unsafe { + unsafe { match PacketStopDriver60() { 0 => false, _ => true, @@ -357,9 +377,6 @@ impl Npcap { } pub unsafe fn close_adapter(&self, adapter: *mut Adapter) { - unsafe { - PacketCloseAdapter(adapter) - } + unsafe { PacketCloseAdapter(adapter) } } } - diff --git a/rscap/src/pktmon.rs b/rscap/src/pktmon.rs index af40352..4034605 100644 --- a/rscap/src/pktmon.rs +++ b/rscap/src/pktmon.rs @@ -9,8 +9,7 @@ // except according to those terms. //! (Windows 10/11) Packet Monitor (pktmon) packet capture interface. -//! - +//! // pktmon is an upgrade from NdisCap // NPcap uses NDIS, but allows for promiscuous mode, BPF and other features