diff --git a/CHANGELOG.md b/CHANGELOG.md index 758e969..2ffdb6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All releases with the relative changes are documented in this file. +## [UNRELEASED] +### Changed +- Lighten the dependency tree: drop `byteorder` on macOS, and use `windows-sys` instead of `windows` on Windows ([#60](https://github.com/GyulyVGC/listeners/pull/60)) + ## [0.6.1] - 2026-08-02 ### Fixed - Correctly report IPv4-mapped IPv6 addresses on macOS ([#57](https://github.com/GyulyVGC/listeners/pull/57) — fixes [#56](https://github.com/GyulyVGC/listeners/issues/56)) diff --git a/Cargo.toml b/Cargo.toml index a3efa34..d8d1ca8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,16 +24,13 @@ print_stdout = "warn" print_stderr = "warn" [target.'cfg(target_os = "windows")'.dependencies] -windows = { version = "0.62", features = [ +windows-sys = { version = "0.61", features = [ "Win32_Foundation", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Threading", "Win32_NetworkManagement_IpHelper" ] } -[target.'cfg(target_os = "macos")'.dependencies] -byteorder = "1.5" - [target.'cfg(target_os = "linux")'.dependencies] rustix = {version = "1.1", features = ["fs"]} diff --git a/src/platform/macos/c_socket_fd_info.rs b/src/platform/macos/c_socket_fd_info.rs index c9f85a5..5df05e7 100644 --- a/src/platform/macos/c_socket_fd_info.rs +++ b/src/platform/macos/c_socket_fd_info.rs @@ -1,8 +1,6 @@ use std::ffi::{c_char, c_int, c_longlong, c_short, c_uchar, c_uint, c_ushort}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use byteorder::{ByteOrder, NetworkEndian}; - use crate::platform::macos::proto_listener::ProtoListener; use crate::{Protocol, SocketState}; @@ -34,13 +32,13 @@ impl CSocketFdInfo { } }; - let lport_bytes: [u8; 4] = i32::to_le_bytes(general_sock_info.insi_lport); + let [lport_hi, lport_lo, ..] = i32::to_le_bytes(general_sock_info.insi_lport); let local_address = Self::get_local_addr(family, general_sock_info)?; let protocol = Self::get_protocol(family, transport_protocol)?; let socket_info = ProtoListener::new( local_address, - NetworkEndian::read_u16(&lport_bytes), + u16::from_be_bytes([lport_hi, lport_lo]), protocol, state, ); @@ -82,10 +80,8 @@ impl CSocketFdInfo { /// The 16-byte `ina_6` slot. fn v6_slot(sock_info: &InSockinfo) -> Ipv6Addr { - let addr = unsafe { &sock_info.insi_laddr.ina_6.__u6_addr.__u6_addr8 }; - let mut ipv6_addr = [0_u16; 8]; - NetworkEndian::read_u16_into(addr, &mut ipv6_addr); - Ipv6Addr::from(ipv6_addr) + let addr = unsafe { sock_info.insi_laddr.ina_6.__u6_addr.__u6_addr8 }; + Ipv6Addr::from(addr) } fn get_protocol(family: c_int, ip_protocol: c_int) -> crate::Result { diff --git a/src/platform/windows/proto_listener.rs b/src/platform/windows/proto_listener.rs index 97f1c9e..90adcb3 100644 --- a/src/platform/windows/proto_listener.rs +++ b/src/platform/windows/proto_listener.rs @@ -6,20 +6,19 @@ use crate::platform::windows::tcp_table::TcpTable; use crate::platform::windows::tcp6_table::Tcp6Table; use std::collections::HashMap; use std::collections::hash_map::Entry; +use std::ffi::CStr; use std::mem::size_of; use std::mem::zeroed; use std::net::{IpAddr, SocketAddr}; use std::os::windows::ffi::OsStringExt; use std::path::Path; -use windows::Win32::Foundation::CloseHandle; -use windows::Win32::System::Diagnostics::ToolHelp::{ +use windows_sys::Win32::Foundation::{CloseHandle, FALSE, HANDLE, INVALID_HANDLE_VALUE}; +use windows_sys::Win32::System::Diagnostics::ToolHelp::{ CreateToolhelp32Snapshot, PROCESSENTRY32, Process32First, Process32Next, TH32CS_SNAPPROCESS, }; -use windows::Win32::System::Threading::{ - OpenProcess, PROCESS_NAME_FORMAT, PROCESS_QUERY_LIMITED_INFORMATION, QueryFullProcessImageNameW, +use windows_sys::Win32::System::Threading::{ + OpenProcess, PROCESS_NAME_WIN32, PROCESS_QUERY_LIMITED_INFORMATION, QueryFullProcessImageNameW, }; -use windows::core::PCSTR; -use windows::core::PWSTR; use super::udp_table::UdpTable; use super::udp6_table::Udp6Table; @@ -149,27 +148,46 @@ impl PidNamePathCache { } } +fn is_invalid(handle: HANDLE) -> bool { + handle.is_null() || handle == INVALID_HANDLE_VALUE +} + +/// Takes a snapshot of the running processes. +fn process_snapshot() -> Option { + let handle = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; + (!is_invalid(handle)).then_some(handle) +} + +/// Reads the `szExeFile` field of a process entry. +/// +/// Returns `None` if the field isn't NUL-terminated or isn't valid UTF-8. +fn exe_file(process: &PROCESSENTRY32) -> Option { + let raw = &process.szExeFile; + // SAFETY: `c_char` and `u8` share their layout, and the length is taken from the + // array itself, so the read stays within `szExeFile` even if the OS didn't + // NUL-terminate it. + let bytes = unsafe { std::slice::from_raw_parts(raw.as_ptr().cast::(), raw.len()) }; + let name = CStr::from_bytes_until_nul(bytes).ok()?; + name.to_str().ok().map(str::to_owned) +} + fn pname(pid: u32) -> Option { - let h = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0).ok()? }; + let dw_size = u32::try_from(size_of::()).ok()?; + let h = process_snapshot()?; let mut process = unsafe { zeroed::() }; - process.dwSize = u32::try_from(size_of::()).ok()?; + process.dwSize = dw_size; let mut result = None; - if unsafe { Process32First(h, &raw mut process) }.is_ok() { + if unsafe { Process32First(h, &raw mut process) } != FALSE { loop { if process.th32ProcessID == pid { - let name = unsafe { - PCSTR(process.szExeFile.as_ptr().cast::()) - .to_string() - .ok()? - }; - result = Some(name); + result = exe_file(&process); break; } - if unsafe { Process32Next(h, &raw mut process) }.is_err() { + if unsafe { Process32Next(h, &raw mut process) } == FALSE { break; } } @@ -184,10 +202,8 @@ fn pname(pid: u32) -> Option { fn ppath(pid: u32) -> String { unsafe { - let Ok(handle) = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid) else { - return String::new(); - }; - if handle.is_invalid() { + let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if is_invalid(handle) { return String::new(); } @@ -196,13 +212,13 @@ fn ppath(pid: u32) -> String { let result = QueryFullProcessImageNameW( handle, - PROCESS_NAME_FORMAT(0), - PWSTR(buffer.as_mut_ptr()), + PROCESS_NAME_WIN32, + buffer.as_mut_ptr(), &raw mut size, ); let _ = CloseHandle(handle); - if result.is_err() { + if result == FALSE { return String::new(); } @@ -214,25 +230,24 @@ fn ppath(pid: u32) -> String { fn pname_collect() -> HashMap { let mut ret_val = HashMap::default(); - let Ok(h) = (unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }) else { + let Ok(dw_size) = u32::try_from(size_of::()) else { return ret_val; }; - - let mut process = unsafe { zeroed::() }; - let Ok(dw_size) = u32::try_from(size_of::()) else { + let Some(h) = process_snapshot() else { return ret_val; }; + + let mut process = unsafe { zeroed::() }; process.dwSize = dw_size; - if unsafe { Process32First(h, &raw mut process) }.is_ok() { + if unsafe { Process32First(h, &raw mut process) } != FALSE { loop { - if let Ok(name) = unsafe { PCSTR(process.szExeFile.as_ptr().cast::()).to_string() } - { + if let Some(name) = exe_file(&process) { let id = process.th32ProcessID; ret_val.insert(id, name); } - if unsafe { Process32Next(h, &raw mut process) }.is_err() { + if unsafe { Process32Next(h, &raw mut process) } == FALSE { break; } } diff --git a/src/platform/windows/socket_table.rs b/src/platform/windows/socket_table.rs index 775413d..5704e2b 100644 --- a/src/platform/windows/socket_table.rs +++ b/src/platform/windows/socket_table.rs @@ -1,18 +1,18 @@ use std::ffi::{c_ulong, c_void}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use super::statics::UDP_TABLE_OWNER_PID; use crate::Protocol; use crate::SocketState; use crate::platform::target_os::proto_listener::ProtoListener; -use crate::platform::windows::statics::{ - AF_INET, AF_INET6, ERROR_INSUFFICIENT_BUFFER, NO_ERROR, TCP_TABLE_OWNER_PID_ALL, -}; +use crate::platform::windows::statics::{AF_INET, AF_INET6}; use crate::platform::windows::tcp_table::TcpTable; use crate::platform::windows::tcp6_table::Tcp6Table; use crate::platform::windows::udp_table::UdpTable; use crate::platform::windows::udp6_table::Udp6Table; -use windows::Win32::NetworkManagement::IpHelper::{GetExtendedTcpTable, GetExtendedUdpTable}; +use windows_sys::Win32::Foundation::{ERROR_INSUFFICIENT_BUFFER, FALSE, NO_ERROR}; +use windows_sys::Win32::NetworkManagement::IpHelper::{ + GetExtendedTcpTable, GetExtendedUdpTable, TCP_TABLE_OWNER_PID_ALL, UDP_TABLE_OWNER_PID, +}; pub(super) trait SocketTable { fn get_table() -> crate::Result>; @@ -180,9 +180,9 @@ fn get_udp_table(address_family: c_ulong) -> crate::Result> { let mut table_size: c_ulong = 0; let mut err_code = unsafe { GetExtendedUdpTable( - None, + std::ptr::null_mut(), &raw mut table_size, - false, + FALSE, address_family, UDP_TABLE_OWNER_PID, 0, @@ -194,9 +194,9 @@ fn get_udp_table(address_family: c_ulong) -> crate::Result> { table = Vec::::with_capacity(table_size as usize); err_code = unsafe { GetExtendedUdpTable( - Some(table.as_mut_ptr().cast::()), + table.as_mut_ptr().cast::(), &raw mut table_size, - false, + FALSE, address_family, UDP_TABLE_OWNER_PID, 0, @@ -218,9 +218,9 @@ fn get_tcp_table(address_family: c_ulong) -> crate::Result> { let mut table_size: c_ulong = 0; let mut err_code = unsafe { GetExtendedTcpTable( - None, + std::ptr::null_mut(), &raw mut table_size, - false, + FALSE, address_family, TCP_TABLE_OWNER_PID_ALL, 0, @@ -232,9 +232,9 @@ fn get_tcp_table(address_family: c_ulong) -> crate::Result> { table = Vec::::with_capacity(table_size as usize); err_code = unsafe { GetExtendedTcpTable( - Some(table.as_mut_ptr().cast::()), + table.as_mut_ptr().cast::(), &raw mut table_size, - false, + FALSE, address_family, TCP_TABLE_OWNER_PID_ALL, 0, diff --git a/src/platform/windows/statics.rs b/src/platform/windows/statics.rs index e20de61..9d56109 100644 --- a/src/platform/windows/statics.rs +++ b/src/platform/windows/statics.rs @@ -1,9 +1,4 @@ use std::ffi::c_ulong; -use windows::Win32::NetworkManagement::IpHelper::{TCP_TABLE_CLASS, UDP_TABLE_CLASS}; -pub(super) const TCP_TABLE_OWNER_PID_ALL: TCP_TABLE_CLASS = TCP_TABLE_CLASS(5); -pub(super) const UDP_TABLE_OWNER_PID: UDP_TABLE_CLASS = UDP_TABLE_CLASS(1); -pub(super) const ERROR_INSUFFICIENT_BUFFER: c_ulong = 0x7A; -pub(super) const NO_ERROR: c_ulong = 0; pub(super) const AF_INET: c_ulong = 2; pub(super) const AF_INET6: c_ulong = 23;