summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ios/MullvadVPN/ConnectViewController.swift7
-rw-r--r--ios/MullvadVPN/TunnelManager.swift32
2 files changed, 34 insertions, 5 deletions
diff --git a/ios/MullvadVPN/ConnectViewController.swift b/ios/MullvadVPN/ConnectViewController.swift
index bef9afe4ed..a388c5e23f 100644
--- a/ios/MullvadVPN/ConnectViewController.swift
+++ b/ios/MullvadVPN/ConnectViewController.swift
@@ -145,7 +145,12 @@ class ConnectViewController: UIViewController, RootContainment, TunnelControlVie
startStopTunnelSubscriber = TunnelManager.shared.stopTunnel()
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { (completion) in
- // no-op
+ if case .failure(let error) = completion {
+ os_log(.error, "Failed to stop the tunnel: %{public}s",
+ error.localizedDescription)
+
+ self.presentError(error, preferredStyle: .alert)
+ }
})
}
diff --git a/ios/MullvadVPN/TunnelManager.swift b/ios/MullvadVPN/TunnelManager.swift
index bc80d8b0c3..f90140491e 100644
--- a/ios/MullvadVPN/TunnelManager.swift
+++ b/ios/MullvadVPN/TunnelManager.swift
@@ -19,6 +19,9 @@ enum TunnelManagerError: Error {
/// A failure to start the tunnel
case startTunnel(StartTunnelError)
+ /// A failure to stop the tunnel
+ case stopTunnel(Error)
+
/// A failure to load the account with the assumption that it was already set up earlier
case loadTunnel(LoadTunnelError)
@@ -57,6 +60,9 @@ extension TunnelManagerError: LocalizedError {
case .startTunnel:
return NSLocalizedString("Cannot start the tunnel", comment: "")
+ case .stopTunnel:
+ return NSLocalizedString("Cannot stop the tunnel", comment: "")
+
default:
return nil
}
@@ -377,10 +383,22 @@ class TunnelManager {
}.eraseToAnyPublisher()
}
- func stopTunnel() -> AnyPublisher<(), Never> {
- MutuallyExclusive(exclusivityQueue: exclusivityQueue, executionQueue: executionQueue) { () -> Just<()> in
- self.tunnelProvider?.connection.stopVPNTunnel()
- return Just(())
+ func stopTunnel() -> AnyPublisher<(), TunnelManagerError> {
+ MutuallyExclusive(exclusivityQueue: exclusivityQueue, executionQueue: executionQueue) { () -> AnyPublisher<(), TunnelManagerError> in
+ if let tunnelProvider = self.tunnelProvider {
+ // Disable on-demand when turning off the tunnel to prevent the tunnel from coming
+ // back up
+ tunnelProvider.isOnDemandEnabled = false
+
+ return tunnelProvider.saveToPreferences()
+ .mapError { TunnelManagerError.stopTunnel($0) }
+ .map { _ -> () in
+ tunnelProvider.connection.stopVPNTunnel()
+ return ()
+ }.eraseToAnyPublisher()
+ } else {
+ return Result.Publisher(()).eraseToAnyPublisher()
+ }
}.eraseToAnyPublisher()
}
@@ -800,6 +818,12 @@ class TunnelManager {
passwordReference: passwordReference
)
+ // Enable on-demand VPN, always connect the tunnel when on Wi-Fi or cellular
+ let alwaysOnRule = NEOnDemandRuleConnect()
+ alwaysOnRule.interfaceTypeMatch = .any
+ tunnelProvider.onDemandRules = [alwaysOnRule]
+ tunnelProvider.isOnDemandEnabled = true
+
return tunnelProvider.saveToPreferences()
.mapError { SetupTunnelError.saveTunnel($0) }
.flatMap {