Skip to content

Commit c99c0b2

Browse files
Handle setting MTU on windows (#107)
1 parent 886186c commit c99c0b2

File tree

2 files changed

+76
-13
lines changed

2 files changed

+76
-13
lines changed

Cargo.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/wgapi_windows.rs

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::{
22
collections::HashMap,
3+
ffi::OsStr,
34
net::IpAddr,
5+
os::windows::ffi::OsStrExt,
46
str::FromStr,
57
sync::{LazyLock, Mutex},
68
};
@@ -10,12 +12,17 @@ use thiserror::Error;
1012
use windows::{
1113
Win32::{
1214
Foundation::{ERROR_BUFFER_OVERFLOW, NO_ERROR},
13-
NetworkManagement::IpHelper::{
14-
DNS_INTERFACE_SETTINGS, DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6,
15-
DNS_SETTING_NAMESERVER, GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses,
16-
IP_ADAPTER_ADDRESSES_LH, SetInterfaceDnsSettings,
15+
NetworkManagement::{
16+
IpHelper::{
17+
ConvertInterfaceGuidToLuid, DNS_INTERFACE_SETTINGS,
18+
DNS_INTERFACE_SETTINGS_VERSION1, DNS_SETTING_IPV6, DNS_SETTING_NAMESERVER,
19+
GAA_FLAG_INCLUDE_PREFIX, GetAdaptersAddresses, GetIpInterfaceEntry,
20+
IP_ADAPTER_ADDRESSES_LH, InitializeIpInterfaceEntry, MIB_IPINTERFACE_ROW,
21+
SetInterfaceDnsSettings, SetIpInterfaceEntry,
22+
},
23+
Ndis::NET_LUID_LH,
1724
},
18-
Networking::WinSock::AF_UNSPEC,
25+
Networking::WinSock::{ADDRESS_FAMILY, AF_INET, AF_INET6, AF_UNSPEC},
1926
System::Com::CLSIDFromString,
2027
},
2128
core::{GUID, PCSTR, PCWSTR, PSTR},
@@ -136,6 +143,55 @@ fn get_adapter_guid(adapter_name: &str) -> Result<GUID, WindowsError> {
136143
guid.ok_or_else(|| WindowsError::AdapterNotFound(adapter_name.to_string()))
137144
}
138145

146+
/// Sets both IPv4 and IPv6 MTU on specified interface.
147+
fn set_interface_mtu(interface_name: &str, mtu: u32) -> Result<(), WindowsError> {
148+
debug!("Setting interface {interface_name} MTU to {mtu}");
149+
let guid = get_adapter_guid(interface_name)?;
150+
151+
// Convert interface GUID to LUID.
152+
let mut luid = NET_LUID_LH::default();
153+
let res = unsafe { ConvertInterfaceGuidToLuid(&guid, &mut luid) };
154+
if res.0 != 0 {
155+
error!(
156+
"ConvertInterfaceGuidToLuid call failed, error value: {}",
157+
res.0
158+
);
159+
return Err(WindowsError::NonZeroReturnValue(res.0));
160+
}
161+
162+
// Helper function, sets MTU for given IP family.
163+
fn set_mtu_for_family(luid: NET_LUID_LH, family: u16, mtu: u32) -> Result<(), WindowsError> {
164+
// InitializeIpInterfaceEntry has to be called before get/set operations.
165+
let mut row = MIB_IPINTERFACE_ROW::default();
166+
unsafe { InitializeIpInterfaceEntry(&mut row) };
167+
168+
// Load current configuration.
169+
row.InterfaceLuid = luid;
170+
row.Family = ADDRESS_FAMILY(family);
171+
let res = unsafe { GetIpInterfaceEntry(&mut row) };
172+
if res.0 != 0 {
173+
error!("GetIpInterfaceEntry call failed, error value: {}", res.0);
174+
return Err(WindowsError::NonZeroReturnValue(res.0));
175+
}
176+
177+
// Modify the configuration and apply.
178+
row.NlMtu = mtu;
179+
let res = unsafe { SetIpInterfaceEntry(&mut row) };
180+
if res.0 != 0 {
181+
error!("SetIpInterfaceEntry call failed, error value: {}", res.0);
182+
return Err(WindowsError::NonZeroReturnValue(res.0));
183+
}
184+
Ok(())
185+
}
186+
187+
// Set MTU for both IP addr families.
188+
set_mtu_for_family(luid, AF_INET.0, mtu)?;
189+
set_mtu_for_family(luid, AF_INET6.0, mtu)?;
190+
191+
info!("Set interface {interface_name} MTU to {mtu}");
192+
Ok(())
193+
}
194+
139195
impl From<wireguard_nt::WireguardPeer> for Peer {
140196
fn from(peer: wireguard_nt::WireguardPeer) -> Self {
141197
Self {
@@ -173,7 +229,7 @@ impl From<wireguard_nt::WireguardInterface> for Host {
173229

174230
/// Converts an str to wide (u16), null-terminated
175231
fn str_to_wide_null_terminated(s: &str) -> Vec<u16> {
176-
s.encode_utf16().chain(std::iter::once(0)).collect()
232+
OsStr::new(s).encode_wide().chain(Some(0)).collect()
177233
}
178234

179235
/// Manages interfaces created with Windows kernel using https://git.zx2c4.com/wireguard-nt.
@@ -272,7 +328,14 @@ impl WireguardInterfaceApi for WGApi<Kernel> {
272328
.set_default_route(&addresses, &interface)
273329
.map_err(WindowsError::from)?;
274330

275-
// Bring the adapter up
331+
// Set MTU
332+
if let Some(mtu) = config.mtu {
333+
set_interface_mtu(&self.ifname, mtu)?;
334+
// Turn it off and on again.
335+
adapter.down().map_err(WindowsError::from)?;
336+
}
337+
338+
// Bring the adapter up.
276339
debug!("Bringing up adapter {}", self.ifname);
277340
adapter.up().map_err(WindowsError::from)?;
278341

0 commit comments

Comments
 (0)