diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-12-09 16:06:03 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-12-09 16:06:03 +0100 |
| commit | fe9fe00c2630efa49d2007dc5c38584aab81dabb (patch) | |
| tree | 476b397e186c024c84ecab5377ac28f384694a46 | |
| parent | bdbd4047299f4ee07ca24d652f3893f35741a98b (diff) | |
| parent | 16c758b397b3a139f5a8662619822fa274fb99e5 (diff) | |
| download | mullvadvpn-fe9fe00c2630efa49d2007dc5c38584aab81dabb.tar.xz mullvadvpn-fe9fe00c2630efa49d2007dc5c38584aab81dabb.zip | |
Merge branch 'handle-application-updates-with-settings-migration'
7 files changed, 113 insertions, 11 deletions
diff --git a/ios/MullvadTypes/PacketTunnelErrorWrapper.swift b/ios/MullvadTypes/PacketTunnelErrorWrapper.swift new file mode 100644 index 0000000000..e70bdb0c9f --- /dev/null +++ b/ios/MullvadTypes/PacketTunnelErrorWrapper.swift @@ -0,0 +1,39 @@ +// +// PacketTunnelErrorWrapper.swift +// MullvadTypes +// +// Created by Sajad Vishkai on 2022-11-28. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public enum PacketTunnelErrorWrapper: Codable, Equatable, LocalizedError { + /// Failure that indicates wire guard errors. + case wireguard(error: String) + + /// Failure to read stored settings. + case readConfiguration + + public var errorDescription: String? { + switch self { + case let .wireguard(error): + return error + case .readConfiguration: + return "Failure to read settings." + } + } + + public static func == (lhs: PacketTunnelErrorWrapper, rhs: PacketTunnelErrorWrapper) -> Bool { + switch (lhs, rhs) { + case (.readConfiguration, .readConfiguration): + return true + + case let (.wireguard(error: lhsError), .wireguard(error: rhsError)): + return lhsError == rhsError + + default: + return false + } + } +} diff --git a/ios/MullvadTypes/PacketTunnelStatus.swift b/ios/MullvadTypes/PacketTunnelStatus.swift index 2b5a1abf91..6f38c25c78 100644 --- a/ios/MullvadTypes/PacketTunnelStatus.swift +++ b/ios/MullvadTypes/PacketTunnelStatus.swift @@ -35,7 +35,7 @@ public struct DeviceCheck: Codable, Equatable { /// Struct describing packet tunnel process status. public struct PacketTunnelStatus: Codable, Equatable { /// Last tunnel error. - public var lastError: String? + public var lastErrors: [PacketTunnelErrorWrapper] /// Flag indicating whether network is reachable. public var isNetworkReachable: Bool @@ -47,12 +47,12 @@ public struct PacketTunnelStatus: Codable, Equatable { public var tunnelRelay: PacketTunnelRelay? public init( - lastError: String? = nil, + lastErrors: [PacketTunnelErrorWrapper] = [], isNetworkReachable: Bool = true, deviceCheck: DeviceCheck? = nil, tunnelRelay: PacketTunnelRelay? = nil ) { - self.lastError = lastError + self.lastErrors = lastErrors self.isNetworkReachable = isNetworkReachable self.deviceCheck = deviceCheck self.tunnelRelay = tunnelRelay diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 03f0efe43a..9c8eb65127 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 06410E07292D108E00AFC18C /* SettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06410E06292D108E00AFC18C /* SettingsStore.swift */; }; 06410E08292D117800AFC18C /* SettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06410E06292D108E00AFC18C /* SettingsStore.swift */; }; 06410E09292D990C00AFC18C /* Result+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F1311427E0B2AB007AC5BC /* Result+Extensions.swift */; }; + 06410E182934F43B00AFC18C /* PacketTunnelErrorWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06410E172934F43B00AFC18C /* PacketTunnelErrorWrapper.swift */; }; 06799ACE28F98E1D00ACD94E /* MullvadREST.h in Headers */ = {isa = PBXBuildFile; fileRef = 06799ABE28F98E1D00ACD94E /* MullvadREST.h */; settings = {ATTRIBUTES = (Public, ); }; }; 06799AD128F98E1D00ACD94E /* MullvadREST.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */; }; 06799AD228F98E1D00ACD94E /* MullvadREST.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -539,6 +540,7 @@ 06410DFD292CE18F00AFC18C /* KeychainSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainSettingsStore.swift; sourceTree = "<group>"; }; 06410E03292D0F7100AFC18C /* SettingsParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsParser.swift; sourceTree = "<group>"; }; 06410E06292D108E00AFC18C /* SettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStore.swift; sourceTree = "<group>"; }; + 06410E172934F43B00AFC18C /* PacketTunnelErrorWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelErrorWrapper.swift; sourceTree = "<group>"; }; 06799AB428F98CE700ACD94E /* le_root_cert.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = le_root_cert.cer; sourceTree = "<group>"; }; 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MullvadREST.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 06799ABE28F98E1D00ACD94E /* MullvadREST.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MullvadREST.h; sourceTree = "<group>"; }; @@ -1080,6 +1082,7 @@ 585DA89826B0329200B8C587 /* PacketTunnelStatus.swift */, 5898D2B62902A9EA00EB5EBA /* PacketTunnelRelay.swift */, 58900D0228BBDCC70094E4F0 /* FixedWidthInteger+Arithmetics.swift */, + 06410E172934F43B00AFC18C /* PacketTunnelErrorWrapper.swift */, ); path = MullvadTypes; sourceTree = "<group>"; @@ -2092,6 +2095,7 @@ 586A9516290133ED007BAF2B /* AnyIPAddress.swift in Sources */, 5856AD592902BE1A008E5127 /* PacketTunnelStatus.swift in Sources */, 5898D2A32901807500EB5EBA /* MullvadEndpoint.swift in Sources */, + 06410E182934F43B00AFC18C /* PacketTunnelErrorWrapper.swift in Sources */, 5898D2B32902A8F000EB5EBA /* RelayLocation.swift in Sources */, 063F026A29002E44001FA09F /* IPv4Endpoint.swift in Sources */, 5856AD582902BE1A008E5127 /* PacketTunnelRelay.swift in Sources */, diff --git a/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift b/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift index 426d97dbad..81c2709267 100644 --- a/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift +++ b/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift @@ -42,8 +42,13 @@ class TunnelStatusNotificationProvider: NotificationProvider, InAppNotificationP private func handleTunnelStatus(_ tunnelStatus: TunnelStatus) { let invalidateForTunnelError = updateLastTunnelError( - tunnelStatus.packetTunnelStatus - .lastError + tunnelStatus.packetTunnelStatus.lastErrors.first(where: { + if case .wireguard = $0 { + return true + } + + return false + })?.localizedDescription ) let invalidateForManagerError = updateTunnelManagerError(tunnelStatus.state) let invalidateForConnectivity = updateConnectivity(tunnelStatus.state) diff --git a/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift b/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift index 65f8f9196f..aa85eda6b2 100644 --- a/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift +++ b/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift @@ -17,6 +17,7 @@ struct PacketTunnelTransport: RESTTransport { } let tunnel: Tunnel + init(tunnel: Tunnel) { self.tunnel = tunnel } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 0489d70229..5dd4711ed1 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -84,6 +84,9 @@ final class TunnelManager: StorePaymentObserver { /// Last processed device check identifier. private var lastDeviceCheckIdentifier: UUID? + /// Flag indicating tunnel reconnected after settings migration. + private var reconnectedTunnelAfterMigration = false + // MARK: - Initialization init( @@ -698,6 +701,14 @@ final class TunnelManager: StorePaymentObserver { // while the tunnel process is trying to connect. startPollingTunnelStatus(interval: establishingTunnelStatusPollInterval) + if newTunnelStatus.packetTunnelStatus.lastErrors.contains(.readConfiguration), + !reconnectedTunnelAfterMigration + { + reconnectTunnel(selectNewRelay: true) + + reconnectedTunnelAfterMigration = true + } + case .connected, .waitingForConnectivity: // Start polling tunnel status to keep connectivity status up to date. startPollingTunnelStatus(interval: establishedTunnelStatusPollInterval) diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift index b83271ad82..13f7646b9f 100644 --- a/ios/PacketTunnel/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider.swift @@ -44,8 +44,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { /// Number of consecutive connection failure attempts. private var numberOfFailedAttempts: UInt = 0 - /// Last runtime error. - private var lastError: Error? + /// Last wireguard error. + private var wgError: PacketTunnelErrorWrapper? + + /// Last tunnel provider error. + private var tunnelProviderError: PacketTunnelErrorWrapper? /// Relay cache. private let relayCache = RelayCache( @@ -87,7 +90,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { /// Returns `PacketTunnelStatus` used for sharing with main bundle process. private var packetTunnelStatus: PacketTunnelStatus { return PacketTunnelStatus( - lastError: lastError?.localizedDescription, + lastErrors: [wgError, tunnelProviderError].compactMap { $0 }, isNetworkReachable: isNetworkReachable, deviceCheck: deviceCheck, tunnelRelay: selectorResult?.packetTunnelRelay @@ -186,7 +189,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { message: "Failed to read tunnel configuration when starting the tunnel." ) - completionHandler(error) + tunnelProviderError = .readConfiguration + + startEmptyTunnel(completionHandler: completionHandler) return } @@ -223,6 +228,34 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { } } + private func startEmptyTunnel(completionHandler: @escaping (Error?) -> Void) { + let emptyTunnelConfiguration = TunnelConfiguration( + name: nil, + interface: InterfaceConfiguration(privateKey: PrivateKey()), + peers: [] + ) + + adapter.start(tunnelConfiguration: emptyTunnelConfiguration) { error in + self.dispatchQueue.async { + if let error = error { + self.providerLogger.error( + error: error, + message: "Failed to start an empty tunnel." + ) + + completionHandler(error) + } else { + self.providerLogger.debug("Started an empty tunnel.") + + self.startTunnelCompletionHandler = { [weak self] in + self?.isConnected = true + completionHandler(nil) + } + } + } + } + } + override func stopTunnel( with reason: NEProviderStopReason, completionHandler: @escaping () -> Void @@ -411,8 +444,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { private func makeConfiguration(_ nextRelay: NextRelay) throws -> PacketTunnelConfiguration { - let deviceState = try SettingsManager.readDeviceState() let tunnelSettings = try SettingsManager.readSettings() + let deviceState = try SettingsManager.readDeviceState() + + tunnelProviderError = nil + let selectorResult: RelaySelectorResult switch nextRelay { @@ -459,7 +495,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { adapter.update(tunnelConfiguration: tunnelConfiguration.wgTunnelConfig) { error in self.dispatchQueue.async { - self.lastError = error + if let error = error { + let wrappedError: PacketTunnelErrorWrapper = .wireguard( + error: error.localizedDescription + ) + + self.wgError = wrappedError + } if let error = error { self.providerLogger.error( |
