From e27ef2f85ec441a4ba4d84f901e63d55da9ab196 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Thu, 6 Nov 2025 00:41:42 -0800 Subject: [PATCH 1/9] set MTU TODO: requires reboot --- Cargo.toml | 6 + src/wgapi_windows.rs | 263 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 259 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 78d3c58..c11ac27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,12 @@ windows = { version = "0.62", features = [ "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", "Win32_System_Com", + "Win32_System_Com_StructuredStorage", + "Win32_System_Rpc", + "Win32_System_Variant", + "Win32_System_Ole", + "Win32_System_Wmi", + "Win32_Foundation", ]} wireguard-nt = "0.5.0" diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index 0633bf2..9e501b9 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -1,8 +1,5 @@ use std::{ - collections::HashMap, - net::IpAddr, - str::FromStr, - sync::{LazyLock, Mutex}, + collections::HashMap, ffi::OsStr, net::IpAddr, os::windows::ffi::OsStrExt, ptr::{null, null_mut}, str::FromStr, sync::{LazyLock, Mutex} }; use ipnet::{IpNet, Ipv4Net, Ipv6Net}; @@ -11,12 +8,10 @@ use windows::{ Win32::{ Foundation::{ERROR_BUFFER_OVERFLOW, NO_ERROR}, NetworkManagement::IpHelper::{ - DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, - DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, - IP_ADAPTER_ADDRESSES_LH, SetInterfaceDnsSettings, + DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIfEntry, IP_ADAPTER_ADDRESSES_LH, MIB_IFROW, SetIfEntry, SetInterfaceDnsSettings }, Networking::WinSock::AF_UNSPEC, - System::Com::CLSIDFromString, + System::{Com::CLSIDFromString, Rpc::{RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE}, Variant::{VARIANT, VT_I4}, Wmi::{IWbemCallResult, IWbemClassObject, WBEM_GENERIC_FLAG_TYPE}}, }, core::{GUID, PCSTR, PCWSTR, PSTR}, }; @@ -70,6 +65,47 @@ fn guid_from_str(s: &str) -> Result { Ok(guid) } +fn get_adapter_index(adapter_name: &str) -> Result { + let mut buffer_size: u32 = 0; + unsafe { + GetAdaptersAddresses( + AF_UNSPEC.0 as u32, + GAA_FLAG_INCLUDE_PREFIX, + None, + None, + &mut buffer_size, + ) + }; + let mut buffer = vec![0u8; buffer_size as usize]; + let addresses = buffer.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH; + + let result = unsafe { + GetAdaptersAddresses( + AF_UNSPEC.0 as u32, + GAA_FLAG_INCLUDE_PREFIX, + None, + Some(addresses), + &mut buffer_size, + ) + }; + if result != 0 { + return Err(WindowsError::NonZeroReturnValue(result)); + } + + let mut current = addresses; + while !current.is_null() { + let adapter = unsafe { &*current }; + let friendly_name = unsafe { PCWSTR(adapter.FriendlyName.0).to_string()? }; + if friendly_name == adapter_name { + let if_index = unsafe { adapter.Anonymous1.Anonymous.IfIndex }; + return Ok(if_index); + } + current = adapter.Next; + } + + Err(WindowsError::AdapterNotFound(adapter_name.to_string())) +} + /// Returns the GUID of a network adapter given its name. /// Example adapter name: "Ethernet", "WireGuard". fn get_adapter_guid(adapter_name: &str) -> Result { @@ -136,6 +172,208 @@ fn get_adapter_guid(adapter_name: &str) -> Result { guid.ok_or_else(|| WindowsError::AdapterNotFound(adapter_name.to_string())) } +// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { +// // Find interface index via GetAdaptersAddresses +// debug!("set_interface_mtu: before get_adapter_buid"); +// let guid = get_adapter_guid(adapter_name)?; +// debug!("set_interface_mtu: after get_adapter_buid"); + +// // Convert GUID to string without braces +// let guid_str = format!("{:?}", guid); +// let guid_str = guid_str.trim_matches(['{', '}']); + +// // Initialize MIB_IFROW with interface name +// debug!("set_interface_mtu: before MIB_IFROW init"); +// let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; +// // Wide string name (null terminated) +// let name_wide = str_to_wide_null_terminated(guid_str); +// row.wszName[..name_wide.len()].copy_from_slice(&name_wide); +// debug!("set_interface_mtu: after MIB_IFROW init"); + +// // Get current entry to populate the row fields +// // TODO use NO_ERROR +// debug!("set_interface_mtu: before GetIfEntry"); +// let res = unsafe { GetIfEntry(&mut row) }; +// if res != 0 { +// error!("Failed to get current interface entry"); +// return Err(WindowsError::NonZeroReturnValue(res)); +// } +// debug!("set_interface_mtu: after GetIfEntry"); + +// // Update MTU +// row.dwMtu = mtu; + +// // Commit change +// // TODO use NO_ERROR +// debug!("set_interface_mtu: before SetIfEntry"); +// let res = unsafe { SetIfEntry(&row) }; +// if res != 0 { +// error!("Failed to set current interface entry"); +// return Err(WindowsError::NonZeroReturnValue(res)); +// } +// debug!("set_interface_mtu: after SetIfEntry"); + +// Ok(()) +// } + +// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { +// let if_index = get_adapter_index(adapter_name)?; +// let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; +// row.dwIndex = if_index; + +// let res = unsafe { GetIfEntry(&mut row) }; +// if res != 0 { +// return Err(WindowsError::NonZeroReturnValue(res)); +// } + +// row.dwMtu = mtu; +// let res = unsafe { SetIfEntry(&row) }; +// if res != 0 { +// return Err(WindowsError::NonZeroReturnValue(res)); +// } + +// Ok(()) +// } + +use windows::{ + // core::{BSTR, VARIANT, HRESULT}, + core::{BSTR, HRESULT}, + Win32::{ + // Foundation::WBEM_E_NOT_FOUND, + System::{ + Com::{ + CoInitializeEx, CoCreateInstance, CoUninitialize, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED, + // VARIANT_TRUE, VT_I4, VT_BSTR, VT_NULL, + }, + // Ole::VariantInit, + Wmi::{ + IWbemLocator, IWbemServices, WbemLocator, WBEM_FLAG_FORWARD_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, + WBEM_INFINITE, + }, + }, + }, +}; + +fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> { + unsafe { + // Initialize COM + CoInitializeEx(None, COINIT_APARTMENTTHREADED).unwrap(); + + // Create WMI locator + // let locator: IWbemLocator = CoCreateInstance(&CLSID_WbemLocator, None, CLSCTX_INPROC_SERVER)?; + let locator: IWbemLocator = CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER)?; + + // Connect to WMI namespace + let empty = BSTR::new(); + let services: IWbemServices = locator.ConnectServer( + &BSTR::from("ROOT\\CIMV2"), + &empty, + &empty, + &empty, + 0, + &empty, + None, + )?; + + use windows::Win32::System::Com::{ + CoSetProxyBlanket, RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, EOAC_NONE, + }; + + CoSetProxyBlanket( + &services, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + None, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + None, + EOAC_NONE, + )?; + + // Build WQL query + let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Description = '{}'", interface_name); + // let mut enumerator = None; + + let enumerator = services.ExecQuery( + &BSTR::from("WQL"), + &BSTR::from(query), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + None, + // &mut enumerator, + )?; + + let mut objs = [None]; + let mut returned = 0; + let hr = enumerator.Next(WBEM_INFINITE as i32, &mut objs, &mut returned); + + if hr.is_err() || returned == 0 { + CoUninitialize(); + // return Err(HRESULT(WBEM_E_NOT_FOUND.0).into()); + error!("hr: {hr}, returned: {returned}"); + return Err(HRESULT(0).into()); + } + + let adapter = objs[0].take().unwrap(); + + // Prepare input parameters for SetMTU + // let class_obj = Some(null_mut()); + let mut class_obj: Option = None; + let result = services.GetObject( + &BSTR::from("Win32_NetworkAdapterConfiguration"), + WBEM_GENERIC_FLAG_TYPE(0), + None, + Some(&mut class_obj), + None, + ); + if result.is_err() { + error!("GetObject result: {result:?}"); + } + // let in_params_def = null_mut(); + // let result = class_obj.unwrap().GetMethod( + // &BSTR::from("SetMTU"), + // 0, + // in_params_def, + // null_mut(), + // )?; + // let in_params = (*in_params_def).unwrap().SpawnInstance(0)?; + + // let mut mtu_variant = VARIANT::default(); + // *mtu_variant.n1.n2_mut().n3.lVal_mut() = mtu as i32; + // mtu_variant.n1.n2_mut().vt = VT_I4.0 as u16; + let mut in_params_def= None; + + // Call GetMethod to fill it + class_obj.unwrap().GetMethod( + &BSTR::from("SetMTU"), + 0, + &mut in_params_def, + &mut None, + )?; + let in_params = in_params_def.unwrap(); + use windows::Win32::System::Variant::{self, VARIANT, VT_I4}; + // use windows::core::VARIANT as CoreVariant; + + let mtu: i32 = 1380; + let mtu_variant = VARIANT::from(mtu as i32); + in_params.Put(&BSTR::from("MTU"), 0, &mtu_variant, 0)?; + // Execute method + let _out_params = services.ExecMethod( + &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Description=\"{}\"", interface_name)), + &BSTR::from("SetMTU"), + WBEM_GENERIC_FLAG_TYPE(0), + None, + &in_params, + None, + None, + )?; + + CoUninitialize(); + } + + Ok(()) +} + impl From for Peer { fn from(peer: wireguard_nt::WireguardPeer) -> Self { Self { @@ -173,7 +411,7 @@ impl From for Host { /// Converts an str to wide (u16), null-terminated fn str_to_wide_null_terminated(s: &str) -> Vec { - s.encode_utf16().chain(std::iter::once(0)).collect() + OsStr::new(s).encode_wide().chain(Some(0)).collect() } /// Manages interfaces created with Windows kernel using https://git.zx2c4.com/wireguard-nt. @@ -213,7 +451,6 @@ impl WireguardInterfaceApi for WGApi { "Configuring interface {} with config: {config:?}", self.ifname ); - // Retrieve the adapter - should be created by calling `Self::create_interface` first. let Some(ref adapter) = self.adapter else { Err(WindowsError::AdapterNotFound(self.ifname.clone()))? @@ -274,6 +511,12 @@ impl WireguardInterfaceApi for WGApi { // Bring the adapter up debug!("Bringing up adapter {}", self.ifname); + + // Set MTU + // set_interface_mtu(&self.ifname, mtu)?; + // let mtu = config.mtu.unwrap_or(1500); + let mtu = 1300; + set_mtu_via_wmi(&self.ifname, mtu).unwrap(); adapter.up().map_err(WindowsError::from)?; info!( From 334ae4beffc80c35b87573c3d0cfecfd92a3013c Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 01:38:18 -0800 Subject: [PATCH 2/9] have you atried turning it off and on again? --- src/wgapi_windows.rs | 238 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 228 insertions(+), 10 deletions(-) diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index 9e501b9..8ca9eff 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -254,6 +254,177 @@ use windows::{ }, }; +fn restart_adapter_via_wmi(interface_name: &str) -> windows::core::Result<()> { + unsafe { + // Connect to WMI just like in your set_mtu_via_wmi + use windows::Win32::System::Com::{ + CoInitializeEx, CoCreateInstance, CoUninitialize, CLSCTX_INPROC_SERVER, + COINIT_APARTMENTTHREADED, CoSetProxyBlanket, + }; + use windows::Win32::System::Rpc::{RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE}; + use windows::Win32::System::Wmi::{ + IWbemLocator, IWbemServices, WbemLocator, WBEM_FLAG_FORWARD_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, + WBEM_INFINITE, + }; + use windows::Win32::System::Com::{ + RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_LEVEL_DEFAULT, EOAC_NONE, + }; + use windows::core::BSTR; + + CoInitializeEx(None, COINIT_APARTMENTTHREADED).unwrap(); + + let locator: IWbemLocator = CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER).expect("Failed to CoCreateInstance()"); + let empty = BSTR::new(); + let services: IWbemServices = locator.ConnectServer( + &BSTR::from("ROOT\\CIMV2"), + &empty, &empty, &empty, + 0, &empty, None, + ).expect("Failed to locator.ConnectServer()"); + + CoSetProxyBlanket( + &services, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + None, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + None, + EOAC_NONE, + )?; + + // Find the adapter + let query = format!("SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionID='{}'", interface_name); + let enumerator = services.ExecQuery( + &BSTR::from("WQL"), + &BSTR::from(query), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + None, + ).expect("Failed to services.ExecQuery()"); + + let mut objs = [None]; + let mut returned = 0; + enumerator.Next(WBEM_INFINITE as i32, &mut objs, &mut returned).unwrap(); + if returned == 0 { + CoUninitialize(); + return Err(HRESULT(0).into()); + } + let adapter = objs[0].take().unwrap(); + + // Disable it + let adapter_index = 12; + let adapter_index = get_adapter_index(interface_name).expect("Failed to get_adapter_index()"); + warn!("adapter_index: {adapter_index}"); + warn!("disabling adapter"); + services.ExecMethod( + // &BSTR::from(format!("Win32_NetworkAdapter.NetConnectionID=\"{}\"", interface_name)), + // &BSTR::from(format!("Win32_NetworkAdapter.Index={adapter_index}")), + // &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Index={adapter_index}")), + &BSTR::from(format!("Win32_NetworkAdapter.Index={adapter_index}")), + &BSTR::from("Disable"), + WBEM_GENERIC_FLAG_TYPE(0), + None, + None, + None, + None, + // ).expect("Failed to disable interface"); + ); + + // Wait briefly for the device to go down + std::thread::sleep(std::time::Duration::from_secs(1)); + + // Enable it again + warn!("enabling adapter"); + services.ExecMethod( + &BSTR::from(format!("Win32_NetworkAdapter.Index={adapter_index}")), + &BSTR::from("Enable"), + WBEM_GENERIC_FLAG_TYPE(0), + None, + None, + None, + None, + // ).expect("Failed to enable interface"); + ); + + warn!("uninitializing"); + // CoUninitialize(); + } + + warn!("done"); + Ok(()) +} + +fn get_wmi_adapter_index_by_guid(interface_name: &str) -> windows::core::Result { + unsafe { + use windows::Win32::System::Com::{ + CoInitializeEx, CoCreateInstance, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED, + CoSetProxyBlanket, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, EOAC_NONE, + }; + use windows::Win32::System::Rpc::{RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE}; + use windows::Win32::System::Wmi::{IWbemLocator, IWbemServices, WbemLocator, + WBEM_FLAG_FORWARD_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_INFINITE}; + use windows::core::BSTR; + + let result = CoInitializeEx(None, COINIT_APARTMENTTHREADED); + if result.0 != 0 { + error!("Failed to CoInitializeEx()"); + return Err(HRESULT(0).into()); + } + let locator: IWbemLocator = CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER)?; + let empty = BSTR::new(); + let services: IWbemServices = locator.ConnectServer( + &BSTR::from("ROOT\\CIMV2"), + &empty, &empty, &empty, 0, &empty, None, + )?; + CoSetProxyBlanket( + &services, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + None, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + None, + EOAC_NONE, + )?; + + let guid = get_adapter_guid(interface_name).expect("Failed to get_adapter_guid()"); + let guid_str = format!("{{{:?}}}", guid); + let query = format!( + "SELECT Index FROM Win32_NetworkAdapterConfiguration WHERE SettingID='{}'", + guid_str + ); + + let enumerator = services.ExecQuery( + &BSTR::from("WQL"), + &BSTR::from(query), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + None, + )?; + + let mut objs = [None]; + let mut returned = 0; + let result = enumerator.Next(WBEM_INFINITE as i32, &mut objs, &mut returned); + if returned == 0 || result.0 != 0 { + error!("enumerator.Next error"); + // return Err(windows::core::Error::new( + // windows::core::HRESULT(0x80041002), + // "Adapter not found".into(), + // )); + return Err(HRESULT(0).into()); + } + let obj = objs[0].take().unwrap(); + let mut variant = VARIANT::default(); + let result = obj.Get(&BSTR::from("Index"), 0, &mut variant, None, None).expect("Failed to obj.Get()"); + let index = variant.Anonymous.Anonymous.Anonymous.lVal; + // let index = unsafe { variant.Anonymous.Anonymous.lVal }; // safe because VT_I4 + // if variant.vt() == VT_I4 { + + // } + // let index = unsafe { variant.Anonymous.Anonymous.lVal() }; // safe because VT_I4 + // let index = i32::try_from(variant).expect("Failed to i32::try_from(variant)"); + Ok(index) + } +} + fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> { unsafe { // Initialize COM @@ -292,9 +463,14 @@ fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> )?; // Build WQL query - let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Description = '{}'", interface_name); + // let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Description = '{}'", interface_name); + let guid = get_adapter_guid(interface_name).expect("set_mtu failed to get_adapter_guid"); + // let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE GUID = '{{{:?}}}'", guid); + let query = format!("SELECT * FROM Win32_NetworkAdapter WHERE GUID = '{{{:?}}}'", guid); + // let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE NetConnectionID='{}'", interface_name); + // let mut enumerator = None; - + warn!("Before enumerator"); let enumerator = services.ExecQuery( &BSTR::from("WQL"), &BSTR::from(query), @@ -302,25 +478,34 @@ fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> None, // &mut enumerator, )?; + warn!("After enumerator"); let mut objs = [None]; let mut returned = 0; let hr = enumerator.Next(WBEM_INFINITE as i32, &mut objs, &mut returned); + warn!("After enumerator.Next"); - if hr.is_err() || returned == 0 { + // if hr.is_err() || returned == 0 { + if returned == 0 { + error!("No adapter found for {interface_name}"); + return Err(HRESULT(0).into()); + } + if hr.is_err() { CoUninitialize(); // return Err(HRESULT(WBEM_E_NOT_FOUND.0).into()); error!("hr: {hr}, returned: {returned}"); return Err(HRESULT(0).into()); } - let adapter = objs[0].take().unwrap(); + let adapter = objs[0].take().expect("objs[0] is None"); + warn!("After objs[0].take()"); // Prepare input parameters for SetMTU // let class_obj = Some(null_mut()); let mut class_obj: Option = None; let result = services.GetObject( &BSTR::from("Win32_NetworkAdapterConfiguration"), + // &BSTR::from("Win32_NetworkAdapter"), WBEM_GENERIC_FLAG_TYPE(0), None, Some(&mut class_obj), @@ -328,6 +513,7 @@ fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> ); if result.is_err() { error!("GetObject result: {result:?}"); + return Err(HRESULT(0).into()); } // let in_params_def = null_mut(); // let result = class_obj.unwrap().GetMethod( @@ -344,29 +530,35 @@ fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> let mut in_params_def= None; // Call GetMethod to fill it - class_obj.unwrap().GetMethod( + class_obj.expect("class_obj is None").GetMethod( &BSTR::from("SetMTU"), 0, &mut in_params_def, &mut None, - )?; + ).expect("failed to GetMethod"); let in_params = in_params_def.unwrap(); use windows::Win32::System::Variant::{self, VARIANT, VT_I4}; // use windows::core::VARIANT as CoreVariant; let mtu: i32 = 1380; let mtu_variant = VARIANT::from(mtu as i32); - in_params.Put(&BSTR::from("MTU"), 0, &mtu_variant, 0)?; + in_params.Put(&BSTR::from("MTU"), 0, &mtu_variant, 0).expect("Failed to in_params.Put()"); // Execute method + let adapter_index = get_adapter_index(interface_name).expect("Failed to get_adapter_index()"); + // let adapter_index = 12; + warn!("Adapter index: {adapter_index}"); let _out_params = services.ExecMethod( - &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Description=\"{}\"", interface_name)), + // &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Description=\"{}\"", interface_name)), + // &BSTR::from(format!("Win32_NetworkAdapterConfiguration.NetConnectionID=\"{}\"", interface_name)), + // &BSTR::from(format!("Win32_NetworkAdapter.GUID=\"{{{:?}}}\"", guid)), + &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Index={adapter_index}")), &BSTR::from("SetMTU"), WBEM_GENERIC_FLAG_TYPE(0), None, &in_params, None, None, - )?; + ).expect("failed to services.ExecMethod()"); CoUninitialize(); } @@ -374,6 +566,26 @@ fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> Ok(()) } +fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { + let if_index = get_adapter_index(adapter_name).expect("failed to get_adapter_index()"); + let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; + row.dwIndex = if_index; + + let res = unsafe { GetIfEntry(&mut row) }; + if res != 0 { + return Err(WindowsError::NonZeroReturnValue(res)); + } + + row.dwMtu = mtu; + + let res = unsafe { SetIfEntry(&row) }; + if res != 0 { + return Err(WindowsError::NonZeroReturnValue(res)); + } + + Ok(()) +} + impl From for Peer { fn from(peer: wireguard_nt::WireguardPeer) -> Self { Self { @@ -516,8 +728,14 @@ impl WireguardInterfaceApi for WGApi { // set_interface_mtu(&self.ifname, mtu)?; // let mtu = config.mtu.unwrap_or(1500); let mtu = 1300; - set_mtu_via_wmi(&self.ifname, mtu).unwrap(); + set_interface_mtu(&self.ifname, mtu).expect("failed to set_interface_mtu()"); + // restart_adapter_via_wmi(&self.ifname).expect("restart_adapter_via_wmi failed"); + adapter.down().map_err(WindowsError::from)?; adapter.up().map_err(WindowsError::from)?; + // adapter.down().map_err(WindowsError::from)?; + // adapter.up().map_err(WindowsError::from)?; + // set_mtu_via_wmi(&self.ifname, mtu).expect("set_mtu_via_wmi failed"); + // restart_adapter_via_wmi(&self.ifname).expect("restart_adapter_via_wmi failed"); info!( "Interface {} has been successfully configured.", From 88b0ca884cdcf8997c6a08af8386243aa6fcdc83 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 01:47:22 -0800 Subject: [PATCH 3/9] cleanup --- Cargo.lock | 12 +- src/wgapi_windows.rs | 424 ++----------------------------------------- 2 files changed, 22 insertions(+), 414 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc83b8e..fd14d6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.44" +version = "1.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" +checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" dependencies = [ "find-msvc-tools", "shlex", @@ -914,9 +914,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -1182,9 +1182,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index 8ca9eff..e0b9ba5 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -1,5 +1,10 @@ use std::{ - collections::HashMap, ffi::OsStr, net::IpAddr, os::windows::ffi::OsStrExt, ptr::{null, null_mut}, str::FromStr, sync::{LazyLock, Mutex} + collections::HashMap, + ffi::OsStr, + net::IpAddr, + os::windows::ffi::OsStrExt, + str::FromStr, + sync::{LazyLock, Mutex}, }; use ipnet::{IpNet, Ipv4Net, Ipv6Net}; @@ -8,10 +13,12 @@ use windows::{ Win32::{ Foundation::{ERROR_BUFFER_OVERFLOW, NO_ERROR}, NetworkManagement::IpHelper::{ - DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIfEntry, IP_ADAPTER_ADDRESSES_LH, MIB_IFROW, SetIfEntry, SetInterfaceDnsSettings + DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, + DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIfEntry, + IP_ADAPTER_ADDRESSES_LH, MIB_IFROW, SetIfEntry, SetInterfaceDnsSettings, }, Networking::WinSock::AF_UNSPEC, - System::{Com::CLSIDFromString, Rpc::{RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE}, Variant::{VARIANT, VT_I4}, Wmi::{IWbemCallResult, IWbemClassObject, WBEM_GENERIC_FLAG_TYPE}}, + System::Com::CLSIDFromString, }, core::{GUID, PCSTR, PCWSTR, PSTR}, }; @@ -172,400 +179,6 @@ fn get_adapter_guid(adapter_name: &str) -> Result { guid.ok_or_else(|| WindowsError::AdapterNotFound(adapter_name.to_string())) } -// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { -// // Find interface index via GetAdaptersAddresses -// debug!("set_interface_mtu: before get_adapter_buid"); -// let guid = get_adapter_guid(adapter_name)?; -// debug!("set_interface_mtu: after get_adapter_buid"); - -// // Convert GUID to string without braces -// let guid_str = format!("{:?}", guid); -// let guid_str = guid_str.trim_matches(['{', '}']); - -// // Initialize MIB_IFROW with interface name -// debug!("set_interface_mtu: before MIB_IFROW init"); -// let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; -// // Wide string name (null terminated) -// let name_wide = str_to_wide_null_terminated(guid_str); -// row.wszName[..name_wide.len()].copy_from_slice(&name_wide); -// debug!("set_interface_mtu: after MIB_IFROW init"); - -// // Get current entry to populate the row fields -// // TODO use NO_ERROR -// debug!("set_interface_mtu: before GetIfEntry"); -// let res = unsafe { GetIfEntry(&mut row) }; -// if res != 0 { -// error!("Failed to get current interface entry"); -// return Err(WindowsError::NonZeroReturnValue(res)); -// } -// debug!("set_interface_mtu: after GetIfEntry"); - -// // Update MTU -// row.dwMtu = mtu; - -// // Commit change -// // TODO use NO_ERROR -// debug!("set_interface_mtu: before SetIfEntry"); -// let res = unsafe { SetIfEntry(&row) }; -// if res != 0 { -// error!("Failed to set current interface entry"); -// return Err(WindowsError::NonZeroReturnValue(res)); -// } -// debug!("set_interface_mtu: after SetIfEntry"); - -// Ok(()) -// } - -// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { -// let if_index = get_adapter_index(adapter_name)?; -// let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; -// row.dwIndex = if_index; - -// let res = unsafe { GetIfEntry(&mut row) }; -// if res != 0 { -// return Err(WindowsError::NonZeroReturnValue(res)); -// } - -// row.dwMtu = mtu; -// let res = unsafe { SetIfEntry(&row) }; -// if res != 0 { -// return Err(WindowsError::NonZeroReturnValue(res)); -// } - -// Ok(()) -// } - -use windows::{ - // core::{BSTR, VARIANT, HRESULT}, - core::{BSTR, HRESULT}, - Win32::{ - // Foundation::WBEM_E_NOT_FOUND, - System::{ - Com::{ - CoInitializeEx, CoCreateInstance, CoUninitialize, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED, - // VARIANT_TRUE, VT_I4, VT_BSTR, VT_NULL, - }, - // Ole::VariantInit, - Wmi::{ - IWbemLocator, IWbemServices, WbemLocator, WBEM_FLAG_FORWARD_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, - WBEM_INFINITE, - }, - }, - }, -}; - -fn restart_adapter_via_wmi(interface_name: &str) -> windows::core::Result<()> { - unsafe { - // Connect to WMI just like in your set_mtu_via_wmi - use windows::Win32::System::Com::{ - CoInitializeEx, CoCreateInstance, CoUninitialize, CLSCTX_INPROC_SERVER, - COINIT_APARTMENTTHREADED, CoSetProxyBlanket, - }; - use windows::Win32::System::Rpc::{RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE}; - use windows::Win32::System::Wmi::{ - IWbemLocator, IWbemServices, WbemLocator, WBEM_FLAG_FORWARD_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, - WBEM_INFINITE, - }; - use windows::Win32::System::Com::{ - RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_LEVEL_DEFAULT, EOAC_NONE, - }; - use windows::core::BSTR; - - CoInitializeEx(None, COINIT_APARTMENTTHREADED).unwrap(); - - let locator: IWbemLocator = CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER).expect("Failed to CoCreateInstance()"); - let empty = BSTR::new(); - let services: IWbemServices = locator.ConnectServer( - &BSTR::from("ROOT\\CIMV2"), - &empty, &empty, &empty, - 0, &empty, None, - ).expect("Failed to locator.ConnectServer()"); - - CoSetProxyBlanket( - &services, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - None, - RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, - None, - EOAC_NONE, - )?; - - // Find the adapter - let query = format!("SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionID='{}'", interface_name); - let enumerator = services.ExecQuery( - &BSTR::from("WQL"), - &BSTR::from(query), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - None, - ).expect("Failed to services.ExecQuery()"); - - let mut objs = [None]; - let mut returned = 0; - enumerator.Next(WBEM_INFINITE as i32, &mut objs, &mut returned).unwrap(); - if returned == 0 { - CoUninitialize(); - return Err(HRESULT(0).into()); - } - let adapter = objs[0].take().unwrap(); - - // Disable it - let adapter_index = 12; - let adapter_index = get_adapter_index(interface_name).expect("Failed to get_adapter_index()"); - warn!("adapter_index: {adapter_index}"); - warn!("disabling adapter"); - services.ExecMethod( - // &BSTR::from(format!("Win32_NetworkAdapter.NetConnectionID=\"{}\"", interface_name)), - // &BSTR::from(format!("Win32_NetworkAdapter.Index={adapter_index}")), - // &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Index={adapter_index}")), - &BSTR::from(format!("Win32_NetworkAdapter.Index={adapter_index}")), - &BSTR::from("Disable"), - WBEM_GENERIC_FLAG_TYPE(0), - None, - None, - None, - None, - // ).expect("Failed to disable interface"); - ); - - // Wait briefly for the device to go down - std::thread::sleep(std::time::Duration::from_secs(1)); - - // Enable it again - warn!("enabling adapter"); - services.ExecMethod( - &BSTR::from(format!("Win32_NetworkAdapter.Index={adapter_index}")), - &BSTR::from("Enable"), - WBEM_GENERIC_FLAG_TYPE(0), - None, - None, - None, - None, - // ).expect("Failed to enable interface"); - ); - - warn!("uninitializing"); - // CoUninitialize(); - } - - warn!("done"); - Ok(()) -} - -fn get_wmi_adapter_index_by_guid(interface_name: &str) -> windows::core::Result { - unsafe { - use windows::Win32::System::Com::{ - CoInitializeEx, CoCreateInstance, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED, - CoSetProxyBlanket, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, EOAC_NONE, - }; - use windows::Win32::System::Rpc::{RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE}; - use windows::Win32::System::Wmi::{IWbemLocator, IWbemServices, WbemLocator, - WBEM_FLAG_FORWARD_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_INFINITE}; - use windows::core::BSTR; - - let result = CoInitializeEx(None, COINIT_APARTMENTTHREADED); - if result.0 != 0 { - error!("Failed to CoInitializeEx()"); - return Err(HRESULT(0).into()); - } - let locator: IWbemLocator = CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER)?; - let empty = BSTR::new(); - let services: IWbemServices = locator.ConnectServer( - &BSTR::from("ROOT\\CIMV2"), - &empty, &empty, &empty, 0, &empty, None, - )?; - CoSetProxyBlanket( - &services, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - None, - RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, - None, - EOAC_NONE, - )?; - - let guid = get_adapter_guid(interface_name).expect("Failed to get_adapter_guid()"); - let guid_str = format!("{{{:?}}}", guid); - let query = format!( - "SELECT Index FROM Win32_NetworkAdapterConfiguration WHERE SettingID='{}'", - guid_str - ); - - let enumerator = services.ExecQuery( - &BSTR::from("WQL"), - &BSTR::from(query), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - None, - )?; - - let mut objs = [None]; - let mut returned = 0; - let result = enumerator.Next(WBEM_INFINITE as i32, &mut objs, &mut returned); - if returned == 0 || result.0 != 0 { - error!("enumerator.Next error"); - // return Err(windows::core::Error::new( - // windows::core::HRESULT(0x80041002), - // "Adapter not found".into(), - // )); - return Err(HRESULT(0).into()); - } - let obj = objs[0].take().unwrap(); - let mut variant = VARIANT::default(); - let result = obj.Get(&BSTR::from("Index"), 0, &mut variant, None, None).expect("Failed to obj.Get()"); - let index = variant.Anonymous.Anonymous.Anonymous.lVal; - // let index = unsafe { variant.Anonymous.Anonymous.lVal }; // safe because VT_I4 - // if variant.vt() == VT_I4 { - - // } - // let index = unsafe { variant.Anonymous.Anonymous.lVal() }; // safe because VT_I4 - // let index = i32::try_from(variant).expect("Failed to i32::try_from(variant)"); - Ok(index) - } -} - -fn set_mtu_via_wmi(interface_name: &str, mtu: u32) -> windows::core::Result<()> { - unsafe { - // Initialize COM - CoInitializeEx(None, COINIT_APARTMENTTHREADED).unwrap(); - - // Create WMI locator - // let locator: IWbemLocator = CoCreateInstance(&CLSID_WbemLocator, None, CLSCTX_INPROC_SERVER)?; - let locator: IWbemLocator = CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER)?; - - // Connect to WMI namespace - let empty = BSTR::new(); - let services: IWbemServices = locator.ConnectServer( - &BSTR::from("ROOT\\CIMV2"), - &empty, - &empty, - &empty, - 0, - &empty, - None, - )?; - - use windows::Win32::System::Com::{ - CoSetProxyBlanket, RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, EOAC_NONE, - }; - - CoSetProxyBlanket( - &services, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - None, - RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, - None, - EOAC_NONE, - )?; - - // Build WQL query - // let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Description = '{}'", interface_name); - let guid = get_adapter_guid(interface_name).expect("set_mtu failed to get_adapter_guid"); - // let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE GUID = '{{{:?}}}'", guid); - let query = format!("SELECT * FROM Win32_NetworkAdapter WHERE GUID = '{{{:?}}}'", guid); - // let query = format!("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE NetConnectionID='{}'", interface_name); - - // let mut enumerator = None; - warn!("Before enumerator"); - let enumerator = services.ExecQuery( - &BSTR::from("WQL"), - &BSTR::from(query), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - None, - // &mut enumerator, - )?; - warn!("After enumerator"); - - let mut objs = [None]; - let mut returned = 0; - let hr = enumerator.Next(WBEM_INFINITE as i32, &mut objs, &mut returned); - warn!("After enumerator.Next"); - - // if hr.is_err() || returned == 0 { - if returned == 0 { - error!("No adapter found for {interface_name}"); - return Err(HRESULT(0).into()); - } - if hr.is_err() { - CoUninitialize(); - // return Err(HRESULT(WBEM_E_NOT_FOUND.0).into()); - error!("hr: {hr}, returned: {returned}"); - return Err(HRESULT(0).into()); - } - - let adapter = objs[0].take().expect("objs[0] is None"); - warn!("After objs[0].take()"); - - // Prepare input parameters for SetMTU - // let class_obj = Some(null_mut()); - let mut class_obj: Option = None; - let result = services.GetObject( - &BSTR::from("Win32_NetworkAdapterConfiguration"), - // &BSTR::from("Win32_NetworkAdapter"), - WBEM_GENERIC_FLAG_TYPE(0), - None, - Some(&mut class_obj), - None, - ); - if result.is_err() { - error!("GetObject result: {result:?}"); - return Err(HRESULT(0).into()); - } - // let in_params_def = null_mut(); - // let result = class_obj.unwrap().GetMethod( - // &BSTR::from("SetMTU"), - // 0, - // in_params_def, - // null_mut(), - // )?; - // let in_params = (*in_params_def).unwrap().SpawnInstance(0)?; - - // let mut mtu_variant = VARIANT::default(); - // *mtu_variant.n1.n2_mut().n3.lVal_mut() = mtu as i32; - // mtu_variant.n1.n2_mut().vt = VT_I4.0 as u16; - let mut in_params_def= None; - - // Call GetMethod to fill it - class_obj.expect("class_obj is None").GetMethod( - &BSTR::from("SetMTU"), - 0, - &mut in_params_def, - &mut None, - ).expect("failed to GetMethod"); - let in_params = in_params_def.unwrap(); - use windows::Win32::System::Variant::{self, VARIANT, VT_I4}; - // use windows::core::VARIANT as CoreVariant; - - let mtu: i32 = 1380; - let mtu_variant = VARIANT::from(mtu as i32); - in_params.Put(&BSTR::from("MTU"), 0, &mtu_variant, 0).expect("Failed to in_params.Put()"); - // Execute method - let adapter_index = get_adapter_index(interface_name).expect("Failed to get_adapter_index()"); - // let adapter_index = 12; - warn!("Adapter index: {adapter_index}"); - let _out_params = services.ExecMethod( - // &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Description=\"{}\"", interface_name)), - // &BSTR::from(format!("Win32_NetworkAdapterConfiguration.NetConnectionID=\"{}\"", interface_name)), - // &BSTR::from(format!("Win32_NetworkAdapter.GUID=\"{{{:?}}}\"", guid)), - &BSTR::from(format!("Win32_NetworkAdapterConfiguration.Index={adapter_index}")), - &BSTR::from("SetMTU"), - WBEM_GENERIC_FLAG_TYPE(0), - None, - &in_params, - None, - None, - ).expect("failed to services.ExecMethod()"); - - CoUninitialize(); - } - - Ok(()) -} - fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { let if_index = get_adapter_index(adapter_name).expect("failed to get_adapter_index()"); let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; @@ -725,18 +338,13 @@ impl WireguardInterfaceApi for WGApi { debug!("Bringing up adapter {}", self.ifname); // Set MTU - // set_interface_mtu(&self.ifname, mtu)?; - // let mtu = config.mtu.unwrap_or(1500); - let mtu = 1300; - set_interface_mtu(&self.ifname, mtu).expect("failed to set_interface_mtu()"); - // restart_adapter_via_wmi(&self.ifname).expect("restart_adapter_via_wmi failed"); - adapter.down().map_err(WindowsError::from)?; - adapter.up().map_err(WindowsError::from)?; - // adapter.down().map_err(WindowsError::from)?; - // adapter.up().map_err(WindowsError::from)?; - // set_mtu_via_wmi(&self.ifname, mtu).expect("set_mtu_via_wmi failed"); - // restart_adapter_via_wmi(&self.ifname).expect("restart_adapter_via_wmi failed"); + if let Some(mtu) = config.mtu { + set_interface_mtu(&self.ifname, mtu).expect("failed to set_interface_mtu()"); + // Turn it off and on again + adapter.down().map_err(WindowsError::from)?; + } + adapter.up().map_err(WindowsError::from)?; info!( "Interface {} has been successfully configured.", self.ifname From 2c4db99b44a1c4c3743aa578e14a8dd63fc5e826 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 04:00:43 -0800 Subject: [PATCH 4/9] fix ipv6 mtu --- src/wgapi_windows.rs | 172 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 155 insertions(+), 17 deletions(-) diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index e0b9ba5..25cf0a6 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -17,7 +17,7 @@ use windows::{ DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIfEntry, IP_ADAPTER_ADDRESSES_LH, MIB_IFROW, SetIfEntry, SetInterfaceDnsSettings, }, - Networking::WinSock::AF_UNSPEC, + Networking::WinSock::{ADDRESS_FAMILY, AF_INET6, AF_UNSPEC}, System::Com::CLSIDFromString, }, core::{GUID, PCSTR, PCWSTR, PSTR}, @@ -179,21 +179,157 @@ fn get_adapter_guid(adapter_name: &str) -> Result { guid.ok_or_else(|| WindowsError::AdapterNotFound(adapter_name.to_string())) } -fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { - let if_index = get_adapter_index(adapter_name).expect("failed to get_adapter_index()"); - let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; - row.dwIndex = if_index; +// use windows::Win32::Foundation::NO_ERROR; +use windows::Win32::NetworkManagement::IpHelper::{ + GetIpInterfaceEntry, MIB_IPINTERFACE_ROW, SetIpInterfaceEntry, +}; - let res = unsafe { GetIfEntry(&mut row) }; - if res != 0 { - return Err(WindowsError::NonZeroReturnValue(res)); +// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { +// let if_index = get_adapter_index(adapter_name)?; + +// // Set for IPv4 +// let mut row_ipv4: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; +// // row_ipv4.Family = AF_INET; +// row_ipv4.InterfaceIndex = if_index; +// let res = unsafe { GetIpInterfaceEntry(&mut row_ipv4) }; +// if res != NO_ERROR { +// return Err(WindowsError::NonZeroReturnValue(res.0)); +// } +// row_ipv4.NlMtu = mtu; +// let res = unsafe { SetIpInterfaceEntry(&mut row_ipv4) }; +// if res != NO_ERROR { +// return Err(WindowsError::NonZeroReturnValue(res.0)); +// } + +// // // Set for IPv6 (skip if not enabled) +// // let mut row_ipv6: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; +// // row_ipv6.Family = AF_INET6; +// // row_ipv6.InterfaceIndex = if_index; +// // let res = unsafe { GetIpInterfaceEntry(&mut row_ipv6) }; +// // if res != NO_ERROR { +// // // IPv6 may not be enabled; handle accordingly (here: skip silently) +// // // return Err(WindowsError::NonZeroReturnValue(res)); +// // } else { +// // row_ipv6.Mtu = mtu; +// // let res = unsafe { SetIpInterfaceEntry(&row_ipv6) }; +// // if res != NO_ERROR { +// // return Err(WindowsError::NonZeroReturnValue(res)); +// // } +// // } + +// Ok(()) + +// // let if_index = get_adapter_index(adapter_name)?; + +// // // Set for IPv4 +// // // let mut row_ipv4: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; +// // let mut row_ipv4 = MIB_IPINTERFACE_ROW::default(); +// // // row_ipv4.Family = AF_INET; +// // row_ipv4.InterfaceIndex = if_index; +// // let res = unsafe { GetIpInterfaceEntry(&mut row_ipv4) }; +// // if res != NO_ERROR { +// // error!("Failed to GetIpInterfaceEntry: {}", res.0); +// // return Err(WindowsError::NonZeroReturnValue(res.0)); +// // } +// // row_ipv4.NlMtu = mtu; +// // let res = unsafe { SetIpInterfaceEntry(&mut row_ipv4) }; +// // if res != NO_ERROR { +// // error!("Failed to SetIpInterfaceEntry: {}", res.0); +// // return Err(WindowsError::NonZeroReturnValue(res.0)); +// // } + +// // // // Set for IPv6 (skip if not enabled) +// // // let mut row_ipv6: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; +// // // row_ipv6.Family = AF_INET6; +// // // row_ipv6.InterfaceIndex = if_index; +// // // let res = unsafe { GetIpInterfaceEntry(&mut row_ipv6) }; +// // // if res != NO_ERROR { +// // // error!("Non-zero result: {}", res.0); +// // // // IPv6 may not be enabled; handle accordingly (here: skip silently) +// // // // return Err(WindowsError::NonZeroReturnValue(res)); +// // // } else { +// // // warn!("Setting ipv6 mtu"); +// // // row_ipv6.NlMtu = mtu; +// // // let res = unsafe { SetIpInterfaceEntry(&mut row_ipv6) }; +// // // if res != NO_ERROR { +// // // return Err(WindowsError::NonZeroReturnValue(res.0)); +// // // } +// // // } + +// // Ok(()) +// } + +// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { +// let if_index = get_adapter_index(adapter_name).expect("failed to get_adapter_index()"); +// let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; +// row.dwIndex = if_index; + +// let res = unsafe { GetIfEntry(&mut row) }; +// if res != 0 { +// return Err(WindowsError::NonZeroReturnValue(res)); +// } + +// row.dwMtu = mtu; + +// let res = unsafe { SetIfEntry(&row) }; +// if res != 0 { +// return Err(WindowsError::NonZeroReturnValue(res)); +// } + +// Ok(()) +// } + +use windows::Win32::NetworkManagement::IpHelper::{ + ConvertInterfaceIndexToLuid, InitializeIpInterfaceEntry, + // GetIpInterfaceEntry, SetIpInterfaceEntry, MIB_IPINTERFACE_ROW, +}; +use windows::Win32::Networking::WinSock::{AF_INET}; +use windows::Win32::NetworkManagement::Ndis::NET_LUID_LH; +// use windows::Win32::Foundation::NO_ERROR; + +fn set_interface_mtu_both_stacks(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { + // 1) Get the interface index (you already have this helper) + let if_index = get_adapter_index(adapter_name)?; + + // 2) Convert to LUID (preferred identifier for IP Interface APIs) + let mut luid = NET_LUID_LH::default(); + let res = unsafe { ConvertInterfaceIndexToLuid(if_index, &mut luid) }; + if res.0 != 0 { + return Err(WindowsError::NonZeroReturnValue(res.0)); } - row.dwMtu = mtu; + // helper to do one family + unsafe fn set_mtu_for_family( + luid: NET_LUID_LH, + family: u16, // ADDRESS_FAMILY + mtu: u32, + ) -> Result<(), WindowsError> { + let mut row: MIB_IPINTERFACE_ROW = MIB_IPINTERFACE_ROW::default(); + // MUST call Initialize before Get/Set + let family = ADDRESS_FAMILY(family); + InitializeIpInterfaceEntry(&mut row); + row.InterfaceLuid = luid; + row.Family = family; + + // Load current, then modify + let res = GetIpInterfaceEntry(&mut row); + if res.0 != 0 { + return Err(WindowsError::NonZeroReturnValue(res.0)); + } + + row.NlMtu = mtu; + + let res = SetIpInterfaceEntry(&mut row); + if res.0 != 0 { + return Err(WindowsError::NonZeroReturnValue(res.0)); + } + Ok(()) + } - let res = unsafe { SetIfEntry(&row) }; - if res != 0 { - return Err(WindowsError::NonZeroReturnValue(res)); + // 3) Apply for IPv4 and IPv6 + unsafe { + set_mtu_for_family(luid, AF_INET.0 as u16, mtu)?; + set_mtu_for_family(luid, AF_INET6.0 as u16, mtu)?; } Ok(()) @@ -338,11 +474,13 @@ impl WireguardInterfaceApi for WGApi { debug!("Bringing up adapter {}", self.ifname); // Set MTU - if let Some(mtu) = config.mtu { - set_interface_mtu(&self.ifname, mtu).expect("failed to set_interface_mtu()"); - // Turn it off and on again - adapter.down().map_err(WindowsError::from)?; - } + set_interface_mtu_both_stacks(&self.ifname, 1300)?; + adapter.down().map_err(WindowsError::from)?; + // if let Some(mtu) = config.mtu { + // set_interface_mtu(&self.ifname, mtu)?; + // // Turn it off and on again + // adapter.down().map_err(WindowsError::from)?; + // } adapter.up().map_err(WindowsError::from)?; info!( From 4b1552e406863b418757b07b526c37430d619048 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 04:24:52 -0800 Subject: [PATCH 5/9] cleanup --- src/wgapi_windows.rs | 161 ++++++++----------------------------------- 1 file changed, 27 insertions(+), 134 deletions(-) diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index 25cf0a6..7333f45 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -12,12 +12,10 @@ use thiserror::Error; use windows::{ Win32::{ Foundation::{ERROR_BUFFER_OVERFLOW, NO_ERROR}, - NetworkManagement::IpHelper::{ - DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, - DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIfEntry, - IP_ADAPTER_ADDRESSES_LH, MIB_IFROW, SetIfEntry, SetInterfaceDnsSettings, - }, - Networking::WinSock::{ADDRESS_FAMILY, AF_INET6, AF_UNSPEC}, + NetworkManagement::{IpHelper::{ + ConvertInterfaceIndexToLuid, DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIpInterfaceEntry, IP_ADAPTER_ADDRESSES_LH, InitializeIpInterfaceEntry, MIB_IPINTERFACE_ROW, SetInterfaceDnsSettings, SetIpInterfaceEntry + }, Ndis::NET_LUID_LH}, + Networking::WinSock::{ADDRESS_FAMILY, AF_INET, AF_INET6, AF_UNSPEC}, System::Com::CLSIDFromString, }, core::{GUID, PCSTR, PCWSTR, PSTR}, @@ -179,159 +177,54 @@ fn get_adapter_guid(adapter_name: &str) -> Result { guid.ok_or_else(|| WindowsError::AdapterNotFound(adapter_name.to_string())) } -// use windows::Win32::Foundation::NO_ERROR; -use windows::Win32::NetworkManagement::IpHelper::{ - GetIpInterfaceEntry, MIB_IPINTERFACE_ROW, SetIpInterfaceEntry, -}; - -// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { -// let if_index = get_adapter_index(adapter_name)?; - -// // Set for IPv4 -// let mut row_ipv4: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; -// // row_ipv4.Family = AF_INET; -// row_ipv4.InterfaceIndex = if_index; -// let res = unsafe { GetIpInterfaceEntry(&mut row_ipv4) }; -// if res != NO_ERROR { -// return Err(WindowsError::NonZeroReturnValue(res.0)); -// } -// row_ipv4.NlMtu = mtu; -// let res = unsafe { SetIpInterfaceEntry(&mut row_ipv4) }; -// if res != NO_ERROR { -// return Err(WindowsError::NonZeroReturnValue(res.0)); -// } - -// // // Set for IPv6 (skip if not enabled) -// // let mut row_ipv6: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; -// // row_ipv6.Family = AF_INET6; -// // row_ipv6.InterfaceIndex = if_index; -// // let res = unsafe { GetIpInterfaceEntry(&mut row_ipv6) }; -// // if res != NO_ERROR { -// // // IPv6 may not be enabled; handle accordingly (here: skip silently) -// // // return Err(WindowsError::NonZeroReturnValue(res)); -// // } else { -// // row_ipv6.Mtu = mtu; -// // let res = unsafe { SetIpInterfaceEntry(&row_ipv6) }; -// // if res != NO_ERROR { -// // return Err(WindowsError::NonZeroReturnValue(res)); -// // } -// // } - -// Ok(()) - -// // let if_index = get_adapter_index(adapter_name)?; - -// // // Set for IPv4 -// // // let mut row_ipv4: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; -// // let mut row_ipv4 = MIB_IPINTERFACE_ROW::default(); -// // // row_ipv4.Family = AF_INET; -// // row_ipv4.InterfaceIndex = if_index; -// // let res = unsafe { GetIpInterfaceEntry(&mut row_ipv4) }; -// // if res != NO_ERROR { -// // error!("Failed to GetIpInterfaceEntry: {}", res.0); -// // return Err(WindowsError::NonZeroReturnValue(res.0)); -// // } -// // row_ipv4.NlMtu = mtu; -// // let res = unsafe { SetIpInterfaceEntry(&mut row_ipv4) }; -// // if res != NO_ERROR { -// // error!("Failed to SetIpInterfaceEntry: {}", res.0); -// // return Err(WindowsError::NonZeroReturnValue(res.0)); -// // } - -// // // // Set for IPv6 (skip if not enabled) -// // // let mut row_ipv6: MIB_IPINTERFACE_ROW = unsafe { std::mem::zeroed() }; -// // // row_ipv6.Family = AF_INET6; -// // // row_ipv6.InterfaceIndex = if_index; -// // // let res = unsafe { GetIpInterfaceEntry(&mut row_ipv6) }; -// // // if res != NO_ERROR { -// // // error!("Non-zero result: {}", res.0); -// // // // IPv6 may not be enabled; handle accordingly (here: skip silently) -// // // // return Err(WindowsError::NonZeroReturnValue(res)); -// // // } else { -// // // warn!("Setting ipv6 mtu"); -// // // row_ipv6.NlMtu = mtu; -// // // let res = unsafe { SetIpInterfaceEntry(&mut row_ipv6) }; -// // // if res != NO_ERROR { -// // // return Err(WindowsError::NonZeroReturnValue(res.0)); -// // // } -// // // } - -// // Ok(()) -// } - -// fn set_interface_mtu(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { -// let if_index = get_adapter_index(adapter_name).expect("failed to get_adapter_index()"); -// let mut row: MIB_IFROW = unsafe { std::mem::zeroed() }; -// row.dwIndex = if_index; - -// let res = unsafe { GetIfEntry(&mut row) }; -// if res != 0 { -// return Err(WindowsError::NonZeroReturnValue(res)); -// } - -// row.dwMtu = mtu; - -// let res = unsafe { SetIfEntry(&row) }; -// if res != 0 { -// return Err(WindowsError::NonZeroReturnValue(res)); -// } - -// Ok(()) -// } - -use windows::Win32::NetworkManagement::IpHelper::{ - ConvertInterfaceIndexToLuid, InitializeIpInterfaceEntry, - // GetIpInterfaceEntry, SetIpInterfaceEntry, MIB_IPINTERFACE_ROW, -}; -use windows::Win32::Networking::WinSock::{AF_INET}; -use windows::Win32::NetworkManagement::Ndis::NET_LUID_LH; -// use windows::Win32::Foundation::NO_ERROR; - -fn set_interface_mtu_both_stacks(adapter_name: &str, mtu: u32) -> Result<(), WindowsError> { - // 1) Get the interface index (you already have this helper) - let if_index = get_adapter_index(adapter_name)?; +/// Sets both IPv4 and IPv6 MTU on specified interface. +fn set_interface_mtu(interface_name: &str, mtu: u32) -> Result<(), WindowsError> { + debug!("Setting interface {interface_name} MTU to {mtu}"); + let if_index = get_adapter_index(interface_name)?; - // 2) Convert to LUID (preferred identifier for IP Interface APIs) + // Convert interface index to LUID. let mut luid = NET_LUID_LH::default(); let res = unsafe { ConvertInterfaceIndexToLuid(if_index, &mut luid) }; if res.0 != 0 { + error!("ConvertInterfaceIndexToLuid call failed, error value: {}", res.0); return Err(WindowsError::NonZeroReturnValue(res.0)); } - // helper to do one family - unsafe fn set_mtu_for_family( + // Helper function, sets MTU for given IP family. + fn set_mtu_for_family( luid: NET_LUID_LH, - family: u16, // ADDRESS_FAMILY + family: u16, mtu: u32, ) -> Result<(), WindowsError> { - let mut row: MIB_IPINTERFACE_ROW = MIB_IPINTERFACE_ROW::default(); - // MUST call Initialize before Get/Set + let mut row = MIB_IPINTERFACE_ROW::default(); + // InitializeIpInterfaceEntry has to be called before get/set operations. let family = ADDRESS_FAMILY(family); - InitializeIpInterfaceEntry(&mut row); + unsafe {InitializeIpInterfaceEntry(&mut row) }; row.InterfaceLuid = luid; row.Family = family; - // Load current, then modify - let res = GetIpInterfaceEntry(&mut row); + // Load current configuration. + let res = unsafe { GetIpInterfaceEntry(&mut row) }; if res.0 != 0 { + error!("GetIpInterfaceEntry call failed, error value: {}", res.0); return Err(WindowsError::NonZeroReturnValue(res.0)); } + // Modify the configuration and apply. row.NlMtu = mtu; - - let res = SetIpInterfaceEntry(&mut row); + let res = unsafe { SetIpInterfaceEntry(&mut row) }; if res.0 != 0 { + error!("SetIpInterfaceEntry call failed, error value: {}", res.0); return Err(WindowsError::NonZeroReturnValue(res.0)); } Ok(()) } - // 3) Apply for IPv4 and IPv6 - unsafe { - set_mtu_for_family(luid, AF_INET.0 as u16, mtu)?; - set_mtu_for_family(luid, AF_INET6.0 as u16, mtu)?; - } + // Set MTU for both IP addr families. + set_mtu_for_family(luid, AF_INET.0, mtu)?; + set_mtu_for_family(luid, AF_INET6.0, mtu)?; + info!("Set interface {interface_name} MTU to {mtu}"); Ok(()) } @@ -474,7 +367,7 @@ impl WireguardInterfaceApi for WGApi { debug!("Bringing up adapter {}", self.ifname); // Set MTU - set_interface_mtu_both_stacks(&self.ifname, 1300)?; + set_interface_mtu(&self.ifname, 1300)?; adapter.down().map_err(WindowsError::from)?; // if let Some(mtu) = config.mtu { // set_interface_mtu(&self.ifname, mtu)?; From 22a0ff3083f9fe126f90d06b59fc636b7bacecbf Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 04:25:11 -0800 Subject: [PATCH 6/9] cargo fmt --- src/wgapi_windows.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index 7333f45..d63a17c 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -12,9 +12,16 @@ use thiserror::Error; use windows::{ Win32::{ Foundation::{ERROR_BUFFER_OVERFLOW, NO_ERROR}, - NetworkManagement::{IpHelper::{ - ConvertInterfaceIndexToLuid, DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIpInterfaceEntry, IP_ADAPTER_ADDRESSES_LH, InitializeIpInterfaceEntry, MIB_IPINTERFACE_ROW, SetInterfaceDnsSettings, SetIpInterfaceEntry - }, Ndis::NET_LUID_LH}, + NetworkManagement::{ + IpHelper::{ + ConvertInterfaceIndexToLuid, DNS_INTERFACE_SETTINGS, + DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, DNS_SETTING_NAMESERVER, + GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIpInterfaceEntry, + IP_ADAPTER_ADDRESSES_LH, InitializeIpInterfaceEntry, MIB_IPINTERFACE_ROW, + SetInterfaceDnsSettings, SetIpInterfaceEntry, + }, + Ndis::NET_LUID_LH, + }, Networking::WinSock::{ADDRESS_FAMILY, AF_INET, AF_INET6, AF_UNSPEC}, System::Com::CLSIDFromString, }, @@ -186,20 +193,19 @@ fn set_interface_mtu(interface_name: &str, mtu: u32) -> Result<(), WindowsError> let mut luid = NET_LUID_LH::default(); let res = unsafe { ConvertInterfaceIndexToLuid(if_index, &mut luid) }; if res.0 != 0 { - error!("ConvertInterfaceIndexToLuid call failed, error value: {}", res.0); + error!( + "ConvertInterfaceIndexToLuid call failed, error value: {}", + res.0 + ); return Err(WindowsError::NonZeroReturnValue(res.0)); } // Helper function, sets MTU for given IP family. - fn set_mtu_for_family( - luid: NET_LUID_LH, - family: u16, - mtu: u32, - ) -> Result<(), WindowsError> { + fn set_mtu_for_family(luid: NET_LUID_LH, family: u16, mtu: u32) -> Result<(), WindowsError> { let mut row = MIB_IPINTERFACE_ROW::default(); // InitializeIpInterfaceEntry has to be called before get/set operations. let family = ADDRESS_FAMILY(family); - unsafe {InitializeIpInterfaceEntry(&mut row) }; + unsafe { InitializeIpInterfaceEntry(&mut row) }; row.InterfaceLuid = luid; row.Family = family; @@ -221,7 +227,7 @@ fn set_interface_mtu(interface_name: &str, mtu: u32) -> Result<(), WindowsError> } // Set MTU for both IP addr families. - set_mtu_for_family(luid, AF_INET.0, mtu)?; + set_mtu_for_family(luid, AF_INET.0, mtu)?; set_mtu_for_family(luid, AF_INET6.0, mtu)?; info!("Set interface {interface_name} MTU to {mtu}"); From bcc2124696ccc48a1d6895b1a565139ba9e8fb30 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 04:31:48 -0800 Subject: [PATCH 7/9] use guid instead of luid --- src/wgapi_windows.rs | 51 +++++--------------------------------------- 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index d63a17c..6faee50 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -14,7 +14,7 @@ use windows::{ Foundation::{ERROR_BUFFER_OVERFLOW, NO_ERROR}, NetworkManagement::{ IpHelper::{ - ConvertInterfaceIndexToLuid, DNS_INTERFACE_SETTINGS, + ConvertInterfaceGuidToLuid, DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIpInterfaceEntry, IP_ADAPTER_ADDRESSES_LH, InitializeIpInterfaceEntry, MIB_IPINTERFACE_ROW, @@ -77,47 +77,6 @@ fn guid_from_str(s: &str) -> Result { Ok(guid) } -fn get_adapter_index(adapter_name: &str) -> Result { - let mut buffer_size: u32 = 0; - unsafe { - GetAdaptersAddresses( - AF_UNSPEC.0 as u32, - GAA_FLAG_INCLUDE_PREFIX, - None, - None, - &mut buffer_size, - ) - }; - let mut buffer = vec![0u8; buffer_size as usize]; - let addresses = buffer.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH; - - let result = unsafe { - GetAdaptersAddresses( - AF_UNSPEC.0 as u32, - GAA_FLAG_INCLUDE_PREFIX, - None, - Some(addresses), - &mut buffer_size, - ) - }; - if result != 0 { - return Err(WindowsError::NonZeroReturnValue(result)); - } - - let mut current = addresses; - while !current.is_null() { - let adapter = unsafe { &*current }; - let friendly_name = unsafe { PCWSTR(adapter.FriendlyName.0).to_string()? }; - if friendly_name == adapter_name { - let if_index = unsafe { adapter.Anonymous1.Anonymous.IfIndex }; - return Ok(if_index); - } - current = adapter.Next; - } - - Err(WindowsError::AdapterNotFound(adapter_name.to_string())) -} - /// Returns the GUID of a network adapter given its name. /// Example adapter name: "Ethernet", "WireGuard". fn get_adapter_guid(adapter_name: &str) -> Result { @@ -187,14 +146,14 @@ fn get_adapter_guid(adapter_name: &str) -> Result { /// Sets both IPv4 and IPv6 MTU on specified interface. fn set_interface_mtu(interface_name: &str, mtu: u32) -> Result<(), WindowsError> { debug!("Setting interface {interface_name} MTU to {mtu}"); - let if_index = get_adapter_index(interface_name)?; + let guid = get_adapter_guid(interface_name)?; - // Convert interface index to LUID. + // Convert interface GUID to LUID. let mut luid = NET_LUID_LH::default(); - let res = unsafe { ConvertInterfaceIndexToLuid(if_index, &mut luid) }; + let res = unsafe { ConvertInterfaceGuidToLuid(&guid, &mut luid) }; if res.0 != 0 { error!( - "ConvertInterfaceIndexToLuid call failed, error value: {}", + "ConvertInterfaceGuidToLuid call failed, error value: {}", res.0 ); return Err(WindowsError::NonZeroReturnValue(res.0)); From 55e7e80caaba1defdfafd8084535fc1581d14e76 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 04:39:34 -0800 Subject: [PATCH 8/9] remove unused features, uncomment actual mtu configuration --- Cargo.toml | 6 ------ src/wgapi_windows.rs | 19 +++++++++---------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c11ac27..78d3c58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,12 +38,6 @@ windows = { version = "0.62", features = [ "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", "Win32_System_Com", - "Win32_System_Com_StructuredStorage", - "Win32_System_Rpc", - "Win32_System_Variant", - "Win32_System_Ole", - "Win32_System_Wmi", - "Win32_Foundation", ]} wireguard-nt = "0.5.0" diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index 6faee50..5f77fcc 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -270,6 +270,7 @@ impl WireguardInterfaceApi for WGApi { "Configuring interface {} with config: {config:?}", self.ifname ); + // Retrieve the adapter - should be created by calling `Self::create_interface` first. let Some(ref adapter) = self.adapter else { Err(WindowsError::AdapterNotFound(self.ifname.clone()))? @@ -328,19 +329,17 @@ impl WireguardInterfaceApi for WGApi { .set_default_route(&addresses, &interface) .map_err(WindowsError::from)?; - // Bring the adapter up - debug!("Bringing up adapter {}", self.ifname); - // Set MTU - set_interface_mtu(&self.ifname, 1300)?; - adapter.down().map_err(WindowsError::from)?; - // if let Some(mtu) = config.mtu { - // set_interface_mtu(&self.ifname, mtu)?; - // // Turn it off and on again - // adapter.down().map_err(WindowsError::from)?; - // } + if let Some(mtu) = config.mtu { + set_interface_mtu(&self.ifname, mtu)?; + // Turn it off and on again. + adapter.down().map_err(WindowsError::from)?; + } + // Bring the adapter up. + debug!("Bringing up adapter {}", self.ifname); adapter.up().map_err(WindowsError::from)?; + info!( "Interface {} has been successfully configured.", self.ifname From 6787b61e7020455c6d6b9d4152da48ff74c1cd33 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Fri, 7 Nov 2025 04:46:57 -0800 Subject: [PATCH 9/9] style tweak --- src/wgapi_windows.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/wgapi_windows.rs b/src/wgapi_windows.rs index 5f77fcc..0f2efa1 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -161,14 +161,13 @@ fn set_interface_mtu(interface_name: &str, mtu: u32) -> Result<(), WindowsError> // Helper function, sets MTU for given IP family. fn set_mtu_for_family(luid: NET_LUID_LH, family: u16, mtu: u32) -> Result<(), WindowsError> { - let mut row = MIB_IPINTERFACE_ROW::default(); // InitializeIpInterfaceEntry has to be called before get/set operations. - let family = ADDRESS_FAMILY(family); + let mut row = MIB_IPINTERFACE_ROW::default(); unsafe { InitializeIpInterfaceEntry(&mut row) }; - row.InterfaceLuid = luid; - row.Family = family; // Load current configuration. + row.InterfaceLuid = luid; + row.Family = ADDRESS_FAMILY(family); let res = unsafe { GetIpInterfaceEntry(&mut row) }; if res.0 != 0 { error!("GetIpInterfaceEntry call failed, error value: {}", res.0);