summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonathan <jonathan@mullvad.net>2022-07-12 12:49:35 +0200
committerJonathan <jonathan@mullvad.net>2022-07-12 12:49:35 +0200
commit854f85e8aee7434fc3ea9e5c0e2ecc7cb7891766 (patch)
treebb37e314f4f690d2ff855c2a0e284578bb0638b6
parent214f1bca1cdee9c98f58dd3593cc8dcc86b8b95d (diff)
parente1cc304e1413854b4af875fa629753c884def1e5 (diff)
downloadmullvadvpn-854f85e8aee7434fc3ea9e5c0e2ecc7cb7891766.tar.xz
mullvadvpn-854f85e8aee7434fc3ea9e5c0e2ecc7cb7891766.zip
Merge branch 'windows-auto-set-mtu'
-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);
+ }
}
}
}