summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2024-09-26 17:10:35 +0200
committerEmīls <emils@mullvad.net>2024-09-26 17:10:35 +0200
commit5266cd4827418b0e6cfb62c174884406afa4c2a8 (patch)
tree2adb34d22cf7dd1cb183e975fbd262b2ac60f44b
parentefabf7f31f512d48e5010d1246287a68704cada6 (diff)
parent65c1c0148a05a0d8e6b62a34a5815431ff719f64 (diff)
downloadmullvadvpn-5266cd4827418b0e6cfb62c174884406afa4c2a8.tar.xz
mullvadvpn-5266cd4827418b0e6cfb62c174884406afa4c2a8.zip
Merge branch 'use-encrypted-dns-proxy-code-in-mullvad-ios-ios-818'
-rw-r--r--ios/CHANGELOG.md6
-rw-r--r--ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift65
-rw-r--r--ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift2
-rw-r--r--ios/MullvadREST/Transport/TransportProvider.swift10
-rw-r--r--ios/MullvadRustRuntime/EncryptedDNSProxy.swift61
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj12
6 files changed, 142 insertions, 14 deletions
diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md
index 75dfa457c1..c3cc16472d 100644
--- a/ios/CHANGELOG.md
+++ b/ios/CHANGELOG.md
@@ -21,9 +21,13 @@ Line wrap the file at 100 chars. Th
* **Fixed**: for any bug fixes.
* **Security**: in case of vulnerabilities.
+## Unreleased
+### Added
+- Add a new access method that uses the encrypted DNS proxy to reach our API.
+
## [2024.7 - 2024-09-16]
### Added
-- Add DAITA (Defence against AI-guided Traffic Analysis) setting
+- Add DAITA (Defence against AI-guided Traffic Analysis) setting.
## [2024.6 - 2024.09-02]
### Fixed
diff --git a/ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift b/ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift
index e0b983d853..230743bdfa 100644
--- a/ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift
+++ b/ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift
@@ -16,21 +16,70 @@ public final class EncryptedDNSTransport: RESTTransport {
/// The `URLSession` used to send requests via `encryptedDNSProxy`
public let urlSession: URLSession
+ private let encryptedDnsProxy: EncryptedDNSProxy
+ private let dispatchQueue = DispatchQueue(label: "net.mullvad.EncryptedDNSTransport")
+ private var dnsProxyTask: URLSessionTask?
- public init(
- urlSession: URLSession,
- addressCache: REST.AddressCache
- ) {
+ public init(urlSession: URLSession) {
self.urlSession = urlSession
+ self.encryptedDnsProxy = EncryptedDNSProxy()
}
+ public func stop() {
+ dispatchQueue.async { [weak self] in
+ self?.encryptedDnsProxy.stop()
+ self?.dnsProxyTask = nil
+ }
+ }
+
+ /// Sends a request via the encrypted DNS proxy.
+ ///
+ /// Starting the proxy can take a very long time due to domain resolution
+ /// Cancellation will only take place if the data task was already started, at which point,
+ /// most of the time starting the DNS proxy was already spent.
public func sendRequest(
_ request: URLRequest,
completion: @escaping (Data?, URLResponse?, (any Error)?) -> Void
) -> any Cancellable {
- // TODO: Start proxy once the backend is integrated into the Swift code.
- let dataTask = urlSession.dataTask(with: request, completionHandler: completion)
- dataTask.resume()
- return dataTask
+ dispatchQueue.async { [weak self] in
+ guard let self else { return }
+ do {
+ try self.encryptedDnsProxy.start()
+ } catch {
+ completion(nil, nil, error)
+ return
+ }
+
+ var urlRequestCopy = request
+ urlRequestCopy.url = request.url.flatMap { url in
+ var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
+ components?.host = "127.0.0.1"
+ components?.port = Int(self.encryptedDnsProxy.localPort())
+ return components?.url
+ }
+
+ let wrappedCompletionHandler: (Data?, URLResponse?, (any Error)?)
+ -> Void = { [weak self] data, response, maybeError in
+ if maybeError != nil {
+ self?.encryptedDnsProxy.stop()
+ }
+ // Do not call the completion handler if the request was cancelled in flight
+ if let cancelledError = maybeError as? URLError, cancelledError.code == .cancelled {
+ return
+ }
+
+ completion(data, response, maybeError)
+ }
+
+ let dataTask = urlSession.dataTask(with: urlRequestCopy, completionHandler: wrappedCompletionHandler)
+ dataTask.resume()
+ dnsProxyTask = dataTask
+ }
+
+ return AnyCancellable { [weak self] in
+ self?.dispatchQueue.async {
+ self?.dnsProxyTask?.cancel()
+ }
+ }
}
}
diff --git a/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift b/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift
index b65edfa52a..57605d7af7 100644
--- a/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift
+++ b/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift
@@ -33,7 +33,7 @@ public class ProxyConfigurationTransportProvider {
addressCache: addressCache
)
case .encryptedDNS:
- return EncryptedDNSTransport(urlSession: urlSession, addressCache: addressCache)
+ return EncryptedDNSTransport(urlSession: urlSession)
case let .shadowsocks(shadowSocksConfiguration):
return ShadowsocksTransport(
urlSession: urlSession,
diff --git a/ios/MullvadREST/Transport/TransportProvider.swift b/ios/MullvadREST/Transport/TransportProvider.swift
index a102f61cd8..f527ae5fdc 100644
--- a/ios/MullvadREST/Transport/TransportProvider.swift
+++ b/ios/MullvadREST/Transport/TransportProvider.swift
@@ -17,6 +17,7 @@ public final class TransportProvider: RESTTransportProvider {
private var currentTransport: RESTTransport?
private var currentTransportType: TransportStrategy.Transport
private let parallelRequestsMutex = NSLock()
+ private let encryptedDNSTransport: EncryptedDNSTransport
public init(
urlSessionTransport: URLSessionTransport,
@@ -27,6 +28,7 @@ public final class TransportProvider: RESTTransportProvider {
self.addressCache = addressCache
self.transportStrategy = transportStrategy
self.currentTransportType = transportStrategy.connectionTransport()
+ self.encryptedDNSTransport = EncryptedDNSTransport(urlSession: urlSessionTransport.urlSession)
}
public func makeTransport() -> RESTTransport? {
@@ -53,6 +55,9 @@ public final class TransportProvider: RESTTransportProvider {
defer { parallelRequestsMutex.unlock() }
if strategy == transportStrategy {
+ if strategy.connectionTransport() == .encryptedDNS {
+ encryptedDNSTransport.stop()
+ }
transportStrategy.didFail()
currentTransport = nil
}
@@ -82,10 +87,7 @@ public final class TransportProvider: RESTTransportProvider {
addressCache: addressCache
)
case .encryptedDNS:
- currentTransport = EncryptedDNSTransport(
- urlSession: urlSessionTransport.urlSession,
- addressCache: addressCache
- )
+ currentTransport = encryptedDNSTransport
case .none:
currentTransport = nil
}
diff --git a/ios/MullvadRustRuntime/EncryptedDNSProxy.swift b/ios/MullvadRustRuntime/EncryptedDNSProxy.swift
new file mode 100644
index 0000000000..690e2459d0
--- /dev/null
+++ b/ios/MullvadRustRuntime/EncryptedDNSProxy.swift
@@ -0,0 +1,61 @@
+//
+// EncryptedDNSProxy.swift
+// MullvadRustRuntime
+//
+// Created by Emils on 24/09/2024.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import MullvadRustRuntimeProxy
+
+enum EncryptedDnsProxyError: Error {
+ case start(err: Int32)
+}
+
+public class EncryptedDNSProxy {
+ private var proxyConfig: ProxyHandle
+ private var stateLock = NSLock()
+ private var didStart = false
+ private let state: OpaquePointer
+
+ public init() {
+ state = encrypted_dns_proxy_init()
+ proxyConfig = ProxyHandle(context: nil, port: 0)
+ }
+
+ public func localPort() -> UInt16 {
+ stateLock.lock()
+ defer { stateLock.unlock() }
+ return proxyConfig.port
+ }
+
+ public func start() throws {
+ stateLock.lock()
+ defer { stateLock.unlock() }
+ guard didStart == false else { return }
+
+ let err = encrypted_dns_proxy_start(state, &proxyConfig)
+ if err != 0 {
+ throw EncryptedDnsProxyError.start(err: err)
+ }
+ didStart = true
+ }
+
+ public func stop() {
+ stateLock.lock()
+ defer { stateLock.unlock() }
+ guard didStart == true else { return }
+ didStart = false
+
+ encrypted_dns_proxy_stop(&proxyConfig)
+ }
+
+ deinit {
+ if didStart {
+ encrypted_dns_proxy_stop(&proxyConfig)
+ }
+
+ encrypted_dns_proxy_free(state)
+ }
+}
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 07fc35037a..ee362edf09 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ 014449952CA293B100C0C2F2 /* EncryptedDNSProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014449942CA293B100C0C2F2 /* EncryptedDNSProxy.swift */; };
01EF6F342B6A590700125696 /* libmullvad_api.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 01EF6F332B6A590700125696 /* libmullvad_api.a */; };
062B45A328FD4CA700746E77 /* le_root_cert.cer in Resources */ = {isa = PBXBuildFile; fileRef = 06799AB428F98CE700ACD94E /* le_root_cert.cer */; };
062B45BC28FD8C3B00746E77 /* RESTDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062B45BB28FD8C3B00746E77 /* RESTDefaults.swift */; };
@@ -1329,6 +1330,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 014449942CA293B100C0C2F2 /* EncryptedDNSProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedDNSProxy.swift; sourceTree = "<group>"; };
01EF6F2D2B6A51B100125696 /* mullvad-api.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "mullvad-api.h"; path = "../mullvad-api/include/mullvad-api.h"; sourceTree = "<group>"; };
01EF6F2F2B6A588300125696 /* aarch64-apple-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "aarch64-apple-ios"; path = "../target/aarch64-apple-ios"; sourceTree = "<group>"; };
01EF6F312B6A58F000125696 /* debug */ = {isa = PBXFileReference; lastKnownFileType = folder; name = debug; path = "../target/aarch64-apple-ios/debug"; sourceTree = "<group>"; };
@@ -2356,6 +2358,13 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 014449932CA1B55200C0C2F2 /* EncryptedDnsProxy */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ path = EncryptedDnsProxy;
+ sourceTree = "<group>";
+ };
062B45A228FD4C0F00746E77 /* Assets */ = {
isa = PBXGroup;
children = (
@@ -4026,6 +4035,7 @@
A9EB4F9C2B7FAB21002A2D7A /* EphemeralPeerNegotiator.swift */,
F0DDE40F2B220458006B57A7 /* ShadowSocksProxy.swift */,
584023212A406BF5007B27AC /* UDPOverTCPObfuscator.swift */,
+ 014449942CA293B100C0C2F2 /* EncryptedDNSProxy.swift */,
);
path = MullvadRustRuntime;
sourceTree = "<group>";
@@ -4177,6 +4187,7 @@
F0DC77A02B2223290087F09D /* Transport */ = {
isa = PBXGroup;
children = (
+ 014449932CA1B55200C0C2F2 /* EncryptedDnsProxy */,
F0164ED02B4F2DCB0020268D /* AccessMethodIterator.swift */,
F0DC77A32B2315800087F09D /* Direct */,
F0E5B2F62C9C689C0007F78C /* EncryptedDNS */,
@@ -6146,6 +6157,7 @@
buildActionMask = 2147483647;
files = (
A9D9A4B12C36D10E004088DD /* ShadowSocksProxy.swift in Sources */,
+ 014449952CA293B100C0C2F2 /* EncryptedDNSProxy.swift in Sources */,
A9D9A4BB2C36D397004088DD /* EphemeralPeerNegotiator.swift in Sources */,
A9D9A4B22C36D12D004088DD /* UDPOverTCPObfuscator.swift in Sources */,
A9173C322C36CCDD00F6A08C /* PacketTunnelProvider+TCPConnection.swift in Sources */,