fix(windows): set MTU on tunnel interface (#2990)

This commit is contained in:
Reactor Scram
2024-01-03 17:37:38 -06:00
committed by GitHub
parent d6985470ef
commit 3a4f2cf9c0
6 changed files with 62 additions and 3 deletions

2
rust/Cargo.lock generated
View File

@@ -1222,6 +1222,7 @@ dependencies = [
"url",
"uuid",
"webrtc",
"windows 0.52.0",
"wintun",
]
@@ -2064,6 +2065,7 @@ dependencies = [
"tracing-android",
"uuid",
"webrtc",
"windows 0.52.0",
"wintun",
]

View File

@@ -53,3 +53,10 @@ rtnetlink = { version = "0.13", default-features = false, features = ["tokio_soc
# Windows tunnel dependencies
[target.'cfg(target_os = "windows")'.dependencies]
wintun = "0.3.2"
# Windows Win32 API
[target.'cfg(windows)'.dependencies.windows]
version = "0.52.0"
features = [
"Win32_Foundation",
]

View File

@@ -144,6 +144,9 @@ pub enum ConnlibError {
#[error(transparent)]
Uuid(#[from] uuid::Error),
#[cfg(target_os = "windows")]
#[error("Windows error: {0}")]
WindowsError(#[from] windows::core::Error),
#[cfg(target_os = "windows")]
#[error(transparent)]
Wintun(#[from] wintun::Error),
#[error("Token has expired")]

View File

@@ -50,3 +50,13 @@ tracing-android = "0.2"
[target.'cfg(target_os = "windows")'.dependencies]
uuid = { version = "1.5.0", features = ["v4"] }
wintun = "0.3.2"
# Windows Win32 API
[target.'cfg(windows)'.dependencies.windows]
version = "0.52.0"
features = [
"Win32_Foundation",
"Win32_NetworkManagement_IpHelper",
"Win32_NetworkManagement_Ndis",
"Win32_Networking_WinSock",
]

View File

@@ -10,6 +10,13 @@ use std::{
task::{ready, Context, Poll},
};
use tokio::sync::mpsc;
use windows::Win32::{
NetworkManagement::{
IpHelper::{GetIpInterfaceEntry, SetIpInterfaceEntry, MIB_IPINTERFACE_ROW},
Ndis::NET_LUID_LH,
},
Networking::WinSock::AF_INET,
};
// TODO: Double-check that all these get dropped gracefully on disconnect
pub struct Tun {
@@ -34,6 +41,8 @@ impl Drop for Tun {
// Hides Powershell's console on Windows
// <https://stackoverflow.com/questions/59692146/is-it-possible-to-use-the-standard-library-to-spawn-a-process-without-showing-th#60958956>
const CREATE_NO_WINDOW: u32 = 0x08000000;
// Copied from tun_linux.rs
const DEFAULT_MTU: u32 = 1280;
impl Tun {
pub fn new(config: &InterfaceConfig) -> Result<Self> {
@@ -86,6 +95,8 @@ impl Tun {
.stdout(Stdio::null())
.status()?;
set_iface_config(adapter.get_luid(), DEFAULT_MTU)?;
// Set our DNS IP as the DNS server for our interface
// TODO: Lots of issues with this. Windows does seem to use it, but I'm not sure why. And there's a delay before some Firefox windows pick it up. Curl might be picking it up faster because its DNS cache starts cold every time.
Command::new("powershell")
@@ -199,3 +210,30 @@ fn start_recv_thread(
tracing::debug!("recv_task exiting gracefully");
})
}
/// Sets MTU on the interface
/// TODO: Set IP and other things in here too, so the code is more organized
fn set_iface_config(luid: wintun::NET_LUID_LH, mtu: u32) -> Result<()> {
// Safety: Both NET_LUID_LH unions should be the same. We're just copying out
// the u64 value and re-wrapping it, since wintun doesn't refer to the windows
// crate's version of NET_LUID_LH.
let luid = NET_LUID_LH {
Value: unsafe { luid.Value },
};
let mut row = MIB_IPINTERFACE_ROW {
Family: AF_INET,
InterfaceLuid: luid,
..Default::default()
};
unsafe { GetIpInterfaceEntry(&mut row) }?;
row.NlMtu = mtu;
// https://stackoverflow.com/questions/54857292/setipinterfaceentry-returns-error-invalid-parameter
row.SitePrefixLength = 0;
// Ignore error if we can't set everything
unsafe { SetIpInterfaceEntry(&mut row) }?;
Ok(())
}

View File

@@ -49,11 +49,10 @@ wintun = "0.3.2"
version = "0.52.0"
features = [
"Win32_Foundation",
# Needed for deep_link module
"Win32_Security",
"Win32_System_LibraryLoader",
# Needed for deep_link module
"Win32_System_SystemServices",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging",
]
[features]