diff options
Diffstat (limited to 'ios')
| -rw-r--r-- | ios/MullvadREST/ApiHandlers/AddressCache.swift | 2 | ||||
| -rw-r--r-- | ios/MullvadRESTTests/MullvadApiTests.swift | 4 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/MullvadAddressCacheProvider.swift | 31 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/MullvadApiContext.swift | 15 | ||||
| -rw-r--r-- | ios/MullvadRustRuntime/include/mullvad_rust_runtime.h | 36 | ||||
| -rw-r--r-- | ios/MullvadTypes/AddressCacheProviding.swift | 25 | ||||
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 8 | ||||
| -rw-r--r-- | ios/MullvadVPN/AppDelegate.swift | 3 | ||||
| -rw-r--r-- | ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift | 3 | ||||
| -rw-r--r-- | ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift | 3 |
10 files changed, 119 insertions, 11 deletions
diff --git a/ios/MullvadREST/ApiHandlers/AddressCache.swift b/ios/MullvadREST/ApiHandlers/AddressCache.swift index d098e91226..b75a515c01 100644 --- a/ios/MullvadREST/ApiHandlers/AddressCache.swift +++ b/ios/MullvadREST/ApiHandlers/AddressCache.swift @@ -11,7 +11,7 @@ import MullvadLogging import MullvadTypes extension REST { - public final class AddressCache: @unchecked Sendable { + public final class AddressCache: AddressCacheProviding, @unchecked Sendable { /// Logger. private let logger = Logger(label: "AddressCache") diff --git a/ios/MullvadRESTTests/MullvadApiTests.swift b/ios/MullvadRESTTests/MullvadApiTests.swift index 506c7240f8..64c0eb371b 100644 --- a/ios/MullvadRESTTests/MullvadApiTests.swift +++ b/ios/MullvadRESTTests/MullvadApiTests.swift @@ -18,6 +18,7 @@ import XCTest class MullvadApiTests: XCTestCase { let encoder = JSONEncoder() + let addressCache = REST.AddressCache(canWriteToCache: false, fileCache: MemoryCache()) func makeApiProxy(port: UInt16) throws -> APIQuerying { let shadowsocksLoader = ShadowsocksLoaderStub(configuration: ShadowsocksConfiguration( @@ -38,7 +39,8 @@ class MullvadApiTests: XCTestCase { accessMethodWrapper: initAccessMethodSettingsWrapper( methods: accessMethodsRepository .fetchAll() - ) + ), + addressCacheProvider: addressCache ) let proxy = REST.MullvadAPIProxy( diff --git a/ios/MullvadRustRuntime/MullvadAddressCacheProvider.swift b/ios/MullvadRustRuntime/MullvadAddressCacheProvider.swift new file mode 100644 index 0000000000..4c731eaf3a --- /dev/null +++ b/ios/MullvadRustRuntime/MullvadAddressCacheProvider.swift @@ -0,0 +1,31 @@ +// +// MullvadAddressCacheProvider.swift +// MullvadRustRuntime +// +// Created by Marco Nikic on 2025-05-15. +// Copyright © 2025 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadTypes + +public func iniSwiftAddressCacheWrapper(provider: DefaultAddressCacheProvider) -> SwiftAddressCacheWrapper { + let rawProvider = Unmanaged.passUnretained(provider).toOpaque() + return init_swift_address_cache_wrapper(rawProvider) +} + +@_cdecl("swift_get_cached_endpoint") +func getCacheEndpoint(rawAddressCacheProvider: UnsafeMutableRawPointer) -> UnsafePointer<CChar>! { + let addressCacheProvider = Unmanaged<DefaultAddressCacheProvider>.fromOpaque(rawAddressCacheProvider) + .takeUnretainedValue() + let cStr = addressCacheProvider.getCurrentEndpoint().description.toCStringPointer() + /** + `cStr` needs to shortly outlive the return of this function in order to get transformed into a `SocketAddr` + This is the simplest way to guarantee that the pointer returned does not get deallocated immediately + Or that no memory is leaked every time this function gets called + **/ + DispatchQueue(label: "com.MullvadRustRuntime.DecallocateQueue").async { + cStr?.deallocate() + } + return cStr +} diff --git a/ios/MullvadRustRuntime/MullvadApiContext.swift b/ios/MullvadRustRuntime/MullvadApiContext.swift index 5517348cc1..bd89ab891f 100644 --- a/ios/MullvadRustRuntime/MullvadApiContext.swift +++ b/ios/MullvadRustRuntime/MullvadApiContext.swift @@ -16,6 +16,8 @@ public struct MullvadApiContext: @unchecked Sendable { public let context: SwiftApiContext private let shadowsocksBridgeProvider: SwiftShadowsocksBridgeProviding! private let shadowsocksBridgeProviderWrapper: SwiftShadowsocksLoaderWrapper! + private let addressCacheWrapper: SwiftAddressCacheWrapper! + private let addressCacheProvider: AddressCacheProviding! public init( host: String, @@ -23,12 +25,17 @@ public struct MullvadApiContext: @unchecked Sendable { domain: String, disableTls: Bool = false, shadowsocksProvider: SwiftShadowsocksBridgeProviding, - accessMethodWrapper: SwiftAccessMethodSettingsWrapper + accessMethodWrapper: SwiftAccessMethodSettingsWrapper, + addressCacheProvider: AddressCacheProviding ) throws { let bridgeProvider = SwiftShadowsocksBridgeProvider(provider: shadowsocksProvider) self.shadowsocksBridgeProvider = bridgeProvider self.shadowsocksBridgeProviderWrapper = initMullvadShadowsocksBridgeProvider(provider: bridgeProvider) + let defaultAddressCache = DefaultAddressCacheProvider(provider: addressCacheProvider) + self.addressCacheProvider = defaultAddressCache + self.addressCacheWrapper = iniSwiftAddressCacheWrapper(provider: defaultAddressCache) + context = switch disableTls { case true: mullvad_api_init_new_tls_disabled( @@ -36,7 +43,8 @@ public struct MullvadApiContext: @unchecked Sendable { address, domain, shadowsocksBridgeProviderWrapper, - accessMethodWrapper + accessMethodWrapper, + addressCacheWrapper ) case false: mullvad_api_init_new( @@ -44,7 +52,8 @@ public struct MullvadApiContext: @unchecked Sendable { address, domain, shadowsocksBridgeProviderWrapper, - accessMethodWrapper + accessMethodWrapper, + addressCacheWrapper ) } diff --git a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h index accd302d53..70c1428098 100644 --- a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h +++ b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h @@ -61,6 +61,14 @@ typedef struct SwiftShadowsocksLoaderWrapper { struct SwiftShadowsocksLoaderWrapperContext _0; } SwiftShadowsocksLoaderWrapper; +typedef struct SwiftAddressCacheProviderContext { + const void *address_cache; +} SwiftAddressCacheProviderContext; + +typedef struct SwiftAddressCacheWrapper { + struct SwiftAddressCacheProviderContext _0; +} SwiftAddressCacheWrapper; + typedef struct SwiftCancelHandle { struct RequestCancelHandle *ptr; } SwiftCancelHandle; @@ -161,7 +169,8 @@ struct SwiftApiContext mullvad_api_init_new_tls_disabled(const char *host, const char *address, const char *domain, struct SwiftShadowsocksLoaderWrapper bridge_provider, - struct SwiftAccessMethodSettingsWrapper settings_provider); + struct SwiftAccessMethodSettingsWrapper settings_provider, + struct SwiftAddressCacheWrapper address_cache); /** * # Safety @@ -181,7 +190,8 @@ struct SwiftApiContext mullvad_api_init_new(const char *host, const char *address, const char *domain, struct SwiftShadowsocksLoaderWrapper bridge_provider, - struct SwiftAccessMethodSettingsWrapper settings_provider); + struct SwiftAccessMethodSettingsWrapper settings_provider, + struct SwiftAddressCacheWrapper address_cache); /** * # Safety @@ -202,7 +212,8 @@ struct SwiftApiContext mullvad_api_init_inner(const char *host, const char *domain, bool disable_tls, struct SwiftShadowsocksLoaderWrapper bridge_provider, - struct SwiftAccessMethodSettingsWrapper settings_provider); + struct SwiftAccessMethodSettingsWrapper settings_provider, + struct SwiftAddressCacheWrapper address_cache); /** * Converts parameters into a `Box<AccessMethodSetting>` raw representation that @@ -299,6 +310,25 @@ struct SwiftCancelHandle mullvad_ios_delete_account(struct SwiftApiContext api_c const char *account_number); /** + * Return the latest available endpoint, or a default one if none are cached + * + * # SAFETY + * `rawAddressCacheProvider` **must** be provided by a call to `init_swift_address_cache_wrapper` + * It is okay to persist it, and use it accross multiple threads. + */ +extern const char *swift_get_cached_endpoint(const void *rawAddressCacheProvider); + +/** + * Called by the Swift side in order to provide an object to rust that provides API addresses in a UTF-8 string form + * + * # SAFETY + * `address_cache` **must be** pointing to a valid instance of a `DefaultAddressCacheProvider` + * That instance's lifetime has to be equivalent to a `'static` lifetime in Rust + * This function does not take ownership of `address_cache` + */ +struct SwiftAddressCacheWrapper init_swift_address_cache_wrapper(const void *address_cache); + +/** * # Safety * * `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created diff --git a/ios/MullvadTypes/AddressCacheProviding.swift b/ios/MullvadTypes/AddressCacheProviding.swift new file mode 100644 index 0000000000..059409bbd5 --- /dev/null +++ b/ios/MullvadTypes/AddressCacheProviding.swift @@ -0,0 +1,25 @@ +// +// AddressCacheProviding.swift +// MullvadTypes +// +// Created by Marco Nikic on 2025-05-15. +// Copyright © 2025 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public protocol AddressCacheProviding: Sendable { + func getCurrentEndpoint() -> AnyIPEndpoint +} + +public final class DefaultAddressCacheProvider: AddressCacheProviding, Sendable { + let provider: AddressCacheProviding + + public init(provider: AddressCacheProviding) { + self.provider = provider + } + + public func getCurrentEndpoint() -> AnyIPEndpoint { + provider.getCurrentEndpoint() + } +} diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index fb003e53b1..de1e60d6b1 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -788,6 +788,8 @@ A970C89D2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */; }; A9711B2B2D662AE3003DA71D /* SwiftConnectionModeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9711B2A2D662AE3003DA71D /* SwiftConnectionModeProvider.swift */; }; A97275562CE36CAE00029F15 /* DaitaV2Parameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97275552CE36CAE00029F15 /* DaitaV2Parameters.swift */; }; + A97687C82DD60D5D000D96E8 /* AddressCacheProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97687C72DD60D5D000D96E8 /* AddressCacheProviding.swift */; }; + A97687CA2DD60F36000D96E8 /* MullvadAddressCacheProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97687C92DD60F36000D96E8 /* MullvadAddressCacheProvider.swift */; }; A97D25AE2B0BB18100946B2D /* ProtocolObfuscator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */; }; A97D25B02B0BB5C400946B2D /* ProtocolObfuscationStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25AF2B0BB5C400946B2D /* ProtocolObfuscationStub.swift */; }; A97D25B22B0CB02D00946B2D /* ProtocolObfuscatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25B12B0CB02D00946B2D /* ProtocolObfuscatorTests.swift */; }; @@ -2343,6 +2345,8 @@ A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Socks5UsernamePasswordCommand.swift; sourceTree = "<group>"; }; A9711B2A2D662AE3003DA71D /* SwiftConnectionModeProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftConnectionModeProvider.swift; sourceTree = "<group>"; }; A97275552CE36CAE00029F15 /* DaitaV2Parameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaitaV2Parameters.swift; sourceTree = "<group>"; }; + A97687C72DD60D5D000D96E8 /* AddressCacheProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCacheProviding.swift; sourceTree = "<group>"; }; + A97687C92DD60F36000D96E8 /* MullvadAddressCacheProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadAddressCacheProvider.swift; sourceTree = "<group>"; }; A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscator.swift; sourceTree = "<group>"; }; A97D25AF2B0BB5C400946B2D /* ProtocolObfuscationStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscationStub.swift; sourceTree = "<group>"; }; A97D25B12B0CB02D00946B2D /* ProtocolObfuscatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscatorTests.swift; sourceTree = "<group>"; }; @@ -3063,6 +3067,7 @@ 58E511E028DDB7F100B0BCDE /* WrappingError.swift */, A9711B2A2D662AE3003DA71D /* SwiftConnectionModeProvider.swift */, A98207EE2D9192A300654558 /* ShadowsocksBridgeProviding.swift */, + A97687C72DD60D5D000D96E8 /* AddressCacheProviding.swift */, ); path = MullvadTypes; sourceTree = "<group>"; @@ -4587,6 +4592,7 @@ A96D0B442D675F0400DD6C59 /* MullvadConnectionModeProvider.swift */, A98207F02D91A0AC00654558 /* MullvadShadowsocksBridgeProvider.swift */, A98207F22D9ACE4C00654558 /* MullvadAccessMethodReceiver.swift */, + A97687C92DD60F36000D96E8 /* MullvadAddressCacheProvider.swift */, ); path = MullvadRustRuntime; sourceTree = "<group>"; @@ -6755,6 +6761,7 @@ 7A7AD14F2BF21EF200B30B3C /* NameInputFormatter.swift in Sources */, 58D22413294C90210029F5F8 /* RelayConstraints.swift in Sources */, 7AB401852DA53D5300522E17 /* NewAccountData.swift in Sources */, + A97687C82DD60D5D000D96E8 /* AddressCacheProviding.swift in Sources */, A97275562CE36CAE00029F15 /* DaitaV2Parameters.swift in Sources */, 7AF9BE8C2A321D1F00DBFEDB /* RelayFilter.swift in Sources */, 58D22414294C90210029F5F8 /* RelayLocation.swift in Sources */, @@ -6904,6 +6911,7 @@ 7AB931242D43C2CA005FCEBA /* MullvadApiContext.swift in Sources */, A9D9A4BB2C36D397004088DD /* EphemeralPeerNegotiator.swift in Sources */, F0A89CB72D9D923300580C27 /* String+UnsafePointer.swift in Sources */, + A97687CA2DD60F36000D96E8 /* MullvadAddressCacheProvider.swift in Sources */, A9D9A4B22C36D12D004088DD /* TunnelObfuscator.swift in Sources */, A98207F12D91A0AC00654558 /* MullvadShadowsocksBridgeProvider.swift in Sources */, 7AB931262D43D22F005FCEBA /* MullvadApiResponse.swift in Sources */, diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 4664fa3b57..2590e2f1e7 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -109,7 +109,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD address: REST.defaultAPIEndpoint.description, domain: REST.encryptedDNSHostname, shadowsocksProvider: shadowsocksLoader, - accessMethodWrapper: transportStrategy.opaqueAccessMethodSettingsWrapper + accessMethodWrapper: transportStrategy.opaqueAccessMethodSettingsWrapper, + addressCacheProvider: addressCache ) accessMethodReceiver = MullvadAccessMethodReceiver( diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift index 2169d0100d..cc496bba63 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift @@ -75,7 +75,8 @@ class TunnelManagerTests: XCTestCase { address: REST.defaultAPIEndpoint.description, domain: REST.encryptedDNSHostname, shadowsocksProvider: shadowsocksLoader, - accessMethodWrapper: transportStrategy.opaqueAccessMethodSettingsWrapper + accessMethodWrapper: transportStrategy.opaqueAccessMethodSettingsWrapper, + addressCacheProvider: addressCache ) try SettingsManager.writeSettings(LatestTunnelSettings()) diff --git a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift index 3f2df2cbdb..8be5f883b9 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift @@ -266,7 +266,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable { address: REST.defaultAPIEndpoint.description, domain: REST.encryptedDNSHostname, shadowsocksProvider: shadowsocksLoader, - accessMethodWrapper: transportStrategy.opaqueAccessMethodSettingsWrapper + accessMethodWrapper: transportStrategy.opaqueAccessMethodSettingsWrapper, + addressCacheProvider: addressCache ) accessMethodReceiver = MullvadAccessMethodReceiver( |
