blob: 6bae2823689682fe30d506a896ee4813b26b0a53 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
//
// ObfuscationMethodSelector.swift
// MullvadREST
//
// Created by Jon Petersson on 2024-11-01.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import MullvadSettings
import MullvadTypes
public protocol ObfuscationProviding {
func bypassUnsupportedObfuscation(_: WireGuardObfuscationState) -> WireGuardObfuscationState
}
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,
obfuscationBypass: any ObfuscationProviding
) -> WireGuardObfuscationState {
if tunnelSettings.wireGuardObfuscation.state == .automatic {
let selectedObfuscation: WireGuardObfuscationState =
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
}
return obfuscationBypass.bypassUnsupportedObfuscation(selectedObfuscation)
}
return tunnelSettings.wireGuardObfuscation.state
}
}
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
}
}
|