diff options
| author | Jonathan <jonathan@mullvad.net> | 2022-07-12 12:49:35 +0200 |
|---|---|---|
| committer | Jonathan <jonathan@mullvad.net> | 2022-07-12 12:49:35 +0200 |
| commit | 854f85e8aee7434fc3ea9e5c0e2ecc7cb7891766 (patch) | |
| tree | bb37e314f4f690d2ff855c2a0e284578bb0638b6 | |
| parent | 214f1bca1cdee9c98f58dd3593cc8dcc86b8b95d (diff) | |
| parent | e1cc304e1413854b4af875fa629753c884def1e5 (diff) | |
| download | mullvadvpn-854f85e8aee7434fc3ea9e5c0e2ecc7cb7891766.tar.xz mullvadvpn-854f85e8aee7434fc3ea9e5c0e2ecc7cb7891766.zip | |
Merge branch 'windows-auto-set-mtu'
| -rw-r--r-- | CHANGELOG.md | 4 | ||||
| -rw-r--r-- | talpid-core/src/routing/windows.rs | 58 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 13 |
3 files changed, 69 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e9bd14c13..d3e9d1c520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ Line wrap the file at 100 chars. Th #### Android - Add device management to the Android app. This simplifies knowing which device is which and adds the option to log other devices out when the account already has five devices. +#### Windows +- Windows daemon now looks up the MTU on the default interface and uses this MTU instead of the + default 1500. The 1500 is still the fallback if this for some reason fails. This may stop + fragmentation. ### Changed - Reject invalid WireGuard ports in the CLI. diff --git a/talpid-core/src/routing/windows.rs b/talpid-core/src/routing/windows.rs index f7325b3963..7d9bcba738 100644 --- a/talpid-core/src/routing/windows.rs +++ b/talpid-core/src/routing/windows.rs @@ -7,7 +7,8 @@ use futures::{ }, StreamExt, }; -use std::collections::HashSet; +use std::{collections::HashSet, net::IpAddr}; +use winnet::WinNetAddrFamily; /// Windows routing errors. #[derive(err_derive::Error, Debug)] @@ -30,6 +31,9 @@ pub enum Error { /// Attempt to use route manager that has been dropped #[error(display = "Cannot send message to route manager since it is down")] RouteManagerDown, + /// Something went wrong when getting the mtu of the interface + #[error(display = "Could not get the mtu of the interface")] + GetMtu, } pub type Result<T> = std::result::Result<T, Error>; @@ -54,11 +58,21 @@ impl RouteManagerHandle { .map_err(|_| Error::RouteManagerDown)?; response_rx.await.map_err(|_| Error::ManagerChannelDown)? } + + /// Applies the given routes while the route manager is running. + pub async fn get_mtu_for_route(&self, ip: IpAddr) -> Result<u16> { + let (response_tx, response_rx) = oneshot::channel(); + self.tx + .unbounded_send(RouteManagerCommand::GetMtuForRoute(ip, response_tx)) + .map_err(|_| Error::RouteManagerDown)?; + response_rx.await.map_err(|_| Error::ManagerChannelDown)? + } } #[derive(Debug)] pub enum RouteManagerCommand { AddRoutes(HashSet<RequiredRoute>, oneshot::Sender<Result<()>>), + GetMtuForRoute(IpAddr, oneshot::Sender<Result<u16>>), Shutdown, } @@ -112,6 +126,19 @@ impl RouteManager { winnet::routing_manager_add_routes(&routes).map_err(Error::AddRoutesFailed), ); } + RouteManagerCommand::GetMtuForRoute(ip, tx) => { + let addr_family = if ip.is_ipv4() { + winnet::WinNetAddrFamily::IPV4 + } else { + winnet::WinNetAddrFamily::IPV6 + }; + let res = match get_mtu_for_route(addr_family) { + Ok(Some(mtu)) => Ok(mtu), + Ok(None) => Err(Error::GetMtu), + Err(e) => Err(e), + }; + let _ = tx.send(res); + } RouteManagerCommand::Shutdown => { break; } @@ -158,6 +185,35 @@ impl RouteManager { } } +fn get_mtu_for_route(addr_family: WinNetAddrFamily) -> Result<Option<u16>> { + use crate::windows::AddressFamily; + use winapi::shared::ifdef::NET_LUID; + match winnet::get_best_default_route(addr_family) { + Ok(Some(route)) => { + let addr_family = match addr_family { + WinNetAddrFamily::IPV4 => AddressFamily::Ipv4, + WinNetAddrFamily::IPV6 => AddressFamily::Ipv6, + }; + let luid = NET_LUID { + Value: route.interface_luid, + }; + let interface_row = crate::windows::get_ip_interface_entry(addr_family, &luid) + .map_err(|e| { + log::error!("Could not get ip interface entry: {}", e); + Error::GetMtu + })?; + let mtu = interface_row.NlMtu; + let mtu = u16::try_from(mtu).map_err(|_| Error::GetMtu)?; + Ok(Some(mtu)) + } + Ok(None) => Ok(None), + Err(e) => { + log::error!("Could not get best default route: {}", e); + Err(Error::GetMtu) + } + } +} + impl Drop for RouteManager { fn drop(&mut self) { self.stop(); diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index 7f78d74b85..a0fda069f5 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -197,7 +197,7 @@ impl TunnelMonitor { + Clone + 'static, { - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "windows"))] args.runtime .block_on(Self::assign_mtu(&args.route_manager, params)); let config = wireguard::config::Config::from_parameters(params)?; @@ -223,7 +223,7 @@ impl TunnelMonitor { }) } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "windows"))] fn set_mtu(params: &mut wireguard_types::TunnelParameters, peer_mtu: u16) { const IPV4_HEADER_SIZE: u16 = 20; const IPV6_HEADER_SIZE: u16 = 40; @@ -248,18 +248,21 @@ impl TunnelMonitor { params.options.mtu = Some(tunnel_mtu); } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "windows"))] async fn assign_mtu( route_manager: &RouteManagerHandle, params: &mut wireguard_types::TunnelParameters, ) { // Only calculate the mtu automatically if the user has not set any if params.options.mtu.is_none() { - if let Ok(mtu) = route_manager + match route_manager .get_mtu_for_route(params.connection.peer.endpoint.ip()) .await { - Self::set_mtu(params, mtu); + Ok(mtu) => Self::set_mtu(params, mtu), + Err(e) => { + log::error!("Could not get the MTU for route {}", e); + } } } } |
