summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonathan <jonathan@mullvad.net>2022-06-23 03:34:13 -0700
committerJonathan <jonathan@mullvad.net>2022-07-12 12:47:09 +0200
commite1cc304e1413854b4af875fa629753c884def1e5 (patch)
treebb37e314f4f690d2ff855c2a0e284578bb0638b6
parent214f1bca1cdee9c98f58dd3593cc8dcc86b8b95d (diff)
downloadmullvadvpn-e1cc304e1413854b4af875fa629753c884def1e5.tar.xz
mullvadvpn-e1cc304e1413854b4af875fa629753c884def1e5.zip
Windows automatically detects and set locally correct MTU
Let Windows daemon detect the MTU for default routing interface and set that MTU as the default. This is implementing the changes that have already been provided in the linux version.
-rw-r--r--CHANGELOG.md4
-rw-r--r--talpid-core/src/routing/windows.rs58
-rw-r--r--talpid-core/src/tunnel/mod.rs13
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);
+ }
}
}
}