summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2025-07-25 14:11:36 +0200
committerDavid Lönnhager <david.l@mullvad.net>2025-07-25 14:11:36 +0200
commit1a8ea02ce90e28d764bcc58cc05bb09fd5e396be (patch)
tree6b391ceeeff85a13456eb15627e70693393cfe7a
parentfe8b307d6ebb8bd99b666b8f16b24dee2bdd5297 (diff)
parent3103e41cd9b12bd48ba597c740a8587cdc7a7144 (diff)
downloadmullvadvpn-1a8ea02ce90e28d764bcc58cc05bb09fd5e396be.tar.xz
mullvadvpn-1a8ea02ce90e28d764bcc58cc05bb09fd5e396be.zip
Merge branch 'boring-multihop'
-rw-r--r--Cargo.lock44
-rw-r--r--talpid-tunnel/src/tun_provider/unix.rs7
-rw-r--r--talpid-wireguard/Cargo.toml4
-rw-r--r--talpid-wireguard/src/boringtun/mod.rs372
-rw-r--r--talpid-wireguard/src/lib.rs36
5 files changed, 371 insertions, 92 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 741615496b..74c8ccd761 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -233,9 +233,9 @@ dependencies = [
[[package]]
name = "async-trait"
-version = "0.1.80"
+version = "0.1.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
+checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
dependencies = [
"proc-macro2",
"quote",
@@ -444,12 +444,15 @@ dependencies = [
[[package]]
name = "boringtun"
version = "0.6.0"
-source = "git+https://github.com/mullvad/boringtun?rev=c29681df54e1c10ba06d9ca7ff98722c9dcb5a81#c29681df54e1c10ba06d9ca7ff98722c9dcb5a81"
+source = "git+https://github.com/mullvad/boringtun?rev=9194fbfd5ba578408887429c59c3b9d9171722fa#9194fbfd5ba578408887429c59c3b9d9171722fa"
dependencies = [
"aead",
+ "async-trait",
"base64 0.13.1",
"blake2",
+ "bytes",
"chacha20poly1305",
+ "either",
"eyre",
"hex",
"hmac",
@@ -457,8 +460,9 @@ dependencies = [
"ip_network_table",
"libc",
"log",
- "nix 0.25.1",
+ "nix 0.30.1",
"parking_lot",
+ "pnet_packet 0.35.0",
"rand_core 0.6.4",
"ring",
"socket2 0.4.10",
@@ -466,9 +470,10 @@ dependencies = [
"tokio",
"tracing",
"tun 0.7.13",
- "typed-builder 0.20.1",
+ "typed-builder 0.21.0",
"untrusted",
"x25519-dalek",
+ "zerocopy",
]
[[package]]
@@ -491,9 +496,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
-version = "1.10.0"
+version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "c2rust-bitfields"
@@ -1154,9 +1159,9 @@ dependencies = [
[[package]]
name = "either"
-version = "1.11.0"
+version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "elliptic-curve"
@@ -3425,19 +3430,6 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.25.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
-dependencies = [
- "autocfg",
- "bitflags 1.3.2",
- "cfg-if",
- "libc",
- "memoffset 0.6.5",
-]
-
-[[package]]
-name = "nix"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
@@ -7156,18 +7148,18 @@ dependencies = [
[[package]]
name = "zerocopy"
-version = "0.8.24"
+version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.24"
+version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
diff --git a/talpid-tunnel/src/tun_provider/unix.rs b/talpid-tunnel/src/tun_provider/unix.rs
index 82b87fc666..70aad330a8 100644
--- a/talpid-tunnel/src/tun_provider/unix.rs
+++ b/talpid-tunnel/src/tun_provider/unix.rs
@@ -285,6 +285,7 @@ mod tun07_imp {
builder.name(name);
}
}
+ builder.mtu(self.config.mtu);
builder.create()?
};
@@ -349,6 +350,12 @@ mod tun07_imp {
self
}
+ /// Set tunnel device MTU.
+ pub fn mtu(&mut self, mtu: u16) -> &mut Self {
+ self.config.mtu(mtu);
+ self
+ }
+
/// Enable packet information.
/// When enabled the first 4 bytes of each packet is a header with flags and protocol type.
#[cfg(target_os = "linux")]
diff --git a/talpid-wireguard/Cargo.toml b/talpid-wireguard/Cargo.toml
index 8784837888..87372c49b3 100644
--- a/talpid-wireguard/Cargo.toml
+++ b/talpid-wireguard/Cargo.toml
@@ -44,9 +44,9 @@ tokio-stream = { version = "0.1", features = ["io-util"] }
[dependencies.boringtun]
optional = true
-features = ["device"]
+features = ["device", "tun"]
git = "https://github.com/mullvad/boringtun"
-rev = "c29681df54e1c10ba06d9ca7ff98722c9dcb5a81"
+rev = "9194fbfd5ba578408887429c59c3b9d9171722fa"
[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["fs"] }
diff --git a/talpid-wireguard/src/boringtun/mod.rs b/talpid-wireguard/src/boringtun/mod.rs
index 273f13b77f..93da4b141e 100644
--- a/talpid-wireguard/src/boringtun/mod.rs
+++ b/talpid-wireguard/src/boringtun/mod.rs
@@ -3,34 +3,90 @@ use crate::{
config::Config,
stats::{Stats, StatsMap},
};
-use boringtun::device::{
- DeviceConfig, DeviceHandle,
- api::{ApiClient, ApiServer, command::*},
- peer::AllowedIP,
+#[cfg(target_os = "android")]
+use boringtun::udp::UdpTransportFactory;
+use boringtun::{
+ device::{
+ DeviceConfig, DeviceHandle,
+ api::{ApiClient, ApiServer, command::*},
+ peer::AllowedIP,
+ },
+ udp::{UdpSocketFactory, channel::PacketChannel},
};
-
#[cfg(not(target_os = "android"))]
use ipnetwork::IpNetwork;
#[cfg(target_os = "android")]
use std::os::fd::IntoRawFd;
use std::{
future::Future,
+ net::{IpAddr, Ipv4Addr, Ipv6Addr},
ops::Deref,
sync::{Arc, Mutex},
};
use talpid_tunnel::tun_provider::{self, Tun, TunProvider};
use talpid_tunnel_config_client::DaitaSettings;
-use tun07::AbstractDevice;
+use tun07::{AbstractDevice, AsyncDevice};
+
+#[cfg(target_os = "android")]
+type UdpFactory = AndroidUdpSocketFactory;
+
+#[cfg(not(target_os = "android"))]
+type UdpFactory = UdpSocketFactory;
+
+type SinglehopDevice = DeviceHandle<(UdpFactory, Arc<tun07::AsyncDevice>, Arc<tun07::AsyncDevice>)>;
+type EntryDevice = DeviceHandle<(UdpFactory, PacketChannel, PacketChannel)>;
+type ExitDevice = DeviceHandle<(PacketChannel, Arc<AsyncDevice>, Arc<AsyncDevice>)>;
+
+const PACKET_CHANNEL_CAPACITY: usize = 100;
pub struct BoringTun {
- device_handle: DeviceHandle,
- config_tx: ApiClient,
+ /// Device handles
+ devices: Devices,
+
+ /// Tunnel config
config: Config,
/// Name of the tun interface.
interface_name: String,
}
+enum Devices {
+ Singlehop {
+ device: SinglehopDevice,
+ api: ApiClient,
+ },
+
+ Multihop {
+ entry_device: EntryDevice,
+ entry_api: ApiClient,
+
+ exit_device: ExitDevice,
+ exit_api: ApiClient,
+ },
+}
+
+#[cfg(target_os = "android")]
+struct AndroidUdpSocketFactory {
+ pub tun: Tun,
+}
+
+#[cfg(target_os = "android")]
+impl UdpTransportFactory for AndroidUdpSocketFactory {
+ type Transport = <UdpSocketFactory as UdpTransportFactory>::Transport;
+
+ async fn bind(
+ &mut self,
+ params: &boringtun::udp::UdpTransportFactoryParams,
+ ) -> std::io::Result<(Arc<Self::Transport>, Arc<Self::Transport>)> {
+ let (udp_v4, udp_v6) = UdpSocketFactory.bind(params).await?;
+
+ self.tun.bypass(&udp_v4).unwrap();
+ self.tun.bypass(&udp_v6).unwrap();
+
+ Ok((udp_v4, udp_v6))
+ }
+}
+
/// Configure and start a boringtun tunnel.
pub async fn open_boringtun_tunnel(
config: &Config,
@@ -55,21 +111,15 @@ pub async fn open_boringtun_tunnel(
}
};
- let (mut config_tx, config_rx) = ApiServer::new();
-
- let boringtun_config = DeviceConfig {
- n_threads: 4,
- api: Some(config_rx),
- on_bind: None,
+ let (entry_api, entry_api_server) = ApiServer::new();
+ let boringtun_entry_config = DeviceConfig {
+ api: Some(entry_api_server),
};
#[cfg(target_os = "android")]
- let mut boringtun_config = boringtun_config;
-
- #[cfg(target_os = "android")]
- let async_tun = {
+ let (tun, async_tun) = {
let _ = routes; // TODO: do we need this?
- let (mut tun, fd) = get_tunnel_for_userspace(Arc::clone(&tun_provider), config)?;
+ let (tun, fd) = get_tunnel_for_userspace(Arc::clone(&tun_provider), config)?;
let is_new_tunnel = tun.is_new;
// TODO We should also wait for routes before sending any ping / connectivity check
@@ -87,42 +137,113 @@ pub async fn open_boringtun_tunnel(
.map_err(|e| TunnelError::RecoverableStartWireguardError(Box::new(e)))?;
}
- let mut config = tun07::Configuration::default();
- config.raw_fd(fd);
+ let mut tun_config = tun07::Configuration::default();
+ tun_config.raw_fd(fd);
- boringtun_config.on_bind = Some(Box::new(move |socket| tun.bypass(socket).unwrap()));
+ let device = tun07::Device::new(&tun_config).unwrap();
- let device = tun07::Device::new(&config).unwrap();
- tun07::AsyncDevice::new(device).unwrap()
+ (tun, tun07::AsyncDevice::new(device).unwrap())
};
let interface_name = async_tun.deref().tun_name().unwrap();
log::info!("passing tunnel dev to boringtun");
- let device_handle: DeviceHandle = DeviceHandle::new(async_tun, boringtun_config)
+ let async_tun = Arc::new(async_tun);
+
+ let mut boringtun = if config.exit_peer.is_some() {
+ // multihop
+
+ let source_v4 = config.tunnel.addresses.iter().find_map(|ip| match ip {
+ &IpAddr::V4(ipv4_addr) => Some(ipv4_addr),
+ IpAddr::V6(..) => None,
+ });
+
+ let source_v6 = config.tunnel.addresses.iter().find_map(|ip| match ip {
+ &IpAddr::V6(ipv6_addr) => Some(ipv6_addr),
+ IpAddr::V4(..) => None,
+ });
+
+ let channel = PacketChannel::new(
+ PACKET_CHANNEL_CAPACITY,
+ source_v4.unwrap_or(Ipv4Addr::UNSPECIFIED), // HACK: unwrap_or
+ source_v6.unwrap_or(Ipv6Addr::UNSPECIFIED), // HACK: unwrap_or
+ );
+
+ let (exit_api, exit_api_server) = ApiServer::new();
+ let exit_device = DeviceHandle::<(PacketChannel, Arc<AsyncDevice>, Arc<AsyncDevice>)>::new(
+ channel.clone(),
+ async_tun.clone(),
+ async_tun,
+ DeviceConfig {
+ api: Some(exit_api_server),
+ },
+ )
+ .await
+ .map_err(TunnelError::BoringTunDevice)?;
+
+ #[cfg(target_os = "android")]
+ let factory = AndroidUdpSocketFactory { tun };
+
+ #[cfg(not(target_os = "android"))]
+ let factory = UdpSocketFactory;
+
+ let entry_device =
+ EntryDevice::new(factory, channel.clone(), channel, boringtun_entry_config)
+ .await
+ .map_err(TunnelError::BoringTunDevice)?;
+
+ BoringTun {
+ config: config.clone(),
+ interface_name,
+ devices: Devices::Multihop {
+ entry_device,
+ entry_api,
+ exit_device,
+ exit_api,
+ },
+ }
+ } else {
+ #[cfg(target_os = "android")]
+ let factory = AndroidUdpSocketFactory { tun };
+
+ #[cfg(not(target_os = "android"))]
+ let factory = UdpSocketFactory;
+
+ let device = SinglehopDevice::new(
+ factory,
+ async_tun.clone(),
+ async_tun,
+ boringtun_entry_config,
+ )
.await
.map_err(TunnelError::BoringTunDevice)?;
- set_boringtun_config(&mut config_tx, config).await?;
+ BoringTun {
+ devices: Devices::Singlehop {
+ device,
+ api: entry_api,
+ },
+ config: config.clone(),
+ interface_name,
+ }
+ };
+
+ // FIXME: double clone
+ boringtun.set_config(config.clone()).await?;
log::info!(
"This tunnel was brought to you by...
-.........................................................
-..*...*.. .--. .---. ..*....*.
-...*..... | ) o | ......*..
-.*..*..*. |--: .-. .--.. .--. .-..|. . .--. ...*.....
-...*..... | )( )| | | |( ||| | | | .*.....*.
-*.....*.. '--' `-' ' -' `-' `-`-`|'`--`-' `- .....*...
-......... ._.' ..*...*..
-..*...*.............................................*...."
+ .........................................................
+ ..*...*.. .--. .---. ..*....*.
+ ...*..... | ) o | ......*..
+ .*..*..*. |--: .-. .--.. .--. .-..|. . .--. ...*.....
+ ...*..... | )( )| | | |( ||| | | | .*.....*.
+ *.....*.. '--' `-' ' -' `-' `-`-`|'`--`-' `- .....*...
+ ......... ._.' ..*...*..
+ ..*...*.............................................*...."
);
- Ok(BoringTun {
- device_handle,
- config: config.clone(),
- config_tx,
- interface_name,
- })
+ Ok(boringtun)
}
#[async_trait::async_trait]
@@ -133,31 +254,56 @@ impl Tunnel for BoringTun {
fn stop(self: Box<Self>) -> Result<(), TunnelError> {
log::info!("BoringTun::stop"); // remove me
- tokio::runtime::Handle::current().block_on(self.device_handle.stop());
+ tokio::runtime::Handle::current().block_on(async {
+ match self.devices {
+ Devices::Singlehop { device, .. } => {
+ device.stop().await;
+ }
+ Devices::Multihop {
+ entry_device,
+ exit_device,
+ ..
+ } => {
+ exit_device.stop().await;
+ entry_device.stop().await;
+ }
+ }
+ });
+
Ok(())
}
async fn get_tunnel_stats(&self) -> Result<StatsMap, TunnelError> {
- let response = self
- .config_tx
- .send(Get::default())
- .await
- .expect("Failed to get peers");
+ let mut stats = StatsMap::default();
- let Response::Get(response) = response else {
- return Err(TunnelError::GetConfigError);
+ let apis = match &self.devices {
+ Devices::Singlehop { api, .. } => [Some(api), None],
+ Devices::Multihop {
+ entry_api,
+ exit_api,
+ ..
+ } => [Some(entry_api), Some(exit_api)],
};
- Ok(StatsMap::from_iter(response.peers.into_iter().map(
- |peer| {
- (
+
+ for api in apis.into_iter().flatten() {
+ let response = api.send(Get::default()).await.expect("Failed to get peers");
+
+ let Response::Get(response) = response else {
+ return Err(TunnelError::GetConfigError);
+ };
+
+ for peer in response.peers {
+ stats.insert(
peer.peer.public_key.0,
Stats {
tx_bytes: peer.tx_bytes.unwrap_or_default(),
rx_bytes: peer.rx_bytes.unwrap_or_default(),
},
- )
- },
- )))
+ );
+ }
+ }
+
+ Ok(stats)
}
fn set_config<'a>(
@@ -166,7 +312,27 @@ impl Tunnel for BoringTun {
) -> std::pin::Pin<Box<dyn Future<Output = Result<(), TunnelError>> + Send + 'a>> {
Box::pin(async move {
self.config = config;
- set_boringtun_config(&mut self.config_tx, &self.config).await?;
+ match &mut self.devices {
+ Devices::Singlehop { api, .. } => {
+ assert!(
+ self.config.exit_peer.is_none(),
+ "todo: support switching between single and multihop"
+ );
+ set_boringtun_config(api, &self.config).await?;
+ }
+ Devices::Multihop {
+ entry_api,
+ exit_api,
+ ..
+ } => {
+ assert!(
+ self.config.exit_peer.is_some(),
+ "todo: support switching between single and multihop"
+ );
+ set_boringtun_entry_config(entry_api, &self.config).await?;
+ set_boringtun_exit_config(exit_api, &self.config).await?;
+ }
+ }
Ok(())
})
}
@@ -224,6 +390,100 @@ async fn set_boringtun_config(
Ok(())
}
+async fn set_boringtun_entry_config(
+ tx: &mut ApiClient,
+ config: &Config,
+) -> Result<(), crate::TunnelError> {
+ log::info!("configuring boringtun device");
+ let mut set_cmd = Set::builder()
+ .private_key(config.tunnel.private_key.to_bytes())
+ .listen_port(0u16)
+ .replace_peers()
+ .build();
+
+ #[cfg(target_os = "linux")]
+ {
+ set_cmd.fwmark = config.fwmark;
+ }
+
+ let peer = &config.entry_peer;
+ let mut boring_peer = Peer::builder()
+ .public_key(*peer.public_key.as_bytes())
+ .endpoint(peer.endpoint)
+ .allowed_ip(
+ peer.allowed_ips
+ .iter()
+ .map(|net| AllowedIP {
+ addr: net.ip(),
+ cidr: net.prefix(),
+ })
+ .collect(),
+ )
+ .build();
+
+ if let Some(psk) = &peer.psk {
+ boring_peer.preshared_key = Some(SetUnset::Set((*psk.as_bytes()).into()));
+ }
+
+ let boring_peer = SetPeer::builder().peer(boring_peer).build();
+
+ set_cmd.peers.push(boring_peer);
+
+ tx.send(set_cmd).await.map_err(|err| {
+ log::error!("Failed to set boringtun config: {err:#}");
+ TunnelError::SetConfigError
+ })?;
+ Ok(())
+}
+
+async fn set_boringtun_exit_config(
+ tx: &mut ApiClient,
+ config: &Config,
+) -> Result<(), crate::TunnelError> {
+ log::info!("configuring boringtun device");
+ let mut set_cmd = Set::builder()
+ .private_key(config.tunnel.private_key.to_bytes())
+ .listen_port(0u16)
+ .replace_peers()
+ .build();
+
+ #[cfg(target_os = "linux")]
+ {
+ set_cmd.fwmark = config.fwmark;
+ }
+
+ // TODO: don't unwrap
+ let peer = config.exit_peer.as_ref().unwrap();
+
+ let mut boring_peer = Peer::builder()
+ .public_key(*peer.public_key.as_bytes())
+ .endpoint(peer.endpoint)
+ .allowed_ip(
+ peer.allowed_ips
+ .iter()
+ .map(|net| AllowedIP {
+ addr: net.ip(),
+ cidr: net.prefix(),
+ })
+ .collect(),
+ )
+ .build();
+
+ if let Some(psk) = &peer.psk {
+ boring_peer.preshared_key = Some(SetUnset::Set((*psk.as_bytes()).into()));
+ }
+
+ let boring_peer = SetPeer::builder().peer(boring_peer).build();
+
+ set_cmd.peers.push(boring_peer);
+
+ tx.send(set_cmd).await.map_err(|err| {
+ log::error!("Failed to set boringtun config: {err:#}");
+ TunnelError::SetConfigError
+ })?;
+ Ok(())
+}
+
#[cfg(target_os = "windows")]
fn get_tunnel_for_userspace(
tun_provider: Arc<Mutex<TunProvider>>,
@@ -238,6 +498,8 @@ fn get_tunnel_for_userspace(
tun_config.ipv6_gateway = config.ipv6_gateway;
tun_config.mtu = config.mtu;
+ // FIXME: mtu is not set
+
let _ = routes;
#[cfg(windows)]
diff --git a/talpid-wireguard/src/lib.rs b/talpid-wireguard/src/lib.rs
index d593b69b72..5e265e4dd5 100644
--- a/talpid-wireguard/src/lib.rs
+++ b/talpid-wireguard/src/lib.rs
@@ -263,7 +263,7 @@ impl WireguardMonitor {
.map_err(Error::SetupRoutingError)
.map_err(CloseMsg::SetupError)?;
- let routes = Self::get_pre_tunnel_routes(&iface_name, &config)
+ let routes = Self::get_pre_tunnel_routes(&iface_name, &config, userspace_wireguard)
.chain(Self::get_endpoint_routes(&endpoint_addrs))
.collect();
@@ -354,7 +354,10 @@ impl WireguardMonitor {
// Add any default route(s) that may exist.
args.route_manager
- .add_routes(Self::get_post_tunnel_routes(&iface_name, &config).collect())
+ .add_routes(
+ Self::get_post_tunnel_routes(&iface_name, &config, userspace_wireguard)
+ .collect(),
+ )
.await
.map_err(Error::SetupRoutingError)
.map_err(CloseMsg::SetupError)?;
@@ -877,6 +880,7 @@ impl WireguardMonitor {
fn get_pre_tunnel_routes<'a>(
iface_name: &str,
config: &'a Config,
+ #[allow(unused_variables)] userspace_wireguard: bool,
) -> impl Iterator<Item = RequiredRoute> + 'a {
// e.g. utun4
let gateway_node = talpid_routing::Node::device(iface_name.to_string());
@@ -895,8 +899,9 @@ impl WireguardMonitor {
let (node_v4, node_v6) = Self::get_tunnel_nodes(iface_name, config);
#[cfg(any(target_os = "linux", target_os = "macos"))]
- let gateway_routes =
- gateway_routes.map(|route| Self::apply_route_mtu_for_multihop(route, config));
+ let gateway_routes = gateway_routes.map(move |route| {
+ Self::apply_route_mtu_for_multihop(route, config, userspace_wireguard)
+ });
gateway_routes.chain(
config
@@ -917,6 +922,7 @@ impl WireguardMonitor {
fn get_post_tunnel_routes<'a>(
iface_name: &str,
config: &'a Config,
+ #[allow(unused_variables)] userspace_wireguard: bool,
) -> impl Iterator<Item = RequiredRoute> + 'a {
let (node_v4, node_v6) = Self::get_tunnel_nodes(iface_name, config);
let iter = config
@@ -935,19 +941,31 @@ impl WireguardMonitor {
#[cfg(target_os = "linux")]
return iter
.map(|route| route.use_main_table(false))
- .map(|route| Self::apply_route_mtu_for_multihop(route, config));
+ .map(move |route| {
+ Self::apply_route_mtu_for_multihop(route, config, userspace_wireguard)
+ });
#[cfg(target_os = "macos")]
- iter.map(|route| Self::apply_route_mtu_for_multihop(route, config))
+ iter.map(move |route| {
+ Self::apply_route_mtu_for_multihop(route, config, userspace_wireguard)
+ })
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
- fn apply_route_mtu_for_multihop(route: RequiredRoute, config: &Config) -> RequiredRoute {
- use talpid_tunnel::{IPV4_HEADER_SIZE, IPV6_HEADER_SIZE, WIREGUARD_HEADER_SIZE};
+ fn apply_route_mtu_for_multihop(
+ route: RequiredRoute,
+ config: &Config,
+ userspace_wireguard: bool,
+ ) -> RequiredRoute {
+ // For userspace multihop, per-route MTU is unnecessary. Packets are not sent back to
+ // the tunnel interface, so we're not constrained by its MTU.
+ let using_boringtun = userspace_wireguard && cfg!(feature = "boringtun");
- if !config.is_multihop() {
+ if !config.is_multihop() || using_boringtun {
route
} else {
+ use talpid_tunnel::{IPV4_HEADER_SIZE, IPV6_HEADER_SIZE, WIREGUARD_HEADER_SIZE};
+
// Set route MTU by subtracting the WireGuard overhead from the tunnel MTU. Plus
// some margin to make room for padding bytes.
let ip_overhead = match route.prefix.is_ipv4() {