diff options
Diffstat (limited to 'ios')
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/SimulatorTunnelProviderHost.swift | 50 | ||||
| -rw-r--r-- | ios/PacketTunnel/PacketTunnelProvider.swift | 57 | ||||
| -rw-r--r-- | ios/TunnelProviderMessaging/URLRequestProxy.swift | 72 |
4 files changed, 113 insertions, 70 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 44ab78144f..caab716d84 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -305,6 +305,7 @@ 58D22422294C921B0029F5F8 /* MullvadLogging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58D223F3294C8FF00029F5F8 /* MullvadLogging.framework */; }; 58D22426294C92750029F5F8 /* MullvadTypes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58D223D5294C8E5E0029F5F8 /* MullvadTypes.framework */; platformFilter = ios; }; 58D22435294C975B0029F5F8 /* Operations.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58D223A5294C8A480029F5F8 /* Operations.framework */; platformFilter = ios; }; + 58D229B8298D1FE200BB5A2D /* URLRequestProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D229B6298D1D5200BB5A2D /* URLRequestProxy.swift */; }; 58DF28A52417CB4B00E836B0 /* StorePaymentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DF28A42417CB4B00E836B0 /* StorePaymentManager.swift */; }; 58E0729D28814AAE008902F8 /* PacketTunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E0729C28814AAE008902F8 /* PacketTunnelConfiguration.swift */; }; 58E0729F28814ACC008902F8 /* WireGuardLogLevel+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E0729E28814ACC008902F8 /* WireGuardLogLevel+Logging.swift */; }; @@ -854,6 +855,7 @@ 58D223D7294C8E5E0029F5F8 /* MullvadTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MullvadTypes.h; sourceTree = "<group>"; }; 58D223F3294C8FF00029F5F8 /* MullvadLogging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MullvadLogging.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 58D223F5294C8FF00029F5F8 /* MullvadLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MullvadLogging.h; sourceTree = "<group>"; }; + 58D229B6298D1D5200BB5A2D /* URLRequestProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLRequestProxy.swift; sourceTree = "<group>"; }; 58DF28A42417CB4B00E836B0 /* StorePaymentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentManager.swift; sourceTree = "<group>"; }; 58DF5B732851FF3F00E92647 /* InputOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputOperation.swift; sourceTree = "<group>"; }; 58DF5B752852108E00E92647 /* InputInjectionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputInjectionBuilder.swift; sourceTree = "<group>"; }; @@ -1244,6 +1246,7 @@ 5898D2AD290185D200EB5EBA /* ProxyURLResponse.swift */, 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */, 5898D2A7290182B000EB5EBA /* TunnelProviderReply.swift */, + 58D229B6298D1D5200BB5A2D /* URLRequestProxy.swift */, ); path = TunnelProviderMessaging; sourceTree = "<group>"; @@ -2228,6 +2231,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 58D229B8298D1FE200BB5A2D /* URLRequestProxy.swift in Sources */, 5898D29129017C3100EB5EBA /* TunnelProviderMessage.swift in Sources */, 5898D29029017BEE00EB5EBA /* PacketTunnelOptions.swift in Sources */, 5898D2AE290185D200EB5EBA /* ProxyURLResponse.swift in Sources */, diff --git a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift index 1ddf7b295f..3841a3bd8b 100644 --- a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift @@ -19,8 +19,7 @@ import TunnelProviderMessaging final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { private var selectorResult: RelaySelectorResult? - private let urlSession = REST.makeURLSession() - private var proxiedRequests = [UUID: URLSessionDataTask]() + private let urlRequestProxy: URLRequestProxy private let relayCacheTracker: RelayCacheTracker private let providerLogger = Logger(label: "SimulatorTunnelProviderHost") @@ -28,6 +27,10 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { init(relayCacheTracker: RelayCacheTracker) { self.relayCacheTracker = relayCacheTracker + self.urlRequestProxy = URLRequestProxy( + urlSession: REST.makeURLSession(), + dispatchQueue: dispatchQueue + ) } override func startTunnel( @@ -123,40 +126,21 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { completionHandler?(nil) case let .sendURLRequest(proxyRequest): - let task = urlSession - .dataTask(with: proxyRequest.urlRequest) { [weak self] data, response, error in - guard let self = self else { return } - - self.dispatchQueue.async { - self.proxiedRequests.removeValue(forKey: proxyRequest.id) - - var reply: Data? - do { - let proxyResponse = ProxyURLResponse( - data: data, - response: response, - error: error - ) - reply = try TunnelProviderReply(proxyResponse).encode() - } catch { - self.providerLogger.error( - error: error, - message: "Failed to encode ProxyURLResponse." - ) - } - - completionHandler?(reply) - } + urlRequestProxy.sendRequest(proxyRequest) { response in + var reply: Data? + do { + reply = try TunnelProviderReply(response).encode() + } catch { + self.providerLogger.error( + error: error, + message: "Failed to encode ProxyURLResponse." + ) } - - proxiedRequests[proxyRequest.id] = task - - task.resume() + completionHandler?(reply) + } case let .cancelURLRequest(id): - let task = proxiedRequests.removeValue(forKey: id) - - task?.cancel() + urlRequestProxy.cancelRequest(identifier: id) completionHandler?(nil) } diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift index b8382e6f3f..9de2504487 100644 --- a/ios/PacketTunnel/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider.swift @@ -64,12 +64,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { /// Current selector result. private var selectorResult: RelaySelectorResult? - /// URL session used for proxy requests. - private let urlSession = REST.makeURLSession() - - /// List of all proxied network requests bypassing VPN. - private var proxiedRequests: [UUID: URLSessionDataTask] = [:] - /// A system completion handler passed from startTunnel and saved for later use once the /// connection is established. private var startTunnelCompletionHandler: (() -> Void)? @@ -77,6 +71,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { /// Tunnel monitor. private var tunnelMonitor: TunnelMonitor! + /// Request proxy used to perform URLRequests bypassing VPN. + private let urlRequestProxy: URLRequestProxy + /// Account data request proxy private let accountsProxy: REST.AccountsProxy @@ -130,6 +127,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { securityGroupIdentifier: ApplicationConfiguration.securityGroupIdentifier, isReadOnly: true )! + + let urlSession = REST.makeURLSession() let urlSessionTransport = REST.URLSessionTransport(urlSession: urlSession) let proxyFactory = REST.ProxyFactory.makeProxyFactory( transportProvider: { () -> RESTTransport? in @@ -137,6 +136,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { }, addressCache: addressCache ) + + urlRequestProxy = URLRequestProxy(urlSession: urlSession, dispatchQueue: dispatchQueue) accountsProxy = proxyFactory.createAccountsProxy() devicesProxy = proxyFactory.createDevicesProxy() @@ -314,40 +315,22 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { completionHandler?(response) case let .sendURLRequest(proxyRequest): - let task = self.urlSession - .dataTask(with: proxyRequest.urlRequest) { [weak self] data, response, error in - guard let self = self else { return } - - self.dispatchQueue.async { - self.proxiedRequests.removeValue(forKey: proxyRequest.id) - - var reply: Data? - do { - let response = ProxyURLResponse( - data: data, - response: response, - error: error - ) - reply = try TunnelProviderReply(response).encode() - } catch { - self.providerLogger.error( - error: error, - message: "Failed to encode ProxyURLResponse." - ) - } - - completionHandler?(reply) - } + self.urlRequestProxy.sendRequest(proxyRequest) { response in + var reply: Data? + do { + reply = try TunnelProviderReply(response).encode() + } catch { + self.providerLogger.error( + error: error, + message: "Failed to encode ProxyURLResponse." + ) } - - self.proxiedRequests[proxyRequest.id] = task - - task.resume() + completionHandler?(reply) + } case let .cancelURLRequest(id): - let task = self.proxiedRequests.removeValue(forKey: id) - - task?.cancel() + self.urlRequestProxy.cancelRequest(identifier: id) + completionHandler?(nil) } } } diff --git a/ios/TunnelProviderMessaging/URLRequestProxy.swift b/ios/TunnelProviderMessaging/URLRequestProxy.swift new file mode 100644 index 0000000000..8d66819ebb --- /dev/null +++ b/ios/TunnelProviderMessaging/URLRequestProxy.swift @@ -0,0 +1,72 @@ +// +// URLRequestProxy.swift +// PacketTunnel +// +// Created by pronebird on 03/02/2023. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public final class URLRequestProxy { + /// Serial queue used for synchronizing access to class members. + private let dispatchQueue: DispatchQueue + + /// URL session used for proxy requests. + private let urlSession: URLSession + + /// List of all proxied network requests bypassing VPN. + private var proxiedRequests: [UUID: URLSessionDataTask] = [:] + + public init(urlSession: URLSession, dispatchQueue: DispatchQueue) { + self.urlSession = urlSession + self.dispatchQueue = dispatchQueue + } + + public func sendRequest( + _ proxyRequest: ProxyURLRequest, + completionHandler: @escaping (ProxyURLResponse) -> Void + ) { + dispatchQueue.async { + let task = self.urlSession + .dataTask(with: proxyRequest.urlRequest) { [weak self] data, response, error in + guard let self = self else { return } + + self.dispatchQueue.async { + let response = ProxyURLResponse( + data: data, + response: response, + error: error + ) + + _ = self.removeRequest(identifier: proxyRequest.id) + + completionHandler(response) + } + } + + // All tasks should have unique identifiers, but if not, cancel the task scheduled + // earlier. + let oldTask = self.addRequest(identifier: proxyRequest.id, task: task) + oldTask?.cancel() + + task.resume() + } + } + + public func cancelRequest(identifier: UUID) { + dispatchQueue.async { + let task = self.removeRequest(identifier: identifier) + + task?.cancel() + } + } + + private func addRequest(identifier: UUID, task: URLSessionDataTask) -> URLSessionDataTask? { + return proxiedRequests.updateValue(task, forKey: identifier) + } + + private func removeRequest(identifier: UUID) -> URLSessionDataTask? { + return proxiedRequests.removeValue(forKey: identifier) + } +} |
