diff options
| author | Emīls <emils@mullvad.net> | 2023-04-19 11:08:52 +0100 |
|---|---|---|
| committer | Emīls <emils@mullvad.net> | 2023-05-22 10:18:27 +0200 |
| commit | e5b73d7abc1b50cfbb9c6f056bf66fef28fef5b2 (patch) | |
| tree | 4e0c6cf3336c69c1c97b0640d5c06bc27819594c /ios/MullvadVPN | |
| parent | 77f51e690b26346ff4b251c27eb2ece493820d85 (diff) | |
| download | mullvadvpn-e5b73d7abc1b50cfbb9c6f056bf66fef28fef5b2.tar.xz mullvadvpn-e5b73d7abc1b50cfbb9c6f056bf66fef28fef5b2.zip | |
Add shadowsocks-proxy crate
Diffstat (limited to 'ios/MullvadVPN')
5 files changed, 127 insertions, 15 deletions
diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 26ac51cccf..69af7faa45 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -59,9 +59,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD ) proxyFactory = REST.ProxyFactory.makeProxyFactory( - transportProvider: { [weak self] in - return self?.transportMonitor.transport - }, + transportProvider: { [weak self] in self?.transportMonitor }, addressCache: addressCache ) @@ -70,6 +68,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD devicesProxy = proxyFactory.createDevicesProxy() relayCacheTracker = RelayCacheTracker(application: application, apiProxy: apiProxy) + addressCacheTracker = AddressCacheTracker( application: application, apiProxy: apiProxy, @@ -93,7 +92,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD accountsProxy: accountsProxy ) - transportMonitor = TransportMonitor(tunnelManager: tunnelManager, tunnelStore: tunnelStore) + transportMonitor = TransportMonitor( + tunnelManager: tunnelManager, + tunnelStore: tunnelStore, + relayCacheTracker: relayCacheTracker + ) #if targetEnvironment(simulator) // Configure mock tunnel provider on simulator diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift index 7d2331b92d..2078646be2 100644 --- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift @@ -21,15 +21,22 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { private var selectorResult: RelaySelectorResult? private let urlRequestProxy: URLRequestProxy private let relayCacheTracker: RelayCacheTracker + private let simulatorTransportProvider: SimulatorTunnelTransportProvider private let providerLogger = Logger(label: "SimulatorTunnelProviderHost") private let dispatchQueue = DispatchQueue(label: "SimulatorTunnelProviderHostQueue") init(relayCacheTracker: RelayCacheTracker) { self.relayCacheTracker = relayCacheTracker + + let urlSession = REST.makeURLSession() + let urlSessionTransport = REST.URLSessionTransport(urlSession: urlSession) + let simulatorTransportProvider = SimulatorTunnelTransportProvider(urlSessionTransport: urlSessionTransport) + self.simulatorTransportProvider = simulatorTransportProvider + self.urlRequestProxy = URLRequestProxy( - urlSession: REST.makeURLSession(), - dispatchQueue: dispatchQueue + dispatchQueue: dispatchQueue, + transportProvider: { simulatorTransportProvider } ) } diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift new file mode 100644 index 0000000000..a571101e3f --- /dev/null +++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift @@ -0,0 +1,26 @@ +// +// SimulatorTunnelTransportProvider.swift +// MullvadVPN +// +// Created by Marco Nikic on 2023-05-10. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadREST + +final class SimulatorTunnelTransportProvider: RESTTransportProvider { + private let urlSessionTransport: REST.URLSessionTransport + + init(urlSessionTransport: REST.URLSessionTransport) { + self.urlSessionTransport = urlSessionTransport + } + + func transport() -> MullvadREST.RESTTransport? { + urlSessionTransport + } + + func shadowSocksTransport() -> MullvadREST.RESTTransport? { + urlSessionTransport + } +} diff --git a/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift b/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift index 4ee628751d..3314fc3823 100644 --- a/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift +++ b/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift @@ -18,16 +18,28 @@ struct PacketTunnelTransport: RESTTransport { } let tunnel: Tunnel + let useShadowsocksTransport: Bool - init(tunnel: Tunnel) { + init(tunnel: Tunnel, useShadowsocksTransport: Bool) { self.tunnel = tunnel + self.useShadowsocksTransport = useShadowsocksTransport } func sendRequest( _ request: URLRequest, completion: @escaping (Data?, URLResponse?, Error?) -> Void - ) throws -> Cancellable { - let proxyRequest = try ProxyURLRequest(id: UUID(), urlRequest: request) + ) -> Cancellable { + let proxyRequest = ProxyURLRequest( + id: UUID(), + urlRequest: request, + useShadowsocksTransport: useShadowsocksTransport + ) + + // If the URL provided to the proxy request was invalid, indicate failure via `.badURL` and return a no-op. + guard let proxyRequest = proxyRequest else { + completion(nil, nil, URLError(.badURL)) + return AnyCancellable {} + } return tunnel.sendRequest(proxyRequest) { result in switch result { diff --git a/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift b/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift index 9f02429348..e37c416682 100644 --- a/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift +++ b/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift @@ -7,21 +7,83 @@ // import Foundation +import MullvadLogging import MullvadREST +import RelayCache +import RelaySelector -final class TransportMonitor { +final class TransportMonitor: RESTTransportProvider { private let tunnelManager: TunnelManager private let tunnelStore: TunnelStore private let urlSessionTransport: REST.URLSessionTransport + private let relayCacheTracker: RelayCacheTracker + private let logger = Logger(label: "TransportMonitor") - init(tunnelManager: TunnelManager, tunnelStore: TunnelStore) { + // MARK: - + + // MARK: Public API + + init(tunnelManager: TunnelManager, tunnelStore: TunnelStore, relayCacheTracker: RelayCacheTracker) { self.tunnelManager = tunnelManager self.tunnelStore = tunnelStore + self.relayCacheTracker = relayCacheTracker urlSessionTransport = REST.URLSessionTransport(urlSession: REST.makeURLSession()) } - var transport: RESTTransport? { + public func transport() -> MullvadREST.RESTTransport? { + return selectTransport(urlSessionTransport, useShadowsocksTransport: false) + } + + public func shadowSocksTransport() -> RESTTransport? { + let shadowSocksTransport: RESTTransport + do { + let cachedRelays = try relayCacheTracker.getCachedRelays() + + let shadowSocksConfiguration = RelaySelector.getShadowsocksTCPBridge(relays: cachedRelays.relays) + let shadowSocksBridgeRelay = RelaySelector.getShadowSocksRelay(relays: cachedRelays.relays) + + guard let shadowSocksConfiguration = shadowSocksConfiguration, + let shadowSocksBridgeRelay = shadowSocksBridgeRelay + else { + logger.error("Could not get shadow socks bridge information.") + return nil + } + + let shadowSocksURLSession = urlSessionTransport.urlSession + let transport = REST.URLSessionShadowSocksTransport( + urlSession: shadowSocksURLSession, + shadowSocksConfiguration: shadowSocksConfiguration, + shadowSocksBridgeRelay: shadowSocksBridgeRelay + ) + + shadowSocksTransport = transport + } catch { + logger.error( + error: error, + message: "Could not create shadow socks transport." + ) + return nil + } + return selectTransport(shadowSocksTransport, useShadowsocksTransport: true) + } + + // MARK: - + + // MARK: Private API + + /// Selects a transport to use for sending an `URLRequest` + /// + /// This method returns the appropriate transport layer based on whether a tunnel is available, and whether it + /// should be bypassed + /// whenever a transport is requested. + /// + /// - Parameters: + /// - transport: The transport to use if there is no tunnel, or if it shouldn't be bypassed + /// - useShadowsocksTransport: A hint for enforcing a Shadowsocks transport when proxying a request via an + /// available `Tunnel` + /// - Returns: A transport to use for sending an `URLRequest` + private func selectTransport(_ transport: RESTTransport, useShadowsocksTransport: Bool) -> RESTTransport { let tunnel = tunnelStore.getPersistentTunnels().first { tunnel in return tunnel.status == .connecting || tunnel.status == .reasserting || @@ -29,10 +91,12 @@ final class TransportMonitor { } if let tunnel = tunnel, shouldByPassVPN(tunnel: tunnel) { - return PacketTunnelTransport(tunnel: tunnel) - } else { - return urlSessionTransport + return PacketTunnelTransport( + tunnel: tunnel, + useShadowsocksTransport: useShadowsocksTransport + ) } + return transport } private func shouldByPassVPN(tunnel: Tunnel) -> Bool { |
