summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2023-04-19 11:08:52 +0100
committerEmīls <emils@mullvad.net>2023-05-22 10:18:27 +0200
commite5b73d7abc1b50cfbb9c6f056bf66fef28fef5b2 (patch)
tree4e0c6cf3336c69c1c97b0640d5c06bc27819594c /ios/MullvadVPN
parent77f51e690b26346ff4b251c27eb2ece493820d85 (diff)
downloadmullvadvpn-e5b73d7abc1b50cfbb9c6f056bf66fef28fef5b2.tar.xz
mullvadvpn-e5b73d7abc1b50cfbb9c6f056bf66fef28fef5b2.zip
Add shadowsocks-proxy crate
Diffstat (limited to 'ios/MullvadVPN')
-rw-r--r--ios/MullvadVPN/AppDelegate.swift11
-rw-r--r--ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift11
-rw-r--r--ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift26
-rw-r--r--ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift18
-rw-r--r--ios/MullvadVPN/TransportMonitor/TransportMonitor.swift76
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 {