diff options
| author | Jon Petersson <jon.petersson@mullvad.net> | 2025-06-25 14:43:35 +0200 |
|---|---|---|
| committer | Jon Petersson <jon.petersson@mullvad.net> | 2025-07-08 12:04:35 +0200 |
| commit | 7ded39e1f58396baa401b93576dd4650e0836645 (patch) | |
| tree | e275fbf4cd1a23ea38bef30e45f87c233e5c3c72 /ios | |
| parent | 216653151569b218ca8f0d78a8585595147a16b9 (diff) | |
| download | mullvadvpn-7ded39e1f58396baa401b93576dd4650e0836645.tar.xz mullvadvpn-7ded39e1f58396baa401b93576dd4650e0836645.zip | |
Update FFI to handle new QUIC params
Diffstat (limited to 'ios')
21 files changed, 161 insertions, 119 deletions
diff --git a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift index 64dbf3a943..d7333dc915 100644 --- a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift +++ b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift @@ -63,7 +63,8 @@ extension RelaySelectorStub { cityCode: "got", latitude: 0, longitude: 0 - ) + ), + features: nil ) return SelectedRelays( diff --git a/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift b/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift index ce265aa90a..57576da35c 100644 --- a/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift +++ b/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift @@ -29,7 +29,8 @@ public struct SelectedRelaysStub { cityCode: "got", latitude: 42, longitude: 42 - ) + ), + features: nil ), retryAttempt: 0 ) diff --git a/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift b/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift index f73509affe..73944a8093 100644 --- a/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift +++ b/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift @@ -11,15 +11,18 @@ import MullvadSettings public struct ObfuscationMethodSelector { /// This retry logic used is explained at the following link: /// https://github.com/mullvad/mullvadvpn-app/blob/main/docs/relay-selector.md#default-constraints-for-tunnel-endpoints + /// + /// - Note: This method should never return `.automatic`. public static func obfuscationMethodBy( connectionAttemptCount: UInt, tunnelSettings: LatestTunnelSettings ) -> WireGuardObfuscationState { - // TODO: Revisit this when QUIC obfuscation is added if tunnelSettings.wireGuardObfuscation.state == .automatic { - if connectionAttemptCount.isOrdered(nth: 2, forEverySetOf: 3) { + if connectionAttemptCount.isOrdered(nth: 2, forEverySetOf: 4) { .shadowsocks - } else if connectionAttemptCount.isOrdered(nth: 3, forEverySetOf: 3) { + } else if connectionAttemptCount.isOrdered(nth: 3, forEverySetOf: 4) { + .quic + } else if connectionAttemptCount.isOrdered(nth: 4, forEverySetOf: 4) { .udpOverTcp } else { .off diff --git a/ios/MullvadREST/Relay/RelayPicking/RelayPicking.swift b/ios/MullvadREST/Relay/RelayPicking/RelayPicking.swift index 2edd67a7ea..18421de3f3 100644 --- a/ios/MullvadREST/Relay/RelayPicking/RelayPicking.swift +++ b/ios/MullvadREST/Relay/RelayPicking/RelayPicking.swift @@ -39,7 +39,8 @@ extension RelayPicking { return SelectedRelay( endpoint: match.endpoint, hostname: match.relay.hostname, - location: match.location + location: match.location, + features: match.relay.features ) } diff --git a/ios/MullvadREST/Relay/RelaySelectorProtocol.swift b/ios/MullvadREST/Relay/RelaySelectorProtocol.swift index 7b2f91c761..174ff9ccb1 100644 --- a/ios/MullvadREST/Relay/RelaySelectorProtocol.swift +++ b/ios/MullvadREST/Relay/RelaySelectorProtocol.swift @@ -6,7 +6,6 @@ // Copyright © 2025 Mullvad VPN AB. All rights reserved. // -import Foundation import MullvadSettings import MullvadTypes @@ -34,11 +33,15 @@ public struct SelectedRelay: Equatable, Codable, Sendable { /// Relay geo location. public let location: Location + /// Relay features, such as `DAITA` or `QUIC`. + public let features: REST.ServerRelay.Features? + /// Designated initializer. - public init(endpoint: MullvadEndpoint, hostname: String, location: Location) { + public init(endpoint: MullvadEndpoint, hostname: String, location: Location, features: REST.ServerRelay.Features?) { self.endpoint = endpoint self.hostname = hostname self.location = location + self.features = features } } diff --git a/ios/MullvadRustRuntime/TunnelObfuscator.swift b/ios/MullvadRustRuntime/TunnelObfuscator.swift index 495930b222..6f74089265 100644 --- a/ios/MullvadRustRuntime/TunnelObfuscator.swift +++ b/ios/MullvadRustRuntime/TunnelObfuscator.swift @@ -14,7 +14,7 @@ import Network public enum TunnelObfuscationProtocol { case udpOverTcp case shadowsocks - case quic + case quic(hostname: String, token: String) } public protocol TunnelObfuscation { @@ -74,22 +74,34 @@ public final class TunnelObfuscator: TunnelObfuscation { stateLock.withLock { guard !isStarted else { return } - let obfuscationProtocol = switch obfuscationProtocol { - case .udpOverTcp: TunnelObfuscatorProtocol(0) - case .shadowsocks: TunnelObfuscatorProtocol(1) - case .quic: TunnelObfuscatorProtocol(2) - } - let result = withUnsafeMutablePointer(to: &proxyHandle) { proxyHandlePointer in let addressData = remoteAddress.rawValue - return start_tunnel_obfuscator_proxy( - addressData.map { $0 }, - UInt(addressData.count), - tcpPort, - obfuscationProtocol, - proxyHandlePointer - ) + return switch obfuscationProtocol { + case .udpOverTcp: + start_udp2tcp_obfuscator_proxy( + addressData.map { $0 }, + UInt(addressData.count), + tcpPort, + proxyHandlePointer + ) + case .shadowsocks: + start_shadowsocks_obfuscator_proxy( + addressData.map { $0 }, + UInt(addressData.count), + tcpPort, + proxyHandlePointer + ) + case let .quic(hostname, token): + start_quic_obfuscator_proxy( + addressData.map { $0 }, + UInt(addressData.count), + tcpPort, + hostname, + token, + proxyHandlePointer + ) + } } assert(result == 0) diff --git a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h index d4c0bf334f..ad15b43d39 100644 --- a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h +++ b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h @@ -17,16 +17,6 @@ enum SwiftAccessMethodKind { }; typedef uint8_t SwiftAccessMethodKind; -/** - * SAFETY: `TunnelObfuscatorProtocol` values must either be `0` or `1` - */ -enum TunnelObfuscatorProtocol { - UdpOverTcp = 0, - Shadowsocks, - Quic, -}; -typedef uint8_t TunnelObfuscatorProtocol; - typedef struct ApiContext ApiContext; /** @@ -930,10 +920,21 @@ int32_t start_shadowsocks_proxy(const uint8_t *forward_address, */ int32_t stop_shadowsocks_proxy(struct ProxyHandle *proxy_config); -int32_t start_tunnel_obfuscator_proxy(const uint8_t *peer_address, - uintptr_t peer_address_len, - uint16_t peer_port, - TunnelObfuscatorProtocol obfuscation_protocol, - struct ProxyHandle *proxy_handle); +int32_t start_udp2tcp_obfuscator_proxy(const uint8_t *peer_address, + uintptr_t peer_address_len, + uint16_t peer_port, + struct ProxyHandle *proxy_handle); + +int32_t start_shadowsocks_obfuscator_proxy(const uint8_t *peer_address, + uintptr_t peer_address_len, + uint16_t peer_port, + struct ProxyHandle *proxy_handle); + +int32_t start_quic_obfuscator_proxy(const uint8_t *peer_address, + uintptr_t peer_address_len, + uint16_t peer_port, + const char *hostname, + const char *token, + struct ProxyHandle *proxy_handle); int32_t stop_tunnel_obfuscator_proxy(struct ProxyHandle *proxy_handle); diff --git a/ios/MullvadSettings/WireGuardObfuscationSettings.swift b/ios/MullvadSettings/WireGuardObfuscationSettings.swift index 80a4a6d425..b32175030f 100644 --- a/ios/MullvadSettings/WireGuardObfuscationSettings.swift +++ b/ios/MullvadSettings/WireGuardObfuscationSettings.swift @@ -18,9 +18,7 @@ public enum WireGuardObfuscationState: Codable, Sendable { case automatic case udpOverTcp case shadowsocks - #if DEBUG case quic - #endif case off public init(from decoder: Decoder) throws { @@ -45,10 +43,8 @@ public enum WireGuardObfuscationState: Codable, Sendable { self = .udpOverTcp case .shadowsocks: self = .shadowsocks - #if DEBUG case .quic: self = .quic - #endif case .off: self = .off } diff --git a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift index 6c31610be4..744beededc 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift @@ -115,7 +115,8 @@ struct ChipContainerView<ViewModel>: View where ViewModel: ChipViewModelProtocol cityCode: "gbg", latitude: 1234, longitude: 1234 - ) + ), + features: nil ), retryAttempt: 0 ), diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift index eca4097f31..91b0a5db98 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift @@ -224,7 +224,6 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { self?.delegate?.showDetails(for: .wireguardOverShadowsocks) } - #if DEBUG case .wireGuardObfuscationQuic: guard let cell = cell as? SelectableSettingsCell else { return } @@ -238,7 +237,7 @@ final class VPNSettingsCellFactory: @preconcurrency CellFactoryProtocol { cell.setAccessibilityIdentifier(item.accessibilityIdentifier) cell.detailTitleLabel.setAccessibilityIdentifier(.wireGuardObfuscationQuic) cell.applySubCellStyling() - #endif + case .wireGuardObfuscationOff: guard let cell = cell as? SelectableSettingsCell else { return } diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift index 84df606905..356ae9bf5c 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift @@ -83,9 +83,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< case wireGuardObfuscationAutomatic case wireGuardObfuscationUdpOverTcp case wireGuardObfuscationShadowsocks - #if DEBUG case wireGuardObfuscationQuic - #endif case wireGuardObfuscationOff case wireGuardObfuscationPort(_ port: WireGuardObfuscationUdpOverTcpPort) case quantumResistanceAutomatic @@ -151,10 +149,8 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< .wireGuardObfuscationUdpOverTcp case .wireGuardObfuscationShadowsocks: .wireGuardObfuscationShadowsocks - #if DEBUG case .wireGuardObfuscationQuic: .wireGuardObfuscationQuic - #endif case .wireGuardObfuscationOff: .wireGuardObfuscationOff case .wireGuardObfuscationPort: @@ -182,13 +178,8 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< .wireGuardPort case .wireGuardCustomPort: .wireGuardCustomPort - #if DEBUG case .wireGuardObfuscationAutomatic, .wireGuardObfuscationOff, .wireGuardObfuscationQuic: .wireGuardObfuscation - #else - case .wireGuardObfuscationAutomatic, .wireGuardObfuscationOff: - .wireGuardObfuscation - #endif case .wireGuardObfuscationUdpOverTcp, .wireGuardObfuscationShadowsocks: .wireGuardObfuscationOption case .wireGuardObfuscationPort: @@ -228,9 +219,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource< case .off: .wireGuardObfuscationOff case .on, .udpOverTcp: .wireGuardObfuscationUdpOverTcp case .shadowsocks: .wireGuardObfuscationShadowsocks - #if DEBUG case .quic: .wireGuardObfuscationQuic - #endif } let quantumResistanceItem: Item = switch viewModel.quantumResistance { diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift index 3694076db0..3526606d72 100644 --- a/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift +++ b/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift @@ -29,7 +29,7 @@ class ObfuscationMethodSelectorTests: XCTestCase { connectionAttemptCount: attempt, tunnelSettings: tunnelSettings ) - if attempt.isOrdered(nth: 1, forEverySetOf: 3) { + if attempt.isOrdered(nth: 1, forEverySetOf: 4) { XCTAssertEqual(method, .off) } else { XCTAssertNotEqual(method, .off) @@ -53,7 +53,7 @@ class ObfuscationMethodSelectorTests: XCTestCase { connectionAttemptCount: attempt, tunnelSettings: tunnelSettings ) - if attempt.isOrdered(nth: 2, forEverySetOf: 3) { + if attempt.isOrdered(nth: 2, forEverySetOf: 4) { XCTAssertEqual(method, .shadowsocks) } else { XCTAssertNotEqual(method, .shadowsocks) @@ -61,6 +61,30 @@ class ObfuscationMethodSelectorTests: XCTestCase { } } + func testMethodSelectionQuic() throws { + (UInt(0) ... 10).forEach { attempt in + tunnelSettings.wireGuardObfuscation = WireGuardObfuscationSettings(state: .quic) + + var method = ObfuscationMethodSelector.obfuscationMethodBy( + connectionAttemptCount: attempt, + tunnelSettings: tunnelSettings + ) + XCTAssertEqual(method, .quic) + + tunnelSettings.wireGuardObfuscation = WireGuardObfuscationSettings(state: .automatic) + + method = ObfuscationMethodSelector.obfuscationMethodBy( + connectionAttemptCount: attempt, + tunnelSettings: tunnelSettings + ) + if attempt.isOrdered(nth: 3, forEverySetOf: 4) { + XCTAssertEqual(method, .quic) + } else { + XCTAssertNotEqual(method, .quic) + } + } + } + func testMethodSelectionUdpOverTcp() throws { (UInt(0) ... 10).forEach { attempt in tunnelSettings.wireGuardObfuscation = WireGuardObfuscationSettings(state: .udpOverTcp) @@ -77,7 +101,7 @@ class ObfuscationMethodSelectorTests: XCTestCase { connectionAttemptCount: attempt, tunnelSettings: tunnelSettings ) - if attempt.isOrdered(nth: 3, forEverySetOf: 3) { + if attempt.isOrdered(nth: 4, forEverySetOf: 4) { XCTAssertEqual(method, .udpOverTcp) } else { XCTAssertNotEqual(method, .udpOverTcp) diff --git a/ios/MullvadVPNUITests/Base/BaseUITestCase.swift b/ios/MullvadVPNUITests/Base/BaseUITestCase.swift index df03759409..ebae341a33 100644 --- a/ios/MullvadVPNUITests/Base/BaseUITestCase.swift +++ b/ios/MullvadVPNUITests/Base/BaseUITestCase.swift @@ -32,9 +32,9 @@ class BaseUITestCase: XCTestCase { /// Default relay to use in tests static let testsDefaultRelayName = "se-got-wg-001" - static let testsDefaultQuicCountryName = "Relay Software Country" - static let testsDefaultQuicCityName = "Relay Software city" - static let testsDefaultQuicRelayName = "se-got-wg-881" + static let testsDefaultQuicCountryName = "Ireland" + static let testsDefaultQuicCityName = "Dublin" + static let testsDefaultQuicRelayName = "ie-dub-wg-001" /// True when the current test case is capturing packets private var currentTestCaseShouldCapturePackets = false diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index bf4feac3c1..7cd230e2fb 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -215,40 +215,6 @@ extension PacketTunnelActor { } /** - Reconnect tunnel to new relays. Enters error state on failure. - - - Parameters: - - nextRelay: next relays to connect to - - reason: reason for reconnect - */ - private func reconnect(to nextRelays: NextRelays, reason: ActorReconnectReason) async { - do { - switch state { - // There is no connection monitoring going on when exchanging keys. - // The procedure starts from scratch for each reconnection attempts. - case .connecting, .connected, .reconnecting, .error, .negotiatingEphemeralPeer: - switch reason { - case .connectionLoss: - // Tunnel monitor is already paused at this point. Avoid calling stop() to prevent the reset of - // internal state - break - case .userInitiated: - tunnelMonitor.stop() - } - - try await tryStart(nextRelays: nextRelays, reason: reason) - - case .disconnected, .disconnecting, .initial: - break - } - } catch { - logger.error(error: error, message: "Failed to reconnect the tunnel.") - - await setErrorStateInternal(with: error) - } - } - - /** Entry point for attempting to start the tunnel by performing the following steps: - Read settings @@ -430,7 +396,9 @@ extension PacketTunnelActor { let obfuscated = protocolObfuscator.obfuscate( connectionState.connectedEndpoint, settings: settings.tunnelSettings, - retryAttempts: connectionState.selectedRelays.retryAttempt + retryAttempts: connectionState.selectedRelays.retryAttempt, + relayFeatures: connectionState.selectedRelays.entry?.features ?? connectionState.selectedRelays.exit + .features ) let transportLayer = protocolObfuscator.transportLayer.map { $0 } ?? .udp diff --git a/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift b/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift index b6588d6de6..868effbe71 100644 --- a/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift +++ b/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift @@ -21,7 +21,8 @@ public protocol ProtocolObfuscation { func obfuscate( _ endpoint: MullvadEndpoint, settings: LatestTunnelSettings, - retryAttempts: UInt + retryAttempts: UInt, + relayFeatures: REST.ServerRelay.Features? ) -> ProtocolObfuscationResult var transportLayer: TransportLayer? { get } var remotePort: UInt16 { get } @@ -46,7 +47,8 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat public func obfuscate( _ endpoint: MullvadEndpoint, settings: LatestTunnelSettings, - retryAttempts: UInt = 0 + retryAttempts: UInt = 0, + relayFeatures: REST.ServerRelay.Features? ) -> ProtocolObfuscationResult { let obfuscationMethod = ObfuscationMethodSelector.obfuscationMethodBy( connectionAttemptCount: retryAttempts, @@ -55,17 +57,29 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat remotePort = endpoint.ipv4Relay.port - guard obfuscationMethod != .off else { + #if DEBUG + let obfuscationProtocol: TunnelObfuscationProtocol? = switch obfuscationMethod { + case .udpOverTcp: + .udpOverTcp + case .shadowsocks: + .shadowsocks + case .quic: + if let relayFeatures = relayFeatures?.quic { + .quic(hostname: relayFeatures.domain, token: relayFeatures.token) + } else { + nil + } + default: + // This is fine, since ObfuscationMethodSelector.obfuscationMethodBy` above should never + // return .automatic. + nil + } + + guard let obfuscationProtocol else { tunnelObfuscator = nil return .init(endpoint: endpoint, method: .off) } - #if DEBUG - let obfuscationProtocol: TunnelObfuscationProtocol = switch obfuscationMethod { - case .shadowsocks: .shadowsocks - case .quic: .quic - default: .udpOverTcp - } let obfuscator = Obfuscator( remoteAddress: endpoint.ipv4Relay.ip, tcpPort: remotePort, diff --git a/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift index 16332271ed..527f6f49ca 100644 --- a/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift +++ b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift @@ -138,7 +138,8 @@ final class AppMessageHandlerTests: XCTestCase { exit: SelectedRelay( endpoint: match.endpoint, hostname: match.relay.hostname, - location: match.location + location: match.location, + features: nil ), retryAttempt: 0 ) diff --git a/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift index d340974131..23b231f8d3 100644 --- a/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift +++ b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift @@ -51,12 +51,14 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase { entryRelay = SelectedRelay( endpoint: entryMatch.endpoint, hostname: entryMatch.relay.hostname, - location: entryMatch.location + location: entryMatch.location, + features: nil ) exitRelay = SelectedRelay( endpoint: exitMatch.endpoint, hostname: exitMatch.relay.hostname, - location: exitMatch.location + location: exitMatch.location, + features: nil ) } diff --git a/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift b/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift index 77087782a3..4f65cb65e9 100644 --- a/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift @@ -6,7 +6,7 @@ // Copyright © 2025 Mullvad VPN AB. All rights reserved. // -import Foundation +@testable import MullvadREST @testable import MullvadSettings @testable import MullvadTypes @testable import PacketTunnelCore @@ -17,7 +17,8 @@ struct ProtocolObfuscationStub: ProtocolObfuscation { func obfuscate( _ endpoint: MullvadEndpoint, settings: LatestTunnelSettings, - retryAttempts: UInt + retryAttempts: UInt, + relayFeatures: REST.ServerRelay.Features? ) -> ProtocolObfuscationResult { .init(endpoint: endpoint, method: .off) } diff --git a/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift b/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift index c77211b5fa..9d2f5289ca 100644 --- a/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift +++ b/ios/PacketTunnelCoreTests/MultiHopEphemeralPeerExchangerTests.swift @@ -50,12 +50,14 @@ final class MultiHopEphemeralPeerExchangerTests: XCTestCase { entryRelay = SelectedRelay( endpoint: entryMatch.endpoint, hostname: entryMatch.relay.hostname, - location: entryMatch.location + location: entryMatch.location, + features: nil ) exitRelay = SelectedRelay( endpoint: exitMatch.endpoint, hostname: exitMatch.relay.hostname, - location: exitMatch.location + location: exitMatch.location, + features: nil ) } diff --git a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift index ba506a0519..1ef7dfe597 100644 --- a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift +++ b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift @@ -6,6 +6,7 @@ // Copyright © 2025 Mullvad VPN AB. All rights reserved. // +@testable import MullvadREST @testable import MullvadSettings @testable import MullvadTypes import Network @@ -33,14 +34,14 @@ final class ProtocolObfuscatorTests: XCTestCase { func testObfuscateOffDoesNotChangeEndpoint() { let settings = settings(.off, obfuscationPort: .automatic) - let nonObfuscated = obfuscator.obfuscate(endpoint, settings: settings) + let nonObfuscated = obfuscator.obfuscate(endpoint, settings: settings, relayFeatures: nil) XCTAssertEqual(endpoint, nonObfuscated.endpoint) } func testObfuscateUdpOverTcp() throws { let settings = settings(.udpOverTcp, obfuscationPort: .automatic) - let obfuscated = obfuscator.obfuscate(endpoint, settings: settings) + let obfuscated = obfuscator.obfuscate(endpoint, settings: settings, relayFeatures: nil) let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub) validate(obfuscated.endpoint, against: obfuscationProtocol) @@ -48,7 +49,19 @@ final class ProtocolObfuscatorTests: XCTestCase { func testObfuscateShadowsocks() throws { let settings = settings(.shadowsocks, obfuscationPort: .automatic) - let obfuscated = obfuscator.obfuscate(endpoint, settings: settings) + let obfuscated = obfuscator.obfuscate(endpoint, settings: settings, relayFeatures: nil) + let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub) + + validate(obfuscated.endpoint, against: obfuscationProtocol) + } + + func testObfuscateQuic() throws { + let settings = settings(.quic, obfuscationPort: .automatic) + let obfuscated = obfuscator.obfuscate( + endpoint, + settings: settings, + relayFeatures: .init(daita: nil, quic: .init(addrIn: [], domain: "", token: "")) + ) let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub) validate(obfuscated.endpoint, against: obfuscationProtocol) @@ -57,13 +70,18 @@ final class ProtocolObfuscatorTests: XCTestCase { func testObfuscateAutomatic() throws { let settings = settings(.automatic, obfuscationPort: .automatic) - try (UInt(0) ... 2).forEach { attempt in - let obfuscated = obfuscator.obfuscate(endpoint, settings: settings, retryAttempts: attempt) + try (UInt(0) ... 3).forEach { attempt in + let obfuscated = obfuscator.obfuscate( + endpoint, + settings: settings, + retryAttempts: attempt, + relayFeatures: .init(daita: nil, quic: .init(addrIn: [], domain: "", token: "")) + ) switch attempt { case 0: XCTAssertEqual(endpoint, obfuscated.endpoint) - case 1, 2: + case 1, 2, 3: let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub) validate(obfuscated.endpoint, against: obfuscationProtocol) default: diff --git a/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift b/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift index 7707ffabf7..314adbee33 100644 --- a/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift +++ b/ios/PacketTunnelCoreTests/SingleHopEphemeralPeerExchangerTests.swift @@ -35,7 +35,12 @@ final class SingleHopEphemeralPeerExchangerTests: XCTestCase { numberOfFailedAttempts: 0 ) - exitRelay = SelectedRelay(endpoint: match.endpoint, hostname: match.relay.hostname, location: match.location) + exitRelay = SelectedRelay( + endpoint: match.endpoint, + hostname: match.relay.hostname, + location: match.location, + features: nil + ) } func testEphemeralPeerExchangeFailsWhenNegotiationCannotStart() async { |
