From f2011e62dd2a28789c63761ae6a91bd06f9ccd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Fri, 8 Nov 2024 15:32:45 +0100 Subject: [PATCH 1/6] Bump submodule wireguard-go --- wireguard-go-rs/libwg/wireguard-go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wireguard-go-rs/libwg/wireguard-go b/wireguard-go-rs/libwg/wireguard-go index 3957ef94034a..430e013e6d90 160000 --- a/wireguard-go-rs/libwg/wireguard-go +++ b/wireguard-go-rs/libwg/wireguard-go @@ -1 +1 @@ -Subproject commit 3957ef94034a9cbb47f323b3290620bb849d58e3 +Subproject commit 430e013e6d9008fe35d07f3db3073807c152bdd5 From 8580f9acb75679c7995996c6049ad6f0541d2215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Tue, 5 Nov 2024 15:55:19 +0100 Subject: [PATCH 2/6] Add support for DAITA v2 to talpid tunnel config client Co-authored-by: Markus Pettersson --- .../examples/tuncfg-server.rs | 5 +- .../proto/ephemeralpeer.proto | 38 ++++++++++++ talpid-tunnel-config-client/src/lib.rs | 60 +++++++++++++++++-- 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/talpid-tunnel-config-client/examples/tuncfg-server.rs b/talpid-tunnel-config-client/examples/tuncfg-server.rs index 4ba996431caa..034652d75a4b 100644 --- a/talpid-tunnel-config-client/examples/tuncfg-server.rs +++ b/talpid-tunnel-config-client/examples/tuncfg-server.rs @@ -67,7 +67,10 @@ impl EphemeralPeer for EphemeralPeerImpl { None }; - Ok(Response::new(EphemeralPeerResponseV1 { post_quantum })) + Ok(Response::new(EphemeralPeerResponseV1 { + post_quantum, + daita: None, + })) } } diff --git a/talpid-tunnel-config-client/proto/ephemeralpeer.proto b/talpid-tunnel-config-client/proto/ephemeralpeer.proto index 7c78425b347b..7fc54002e5b1 100644 --- a/talpid-tunnel-config-client/proto/ephemeralpeer.proto +++ b/talpid-tunnel-config-client/proto/ephemeralpeer.proto @@ -41,6 +41,7 @@ message EphemeralPeerRequestV1 { bytes wg_ephemeral_peer_pubkey = 2; PostQuantumRequestV1 post_quantum = 3; DaitaRequestV1 daita = 4; + DaitaRequestV2 daita_v2 = 5; } // The v1 request supports these three algorithms. @@ -58,6 +59,41 @@ message KemPubkeyV1 { message DaitaRequestV1 { bool activate_daita = 1; } +enum DaitaPlatform { + undefined = 0; + windows_native = 1; + linux_wg_go = 2; + macos_wg_go = 3; + ios_wg_go = 4; + android_wg_go = 5; +} + +enum DaitaLevel { + level_default = 0; + level_1 = 1; + level_2 = 2; + level_3 = 3; + level_4 = 4; + level_5 = 5; + level_6 = 6; + level_7 = 7; + level_8 = 8; + level_9 = 9; + level_10 = 10; +} + +message DaitaRequestV2 { + uint32 version = 1; + DaitaPlatform platform = 2; + DaitaLevel level = 3; +} + +message DaitaResponseV2 { + repeated string client_machines = 1; + double max_padding_frac = 2; + double max_blocking_frac = 3; +} + message EphemeralPeerResponseV1 { // The response from the VPN server contains: // * `ciphertexts` - A list of the ciphertexts (the encapsulated shared secrets) for all @@ -80,6 +116,8 @@ message EphemeralPeerResponseV1 { // is known. Both B *and* C must be known to compute any bit in A. This means all involved // KEM algorithms must be broken before the PSK can be computed by an attacker. PostQuantumResponseV1 post_quantum = 1; + + DaitaResponseV2 daita = 2; } message PostQuantumResponseV1 { repeated bytes ciphertexts = 1; } diff --git a/talpid-tunnel-config-client/src/lib.rs b/talpid-tunnel-config-client/src/lib.rs index 2a6163b61da4..fecd9de32b8e 100644 --- a/talpid-tunnel-config-client/src/lib.rs +++ b/talpid-tunnel-config-client/src/lib.rs @@ -22,6 +22,8 @@ mod proto { tonic::include_proto!("ephemeralpeer"); } +const DAITA_VERSION: u32 = 2; + #[derive(Debug)] pub enum Error { GrpcConnectError(tonic::transport::Error), @@ -35,6 +37,7 @@ pub enum Error { InvalidCiphertextCount { actual: usize, }, + MissingDaitaResponse, #[cfg(target_os = "ios")] TcpConnectionExpired, #[cfg(target_os = "ios")] @@ -59,6 +62,7 @@ impl std::fmt::Display for Error { InvalidCiphertextCount { actual } => { write!(f, "Expected 2 ciphertext in the response, got {actual}") } + MissingDaitaResponse => "Expected DAITA configuration in response".fmt(f), #[cfg(target_os = "ios")] TcpConnectionExpired => "TCP connection is already shut down".fmt(f), #[cfg(target_os = "ios")] @@ -83,6 +87,13 @@ pub const CONFIG_SERVICE_PORT: u16 = 1337; pub struct EphemeralPeer { pub psk: Option, + pub daita: Option, +} + +pub struct DaitaSettings { + pub client_machines: Vec, + pub max_padding_frac: f64, + pub max_blocking_frac: f64, } /// Negotiate a short-lived peer with a PQ-safe PSK or with DAITA enabled. @@ -125,16 +136,21 @@ pub async fn request_ephemeral_peer_with( wg_parent_pubkey: parent_pubkey.as_bytes().to_vec(), wg_ephemeral_peer_pubkey: ephemeral_pubkey.as_bytes().to_vec(), post_quantum: pq_request, - daita: Some(proto::DaitaRequestV1 { - activate_daita: enable_daita, + daita: None, + daita_v2: enable_daita.then(|| proto::DaitaRequestV2 { + // TODO + level: i32::from(proto::DaitaLevel::LevelDefault), + platform: i32::from(get_platform()), + version: DAITA_VERSION, }), }) .await .map_err(Error::GrpcError)?; + let response = response.into_inner(); + let psk = if let Some((cme_kem_secret, ml_kem_secret)) = kem_secrets { let ciphertexts = response - .into_inner() .post_quantum .ok_or(Error::MissingCiphertexts)? .ciphertexts; @@ -176,7 +192,43 @@ pub async fn request_ephemeral_peer_with( None }; - Ok(EphemeralPeer { psk }) + let daita = response.daita.map(|daita| DaitaSettings { + client_machines: daita.client_machines, + max_padding_frac: daita.max_padding_frac, + max_blocking_frac: daita.max_blocking_frac, + }); + if daita.is_none() && enable_daita { + return Err(Error::MissingDaitaResponse); + } + + Ok(EphemeralPeer { psk, daita }) +} + +fn get_platform() -> proto::DaitaPlatform { + #[cfg(windows)] + { + proto::DaitaPlatform::WindowsNative + } + + #[cfg(target_os = "linux")] + { + proto::DaitaPlatform::LinuxWgGo + } + + #[cfg(target_os = "macos")] + { + proto::DaitaPlatform::MacosWgGo + } + + #[cfg(target_os = "android")] + { + proto::DaitaPlatform::AndroidWgGo + } + + #[cfg(target_os = "ios")] + { + proto::DaitaPlatform::IosWgGo + } } async fn post_quantum_secrets() -> ( From f1ea8f1b344a0fcb33a7c13b66f2bd9b952252d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Tue, 5 Nov 2024 16:20:19 +0100 Subject: [PATCH 3/6] Use dynamic DAITA machines in wireguard-go Co-authored-by: Markus Pettersson --- talpid-tunnel-config-client/src/lib.rs | 72 ++++++++++--------- talpid-wireguard/src/connectivity/mock.rs | 5 +- talpid-wireguard/src/ephemeral.rs | 36 +++++++--- talpid-wireguard/src/lib.rs | 21 +++--- talpid-wireguard/src/wireguard_go/mod.rs | 36 +++------- .../src/wireguard_kernel/netlink_tunnel.rs | 3 +- .../src/wireguard_kernel/nm_tunnel.rs | 3 +- wireguard-go-rs/libwg/libwg_daita.go | 7 +- wireguard-go-rs/src/lib.rs | 6 ++ 9 files changed, 103 insertions(+), 86 deletions(-) diff --git a/talpid-tunnel-config-client/src/lib.rs b/talpid-tunnel-config-client/src/lib.rs index fecd9de32b8e..f7d559f6417d 100644 --- a/talpid-tunnel-config-client/src/lib.rs +++ b/talpid-tunnel-config-client/src/lib.rs @@ -22,6 +22,7 @@ mod proto { tonic::include_proto!("ephemeralpeer"); } +#[cfg(all(unix, not(target_os = "ios")))] const DAITA_VERSION: u32 = 2; #[derive(Debug)] @@ -87,6 +88,7 @@ pub const CONFIG_SERVICE_PORT: u16 = 1337; pub struct EphemeralPeer { pub psk: Option, + #[cfg(all(unix, not(target_os = "ios")))] pub daita: Option, } @@ -136,9 +138,16 @@ pub async fn request_ephemeral_peer_with( wg_parent_pubkey: parent_pubkey.as_bytes().to_vec(), wg_ephemeral_peer_pubkey: ephemeral_pubkey.as_bytes().to_vec(), post_quantum: pq_request, + #[cfg(any(windows, target_os = "ios"))] + daita: Some(proto::DaitaRequestV1 { + activate_daita: enable_daita, + }), + #[cfg(any(windows, target_os = "ios"))] + daita_v2: None, + #[cfg(all(unix, not(target_os = "ios")))] daita: None, + #[cfg(all(unix, not(target_os = "ios")))] daita_v2: enable_daita.then(|| proto::DaitaRequestV2 { - // TODO level: i32::from(proto::DaitaLevel::LevelDefault), platform: i32::from(get_platform()), version: DAITA_VERSION, @@ -192,43 +201,42 @@ pub async fn request_ephemeral_peer_with( None }; - let daita = response.daita.map(|daita| DaitaSettings { - client_machines: daita.client_machines, - max_padding_frac: daita.max_padding_frac, - max_blocking_frac: daita.max_blocking_frac, - }); - if daita.is_none() && enable_daita { - return Err(Error::MissingDaitaResponse); - } - - Ok(EphemeralPeer { psk, daita }) -} - -fn get_platform() -> proto::DaitaPlatform { - #[cfg(windows)] - { - proto::DaitaPlatform::WindowsNative - } - - #[cfg(target_os = "linux")] - { - proto::DaitaPlatform::LinuxWgGo - } - - #[cfg(target_os = "macos")] + #[cfg(all(unix, not(target_os = "ios")))] { - proto::DaitaPlatform::MacosWgGo + let daita = response.daita.map(|daita| DaitaSettings { + client_machines: daita.client_machines, + max_padding_frac: daita.max_padding_frac, + max_blocking_frac: daita.max_blocking_frac, + }); + if daita.is_none() && enable_daita { + return Err(Error::MissingDaitaResponse); + } + Ok(EphemeralPeer { psk, daita }) } - #[cfg(target_os = "android")] + #[cfg(any(windows, target_os = "ios"))] { - proto::DaitaPlatform::AndroidWgGo + Ok(EphemeralPeer { psk }) } +} - #[cfg(target_os = "ios")] - { - proto::DaitaPlatform::IosWgGo - } +#[cfg(all(unix, not(target_os = "ios")))] +const fn get_platform() -> proto::DaitaPlatform { + use proto::DaitaPlatform; + const PLATFORM: DaitaPlatform = if cfg!(target_os = "windows") { + DaitaPlatform::WindowsNative + } else if cfg!(target_os = "linux") { + DaitaPlatform::LinuxWgGo + } else if cfg!(target_os = "macos") { + DaitaPlatform::MacosWgGo + } else if cfg!(target_os = "android") { + DaitaPlatform::AndroidWgGo + } else if cfg!(target_os = "ios") { + DaitaPlatform::IosWgGo + } else { + panic!("This platform does not support DAITA V2") + }; + PLATFORM } async fn post_quantum_secrets() -> ( diff --git a/talpid-wireguard/src/connectivity/mock.rs b/talpid-wireguard/src/connectivity/mock.rs index 892f3966ea5a..eea3004bfc71 100644 --- a/talpid-wireguard/src/connectivity/mock.rs +++ b/talpid-wireguard/src/connectivity/mock.rs @@ -118,7 +118,10 @@ impl Tunnel for MockTunnel { } #[cfg(daita)] - fn start_daita(&mut self) -> std::result::Result<(), TunnelError> { + fn start_daita( + &mut self, + #[cfg(not(target_os = "windows"))] _: talpid_tunnel_config_client::DaitaSettings, + ) -> std::result::Result<(), TunnelError> { Ok(()) } } diff --git a/talpid-wireguard/src/ephemeral.rs b/talpid-wireguard/src/ephemeral.rs index a9283fcb2e2b..31f3957253e9 100644 --- a/talpid-wireguard/src/ephemeral.rs +++ b/talpid-wireguard/src/ephemeral.rs @@ -16,7 +16,8 @@ use std::{ use talpid_tunnel::tun_provider::TunProvider; use ipnetwork::IpNetwork; -use talpid_types::net::wireguard::{PresharedKey, PrivateKey, PublicKey}; +use talpid_tunnel_config_client::EphemeralPeer; +use talpid_types::net::wireguard::{PrivateKey, PublicKey}; use tokio::sync::Mutex as AsyncMutex; const INITIAL_PSK_EXCHANGE_TIMEOUT: Duration = Duration::from_secs(8); @@ -100,7 +101,7 @@ async fn config_ephemeral_peers_inner( let close_obfs_sender = close_obfs_sender.clone(); let exit_should_have_daita = config.daita && !config.is_multihop(); - let exit_psk = request_ephemeral_peer( + let exit_ephemeral_peer = request_ephemeral_peer( retry_attempt, config, ephemeral_private_key.public_key(), @@ -109,6 +110,9 @@ async fn config_ephemeral_peers_inner( ) .await?; + #[cfg(not(target_os = "windows"))] + let mut daita = exit_ephemeral_peer.daita; + log::debug!("Retrieved ephemeral peer"); if config.is_multihop() { @@ -130,8 +134,7 @@ async fn config_ephemeral_peers_inner( &tun_provider, ) .await?; - - let entry_psk = request_ephemeral_peer( + let entry_ephemeral_peer = request_ephemeral_peer( retry_attempt, &entry_config, ephemeral_private_key.public_key(), @@ -141,10 +144,14 @@ async fn config_ephemeral_peers_inner( .await?; log::debug!("Successfully exchanged PSK with entry peer"); - config.entry_peer.psk = entry_psk; + config.entry_peer.psk = entry_ephemeral_peer.psk; + #[cfg(not(target_os = "windows"))] + { + daita = entry_ephemeral_peer.daita; + } } - config.exit_peer_mut().psk = exit_psk; + config.exit_peer_mut().psk = exit_ephemeral_peer.psk; #[cfg(daita)] if config.daita { log::trace!("Enabling constant packet size for entry peer"); @@ -165,9 +172,22 @@ async fn config_ephemeral_peers_inner( #[cfg(daita)] if config.daita { + #[cfg(not(target_os = "windows"))] + let Some(daita) = daita + else { + unreachable!("missing DAITA settings"); + }; + // Start local DAITA machines let mut tunnel = tunnel.lock().await; if let Some(tunnel) = tunnel.as_mut() { + #[cfg(not(target_os = "windows"))] + tunnel + .start_daita(daita) + .map_err(Error::TunnelError) + .map_err(CloseMsg::SetupError)?; + + #[cfg(target_os = "windows")] tunnel .start_daita() .map_err(Error::TunnelError) @@ -254,7 +274,7 @@ async fn request_ephemeral_peer( wg_psk_pubkey: PublicKey, enable_pq: bool, enable_daita: bool, -) -> std::result::Result, CloseMsg> { +) -> std::result::Result { log::debug!("Requesting ephemeral peer"); let timeout = std::cmp::min( @@ -281,5 +301,5 @@ async fn request_ephemeral_peer( .map_err(Error::EphemeralPeerNegotiationError) .map_err(CloseMsg::SetupError)?; - Ok(ephemeral.psk) + Ok(ephemeral) } diff --git a/talpid-wireguard/src/lib.rs b/talpid-wireguard/src/lib.rs index c3cf9a554fa8..2d282c6315c6 100644 --- a/talpid-wireguard/src/lib.rs +++ b/talpid-wireguard/src/lib.rs @@ -28,6 +28,8 @@ use talpid_tunnel::{ tun_provider::TunProvider, EventHook, TunnelArgs, TunnelEvent, TunnelMetadata, }; +#[cfg(not(target_os = "windows"))] +use talpid_tunnel_config_client::DaitaSettings; use talpid_types::{ net::{wireguard::TunnelParameters, AllowedTunnelTraffic, Endpoint, TransportProtocol}, BoxedError, ErrorExt, @@ -196,6 +198,7 @@ impl WireguardMonitor { args.runtime.clone(), &config, log_path, + #[cfg(target_os = "windows")] args.resource_dir, args.tun_provider.clone(), #[cfg(target_os = "windows")] @@ -426,7 +429,6 @@ impl WireguardMonitor { let tunnel = Self::open_wireguard_go_tunnel( &config, log_path, - args.resource_dir, args.tun_provider.clone(), // In case we should negotiate an ephemeral peer, we should specify via AllowedIPs // that we only allows traffic to/from the gateway. This is only needed on Android @@ -634,7 +636,7 @@ impl WireguardMonitor { runtime: tokio::runtime::Handle, config: &Config, log_path: Option<&Path>, - resource_dir: &Path, + #[cfg(windows)] resource_dir: &Path, tun_provider: Arc>, #[cfg(windows)] route_manager: talpid_routing::RouteManagerHandle, #[cfg(windows)] setup_done_tx: mpsc::Sender>, @@ -646,8 +648,7 @@ impl WireguardMonitor { // If DAITA is enabled, wireguard-go has to be used. if config.daita { let tunnel = - Self::open_wireguard_go_tunnel(config, log_path, resource_dir, tun_provider) - .map(Box::new)?; + Self::open_wireguard_go_tunnel(config, log_path, tun_provider).map(Box::new)?; return Ok(tunnel); } @@ -699,8 +700,6 @@ impl WireguardMonitor { let tunnel = Self::open_wireguard_go_tunnel( config, log_path, - #[cfg(daita)] - resource_dir, tun_provider, #[cfg(target_os = "android")] gateway_only, @@ -715,7 +714,6 @@ impl WireguardMonitor { fn open_wireguard_go_tunnel( config: &Config, log_path: Option<&Path>, - #[cfg(daita)] resource_dir: &Path, tun_provider: Arc>, #[cfg(target_os = "android")] gateway_only: bool, #[cfg(target_os = "android")] connectivity_check: connectivity::Check< @@ -733,8 +731,6 @@ impl WireguardMonitor { log_path, tun_provider, routes, - #[cfg(daita)] - resource_dir, ) .map_err(Error::TunnelError)?; @@ -757,8 +753,6 @@ impl WireguardMonitor { log_path, tun_provider, routes, - #[cfg(daita)] - resource_dir, connectivity_check, ) .map_err(Error::TunnelError)? @@ -769,8 +763,6 @@ impl WireguardMonitor { log_path, tun_provider, routes, - #[cfg(daita)] - resource_dir, connectivity_check, ) .map_err(Error::TunnelError)? @@ -994,6 +986,9 @@ pub(crate) trait Tunnel: Send { ) -> Pin> + Send + 'a>>; #[cfg(daita)] /// A [`Tunnel`] capable of using DAITA. + #[cfg(not(target_os = "windows"))] + fn start_daita(&mut self, settings: DaitaSettings) -> std::result::Result<(), TunnelError>; + #[cfg(target_os = "windows")] fn start_daita(&mut self) -> std::result::Result<(), TunnelError>; } diff --git a/talpid-wireguard/src/wireguard_go/mod.rs b/talpid-wireguard/src/wireguard_go/mod.rs index e2072c291ed9..c0775ac33984 100644 --- a/talpid-wireguard/src/wireguard_go/mod.rs +++ b/talpid-wireguard/src/wireguard_go/mod.rs @@ -13,19 +13,18 @@ use crate::connectivity; use crate::logging::{clean_up_logging, initialize_logging}; use ipnetwork::IpNetwork; #[cfg(daita)] -use once_cell::sync::OnceCell; -#[cfg(daita)] -use std::{ffi::CString, fs, path::PathBuf}; +use std::ffi::CString; use std::{ future::Future, os::unix::io::{AsRawFd, RawFd}, - path::Path, + path::{Path, PathBuf}, pin::Pin, sync::{Arc, Mutex}, }; #[cfg(target_os = "android")] use talpid_tunnel::tun_provider::Error as TunProviderError; use talpid_tunnel::tun_provider::{Tun, TunProvider}; +use talpid_tunnel_config_client::DaitaSettings; #[cfg(target_os = "android")] use talpid_types::net::wireguard::PeerConfig; use talpid_types::BoxedError; @@ -115,8 +114,6 @@ impl WgGoTunnel { let log_path = state._logging_context.path.clone(); let tun_provider = Arc::clone(&state.tun_provider); let routes = config.get_tunnel_destinations(); - #[cfg(daita)] - let resource_dir = state.resource_dir.clone(); match self { WgGoTunnel::Multihop(state) if !config.is_multihop() => { @@ -126,7 +123,6 @@ impl WgGoTunnel { log_path.as_deref(), tun_provider, routes, - &resource_dir, connectivity_checker, ) } @@ -138,7 +134,6 @@ impl WgGoTunnel { log_path.as_deref(), tun_provider, routes, - &resource_dir, connectivity_checker, ) } @@ -169,8 +164,6 @@ pub(crate) struct WgGoTunnelState { #[cfg(target_os = "android")] tun_provider: Arc>, #[cfg(daita)] - resource_dir: PathBuf, - #[cfg(daita)] config: Config, // HACK: Check is not Clone, so we have to pass this around .. // This is conceptually the connection between this Tunnel and the currently running @@ -224,7 +217,6 @@ impl WgGoTunnel { log_path: Option<&Path>, tun_provider: Arc>, routes: impl Iterator, - #[cfg(daita)] resource_dir: &Path, ) -> Result { let (tunnel_device, tunnel_fd) = Self::get_tunnel(tun_provider, config, routes)?; @@ -251,8 +243,6 @@ impl WgGoTunnel { _tunnel_device: tunnel_device, _logging_context: logging_context, #[cfg(daita)] - resource_dir: resource_dir.to_owned(), - #[cfg(daita)] config: config.clone(), })) } @@ -303,7 +293,6 @@ impl WgGoTunnel { log_path: Option<&Path>, tun_provider: Arc>, routes: impl Iterator, - #[cfg(daita)] resource_dir: &Path, mut connectivity_check: connectivity::Check, ) -> Result { let (mut tunnel_device, tunnel_fd) = @@ -334,8 +323,6 @@ impl WgGoTunnel { _logging_context: logging_context, tun_provider, #[cfg(daita)] - resource_dir: resource_dir.to_owned(), - #[cfg(daita)] config: config.clone(), connectivity_checker: None, }); @@ -353,7 +340,6 @@ impl WgGoTunnel { log_path: Option<&Path>, tun_provider: Arc>, routes: impl Iterator, - #[cfg(daita)] resource_dir: &Path, mut connectivity_check: connectivity::Check, ) -> Result { let (mut tunnel_device, tunnel_fd) = @@ -400,8 +386,6 @@ impl WgGoTunnel { _logging_context: logging_context, tun_provider, #[cfg(daita)] - resource_dir: resource_dir.to_owned(), - #[cfg(daita)] config: config.clone(), connectivity_checker: None, }); @@ -477,20 +461,22 @@ impl Tunnel for WgGoTunnel { } #[cfg(daita)] - fn start_daita(&mut self) -> Result<()> { - static MAYBENOT_MACHINES: OnceCell = OnceCell::new(); - let machines = MAYBENOT_MACHINES - .get_or_try_init(|| load_maybenot_machines(&self.as_state().resource_dir))?; - + fn start_daita(&mut self, settings: DaitaSettings) -> Result<()> { log::info!("Initializing DAITA for wireguard device"); let config = &self.as_state().config; let peer_public_key = &config.entry_peer.public_key; + let machines = settings.client_machines.join("\n"); + let machines = + CString::new(machines).map_err(|err| TunnelError::StartDaita(Box::new(err)))?; + self.as_state() .tunnel_handle .activate_daita( peer_public_key.as_bytes(), - machines, + &machines, + settings.max_padding_frac, + settings.max_blocking_frac, DAITA_EVENTS_CAPACITY, DAITA_ACTIONS_CAPACITY, ) diff --git a/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs b/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs index 52d8616c029a..8b84b3769d99 100644 --- a/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs +++ b/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs @@ -1,6 +1,7 @@ use std::pin::Pin; use futures::Future; +use talpid_tunnel_config_client::DaitaSettings; use crate::config::MULLVAD_INTERFACE_NAME; @@ -131,7 +132,7 @@ impl Tunnel for NetlinkTunnel { } /// Outright fail to start - this tunnel type does not support DAITA. - fn start_daita(&mut self) -> std::result::Result<(), TunnelError> { + fn start_daita(&mut self, _: DaitaSettings) -> std::result::Result<(), TunnelError> { Err(TunnelError::DaitaNotSupported) } } diff --git a/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs index 76cfbcaddd6b..070e3d1ee9e8 100644 --- a/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs +++ b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs @@ -13,6 +13,7 @@ use talpid_dbus::{ WireguardTunnel, }, }; +use talpid_tunnel_config_client::DaitaSettings; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -114,7 +115,7 @@ impl Tunnel for NetworkManagerTunnel { } /// Outright fail to start - this tunnel type does not support DAITA. - fn start_daita(&mut self) -> std::result::Result<(), TunnelError> { + fn start_daita(&mut self, _: DaitaSettings) -> std::result::Result<(), TunnelError> { Err(TunnelError::DaitaNotSupported) } } diff --git a/wireguard-go-rs/libwg/libwg_daita.go b/wireguard-go-rs/libwg/libwg_daita.go index fbfceec8f0c9..b73be376a3e9 100644 --- a/wireguard-go-rs/libwg/libwg_daita.go +++ b/wireguard-go-rs/libwg/libwg_daita.go @@ -19,11 +19,8 @@ import ( "golang.zx2c4.com/wireguard/device" ) -const maxPaddingBytes = 0.0 -const maxBlockingBytes = 0.0 - //export wgActivateDaita -func wgActivateDaita(tunnelHandle C.int32_t, peerPubkey *C.uint8_t, machines *C.char, eventsCapacity C.uint32_t, actionsCapacity C.uint32_t) C.int32_t { +func wgActivateDaita(tunnelHandle C.int32_t, peerPubkey *C.uint8_t, machines *C.char, maxPaddingFrac C.double, maxBlockingFrac C.double, eventsCapacity C.uint32_t, actionsCapacity C.uint32_t) C.int32_t { tunnel, err := tunnels.Get(int32(tunnelHandle)) if err != nil { @@ -46,7 +43,7 @@ func wgActivateDaita(tunnelHandle C.int32_t, peerPubkey *C.uint8_t, machines *C. return ERROR_UNKNOWN_PEER } - if !peer.EnableDaita(goStringFixed((*C.char)(machines)), uint(eventsCapacity), uint(actionsCapacity), maxPaddingBytes, maxBlockingBytes) { + if !peer.EnableDaita(goStringFixed((*C.char)(machines)), uint(eventsCapacity), uint(actionsCapacity), float64(maxPaddingFrac), float64(maxBlockingFrac)) { return ERROR_ENABLE_DAITA } diff --git a/wireguard-go-rs/src/lib.rs b/wireguard-go-rs/src/lib.rs index 851fd47b9ffb..3e75506f6126 100644 --- a/wireguard-go-rs/src/lib.rs +++ b/wireguard-go-rs/src/lib.rs @@ -191,6 +191,8 @@ impl Tunnel { &self, peer_public_key: &[u8; 32], machines: &CStr, + max_padding_frac: f64, + max_blocking_frac: f64, events_capacity: u32, actions_capacity: u32, ) -> Result<(), Error> { @@ -200,6 +202,8 @@ impl Tunnel { self.handle, peer_public_key.as_ptr(), machines.as_ptr(), + max_padding_frac, + max_blocking_frac, events_capacity, actions_capacity, ) @@ -342,6 +346,8 @@ mod ffi { tunnel_handle: i32, peer_public_key: *const u8, machines: *const c_char, + max_padding_frac: f64, + max_blocking_frac: f64, events_capacity: u32, actions_capacity: u32, ) -> i32; From 20931c2b4ae8dd2b470bc2e4abec01b2cdde7ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Fri, 8 Nov 2024 15:28:06 +0100 Subject: [PATCH 4/6] Adjust DAITA buffer sizes Previous size resulted in occasional dropped events --- talpid-wireguard/src/wireguard_go/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/talpid-wireguard/src/wireguard_go/mod.rs b/talpid-wireguard/src/wireguard_go/mod.rs index c0775ac33984..11c5adf1d46a 100644 --- a/talpid-wireguard/src/wireguard_go/mod.rs +++ b/talpid-wireguard/src/wireguard_go/mod.rs @@ -33,11 +33,11 @@ const MAX_PREPARE_TUN_ATTEMPTS: usize = 4; /// Maximum number of events that can be stored in the underlying buffer #[cfg(daita)] -const DAITA_EVENTS_CAPACITY: u32 = 1000; +const DAITA_EVENTS_CAPACITY: u32 = 2048; /// Maximum number of actions that can be stored in the underlying buffer #[cfg(daita)] -const DAITA_ACTIONS_CAPACITY: u32 = 1000; +const DAITA_ACTIONS_CAPACITY: u32 = 1024; type Result = std::result::Result; From 6546f77f4bb57072027944004bffdd20a7782c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Fri, 8 Nov 2024 15:38:58 +0100 Subject: [PATCH 5/6] Remove unused test --- talpid-wireguard/src/wireguard_go/mod.rs | 30 ------------------------ 1 file changed, 30 deletions(-) diff --git a/talpid-wireguard/src/wireguard_go/mod.rs b/talpid-wireguard/src/wireguard_go/mod.rs index 11c5adf1d46a..39b23a185aeb 100644 --- a/talpid-wireguard/src/wireguard_go/mod.rs +++ b/talpid-wireguard/src/wireguard_go/mod.rs @@ -486,36 +486,6 @@ impl Tunnel for WgGoTunnel { } } -#[cfg(daita)] -fn load_maybenot_machines(resource_dir: &Path) -> Result { - let path = resource_dir.join("maybenot_machines"); - log::debug!("Reading maybenot machines from {}", path.display()); - - let machines = fs::read_to_string(path).map_err(|e| TunnelError::StartDaita(Box::new(e)))?; - let machines = CString::new(machines).map_err(|e| TunnelError::StartDaita(Box::new(e)))?; - Ok(machines) -} - -#[cfg(test)] -mod test { - /// Test whether `maybenot_machines` in dist-assets contains valid machines. - /// TODO: Remove when switching to dynamic machines. - #[cfg(daita)] - #[test] - fn test_load_maybenot_machines() { - use super::load_maybenot_machines; - use std::path::PathBuf; - - let dist_assets = std::env::var("CARGO_MANIFEST_DIR") - .map(PathBuf::from) - .expect("CARGO_MANIFEST_DIR env var not set") - .join("..") - .join("dist-assets"); - let machines = load_maybenot_machines(&dist_assets).unwrap(); - wireguard_go_rs::validate_maybenot_machines(&machines).unwrap(); - } -} - mod stats { use super::{Stats, StatsMap}; From 39a61f717cca86261023aa4bec7952d6c1b7f951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Mon, 11 Nov 2024 18:27:51 +0100 Subject: [PATCH 6/6] Remove machines file except on Windows --- .github/workflows/android-app.yml | 3 --- android/app/build.gradle.kts | 10 ---------- android/scripts/update-lockfile.sh | 1 - .../mullvad/mullvadvpn/service/MullvadVpnService.kt | 2 -- build-apk.sh | 3 --- desktop/packages/mullvad-vpn/tasks/distribution.js | 2 -- 6 files changed, 21 deletions(-) diff --git a/.github/workflows/android-app.yml b/.github/workflows/android-app.yml index a016fad97e16..5e784b5d6904 100644 --- a/.github/workflows/android-app.yml +++ b/.github/workflows/android-app.yml @@ -324,9 +324,6 @@ jobs: name: relay-list path: android/app/build/extraAssets - - name: Copy maybenot machines to asset directory - run: cp dist-assets/maybenot_machines android/app/build/extraAssets/ - - name: Build app uses: burrunan/gradle-cache-action@v1 with: diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index f2a76b6d8d81..d62df346450f 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -19,7 +19,6 @@ plugins { val repoRootPath = rootProject.projectDir.absoluteFile.parentFile.absolutePath val extraAssetsDirectory = layout.buildDirectory.dir("extraAssets").get() val relayListPath = extraAssetsDirectory.file("relays.json").asFile -val maybenotMachinesFile = extraAssetsDirectory.file("maybenot_machines").asFile val defaultChangelogAssetsDirectory = "$repoRootPath/android/src/main/play/release-notes/" val extraJniDirectory = layout.buildDirectory.dir("extraJni").get() @@ -245,7 +244,6 @@ android { // Ensure all relevant assemble tasks depend on our ensure tasks. tasks["assemble$capitalizedVariantName"].apply { dependsOn(tasks["ensureRelayListExist"]) - dependsOn(tasks["ensureMaybenotMachinesExist"]) dependsOn(tasks["ensureJniDirectoryExist"]) dependsOn(tasks["ensureValidVersionCode"]) } @@ -288,14 +286,6 @@ tasks.register("ensureRelayListExist") { } } -tasks.register("ensureMaybenotMachinesExist") { - doLast { - if (!maybenotMachinesFile.exists()) { - throw GradleException("Missing maybenot machines: $maybenotMachinesFile") - } - } -} - tasks.register("ensureJniDirectoryExist") { doLast { if (!extraJniDirectory.asFile.exists()) { diff --git a/android/scripts/update-lockfile.sh b/android/scripts/update-lockfile.sh index e062fd08c352..e400caed72ae 100755 --- a/android/scripts/update-lockfile.sh +++ b/android/scripts/update-lockfile.sh @@ -22,7 +22,6 @@ GRADLE_TASKS=( EXCLUDED_GRADLE_TASKS=( "-xensureRelayListExist" "-xensureJniDirectoryExist" - "-xensureMaybenotMachinesExist" ) export GRADLE_OPTS diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt index 55aa416e537b..458f592f1b85 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt @@ -32,7 +32,6 @@ import org.koin.android.ext.android.getKoin import org.koin.core.context.loadKoinModules private const val RELAY_LIST_ASSET_NAME = "relays.json" -private const val MAYBENOT_MACHINES_ASSET_NAME = "maybenot_machines" class MullvadVpnService : TalpidVpnService() { @@ -224,7 +223,6 @@ class MullvadVpnService : TalpidVpnService() { private fun Context.prepareFiles() { extractAndOverwriteIfAssetMoreRecent(RELAY_LIST_ASSET_NAME) - extractAndOverwriteIfAssetMoreRecent(MAYBENOT_MACHINES_ASSET_NAME) } companion object { diff --git a/build-apk.sh b/build-apk.sh index 4f1162807585..da09e0647962 100755 --- a/build-apk.sh +++ b/build-apk.sh @@ -130,9 +130,6 @@ done echo "Updating relays.json..." cargo run --bin relay_list "${CARGO_ARGS[@]}" > android/app/build/extraAssets/relays.json -echo "Copying maybenot machines..." -cp dist-assets/maybenot_machines android/app/build/extraAssets/ - cd "$SCRIPT_DIR/android" $GRADLE_CMD --console plain "${GRADLE_TASKS[@]}" diff --git a/desktop/packages/mullvad-vpn/tasks/distribution.js b/desktop/packages/mullvad-vpn/tasks/distribution.js index c8282434bd55..48f5b79f337d 100644 --- a/desktop/packages/mullvad-vpn/tasks/distribution.js +++ b/desktop/packages/mullvad-vpn/tasks/distribution.js @@ -111,7 +111,6 @@ function newConfig() { { from: distAssets('uninstall_macos.sh'), to: './uninstall.sh' }, { from: buildAssets('shell-completions/_mullvad'), to: '.' }, { from: buildAssets('shell-completions/mullvad.fish'), to: '.' }, - { from: distAssets('maybenot_machines'), to: '.' }, ], }, @@ -208,7 +207,6 @@ function newConfig() { { from: distAssets(path.join('linux', 'apparmor_mullvad')), to: '.' }, { from: distAssets(path.join('binaries', '${env.TARGET_TRIPLE}', 'openvpn')), to: '.' }, { from: distAssets(path.join('binaries', '${env.TARGET_TRIPLE}', 'apisocks5')), to: '.' }, - { from: distAssets('maybenot_machines'), to: '.' }, ], },