summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2021-03-17 13:27:59 +0100
committerAndrej Mihajlov <and@mullvad.net>2021-03-19 14:07:57 +0100
commit303573b7b6b882af8a09f46148781e9675376847 (patch)
treec31298cdf31b20111c22ad82775ced6e74ec81a6
parentcf005068637c57ac5500cb67cbf35734f724fc6a (diff)
downloadmullvadvpn-303573b7b6b882af8a09f46148781e9675376847.tar.xz
mullvadvpn-303573b7b6b882af8a09f46148781e9675376847.zip
SimulatorTunnelProviderHost: pick the actual tunnel based on relay constraints
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj6
-rw-r--r--ios/MullvadVPN/Operations/OperationObserver.swift1
-rw-r--r--ios/MullvadVPN/Operations/TransformOperationObserver.swift6
-rw-r--r--ios/MullvadVPN/RelaySelector.swift11
-rw-r--r--ios/MullvadVPN/SimulatorTunnelProvider.swift72
-rw-r--r--ios/MullvadVPN/SimulatorTunnelProviderHost.swift87
-rw-r--r--ios/PacketTunnel/PacketTunnelProvider.swift11
7 files changed, 156 insertions, 38 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 25de8e2f1b..1a591c36f9 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -151,6 +151,7 @@
58B0A2AA238EE6A900BC001D /* RelaySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CD422AFBA39009B9D8E /* RelaySelector.swift */; };
58B0A2AC238EE6D500BC001D /* IPAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IPAddress+Codable.swift */; };
58B0A2AD238EE6EC00BC001D /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; };
+ 58B67B482602079E008EF58E /* RelaySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CD422AFBA39009B9D8E /* RelaySelector.swift */; };
58B8743222B25A7600015324 /* WireguardAssociatedAddresses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */; };
58B8743B22B788D200015324 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743722B25EAB00015324 /* PacketTunnelSettingsGenerator.swift */; };
58B9814E24FEA70D00C0D59E /* WireguardKeysViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58B9814D24FEA70D00C0D59E /* WireguardKeysViewController.xib */; };
@@ -170,6 +171,8 @@
58C3B06724EA768100C0348E /* LogStreamerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C3B06624EA768100C0348E /* LogStreamerViewController.swift */; };
58C3B06924EAA25000C0348E /* StringStreamIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C3B06824EAA25000C0348E /* StringStreamIterator.swift */; };
58C4CB0124EBE5A700A22D49 /* LogEntryParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C4CB0024EBE5A700A22D49 /* LogEntryParser.swift */; };
+ 58CAF4EA26025927007C5886 /* PacketTunnelIpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */; };
+ 58CAF4EF26025954007C5886 /* SimulatorTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BA693023EADA6A009DC256 /* SimulatorTunnelProvider.swift */; };
58CB0EE024B86751001EF0D8 /* MullvadRest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58CB0EDF24B86751001EF0D8 /* MullvadRest.swift */; };
58CB0EE124B86751001EF0D8 /* MullvadRest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58CB0EDF24B86751001EF0D8 /* MullvadRest.swift */; };
58CC40EF24A601900019D96E /* ObserverList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58CC40EE24A601900019D96E /* ObserverList.swift */; };
@@ -905,6 +908,7 @@
5896AE81246ACE81005B36CB /* KeychainMatchLimit.swift in Sources */,
5896AE80246ACE79005B36CB /* KeychainClass.swift in Sources */,
582AE3132440CA2700E6733A /* AccountTokenInput.swift in Sources */,
+ 58CAF4EF26025954007C5886 /* SimulatorTunnelProvider.swift in Sources */,
5857F23724C8446400CF6F47 /* AssociatedValue.swift in Sources */,
5857F23B24C8448600CF6F47 /* OperationProtocol.swift in Sources */,
58B0A2AA238EE6A900BC001D /* RelaySelector.swift in Sources */,
@@ -928,6 +932,7 @@
5896AE7E246ACE65005B36CB /* KeychainAttributes.swift in Sources */,
58B0A2A9238EE6A100BC001D /* RelayConstraints.swift in Sources */,
5807E2C2243203D000F5FF30 /* StringTests.swift in Sources */,
+ 58CAF4EA26025927007C5886 /* PacketTunnelIpc.swift in Sources */,
5857F23E24C844A000CF6F47 /* OperationBlockObserver.swift in Sources */,
5857F23024C843ED00CF6F47 /* ChainedError.swift in Sources */,
58A8BE81239FBE62006B74AC /* IPEndpoint.swift in Sources */,
@@ -994,6 +999,7 @@
580EE20F24B322E700F9D8A1 /* TransformOperation.swift in Sources */,
58B8743222B25A7600015324 /* WireguardAssociatedAddresses.swift in Sources */,
5850368C25A49E2200A43E93 /* PrivateKeyWithMetadata.swift in Sources */,
+ 58B67B482602079E008EF58E /* RelaySelector.swift in Sources */,
58DF28A52417CB4B00E836B0 /* AppStorePaymentManager.swift in Sources */,
580EE22124B3240100F9D8A1 /* TransformOperationObserver.swift in Sources */,
582BB1AF229566420055B6EF /* SettingsCell.swift in Sources */,
diff --git a/ios/MullvadVPN/Operations/OperationObserver.swift b/ios/MullvadVPN/Operations/OperationObserver.swift
index 295b993a10..a7d3ea3aa3 100644
--- a/ios/MullvadVPN/Operations/OperationObserver.swift
+++ b/ios/MullvadVPN/Operations/OperationObserver.swift
@@ -11,6 +11,7 @@ import Foundation
protocol OperationObserver {
associatedtype OperationType: OperationProtocol
+ func operationWillExecute(_ operation: OperationType)
func operationWillFinish(_ operation: OperationType)
func operationDidFinish(_ operation: OperationType)
}
diff --git a/ios/MullvadVPN/Operations/TransformOperationObserver.swift b/ios/MullvadVPN/Operations/TransformOperationObserver.swift
index 48fbe02dbb..e6ed695e0b 100644
--- a/ios/MullvadVPN/Operations/TransformOperationObserver.swift
+++ b/ios/MullvadVPN/Operations/TransformOperationObserver.swift
@@ -11,14 +11,20 @@ import Foundation
/// A private type erasing observer that type casts the input operation type to the expected
/// operation type before calling the wrapped observer
class TransformOperationObserver<S: OperationProtocol>: OperationObserver {
+ private let willExecute: (S) -> Void
private let willFinish: (S) -> Void
private let didFinish: (S) -> Void
init<T: OperationObserver>(_ observer: T) {
+ willExecute = Self.wrap(observer.operationWillExecute)
willFinish = Self.wrap(observer.operationWillFinish)
didFinish = Self.wrap(observer.operationDidFinish)
}
+ func operationWillExecute(_ operation: S) {
+ willExecute(operation)
+ }
+
func operationWillFinish(_ operation: S) {
willFinish(operation)
}
diff --git a/ios/MullvadVPN/RelaySelector.swift b/ios/MullvadVPN/RelaySelector.swift
index baf0595518..da1074452c 100644
--- a/ios/MullvadVPN/RelaySelector.swift
+++ b/ios/MullvadVPN/RelaySelector.swift
@@ -20,6 +20,17 @@ private struct RelayWithLocation {
var location: Location
}
+extension RelaySelectorResult {
+ var tunnelConnectionInfo: TunnelConnectionInfo {
+ return TunnelConnectionInfo(
+ ipv4Relay: self.endpoint.ipv4Relay,
+ ipv6Relay: self.endpoint.ipv6Relay,
+ hostname: self.relay.hostname,
+ location: self.location
+ )
+ }
+}
+
struct RelaySelector {
private let relays: ServerRelaysResponse
diff --git a/ios/MullvadVPN/SimulatorTunnelProvider.swift b/ios/MullvadVPN/SimulatorTunnelProvider.swift
index 6844dd9921..98b51dda34 100644
--- a/ios/MullvadVPN/SimulatorTunnelProvider.swift
+++ b/ios/MullvadVPN/SimulatorTunnelProvider.swift
@@ -50,10 +50,33 @@ extension NETunnelProviderManager: VPNTunnelProviderManagerProtocol {}
// MARK: - NEPacketTunnelProvider stubs
-protocol SimulatorTunnelProviderDelegate {
- func startTunnel(options: [String: Any]?, completionHandler: @escaping (Error?) -> Void)
- func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void)
- func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?)
+class SimulatorTunnelProviderDelegate {
+ fileprivate(set) var connection: SimulatorVPNConnection?
+
+ var protocolConfiguration: NEVPNProtocol {
+ return connection?.protocolConfiguration ?? NEVPNProtocol()
+ }
+
+ var reasserting: Bool {
+ get {
+ return connection?.reasserting ?? false
+ }
+ set {
+ connection?.reasserting = newValue
+ }
+ }
+
+ func startTunnel(options: [String: Any]?, completionHandler: @escaping (Error?) -> Void) {
+ completionHandler(nil)
+ }
+
+ func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
+ completionHandler()
+ }
+
+ func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
+ completionHandler?(nil)
+ }
}
class SimulatorTunnelProvider {
@@ -84,6 +107,9 @@ class SimulatorTunnelProvider {
class SimulatorVPNConnection: NSObject, VPNConnectionProtocol {
+ // Protocol configuration is automatically synced by `SimulatorTunnelInfo`
+ fileprivate var protocolConfiguration = NEVPNProtocol()
+
private let lock = NSRecursiveLock()
private var _status: NEVPNStatus = .disconnected
@@ -104,11 +130,36 @@ class SimulatorVPNConnection: NSObject, VPNConnectionProtocol {
}
}
+ private var statusBeforeReasserting: NEVPNStatus?
+ private var _reasserting = false
+ var reasserting: Bool {
+ get {
+ lock.withCriticalBlock { _reasserting }
+ }
+ set {
+ lock.withCriticalBlock {
+ if newValue != _reasserting {
+ _reasserting = newValue
+
+ if newValue {
+ statusBeforeReasserting = status
+ status = .reasserting
+ } else if let newStatus = statusBeforeReasserting {
+ status = newStatus
+ statusBeforeReasserting = nil
+ }
+ }
+ }
+ }
+ }
+
func startVPNTunnel() throws {
try startVPNTunnel(options: nil)
}
func startVPNTunnel(options: [String: NSObject]?) throws {
+ SimulatorTunnelProvider.shared.delegate.connection = self
+
status = .connecting
SimulatorTunnelProvider.shared.delegate.startTunnel(options: options) { (error) in
@@ -165,10 +216,17 @@ private struct SimulatorTunnelInfo {
var onDemandRules = [NEOnDemandRule]()
/// Protocol configuration
- var protocolConfiguration: NEVPNProtocol?
+ var protocolConfiguration: NEVPNProtocol? {
+ didSet {
+ self.connection.protocolConfiguration = protocolConfiguration ?? NEVPNProtocol()
+ }
+ }
/// Tunnel description
var localizedDescription: String?
+
+ /// Designated initializer
+ init() {}
}
class SimulatorTunnelProviderManager: VPNTunnelProviderManagerProtocol, Equatable {
@@ -245,8 +303,8 @@ class SimulatorTunnelProviderManager: VPNTunnelProviderManagerProtocol, Equatabl
}
}
- required init() {
- self.tunnelInfo = SimulatorTunnelInfo()
+ required convenience init() {
+ self.init(tunnelInfo: SimulatorTunnelInfo())
}
private init(tunnelInfo: SimulatorTunnelInfo) {
diff --git a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift
index 0f31e5d882..37ac1f38f3 100644
--- a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift
+++ b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift
@@ -15,30 +15,25 @@ import Logging
class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
+ private enum ExclusivityCategory {
+ case exclusive
+ }
+
private var connectionInfo: TunnelConnectionInfo?
private let logger = Logger(label: "SimulatorTunnelProviderHost")
- func startTunnel(options: [String: Any]?, completionHandler: @escaping (Error?) -> Void) {
- DispatchQueue.main.async {
- self.connectionInfo = TunnelConnectionInfo(
- ipv4Relay: IPv4Endpoint(ip: IPv4Address("10.0.0.1")!, port: 53),
- ipv6Relay: nil,
- hostname: "au4-wireguard",
- location: Location(
- country: "Australia",
- countryCode: "au",
- city: "Melbourne",
- cityCode: "mel",
- latitude: -37.815018,
- longitude: 144.946014
- )
- )
+ private let operationQueue = OperationQueue()
+ private lazy var exclusivityController = ExclusivityController<ExclusivityCategory>(operationQueue: operationQueue)
+ override func startTunnel(options: [String: Any]?, completionHandler: @escaping (Error?) -> Void) {
+ let startOperation = makeStartOperation()
+ startOperation.addDidFinishBlockObserver(queue: .main) { _ in
completionHandler(nil)
}
+ exclusivityController.addOperation(startOperation, categories: [.exclusive])
}
- func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
+ override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
DispatchQueue.main.async {
self.connectionInfo = nil
@@ -46,14 +41,28 @@ class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
}
}
- func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
+ override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
DispatchQueue.main.async {
let result = PacketTunnelIpcHandler.decodeRequest(messageData: messageData)
switch result {
case .success(let request):
switch request {
case .reloadTunnelSettings:
- self.replyAppMessage(true, completionHandler: completionHandler)
+ let operationObserver = OperationBlockObserver<AsyncBlockOperation>(
+ queue: .main,
+ willExecute: { _ in
+ self.reasserting = true
+ },
+ willFinish: { _ in
+ self.reasserting = false
+ },
+ didFinish: { _ in
+ self.replyAppMessage(true, completionHandler: completionHandler)
+ })
+
+ let startOperation = self.makeStartOperation()
+ startOperation.addObserver(operationObserver)
+ self.exclusivityController.addOperation(startOperation, categories: [.exclusive])
case .tunnelInformation:
self.replyAppMessage(self.connectionInfo, completionHandler: completionHandler)
@@ -65,8 +74,7 @@ class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
}
}
- private func replyAppMessage<T: Codable>(_ response: T, completionHandler: ((Data?) -> Void)?)
- {
+ private func replyAppMessage<T: Codable>(_ response: T, completionHandler: ((Data?) -> Void)?) {
switch PacketTunnelIpcHandler.encodeResponse(response: response) {
case .success(let data):
completionHandler?(data)
@@ -77,6 +85,45 @@ class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
}
}
+ private func makeStartOperation() -> AsyncBlockOperation {
+ return AsyncBlockOperation { [weak self] (finish) in
+ guard let self = self else {
+ finish()
+ return
+ }
+
+ self.pickRelay { (selectorResult) in
+ DispatchQueue.main.async {
+ self.connectionInfo = selectorResult?.tunnelConnectionInfo
+ finish()
+ }
+ }
+ }
+ }
+
+ private func pickRelay(completion: @escaping (RelaySelectorResult?) -> Void) {
+ RelayCache.shared.read { (result) in
+ switch result {
+ case .success(let cachedRelays):
+ let keychainReference = self.protocolConfiguration.passwordReference!
+ switch TunnelSettingsManager.load(searchTerm: .persistentReference(keychainReference)) {
+ case .success(let entry):
+ let relayConstraints = entry.tunnelSettings.relayConstraints
+ let relaySelector = RelaySelector(relays: cachedRelays.relays)
+ let selectorResult = relaySelector.evaluate(with: relayConstraints)
+ completion(selectorResult)
+
+ case .failure(let error):
+ self.logger.error(chainedError: error)
+ completion(nil)
+ }
+ case .failure(let error):
+ self.logger.error(chainedError: error)
+ completion(nil)
+ }
+ }
+ }
+
}
#endif
diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift
index 28af108148..8e12bdb9f7 100644
--- a/ios/PacketTunnel/PacketTunnelProvider.swift
+++ b/ios/PacketTunnel/PacketTunnelProvider.swift
@@ -539,17 +539,6 @@ extension PacketTunnelState: CustomStringConvertible, CustomDebugStringConvertib
}
}
-extension RelaySelectorResult {
- var tunnelConnectionInfo: TunnelConnectionInfo {
- return TunnelConnectionInfo(
- ipv4Relay: self.endpoint.ipv4Relay,
- ipv6Relay: self.endpoint.ipv6Relay,
- hostname: self.relay.hostname,
- location: self.location
- )
- }
-}
-
extension WireGuardLogLevel {
var loggerLevel: Logger.Level {
switch self {