From c5b0631a01d79b437d1a1b16b90930d8e4fe7bf1 Mon Sep 17 00:00:00 2001 From: mojganii Date: Wed, 18 Sep 2024 12:35:43 +0200 Subject: [PATCH] Fix some build warnings --- .../ShadowsocksRelaySelector.swift | 2 +- ios/MullvadVPN.xcodeproj/project.pbxproj | 12 +- .../VPNSettings/CustomDNSViewController.swift | 37 +---- .../VPNSettings/VPNSettingsDataSource.swift | 4 +- .../VPNSettingsDataSourceDelegate.swift | 1 + .../VPNSettingsInfoButtonItem.swift | 106 ++++++++++++- .../VPNSettingsPromptAlertItem.swift | 32 ++++ .../VPNSettingsViewController.swift | 143 +++--------------- .../IPOverrideWrapperTests.swift | 8 +- .../ConnectionConfigurationBuilder.swift | 142 +++++++++++++++++ .../Actor/PacketTunnelActor+PostQuantum.swift | 39 ++--- .../Actor/PacketTunnelActor.swift | 39 +---- 12 files changed, 338 insertions(+), 227 deletions(-) create mode 100644 ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift create mode 100644 ios/PacketTunnelCore/Actor/ConnectionConfigurationBuilder.swift diff --git a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift index 2cc305879864..c0d83bc701fb 100644 --- a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift +++ b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift @@ -43,6 +43,6 @@ final public class ShadowsocksRelaySelector: ShadowsocksRelaySelectorProtocol { public func getBridges() throws -> REST.ServerShadowsocks? { let cachedRelays = try relayCache.read() - return RelaySelector.Shadowsocks.tcpBridge(from: try cachedRelays.relays) + return RelaySelector.Shadowsocks.tcpBridge(from: cachedRelays.relays) } } diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 3874f7550c8f..7e4fcbbfc2a2 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -862,6 +862,8 @@ F03580252A13842C00E5DAFD /* IncreasedHitButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03580242A13842C00E5DAFD /* IncreasedHitButton.swift */; }; F03A69F72C2AD2D6000E2E7E /* TimeInterval+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03A69F62C2AD2D5000E2E7E /* TimeInterval+Timeout.swift */; }; F03A69F92C2AD414000E2E7E /* FormsheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03A69F82C2AD413000E2E7E /* FormsheetPresentationController.swift */; }; + F041BE4F2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F041BE4E2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift */; }; + F041BE532C9878B60083EC28 /* ConnectionConfigurationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F041BE522C9878B60083EC28 /* ConnectionConfigurationBuilder.swift */; }; F04413612BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; F04413622BA45CE30018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; F04AF92D2C466013004A8314 /* EphemeralPeerNegotiationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */; }; @@ -2077,6 +2079,8 @@ F03580242A13842C00E5DAFD /* IncreasedHitButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncreasedHitButton.swift; sourceTree = ""; }; F03A69F62C2AD2D5000E2E7E /* TimeInterval+Timeout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Timeout.swift"; sourceTree = ""; }; F03A69F82C2AD413000E2E7E /* FormsheetPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormsheetPresentationController.swift; sourceTree = ""; }; + F041BE4E2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNSettingsPromptAlertItem.swift; sourceTree = ""; }; + F041BE522C9878B60083EC28 /* ConnectionConfigurationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionConfigurationBuilder.swift; sourceTree = ""; }; F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomListLocationNodeBuilder.swift; sourceTree = ""; }; F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerNegotiationState.swift; sourceTree = ""; }; F04DD3D72C130DF600E03E28 /* TunnelSettingsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelSettingsManager.swift; sourceTree = ""; }; @@ -2819,6 +2823,7 @@ 587EB6732714520600123C75 /* VPNSettingsDataSourceDelegate.swift */, 7A6F2FAE2AFE36E7006D0856 /* VPNSettingsInfoButtonItem.swift */, 5871167E2910035700D41AAC /* VPNSettingsInteractor.swift */, + F041BE4E2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift */, 58ACF6482655365700ACE4B7 /* VPNSettingsViewController.swift */, 587EB671271451E300123C75 /* VPNSettingsViewModel.swift */, ); @@ -3084,6 +3089,9 @@ 58BDEBA02A9CA14B00F578F2 /* AnyTask.swift */, 58F3F3652AA086A400D3B0A4 /* AutoCancellingTask.swift */, 583E60952A9F6D0800DC61EF /* ConfigurationBuilder.swift */, + F041BE522C9878B60083EC28 /* ConnectionConfigurationBuilder.swift */, + F05919742C45194B00C301F3 /* EphemeralPeerKey.swift */, + F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */, 5838322A2AC3EF9600EA2071 /* EventChannel.swift */, 580D6B892AB31AB400B2D6E0 /* NetworkPath+NetworkReachability.swift */, 58CF95A12AD6F35800B59F5D /* ObservedState.swift */, @@ -3100,8 +3108,6 @@ 583832282AC3DF1300EA2071 /* PacketTunnelActorCommand.swift */, 7AD0AA192AD69B6E00119E10 /* PacketTunnelActorProtocol.swift */, 44B3C4392BFE2C800079782C /* PacketTunnelActorReducer.swift */, - F05919742C45194B00C301F3 /* EphemeralPeerKey.swift */, - F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */, A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */, 58E7A0312AA0715100C57861 /* Protocols */, 58ED3A132A7C199C0085CE65 /* StartOptions.swift */, @@ -5495,6 +5501,7 @@ 5838322B2AC3EF9600EA2071 /* EventChannel.swift in Sources */, 586C145A2AC4735F00245C01 /* PacketTunnelActor+Public.swift in Sources */, F0DAC8AD2C16EFE400F80144 /* TunnelSettingsManager.swift in Sources */, + F041BE532C9878B60083EC28 /* ConnectionConfigurationBuilder.swift in Sources */, 58342C042AAB61FB003BA12D /* State+Extensions.swift in Sources */, A95EEE382B722DFC00A8A39B /* PingStats.swift in Sources */, 583832272AC3193600EA2071 /* PacketTunnelActor+SleepCycle.swift in Sources */, @@ -5573,6 +5580,7 @@ 7AC8A3AF2ABC71D600DC4939 /* TermsOfServiceCoordinator.swift in Sources */, 58FF9FE22B075BA600E4C97D /* EditAccessMethodSectionIdentifier.swift in Sources */, F0C2AEFD2A0BB5CC00986207 /* NotificationProviderIdentifier.swift in Sources */, + F041BE4F2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift in Sources */, 7A58699B2B482FE200640D27 /* UITableViewCell+Disable.swift in Sources */, 7AB2B6702BA1EB8C00B03E3B /* ListCustomListViewController.swift in Sources */, 7A9CCCB72A96302800DD6A34 /* RevokedCoordinator.swift in Sources */, diff --git a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift index 40fa74e0f625..5280cd00a588 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSViewController.swift @@ -102,38 +102,9 @@ extension CustomDNSViewController: DNSSettingsDataSourceDelegate { } func showInfo(for item: VPNSettingsInfoButtonItem) { - var message = NSAttributedString() - - switch item { - case .contentBlockers: - message = NSAttributedString(markdownString: NSLocalizedString( - "VPN_SETTINGS_CONTENT_BLOCKERS_GENERAL", - tableName: "ContentBlockers", - value: """ - When this feature is enabled it stops the device from contacting certain \ - domains or websites known for distributing ads, malware, trackers and more. \ - - This might cause issues on certain websites, services, and apps. - Attention: this setting cannot be used in combination with **Use custom DNS server**. - """, - comment: "" - ), options: MarkdownStylingOptions(font: .preferredFont(forTextStyle: .body))) - - case .blockMalware: - message = NSAttributedString(markdownString: NSLocalizedString( - "VPN_SETTINGS_CONTENT_BLOCKERS_MALWARE", - tableName: "ContentBlockers", - value: """ - Warning: The malware blocker is not an anti-virus and should not \ - be treated as such, this is just an extra layer of protection. - """, - comment: "" - ), options: MarkdownStylingOptions(font: .preferredFont(forTextStyle: .body))) - - default: - assertionFailure("No matching InfoButtonItem") - } - - showInfo(with: message) + showInfo(with: NSAttributedString( + markdownString: item.description, + options: MarkdownStylingOptions(font: .preferredFont(forTextStyle: .body)) + )) } } diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift index 45dbc344ab12..bd24a10f6dda 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift @@ -461,8 +461,8 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< header.accessibilityCustomActionName = title header.isExpanded = isExpanded(.wireGuardPorts) header.infoButtonHandler = { [weak self] in - if let self { - self.delegate?.showInfo(for: .wireGuardPorts) + if let self, let humanReadablePortRepresentation = delegate?.humanReadablePortRepresentation() { + self.delegate?.showInfo(for: .wireGuardPorts(humanReadablePortRepresentation)) } } diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift index f6482e80ef37..84bf9795d042 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift @@ -22,4 +22,5 @@ protocol VPNSettingsDataSourceDelegate: AnyObject { func showIPOverrides() func didSelectWireGuardPort(_ port: UInt16?) func showPrompt(for: VPNSettingsPromptAlertItem, onSave: @escaping () -> Void, onDiscard: @escaping () -> Void) + func humanReadablePortRepresentation() -> String } diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift index f8cb79bb417d..1ba634301583 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift @@ -6,18 +6,112 @@ // Copyright © 2023 Mullvad VPN AB. All rights reserved. // -enum VPNSettingsInfoButtonItem { +import Foundation + +enum VPNSettingsInfoButtonItem: CustomStringConvertible { case contentBlockers case blockMalware - case wireGuardPorts + case wireGuardPorts(String) case wireGuardObfuscation case wireGuardObfuscationPort case quantumResistance case multihop case daita -} -enum VPNSettingsPromptAlertItem { - case daitaSettingIncompatibleWithSinglehop - case daitaSettingIncompatibleWithMultihop + var description: String { + switch self { + case .contentBlockers: + NSLocalizedString( + "VPN_SETTINGS_CONTENT_BLOCKERS_GENERAL", + tableName: "ContentBlockers", + value: """ + When this feature is enabled it stops the device from contacting certain \ + domains or websites known for distributing ads, malware, trackers and more. \ + + This might cause issues on certain websites, services, and apps. + Attention: this setting cannot be used in combination with **Use custom DNS server**. + """, + comment: "" + ) + case .blockMalware: + NSLocalizedString( + "VPN_SETTINGS_CONTENT_BLOCKERS_MALWARE", + tableName: "ContentBlockers", + value: """ + Warning: The malware blocker is not an anti-virus and should not \ + be treated as such, this is just an extra layer of protection. + """, + comment: "" + ) + case let .wireGuardPorts(portsString): + String( + format: NSLocalizedString( + "VPN_SETTINGS_WIRE_GUARD_PORTS_GENERAL", + tableName: "WireGuardPorts", + value: """ + The automatic setting will randomly choose from the valid port ranges shown below. + The custom port can be any value inside the valid ranges: + %@ + """, + comment: "" + ), + portsString + ) + case .wireGuardObfuscation: + NSLocalizedString( + "VPN_SETTINGS_WIRE_GUARD_OBFUSCATION_GENERAL", + tableName: "WireGuardObfuscation", + value: """ + Obfuscation hides the WireGuard traffic inside another protocol. \ + It can be used to help circumvent censorship and other types of filtering, \ + where a plain WireGuard connect would be blocked. + """, + comment: "" + ) + case .wireGuardObfuscationPort: + NSLocalizedString( + "VPN_SETTINGS_WIRE_GUARD_OBFUSCATION_PORT_GENERAL", + tableName: "WireGuardObfuscation", + value: "Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.", + comment: "" + ) + case .quantumResistance: + NSLocalizedString( + "VPN_SETTINGS_QUANTUM_RESISTANCE_GENERAL", + tableName: "QuantumResistance", + value: """ + This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers. + It does this by performing an extra key exchange using a quantum safe algorithm and mixing \ + the result into WireGuard’s regular encryption. + This extra step uses approximately 500 kiB of traffic every time a new tunnel is established. + """, + comment: "" + ) + case .multihop: + NSLocalizedString( + "MULTIHOP_INFORMATION_TEXT", + tableName: "Multihop", + value: """ + Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. + This results in increased latency but increases anonymity online. + """, + comment: "" + ) + case .daita: + NSLocalizedString( + "DAITA_INFORMATION_TEXT", + tableName: "DAITA", + value: """ + DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. \ + If anyone is monitoring your connection, this makes it significantly harder for them to identify \ + what websites you are visiting. It does this by carefully adding network noise and making all \ + network packets the same size. + Attention: Since this increases your total network traffic, \ + be cautious if you have a limited data plan. \ + It can also negatively impact your network speed and battery usage. + """, + comment: "" + ) + } + } } diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift new file mode 100644 index 000000000000..74cc90b8d836 --- /dev/null +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift @@ -0,0 +1,32 @@ +// +// VPNSettingsPromptAlertItem.swift +// MullvadVPN +// +// Created by Mojgan on 2024-09-16. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +enum VPNSettingsPromptAlertItem: CustomStringConvertible { + case daitaSettingIncompatibleWithSinglehop + case daitaSettingIncompatibleWithMultihop + + var description: String { + switch self { + case .daitaSettingIncompatibleWithSinglehop: + """ + DAITA isn’t available on the current server. After enabling, please go to the Switch \ + location view and select a location that supports DAITA. + Attention: Since this increases your total network traffic, be cautious if you have a \ + limited data plan. It can also negatively impact your network speed and battery usage. + """ + case .daitaSettingIncompatibleWithMultihop: + """ + DAITA isn’t available on the current entry server. After enabling, please go to the Switch \ + location view and select an entry location that supports DAITA. + Attention: Since this increases your total network traffic, be cautious if you have a \ + limited data plan. It can also negatively impact your network speed and battery usage. + """ + } + } +} diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift index 201043c9418c..32facd0ecab8 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift @@ -70,12 +70,31 @@ class VPNSettingsViewController: UITableViewController { size: CGSize(width: 0, height: UIMetrics.TableView.sectionSpacing) )) } +} + +extension VPNSettingsViewController: VPNSettingsDataSourceDelegate { + func humanReadablePortRepresentation() -> String { + let ranges = interactor.cachedRelays?.relays.wireguard.portRanges ?? [] + return ranges + .compactMap { range in + if let minPort = range.first, let maxPort = range.last { + return minPort == maxPort ? String(minPort) : "\(minPort)-\(maxPort)" + } else { + return nil + } + } + .joined(separator: ", ") + } + + func didUpdateTunnelSettings(_ update: TunnelSettingsUpdate) { + interactor.updateSettings([update]) + } - private func showInfo(with message: String) { + func showInfo(for item: VPNSettingsInfoButtonItem) { let presentation = AlertPresentation( id: "vpn-settings-content-blockers-alert", icon: .info, - message: message, + message: item.description, buttons: [ AlertAction( title: NSLocalizedString( @@ -92,107 +111,6 @@ class VPNSettingsViewController: UITableViewController { alertPresenter.showAlert(presentation: presentation, animated: true) } - private func humanReadablePortRepresentation(_ ranges: [[UInt16]]) -> String { - ranges - .compactMap { range in - if let minPort = range.first, let maxPort = range.last { - return minPort == maxPort ? String(minPort) : "\(minPort)-\(maxPort)" - } else { - return nil - } - } - .joined(separator: ", ") - } -} - -extension VPNSettingsViewController: VPNSettingsDataSourceDelegate { - func didUpdateTunnelSettings(_ update: TunnelSettingsUpdate) { - interactor.updateSettings([update]) - } - - // swiftlint:disable:next function_body_length - func showInfo(for item: VPNSettingsInfoButtonItem) { switch item { - case .wireGuardPorts: - let portsString = humanReadablePortRepresentation( - interactor.cachedRelays?.relays.wireguard.portRanges ?? [] - ) - - showInfo(with: String( - format: NSLocalizedString( - "VPN_SETTINGS_WIRE_GUARD_PORTS_GENERAL", - tableName: "WireGuardPorts", - value: """ - The automatic setting will randomly choose from the valid port ranges shown below. - The custom port can be any value inside the valid ranges: - %@ - """, - comment: "" - ), - portsString - )) - - case .wireGuardObfuscation: - showInfo(with: NSLocalizedString( - "VPN_SETTINGS_WIRE_GUARD_OBFUSCATION_GENERAL", - tableName: "WireGuardObfuscation", - value: """ - Obfuscation hides the WireGuard traffic inside another protocol. \ - It can be used to help circumvent censorship and other types of filtering, \ - where a plain WireGuard connect would be blocked. - """, - comment: "" - )) - - case .wireGuardObfuscationPort: - showInfo(with: NSLocalizedString( - "VPN_SETTINGS_WIRE_GUARD_OBFUSCATION_PORT_GENERAL", - tableName: "WireGuardObfuscation", - value: "Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.", - comment: "" - )) - - case .quantumResistance: - showInfo(with: NSLocalizedString( - "VPN_SETTINGS_QUANTUM_RESISTANCE_GENERAL", - tableName: "QuantumResistance", - value: """ - This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers. - It does this by performing an extra key exchange using a quantum safe algorithm and mixing \ - the result into WireGuard’s regular encryption. - This extra step uses approximately 500 kiB of traffic every time a new tunnel is established. - """, - comment: "" - )) - - case .multihop: - showInfo(with: NSLocalizedString( - "MULTIHOP_INFORMATION_TEXT", - tableName: "Multihop", - value: """ - Multihop routes your traffic into one WireGuard server and out another, making it harder to trace. - This results in increased latency but increases anonymity online. - """, - comment: "" - )) - case .daita: - showInfo(with: NSLocalizedString( - "DAITA_INFORMATION_TEXT", - tableName: "DAITA", - value: """ - DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. \ - If anyone is monitoring your connection, this makes it significantly harder for them to identify \ - what websites you are visiting. It does this by carefully adding network noise and making all \ - network packets the same size. - Attention: Since this increases your total network traffic, be cautious if you have a limited data plan. \ - It can also negatively impact your network speed and battery usage. - """, - comment: "" - )) - default: - assertionFailure("No matching InfoButtonItem") - } - } - func showDNSSettings() { let viewController = CustomDNSViewController(interactor: interactor, alertPresenter: alertPresenter) navigationController?.pushViewController(viewController, animated: true) @@ -215,23 +133,6 @@ extension VPNSettingsViewController: VPNSettingsDataSourceDelegate { onSave: @escaping () -> Void, onDiscard: @escaping () -> Void ) { - let messageString = switch item { - case .daitaSettingIncompatibleWithSinglehop: - """ - DAITA isn’t available on the current server. After enabling, please go to the Switch \ - location view and select a location that supports DAITA. - Attention: Since this increases your total network traffic, be cautious if you have a \ - limited data plan. It can also negatively impact your network speed and battery usage. - """ - case .daitaSettingIncompatibleWithMultihop: - """ - DAITA isn’t available on the current entry server. After enabling, please go to the Switch \ - location view and select an entry location that supports DAITA. - Attention: Since this increases your total network traffic, be cautious if you have a \ - limited data plan. It can also negatively impact your network speed and battery usage. - """ - } - let presentation = AlertPresentation( id: "vpn-settings-content-blockers-alert", accessibilityIdentifier: .daitaPromptAlert, @@ -239,7 +140,7 @@ extension VPNSettingsViewController: VPNSettingsDataSourceDelegate { message: NSLocalizedString( "VPN_SETTINGS_VPN_DAITA_ENABLE_TEXT", tableName: "DAITA", - value: messageString, + value: item.description, comment: "" ), buttons: [ diff --git a/ios/MullvadVPNTests/MullvadSettings/IPOverrideWrapperTests.swift b/ios/MullvadVPNTests/MullvadSettings/IPOverrideWrapperTests.swift index c694f50f9004..5f5648c06b0b 100644 --- a/ios/MullvadVPNTests/MullvadSettings/IPOverrideWrapperTests.swift +++ b/ios/MullvadVPNTests/MullvadSettings/IPOverrideWrapperTests.swift @@ -32,12 +32,12 @@ final class IPOverrideWrapperTests: XCTestCase { let storedCache = try overrideWrapper.read() // Assert that relay was overridden. - let host1 = try storedCache.relays.wireguard.relays.first + let host1 = storedCache.relays.wireguard.relays.first XCTAssertEqual(host1?.ipv4AddrIn, .loopback) XCTAssertEqual(host1?.ipv6AddrIn, .broadcast) // Assert that relay was NOT overridden. - let host2 = try storedCache.relays.wireguard.relays.last + let host2 = storedCache.relays.wireguard.relays.last XCTAssertEqual(host2?.ipv4AddrIn, .any) XCTAssertEqual(host2?.ipv6AddrIn, .any) } @@ -62,11 +62,11 @@ final class IPOverrideWrapperTests: XCTestCase { let storedCache = try overrideWrapper.read() // Assert that relay was overridden. - let host1 = try storedCache.relays.bridge.relays.first + let host1 = storedCache.relays.bridge.relays.first XCTAssertEqual(host1?.ipv4AddrIn, .loopback) // Assert that relay was NOT overridden. - let host2 = try storedCache.relays.bridge.relays.last + let host2 = storedCache.relays.bridge.relays.last XCTAssertEqual(host2?.ipv4AddrIn, .any) } } diff --git a/ios/PacketTunnelCore/Actor/ConnectionConfigurationBuilder.swift b/ios/PacketTunnelCore/Actor/ConnectionConfigurationBuilder.swift new file mode 100644 index 000000000000..54eca7b54d74 --- /dev/null +++ b/ios/PacketTunnelCore/Actor/ConnectionConfigurationBuilder.swift @@ -0,0 +1,142 @@ +// +// ConnectionConfigurationBuilder.swift +// PacketTunnelCore +// +// Created by Mojgan on 2024-09-16. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import WireGuardKitTypes + +protocol Configuration { + var name: String { get } + func make() throws -> ConnectionConfiguration +} + +struct ConnectionConfiguration { + let entryConfiguration: TunnelAdapterConfiguration? + let exitConfiguration: TunnelAdapterConfiguration +} + +struct ConnectionConfigurationBuilder { + enum ConnectionType { + case normal + case ephemeral(EphemeralPeerNegotiationState) + } + + let type: ConnectionType + let settings: Settings + let connectionData: State.ConnectionData + + func make() throws -> ConnectionConfiguration { + switch type { + case .normal: + try NormalConnectionConfiguration(settings: settings, connectionData: connectionData).make() + case let .ephemeral(ephemeralPeerNegotiationState): + try EphemeralConnectionConfiguration( + settings: settings, + connectionData: connectionData, + ephemeralPeerNegotiationState: ephemeralPeerNegotiationState + ).make() + } + } +} + +private struct NormalConnectionConfiguration: Configuration { + let settings: Settings + let connectionData: State.ConnectionData + + var name: String { + "Normal connection configuration" + } + + private var activeKey: PrivateKey { + switch connectionData.keyPolicy { + case .useCurrent: + settings.privateKey + case let .usePrior(priorKey, _): + priorKey + } + } + + func make() throws -> ConnectionConfiguration { + let entryConfiguration: TunnelAdapterConfiguration? = if connectionData.selectedRelays.entry != nil { + try ConfigurationBuilder( + privateKey: activeKey, + interfaceAddresses: settings.interfaceAddresses, + dns: settings.dnsServers, + endpoint: connectionData.connectedEndpoint, + allowedIPs: [ + IPAddressRange(from: "\(connectionData.selectedRelays.exit.endpoint.ipv4Relay.ip)/32")!, + ] + ).makeConfiguration() + } else { + nil + } + let exitConfiguration = try ConfigurationBuilder( + privateKey: activeKey, + interfaceAddresses: settings.interfaceAddresses, + dns: settings.dnsServers, + endpoint: (entryConfiguration != nil) + ? connectionData.selectedRelays.exit.endpoint + : connectionData.connectedEndpoint, + allowedIPs: [ + IPAddressRange(from: "0.0.0.0/0")!, + IPAddressRange(from: "::/0")!, + ] + ).makeConfiguration() + + return ConnectionConfiguration( + entryConfiguration: entryConfiguration, + exitConfiguration: exitConfiguration + ) + } +} + +private struct EphemeralConnectionConfiguration: Configuration { + let settings: Settings + let connectionData: State.ConnectionData + let ephemeralPeerNegotiationState: EphemeralPeerNegotiationState + + var name: String { + "Ephemeral connection configuration" + } + + func make() throws -> ConnectionConfiguration { + switch ephemeralPeerNegotiationState { + case let .single(hop): + let exitConfiguration = try ConfigurationBuilder( + privateKey: hop.configuration.privateKey, + interfaceAddresses: settings.interfaceAddresses, + dns: settings.dnsServers, + endpoint: connectionData.connectedEndpoint, + allowedIPs: hop.configuration.allowedIPs, + preSharedKey: hop.configuration.preSharedKey + ).makeConfiguration() + + return ConnectionConfiguration(entryConfiguration: nil, exitConfiguration: exitConfiguration) + + case let .multi(firstHop, secondHop): + let entryConfiguration = try ConfigurationBuilder( + privateKey: firstHop.configuration.privateKey, + interfaceAddresses: settings.interfaceAddresses, + dns: settings.dnsServers, + endpoint: connectionData.connectedEndpoint, + allowedIPs: firstHop.configuration.allowedIPs, + preSharedKey: firstHop.configuration.preSharedKey + ).makeConfiguration() + + let exitConfiguration = try ConfigurationBuilder( + privateKey: secondHop.configuration.privateKey, + interfaceAddresses: settings.interfaceAddresses, + dns: settings.dnsServers, + endpoint: secondHop.relay.endpoint, + allowedIPs: secondHop.configuration.allowedIPs, + preSharedKey: secondHop.configuration.preSharedKey + ).makeConfiguration() + + return ConnectionConfiguration(entryConfiguration: entryConfiguration, exitConfiguration: exitConfiguration) + } + } +} diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift index 4bebc5c32446..3b3c5ad560ed 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift @@ -76,38 +76,23 @@ extension PacketTunnelActor { switch configuration { case let .single(hop): - let exitConfiguration = try ConfigurationBuilder( - privateKey: hop.configuration.privateKey, - interfaceAddresses: settings.interfaceAddresses, - dns: settings.dnsServers, - endpoint: connectionData.connectedEndpoint, - allowedIPs: hop.configuration.allowedIPs, - preSharedKey: hop.configuration.preSharedKey - ).makeConfiguration() - + let exitConfiguration = try ConnectionConfigurationBuilder( + type: .ephemeral(.single(hop)), + settings: settings, + connectionData: connectionData + ).make().exitConfiguration try await tunnelAdapter.start(configuration: exitConfiguration, daita: daitaConfiguration) case let .multi(firstHop, secondHop): - let entryConfiguration = try ConfigurationBuilder( - privateKey: firstHop.configuration.privateKey, - interfaceAddresses: settings.interfaceAddresses, - dns: settings.dnsServers, - endpoint: connectionData.connectedEndpoint, - allowedIPs: firstHop.configuration.allowedIPs, - preSharedKey: firstHop.configuration.preSharedKey - ).makeConfiguration() - - let exitConfiguration = try ConfigurationBuilder( - privateKey: secondHop.configuration.privateKey, - interfaceAddresses: settings.interfaceAddresses, - dns: settings.dnsServers, - endpoint: secondHop.relay.endpoint, - allowedIPs: secondHop.configuration.allowedIPs, - preSharedKey: secondHop.configuration.preSharedKey - ).makeConfiguration() + let connectionConfiguration = try ConnectionConfigurationBuilder( + type: .ephemeral(.multi(entry: firstHop, exit: secondHop)), + settings: settings, + connectionData: connectionData + ).make() try await tunnelAdapter.startMultihop( - entryConfiguration: entryConfiguration, exitConfiguration: exitConfiguration, daita: daitaConfiguration + entryConfiguration: connectionConfiguration.entryConfiguration, + exitConfiguration: connectionConfiguration.exitConfiguration, daita: daitaConfiguration ) } } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index 0a4b9dc493fc..98dbeea262b7 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -287,35 +287,11 @@ extension PacketTunnelActor { ) async throws { guard let connectionState = try obfuscateConnection(nextRelays: nextRelays, settings: settings, reason: reason), let targetState = state.targetStateForReconnect else { return } - - let activeKey = activeKey(from: connectionState, in: settings) - - let entryConfiguration: TunnelAdapterConfiguration? = if connectionState.selectedRelays.entry != nil { - try ConfigurationBuilder( - privateKey: activeKey, - interfaceAddresses: settings.interfaceAddresses, - dns: settings.dnsServers, - endpoint: connectionState.connectedEndpoint, - allowedIPs: [ - IPAddressRange(from: "\(connectionState.selectedRelays.exit.endpoint.ipv4Relay.ip)/32")!, - ] - ).makeConfiguration() - } else { - nil - } - - let exitConfiguration = try ConfigurationBuilder( - privateKey: activeKey, - interfaceAddresses: settings.interfaceAddresses, - dns: settings.dnsServers, - endpoint: (entryConfiguration != nil) - ? connectionState.selectedRelays.exit.endpoint - : connectionState.connectedEndpoint, - allowedIPs: [ - IPAddressRange(from: "0.0.0.0/0")!, - IPAddressRange(from: "::/0")!, - ] - ).makeConfiguration() + let configuration = try ConnectionConfigurationBuilder( + type: .normal, + settings: settings, + connectionData: connectionState + ).make() /* Stop default path observer while updating WireGuard configuration since it will call the system method @@ -341,8 +317,8 @@ extension PacketTunnelActor { } try await tunnelAdapter.startMultihop( - entryConfiguration: entryConfiguration, - exitConfiguration: exitConfiguration, + entryConfiguration: configuration.entryConfiguration, + exitConfiguration: configuration.exitConfiguration, daita: daitaConfiguration ) @@ -528,4 +504,5 @@ extension PacketTunnelActor { } extension PacketTunnelActor: PacketTunnelActorProtocol {} + // swiftlint:disable:this file_length