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 0633bf2..0f2efa1 100644 --- a/src/wgapi_windows.rs +++ b/src/wgapi_windows.rs @@ -1,6 +1,8 @@ use std::{ collections::HashMap, + ffi::OsStr, net::IpAddr, + os::windows::ffi::OsStrExt, str::FromStr, sync::{LazyLock, Mutex}, }; @@ -10,12 +12,17 @@ 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, - IP_ADAPTER_ADDRESSES_LH, SetInterfaceDnsSettings, + NetworkManagement::{ + IpHelper::{ + 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, + SetInterfaceDnsSettings, SetIpInterfaceEntry, + }, + Ndis::NET_LUID_LH, }, - Networking::WinSock::AF_UNSPEC, + Networking::WinSock::{ADDRESS_FAMILY, AF_INET, AF_INET6, AF_UNSPEC}, System::Com::CLSIDFromString, }, core::{GUID, PCSTR, PCWSTR, PSTR}, @@ -136,6 +143,55 @@ fn get_adapter_guid(adapter_name: &str) -> Result { guid.ok_or_else(|| WindowsError::AdapterNotFound(adapter_name.to_string())) } +/// 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 guid = get_adapter_guid(interface_name)?; + + // Convert interface GUID to LUID. + let mut luid = NET_LUID_LH::default(); + let res = unsafe { ConvertInterfaceGuidToLuid(&guid, &mut luid) }; + if res.0 != 0 { + error!( + "ConvertInterfaceGuidToLuid 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> { + // InitializeIpInterfaceEntry has to be called before get/set operations. + let mut row = MIB_IPINTERFACE_ROW::default(); + unsafe { InitializeIpInterfaceEntry(&mut row) }; + + // 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); + return Err(WindowsError::NonZeroReturnValue(res.0)); + } + + // Modify the configuration and apply. + row.NlMtu = mtu; + 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(()) + } + + // 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(()) +} + impl From for Peer { fn from(peer: wireguard_nt::WireguardPeer) -> Self { Self { @@ -173,7 +229,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. @@ -272,7 +328,14 @@ impl WireguardInterfaceApi for WGApi { .set_default_route(&addresses, &interface) .map_err(WindowsError::from)?; - // Bring the adapter up + // Set MTU + 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)?;