summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBug Magnet <marco.nikic@mullvad.net>2025-09-16 08:59:04 +0200
committerBug Magnet <marco.nikic@mullvad.net>2025-09-16 09:19:29 +0200
commit6856500e2e84da7737c9f3c75a8299a1cda5a846 (patch)
treef8f7642eb227264b0fef1fe10da8d2d9516808ed
parentf49be85049222834a1c63d0385723f15cf56f9e9 (diff)
downloadmullvadvpn-6856500e2e84da7737c9f3c75a8299a1cda5a846.tar.xz
mullvadvpn-6856500e2e84da7737c9f3c75a8299a1cda5a846.zip
Merge branch 'fix-quic-relay-selector-invalid-constraint'
-rw-r--r--ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift3
-rw-r--r--ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift2
-rw-r--r--ios/MullvadMockData/MullvadREST/ServerRelaysResponse+Stubs.swift2
-rw-r--r--ios/MullvadREST/Relay/MultihopDecisionFlow.swift28
-rw-r--r--ios/MullvadREST/Relay/Obfuscation/RelayObfuscator.swift6
-rw-r--r--ios/MullvadREST/Relay/Obfuscation/ShadowsocksObfuscator.swift5
-rw-r--r--ios/MullvadREST/Relay/ObfuscationMethodSelector.swift71
-rw-r--r--ios/MullvadREST/Relay/RelayPicking/MultihopPicker.swift62
-rw-r--r--ios/MullvadREST/Relay/RelayPicking/SinglehopPicker.swift33
-rw-r--r--ios/MullvadREST/Relay/RelaySelectorProtocol.swift11
-rw-r--r--ios/MullvadREST/Relay/RelaySelectorWrapper.swift11
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift3
-rw-r--r--ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift6
-rw-r--r--ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift16
-rw-r--r--ios/MullvadVPNTests/MullvadREST/Relay/RelayObfuscatorTests.swift64
-rw-r--r--ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift76
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift6
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActor.swift15
-rw-r--r--ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift17
-rw-r--r--ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift6
-rw-r--r--ios/PacketTunnelCore/Actor/State.swift2
-rw-r--r--ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift3
-rw-r--r--ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift7
-rw-r--r--ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift5
-rw-r--r--ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift37
25 files changed, 353 insertions, 144 deletions
diff --git a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift
index d7333dc915..f43e75b8ac 100644
--- a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift
+++ b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift
@@ -70,7 +70,8 @@ extension RelaySelectorStub {
return SelectedRelays(
entry: cityRelay,
exit: cityRelay,
- retryAttempt: 0
+ retryAttempt: 0,
+ obfuscation: .off
)
}, candidatesResult: nil)
}
diff --git a/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift b/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift
index 57576da35c..51e72eaf9c 100644
--- a/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift
+++ b/ios/MullvadMockData/MullvadREST/SelectedRelaysStub+Stubs.swift
@@ -32,6 +32,6 @@ public struct SelectedRelaysStub {
),
features: nil
),
- retryAttempt: 0
+ retryAttempt: 0, obfuscation: .off
)
}
diff --git a/ios/MullvadMockData/MullvadREST/ServerRelaysResponse+Stubs.swift b/ios/MullvadMockData/MullvadREST/ServerRelaysResponse+Stubs.swift
index 6bd66979b9..3f85e17651 100644
--- a/ios/MullvadMockData/MullvadREST/ServerRelaysResponse+Stubs.swift
+++ b/ios/MullvadMockData/MullvadREST/ServerRelaysResponse+Stubs.swift
@@ -150,7 +150,7 @@ public enum ServerRelaysResponseStubs {
ipv6AddrIn: .loopback,
publicKey: PrivateKey().publicKey.rawValue,
includeInCountry: true,
- daita: false,
+ daita: true,
shadowsocksExtraAddrIn: ["0.0.0.0"],
features: nil
),
diff --git a/ios/MullvadREST/Relay/MultihopDecisionFlow.swift b/ios/MullvadREST/Relay/MultihopDecisionFlow.swift
index dcb4106b95..9046f44dd5 100644
--- a/ios/MullvadREST/Relay/MultihopDecisionFlow.swift
+++ b/ios/MullvadREST/Relay/MultihopDecisionFlow.swift
@@ -55,7 +55,12 @@ struct OneToOne: MultihopDecisionFlow {
useObfuscatedPortIfAvailable: true
)
- return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
+ return SelectedRelays(
+ entry: entryMatch,
+ exit: exitMatch,
+ retryAttempt: relayPicker.connectionAttemptCount,
+ obfuscation: relayPicker.obfuscation.method
+ )
}
func canHandle(entryCandidates: [RelayCandidate], exitCandidates: [RelayCandidate]) -> Bool {
@@ -99,7 +104,12 @@ struct OneToMany: MultihopDecisionFlow {
useObfuscatedPortIfAvailable: false
)
- return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
+ return SelectedRelays(
+ entry: entryMatch,
+ exit: exitMatch,
+ retryAttempt: relayPicker.connectionAttemptCount,
+ obfuscation: relayPicker.obfuscation.method
+ )
}
func canHandle(entryCandidates: [RelayCandidate], exitCandidates: [RelayCandidate]) -> Bool {
@@ -144,7 +154,12 @@ struct ManyToOne: MultihopDecisionFlow {
useObfuscatedPortIfAvailable: true
)
- return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
+ return SelectedRelays(
+ entry: entryMatch,
+ exit: exitMatch,
+ retryAttempt: relayPicker.connectionAttemptCount,
+ obfuscation: relayPicker.obfuscation.method
+ )
}
func canHandle(entryCandidates: [RelayCandidate], exitCandidates: [RelayCandidate]) -> Bool {
@@ -189,7 +204,12 @@ struct ManyToMany: MultihopDecisionFlow {
useObfuscatedPortIfAvailable: true
)
- return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
+ return SelectedRelays(
+ entry: entryMatch,
+ exit: exitMatch,
+ retryAttempt: relayPicker.connectionAttemptCount,
+ obfuscation: relayPicker.obfuscation.method
+ )
}
func canHandle(entryCandidates: [RelayCandidate], exitCandidates: [RelayCandidate]) -> Bool {
diff --git a/ios/MullvadREST/Relay/Obfuscation/RelayObfuscator.swift b/ios/MullvadREST/Relay/Obfuscation/RelayObfuscator.swift
index 41c2d418dd..7abd47f30b 100644
--- a/ios/MullvadREST/Relay/Obfuscation/RelayObfuscator.swift
+++ b/ios/MullvadREST/Relay/Obfuscation/RelayObfuscator.swift
@@ -27,11 +27,13 @@ struct RelayObfuscator: RelayObfuscating {
let relays: REST.ServerRelaysResponse
let tunnelSettings: LatestTunnelSettings
let connectionAttemptCount: UInt
+ let obfuscationBypass: any ObfuscationProviding
- func obfuscate() throws -> RelayObfuscation {
+ func obfuscate() -> RelayObfuscation {
let obfuscationMethod = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: connectionAttemptCount,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings,
+ obfuscationBypass: obfuscationBypass
)
return switch obfuscationMethod {
diff --git a/ios/MullvadREST/Relay/Obfuscation/ShadowsocksObfuscator.swift b/ios/MullvadREST/Relay/Obfuscation/ShadowsocksObfuscator.swift
index f196305075..10ccee7b4d 100644
--- a/ios/MullvadREST/Relay/Obfuscation/ShadowsocksObfuscator.swift
+++ b/ios/MullvadREST/Relay/Obfuscation/ShadowsocksObfuscator.swift
@@ -75,10 +75,7 @@ struct ShadowsocksObfuscator: RelayObfuscating {
}
}
- guard
- wireGuardObfuscation.state == .shadowsocks,
- let port = shadowsockPort()
- else {
+ guard let port = shadowsockPort() else {
return tunnelSettings.relayConstraints.port
}
diff --git a/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift b/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift
index 73944a8093..166c955147 100644
--- a/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift
+++ b/ios/MullvadREST/Relay/ObfuscationMethodSelector.swift
@@ -7,6 +7,11 @@
//
import MullvadSettings
+import MullvadTypes
+
+public protocol ObfuscationProviding {
+ func bypassUnsupportedObfuscation(_: WireGuardObfuscationState) -> WireGuardObfuscationState
+}
public struct ObfuscationMethodSelector {
/// This retry logic used is explained at the following link:
@@ -15,20 +20,64 @@ public struct ObfuscationMethodSelector {
/// - Note: This method should never return `.automatic`.
public static func obfuscationMethodBy(
connectionAttemptCount: UInt,
- tunnelSettings: LatestTunnelSettings
+ tunnelSettings: LatestTunnelSettings,
+ obfuscationBypass: any ObfuscationProviding
) -> WireGuardObfuscationState {
- if tunnelSettings.wireGuardObfuscation.state == .automatic {
- if connectionAttemptCount.isOrdered(nth: 2, forEverySetOf: 4) {
- .shadowsocks
- } else if connectionAttemptCount.isOrdered(nth: 3, forEverySetOf: 4) {
- .quic
- } else if connectionAttemptCount.isOrdered(nth: 4, forEverySetOf: 4) {
- .udpOverTcp
+ let selectedObfuscation: WireGuardObfuscationState =
+ if tunnelSettings.wireGuardObfuscation.state == .automatic {
+ if connectionAttemptCount.isOrdered(nth: 2, forEverySetOf: 4) {
+ .shadowsocks
+ } else if connectionAttemptCount.isOrdered(nth: 3, forEverySetOf: 4) {
+ .quic
+ } else if connectionAttemptCount.isOrdered(nth: 4, forEverySetOf: 4) {
+ .udpOverTcp
+ } else {
+ .off
+ }
} else {
- .off
+ tunnelSettings.wireGuardObfuscation.state
}
- } else {
- tunnelSettings.wireGuardObfuscation.state
+ return obfuscationBypass.bypassUnsupportedObfuscation(selectedObfuscation)
+ }
+}
+
+public struct UnsupportedObfuscationProvider: ObfuscationProviding {
+ let relayConstraint: RelayConstraint<UserSelectedRelays>
+ let relays: REST.ServerRelaysResponse
+ let filterConstraint: RelayConstraint<RelayFilter>
+ let daitaEnabled: Bool
+
+ public init(
+ relayConstraint: RelayConstraint<UserSelectedRelays>,
+ relays: REST.ServerRelaysResponse,
+ filterConstraint: RelayConstraint<RelayFilter>,
+ daitaEnabled: Bool
+ ) {
+ self.relayConstraint = relayConstraint
+ self.relays = relays
+ self.filterConstraint = filterConstraint
+ self.daitaEnabled = daitaEnabled
+ }
+
+ public func bypassUnsupportedObfuscation(_ obfuscation: WireGuardObfuscationState) -> WireGuardObfuscationState {
+ guard obfuscation != .off else { return .off }
+ do {
+ let candidates = try RelaySelector.WireGuard.findCandidates(
+ by: relayConstraint,
+ in: relays,
+ filterConstraint: filterConstraint,
+ daitaEnabled: daitaEnabled
+ )
+ return candidates.isEmpty ? .udpOverTcp : obfuscation
+ } catch {
+ return .udpOverTcp
}
}
}
+
+public struct IdentityObfuscationProvider: ObfuscationProviding {
+ public init() {}
+ public func bypassUnsupportedObfuscation(_ obfuscation: WireGuardObfuscationState) -> WireGuardObfuscationState {
+ obfuscation
+ }
+}
diff --git a/ios/MullvadREST/Relay/RelayPicking/MultihopPicker.swift b/ios/MullvadREST/Relay/RelayPicking/MultihopPicker.swift
index 0dad74797f..f63bc25ba3 100644
--- a/ios/MullvadREST/Relay/RelayPicking/MultihopPicker.swift
+++ b/ios/MullvadREST/Relay/RelayPicking/MultihopPicker.swift
@@ -15,6 +15,43 @@ struct MultihopPicker: RelayPicking {
let connectionAttemptCount: UInt
func pick() throws -> SelectedRelays {
+ let constraints = tunnelSettings.relayConstraints
+ let daitaSettings = tunnelSettings.daita
+
+ // Guarantee that the entry relay supports selected obfuscation
+ let obfuscationBypass = UnsupportedObfuscationProvider(
+ relayConstraint: constraints.entryLocations,
+ relays: obfuscation.obfuscatedRelays,
+ filterConstraint: constraints.filter,
+ daitaEnabled: daitaSettings.daitaState.isEnabled
+ )
+
+ let supportedObfuscation = RelayObfuscator(
+ relays: obfuscation.allRelays,
+ tunnelSettings: tunnelSettings,
+ connectionAttemptCount: connectionAttemptCount,
+ obfuscationBypass: obfuscationBypass
+ ).obfuscate()
+
+ let entryCandidates = try RelaySelector.WireGuard.findCandidates(
+ by: daitaSettings.isAutomaticRouting ? .any : constraints.entryLocations,
+ in: supportedObfuscation.obfuscatedRelays,
+ filterConstraint: constraints.filter,
+ daitaEnabled: daitaSettings.daitaState.isEnabled
+ )
+
+ let exitCandidates = try RelaySelector.WireGuard.findCandidates(
+ by: constraints.exitLocations,
+ in: supportedObfuscation.allRelays,
+ filterConstraint: constraints.filter,
+ daitaEnabled: false
+ )
+
+ let picker = MultihopPicker(
+ obfuscation: supportedObfuscation,
+ tunnelSettings: tunnelSettings,
+ connectionAttemptCount: connectionAttemptCount
+ )
/*
Relay selection is prioritised in the following order:
1. Both entry and exit constraints match only a single relay. Both relays are selected.
@@ -30,30 +67,13 @@ struct MultihopPicker: RelayPicking {
next: ManyToOne(
next: ManyToMany(
next: nil,
- relayPicker: self
+ relayPicker: picker
),
- relayPicker: self
+ relayPicker: picker
),
- relayPicker: self
+ relayPicker: picker
),
- relayPicker: self
- )
-
- let constraints = tunnelSettings.relayConstraints
- let daitaSettings = tunnelSettings.daita
-
- let entryCandidates = try RelaySelector.WireGuard.findCandidates(
- by: daitaSettings.isAutomaticRouting ? .any : constraints.entryLocations,
- in: obfuscation.obfuscatedRelays,
- filterConstraint: constraints.filter,
- daitaEnabled: daitaSettings.daitaState.isEnabled
- )
-
- let exitCandidates = try RelaySelector.WireGuard.findCandidates(
- by: constraints.exitLocations,
- in: obfuscation.allRelays,
- filterConstraint: constraints.filter,
- daitaEnabled: false
+ relayPicker: picker
)
return try decisionFlow.pick(
diff --git a/ios/MullvadREST/Relay/RelayPicking/SinglehopPicker.swift b/ios/MullvadREST/Relay/RelayPicking/SinglehopPicker.swift
index 4ce8518cb0..144a1bb50c 100644
--- a/ios/MullvadREST/Relay/RelayPicking/SinglehopPicker.swift
+++ b/ios/MullvadREST/Relay/RelayPicking/SinglehopPicker.swift
@@ -32,15 +32,38 @@ struct SinglehopPicker: RelayPicking {
}
}
- private func pick(from exitRelays: REST.ServerRelaysResponse) throws -> SelectedRelays {
+ private func pick(from obfuscatedRelays: REST.ServerRelaysResponse) throws -> SelectedRelays {
+ let constraints = tunnelSettings.relayConstraints
+ let daitaSettings = tunnelSettings.daita
+
+ // Guarantee that the chosen relay supports selected obfuscation
+ let obfuscationBypass = UnsupportedObfuscationProvider(
+ relayConstraint: constraints.exitLocations,
+ relays: obfuscatedRelays,
+ filterConstraint: constraints.filter,
+ daitaEnabled: daitaSettings.daitaState.isEnabled
+ )
+
+ let supportedObfuscation = RelayObfuscator(
+ relays: obfuscation.allRelays,
+ tunnelSettings: tunnelSettings,
+ connectionAttemptCount: connectionAttemptCount,
+ obfuscationBypass: obfuscationBypass
+ ).obfuscate()
+
let exitCandidates = try RelaySelector.WireGuard.findCandidates(
by: tunnelSettings.relayConstraints.exitLocations,
- in: exitRelays,
- filterConstraint: tunnelSettings.relayConstraints.filter,
- daitaEnabled: tunnelSettings.daita.daitaState.isEnabled
+ in: supportedObfuscation.obfuscatedRelays,
+ filterConstraint: constraints.filter,
+ daitaEnabled: daitaSettings.daitaState.isEnabled
)
let match = try findBestMatch(from: exitCandidates, useObfuscatedPortIfAvailable: true)
- return SelectedRelays(entry: nil, exit: match, retryAttempt: connectionAttemptCount)
+ return SelectedRelays(
+ entry: nil,
+ exit: match,
+ retryAttempt: connectionAttemptCount,
+ obfuscation: supportedObfuscation.method
+ )
}
}
diff --git a/ios/MullvadREST/Relay/RelaySelectorProtocol.swift b/ios/MullvadREST/Relay/RelaySelectorProtocol.swift
index 174ff9ccb1..f400d81e86 100644
--- a/ios/MullvadREST/Relay/RelaySelectorProtocol.swift
+++ b/ios/MullvadREST/Relay/RelaySelectorProtocol.swift
@@ -55,21 +55,28 @@ public struct SelectedRelays: Equatable, Codable, Sendable {
public let entry: SelectedRelay?
public let exit: SelectedRelay
public let retryAttempt: UInt
+ public let obfuscation: WireGuardObfuscationState
public var ingress: SelectedRelay {
entry ?? exit
}
- public init(entry: SelectedRelay?, exit: SelectedRelay, retryAttempt: UInt) {
+ public init(
+ entry: SelectedRelay?,
+ exit: SelectedRelay,
+ retryAttempt: UInt,
+ obfuscation: WireGuardObfuscationState
+ ) {
self.entry = entry
self.exit = exit
self.retryAttempt = retryAttempt
+ self.obfuscation = obfuscation
}
}
extension SelectedRelays: CustomDebugStringConvertible {
public var debugDescription: String {
"Entry: \(entry?.hostname ?? "-") -> \(entry?.endpoint.ipv4Relay.description ?? "-"), " +
- "Exit: \(exit.hostname) -> \(exit.endpoint.ipv4Relay.description)"
+ "Exit: \(exit.hostname) -> \(exit.endpoint.ipv4Relay.description), obfuscation: \(obfuscation)"
}
}
diff --git a/ios/MullvadREST/Relay/RelaySelectorWrapper.swift b/ios/MullvadREST/Relay/RelaySelectorWrapper.swift
index 197259ce11..0bc0c08120 100644
--- a/ios/MullvadREST/Relay/RelaySelectorWrapper.swift
+++ b/ios/MullvadREST/Relay/RelaySelectorWrapper.swift
@@ -23,10 +23,12 @@ public final class RelaySelectorWrapper: RelaySelectorProtocol, Sendable {
let relays = try relayCache.read().relays
try validateWireguardCustomPort(tunnelSettings, relays: relays)
- let obfuscation = try RelayObfuscator(
+ // Filter for obfuscation
+ let obfuscation = RelayObfuscator(
relays: relays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: connectionAttemptCount
+ connectionAttemptCount: connectionAttemptCount,
+ obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
return switch tunnelSettings.tunnelMultihopState {
@@ -48,10 +50,11 @@ public final class RelaySelectorWrapper: RelaySelectorProtocol, Sendable {
public func findCandidates(tunnelSettings: LatestTunnelSettings) throws -> RelayCandidates {
let relays = try relayCache.read().relays
- let obfuscation = try RelayObfuscator(
+ let obfuscation = RelayObfuscator(
relays: relays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0,
+ obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
let findCandidates: (REST.ServerRelaysResponse, Bool) throws
diff --git a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift
index 744beededc..ff97f2ae1c 100644
--- a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift
+++ b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipContainerView.swift
@@ -118,7 +118,8 @@ struct ChipContainerView<ViewModel>: View where ViewModel: ChipViewModelProtocol
),
features: nil
),
- retryAttempt: 0
+ retryAttempt: 0,
+ obfuscation: .off
),
isPostQuantum: false,
isDaita: false
diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift
index 286b287a5b..a8e0f27559 100644
--- a/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift
+++ b/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift
@@ -169,10 +169,10 @@ class MultihopDecisionFlowTests: XCTestCase {
extension MultihopDecisionFlowTests {
var picker: MultihopPicker {
- let obfuscation = try? RelayObfuscator(
+ let obfuscation = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: LatestTunnelSettings(),
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
var tunnelSettings = LatestTunnelSettings()
@@ -182,7 +182,7 @@ extension MultihopDecisionFlowTests {
)
return MultihopPicker(
- obfuscation: obfuscation.unsafelyUnwrapped,
+ obfuscation: obfuscation,
tunnelSettings: tunnelSettings,
connectionAttemptCount: 0
)
diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift
index 3526606d72..00a961183d 100644
--- a/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift
+++ b/ios/MullvadVPNTests/MullvadREST/Relay/ObfuscationMethodSelectorTests.swift
@@ -19,7 +19,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
var method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
XCTAssertEqual(method, .off)
@@ -27,7 +27,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
if attempt.isOrdered(nth: 1, forEverySetOf: 4) {
XCTAssertEqual(method, .off)
@@ -43,7 +43,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
var method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
XCTAssertEqual(method, .shadowsocks)
@@ -51,7 +51,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
if attempt.isOrdered(nth: 2, forEverySetOf: 4) {
XCTAssertEqual(method, .shadowsocks)
@@ -67,7 +67,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
var method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
XCTAssertEqual(method, .quic)
@@ -75,7 +75,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
if attempt.isOrdered(nth: 3, forEverySetOf: 4) {
XCTAssertEqual(method, .quic)
@@ -91,7 +91,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
var method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
XCTAssertEqual(method, .udpOverTcp)
@@ -99,7 +99,7 @@ class ObfuscationMethodSelectorTests: XCTestCase {
method = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: attempt,
- tunnelSettings: tunnelSettings
+ tunnelSettings: tunnelSettings, obfuscationBypass: IdentityObfuscationProvider()
)
if attempt.isOrdered(nth: 4, forEverySetOf: 4) {
XCTAssertEqual(method, .udpOverTcp)
diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/RelayObfuscatorTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/RelayObfuscatorTests.swift
index df9778a2dc..0593c1a08d 100644
--- a/ios/MullvadVPNTests/MullvadREST/Relay/RelayObfuscatorTests.swift
+++ b/ios/MullvadVPNTests/MullvadREST/Relay/RelayObfuscatorTests.swift
@@ -26,10 +26,10 @@ final class RelayObfuscatorTests: XCTestCase {
func testObfuscateOffDoesNotChangeEndpoint() throws {
tunnelSettings.wireGuardObfuscation = WireGuardObfuscationSettings(state: .off)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
XCTAssertEqual(obfuscationResult.port, defaultWireguardPort)
@@ -45,10 +45,10 @@ final class RelayObfuscatorTests: XCTestCase {
)
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: settings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
let picker = SinglehopPicker(
@@ -73,10 +73,10 @@ final class RelayObfuscatorTests: XCTestCase {
)
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: settings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
let picker = MultihopPicker(
@@ -99,10 +99,10 @@ final class RelayObfuscatorTests: XCTestCase {
udpOverTcpPort: .port80
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
XCTAssertEqual(obfuscationResult.port, .only(80))
@@ -114,10 +114,10 @@ final class RelayObfuscatorTests: XCTestCase {
udpOverTcpPort: .port5001
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
XCTAssertEqual(obfuscationResult.port, .only(5001))
@@ -130,10 +130,10 @@ final class RelayObfuscatorTests: XCTestCase {
)
try (0 ... 10).filter { $0.isMultiple(of: 2) }.forEach { attempt in
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: UInt(attempt)
+ connectionAttemptCount: UInt(attempt), obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
let validPorts: [RelayConstraint<UInt16>] = [.only(80), .only(5001)]
@@ -149,10 +149,10 @@ final class RelayObfuscatorTests: XCTestCase {
shadowsocksPort: .custom(5500)
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
XCTAssertEqual(obfuscationResult.port, .only(5500))
@@ -164,10 +164,10 @@ final class RelayObfuscatorTests: XCTestCase {
shadowsocksPort: .automatic
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
let portRanges = RelaySelector.parseRawPortRanges(sampleRelays.wireguard.shadowsocksPortRanges)
@@ -194,10 +194,10 @@ final class RelayObfuscatorTests: XCTestCase {
shadowsocksPort: .custom(port)
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
let relaysWithExtraAddresses = sampleRelays.wireguard.relays.filter { relay in
@@ -216,10 +216,10 @@ final class RelayObfuscatorTests: XCTestCase {
shadowsocksPort: .custom(port)
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
XCTAssertEqual(obfuscationResult.obfuscatedRelays.wireguard.relays.count, sampleRelays.wireguard.relays.count)
@@ -232,12 +232,32 @@ final class RelayObfuscatorTests: XCTestCase {
state: .quic
)
- let obfuscationResult = try RelayObfuscator(
+ let obfuscationResult = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: tunnelSettings,
- connectionAttemptCount: 0
+ connectionAttemptCount: 0, obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
XCTAssertEqual(obfuscationResult.port, defaultQuicPort)
}
+
+ // MARK: Obfuscation Bypass
+
+ func testObfuscatorBypass() throws {
+ tunnelSettings.wireGuardObfuscation = WireGuardObfuscationSettings(state: .quic)
+
+ let obfuscationResult = RelayObfuscator(
+ relays: sampleRelays,
+ tunnelSettings: tunnelSettings,
+ connectionAttemptCount: 0, obfuscationBypass: ForceShadowsocksObfuscationBypassStub()
+ ).obfuscate()
+
+ XCTAssertEqual(obfuscationResult.method, .shadowsocks)
+ }
+}
+
+struct ForceShadowsocksObfuscationBypassStub: ObfuscationProviding {
+ func bypassUnsupportedObfuscation(_: WireGuardObfuscationState) -> WireGuardObfuscationState {
+ .shadowsocks
+ }
}
diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift
index 6488306221..314be7a61c 100644
--- a/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift
+++ b/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift
@@ -20,10 +20,11 @@ class RelayPickingTests: XCTestCase {
override func setUpWithError() throws {
// Default obfuscation settings to satisfy picker constructors for the tests below.
- obfuscation = try RelayObfuscator(
+ obfuscation = RelayObfuscator(
relays: sampleRelays,
tunnelSettings: LatestTunnelSettings(),
- connectionAttemptCount: 0
+ connectionAttemptCount: 0,
+ obfuscationBypass: IdentityObfuscationProvider()
).obfuscate()
}
@@ -255,4 +256,75 @@ class RelayPickingTests: XCTestCase {
XCTAssertThrowsError(try picker.pick())
}
+
+ // DAITA - ON, Direct only - ON, Entry supports DAITA - TRUE, Entry does not support QUIC
+ // Shadowsocks obfuscation should be picked instead of QUIC since entry does not support it
+ func testMultihopCannotPickAutomaticallyInvalidObfuscation() throws {
+ let constraints = RelayConstraints(
+ entryLocations: .only(UserSelectedRelays(locations: [.hostname("us", "dal", "us-dal-wg-001")])),
+ exitLocations: .only(UserSelectedRelays(locations: [.hostname("se", "got", "se10-wireguard")]))
+ )
+
+ var settings = LatestTunnelSettings()
+ settings.relayConstraints = constraints
+ settings.daita = DAITASettings(daitaState: .on, directOnlyState: .on)
+
+ // Mimic the obfuscator ran by the relay selector wrapper prior to invoking the `MultihopPicker`
+ obfuscation = RelayObfuscator(
+ relays: sampleRelays,
+ tunnelSettings: LatestTunnelSettings(),
+ connectionAttemptCount: 2,
+ obfuscationBypass: IdentityObfuscationProvider()
+ ).obfuscate()
+
+ // It will already have pre-filtered relays to select obfuscation via QUIC because it's the 2nd connection attempt
+ XCTAssertEqual(obfuscation.method, .quic)
+
+ // The `MultihopPicker` will re-roll an obfuscator to find out that QUIC is not supported for the selected entry
+ // It will then fallback to picking shadowsocks obfuscation instead
+ let picker = MultihopPicker(
+ obfuscation: obfuscation,
+ tunnelSettings: settings,
+ connectionAttemptCount: 2
+ )
+
+ let selectedRelays = try picker.pick()
+
+ XCTAssertEqual(selectedRelays.obfuscation, .udpOverTcp)
+ XCTAssertEqual(selectedRelays.entry?.hostname, "us-dal-wg-001")
+ XCTAssertEqual(selectedRelays.exit.hostname, "se10-wireguard")
+ }
+
+ // DAITA - OFF, Entry does not support QUIC
+ // Shadowsocks obfuscation should be picked instead of QUIC since entry does not support it
+ func testSinglehopCannotPickAutomaticallyInvalidObfuscation() throws {
+ let constraints = RelayConstraints(
+ exitLocations: .only(UserSelectedRelays(locations: [.hostname("us", "dal", "us-dal-wg-001")]))
+ )
+
+ var settings = LatestTunnelSettings()
+ settings.relayConstraints = constraints
+
+ // Mimic the obfuscator ran by the relay selector wrapper prior to invoking the `SinglehopPicker`
+ obfuscation = RelayObfuscator(
+ relays: sampleRelays,
+ tunnelSettings: LatestTunnelSettings(),
+ connectionAttemptCount: 2,
+ obfuscationBypass: IdentityObfuscationProvider()
+ ).obfuscate()
+
+ // It will already have pre-filtered relays to select obfuscation via QUIC because it's the 2nd connection attempt
+ XCTAssertEqual(obfuscation.method, .quic)
+
+ let picker = SinglehopPicker(
+ obfuscation: obfuscation,
+ tunnelSettings: settings,
+ connectionAttemptCount: 2
+ )
+
+ let selectedRelays = try picker.pick()
+ XCTAssertEqual(selectedRelays.obfuscation, .udpOverTcp)
+ XCTAssertEqual(selectedRelays.entry?.hostname, nil)
+ XCTAssertEqual(selectedRelays.exit.hostname, "us-dal-wg-001")
+ }
}
diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift
index 46c98c122c..3c3e3e7ac7 100644
--- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift
+++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+ErrorState.swift
@@ -76,6 +76,9 @@ extension PacketTunnelActor {
case let .reconnecting(connState):
return mapConnectionState(connState, reason: reason, priorState: .reconnecting)
+ case let .negotiatingEphemeralPeer(connState, _):
+ return mapConnectionState(connState, reason: reason, priorState: .connecting)
+
case var .error(blockedState):
if blockedState.reason != reason {
blockedState.reason = reason
@@ -84,8 +87,7 @@ extension PacketTunnelActor {
return nil
}
- // Ephemeral peer exchange cannot enter the blocked state
- case .disconnecting, .disconnected, .negotiatingEphemeralPeer:
+ case .disconnecting, .disconnected:
return nil
}
}
diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
index 7cd230e2fb..5c2f58d449 100644
--- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
+++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
@@ -266,10 +266,13 @@ extension PacketTunnelActor {
startDefaultPathObserver()
}
+ let entryConfiguration = configuration.entryConfiguration
+ let exitConfiguration = configuration.exitConfiguration
+
// Daita parameters are gotten from an ephemeral peer
try await tunnelAdapter.startMultihop(
- entryConfiguration: configuration.entryConfiguration,
- exitConfiguration: configuration.exitConfiguration,
+ entryConfiguration: entryConfiguration,
+ exitConfiguration: exitConfiguration,
daita: nil
)
@@ -329,6 +332,7 @@ extension PacketTunnelActor {
connectionState.relayConstraints = settings.relayConstraints
connectionState.connectedEndpoint = connectedRelay.endpoint
connectionState.remotePort = connectedRelay.endpoint.ipv4Relay.port
+ connectionState.obfuscationMethod = selectedRelays.obfuscation
return connectionState
case var .connecting(connectionState), var .reconnecting(connectionState):
@@ -347,6 +351,7 @@ extension PacketTunnelActor {
connectionState.currentKey = settings.privateKey
connectionState.connectedEndpoint = connectedRelay.endpoint
connectionState.remotePort = connectedRelay.endpoint.ipv4Relay.port
+ connectionState.obfuscationMethod = selectedRelays.obfuscation
return connectionState
case let .error(blockedState):
keyPolicy = blockedState.keyPolicy
@@ -369,7 +374,7 @@ extension PacketTunnelActor {
remotePort: connectedRelay.endpoint.ipv4Relay.port,
isPostQuantum: settings.quantumResistance.isEnabled,
isDaitaEnabled: settings.daita.daitaState.isEnabled,
- obfuscationMethod: .off
+ obfuscationMethod: selectedRelays.obfuscation
)
case .disconnecting, .disconnected:
return nil
@@ -395,10 +400,8 @@ extension PacketTunnelActor {
let obfuscated = protocolObfuscator.obfuscate(
connectionState.connectedEndpoint,
- settings: settings.tunnelSettings,
- retryAttempts: connectionState.selectedRelays.retryAttempt,
relayFeatures: connectionState.selectedRelays.entry?.features ?? connectionState.selectedRelays.exit
- .features
+ .features, obfuscationMethod: connectionState.obfuscationMethod
)
let transportLayer = protocolObfuscator.transportLayer.map { $0 } ?? .udp
diff --git a/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift b/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift
index d0ede0dcb5..6d59b5bc15 100644
--- a/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift
+++ b/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift
@@ -20,9 +20,8 @@ public struct ProtocolObfuscationResult {
public protocol ProtocolObfuscation {
func obfuscate(
_ endpoint: MullvadEndpoint,
- settings: LatestTunnelSettings,
- retryAttempts: UInt,
- relayFeatures: REST.ServerRelay.Features?
+ relayFeatures: REST.ServerRelay.Features?,
+ obfuscationMethod: WireGuardObfuscationState
) -> ProtocolObfuscationResult
var transportLayer: TransportLayer? { get }
var remotePort: UInt16 { get }
@@ -46,15 +45,9 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat
public func obfuscate(
_ endpoint: MullvadEndpoint,
- settings: LatestTunnelSettings,
- retryAttempts: UInt = 0,
- relayFeatures: REST.ServerRelay.Features?
+ relayFeatures: REST.ServerRelay.Features?,
+ obfuscationMethod: WireGuardObfuscationState
) -> ProtocolObfuscationResult {
- let obfuscationMethod = ObfuscationMethodSelector.obfuscationMethodBy(
- connectionAttemptCount: retryAttempts,
- tunnelSettings: settings
- )
-
remotePort = endpoint.ipv4Relay.port
let obfuscationProtocol: TunnelObfuscationProtocol? = switch obfuscationMethod {
@@ -69,8 +62,6 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat
nil
}
default:
- // This is fine, since ObfuscationMethodSelector.obfuscationMethodBy` above should never
- // return .automatic.
nil
}
diff --git a/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift b/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift
index fc8e89c0d7..887cd8c960 100644
--- a/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift
+++ b/ios/PacketTunnelCore/Actor/Protocols/TunnelAdapterProtocol.swift
@@ -44,3 +44,9 @@ public struct TunnelPeer {
public var publicKey: PublicKey
public var preSharedKey: PreSharedKey?
}
+
+extension TunnelAdapterConfiguration: CustomDebugStringConvertible {
+ public var debugDescription: String {
+ "interfaceAddresses: \(interfaceAddresses) peerEndpoint: \(peer?.endpoint) allowedIPs: \(allowedIPs)"
+ }
+}
diff --git a/ios/PacketTunnelCore/Actor/State.swift b/ios/PacketTunnelCore/Actor/State.swift
index 6f837fc734..2b1dfd87f7 100644
--- a/ios/PacketTunnelCore/Actor/State.swift
+++ b/ios/PacketTunnelCore/Actor/State.swift
@@ -156,7 +156,7 @@ extension State {
public let isDaitaEnabled: Bool
/// The obfuscation method in force on the connection
- public let obfuscationMethod: WireGuardObfuscationState
+ public var obfuscationMethod: WireGuardObfuscationState
}
/// Data associated with error state.
diff --git a/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift
index 527f6f49ca..ea111b9953 100644
--- a/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift
+++ b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift
@@ -141,7 +141,8 @@ final class AppMessageHandlerTests: XCTestCase {
location: match.location,
features: nil
),
- retryAttempt: 0
+ retryAttempt: 0,
+ obfuscation: .off
)
_ = try? await appMessageHandler.handleAppMessage(
diff --git a/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift
index 23b231f8d3..77fd9ebe6d 100644
--- a/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift
+++ b/ios/PacketTunnelCoreTests/EphemeralPeerExchangingPipelineTests.swift
@@ -190,7 +190,12 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase {
enableDaita: Bool
) -> ObservedConnectionState {
ObservedConnectionState(
- selectedRelays: SelectedRelays(entry: enableMultiHop ? entryRelay : nil, exit: exitRelay, retryAttempt: 0),
+ selectedRelays: SelectedRelays(
+ entry: enableMultiHop ? entryRelay : nil,
+ exit: exitRelay,
+ retryAttempt: 0,
+ obfuscation: .off
+ ),
relayConstraints: relayConstraints,
networkReachability: NetworkReachability.reachable,
connectionAttemptCount: 0,
diff --git a/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift b/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift
index 4f65cb65e9..acbd721ca5 100644
--- a/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift
+++ b/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift
@@ -16,9 +16,8 @@ struct ProtocolObfuscationStub: ProtocolObfuscation {
func obfuscate(
_ endpoint: MullvadEndpoint,
- settings: LatestTunnelSettings,
- retryAttempts: UInt,
- relayFeatures: REST.ServerRelay.Features?
+ relayFeatures: REST.ServerRelay.Features?,
+ obfuscationMethod: WireGuardObfuscationState
) -> ProtocolObfuscationResult {
.init(endpoint: endpoint, method: .off)
}
diff --git a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift
index 1ef7dfe597..33ba532eb5 100644
--- a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift
+++ b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift
@@ -34,14 +34,14 @@ final class ProtocolObfuscatorTests: XCTestCase {
func testObfuscateOffDoesNotChangeEndpoint() {
let settings = settings(.off, obfuscationPort: .automatic)
- let nonObfuscated = obfuscator.obfuscate(endpoint, settings: settings, relayFeatures: nil)
+ let nonObfuscated = obfuscator.obfuscate(endpoint, relayFeatures: nil, obfuscationMethod: .off)
XCTAssertEqual(endpoint, nonObfuscated.endpoint)
}
func testObfuscateUdpOverTcp() throws {
let settings = settings(.udpOverTcp, obfuscationPort: .automatic)
- let obfuscated = obfuscator.obfuscate(endpoint, settings: settings, relayFeatures: nil)
+ let obfuscated = obfuscator.obfuscate(endpoint, relayFeatures: nil, obfuscationMethod: .udpOverTcp)
let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub)
validate(obfuscated.endpoint, against: obfuscationProtocol)
@@ -49,7 +49,7 @@ final class ProtocolObfuscatorTests: XCTestCase {
func testObfuscateShadowsocks() throws {
let settings = settings(.shadowsocks, obfuscationPort: .automatic)
- let obfuscated = obfuscator.obfuscate(endpoint, settings: settings, relayFeatures: nil)
+ let obfuscated = obfuscator.obfuscate(endpoint, relayFeatures: nil, obfuscationMethod: .shadowsocks)
let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub)
validate(obfuscated.endpoint, against: obfuscationProtocol)
@@ -59,35 +59,22 @@ final class ProtocolObfuscatorTests: XCTestCase {
let settings = settings(.quic, obfuscationPort: .automatic)
let obfuscated = obfuscator.obfuscate(
endpoint,
- settings: settings,
- relayFeatures: .init(daita: nil, quic: .init(addrIn: [], domain: "", token: ""))
+ relayFeatures: .init(daita: nil, quic: .init(addrIn: [], domain: "", token: "")), obfuscationMethod: .quic
)
let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub)
validate(obfuscated.endpoint, against: obfuscationProtocol)
}
- func testObfuscateAutomatic() throws {
- let settings = settings(.automatic, obfuscationPort: .automatic)
-
- 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: ""))
- )
+ func testObfuscateAutomaticDoesNotObfuscate() throws {
+ let obfuscated = obfuscator.obfuscate(
+ endpoint,
+ relayFeatures: .init(daita: nil, quic: .init(addrIn: [], domain: "", token: "")),
+ obfuscationMethod: .automatic
+ )
- switch attempt {
- case 0:
- XCTAssertEqual(endpoint, obfuscated.endpoint)
- case 1, 2, 3:
- let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub)
- validate(obfuscated.endpoint, against: obfuscationProtocol)
- default:
- XCTExpectFailure("Should not end up here, test setup is wrong")
- }
- }
+ XCTAssertEqual(endpoint, obfuscated.endpoint)
+ XCTAssertEqual(.off, obfuscated.method)
}
}