diff options
| author | Sebastian Holmin <sebastian.holmin@mullvad.net> | 2024-10-07 15:54:14 +0200 |
|---|---|---|
| committer | Sebastian Holmin <sebastian.holmin@mullvad.net> | 2024-10-07 15:54:14 +0200 |
| commit | bdd4675c11f0a365704b6c32cf0a4d482d4e8b9f (patch) | |
| tree | e05e904006ccc43f0845d12231b119c71f7775dd | |
| parent | adc7e44b69da58740bd5a18abbc267c319649714 (diff) | |
| parent | 777013135b01d1c4d13961802db511b0e06e90e9 (diff) | |
| download | mullvadvpn-bdd4675c11f0a365704b6c32cf0a4d482d4e8b9f.tar.xz mullvadvpn-bdd4675c11f0a365704b6c32cf0a4d482d4e8b9f.zip | |
Merge branch 'rename-smart_routing-to-use_multihop_if_necessary-des-1292'
28 files changed, 255 insertions, 218 deletions
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt index 7961b5460c..024091c9dc 100644 --- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt +++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt @@ -511,7 +511,13 @@ class ManagementService( suspend fun setDaitaEnabled(enabled: Boolean): Either<SetDaitaSettingsError, Unit> = Either.catch { val daitaSettings = - ManagementInterface.DaitaSettings.newBuilder().setEnabled(enabled).build() + ManagementInterface.DaitaSettings.newBuilder() + .setEnabled(enabled) + // Before Multihop is supported on Android, calling `setDirectOnly` with + // false will cause undefined behaviour. Will be fixed by as part of + // DROID-1412. + .setDirectOnly(true) + .build() grpc.setDaitaSettings(daitaSettings) } .mapLeft(SetDaitaSettingsError::Unknown) diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt index 4a8ee04683..2f6a08eede 100644 --- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt +++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt @@ -621,7 +621,6 @@ internal fun ManagementInterface.FeatureIndicator.toDomain() = ManagementInterface.FeatureIndicator.CUSTOM_MTU -> FeatureIndicator.CUSTOM_MTU ManagementInterface.FeatureIndicator.DAITA -> FeatureIndicator.DAITA ManagementInterface.FeatureIndicator.SHADOWSOCKS -> FeatureIndicator.SHADOWSOCKS - ManagementInterface.FeatureIndicator.DAITA_SMART_ROUTING, ManagementInterface.FeatureIndicator.LOCKDOWN_MODE, ManagementInterface.FeatureIndicator.MULTIHOP, ManagementInterface.FeatureIndicator.BRIDGE_MODE, diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/FeatureIndicator.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/FeatureIndicator.kt index 74fea07326..3c8df824f4 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/FeatureIndicator.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/FeatureIndicator.kt @@ -3,7 +3,6 @@ package net.mullvad.mullvadvpn.lib.model // The order of the variants match the priority order and can be sorted on. enum class FeatureIndicator { DAITA, - // DAITA_SMART_ROUTING QUANTUM_RESISTANCE, // MULTIHOP, SPLIT_TUNNELING, diff --git a/gui/locales/messages.pot b/gui/locales/messages.pot index e9ef237a3a..174688cf27 100644 --- a/gui/locales/messages.pot +++ b/gui/locales/messages.pot @@ -5,11 +5,6 @@ msgstr "" msgid "%(amount)d more..." msgstr "" -#. This refers to the Smart Routing setting in the VPN settings view. -#. This is displayed when both Smart Routing and DAITA features are on. -msgid "%(daita)s: Smart routing" -msgstr "" - msgid "%(duration)s was added, account paid until %(expiry)s." msgstr "" @@ -127,10 +122,10 @@ msgstr "" msgid "Delete list" msgstr "" -msgid "Disable" +msgid "Direct only" msgstr "" -msgid "Disable anyway" +msgid "Disable" msgstr "" msgid "Disconnect" @@ -157,6 +152,9 @@ msgstr "" msgid "Enable" msgstr "" +msgid "Enable \"Direct only\"" +msgstr "" + msgid "Enable anyway" msgstr "" @@ -253,9 +251,6 @@ msgstr "" msgid "Settings" msgstr "" -msgid "Smart routing" -msgstr "" - msgid "System default" msgstr "" @@ -1956,13 +1951,13 @@ msgctxt "vpn-settings-view" msgid "Lockdown mode" msgstr "" +#. Label for settings that enables malware blocking. msgctxt "vpn-settings-view" -msgid "Makes it possible to use %(daita)s with any server and is automatically enabled." +msgid "Malware" msgstr "" -#. Label for settings that enables malware blocking. msgctxt "vpn-settings-view" -msgid "Malware" +msgid "Manually choose which %(daita)s-enabled server to use." msgstr "" msgctxt "vpn-settings-view" @@ -2071,7 +2066,15 @@ msgid "%(wireguard)s settings" msgstr "" msgctxt "wireguard-settings-view" -msgid "Can only be used with WireGuard. Since this increases your total network traffic, be cautious if you have a limited data plan. It can also negatively impact your network speed." +msgid "Attention: Be cautious if you have a limited data plan as this feature will increase your network traffic. This feature can only be used with WireGuard." +msgstr "" + +msgctxt "wireguard-settings-view" +msgid "By enabling “Direct only” you will have to manually select a server that is %(daita)s-enabled. This can cause you to end up in a blocked state until you have selected a compatible server in the “Select location” view." +msgstr "" + +msgctxt "wireguard-settings-view" +msgid "Cancel" msgstr "" msgctxt "wireguard-settings-view" @@ -2104,11 +2107,11 @@ msgstr "" #. Warning text in a dialog that is displayed after a setting is toggled. msgctxt "wireguard-settings-view" -msgid "Not all our servers are %(daita)s-enabled. In order to use the internet, you might have to select a new location after disabling, or you can continue using %(daita)s with Smart routing." +msgid "Not all our servers are %(daita)s-enabled. In order to use the internet, you might have to select a new location after enabling." msgstr "" msgctxt "wireguard-settings-view" -msgid "Not all our servers are %(daita)s-enabled. Smart routing allows %(daita)s to be used at any location. It does this by using multihop in the background to route your traffic via the closest %(daita)s-enabled server first." +msgid "Not all our servers are %(daita)s-enabled. We use multihop automatically to use %(daita)s with any server." msgstr "" msgctxt "wireguard-settings-view" @@ -2181,10 +2184,6 @@ msgctxt "wireguard-settings-view" msgid "UDP-over-TCP port" msgstr "" -msgctxt "wireguard-settings-view" -msgid "Use Smart routing" -msgstr "" - #. Text describing the valid port range for a port selector. msgctxt "wireguard-settings-view" msgid "Valid range: %(min)s - %(max)s" diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index c504efe2b9..c86bed047f 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -464,8 +464,8 @@ export class DaemonRpc extends GrpcClient { await this.callBool(this.client.setEnableDaita, value); } - public async setDaitaSmartRouting(value: boolean): Promise<void> { - await this.callBool(this.client.setDaitaSmartRouting, value); + public async setDaitaDirectOnly(value: boolean): Promise<void> { + await this.callBool(this.client.setDaitaDirectOnly, value); } public async listDevices(accountNumber: AccountNumber): Promise<Array<IDevice>> { diff --git a/gui/src/main/grpc-type-convertions.ts b/gui/src/main/grpc-type-convertions.ts index d37dd3a9b8..6511f10c67 100644 --- a/gui/src/main/grpc-type-convertions.ts +++ b/gui/src/main/grpc-type-convertions.ts @@ -381,8 +381,6 @@ function convertFromFeatureIndicator( return FeatureIndicator.customMssFix; case grpcTypes.FeatureIndicator.DAITA: return FeatureIndicator.daita; - case grpcTypes.FeatureIndicator.DAITA_SMART_ROUTING: - return FeatureIndicator.daitaSmartRouting; case grpcTypes.FeatureIndicator.SHADOWSOCKS: return FeatureIndicator.shadowsocks; } diff --git a/gui/src/main/settings.ts b/gui/src/main/settings.ts index 03537ba581..99fb4f2a5a 100644 --- a/gui/src/main/settings.ts +++ b/gui/src/main/settings.ts @@ -110,8 +110,8 @@ export default class Settings implements Readonly<ISettings> { IpcMainEventChannel.settings.handleSetEnableDaita((value) => { return this.daemonRpc.setEnableDaita(value); }); - IpcMainEventChannel.settings.handleSetDaitaSmartRouting((value) => { - return this.daemonRpc.setDaitaSmartRouting(value); + IpcMainEventChannel.settings.handleSetDaitaDirectOnly((value) => { + return this.daemonRpc.setDaitaDirectOnly(value); }); IpcMainEventChannel.guiSettings.handleSetEnableSystemNotifications((flag: boolean) => { diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index 6c40b0e908..d36c27aa14 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -349,8 +349,8 @@ export default class AppRenderer { IpcRendererEventChannel.settings.setObfuscationSettings(obfuscationSettings); public setEnableDaita = (value: boolean) => IpcRendererEventChannel.settings.setEnableDaita(value); - public setDaitaSmartRouting = (value: boolean) => - IpcRendererEventChannel.settings.setDaitaSmartRouting(value); + public setDaitaDirectOnly = (value: boolean) => + IpcRendererEventChannel.settings.setDaitaDirectOnly(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/DaitaSettings.tsx b/gui/src/renderer/components/DaitaSettings.tsx index b4ee10c94d..2d09a3996e 100644 --- a/gui/src/renderer/components/DaitaSettings.tsx +++ b/gui/src/renderer/components/DaitaSettings.tsx @@ -95,9 +95,18 @@ export default function DaitaSettings() { )} </StyledHeaderSubTitle> <StyledHeaderSubTitle> + {sprintf( + messages.pgettext( + 'wireguard-settings-view', + 'Not all our servers are %(daita)s-enabled. We use multihop automatically to use %(daita)s with any server.', + ), + { daita: strings.daita, daitaFull: strings.daitaFull }, + )} + </StyledHeaderSubTitle> + <StyledHeaderSubTitle> {messages.pgettext( 'wireguard-settings-view', - 'Can only be used with WireGuard. Since this increases your total network traffic, be cautious if you have a limited data plan. It can also negatively impact your network speed.', + 'Attention: Be cautious if you have a limited data plan as this feature will increase your network traffic. This feature can only be used with WireGuard.', )} </StyledHeaderSubTitle> </React.Fragment>, @@ -119,12 +128,10 @@ export default function DaitaSettings() { } function DaitaToggle() { - const { setEnableDaita, setDaitaSmartRouting } = useAppContext(); + const { setEnableDaita, setDaitaDirectOnly } = useAppContext(); const relaySettings = useSelector((state) => state.settings.relaySettings); const daita = useSelector((state) => state.settings.wireguard.daita?.enabled ?? false); - const smartRouting = useSelector( - (state) => state.settings.wireguard.daita?.smartRouting ?? false, - ); + const directOnly = useSelector((state) => state.settings.wireguard.daita?.directOnly ?? false); const [confirmationDialogVisible, showConfirmationDialog, hideConfirmationDialog] = useBoolean(); @@ -135,16 +142,16 @@ function DaitaToggle() { void setEnableDaita(value); }, []); - const setSmartRouting = useCallback((value: boolean) => { + const setDirectOnly = useCallback((value: boolean) => { if (value) { - void setDaitaSmartRouting(value); - } else { showConfirmationDialog(); + } else { + void setDaitaDirectOnly(value); } }, []); - const confirmDisableSmartRouting = useCallback(() => { - void setDaitaSmartRouting(false); + const confirmEnableDirectOnly = useCallback(() => { + void setDaitaDirectOnly(true); hideConfirmationDialog(); }, []); @@ -170,13 +177,13 @@ function DaitaToggle() { <AriaInputGroup> <Cell.Container disabled={!daita || unavailable}> <AriaLabel> - <Cell.InputLabel>{messages.gettext('Smart routing')}</Cell.InputLabel> + <Cell.InputLabel>{messages.gettext('Direct only')}</Cell.InputLabel> </AriaLabel> <InfoButton> - <SmartRoutingModalMessage /> + <DirectOnlyModalMessage /> </InfoButton> <AriaInput> - <Cell.Switch isOn={smartRouting && !unavailable} onChange={setSmartRouting} /> + <Cell.Switch isOn={directOnly && !unavailable} onChange={setDirectOnly} /> </AriaInput> </Cell.Container> <Cell.CellFooter> @@ -185,7 +192,7 @@ function DaitaToggle() { {sprintf( messages.pgettext( 'vpn-settings-view', - 'Makes it possible to use %(daita)s with any server and is automatically enabled.', + 'Manually choose which %(daita)s-enabled server to use.', ), { daita: strings.daita }, )} @@ -199,12 +206,12 @@ function DaitaToggle() { gridButtons={[ <SmallButton key="confirm" - onClick={confirmDisableSmartRouting} + onClick={confirmEnableDirectOnly} color={SmallButtonColor.blue}> - {messages.gettext('Disable anyway')} + {messages.gettext('Enable "Direct only"')} </SmallButton>, <SmallButton key="cancel" onClick={hideConfirmationDialog} color={SmallButtonColor.blue}> - {messages.pgettext('wireguard-settings-view', 'Use Smart routing')} + {messages.pgettext('wireguard-settings-view', 'Cancel')} </SmallButton>, ]} close={hideConfirmationDialog}> @@ -213,7 +220,7 @@ function DaitaToggle() { // TRANSLATORS: Warning text in a dialog that is displayed after a setting is toggled. messages.pgettext( 'wireguard-settings-view', - 'Not all our servers are %(daita)s-enabled. In order to use the internet, you might have to select a new location after disabling, or you can continue using %(daita)s with Smart routing.', + 'Not all our servers are %(daita)s-enabled. In order to use the internet, you might have to select a new location after enabling.', ), { daita: strings.daita }, )} @@ -223,13 +230,13 @@ function DaitaToggle() { ); } -export function SmartRoutingModalMessage() { +function DirectOnlyModalMessage() { return ( <ModalMessage> {sprintf( messages.pgettext( 'wireguard-settings-view', - 'Not all our servers are %(daita)s-enabled. Smart routing allows %(daita)s to be used at any location. It does this by using multihop in the background to route your traffic via the closest %(daita)s-enabled server first.', + 'By enabling “Direct only” you will have to manually select a server that is %(daita)s-enabled. This can cause you to end up in a blocked state until you have selected a compatible server in the “Select location” view.', ), { daita: strings.daita, diff --git a/gui/src/renderer/components/main-view/FeatureIndicators.tsx b/gui/src/renderer/components/main-view/FeatureIndicators.tsx index a4bf8659c6..2d7914fd87 100644 --- a/gui/src/renderer/components/main-view/FeatureIndicators.tsx +++ b/gui/src/renderer/components/main-view/FeatureIndicators.tsx @@ -5,13 +5,10 @@ import styled from 'styled-components'; import { colors, strings } from '../../../config.json'; import { FeatureIndicator } from '../../../shared/daemon-rpc-types'; import { messages } from '../../../shared/gettext'; -import { useBoolean, useStyledRef } from '../../lib/utilityHooks'; +import { useStyledRef } from '../../lib/utilityHooks'; import { useSelector } from '../../redux/store'; import { tinyText } from '../common-styles'; -import { SmartRoutingModalMessage } from '../DaitaSettings'; import { InfoIcon } from '../InfoButton'; -import { ModalAlert, ModalAlertType } from '../Modal'; -import { SmallButton, SmallButtonColor } from '../SmallButton'; import { ConnectionPanelAccordion } from './styles'; const LINE_HEIGHT = 22; @@ -102,11 +99,6 @@ interface FeatureIndicatorsProps { // we can count those and add another ellipsis element which is visible and place it after the last // visible indicator. export default function FeatureIndicators(props: FeatureIndicatorsProps) { - const [ - daitaSmartRoutingDialogueVisible, - showDaitaSmartRoutingDialogue, - hideDaitaSmartRoutingDialogue, - ] = useBoolean(); const tunnelState = useSelector((state) => state.connection.status); const ellipsisRef = useStyledRef<HTMLSpanElement>(); const ellipsisSpacerRef = useStyledRef<HTMLSpanElement>(); @@ -127,9 +119,8 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) { // Returns an optional callback for clickable feature indicators, or undefined. const getFeatureIndicatorOnClick = (indicator: FeatureIndicator) => { + // NOTE: With the "smart routing" feature indicator removed, this function now does nothing, should it be removed? switch (indicator) { - case FeatureIndicator.daitaSmartRouting: - return showDaitaSmartRoutingDialogue; default: return undefined; } @@ -231,21 +222,6 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) { /> </StyledFeatureIndicators> </StyledFeatureIndicatorsContainer> - - <ModalAlert - isOpen={daitaSmartRoutingDialogueVisible} - type={ModalAlertType.info} - gridButtons={[ - <SmallButton - key="dismiss" - onClick={hideDaitaSmartRoutingDialogue} - color={SmallButtonColor.blue}> - {messages.gettext('Got it!')} - </SmallButton>, - ]} - close={hideDaitaSmartRoutingDialogue}> - <SmartRoutingModalMessage /> - </ModalAlert> </StyledAccordion> ); } @@ -276,13 +252,6 @@ function getFeatureIndicatorLabel(indicator: FeatureIndicator) { switch (indicator) { case FeatureIndicator.daita: return strings.daita; - case FeatureIndicator.daitaSmartRouting: - return sprintf( - // TRANSLATORS: This refers to the Smart Routing setting in the VPN settings view. - // TRANSLATORS: This is displayed when both Smart Routing and DAITA features are on. - messages.gettext('%(daita)s: Smart routing'), - { daita: strings.daita }, - ); case FeatureIndicator.udp2tcp: case FeatureIndicator.shadowsocks: return messages.pgettext('wireguard-settings-view', 'Obfuscation'); diff --git a/gui/src/renderer/components/select-location/RelayListContext.tsx b/gui/src/renderer/components/select-location/RelayListContext.tsx index 241d11fbdc..e41b04c17e 100644 --- a/gui/src/renderer/components/select-location/RelayListContext.tsx +++ b/gui/src/renderer/components/select-location/RelayListContext.tsx @@ -62,9 +62,7 @@ interface RelayListContextProviderProps { export function RelayListContextProvider(props: RelayListContextProviderProps) { const { locationType, searchTerm } = useSelectLocationContext(); const daita = useSelector((state) => state.settings.wireguard.daita?.enabled ?? false); - const smartRouting = useSelector( - (state) => state.settings.wireguard.daita?.smartRouting ?? false, - ); + const directOnly = useSelector((state) => state.settings.wireguard.daita?.directOnly ?? false); const fullRelayList = useSelector((state) => state.settings.relayLocations); const relaySettings = useNormalRelaySettings(); @@ -81,7 +79,7 @@ export function RelayListContextProvider(props: RelayListContextProviderProps) { return filterLocationsByDaita( relayListForEndpointType, daita, - smartRouting, + directOnly, locationType, relaySettings?.tunnelProtocol ?? 'any', relaySettings?.wireguard.useMultihop ?? false, diff --git a/gui/src/renderer/components/select-location/SelectLocation.tsx b/gui/src/renderer/components/select-location/SelectLocation.tsx index 9cd66f98f4..01297f5630 100644 --- a/gui/src/renderer/components/select-location/SelectLocation.tsx +++ b/gui/src/renderer/components/select-location/SelectLocation.tsx @@ -68,12 +68,10 @@ export default function SelectLocation() { const providers = relaySettings?.providers ?? []; const filteredProviders = useFilteredProviders(providers, ownership); const daita = useSelector((state) => state.settings.wireguard.daita?.enabled ?? false); - const smartRouting = useSelector( - (state) => state.settings.wireguard.daita?.smartRouting ?? false, - ); + const directOnly = useSelector((state) => state.settings.wireguard.daita?.directOnly ?? false); const showDaitaFilter = daitaFilterActive( daita, - smartRouting, + directOnly, locationType, relaySettings?.tunnelProtocol ?? 'any', relaySettings?.wireguard.useMultihop ?? false, diff --git a/gui/src/renderer/lib/filter-locations.ts b/gui/src/renderer/lib/filter-locations.ts index 661d8ecc29..e559e64096 100644 --- a/gui/src/renderer/lib/filter-locations.ts +++ b/gui/src/renderer/lib/filter-locations.ts @@ -37,19 +37,19 @@ export function filterLocationsByEndPointType( export function filterLocationsByDaita( locations: IRelayLocationCountryRedux[], daita: boolean, - smartRouting: boolean, + directOnly: boolean, locationType: LocationType, tunnelProtocol: LiftedConstraint<TunnelProtocol>, multihop: boolean, ): IRelayLocationCountryRedux[] { - return daitaFilterActive(daita, smartRouting, locationType, tunnelProtocol, multihop) + return daitaFilterActive(daita, directOnly, locationType, tunnelProtocol, multihop) ? filterLocationsImpl(locations, (relay: IRelayLocationRelayRedux) => relay.daita) : locations; } export function daitaFilterActive( daita: boolean, - smartRouting: boolean, + directOnly: boolean, locationType: LocationType, tunnelProtocol: LiftedConstraint<TunnelProtocol>, multihop: boolean, @@ -57,7 +57,7 @@ export function daitaFilterActive( const isEntry = multihop ? locationType === LocationType.entry : locationType === LocationType.exit; - return daita && (!smartRouting || multihop) && isEntry && tunnelProtocol !== 'openvpn'; + return daita && (directOnly || multihop) && isEntry && tunnelProtocol !== 'openvpn'; } export function filterLocations( diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts index a22021a1d0..bd8f99711b 100644 --- a/gui/src/shared/daemon-rpc-types.ts +++ b/gui/src/shared/daemon-rpc-types.ts @@ -183,7 +183,6 @@ export interface ITunnelStateRelayInfo { // The order of the variants match the priority order and can be sorted on. export enum FeatureIndicator { daita, - daitaSmartRouting, quantumResistance, multihop, bridgeMode, @@ -552,7 +551,7 @@ export interface RelayOverride { export interface IDaitaSettings { enabled: boolean; - smartRouting: boolean; + directOnly: boolean; } export function parseSocketAddress(socketAddrStr: string): ISocketAddress { diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts index b10c79623e..954dce1680 100644 --- a/gui/src/shared/ipc-schema.ts +++ b/gui/src/shared/ipc-schema.ts @@ -195,7 +195,7 @@ export const ipcSchema = { testCustomApiAccessMethod: invoke<CustomProxy, boolean>(), clearAllRelayOverrides: invoke<void, void>(), setEnableDaita: invoke<boolean, void>(), - setDaitaSmartRouting: invoke<boolean, void>(), + setDaitaDirectOnly: invoke<boolean, void>(), }, guiSettings: { '': notifyRenderer<IGuiSettingsState>(), diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs index da66cac5d5..118fd63a8d 100644 --- a/mullvad-cli/src/cmds/tunnel.rs +++ b/mullvad-cli/src/cmds/tunnel.rs @@ -41,9 +41,9 @@ pub enum TunnelOptions { /// Configure whether to enable DAITA #[arg(long)] daita: Option<BooleanOption>, - /// Configure whether to enable DAITA smart routing + /// Configure whether to enable DAITA direct only #[arg(long)] - daita_smart_routing: Option<BooleanOption>, + daita_direct_only: Option<BooleanOption>, /// The key rotation interval. Number of hours, or 'any' #[arg(long)] rotation_interval: Option<Constraint<RotationInterval>>, @@ -138,7 +138,7 @@ impl Tunnel { mtu, quantum_resistant, daita, - daita_smart_routing, + daita_direct_only, rotation_interval, rotate_key, } => { @@ -146,7 +146,7 @@ impl Tunnel { mtu, quantum_resistant, daita, - daita_smart_routing, + daita_direct_only, rotation_interval, rotate_key, ) @@ -178,7 +178,7 @@ impl Tunnel { mtu: Option<Constraint<u16>>, quantum_resistant: Option<QuantumResistantState>, daita: Option<BooleanOption>, - daita_smart_routing: Option<BooleanOption>, + daita_direct_only: Option<BooleanOption>, rotation_interval: Option<Constraint<RotationInterval>>, rotate_key: Option<RotateKey>, ) -> Result<()> { @@ -197,12 +197,12 @@ impl Tunnel { if let Some(enable_daita) = daita { rpc.set_enable_daita(*enable_daita).await?; println!("DAITA setting has been updated"); - println!("Smart routing setting has been updated"); + println!("Direct only setting has been updated"); } - if let Some(daita_smart_routing) = daita_smart_routing { - rpc.set_daita_smart_routing(*daita_smart_routing).await?; - println!("Smart routing setting has been updated"); + if let Some(daita_direct_only) = daita_direct_only { + rpc.set_daita_direct_only(*daita_direct_only).await?; + println!("Direct only setting has been updated"); } if let Some(interval) = rotation_interval { diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index e833f1b82c..dd6c828802 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -266,7 +266,7 @@ pub enum DaemonCommand { #[cfg(daita)] SetEnableDaita(ResponseTx<(), settings::Error>, bool), #[cfg(daita)] - SetDaitaSmartRouting(ResponseTx<(), settings::Error>, bool), + SetDaitaUseMultihopIfNecessary(ResponseTx<(), settings::Error>, bool), #[cfg(daita)] SetDaitaSettings(ResponseTx<(), settings::Error>, DaitaSettings), /// Set DNS options or servers to use @@ -1261,7 +1261,9 @@ impl Daemon { #[cfg(daita)] SetEnableDaita(tx, value) => self.on_set_daita_enabled(tx, value).await, #[cfg(daita)] - SetDaitaSmartRouting(tx, value) => self.on_set_daita_smart_routing(tx, value).await, + SetDaitaUseMultihopIfNecessary(tx, value) => { + self.on_set_daita_use_multihop_if_necessary(tx, value).await + } #[cfg(daita)] SetDaitaSettings(tx, daita_settings) => { self.on_set_daita_settings(tx, daita_settings).await @@ -2343,11 +2345,6 @@ impl Daemon { .settings .update(|settings| { settings.tunnel_options.wireguard.daita.enabled = value; - - // enable smart-routing automatically with daita - if cfg!(not(target_os = "android")) { - settings.tunnel_options.wireguard.daita.smart_routing = value - } }) .await; @@ -2376,7 +2373,7 @@ impl Daemon { } #[cfg(daita)] - async fn on_set_daita_smart_routing( + async fn on_set_daita_use_multihop_if_necessary( &mut self, tx: ResponseTx<(), settings::Error>, value: bool, @@ -2385,11 +2382,17 @@ impl Daemon { match self .settings - .update(|settings| settings.tunnel_options.wireguard.daita.smart_routing = value) + .update(|settings| { + settings + .tunnel_options + .wireguard + .daita + .use_multihop_if_necessary = value + }) .await { Ok(settings_changed) => { - Self::oneshot_send(tx, Ok(()), "set_daita_smart_routing response"); + Self::oneshot_send(tx, Ok(()), "set_daita_use_multihop_if_necessary response"); let RelaySettings::Normal(constraints) = &self.settings.relay_settings else { return; // DAITA is not supported for custom relays @@ -2410,7 +2413,7 @@ impl Daemon { } Err(e) => { log::error!("{}", e.display_chain_with_msg("Unable to save settings")); - Self::oneshot_send(tx, Err(e), "set_daita_smart_routing response"); + Self::oneshot_send(tx, Err(e), "set_daita_use_multihop_if_necessary response"); } } } @@ -3024,12 +3027,16 @@ fn new_selector_config(settings: &Settings) -> SelectorConfig { #[cfg(daita)] daita: settings.tunnel_options.wireguard.daita.enabled, #[cfg(daita)] - daita_smart_routing: settings.tunnel_options.wireguard.daita.smart_routing, + daita_use_multihop_if_necessary: settings + .tunnel_options + .wireguard + .daita + .use_multihop_if_necessary, #[cfg(not(daita))] daita: false, #[cfg(not(daita))] - daita_smart_routing: false, + daita_use_multihop_if_necessary: false, quantum_resistant: settings.tunnel_options.wireguard.quantum_resistant, }, diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index b52c214a01..eadfd99806 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -343,20 +343,23 @@ impl ManagementService for ManagementServiceImpl { #[cfg(daita)] async fn set_enable_daita(&self, request: Request<bool>) -> ServiceResult<()> { - let value = request.into_inner(); - log::debug!("set_enable_daita({value})"); + let daita_enabled = request.into_inner(); + log::debug!("set_enable_daita({daita_enabled})"); let (tx, rx) = oneshot::channel(); - self.send_command_to_daemon(DaemonCommand::SetEnableDaita(tx, value))?; + self.send_command_to_daemon(DaemonCommand::SetEnableDaita(tx, daita_enabled))?; self.wait_for_result(rx).await?.map(Response::new)?; Ok(Response::new(())) } #[cfg(daita)] - async fn set_daita_smart_routing(&self, request: Request<bool>) -> ServiceResult<()> { - let value = request.into_inner(); - log::debug!("set_daita_smart_routing({value})"); + async fn set_daita_direct_only(&self, request: Request<bool>) -> ServiceResult<()> { + let direct_only_enabled = request.into_inner(); + log::debug!("set_daita_direct_only({direct_only_enabled})"); let (tx, rx) = oneshot::channel(); - self.send_command_to_daemon(DaemonCommand::SetDaitaSmartRouting(tx, value))?; + self.send_command_to_daemon(DaemonCommand::SetDaitaUseMultihopIfNecessary( + tx, + !direct_only_enabled, + ))?; self.wait_for_result(rx).await?.map(Response::new)?; Ok(Response::new(())) } @@ -381,7 +384,7 @@ impl ManagementService for ManagementServiceImpl { } #[cfg(not(daita))] - async fn set_daita_smart_routing(&self, _: Request<bool>) -> ServiceResult<()> { + async fn set_daita_direct_only(&self, _: Request<bool>) -> ServiceResult<()> { Ok(Response::new(())) } @@ -1135,8 +1138,9 @@ impl ManagementInterfaceServer { }) } - /// Wait for the server to shut down gracefully. If that does not happend within [`RPC_SERVER_SHUTDOWN_TIMEOUT`], - /// the gRPC server is aborted and we yield the async execution. + /// Wait for the server to shut down gracefully. If that does not happend within + /// [`RPC_SERVER_SHUTDOWN_TIMEOUT`], the gRPC server is aborted and we yield the async + /// execution. pub async fn stop(mut self) { use futures::SinkExt; // Send a singal to the underlying RPC server to shut down. diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index 70d9e1ad2b..b57d63dcf3 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -49,7 +49,7 @@ service ManagementService { 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 SetDaitaSmartRouting(google.protobuf.BoolValue) returns (google.protobuf.Empty) {} + rpc SetDaitaDirectOnly(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) {} @@ -264,7 +264,6 @@ enum FeatureIndicator { CUSTOM_MTU = 11; CUSTOM_MSS_FIX = 12; DAITA = 13; - DAITA_SMART_ROUTING = 14; } message ObfuscationEndpoint { @@ -546,7 +545,7 @@ message QuantumResistantState { message DaitaSettings { bool enabled = 1; - bool smart_routing = 2; + bool direct_only = 2; } message TunnelOptions { diff --git a/mullvad-management-interface/src/client.rs b/mullvad-management-interface/src/client.rs index 73bff561a4..0b74f9d9d6 100644 --- a/mullvad-management-interface/src/client.rs +++ b/mullvad-management-interface/src/client.rs @@ -385,9 +385,9 @@ impl MullvadProxyClient { } #[cfg(daita)] - pub async fn set_daita_smart_routing(&mut self, value: bool) -> Result<()> { + pub async fn set_daita_direct_only(&mut self, value: bool) -> Result<()> { self.0 - .set_daita_smart_routing(value) + .set_daita_direct_only(value) .await .map_err(Error::Rpc)?; Ok(()) diff --git a/mullvad-management-interface/src/types/conversions/features.rs b/mullvad-management-interface/src/types/conversions/features.rs index 85c85b8b77..ac235d8163 100644 --- a/mullvad-management-interface/src/types/conversions/features.rs +++ b/mullvad-management-interface/src/types/conversions/features.rs @@ -18,7 +18,6 @@ impl From<mullvad_types::features::FeatureIndicator> for proto::FeatureIndicator mullvad_types::features::FeatureIndicator::CustomMtu => CustomMtu, mullvad_types::features::FeatureIndicator::CustomMssFix => CustomMssFix, mullvad_types::features::FeatureIndicator::Daita => Daita, - mullvad_types::features::FeatureIndicator::DaitaSmartRouting => DaitaSmartRouting, } } } @@ -40,7 +39,6 @@ impl From<proto::FeatureIndicator> for mullvad_types::features::FeatureIndicator proto::FeatureIndicator::CustomMtu => Self::CustomMtu, proto::FeatureIndicator::CustomMssFix => Self::CustomMssFix, proto::FeatureIndicator::Daita => Self::Daita, - proto::FeatureIndicator::DaitaSmartRouting => Self::DaitaSmartRouting, } } } diff --git a/mullvad-management-interface/src/types/conversions/wireguard.rs b/mullvad-management-interface/src/types/conversions/wireguard.rs index 9e40b4b526..3e896da22d 100644 --- a/mullvad-management-interface/src/types/conversions/wireguard.rs +++ b/mullvad-management-interface/src/types/conversions/wireguard.rs @@ -78,7 +78,7 @@ impl From<mullvad_types::wireguard::DaitaSettings> for proto::DaitaSettings { fn from(settings: mullvad_types::wireguard::DaitaSettings) -> Self { proto::DaitaSettings { enabled: settings.enabled, - smart_routing: settings.smart_routing, + direct_only: !settings.use_multihop_if_necessary, } } } @@ -88,7 +88,7 @@ impl From<proto::DaitaSettings> for mullvad_types::wireguard::DaitaSettings { fn from(settings: proto::DaitaSettings) -> Self { mullvad_types::wireguard::DaitaSettings { enabled: settings.enabled, - smart_routing: settings.smart_routing, + use_multihop_if_necessary: !settings.direct_only, } } } diff --git a/mullvad-relay-selector/src/relay_selector/mod.rs b/mullvad-relay-selector/src/relay_selector/mod.rs index 6233e2da05..b94a5812a0 100644 --- a/mullvad-relay-selector/src/relay_selector/mod.rs +++ b/mullvad-relay-selector/src/relay_selector/mod.rs @@ -126,7 +126,7 @@ pub struct AdditionalWireguardConstraints { /// If true and multihop is disabled, will set up multihop with an automatic entry relay if /// DAITA is enabled. - pub daita_smart_routing: bool, + pub daita_use_multihop_if_necessary: bool, /// If enabled, select relays that support PQ. pub quantum_resistant: QuantumResistantState, @@ -349,7 +349,7 @@ impl<'a> TryFrom<NormalSelectorConfig<'a>> for RelayQuery { } = wireguard_constraints; let AdditionalWireguardConstraints { daita, - daita_smart_routing, + daita_use_multihop_if_necessary, quantum_resistant, } = additional_constraints; WireguardRelayQuery { @@ -359,7 +359,7 @@ impl<'a> TryFrom<NormalSelectorConfig<'a>> for RelayQuery { entry_location, obfuscation: ObfuscationQuery::from(obfuscation_settings), daita: Constraint::Only(daita), - daita_smart_routing: Constraint::Only(daita_smart_routing), + daita_use_multihop_if_necessary: Constraint::Only(daita_use_multihop_if_necessary), quantum_resistant, } } @@ -738,18 +738,23 @@ impl RelaySelector { Result::<_, Error>::Ok(!candidates.is_empty()) }; - // is `smart_routing` enabled? - let smart_routing = || { + // is `use_multihop_if_necessary` enabled? + let use_multihop_if_necessary = || { query .wireguard_constraints() - .daita_smart_routing + .daita_use_multihop_if_necessary .intersection(Constraint::Only(true)) .is_some() }; - // if we found no matching relays because DAITA was enabled, and `smart_routing` is enabled, - // try enabling multihop and connecting using an automatically selected entry relay. - if candidates.is_empty() && using_daita() && no_relay_because_daita()? && smart_routing() { + // if we found no matching relays because DAITA was enabled, and `use_multihop_if_necessary` + // is enabled, try enabling multihop and connecting using an automatically selected + // entry relay. + if candidates.is_empty() + && using_daita() + && no_relay_because_daita()? + && use_multihop_if_necessary() + { return Self::get_wireguard_auto_multihop_config(query, custom_lists, parsed_relays); } diff --git a/mullvad-relay-selector/src/relay_selector/query.rs b/mullvad-relay-selector/src/relay_selector/query.rs index 2dc81b0833..570a2212cb 100644 --- a/mullvad-relay-selector/src/relay_selector/query.rs +++ b/mullvad-relay-selector/src/relay_selector/query.rs @@ -268,7 +268,7 @@ pub struct WireguardRelayQuery { pub entry_location: Constraint<LocationConstraint>, pub obfuscation: ObfuscationQuery, pub daita: Constraint<bool>, - pub daita_smart_routing: Constraint<bool>, + pub daita_use_multihop_if_necessary: Constraint<bool>, pub quantum_resistant: QuantumResistantState, } @@ -354,7 +354,7 @@ impl WireguardRelayQuery { entry_location: Constraint::Any, obfuscation: ObfuscationQuery::Auto, daita: Constraint::Any, - daita_smart_routing: Constraint::Any, + daita_use_multihop_if_necessary: Constraint::Any, quantum_resistant: QuantumResistantState::Auto, } } @@ -673,9 +673,14 @@ pub mod builder { impl<Multihop, Obfuscation, QuantumResistant> RelayQueryBuilder<Wireguard<Multihop, Obfuscation, bool, QuantumResistant>> { - /// Enable DAITA smart routing. - pub fn daita_smart_routing(mut self, constraint: impl Into<Constraint<bool>>) -> Self { - self.query.wireguard_constraints.daita_smart_routing = constraint.into(); + /// Enable DAITA 'use_multihop_if_necessary'. + pub fn daita_use_multihop_if_necessary( + mut self, + constraint: impl Into<Constraint<bool>>, + ) -> Self { + self.query + .wireguard_constraints + .daita_use_multihop_if_necessary = constraint.into(); self } } diff --git a/mullvad-relay-selector/tests/relay_selector.rs b/mullvad-relay-selector/tests/relay_selector.rs index dc05d04eb2..1ce69b0591 100644 --- a/mullvad-relay-selector/tests/relay_selector.rs +++ b/mullvad-relay-selector/tests/relay_selector.rs @@ -1451,7 +1451,7 @@ fn test_daita() { let query = RelayQueryBuilder::new() .wireguard() .daita() - .daita_smart_routing(false) + .daita_use_multihop_if_necessary(false) .build(); let relay = unwrap_entry_relay(relay_selector.get_relay_by_query(query).unwrap()); assert!( @@ -1463,23 +1463,23 @@ fn test_daita() { let query = RelayQueryBuilder::new() .wireguard() .daita() - .daita_smart_routing(false) + .daita_use_multihop_if_necessary(false) .location(NON_DAITA_RELAY_LOCATION.clone()) .build(); relay_selector .get_relay_by_query(query) .expect_err("Expected to find no matching relay"); - // Should be able to connect to non-DAITA relay with smart_routing + // Should be able to connect to non-DAITA relay with use_multihop_if_necessary let query = RelayQueryBuilder::new() .wireguard() .daita() - .daita_smart_routing(true) + .daita_use_multihop_if_necessary(true) .location(NON_DAITA_RELAY_LOCATION.clone()) .build(); let relay = relay_selector .get_relay_by_query(query) - .expect("Expected to find a relay with daita_smart_routing"); + .expect("Expected to find a relay with daita_use_multihop_if_necessary"); match relay { GetRelay::Wireguard { inner: WireguardConfig::Multihop { exit, entry }, @@ -1493,16 +1493,16 @@ fn test_daita() { ), } - // Should be able to connect to DAITA relay with smart_routing + // Should be able to connect to DAITA relay with use_multihop_if_necessary let query = RelayQueryBuilder::new() .wireguard() .daita() - .daita_smart_routing(true) + .daita_use_multihop_if_necessary(true) .location(DAITA_RELAY_LOCATION.clone()) .build(); let relay = relay_selector .get_relay_by_query(query) - .expect("Expected to find a relay with daita_smart_routing"); + .expect("Expected to find a relay with daita_use_multihop_if_necessary"); match relay { GetRelay::Wireguard { inner: WireguardConfig::Singlehop { exit }, @@ -1537,7 +1537,7 @@ fn test_daita() { let query = RelayQueryBuilder::new() .wireguard() .daita() - .daita_smart_routing(false) + .daita_use_multihop_if_necessary(false) .multihop() .build(); let relay = relay_selector.get_relay_by_query(query).unwrap(); @@ -1557,7 +1557,7 @@ fn test_daita() { let query = RelayQueryBuilder::new() .wireguard() .daita() - .daita_smart_routing(false) + .daita_use_multihop_if_necessary(false) .multihop() .location(NON_DAITA_RELAY_LOCATION.clone()) .build(); diff --git a/mullvad-types/src/features.rs b/mullvad-types/src/features.rs index ba40e42d18..0e25f5a59c 100644 --- a/mullvad-types/src/features.rs +++ b/mullvad-types/src/features.rs @@ -1,4 +1,7 @@ -use std::{collections::HashSet, fmt::Display}; +use std::{ + collections::HashSet, + fmt::{Debug, Display}, +}; use crate::settings::{DnsState, Settings}; use serde::{Deserialize, Serialize}; @@ -8,9 +11,20 @@ use talpid_types::net::{ObfuscationType, TunnelEndpoint, TunnelType}; /// what is affecting their connection at any given time. /// /// Note that the feature indicators are not ordered. -#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct FeatureIndicators(HashSet<FeatureIndicator>); +impl Debug for FeatureIndicators { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut indicators: Vec<&str> = self.0.iter().map(|feature| feature.to_str()).collect(); + // Sort the features alphabetically (Just to have some order, arbitrarily chosen) + indicators.sort(); + f.debug_tuple("FeatureIndicators") + .field(&indicators) + .finish() + } +} + impl FeatureIndicators { pub fn is_empty(&self) -> bool { self.0.is_empty() @@ -65,14 +79,7 @@ pub enum FeatureIndicator { ServerIpOverride, CustomMtu, CustomMssFix, - - /// Whether DAITA (without smart routing) is in use. - /// Mutually exclusive with [FeatureIndicator::DaitaSmartRouting]. Daita, - - /// Whether DAITA (with smart routing) is in use. - /// Mutually exclusive with [FeatureIndicator::Daita]. - DaitaSmartRouting, } impl FeatureIndicator { @@ -92,7 +99,6 @@ impl FeatureIndicator { FeatureIndicator::CustomMtu => "Custom MTU", FeatureIndicator::CustomMssFix => "Custom MSS", FeatureIndicator::Daita => "DAITA", - FeatureIndicator::DaitaSmartRouting => "DAITA: Smart Routing", } } } @@ -165,28 +171,13 @@ pub fn compute_feature_indicators( let mtu = settings.tunnel_options.wireguard.mtu.is_some(); - let mut daita_smart_routing = false; - let mut multihop = false; + let mut daita = false; + let multihop = endpoint.entry_endpoint.is_some(); - if let crate::relay_constraints::RelaySettings::Normal(constraints) = - &settings.relay_settings - { - multihop = endpoint.entry_endpoint.is_some() - && constraints.wireguard_constraints.use_multihop; - - #[cfg(daita)] - { - // Detect whether we're using "smart_routing" by checking if multihop is - // in use but not explicitly enabled. - daita_smart_routing = endpoint.daita - && endpoint.entry_endpoint.is_some() - && !constraints.wireguard_constraints.use_multihop - } - }; - - // Daita is mutually exclusive with DaitaSmartRouting #[cfg(daita)] - let daita = endpoint.daita && !daita_smart_routing; + if endpoint.daita { + daita = true; + } vec![ (quantum_resistant, FeatureIndicator::QuantumResistance), @@ -194,9 +185,7 @@ pub fn compute_feature_indicators( (udp_tcp, FeatureIndicator::Udp2Tcp), (shadowsocks, FeatureIndicator::Shadowsocks), (mtu, FeatureIndicator::CustomMtu), - #[cfg(daita)] (daita, FeatureIndicator::Daita), - (daita_smart_routing, FeatureIndicator::DaitaSmartRouting), ] } }; @@ -328,13 +317,18 @@ mod tests { expected_indicators ); + if let RelaySettings::Normal(constraints) = &mut settings.relay_settings { + constraints.wireguard_constraints.use_multihop = true; + }; + assert_eq!( + compute_feature_indicators(&settings, &endpoint, false), + expected_indicators, + "The multihop feature indicator should be enabled by the endpoint, not the settings" + ); endpoint.entry_endpoint = Some(Endpoint { address: SocketAddr::from(([1, 2, 3, 4], 443)), protocol: TransportProtocol::Tcp, }); - if let RelaySettings::Normal(constraints) = &mut settings.relay_settings { - constraints.wireguard_constraints.use_multihop = true; - }; expected_indicators.0.insert(FeatureIndicator::Multihop); assert_eq!( compute_feature_indicators(&settings, &endpoint, false), @@ -370,25 +364,57 @@ mod tests { #[cfg(daita)] { + // Multihop and DAITA on endpoint.daita = true; + settings + .tunnel_options + .wireguard + .daita + .use_multihop_if_necessary = true; + expected_indicators.0.insert(FeatureIndicator::Daita); assert_eq!( compute_feature_indicators(&settings, &endpoint, false), expected_indicators ); + // Should not change regardless of whether `use_multihop_if_necessary` is true, since + // multihop is enabled explicitly + settings + .tunnel_options + .wireguard + .daita + .use_multihop_if_necessary = false; + assert_eq!( + compute_feature_indicators(&settings, &endpoint, false), + expected_indicators, + ); + + // Here we mock that multihop was automatically enabled by DAITA. + // We enable `use_multihop_if_necessary` again and disable the multihop setting, while + // keeping the entry relay. In this scenario, we should still get a Multihop + // indicator. + settings + .tunnel_options + .wireguard + .daita + .use_multihop_if_necessary = true; if let RelaySettings::Normal(constraints) = &mut settings.relay_settings { constraints.wireguard_constraints.use_multihop = false; }; - expected_indicators - .0 - .insert(FeatureIndicator::DaitaSmartRouting); - expected_indicators.0.remove(&FeatureIndicator::Daita); + assert_eq!( + compute_feature_indicators(&settings, &endpoint, false), + expected_indicators, + "DaitaDirectOnly should be enabled" + ); + + // If we also remove the entry relay, we should not get a multihop indicator + endpoint.entry_endpoint = None; expected_indicators.0.remove(&FeatureIndicator::Multihop); assert_eq!( compute_feature_indicators(&settings, &endpoint, false), expected_indicators, - "DaitaSmartRouting should be enabled" + "DaitaDirectOnly should be enabled" ); } @@ -409,7 +435,6 @@ mod tests { FeatureIndicator::CustomMtu => {} FeatureIndicator::CustomMssFix => {} FeatureIndicator::Daita => {} - FeatureIndicator::DaitaSmartRouting => {} } } } diff --git a/mullvad-types/src/wireguard.rs b/mullvad-types/src/wireguard.rs index c6ec6cec5f..12f68566bd 100644 --- a/mullvad-types/src/wireguard.rs +++ b/mullvad-types/src/wireguard.rs @@ -81,12 +81,34 @@ impl FromStr for QuantumResistantState { pub struct QuantumResistantStateParseError; #[cfg(daita)] -#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct DaitaSettings { pub enabled: bool, - #[serde(default)] - pub smart_routing: bool, + #[cfg_attr(target_os = "android", serde(skip))] + #[serde(default = "DaitaSettings::default_use_multihop_if_necessary")] + /// Whether to use multihop if the selected relay is not DAITA-compatible. Note that this is + /// the inverse of of "Direct only" in the GUI. + pub use_multihop_if_necessary: bool, +} + +#[cfg(daita)] +impl DaitaSettings { + /// This setting should be enabled by default, expect on Android where multihop is not + /// supported. + const fn default_use_multihop_if_necessary() -> bool { + cfg!(not(target_os = "android")) + } +} + +#[cfg(daita)] +impl Default for DaitaSettings { + fn default() -> Self { + Self { + enabled: false, + use_multihop_if_necessary: Self::default_use_multihop_if_necessary(), + } + } } /// Contains account specific wireguard data diff --git a/test/test-manager/src/tests/daita.rs b/test/test-manager/src/tests/daita.rs index 912c811ecc..24f5f4b0df 100644 --- a/test/test-manager/src/tests/daita.rs +++ b/test/test-manager/src/tests/daita.rs @@ -12,10 +12,10 @@ use test_rpc::ServiceClient; use super::{helpers, Error, TestContext}; -/// Test that daita and daita_smart_routing works by connecting +/// Test that daita and daita_direct_only works by connecting /// - to a non-DAITA relay with singlehop (should block) /// - to a DAITA relay with singlehop -/// - to a DAITA relay with auto-multihop using smart_routing +/// - to a DAITA relay with auto-multihop by disabling direct_only /// - to a DAITA relay with explicit multihop /// - to a non-DAITA relay with multihop (should block) /// @@ -90,25 +90,25 @@ pub async fn test_daita( .await? .inspect(|event| log::debug!("New daemon event: {event:?}")); - log::info!("Connecting to non-daita relay with DAITA smart routing"); + log::info!("Connecting to non-daita relay with DAITA by automatically using multihop"); { helpers::set_relay_settings(&mut mullvad_client, non_daita_location_query.clone()).await?; mullvad_client.set_enable_daita(true).await?; mullvad_client.connect_tunnel().await?; let state = wait_for_daemon_reconnect(&mut events) .await - .context("Failed to connect with smart_routing enabled")?; + .context("Failed to connect with 'direct only' disabled")?; let endpoint: &TunnelEndpoint = state.endpoint().ok_or(anyhow!("No endpoint"))?; ensure!(endpoint.daita, "DAITA must be used"); ensure!(endpoint.entry_endpoint.is_some(), "multihop must be used"); - log::info!("Successfully multihopped with use smart_routing"); + log::info!("Successfully multihopped with 'direct only' disabled"); } - log::info!("Connecting to non-daita relay with DAITA but no smart routing"); + log::info!("Connecting to non-daita relay with 'DAITA: direct only'"); { - mullvad_client.set_daita_smart_routing(false).await?; + mullvad_client.set_daita_direct_only(true).await?; let result = wait_for_daemon_reconnect(&mut events).await; let Err(Error::UnexpectedErrorState(state)) = result else { @@ -121,13 +121,13 @@ pub async fn test_daita( log::info!("Failed to connect, this is expected!"); } - log::info!("Connecting to daita relay with smart_routing"); + log::info!("Connecting to daita relay with 'direct_only' disabled"); { helpers::set_relay_settings(&mut mullvad_client, daita_location_query).await?; let state = wait_for_daemon_reconnect(&mut events) .await - .context("Failed to connect to daita location with smart_routing enabled")?; + .context("Failed to connect to daita location with 'direct_only' disabled")?; let endpoint = state.endpoint().context("No endpoint")?; ensure!(endpoint.daita, "DAITA must be used"); @@ -136,7 +136,7 @@ pub async fn test_daita( "multihop must not be used" ); - log::info!("Successfully singlehopped with smart_routing"); + log::info!("Successfully singlehopped with 'direct_only' disabled"); } log::info!("Connecting to daita relay with multihop"); |
