diff --git a/nym-vpn-core/Cargo.lock b/nym-vpn-core/Cargo.lock index 8ac4c1d4e9..d0f48dafeb 100644 --- a/nym-vpn-core/Cargo.lock +++ b/nym-vpn-core/Cargo.lock @@ -3474,7 +3474,7 @@ dependencies = [ "libc", "thiserror 2.0.11", "tracing", - "windows-sys 0.52.0", + "windows 0.59.0", ] [[package]] @@ -3712,7 +3712,7 @@ dependencies = [ "tracing", "triggered", "which", - "windows-sys 0.52.0", + "windows 0.59.0", "winreg 0.52.0", ] @@ -4211,7 +4211,7 @@ dependencies = [ "tokio", "tracing", "widestring", - "windows-sys 0.52.0", + "windows 0.59.0", ] [[package]] @@ -4813,7 +4813,7 @@ dependencies = [ "uniffi", "url", "vergen", - "windows-sys 0.52.0", + "windows 0.59.0", ] [[package]] @@ -4968,8 +4968,8 @@ dependencies = [ "url", "vergen", "winapi", + "windows 0.59.0", "windows-service", - "windows-sys 0.52.0", "zeroize", ] @@ -5017,7 +5017,7 @@ dependencies = [ "rand 0.8.5", "thiserror 2.0.11", "tracing", - "windows-sys 0.52.0", + "windows 0.59.0", "x25519-dalek", "zeroize", ] @@ -5028,11 +5028,10 @@ version = "1.2.0-dev" dependencies = [ "futures", "nym-common", - "socket2", "thiserror 2.0.11", "tokio", "tracing", - "windows-sys 0.52.0", + "windows 0.59.0", ] [[package]] @@ -5570,7 +5569,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.95", @@ -8299,6 +8298,16 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +dependencies = [ + "windows-core 0.59.0", + "windows-targets 0.53.0", +] + [[package]] name = "windows-core" version = "0.51.1" @@ -8338,10 +8347,23 @@ dependencies = [ "windows-implement 0.58.0", "windows-interface 0.58.0", "windows-result 0.2.0", - "windows-strings", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.0", + "windows-result 0.3.0", + "windows-strings 0.3.0", + "windows-targets 0.53.0", +] + [[package]] name = "windows-implement" version = "0.57.0" @@ -8364,6 +8386,17 @@ dependencies = [ "syn 2.0.95", ] +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "windows-interface" version = "0.57.0" @@ -8386,6 +8419,17 @@ dependencies = [ "syn 2.0.95", ] +[[package]] +name = "windows-interface" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "windows-result" version = "0.1.2" @@ -8404,6 +8448,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08106ce80268c4067c0571ca55a9b4e9516518eaa1a1fe9b37ca403ae1d1a34" +dependencies = [ + "windows-targets 0.53.0", +] + [[package]] name = "windows-service" version = "0.7.0" @@ -8425,6 +8478,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b888f919960b42ea4e11c2f408fadb55f78a9f236d5eef084103c8ce52893491" +dependencies = [ + "windows-targets 0.53.0", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -8476,13 +8538,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -8495,6 +8573,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -8507,6 +8591,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -8519,12 +8609,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -8537,6 +8639,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -8549,6 +8657,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -8561,6 +8675,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -8573,6 +8693,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.6.22" diff --git a/nym-vpn-core/Cargo.toml b/nym-vpn-core/Cargo.toml index dd50e3c340..f95988e60b 100644 --- a/nym-vpn-core/Cargo.toml +++ b/nym-vpn-core/Cargo.toml @@ -132,7 +132,6 @@ serde_json = "1.0" sha2 = "0.10" si-scale = "0.2.3" signature = "2.2.0" -socket2 = "0.5.8" sqlx = "0.7.4" strum = "0.26" strum_macros = "0.26" @@ -167,7 +166,7 @@ vergen = { version = "8.3.1", default-features = false } which = { version = "7.0", default-features = false } widestring = "1.0" windows-service = "0.7.0" -windows-sys = "0.52" +windows = "0.59" x25519-dalek = "2.0" zeroize = "1.6.0" diff --git a/nym-vpn-core/crates/nym-common/Cargo.toml b/nym-vpn-core/crates/nym-common/Cargo.toml index ea27ff1087..27df328a4b 100644 --- a/nym-vpn-core/crates/nym-common/Cargo.toml +++ b/nym-vpn-core/crates/nym-common/Cargo.toml @@ -13,6 +13,6 @@ tracing.workspace = true libc.workspace = true thiserror.workspace = true -[target.'cfg(windows)'.dependencies.windows-sys] +[target.'cfg(windows)'.dependencies.windows] workspace = true features = ["Win32_Foundation"] diff --git a/nym-vpn-core/crates/nym-common/src/error.rs b/nym-vpn-core/crates/nym-common/src/error.rs index 61b73aa887..e92910c7e7 100644 --- a/nym-vpn-core/crates/nym-common/src/error.rs +++ b/nym-vpn-core/crates/nym-common/src/error.rs @@ -56,23 +56,6 @@ impl BoxedError { } } -/// Helper macro allowing simpler handling of Windows FFI returning `WIN32_ERROR` -/// status codes. Converts a `WIN32_ERROR` into an `io::Result<()>`. -/// -/// The caller of this macro must have `windows_sys` as a dependency. -#[cfg(windows)] -#[macro_export] -macro_rules! win32_err { - ($expr:expr) => {{ - let status = $expr; - if status == ::windows_sys::Win32::Foundation::NO_ERROR { - Ok(()) - } else { - Err(::std::io::Error::from_raw_os_error(status as i32)) - } - }}; -} - pub mod flood { use std::time::{Duration, Instant}; diff --git a/nym-vpn-core/crates/nym-dns/Cargo.toml b/nym-vpn-core/crates/nym-dns/Cargo.toml index 09ced05976..d0b6410bfa 100644 --- a/nym-vpn-core/crates/nym-dns/Cargo.toml +++ b/nym-vpn-core/crates/nym-dns/Cargo.toml @@ -40,7 +40,7 @@ winreg = { version = "0.52", features = ["transactions"] } nym-windows = { path = "../nym-windows" } nym-common = { path = "../nym-common" } -[target.'cfg(windows)'.dependencies.windows-sys] +[target.'cfg(windows)'.dependencies.windows] workspace = true features = [ "Win32_Foundation", diff --git a/nym-vpn-core/crates/nym-dns/src/windows/auto.rs b/nym-vpn-core/crates/nym-dns/src/windows/auto.rs index ecadf9d9f3..91a7e1390c 100644 --- a/nym-vpn-core/crates/nym-dns/src/windows/auto.rs +++ b/nym-vpn-core/crates/nym-dns/src/windows/auto.rs @@ -4,7 +4,7 @@ use super::{iphlpapi, netsh, tcpip}; use crate::{DnsMonitorT, ResolvedDnsConfig}; -use windows_sys::Win32::System::Rpc::RPC_S_SERVER_UNAVAILABLE; +use windows::Win32::System::Rpc::RPC_S_SERVER_UNAVAILABLE; pub struct DnsMonitor { current_monitor: InnerMonitor, @@ -86,7 +86,7 @@ impl DnsMonitor { fn fallback_due_to_dnscache(&mut self, result: &Result<(), super::Error>) -> bool { let is_dnscache_error = match result { Err(super::Error::Iphlpapi(iphlpapi::Error::SetInterfaceDnsSettings(error))) => { - error.raw_os_error() == Some(RPC_S_SERVER_UNAVAILABLE) + error.code() == RPC_S_SERVER_UNAVAILABLE.to_hresult() } Err(super::Error::Netsh(netsh::Error::Netsh(Some(1)))) => true, _ => false, diff --git a/nym-vpn-core/crates/nym-dns/src/windows/dnsapi.rs b/nym-vpn-core/crates/nym-dns/src/windows/dnsapi.rs index 7bd6512cf7..0bdc91eccb 100644 --- a/nym-vpn-core/crates/nym-dns/src/windows/dnsapi.rs +++ b/nym-vpn-core/crates/nym-dns/src/windows/dnsapi.rs @@ -9,7 +9,7 @@ use std::{ }, time::{Duration, Instant}, }; -use windows_sys::Win32::Foundation::BOOL; +use windows::Win32::Foundation::BOOL; static FLUSH_TIMEOUT: Duration = Duration::from_secs(5); static DNSAPI_HANDLE: OnceLock = OnceLock::new(); @@ -66,7 +66,7 @@ impl DnsApi { std::thread::spawn(move || { let begin = Instant::now(); - let result = if unsafe { (DnsFlushResolverCache)() } != 0 { + let result = if unsafe { (DnsFlushResolverCache)() }.0 != 0 { let elapsed = begin.elapsed(); if elapsed >= FLUSH_TIMEOUT { tracing::warn!( diff --git a/nym-vpn-core/crates/nym-dns/src/windows/iphlpapi.rs b/nym-vpn-core/crates/nym-dns/src/windows/iphlpapi.rs index 7b8d6dbc59..18f3ca265d 100644 --- a/nym-vpn-core/crates/nym-dns/src/windows/iphlpapi.rs +++ b/nym-vpn-core/crates/nym-dns/src/windows/iphlpapi.rs @@ -8,7 +8,6 @@ //! back on other methods if it is not available. use crate::{DnsMonitorT, ResolvedDnsConfig}; -use nym_common::win32_err; use nym_windows::net::{guid_from_luid, luid_from_alias}; use once_cell::sync::OnceCell; use std::{ @@ -16,11 +15,9 @@ use std::{ io, net::{IpAddr, Ipv4Addr, Ipv6Addr}, os::windows::ffi::OsStrExt, - ptr, }; -use windows_sys::{ - core::GUID, - s, w, +use windows::{ + core::{s, w, GUID, PWSTR}, Win32::{ Foundation::{FreeLibrary, ERROR_PROC_NOT_FOUND, WIN32_ERROR}, NetworkManagement::IpHelper::{ @@ -44,7 +41,7 @@ pub enum Error { /// Failed to set DNS settings on interface. #[error("Failed to set DNS settings on interface")] - SetInterfaceDnsSettings(#[source] io::Error), + SetInterfaceDnsSettings(#[source] windows::core::Error), /// Failure to flush DNS cache. #[error("Failed to flush DNS resolver cache")] @@ -52,11 +49,11 @@ pub enum Error { /// Failed to load iphlpapi.dll. #[error("Failed to load iphlpapi.dll")] - LoadDll(#[source] io::Error), + LoadDll(#[source] windows::core::Error), /// Failed to obtain exported function. #[error("Failed to obtain DNS function")] - GetFunction(#[source] io::Error), + GetFunction(#[source] windows::core::Error), } type SetInterfaceDnsSettingsFn = unsafe extern "stdcall" fn( @@ -75,11 +72,12 @@ static IPHLPAPI_HANDLE: OnceCell = OnceCell::new(); impl IphlpApi { fn new() -> Result { - let module = unsafe { LoadLibraryExW(w!("iphlpapi.dll"), 0, LOAD_LIBRARY_SEARCH_SYSTEM32) }; - if module == 0 { - tracing::error!("Failed to load iphlpapi.dll"); - return Err(Error::LoadDll(io::Error::last_os_error())); - } + let module = + unsafe { LoadLibraryExW(w!("iphlpapi.dll"), None, LOAD_LIBRARY_SEARCH_SYSTEM32) } + .map_err(|e| { + tracing::error!("Failed to load iphlpapi.dll: {}", e); + Error::LoadDll(e) + })?; // This function is loaded at runtime since it may be unavailable. See the module-level // docs. TODO: `windows_sys` can be used directly when support for versions older @@ -87,15 +85,17 @@ impl IphlpApi { let set_interface_dns_settings = unsafe { GetProcAddress(module, s!("SetInterfaceDnsSettings")) }; let set_interface_dns_settings = set_interface_dns_settings.ok_or_else(|| { - let error = io::Error::last_os_error(); + let error = windows::core::Error::from_win32(); - if error.raw_os_error() != Some(ERROR_PROC_NOT_FOUND as i32) { + if error.code() != ERROR_PROC_NOT_FOUND.to_hresult() { tracing::error!( "Could not find SetInterfaceDnsSettings due to an unexpected error: {error}" ); } - unsafe { FreeLibrary(module) }; + if let Err(e) = unsafe { FreeLibrary(module) } { + tracing::error!("Failed to free library iphlpapi.dll: {}", e); + } Error::GetFunction(error) })?; @@ -200,20 +200,19 @@ fn set_interface_dns_servers( let dns_interface_settings = DNS_INTERFACE_SETTINGS { Version: DNS_INTERFACE_SETTINGS_VERSION1, Flags: u64::from(flags), - Domain: ptr::null_mut(), - NameServer: nameservers.as_mut_ptr(), - SearchList: ptr::null_mut(), + Domain: PWSTR::null(), + NameServer: PWSTR::from_raw(nameservers.as_mut_ptr()), + SearchList: PWSTR::null(), RegistrationEnabled: 0, RegisterAdapterName: 0, EnableLLMNR: 0, QueryAdapterName: 0, - ProfileNameServer: ptr::null_mut(), + ProfileNameServer: PWSTR::null(), }; - win32_err!(unsafe { - (iphlpapi.set_interface_dns_settings)(guid.to_owned(), &dns_interface_settings) - }) - .map_err(Error::SetInterfaceDnsSettings) + unsafe { (iphlpapi.set_interface_dns_settings)(guid.to_owned(), &dns_interface_settings) } + .ok() + .map_err(Error::SetInterfaceDnsSettings) } fn flush_dns_cache() -> Result<(), Error> { diff --git a/nym-vpn-core/crates/nym-dns/src/windows/netsh.rs b/nym-vpn-core/crates/nym-dns/src/windows/netsh.rs index 4cf2e00a76..5d12e2db16 100644 --- a/nym-vpn-core/crates/nym-dns/src/windows/netsh.rs +++ b/nym-vpn-core/crates/nym-dns/src/windows/netsh.rs @@ -14,8 +14,8 @@ use std::{ process::{Child, Command, ExitStatus, Stdio}, time::Duration, }; -use windows_sys::Win32::{ - Foundation::{MAX_PATH, WAIT_OBJECT_0, WAIT_TIMEOUT}, +use windows::Win32::{ + Foundation::{HANDLE, MAX_PATH, WAIT_OBJECT_0, WAIT_TIMEOUT}, System::{ SystemInformation::GetSystemDirectoryW, Threading::{WaitForSingleObject, INFINITE}, @@ -41,7 +41,7 @@ pub enum Error { /// Failure to spawn netsh subprocess. #[error("Failed to obtain system directory")] - GetSystemDir(#[source] io::Error), + GetSystemDir(#[source] windows::core::Error), /// Failure to write to stdin. #[error("Failed to write to stdin for 'netsh'")] @@ -173,8 +173,8 @@ fn run_netsh_with_timeout(netsh_input: String, timeout: Duration) -> Result<(), fn wait_for_child(subproc: &mut Child, timeout: Duration) -> io::Result> { let dur_millis = u32::try_from(timeout.as_millis()).unwrap_or(INFINITE); - let subproc_handle = subproc.as_raw_handle(); - match unsafe { WaitForSingleObject(subproc_handle as isize, dur_millis) } { + let subproc_handle = HANDLE(subproc.as_raw_handle()); + match unsafe { WaitForSingleObject(subproc_handle, dur_millis) } { WAIT_OBJECT_0 => subproc.try_wait(), WAIT_TIMEOUT => Ok(None), _error => Err(io::Error::last_os_error()), @@ -210,15 +210,16 @@ fn create_netsh_flush_command(interface_index: u32, ip_version: IpVersion) -> St format!("interface {interface_type} set dnsservers name={interface_index} source=static address=none validate=no\r\n") } -fn get_system_dir() -> io::Result { - let mut sysdir = [0u16; MAX_PATH as usize + 1]; - let len = unsafe { GetSystemDirectoryW(sysdir.as_mut_ptr(), (sysdir.len() - 1) as u32) }; +fn get_system_dir() -> windows::core::Result { + let mut sysdir = [0u16; MAX_PATH as usize]; + let len = unsafe { GetSystemDirectoryW(Some(&mut sysdir)) }; if len == 0 { - return Err(io::Error::last_os_error()); + Err(windows::core::Error::from_win32()) + } else { + Ok(PathBuf::from(OsString::from_wide( + &sysdir[0..(len as usize)], + ))) } - Ok(PathBuf::from(OsString::from_wide( - &sysdir[0..(len as usize)], - ))) } /// IP protocol version. diff --git a/nym-vpn-core/crates/nym-dns/src/windows/tcpip.rs b/nym-vpn-core/crates/nym-dns/src/windows/tcpip.rs index b6b00137d1..3c9820c084 100644 --- a/nym-vpn-core/crates/nym-dns/src/windows/tcpip.rs +++ b/nym-vpn-core/crates/nym-dns/src/windows/tcpip.rs @@ -6,7 +6,7 @@ use crate::{DnsMonitorT, ResolvedDnsConfig}; use nym_common::ErrorExt; use nym_windows::net::{guid_from_luid, luid_from_alias}; use std::{io, net::IpAddr}; -use windows_sys::{core::GUID, Win32::System::Com::StringFromGUID2}; +use windows::{core::GUID, Win32::System::Com::StringFromGUID2}; use winreg::{ enums::{HKEY_LOCAL_MACHINE, KEY_SET_VALUE}, transaction::Transaction, @@ -168,8 +168,7 @@ fn flush_dns_cache() -> Result<(), Error> { /// Obtain a string representation for a GUID object. fn string_from_guid(guid: &GUID) -> String { let mut buffer = [0u16; 40]; - let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) } - as usize; + let length = unsafe { StringFromGUID2(guid, &mut buffer) } as usize; // cannot fail because `buffer` is large enough assert!(length > 0); let length = length - 1; diff --git a/nym-vpn-core/crates/nym-routing/Cargo.toml b/nym-vpn-core/crates/nym-routing/Cargo.toml index 54f09d58ba..cd459ef386 100644 --- a/nym-vpn-core/crates/nym-routing/Cargo.toml +++ b/nym-vpn-core/crates/nym-routing/Cargo.toml @@ -39,7 +39,7 @@ system-configuration.workspace = true nym-windows = { path = "../nym-windows" } widestring.workspace = true -[target.'cfg(windows)'.dependencies.windows-sys] +[target.'cfg(windows)'.dependencies.windows] workspace = true features = ["Win32_NetworkManagement_Ndis", "Win32_Globalization"] diff --git a/nym-vpn-core/crates/nym-routing/src/windows/default_route_monitor.rs b/nym-vpn-core/crates/nym-routing/src/windows/default_route_monitor.rs index 916f163aaf..000a070360 100644 --- a/nym-vpn-core/crates/nym-routing/src/windows/default_route_monitor.rs +++ b/nym-vpn-core/crates/nym-routing/src/windows/default_route_monitor.rs @@ -8,14 +8,13 @@ use super::{ }; use crate::debounce::BurstGuard; -use nym_common::win32_err; use std::{ ffi::c_void, sync::{Arc, Mutex}, time::Duration, }; -use windows_sys::Win32::{ - Foundation::{BOOLEAN, HANDLE}, +use windows::Win32::{ + Foundation::HANDLE, NetworkManagement::{ IpHelper::{ CancelMibChangeNotify2, ConvertInterfaceLuidToIndex, NotifyIpInterfaceChange, @@ -24,12 +23,11 @@ use windows_sys::Win32::{ }, Ndis::NET_LUID_LH, }, + Networking::WinSock::ADDRESS_FAMILY, }; use nym_windows::net::AddressFamily; -const WIN_FALSE: BOOLEAN = 0; - struct DefaultRouteMonitorContext { callback: Box Fn(EventType<'a>) + Send + 'static>, refresh_current_route: bool, @@ -67,9 +65,9 @@ impl DefaultRouteMonitorContext { let mut default_interface_index = 0; let route_luid = best_route.iface; // SAFETY: No clear safety specifications - match win32_err!(unsafe { - ConvertInterfaceLuidToIndex(&route_luid, &mut default_interface_index) - }) { + match unsafe { ConvertInterfaceLuidToIndex(&route_luid, &mut default_interface_index) } + .ok() + { Ok(()) => self.refresh_current_route = index == default_interface_index, Err(_) => self.refresh_current_route = true, } @@ -142,7 +140,7 @@ impl Drop for NotifyChangeHandle { // SAFETY: There is no clear safety specification on this function. However self.0 should // point to a handle that has been allocated by windows and should be non-null. Even // if it would be null that would cause a panic rather than UB. - if let Err(e) = win32_err!(unsafe { CancelMibChangeNotify2(self.0) }) { + if let Err(e) = unsafe { CancelMibChangeNotify2(self.0) }.ok() { // If this callback is called after we free the context that could result in UB, in // order to avoid that we panic. panic!("Could not cancel change notification callback: {}", e) @@ -244,48 +242,51 @@ impl DefaultRouteMonitor { // we cancel the callbacks. This will leak the weak pointer but the context state itself // will be correctly dropped when DefaultRouteManager is dropped. let context_ptr = context_and_burst; - let mut handle_ptr = 0; + let mut handle_ptr = HANDLE::default(); // SAFETY: No clear safety specifications, context_ptr must be valid for as long as handle // has not been dropped. - win32_err!(unsafe { + unsafe { NotifyRouteChange2( - family, + ADDRESS_FAMILY(family), Some(route_change_callback), context_ptr as *const _, - WIN_FALSE, + false, &mut handle_ptr, ) - }) + } + .ok() .map_err(Error::RegisterNotifyRouteCallback)?; let notify_route_change_handle = NotifyChangeHandle(handle_ptr); - let mut handle_ptr = 0; + let mut handle_ptr = HANDLE::default(); // SAFETY: No clear safety specifications, context_ptr must be valid for as long as handle // has not been dropped. - win32_err!(unsafe { + unsafe { NotifyIpInterfaceChange( - family, + ADDRESS_FAMILY(family), Some(interface_change_callback), - context_ptr as *const _, - WIN_FALSE, + Some(context_ptr as *const _), + false, &mut handle_ptr, ) - }) + } + .ok() .map_err(Error::RegisterNotifyIpInterfaceCallback)?; let notify_interface_change_handle = NotifyChangeHandle(handle_ptr); - let mut handle_ptr = 0; + let mut handle_ptr = HANDLE::default(); // SAFETY: No clear safety specifications, context_ptr must be valid for as long as handle // has not been dropped. - win32_err!(unsafe { + unsafe { NotifyUnicastIpAddressChange( - family, + ADDRESS_FAMILY(family), Some(ip_address_change_callback), - context_ptr as *const _, - WIN_FALSE, + Some(context_ptr as *const _), + false, &mut handle_ptr, ) - }) + } + .ok() .map_err(Error::RegisterNotifyUnicastIpAddressCallback)?; let notify_address_change_handle = NotifyChangeHandle(handle_ptr); diff --git a/nym-vpn-core/crates/nym-routing/src/windows/get_best_default_route.rs b/nym-vpn-core/crates/nym-routing/src/windows/get_best_default_route.rs index 5b21ca328c..ee95507fff 100644 --- a/nym-vpn-core/crates/nym-routing/src/windows/get_best_default_route.rs +++ b/nym-vpn-core/crates/nym-routing/src/windows/get_best_default_route.rs @@ -3,16 +3,18 @@ // SPDX-License-Identifier: GPL-3.0-only use super::{Error, Result}; -use nym_common::win32_err; use nym_windows::net::{get_ip_interface_entry, try_socketaddr_from_inet_sockaddr, AddressFamily}; use std::{net::SocketAddr, slice}; use widestring::{widecstr, WideCStr}; -use windows_sys::Win32::NetworkManagement::{ - IpHelper::{ - FreeMibTable, GetIfEntry2, GetIpForwardTable2, IF_TYPE_SOFTWARE_LOOPBACK, IF_TYPE_TUNNEL, - MIB_IF_ROW2, MIB_IPFORWARD_ROW2, +use windows::Win32::{ + NetworkManagement::{ + IpHelper::{ + FreeMibTable, GetIfEntry2, GetIpForwardTable2, IF_TYPE_SOFTWARE_LOOPBACK, + IF_TYPE_TUNNEL, MIB_IF_ROW2, MIB_IPFORWARD_ROW2, + }, + Ndis::NET_LUID_LH, }, - Ndis::NET_LUID_LH, + Networking::WinSock::ADDRESS_FAMILY, }; // Interface description substrings found for virtual adapters. @@ -28,7 +30,8 @@ fn get_ip_forward_table(family: AddressFamily) -> Result // SAFETY: GetIpForwardTable2 does not have clear safety specifications however what it does is // heap allocate a IpForwardTable2 and then change table_ptr to point to that allocation. - win32_err!(unsafe { GetIpForwardTable2(family, &mut table_ptr) }) + unsafe { GetIpForwardTable2(ADDRESS_FAMILY(family), &mut table_ptr) } + .ok() .map_err(Error::GetIpForwardTableFailed)?; // SAFETY: table_ptr is valid since GetIpForwardTable2 did not return an error @@ -129,7 +132,9 @@ fn is_route_on_physical_interface(route: &MIB_IPFORWARD_ROW2) -> Result { // SAFETY: GetIfEntry2 does not have clear safety rules however it will read the // row.InterfaceLuid or row.InterfaceIndex and use that information to populate the struct. // We guarantee here that these fields are valid since they are set. - win32_err!(unsafe { GetIfEntry2(&mut row) }).map_err(Error::GetIfEntryFailed)?; + unsafe { GetIfEntry2(&mut row) } + .ok() + .map_err(Error::GetIfEntryFailed)?; let row_description = WideCStr::from_slice_truncate(&row.Description) .expect("Windows provided incorrectly formatted utf16 string"); @@ -157,18 +162,18 @@ struct AnnotatedRoute<'a> { fn annotate_route(route: &MIB_IPFORWARD_ROW2) -> Option> { // SAFETY: `si_family` is valid in both `Ipv4` and `Ipv6` so we can safely access `si_family`. let iface = get_ip_interface_entry( - AddressFamily::try_from_af_family(unsafe { route.DestinationPrefix.Prefix.si_family }) + AddressFamily::try_from_af_family(unsafe { route.DestinationPrefix.Prefix.si_family.0 }) .ok()?, &route.InterfaceLuid, ) .ok()?; - if iface.Connected == 0 { - None - } else { + if iface.Connected { Some(AnnotatedRoute { route, effective_metric: route.Metric + iface.Metric, }) + } else { + None } } diff --git a/nym-vpn-core/crates/nym-routing/src/windows/mod.rs b/nym-vpn-core/crates/nym-routing/src/windows/mod.rs index 69cb085eb5..d40f74aa1a 100644 --- a/nym-vpn-core/crates/nym-routing/src/windows/mod.rs +++ b/nym-vpn-core/crates/nym-routing/src/windows/mod.rs @@ -33,25 +33,25 @@ pub enum Error { RouteManagerDown, /// Low level error caused by a failure to add to route table #[error("Could not add route to route table")] - AddToRouteTable(io::Error), + AddToRouteTable(#[source] windows::core::Error), /// Low level error caused by failure to delete route from route table #[error("Failed to delete applied routes")] - DeleteFromRouteTable(io::Error), + DeleteFromRouteTable(#[source] windows::core::Error), /// GetIpForwardTable2 windows API call failed #[error("Failed to retrieve the routing table")] - GetIpForwardTableFailed(io::Error), + GetIpForwardTableFailed(#[source] windows::core::Error), /// GetIfEntry2 windows API call failed #[error("Failed to retrieve network interface entry")] - GetIfEntryFailed(io::Error), + GetIfEntryFailed(#[source] windows::core::Error), /// Low level error caused by failing to register the route callback #[error("Attempt to register notify route change callback failed")] - RegisterNotifyRouteCallback(io::Error), + RegisterNotifyRouteCallback(#[source] windows::core::Error), /// Low level error caused by failing to register the ip interface callback #[error("Attempt to register notify ip interface change callback failed")] - RegisterNotifyIpInterfaceCallback(io::Error), + RegisterNotifyIpInterfaceCallback(#[source] windows::core::Error), /// Low level error caused by failing to register the unicast ip address callback #[error("Attempt to register notify unicast ip address change callback failed")] - RegisterNotifyUnicastIpAddressCallback(io::Error), + RegisterNotifyUnicastIpAddressCallback(#[source] windows::core::Error), /// Low level error caused by windows Adapters API #[error("Windows adapter error")] Adapter(io::Error), diff --git a/nym-vpn-core/crates/nym-routing/src/windows/route_manager.rs b/nym-vpn-core/crates/nym-routing/src/windows/route_manager.rs index c8752272f3..899cbaf478 100644 --- a/nym-vpn-core/crates/nym-routing/src/windows/route_manager.rs +++ b/nym-vpn-core/crates/nym-routing/src/windows/route_manager.rs @@ -8,10 +8,7 @@ use super::{ }; use crate::NetNode; use ipnetwork::IpNetwork; -use nym_common::win32_err; -use nym_windows::net::{ - inet_sockaddr_from_socketaddr, try_socketaddr_from_inet_sockaddr, AddressFamily, -}; +use nym_windows::net::{try_socketaddr_from_inet_sockaddr, AddressFamily}; use std::{ collections::HashMap, io, @@ -19,25 +16,28 @@ use std::{ sync::{Arc, Mutex}, }; use widestring::{WideCStr, WideCString}; -use windows_sys::Win32::{ - Foundation::{ - ERROR_BUFFER_OVERFLOW, ERROR_NOT_FOUND, ERROR_NO_DATA, ERROR_OBJECT_ALREADY_EXISTS, - ERROR_SUCCESS, - }, - NetworkManagement::{ - IpHelper::{ - ConvertInterfaceAliasToLuid, CreateIpForwardEntry2, DeleteIpForwardEntry2, - GetAdaptersAddresses, InitializeIpForwardEntry, SetIpForwardEntry2, - GAA_FLAG_INCLUDE_GATEWAYS, GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_DNS_SERVER, - GAA_FLAG_SKIP_FRIENDLY_NAME, GAA_FLAG_SKIP_MULTICAST, GET_ADAPTERS_ADDRESSES_FLAGS, - IP_ADAPTER_ADDRESSES_LH, IP_ADAPTER_GATEWAY_ADDRESS_LH, IP_ADAPTER_IPV4_ENABLED, - IP_ADAPTER_IPV6_ENABLED, IP_ADDRESS_PREFIX, MIB_IPFORWARD_ROW2, +use windows::{ + core::HSTRING, + Win32::{ + Foundation::{ + ERROR_BUFFER_OVERFLOW, ERROR_NOT_FOUND, ERROR_NO_DATA, ERROR_OBJECT_ALREADY_EXISTS, + ERROR_SUCCESS, + }, + NetworkManagement::{ + IpHelper::{ + ConvertInterfaceAliasToLuid, CreateIpForwardEntry2, DeleteIpForwardEntry2, + GetAdaptersAddresses, InitializeIpForwardEntry, SetIpForwardEntry2, + GAA_FLAG_INCLUDE_GATEWAYS, GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_DNS_SERVER, + GAA_FLAG_SKIP_FRIENDLY_NAME, GAA_FLAG_SKIP_MULTICAST, GET_ADAPTERS_ADDRESSES_FLAGS, + IP_ADAPTER_ADDRESSES_LH, IP_ADAPTER_GATEWAY_ADDRESS_LH, IP_ADAPTER_IPV4_ENABLED, + IP_ADAPTER_IPV6_ENABLED, IP_ADDRESS_PREFIX, MIB_IPFORWARD_ROW2, + }, + Ndis::NET_LUID_LH, + }, + Networking::WinSock::{ + NlroManual, ADDRESS_FAMILY, AF_INET, AF_INET6, MIB_IPPROTO_NETMGMT, SOCKADDR_IN, + SOCKADDR_IN6, SOCKADDR_INET, SOCKET_ADDRESS, }, - Ndis::NET_LUID_LH, - }, - Networking::WinSock::{ - NlroManual, ADDRESS_FAMILY, AF_INET, AF_INET6, MIB_IPPROTO_NETMGMT, SOCKADDR_IN, - SOCKADDR_IN6, SOCKADDR_INET, SOCKET_ADDRESS, }, }; @@ -195,7 +195,7 @@ impl RouteManagerInternal { spec.InterfaceLuid = node.iface; spec.DestinationPrefix = win_ip_address_prefix_from_ipnetwork_port_zero(route.network); - spec.NextHop = inet_sockaddr_from_socketaddr(node.gateway); + spec.NextHop = SOCKADDR_INET::from(node.gateway); spec.Metric = 0; spec.Protocol = MIB_IPPROTO_NETMGMT; spec.Origin = NlroManual; @@ -221,7 +221,7 @@ impl RouteManagerInternal { status = unsafe { SetIpForwardEntry2(&spec) }; } - win32_err!(status).map_err(|e| { + status.ok().map_err(|e| { tracing::error!("Could not register route in routing table"); Error::AddToRouteTable(e) })?; @@ -255,15 +255,18 @@ impl RouteManagerInternal { } NetNode::RealNode(node) => { if let Some(device_name) = &node.get_device() { - let device_name = WideCString::from_str(device_name) + let device_name_ucstr = WideCString::from_str(device_name) .expect("Failed to convert UTF-8 string to null terminated UCS string"); - let luid = match Self::parse_string_encoded_luid(device_name.as_ucstr())? { + let luid = match Self::parse_string_encoded_luid(device_name_ucstr.as_ucstr())? + { None => { let mut luid = NET_LUID_LH { Value: 0 }; // SAFETY: No specific safety requirement - if let Err(e) = win32_err!(unsafe { - ConvertInterfaceAliasToLuid(device_name.as_ptr(), &mut luid) - }) { + if let Err(e) = unsafe { + ConvertInterfaceAliasToLuid(&HSTRING::from(*device_name), &mut luid) + } + .ok() + { tracing::error!("Unable to get interface LUID for interface \"{device_name:?}\": {e}"); return Err(Error::DeviceNameNotFound); } else { @@ -294,7 +297,13 @@ impl RouteManagerInternal { // Unwrapping is fine because the node must have an address since no device name was // found. - let gateway = node.get_address().map(inet_sockaddr_from_ipaddr).unwrap(); + let gateway = node + .get_address() + .map(|addr| { + // Port should not matter so we set it to 0 + SOCKADDR_INET::from(SocketAddr::new(addr, 0)) + }) + .unwrap(); Ok(InterfaceAndGateway { iface: interface_luid_from_gateway(&gateway)?, gateway: try_socketaddr_from_inet_sockaddr(gateway) @@ -343,14 +352,14 @@ impl RouteManagerInternal { r.InterfaceLuid = route.luid; r.DestinationPrefix = win_ip_address_prefix_from_ipnetwork_port_zero(route.network); - r.NextHop = inet_sockaddr_from_socketaddr(route.next_hop); + r.NextHop = SOCKADDR_INET::from(route.next_hop); // SAFETY: DestinationPrefix must be initialized to a valid prefix. NextHop must have // a valid IP address and family. At least one of InterfaceLuid and InterfaceIndex must be // set to the interface. - match win32_err!(unsafe { DeleteIpForwardEntry2(&r) }) { + match unsafe { DeleteIpForwardEntry2(&r) }.ok() { Ok(()) => Ok(()), - Err(e) if e.raw_os_error() == Some(ERROR_NOT_FOUND as i32) => { + Err(e) if e.code() == ERROR_NOT_FOUND.to_hresult() => { tracing::warn!("Attempting to delete route which was not present in routing table, ignoring and proceeding. Route: {route}"); Ok(()) } @@ -374,7 +383,7 @@ impl RouteManagerInternal { spec.InterfaceLuid = route.luid; spec.DestinationPrefix = win_ip_address_prefix_from_ipnetwork_port_zero(route.network); - spec.NextHop = inet_sockaddr_from_socketaddr(route.next_hop); + spec.NextHop = SOCKADDR_INET::from(route.next_hop); spec.Metric = 0; spec.Protocol = MIB_IPPROTO_NETMGMT; spec.Origin = NlroManual; @@ -382,7 +391,7 @@ impl RouteManagerInternal { // SAFETY: DestinationPrefix must be initialized to a valid prefix. NextHop must have a // valid IP address and family. At least one of InterfaceLuid and InterfaceIndex must be set // to the interface. - win32_err!(unsafe { CreateIpForwardEntry2(&spec) }).map_err(|e| { + unsafe { CreateIpForwardEntry2(&spec) }.ok().map_err(|e| { tracing::error!("Could not register route in routing table. Route: {route}"); Error::AddToRouteTable(e) })?; @@ -461,7 +470,7 @@ impl RouteManagerInternal { { let (_, callbacks) = &mut *callbacks.lock().unwrap(); for callback in callbacks.values() { - let family = AddressFamily::try_from_af_family(family).unwrap(); + let family = AddressFamily::try_from_af_family(family.0).unwrap(); callback(event_type, family); } } @@ -483,7 +492,10 @@ impl RouteManagerInternal { for record in (*records).iter_mut() { if matches!(record.route.node, NetNode::DefaultNode) - && family == ipnetwork_to_address_family(record.route.network).to_af_family() + && family + == ADDRESS_FAMILY( + ipnetwork_to_address_family(record.route.network).to_af_family(), + ) { affected_routes.push(record); } @@ -540,7 +552,7 @@ impl Drop for RouteManagerInternal { } fn interface_luid_from_gateway(gateway: &SOCKADDR_INET) -> Result { - const ADAPTER_FLAGS: GET_ADAPTERS_ADDRESSES_FLAGS = GAA_FLAG_SKIP_ANYCAST + let adapter_flags: GET_ADAPTERS_ADDRESSES_FLAGS = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME @@ -548,7 +560,7 @@ fn interface_luid_from_gateway(gateway: &SOCKADDR_INET) -> Result { // SAFETY: The si_family field is always valid to access. let family = unsafe { gateway.si_family }; - let adapters = Adapters::new(family, ADAPTER_FLAGS)?; + let adapters = Adapters::new(family, adapter_flags)?; // Process adapters to find matching ones. // @@ -712,15 +724,15 @@ impl Adapters { // called again. let status = unsafe { GetAdaptersAddresses( - u32::from(family), + u32::from(family.0), flags, - std::ptr::null_mut(), - buffer_pointer as *mut IP_ADAPTER_ADDRESSES_LH, + None, + Some(buffer_pointer as *mut IP_ADAPTER_ADDRESSES_LH), &mut buffer_size, ) }; - if ERROR_SUCCESS == status { + if ERROR_SUCCESS.0 == status { // SAFETY: We truncate the buffer to avoid having a bunch of zero:ed objects at the // end of it truncate will not change capacity and will therefore // never reallocate the vector which means it can not cause the @@ -729,11 +741,11 @@ impl Adapters { break; } - if ERROR_NO_DATA == status { + if ERROR_NO_DATA.0 == status { return Ok(Self { buffer: Vec::new() }); } - if ERROR_BUFFER_OVERFLOW != status { + if ERROR_BUFFER_OVERFLOW.0 != status { tracing::error!("Probe required buffer size for GetAdaptersAddresses"); return Err(Error::Adapter(io::Error::from_raw_os_error( i32::try_from(status).unwrap(), @@ -825,20 +837,13 @@ impl<'a> Iterator for AdaptersIterator<'a> { /// to 0 pub fn win_ip_address_prefix_from_ipnetwork_port_zero(from: IpNetwork) -> IP_ADDRESS_PREFIX { // Port should not matter so we set it to 0 - let prefix = - nym_windows::net::inet_sockaddr_from_socketaddr(std::net::SocketAddr::new(from.ip(), 0)); + let prefix = SOCKADDR_INET::from(std::net::SocketAddr::new(from.ip(), 0)); IP_ADDRESS_PREFIX { Prefix: prefix, PrefixLength: from.prefix(), } } -/// Convert to a windows defined `SOCKADDR_INET` from a `IpAddr` but set the port to 0 -pub fn inet_sockaddr_from_ipaddr(from: IpAddr) -> SOCKADDR_INET { - // Port should not matter so we set it to 0 - nym_windows::net::inet_sockaddr_from_socketaddr(std::net::SocketAddr::new(from, 0)) -} - /// Convert to a `AddressFamily` from a `ipnetwork::IpNetwork` pub fn ipnetwork_to_address_family(from: IpNetwork) -> AddressFamily { if from.is_ipv4() { diff --git a/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml b/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml index 2c324e2a2c..a5f28a123f 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml +++ b/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml @@ -86,7 +86,7 @@ nym-vpn-lib-types = { path = "../nym-vpn-lib-types" } nix = { workspace = true, features = ["socket", "net", "fs"] } [target.'cfg(windows)'.dependencies] -windows-sys = { workspace = true, features = ["Win32_NetworkManagement_Ndis"] } +windows = { workspace = true, features = ["Win32_NetworkManagement_Ndis"] } nym-windows = { path = "../nym-windows" } nym-routing = { path = "../nym-routing" } nym-dns = { path = "../nym-dns" } diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/wintun.rs b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/wintun.rs index 889661ba7a..7d00da0276 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/wintun.rs +++ b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/wintun.rs @@ -1,7 +1,7 @@ use nym_windows::net as wnet; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use windows_sys::Win32::NetworkManagement::Ndis::NET_LUID_LH; +use windows::Win32::NetworkManagement::Ndis::NET_LUID_LH; /// Wintun adapter configuration error. #[derive(Debug, thiserror::Error)] diff --git a/nym-vpn-core/crates/nym-vpnd/Cargo.toml b/nym-vpn-core/crates/nym-vpnd/Cargo.toml index 14e2d61b16..a7876bbc63 100644 --- a/nym-vpn-core/crates/nym-vpnd/Cargo.toml +++ b/nym-vpn-core/crates/nym-vpnd/Cargo.toml @@ -67,7 +67,7 @@ windows-service.workspace = true eventlog.workspace = true winapi = { version = "0.3", features = ["winnt", "excpt", "winerror"] } -[target.'cfg(windows)'.dependencies.windows-sys] +[target.'cfg(windows)'.dependencies.windows] workspace = true features = [ "Win32_Foundation", diff --git a/nym-vpn-core/crates/nym-vpnd/src/windows_service/install.rs b/nym-vpn-core/crates/nym-vpnd/src/windows_service/install.rs index 3569d31e67..302baf3a92 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/windows_service/install.rs +++ b/nym-vpn-core/crates/nym-vpnd/src/windows_service/install.rs @@ -6,11 +6,11 @@ use std::{ time::{Duration, Instant}, }; +use windows::Win32::Foundation::ERROR_SERVICE_DOES_NOT_EXIST; use windows_service::{ service::{ServiceAccess, ServiceState}, service_manager::{ServiceManager, ServiceManagerAccess}, }; -use windows_sys::Win32::Foundation::ERROR_SERVICE_DOES_NOT_EXIST; use super::{service::get_service_info, SERVICE_DESCRIPTION, SERVICE_DISPLAY_NAME, SERVICE_NAME}; @@ -65,7 +65,7 @@ pub(super) fn uninstall_service() -> windows_service::Result<()> { if let Err(windows_service::Error::Winapi(e)) = service_manager.open_service(SERVICE_NAME, ServiceAccess::QUERY_STATUS) { - if e.raw_os_error() == Some(ERROR_SERVICE_DOES_NOT_EXIST as i32) { + if e.raw_os_error() == Some(ERROR_SERVICE_DOES_NOT_EXIST.0 as i32) { println!("{} is deleted.", SERVICE_NAME); return Ok(()); } diff --git a/nym-vpn-core/crates/nym-wg-go/Cargo.toml b/nym-vpn-core/crates/nym-wg-go/Cargo.toml index bdc52f1d6d..d0d84f2f9d 100644 --- a/nym-vpn-core/crates/nym-wg-go/Cargo.toml +++ b/nym-vpn-core/crates/nym-wg-go/Cargo.toml @@ -23,5 +23,5 @@ zeroize.workspace = true rand.workspace = true [target.'cfg(windows)'.dependencies] -windows-sys = { workspace = true, features = ["Win32_NetworkManagement_Ndis"] } +windows = { workspace = true, features = ["Win32_NetworkManagement_Ndis"] } nym-windows = { path = "../nym-windows" } diff --git a/nym-vpn-core/crates/nym-wg-go/src/wireguard_go.rs b/nym-vpn-core/crates/nym-wg-go/src/wireguard_go.rs index a300665b77..30ad1bc319 100644 --- a/nym-vpn-core/crates/nym-wg-go/src/wireguard_go.rs +++ b/nym-vpn-core/crates/nym-wg-go/src/wireguard_go.rs @@ -11,7 +11,7 @@ use std::{ #[cfg(windows)] use nym_windows::net::AddressFamily; #[cfg(windows)] -use windows_sys::Win32::NetworkManagement::Ndis::NET_LUID_LH; +use windows::Win32::NetworkManagement::Ndis::NET_LUID_LH; use super::{ uapi::UapiConfigBuilder, Error, LoggingCallback, PeerConfig, PeerEndpointUpdate, PrivateKey, diff --git a/nym-vpn-core/crates/nym-windows/Cargo.toml b/nym-vpn-core/crates/nym-windows/Cargo.toml index 6ca4b1adf5..eb6f9621fe 100644 --- a/nym-vpn-core/crates/nym-windows/Cargo.toml +++ b/nym-vpn-core/crates/nym-windows/Cargo.toml @@ -8,14 +8,13 @@ version.workspace = true [target.'cfg(windows)'.dependencies] thiserror.workspace = true -socket2.workspace = true futures.workspace = true -tokio.workspace = true +tokio = { workspace = true, features = ["sync"] } tracing.workspace = true nym-common = { path = "../nym-common" } -[target.'cfg(windows)'.dependencies.windows-sys] +[target.'cfg(windows)'.dependencies.windows] workspace = true features = [ "Win32_Foundation", diff --git a/nym-vpn-core/crates/nym-windows/src/io.rs b/nym-vpn-core/crates/nym-windows/src/io.rs index 48ab66d871..a804a04376 100644 --- a/nym-vpn-core/crates/nym-windows/src/io.rs +++ b/nym-vpn-core/crates/nym-windows/src/io.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-only use std::{io, mem}; -use windows_sys::Win32::System::IO::OVERLAPPED; +use windows::Win32::{Foundation::HANDLE, System::IO::OVERLAPPED}; use crate::sync::Event; @@ -45,7 +45,7 @@ impl Overlapped { self.event = Some(event); } None => { - self.overlapped.hEvent = 0; + self.overlapped.hEvent = HANDLE::default(); self.event = None; } } diff --git a/nym-vpn-core/crates/nym-windows/src/net.rs b/nym-vpn-core/crates/nym-windows/src/net.rs index 49ecb897cb..4940f97439 100644 --- a/nym-vpn-core/crates/nym-windows/src/net.rs +++ b/nym-vpn-core/crates/nym-windows/src/net.rs @@ -2,19 +2,18 @@ // Copyright 2024 Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use nym_common::win32_err; -use socket2::SockAddr; use std::{ ffi::{OsStr, OsString}, fmt, io, mem::{self, MaybeUninit}, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, - os::windows::ffi::{OsStrExt, OsStringExt}, + os::windows::ffi::OsStringExt, sync::Mutex, time::{Duration, Instant}, }; -use windows_sys::{ - core::GUID, + +use windows::{ + core::{GUID, HSTRING}, Win32::{ Foundation::{ERROR_NOT_FOUND, HANDLE}, NetworkManagement::{ @@ -24,16 +23,15 @@ use windows_sys::{ CreateUnicastIpAddressEntry, FreeMibTable, GetIpInterfaceEntry, GetUnicastIpAddressEntry, GetUnicastIpAddressTable, InitializeIpForwardEntry, InitializeUnicastIpAddressEntry, MibAddInstance, NotifyIpInterfaceChange, - SetIpInterfaceEntry, MIB_IPINTERFACE_ROW, MIB_UNICASTIPADDRESS_ROW, - MIB_UNICASTIPADDRESS_TABLE, + SetIpInterfaceEntry, MIB_IPINTERFACE_ROW, MIB_NOTIFICATION_TYPE, + MIB_UNICASTIPADDRESS_ROW, MIB_UNICASTIPADDRESS_TABLE, }, Ndis::{IF_MAX_STRING_SIZE, NET_LUID_LH}, }, Networking::WinSock::{ IpDadStateDeprecated, IpDadStateDuplicate, IpDadStateInvalid, IpDadStatePreferred, - IpDadStateTentative, NlroManual, AF_INET, AF_INET6, AF_UNSPEC, IN6_ADDR, IN_ADDR, - MIB_IPPROTO_NT_STATIC, NL_DAD_STATE, SOCKADDR_IN as sockaddr_in, - SOCKADDR_IN6 as sockaddr_in6, SOCKADDR_INET, SOCKADDR_STORAGE as sockaddr_storage, + IpDadStateTentative, NlroManual, ADDRESS_FAMILY, AF_INET, AF_INET6, AF_UNSPEC, + IN6_ADDR, IN_ADDR, MIB_IPPROTO_NT_STATIC, NL_DAD_STATE, SOCKADDR_INET, }, }, }; @@ -55,7 +53,7 @@ pub enum Error { /// Error returned from `GetUnicastIpAddressTable`/`GetUnicastIpAddressEntry` #[cfg(windows)] #[error("Failed to obtain unicast IP address table")] - ObtainUnicastAddress(#[source] io::Error), + ObtainUnicastAddress(#[source] windows::core::Error), /// `GetUnicastIpAddressTable` contained no addresses for the interface #[cfg(windows)] @@ -65,12 +63,12 @@ pub enum Error { /// Error returned from `CreateUnicastIpAddressEntry` #[cfg(windows)] #[error("Failed to create unicast IP address")] - CreateUnicastEntry(#[source] io::Error), + CreateUnicastEntry(#[source] windows::core::Error), /// Error returned from `CreateIpForwardEntry2` #[cfg(windows)] #[error("Failed to create IP forwarding entry")] - CreateForwardEntry(#[source] io::Error), + CreateForwardEntry(#[source] windows::core::Error), /// Unexpected DAD state returned for a unicast address #[cfg(windows)] @@ -119,7 +117,7 @@ impl From for DadStateError { IpDadStateInvalid => DadStateError::Invalid, IpDadStateDuplicate => DadStateError::Duplicate, IpDadStateDeprecated => DadStateError::Deprecated, - other => DadStateError::Unknown(other), + other => DadStateError::Unknown(other.0), } } } @@ -127,10 +125,10 @@ impl From for DadStateError { impl AddressFamily { /// Convert one of the `AF_*` constants to an [`AddressFamily`]. pub fn try_from_af_family(family: u16) -> Result { - match family { + match ADDRESS_FAMILY(family) { AF_INET => Ok(AddressFamily::Ipv4), AF_INET6 => Ok(AddressFamily::Ipv6), - family => Err(Error::UnknownAddressFamily(family)), + family => Err(Error::UnknownAddressFamily(family.0)), } } @@ -140,6 +138,7 @@ impl AddressFamily { Self::Ipv4 => AF_INET, Self::Ipv6 => AF_INET6, } + .0 } } @@ -147,7 +146,7 @@ impl AddressFamily { /// the callback is unregistered. pub struct IpNotifierHandle<'a> { #[allow(clippy::type_complexity)] - callback: Mutex>, + callback: Mutex>, handle: HANDLE, } @@ -155,14 +154,16 @@ unsafe impl Send for IpNotifierHandle<'_> {} impl Drop for IpNotifierHandle<'_> { fn drop(&mut self) { - unsafe { CancelMibChangeNotify2(self.handle) }; + if let Err(e) = unsafe { CancelMibChangeNotify2(self.handle) }.ok() { + tracing::error!("Failed to cancel ip notifier: {}", e); + } } } unsafe extern "system" fn inner_callback( context: *const std::ffi::c_void, row: *const MIB_IPINTERFACE_ROW, - notify_type: i32, + notify_type: MIB_NOTIFICATION_TYPE, ) { let context = &mut *(context as *mut IpNotifierHandle<'_>); context @@ -173,24 +174,29 @@ unsafe extern "system" fn inner_callback( /// Registers a callback function that is invoked when an interface is added, removed, /// or changed. -pub fn notify_ip_interface_change<'a, T: FnMut(&MIB_IPINTERFACE_ROW, i32) + Send + 'a>( +pub fn notify_ip_interface_change< + 'a, + T: FnMut(&MIB_IPINTERFACE_ROW, MIB_NOTIFICATION_TYPE) + Send + 'a, +>( callback: T, family: Option, -) -> io::Result>> { +) -> windows::core::Result>> { let mut context = Box::new(IpNotifierHandle { callback: Mutex::new(Box::new(callback)), - handle: 0, + handle: HANDLE::default(), }); - win32_err!(unsafe { + unsafe { NotifyIpInterfaceChange( af_family_from_family(family), Some(inner_callback), - &mut *context as *mut _ as *mut _, - 0, + Some(&*context as *const _ as *const _), + false, (&mut context.handle) as *mut _, ) - })?; + } + .ok()?; + Ok(context) } @@ -198,24 +204,28 @@ pub fn notify_ip_interface_change<'a, T: FnMut(&MIB_IPINTERFACE_ROW, i32) + Send pub fn get_ip_interface_entry( family: AddressFamily, luid: &NET_LUID_LH, -) -> io::Result { +) -> windows::core::Result { let mut row: MIB_IPINTERFACE_ROW = unsafe { mem::zeroed() }; - row.Family = family as u16; + row.Family = ADDRESS_FAMILY(family as u16); row.InterfaceLuid = *luid; - win32_err!(unsafe { GetIpInterfaceEntry(&mut row) })?; + unsafe { GetIpInterfaceEntry(&mut row) }.ok()?; + Ok(row) } /// Set the properties of an IP interface. -pub fn set_ip_interface_entry(row: &mut MIB_IPINTERFACE_ROW) -> io::Result<()> { - win32_err!(unsafe { SetIpInterfaceEntry(row as *mut _) }) +pub fn set_ip_interface_entry(row: &mut MIB_IPINTERFACE_ROW) -> windows::core::Result<()> { + unsafe { SetIpInterfaceEntry(row as *mut _) }.ok() } -fn ip_interface_entry_exists(family: AddressFamily, luid: &NET_LUID_LH) -> io::Result { +fn ip_interface_entry_exists( + family: AddressFamily, + luid: &NET_LUID_LH, +) -> windows::core::Result { match get_ip_interface_entry(family, luid) { Ok(_) => Ok(true), - Err(error) if error.raw_os_error() == Some(ERROR_NOT_FOUND as i32) => Ok(false), + Err(error) if error.code() == ERROR_NOT_FOUND.to_hresult() => Ok(false), Err(error) => Err(error), } } @@ -287,7 +297,8 @@ pub async fn wait_for_addresses(luid: NET_LUID_LH) -> Result<()> { let mut ready = true; for row in &mut unicast_rows { - win32_err!(unsafe { GetUnicastIpAddressEntry(row) }) + unsafe { GetUnicastIpAddressEntry(row) } + .ok() .map_err(Error::ObtainUnicastAddress)?; if row.DadState == IpDadStateTentative { ready = false; @@ -333,11 +344,13 @@ pub fn add_ip_address_for_interface(luid: NET_LUID_LH, address: IpAddr) -> Resul unsafe { InitializeUnicastIpAddressEntry(&mut row) }; row.InterfaceLuid = luid; - row.Address = inet_sockaddr_from_socketaddr(SocketAddr::new(address, 0)); + row.Address = SOCKADDR_INET::from(SocketAddr::new(address, 0)); row.DadState = IpDadStatePreferred; row.OnLinkPrefixLength = 255; - win32_err!(unsafe { CreateUnicastIpAddressEntry(&row) }).map_err(Error::CreateUnicastEntry) + unsafe { CreateUnicastIpAddressEntry(&row) } + .ok() + .map_err(Error::CreateUnicastEntry) } /// Add default IPv4 gateway for the given interface. @@ -350,13 +363,15 @@ pub fn add_default_ipv4_gateway_for_interface(luid: NET_LUID_LH, address: Ipv4Ad forward_row.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; forward_row.NextHop.si_family = AF_INET; forward_row.NextHop.Ipv4.sin_family = AF_INET; - forward_row.NextHop.Ipv4.sin_addr = inaddr_from_ipaddr(address); + forward_row.NextHop.Ipv4.sin_addr = IN_ADDR::from(address); forward_row.SitePrefixLength = 0; forward_row.Metric = 1; forward_row.Protocol = MIB_IPPROTO_NT_STATIC; forward_row.Origin = NlroManual; - win32_err!(unsafe { CreateIpForwardEntry2(&forward_row) }).map_err(Error::CreateForwardEntry) + unsafe { CreateIpForwardEntry2(&forward_row) } + .ok() + .map_err(Error::CreateForwardEntry) } /// Add default IPv6 gateway for the given interface. @@ -369,17 +384,19 @@ pub fn add_default_ipv6_gateway_for_interface(luid: NET_LUID_LH, address: Ipv6Ad forward_row.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; forward_row.NextHop.si_family = AF_INET6; forward_row.NextHop.Ipv6.sin6_family = AF_INET6; - forward_row.NextHop.Ipv6.sin6_addr = in6addr_from_ipaddr(address); + forward_row.NextHop.Ipv6.sin6_addr = IN6_ADDR::from(address); forward_row.SitePrefixLength = 0; forward_row.Metric = 1; forward_row.Protocol = MIB_IPPROTO_NT_STATIC; forward_row.Origin = NlroManual; - win32_err!(unsafe { CreateIpForwardEntry2(&forward_row) }).map_err(Error::CreateForwardEntry) + unsafe { CreateIpForwardEntry2(&forward_row) } + .ok() + .map_err(Error::CreateForwardEntry) } /// Sets MTU on the specified network interface identified by `luid`. -pub fn set_mtu(mtu: u32, luid: NET_LUID_LH, ip_family: AddressFamily) -> io::Result<()> { +pub fn set_mtu(mtu: u32, luid: NET_LUID_LH, ip_family: AddressFamily) -> windows::core::Result<()> { let mut row = get_ip_interface_entry(ip_family, &luid)?; row.NlMtu = mtu; @@ -391,13 +408,11 @@ pub fn set_mtu(mtu: u32, luid: NET_LUID_LH, ip_family: AddressFamily) -> io::Res /// returned. pub fn get_unicast_table( family: Option, -) -> io::Result> { +) -> windows::core::Result> { let mut unicast_rows = vec![]; let mut unicast_table: *mut MIB_UNICASTIPADDRESS_TABLE = std::ptr::null_mut(); - win32_err!(unsafe { - GetUnicastIpAddressTable(af_family_from_family(family), &mut unicast_table) - })?; + unsafe { GetUnicastIpAddressTable(af_family_from_family(family), &mut unicast_table) }.ok()?; let first_row = unsafe { &(*unicast_table).Table[0] } as *const MIB_UNICASTIPADDRESS_ROW; for i in 0..unsafe { *unicast_table }.NumEntries { unicast_rows.push(unsafe { *(first_row.offset(i as isize)) }); @@ -410,102 +425,70 @@ pub fn get_unicast_table( /// Returns the index of a network interface given its LUID. pub fn index_from_luid(luid: &NET_LUID_LH) -> io::Result { let mut index = 0u32; - win32_err!(unsafe { ConvertInterfaceLuidToIndex(luid, &mut index) })?; + unsafe { ConvertInterfaceLuidToIndex(luid, &mut index) }.ok()?; Ok(index) } /// Returns the GUID of a network interface given its LUID. pub fn guid_from_luid(luid: &NET_LUID_LH) -> io::Result { let mut guid = MaybeUninit::zeroed(); - win32_err!(unsafe { ConvertInterfaceLuidToGuid(luid, guid.as_mut_ptr()) })?; + unsafe { ConvertInterfaceLuidToGuid(luid, guid.as_mut_ptr()) }.ok()?; Ok(unsafe { guid.assume_init() }) } /// Returns the LUID of an interface given its alias. pub fn luid_from_alias>(alias: T) -> io::Result { - let alias_wide: Vec = alias - .as_ref() - .encode_wide() - .chain(std::iter::once(0u16)) - .collect(); let mut luid: NET_LUID_LH = unsafe { std::mem::zeroed() }; - win32_err!(unsafe { ConvertInterfaceAliasToLuid(alias_wide.as_ptr(), &mut luid) })?; + unsafe { ConvertInterfaceAliasToLuid(&HSTRING::from(alias.as_ref()), &mut luid) }.ok()?; Ok(luid) } /// Returns the alias of an interface given its LUID. -pub fn alias_from_luid(luid: &NET_LUID_LH) -> io::Result { +pub fn alias_from_luid(luid: &NET_LUID_LH) -> windows::core::Result { let mut buffer = [0u16; IF_MAX_STRING_SIZE as usize + 1]; - win32_err!(unsafe { - ConvertInterfaceLuidToAlias(luid, &mut buffer[0] as *mut _, buffer.len()) - })?; + unsafe { ConvertInterfaceLuidToAlias(luid, &mut buffer) }.ok()?; let nul = buffer.iter().position(|&c| c == 0u16).unwrap(); Ok(OsString::from_wide(&buffer[0..nul])) } -fn af_family_from_family(family: Option) -> u16 { - family.map(|family| family as u16).unwrap_or(AF_UNSPEC) -} - -/// Converts an `Ipv4Addr` to `IN_ADDR` -pub fn inaddr_from_ipaddr(addr: Ipv4Addr) -> IN_ADDR { - let sockaddr = SockAddr::from(SocketAddr::V4(SocketAddrV4::new(addr, 0))); - unsafe { *(sockaddr.as_ptr() as *const sockaddr_in) }.sin_addr -} - -/// Converts an `Ipv6Addr` to `IN6_ADDR` -pub fn in6addr_from_ipaddr(addr: Ipv6Addr) -> IN6_ADDR { - let sockaddr = SockAddr::from(SocketAddr::V6(SocketAddrV6::new(addr, 0, 0, 0))); - unsafe { *(sockaddr.as_ptr() as *const sockaddr_in6) }.sin6_addr -} - -/// Converts an `IN_ADDR` to `Ipv4Addr` -pub fn ipaddr_from_inaddr(addr: IN_ADDR) -> Ipv4Addr { - Ipv4Addr::from(unsafe { addr.S_un.S_addr }.to_ne_bytes()) -} - -/// Converts an `IN6_ADDR` to `Ipv6Addr` -pub fn ipaddr_from_in6addr(addr: IN6_ADDR) -> Ipv6Addr { - Ipv6Addr::from(unsafe { addr.u.Byte }) -} - -/// Converts a `SocketAddr` to `SOCKADDR_INET` -pub fn inet_sockaddr_from_socketaddr(addr: SocketAddr) -> SOCKADDR_INET { - let mut sockaddr: SOCKADDR_INET = unsafe { mem::zeroed() }; - match addr { - // SAFETY: `*const sockaddr` may be treated as `*const sockaddr_in` since we know it's a v4 - // address. - SocketAddr::V4(_) => unsafe { - sockaddr.Ipv4 = *(SockAddr::from(addr).as_ptr() as *const _) - }, - // SAFETY: `*const sockaddr` may be treated as `*const sockaddr_in6` since we know it's a v6 - // address. - SocketAddr::V6(_) => unsafe { - sockaddr.Ipv6 = *(SockAddr::from(addr).as_ptr() as *const _) - }, - } - sockaddr +fn af_family_from_family(family: Option) -> ADDRESS_FAMILY { + family + .map(|family| ADDRESS_FAMILY(family as u16)) + .unwrap_or(AF_UNSPEC) } /// Converts a `SOCKADDR_INET` to `SocketAddr`. Returns an error if the address family is invalid. pub fn try_socketaddr_from_inet_sockaddr(addr: SOCKADDR_INET) -> Result { let family = unsafe { addr.si_family }; - unsafe { - let mut storage: sockaddr_storage = mem::zeroed(); - *(&mut storage as *mut _ as *mut SOCKADDR_INET) = addr; - SockAddr::new(storage, mem::size_of_val(&addr) as i32) + + match family { + AF_INET => { + let ipv4_addr = Ipv4Addr::from(unsafe { addr.Ipv4.sin_addr }); + let port = u16::from_be(unsafe { addr.Ipv4.sin_port }); + + Ok(SocketAddr::V4(SocketAddrV4::new(ipv4_addr, port))) + } + AF_INET6 => { + let ipv6_addr = Ipv6Addr::from(unsafe { addr.Ipv6.sin6_addr }); + let port = u16::from_be(unsafe { addr.Ipv6.sin6_port }); + let flowinfo = u32::from_be(unsafe { addr.Ipv6.sin6_flowinfo }); + let scope_id = unsafe { addr.Ipv6.Anonymous.sin6_scope_id }; + + Ok(SocketAddr::V6(SocketAddrV6::new( + ipv6_addr, port, flowinfo, scope_id, + ))) + } + _ => Err(Error::UnknownAddressFamily(family.0)), } - .as_socket() - .ok_or(Error::UnknownAddressFamily(family)) } /// Address family. These correspond to the `AF_*` constants. #[derive(Debug, Clone, Copy)] pub enum AddressFamily { /// IPv4 address family - Ipv4 = AF_INET as isize, + Ipv4 = AF_INET.0 as isize, /// IPv6 address family - Ipv6 = AF_INET6 as isize, + Ipv6 = AF_INET6.0 as isize, } impl fmt::Display for AddressFamily { @@ -526,7 +509,7 @@ mod tests { let addr_v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 1234)); assert_eq!( addr_v4, - try_socketaddr_from_inet_sockaddr(inet_sockaddr_from_socketaddr(addr_v4)).unwrap() + try_socketaddr_from_inet_sockaddr(SOCKADDR_INET::from(addr_v4)).unwrap() ); } @@ -540,7 +523,7 @@ mod tests { )); assert_eq!( addr_v6, - try_socketaddr_from_inet_sockaddr(inet_sockaddr_from_socketaddr(addr_v6)).unwrap() + try_socketaddr_from_inet_sockaddr(SOCKADDR_INET::from(addr_v6)).unwrap() ); } } diff --git a/nym-vpn-core/crates/nym-windows/src/process.rs b/nym-vpn-core/crates/nym-windows/src/process.rs index 7268733e4b..48da541f86 100644 --- a/nym-vpn-core/crates/nym-windows/src/process.rs +++ b/nym-vpn-core/crates/nym-windows/src/process.rs @@ -4,13 +4,13 @@ use std::{ ffi::{c_char, CStr}, - io, mem, + mem, }; -use windows_sys::Win32::{ - Foundation::{CloseHandle, ERROR_NO_MORE_FILES, HANDLE, INVALID_HANDLE_VALUE}, +use windows::Win32::{ + Foundation::{CloseHandle, ERROR_NO_MORE_FILES, HANDLE}, System::Diagnostics::ToolHelp::{ CreateToolhelp32Snapshot, Module32First, Module32Next, Process32FirstW, Process32NextW, - MODULEENTRY32, PROCESSENTRY32W, + CREATE_TOOLHELP_SNAPSHOT_FLAGS, MODULEENTRY32, PROCESSENTRY32W, }, }; @@ -21,14 +21,13 @@ pub struct ProcessSnapshot { impl ProcessSnapshot { /// Create a new process snapshot using `CreateToolhelp32Snapshot` - pub fn new(flags: u32, process_id: u32) -> io::Result { - let snap = unsafe { CreateToolhelp32Snapshot(flags, process_id) }; - - if snap == INVALID_HANDLE_VALUE { - Err(io::Error::last_os_error()) - } else { - Ok(ProcessSnapshot { handle: snap }) - } + pub fn new( + flags: CREATE_TOOLHELP_SNAPSHOT_FLAGS, + process_id: u32, + ) -> windows::core::Result { + Ok(ProcessSnapshot { + handle: unsafe { CreateToolhelp32Snapshot(flags, process_id) }?, + }) } /// Return the raw handle @@ -63,8 +62,8 @@ impl ProcessSnapshot { impl Drop for ProcessSnapshot { fn drop(&mut self) { - unsafe { - CloseHandle(self.handle); + if let Err(e) = unsafe { CloseHandle(self.handle) } { + tracing::error!("Failed to close process snapshot handle: {}", e); } } } @@ -87,28 +86,28 @@ pub struct ProcessSnapshotModules<'a> { } impl Iterator for ProcessSnapshotModules<'_> { - type Item = io::Result; + type Item = windows::core::Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { if self.iter_started { - if unsafe { Module32Next(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { - let last_error = io::Error::last_os_error(); - - return if last_error.raw_os_error().unwrap() as u32 == ERROR_NO_MORE_FILES { + if let Err(last_error) = + unsafe { Module32Next(self.snapshot.as_raw(), &mut self.temp_entry) } + { + return if last_error.code() == ERROR_NO_MORE_FILES.to_hresult() { None } else { Some(Err(last_error)) }; } } else { - if unsafe { Module32First(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { - return Some(Err(io::Error::last_os_error())); + if let Err(e) = unsafe { Module32First(self.snapshot.as_raw(), &mut self.temp_entry) } { + return Some(Err(e)); } self.iter_started = true; } let cstr_ref = &self.temp_entry.szModule[0]; - let cstr = unsafe { CStr::from_ptr(cstr_ref as *const u8 as *const c_char) }; + let cstr = unsafe { CStr::from_ptr(cstr_ref as *const c_char) }; Some(Ok(ModuleEntry { name: cstr.to_string_lossy().into_owned(), base_address: self.temp_entry.modBaseAddr, @@ -133,22 +132,23 @@ pub struct ProcessSnapshotEntries<'a> { } impl Iterator for ProcessSnapshotEntries<'_> { - type Item = io::Result; + type Item = windows::core::Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { if self.iter_started { - if unsafe { Process32NextW(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { - let last_error = io::Error::last_os_error(); - - return if last_error.raw_os_error().unwrap() as u32 == ERROR_NO_MORE_FILES { + if let Err(last_error) = + unsafe { Process32NextW(self.snapshot.as_raw(), &mut self.temp_entry) } + { + return if last_error.code() == ERROR_NO_MORE_FILES.to_hresult() { None } else { Some(Err(last_error)) }; } } else { - if unsafe { Process32FirstW(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { - return Some(Err(io::Error::last_os_error())); + if let Err(e) = unsafe { Process32FirstW(self.snapshot.as_raw(), &mut self.temp_entry) } + { + return Some(Err(e)); } self.iter_started = true; } diff --git a/nym-vpn-core/crates/nym-windows/src/sync.rs b/nym-vpn-core/crates/nym-windows/src/sync.rs index e1296ef11d..1af8f0276b 100644 --- a/nym-vpn-core/crates/nym-windows/src/sync.rs +++ b/nym-vpn-core/crates/nym-windows/src/sync.rs @@ -2,9 +2,9 @@ // Copyright 2024 Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use std::{io, ptr}; -use windows_sys::Win32::{ - Foundation::{CloseHandle, DuplicateHandle, BOOL, DUPLICATE_SAME_ACCESS, HANDLE}, +use std::io; +use windows::Win32::{ + Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE}, System::Threading::{CreateEventW, GetCurrentProcess, SetEvent}, }; @@ -16,27 +16,15 @@ unsafe impl Sync for Event {} impl Event { /// Create a new event object using `CreateEventW` - pub fn new(manual_reset: bool, initial_state: bool) -> io::Result { - let event = unsafe { - CreateEventW( - ptr::null_mut(), - bool_to_winbool(manual_reset), - bool_to_winbool(initial_state), - ptr::null(), - ) - }; - if event == 0 { - return Err(io::Error::last_os_error()); - } - Ok(Self(event)) + pub fn new(manual_reset: bool, initial_state: bool) -> windows::core::Result { + Ok(Self(unsafe { + CreateEventW(None, manual_reset, initial_state, None) + }?)) } /// Signal the event object - pub fn set(&self) -> io::Result<()> { - if unsafe { SetEvent(self.0) } == 0 { - return Err(io::Error::last_os_error()); - } - Ok(()) + pub fn set(&self) -> windows::core::Result<()> { + unsafe { SetEvent(self.0) } } /// Return raw event object @@ -46,34 +34,26 @@ impl Event { /// Duplicate the event object with `DuplicateHandle()` pub fn duplicate(&self) -> io::Result { - let mut new_event = 0; - let status = unsafe { + let mut new_event = HANDLE::default(); + unsafe { DuplicateHandle( GetCurrentProcess(), self.0, GetCurrentProcess(), &mut new_event, 0, - 0, + false, DUPLICATE_SAME_ACCESS, ) - }; - if status == 0 { - return Err(io::Error::last_os_error()); - } + }?; Ok(Event(new_event)) } } impl Drop for Event { fn drop(&mut self) { - unsafe { CloseHandle(self.0) }; - } -} - -const fn bool_to_winbool(val: bool) -> BOOL { - match val { - true => 1, - false => 0, + if let Err(e) = unsafe { CloseHandle(self.0) } { + tracing::error!("Failed to close event handle: {}", e); + } } } diff --git a/nym-vpn-core/crates/nym-windows/src/window.rs b/nym-vpn-core/crates/nym-windows/src/window.rs index 99c82ca780..8e2073a780 100644 --- a/nym-vpn-core/crates/nym-windows/src/window.rs +++ b/nym-vpn-core/crates/nym-windows/src/window.rs @@ -4,20 +4,24 @@ //! Utilities for working with windows on Windows. -use std::{os::windows::io::AsRawHandle, ptr, sync::Arc, thread}; +use std::{os::windows::io::AsRawHandle, sync::Arc, thread}; use tokio::sync::broadcast; -use windows_sys::Win32::{ - Foundation::{HANDLE, HWND, LPARAM, LRESULT, WPARAM}, - System::{LibraryLoader::GetModuleHandleW, Threading::GetThreadId}, - UI::WindowsAndMessaging::{ - CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GetMessageW, - GetWindowLongPtrW, PostQuitMessage, PostThreadMessageW, SetWindowLongPtrW, - TranslateMessage, GWLP_USERDATA, GWLP_WNDPROC, PBT_APMRESUMEAUTOMATIC, - PBT_APMRESUMESUSPEND, PBT_APMSUSPEND, WM_DESTROY, WM_POWERBROADCAST, WM_USER, +use windows::{ + core::{w, PCWSTR}, + Win32::{ + Foundation::{HANDLE, HINSTANCE, HWND, LPARAM, LRESULT, WPARAM}, + System::{LibraryLoader::GetModuleHandleW, Threading::GetThreadId}, + UI::WindowsAndMessaging::{ + CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GetMessageW, + GetWindowLongPtrW, PostQuitMessage, PostThreadMessageW, SetWindowLongPtrW, + TranslateMessage, GWLP_USERDATA, GWLP_WNDPROC, PBT_APMRESUMEAUTOMATIC, + PBT_APMRESUMESUSPEND, PBT_APMSUSPEND, WINDOW_EX_STYLE, WINDOW_STYLE, WM_DESTROY, + WM_POWERBROADCAST, WM_USER, + }, }, }; -const CLASS_NAME: *const u16 = windows_sys::w!("STATIC"); +const CLASS_NAME: PCWSTR = w!("STATIC"); const REQUEST_THREAD_SHUTDOWN: u32 = WM_USER + 1; /// Handle for closing an associated window. @@ -30,8 +34,17 @@ impl WindowCloseHandle { /// Close the window and wait for the thread. pub fn close(&mut self) { if let Some(thread) = self.thread.take() { - let thread_id = unsafe { GetThreadId(thread.as_raw_handle() as HANDLE) }; - unsafe { PostThreadMessageW(thread_id, REQUEST_THREAD_SHUTDOWN, 0, 0) }; + let thread_id = unsafe { GetThreadId(HANDLE(thread.as_raw_handle())) }; + if let Err(e) = unsafe { + PostThreadMessageW( + thread_id, + REQUEST_THREAD_SHUTDOWN, + WPARAM::default(), + LPARAM::default(), + ) + } { + tracing::error!("Failed to post thread shutdown message: {}", e); + } let _ = thread.join(); } } @@ -42,21 +55,31 @@ pub fn create_hidden_window LRESULT) + Send wnd_proc: F, ) -> WindowCloseHandle { let join_handle = thread::spawn(move || { - let dummy_window = unsafe { + let Ok(module_instance) = unsafe { GetModuleHandleW(None) } + .inspect_err(|e| tracing::error!("Failed to obtain GetModuleHandleW(0): {}", e)) + else { + return; + }; + let Ok(dummy_window) = unsafe { CreateWindowExW( - 0, + WINDOW_EX_STYLE::default(), CLASS_NAME, - ptr::null_mut(), - 0, + None, + WINDOW_STYLE::default(), 0, 0, 0, 0, - 0, - 0, - GetModuleHandleW(ptr::null_mut()), - ptr::null_mut(), + None, + None, + Some(HINSTANCE::from(module_instance)), + None, ) + } + .inspect_err(|e| { + tracing::error!("Failed to create hidden window: {}", e); + }) else { + return; }; // Move callback information to the heap. @@ -77,22 +100,24 @@ pub fn create_hidden_window LRESULT) + Send let mut msg = unsafe { std::mem::zeroed() }; loop { - let status = unsafe { GetMessageW(&mut msg, 0, 0, 0) }; + let status = unsafe { GetMessageW(&mut msg, None, 0, 0) }; - if status < 0 { + if status.0 < 0 { continue; } - if status == 0 { + if status.0 == 0 { break; } - if msg.hwnd == 0 { + if msg.hwnd.is_invalid() { if msg.message == REQUEST_THREAD_SHUTDOWN { - unsafe { DestroyWindow(dummy_window) }; + if let Err(e) = unsafe { DestroyWindow(dummy_window) } { + tracing::error!("Failed to destroy window: {}", e); + } } } else { unsafe { - TranslateMessage(&msg); + _ = TranslateMessage(&msg); DispatchMessageW(&msg); } } @@ -118,7 +143,7 @@ where { if message == WM_DESTROY { PostQuitMessage(0); - return 0; + return LRESULT::default(); } let raw_callback = GetWindowLongPtrW(window, GWLP_USERDATA); if raw_callback != 0 { @@ -143,9 +168,9 @@ pub enum PowerManagementEvent { } impl PowerManagementEvent { - fn try_from_winevent(wparam: usize) -> Option { + fn try_from_winevent(wparam: WPARAM) -> Option { use PowerManagementEvent::*; - match wparam as u32 { + match wparam.0 as u32 { PBT_APMRESUMEAUTOMATIC => Some(ResumeAutomatic), PBT_APMRESUMESUSPEND => Some(ResumeSuspend), PBT_APMSUSPEND => Some(Suspend), @@ -165,13 +190,13 @@ impl PowerManagementListener { pub fn new() -> Self { let (tx, rx) = tokio::sync::broadcast::channel(16); - let power_broadcast_callback = move |window, message, wparam, lparam| { + let power_broadcast_callback = move |window, message, wparam, lparam: LPARAM| { if message == WM_POWERBROADCAST { if let Some(event) = PowerManagementEvent::try_from_winevent(wparam) { if tx.send(event).is_err() { tracing::error!("Stopping power management event monitor"); unsafe { PostQuitMessage(0) }; - return 0; + return LRESULT::default(); } } }