diff --git a/Cargo.lock b/Cargo.lock index 067526d4..3e78c8c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2368,9 +2368,8 @@ dependencies = [ "wildmatch", "winapi", "windivert", - "windows 0.52.0", + "windows 0.62.2", "windows-service", - "windows-sys 0.52.0", "winreg 0.52.0", "x25519-dalek", "zerocopy 0.7.35", @@ -11234,11 +11233,23 @@ version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections", + "windows-collections 0.2.0", "windows-core 0.61.2", - "windows-future", + "windows-future 0.2.1", "windows-link 0.1.3", - "windows-numerics", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", ] [[package]] @@ -11250,6 +11261,15 @@ dependencies = [ "windows-core 0.61.2", ] +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core 0.62.2", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -11285,6 +11305,19 @@ dependencies = [ "windows-strings 0.4.2", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-future" version = "0.2.1" @@ -11293,7 +11326,18 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", ] [[package]] @@ -11362,6 +11406,16 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + [[package]] name = "windows-registry" version = "0.2.0" @@ -11391,6 +11445,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-service" version = "0.7.0" @@ -11421,6 +11484,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -11546,6 +11618,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-version" version = "0.1.7" diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 70127b62..7aa7d64b 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -274,11 +274,15 @@ windivert = { git = "https://github.com/EasyTier/windivert-rust.git", rev = "adc ] } [target.'cfg(windows)'.dependencies] -windows = { version = "0.52.0", features = [ +windows = { version = "0.62.2", features = [ "Win32_Foundation", + "Win32_NetworkManagement_IpHelper", + "Win32_NetworkManagement_Ndis", "Win32_NetworkManagement_WindowsFirewall", - "Win32_System_Com", "Win32_Networking", + "Win32_System_Com", + "Win32_System_Diagnostics", + "Win32_System_Diagnostics_Debug", "Win32_System_Ole", "Win32_System_Variant", "Win32_Networking_WinSock", @@ -287,14 +291,6 @@ windows = { version = "0.52.0", features = [ encoding = "0.2" winreg = "0.52" windows-service = "0.7.0" -windows-sys = { version = "0.52", features = [ - "Win32_NetworkManagement_IpHelper", - "Win32_NetworkManagement_Ndis", - "Win32_Networking_WinSock", - "Win32_Foundation", - "Win32_System_Diagnostics", - "Win32_System_Diagnostics_Debug", -] } winapi = { version = "0.3.9", features = ["impl-default"] } [target.'cfg(not(windows))'.dependencies] diff --git a/easytier/src/arch/windows.rs b/easytier/src/arch/windows.rs index abf14b23..d0332831 100644 --- a/easytier/src/arch/windows.rs +++ b/easytier/src/arch/windows.rs @@ -4,15 +4,16 @@ use anyhow::Context; use network_interface::NetworkInterfaceConfig; use windows::{ Win32::{ - Foundation::{BOOL, FALSE}, + Foundation::FALSE, NetworkManagement::WindowsFirewall::{ INetFwPolicy2, INetFwRule, NET_FW_ACTION_ALLOW, NET_FW_PROFILE2_DOMAIN, NET_FW_PROFILE2_PRIVATE, NET_FW_PROFILE2_PUBLIC, NET_FW_RULE_DIR_IN, NET_FW_RULE_DIR_OUT, }, Networking::WinSock::{ - IP_UNICAST_IF, IPPROTO_IP, IPPROTO_IPV6, IPV6_UNICAST_IF, SIO_UDP_CONNRESET, SOCKET, - SOCKET_ERROR, WSAGetLastError, WSAIoctl, htonl, setsockopt, + IP_UNICAST_IF, IPPROTO_IP, IPPROTO_IPV6, IPV6_UNICAST_IF, SIO_UDP_CONNRESET, + SO_EXCLUSIVEADDRUSE, SOCKET, SOCKET_ERROR, SOL_SOCKET, WSAGetLastError, WSAIoctl, + htonl, setsockopt, }, System::Com::{ CLSCTX_ALL, COINIT_MULTITHREADED, CoCreateInstance, CoInitializeEx, CoUninitialize, @@ -20,7 +21,7 @@ use windows::{ System::Ole::{SafeArrayCreateVector, SafeArrayPutElement}, System::Variant::{VARENUM, VARIANT, VT_ARRAY, VT_BSTR, VT_VARIANT}, }, - core::BSTR, + core::{BOOL, BSTR}, }; pub fn disable_connection_reset(socket: &S) -> io::Result<()> { @@ -88,13 +89,7 @@ pub fn find_interface_index(iface_name: &str) -> io::Result { )) } -pub fn set_ip_unicast_if( - socket: &S, - addr: &SocketAddr, - iface: &str, -) -> io::Result<()> { - let handle = SOCKET(socket.as_raw_socket() as usize); - +pub fn set_ip_unicast_if(socket: SOCKET, addr: &SocketAddr, iface: &str) -> io::Result<()> { let if_index = find_interface_index(iface)?; unsafe { @@ -103,12 +98,12 @@ pub fn set_ip_unicast_if( SocketAddr::V4(..) => { let if_index = htonl(if_index); let if_index_bytes = if_index.to_ne_bytes(); - setsockopt(handle, IPPROTO_IP.0, IP_UNICAST_IF, Some(&if_index_bytes)) + setsockopt(socket, IPPROTO_IP.0, IP_UNICAST_IF, Some(&if_index_bytes)) } SocketAddr::V6(..) => { let if_index_bytes = if_index.to_ne_bytes(); setsockopt( - handle, + socket, IPPROTO_IPV6.0, IPV6_UNICAST_IF, Some(&if_index_bytes), @@ -141,8 +136,16 @@ pub fn setup_socket_for_win( disable_connection_reset(socket)?; } + let socket = SOCKET(socket.as_raw_socket() as usize); + let optval = 1_i32.to_ne_bytes(); + unsafe { + if setsockopt(socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, Some(&optval)) == SOCKET_ERROR { + return Err(io::Error::last_os_error()); + } + } + if let Some(iface) = bind_dev { - set_ip_unicast_if(socket, bind_addr, iface.as_str())?; + set_ip_unicast_if(socket, bind_addr, &iface)?; } Ok(()) @@ -152,7 +155,7 @@ struct ComInitializer; impl ComInitializer { fn new() -> windows::core::Result { - unsafe { CoInitializeEx(None, COINIT_MULTITHREADED)? }; + unsafe { CoInitializeEx(None, COINIT_MULTITHREADED).ok()? }; Ok(Self) } } @@ -354,7 +357,7 @@ fn add_protocol_firewall_rules( (*interface_variant.Anonymous.Anonymous).vt = VARENUM(VT_ARRAY.0 | VT_VARIANT.0); (*interface_variant.Anonymous.Anonymous).Anonymous.parray = interface_array; - rule.SetInterfaces(interface_variant)?; + rule.SetInterfaces(&interface_variant)?; // Get rule collection and add new rule let rules = policy.Rules()?; diff --git a/easytier/src/common/ifcfg/windows.rs b/easytier/src/common/ifcfg/windows.rs index aa995e54..db3ca512 100644 --- a/easytier/src/common/ifcfg/windows.rs +++ b/easytier/src/common/ifcfg/windows.rs @@ -6,15 +6,16 @@ use cidr::{Ipv4Inet, Ipv6Inet}; use std::{ io, net::{Ipv4Addr, Ipv6Addr}, - ptr::null_mut, }; -use windows_sys::Win32::{ +use windows::Win32::NetworkManagement::IpHelper::INTERNAL_IF_OPER_STATUS; +use windows::Win32::{ Foundation::NO_ERROR, NetworkManagement::IpHelper::{GetIfEntry, MIB_IFROW, SetIfEntry}, System::Diagnostics::Debug::{ FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessageW, }, }; +use windows::core::PWSTR; use winreg::{ RegKey, enums::{HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE}, @@ -32,12 +33,12 @@ fn format_win_error(error: u32) -> String { unsafe { FormatMessageW( flags, - null_mut(), + None, error, 0, - buffer.as_mut_ptr(), + PWSTR(buffer.as_mut_ptr()), size, - null_mut(), + None, ); } let str_end = buffer.iter().position(|&b| b == 0).unwrap_or(buffer.len()); @@ -100,7 +101,7 @@ impl WindowsIfConfiger { dwPhysAddrLen: 0, bPhysAddr: [0; 8], dwAdminStatus: if up { 1 } else { 2 }, // 1 = up, 2 = down - dwOperStatus: 0, + dwOperStatus: INTERNAL_IF_OPER_STATUS(0), dwLastChange: 0, dwInOctets: 0, dwInUcastPkts: 0, @@ -118,8 +119,8 @@ impl WindowsIfConfiger { bDescr: [0; 256], }; - if GetIfEntry(&mut if_row) == NO_ERROR { - if SetIfEntry(&if_row) == NO_ERROR { + if GetIfEntry(&mut if_row) == NO_ERROR.0 { + if SetIfEntry(&if_row) == NO_ERROR.0 { Ok(()) } else { Err(anyhow::anyhow!("Failed to set interface status").into()) diff --git a/easytier/src/tunnel/common.rs b/easytier/src/tunnel/common.rs index f73e53e7..f24e5d27 100644 --- a/easytier/src/tunnel/common.rs +++ b/easytier/src/tunnel/common.rs @@ -423,7 +423,7 @@ fn setup_socket2_ext( } socket2_socket.set_nonblocking(true)?; - socket2_socket.set_reuse_address(true)?; + socket2_socket.set_reuse_address(!cfg!(target_os = "windows"))?; if let Err(e) = socket2_socket.bind(&socket2::SockAddr::from(*bind_addr)) { if bind_addr.is_ipv4() { return Err(e.into());