From f31112ec47c4184b4c0bab8c11099a654d99dd17 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Mon, 19 Aug 2024 14:47:35 +0200 Subject: [PATCH] Add daita.enabled and daita.use_anywhere rpc calls --- gui/src/main/daemon-rpc.ts | 15 ++--- gui/src/main/settings.ts | 7 ++- gui/src/renderer/app.tsx | 7 ++- .../renderer/components/WireguardSettings.tsx | 8 +-- gui/src/shared/ipc-schema.ts | 4 +- mullvad-cli/src/cmds/tunnel.rs | 25 ++++++--- mullvad-daemon/src/lib.rs | 56 +++++++++++++++++++ mullvad-daemon/src/management_interface.rs | 30 ++++++++++ .../proto/management_interface.proto | 2 + mullvad-management-interface/src/client.rs | 15 +++++ .../src/relay_selector/mod.rs | 2 +- 11 files changed, 142 insertions(+), 29 deletions(-) diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index 0e738306610d..04f17de927f6 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -36,7 +36,6 @@ import { IAppVersionInfo, IBridgeConstraints, ICustomList, - IDaitaSettings, IDevice, IDeviceRemoval, IDnsOptions, @@ -573,14 +572,12 @@ export class DaemonRpc { await this.callBool(this.client.prepareRestartV2, quit); } - public async setDaitaSettings(daitaSettings: IDaitaSettings): Promise { - const grpcDaitaSettings = new grpcTypes.DaitaSettings(); - grpcDaitaSettings.setEnabled(daitaSettings.enabled); - grpcDaitaSettings.setUseAnywhere(daitaSettings.useAnywhere); - await this.call( - this.client.setDaitaSettings, - grpcDaitaSettings, - ); + public async setEnableDaita(value: boolean): Promise { + await this.callBool(this.client.setEnableDaita, value); + } + + public async setDaitaUseAnywhere(value: boolean): Promise { + await this.callBool(this.client.setDaitaUseAnywhere, value); } public async listDevices(accountToken: AccountToken): Promise> { diff --git a/gui/src/main/settings.ts b/gui/src/main/settings.ts index 22238c72c459..6ec4e0b09d2f 100644 --- a/gui/src/main/settings.ts +++ b/gui/src/main/settings.ts @@ -107,8 +107,11 @@ export default class Settings implements Readonly { const settings = await fs.readFile(path); return this.daemonRpc.applyJsonSettings(settings.toString()); }); - IpcMainEventChannel.settings.handleSetDaitaSettings((daitaSettings) => { - return this.daemonRpc.setDaitaSettings(daitaSettings); + IpcMainEventChannel.settings.handleSetEnableDaita((value) => { + return this.daemonRpc.setEnableDaita(value); + }); + IpcMainEventChannel.settings.handleSetDaitaUseAnywhere((value) => { + return this.daemonRpc.setDaitaUseAnywhere(value); }); IpcMainEventChannel.guiSettings.handleSetEnableSystemNotifications((flag: boolean) => { diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index e0655707c2e5..28b27416f680 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -19,7 +19,6 @@ import { IAccountData, IAppVersionInfo, ICustomList, - IDaitaSettings, IDevice, IDeviceRemoval, IDnsOptions, @@ -345,8 +344,10 @@ export default class AppRenderer { IpcRendererEventChannel.splitTunneling.forgetManuallyAddedApplication(application); public setObfuscationSettings = (obfuscationSettings: ObfuscationSettings) => IpcRendererEventChannel.settings.setObfuscationSettings(obfuscationSettings); - public setDaitaSettings = (daitaSettings: IDaitaSettings) => - IpcRendererEventChannel.settings.setDaitaSettings(daitaSettings); + public setEnableDaita = (value: boolean) => + IpcRendererEventChannel.settings.setEnableDaita(value); + public setDaitaUseAnywhere = (value: boolean) => + IpcRendererEventChannel.settings.setDaitaUseAnywhere(value); public collectProblemReport = (toRedact: string | undefined) => IpcRendererEventChannel.problemReport.collectLogs(toRedact); public viewLog = (path: string) => IpcRendererEventChannel.problemReport.viewLog(path); diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx index 8faaeb168e2a..f530d981bd61 100644 --- a/gui/src/renderer/components/WireguardSettings.tsx +++ b/gui/src/renderer/components/WireguardSettings.tsx @@ -555,7 +555,7 @@ function MtuSetting() { } function DaitaSettings() { - const { setDaitaSettings } = useAppContext(); + const { setEnableDaita, setDaitaUseAnywhere } = useAppContext(); const daita = useSelector((state) => state.settings.wireguard.daita?.enabled ?? false); const useAnywhere = useSelector((state) => state.settings.wireguard.daita?.useAnywhere ?? false); @@ -565,16 +565,16 @@ function DaitaSettings() { if (value) { showConfirmationDialog(); } else { - void setDaitaSettings({ enabled: value, useAnywhere: useAnywhere }); + void setEnableDaita(value); } }, []); const setUseAnywhere = useCallback((value: boolean) => { - void setDaitaSettings({ enabled: daita, useAnywhere: value }); + void setDaitaUseAnywhere(value); }, []); const confirmDaita = useCallback(() => { - void setDaitaSettings({ enabled: true, useAnywhere: useAnywhere }); + void setEnableDaita(true); hideConfirmationDialog(); }, []); diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts index acbb6366d262..78acc9fae99b 100644 --- a/gui/src/shared/ipc-schema.ts +++ b/gui/src/shared/ipc-schema.ts @@ -14,7 +14,6 @@ import { IAccountData, IAppVersionInfo, ICustomList, - IDaitaSettings, IDevice, IDeviceRemoval, IDnsOptions, @@ -195,7 +194,8 @@ export const ipcSchema = { testApiAccessMethodById: invoke(), testCustomApiAccessMethod: invoke(), clearAllRelayOverrides: invoke(), - setDaitaSettings: invoke(), + setEnableDaita: invoke(), + setDaitaUseAnywhere: invoke(), }, guiSettings: { '': notifyRenderer(), diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs index 2464334cc63f..911c2f010bbd 100644 --- a/mullvad-cli/src/cmds/tunnel.rs +++ b/mullvad-cli/src/cmds/tunnel.rs @@ -1,8 +1,6 @@ use anyhow::Result; use clap::Subcommand; use mullvad_management_interface::MullvadProxyClient; -#[cfg(daita)] -use mullvad_types::wireguard::DaitaSettings; use mullvad_types::{ constraints::Constraint, wireguard::{QuantumResistantState, RotationInterval, DEFAULT_ROTATION_INTERVAL}, @@ -44,6 +42,10 @@ pub enum TunnelOptions { #[cfg(daita)] #[arg(long)] daita: Option, + /// Configure whether to enable DAITA "use anywhere" + #[cfg(daita)] + #[arg(long)] + daita_use_anywhere: Option, /// The key rotation interval. Number of hours, or 'any' #[arg(long)] rotation_interval: Option>, @@ -140,6 +142,8 @@ impl Tunnel { quantum_resistant, #[cfg(daita)] daita, + #[cfg(daita)] + daita_use_anywhere, rotation_interval, rotate_key, } => { @@ -148,6 +152,8 @@ impl Tunnel { quantum_resistant, #[cfg(daita)] daita, + #[cfg(daita)] + daita_use_anywhere, rotation_interval, rotate_key, ) @@ -179,6 +185,7 @@ impl Tunnel { mtu: Option>, quantum_resistant: Option, #[cfg(daita)] daita: Option, + #[cfg(daita)] daita_use_anywhere: Option, rotation_interval: Option>, rotate_key: Option, ) -> Result<()> { @@ -195,12 +202,14 @@ impl Tunnel { } #[cfg(daita)] - if let Some(daita) = daita { - rpc.set_daita_settings(DaitaSettings { - enabled: *daita, - use_anywhere: true, /* TODO */ - }) - .await?; + if let Some(enable_daita) = daita { + rpc.set_enable_daita(*enable_daita).await?; + println!("DAITA setting has been updated"); + } + + #[cfg(daita)] + if let Some(daita_use_anywhere) = daita_use_anywhere { + rpc.set_daita_use_anywhere(*daita_use_anywhere).await?; println!("DAITA setting has been updated"); } diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 62014367548d..a680712ff384 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -264,6 +264,10 @@ pub enum DaemonCommand { SetQuantumResistantTunnel(ResponseTx<(), settings::Error>, QuantumResistantState), /// Set DAITA settings for the tunnel #[cfg(daita)] + SetEnableDaita(ResponseTx<(), settings::Error>, bool), + #[cfg(daita)] + SetDaitaUseAnywhere(ResponseTx<(), settings::Error>, bool), + #[cfg(daita)] SetDaitaSettings(ResponseTx<(), settings::Error>, DaitaSettings), /// Set DNS options or servers to use SetDnsOptions(ResponseTx<(), settings::Error>, DnsOptions), @@ -1219,6 +1223,10 @@ impl Daemon { .await } #[cfg(daita)] + SetEnableDaita(tx, value) => self.on_set_daita_enabled(tx, value).await, + #[cfg(daita)] + SetDaitaUseAnywhere(tx, value) => self.on_set_daita_use_anywhere(tx, value).await, + #[cfg(daita)] SetDaitaSettings(tx, daita_settings) => { self.on_set_daita_settings(tx, daita_settings).await } @@ -2291,6 +2299,54 @@ impl Daemon { } } + #[cfg(daita)] + async fn on_set_daita_enabled(&mut self, tx: ResponseTx<(), settings::Error>, value: bool) { + match self + .settings + .update(|settings| settings.tunnel_options.wireguard.daita.enabled = value) + .await + { + Ok(settings_changed) => { + Self::oneshot_send(tx, Ok(()), "set_daita_enabled response"); + if settings_changed && self.get_target_tunnel_type() != Some(TunnelType::OpenVpn) { + log::info!("Reconnecting because DAITA settings changed"); + self.reconnect_tunnel(); + } + } + Err(e) => { + log::error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_daita_enabled response"); + } + } + } + + #[cfg(daita)] + async fn on_set_daita_use_anywhere( + &mut self, + tx: ResponseTx<(), settings::Error>, + value: bool, + ) { + match self + .settings + .update(|settings| settings.tunnel_options.wireguard.daita.use_anywhere = value) + .await + { + Ok(settings_changed) => { + Self::oneshot_send(tx, Ok(()), "set_daita_use_anywhere response"); + + // TODO: don't reconnect if multihop is enabled + if settings_changed && self.get_target_tunnel_type() != Some(TunnelType::OpenVpn) { + log::info!("Reconnecting because DAITA settings changed"); + self.reconnect_tunnel(); + } + } + Err(e) => { + log::error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_daita_use_anywhere response"); + } + } + } + #[cfg(daita)] async fn on_set_daita_settings( &mut self, diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 4d0f558a97f4..594fd7a19e63 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -341,6 +341,26 @@ impl ManagementService for ManagementServiceImpl { Ok(Response::new(())) } + #[cfg(daita)] + async fn set_enable_daita(&self, request: Request) -> ServiceResult<()> { + let value = request.into_inner(); + log::debug!("set_enable_daita({value})"); + let (tx, rx) = oneshot::channel(); + self.send_command_to_daemon(DaemonCommand::SetEnableDaita(tx, value))?; + self.wait_for_result(rx).await?.map(Response::new)?; + Ok(Response::new(())) + } + + #[cfg(daita)] + async fn set_daita_use_anywhere(&self, request: Request) -> ServiceResult<()> { + let value = request.into_inner(); + log::debug!("set_daita_use_anywhere({value})"); + let (tx, rx) = oneshot::channel(); + self.send_command_to_daemon(DaemonCommand::SetDaitaUseAnywhere(tx, value))?; + self.wait_for_result(rx).await?.map(Response::new)?; + Ok(Response::new(())) + } + #[cfg(daita)] async fn set_daita_settings( &self, @@ -355,6 +375,16 @@ impl ManagementService for ManagementServiceImpl { Ok(Response::new(())) } + #[cfg(not(daita))] + async fn set_enable_daita(&self, _: Request) -> ServiceResult<()> { + Ok(Response::new(())) + } + + #[cfg(not(daita))] + async fn set_daita_use_anywhere(&self, _: Request) -> ServiceResult<()> { + Ok(Response::new(())) + } + #[cfg(not(daita))] async fn set_daita_settings(&self, _: Request) -> ServiceResult<()> { Ok(Response::new(())) diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index 595c8f35273b..29acf34923cd 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -48,6 +48,8 @@ service ManagementService { rpc SetWireguardMtu(google.protobuf.UInt32Value) returns (google.protobuf.Empty) {} rpc SetEnableIpv6(google.protobuf.BoolValue) returns (google.protobuf.Empty) {} rpc SetQuantumResistantTunnel(QuantumResistantState) returns (google.protobuf.Empty) {} + rpc SetEnableDaita(google.protobuf.BoolValue) returns (google.protobuf.Empty) {} + rpc SetDaitaUseAnywhere(google.protobuf.BoolValue) returns (google.protobuf.Empty) {} rpc SetDaitaSettings(DaitaSettings) returns (google.protobuf.Empty) {} rpc SetDnsOptions(DnsOptions) returns (google.protobuf.Empty) {} rpc SetRelayOverride(RelayOverride) returns (google.protobuf.Empty) {} diff --git a/mullvad-management-interface/src/client.rs b/mullvad-management-interface/src/client.rs index b0876093fa2a..c32b346bbc3a 100644 --- a/mullvad-management-interface/src/client.rs +++ b/mullvad-management-interface/src/client.rs @@ -378,6 +378,21 @@ impl MullvadProxyClient { Ok(()) } + #[cfg(daita)] + pub async fn set_enable_daita(&mut self, value: bool) -> Result<()> { + self.0.set_enable_daita(value).await.map_err(Error::Rpc)?; + Ok(()) + } + + #[cfg(daita)] + pub async fn set_daita_use_anywhere(&mut self, value: bool) -> Result<()> { + self.0 + .set_daita_use_anywhere(value) + .await + .map_err(Error::Rpc)?; + Ok(()) + } + #[cfg(daita)] pub async fn set_daita_settings(&mut self, settings: DaitaSettings) -> Result<()> { let settings = types::DaitaSettings::from(settings); diff --git a/mullvad-relay-selector/src/relay_selector/mod.rs b/mullvad-relay-selector/src/relay_selector/mod.rs index 5deb5fbefafa..f1f77c0a68ac 100644 --- a/mullvad-relay-selector/src/relay_selector/mod.rs +++ b/mullvad-relay-selector/src/relay_selector/mod.rs @@ -789,7 +789,7 @@ impl RelaySelector { .take_while(|relay| relay.distance <= smallest_distance) .map(|relay_with_distance| relay_with_distance.relay) .collect_vec(); - let entry = pick_random_excluding(&entry_candidates, &exit).ok_or(Error::NoRelay)?; + let entry = pick_random_excluding(&entry_candidates, exit).ok_or(Error::NoRelay)?; Ok(WireguardConfig::multihop(exit.clone(), entry.clone())) }