Skip to content

Commit

Permalink
Apply the obfuscation port to the entry configuration only
Browse files Browse the repository at this point in the history
  • Loading branch information
rablador committed Nov 19, 2024
1 parent 2a0f20f commit 7432679
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 44 deletions.
20 changes: 12 additions & 8 deletions ios/MullvadREST/Relay/MultihopDecisionFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ protocol MultihopDecisionFlow {
struct OneToOne: MultihopDecisionFlow {
let next: MultihopDecisionFlow?
let relayPicker: RelayPicking

init(next: (any MultihopDecisionFlow)?, relayPicker: RelayPicking) {
self.next = next
self.relayPicker = relayPicker
Expand All @@ -47,10 +48,11 @@ struct OneToOne: MultihopDecisionFlow {
throw NoRelaysSatisfyingConstraintsError(.entryEqualsExit)
}

let exitMatch = try relayPicker.findBestMatch(from: exitCandidates)
let exitMatch = try relayPicker.findBestMatch(from: exitCandidates, obfuscate: false)
let entryMatch = try relayPicker.findBestMatch(
from: entryCandidates,
closeTo: daitaAutomaticRouting ? exitMatch.location : nil
closeTo: daitaAutomaticRouting ? exitMatch.location : nil,
obfuscate: true
)

return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
Expand Down Expand Up @@ -95,8 +97,8 @@ struct OneToMany: MultihopDecisionFlow {
.pick(entryCandidates: entryCandidates, exitCandidates: exitCandidates, daitaAutomaticRouting: true)
}

let entryMatch = try multihopPicker.findBestMatch(from: entryCandidates)
let exitMatch = try multihopPicker.exclude(relay: entryMatch, from: exitCandidates)
let entryMatch = try multihopPicker.findBestMatch(from: entryCandidates, obfuscate: true)
let exitMatch = try multihopPicker.exclude(relay: entryMatch, from: exitCandidates, obfuscate: false)

return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
}
Expand Down Expand Up @@ -135,11 +137,12 @@ struct ManyToOne: MultihopDecisionFlow {
)
}

let exitMatch = try multihopPicker.findBestMatch(from: exitCandidates)
let exitMatch = try multihopPicker.findBestMatch(from: exitCandidates, obfuscate: false)
let entryMatch = try multihopPicker.exclude(
relay: exitMatch,
from: entryCandidates,
closeTo: daitaAutomaticRouting ? exitMatch.location : nil
closeTo: daitaAutomaticRouting ? exitMatch.location : nil,
obfuscate: true
)

return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
Expand Down Expand Up @@ -179,11 +182,12 @@ struct ManyToMany: MultihopDecisionFlow {
)
}

let exitMatch = try multihopPicker.findBestMatch(from: exitCandidates)
let exitMatch = try multihopPicker.findBestMatch(from: exitCandidates, obfuscate: false)
let entryMatch = try multihopPicker.exclude(
relay: exitMatch,
from: entryCandidates,
closeTo: daitaAutomaticRouting ? exitMatch.location : nil
closeTo: daitaAutomaticRouting ? exitMatch.location : nil,
obfuscate: true
)

return SelectedRelays(entry: entryMatch, exit: exitMatch, retryAttempt: relayPicker.connectionAttemptCount)
Expand Down
6 changes: 3 additions & 3 deletions ios/MullvadREST/Relay/ObfuscatorPortSelector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import MullvadSettings
import MullvadTypes

struct ObfuscatorPortSelectorResult {
struct ObfuscatorPortSelection {
let relays: REST.ServerRelaysResponse
let port: RelayConstraint<UInt16>
}
Expand All @@ -20,7 +20,7 @@ struct ObfuscatorPortSelector {
func obfuscate(
tunnelSettings: LatestTunnelSettings,
connectionAttemptCount: UInt
) throws -> ObfuscatorPortSelectorResult {
) throws -> ObfuscatorPortSelection {
var relays = relays
var port = tunnelSettings.relayConstraints.port
let obfuscationMethod = ObfuscationMethodSelector.obfuscationMethodBy(
Expand All @@ -44,7 +44,7 @@ struct ObfuscatorPortSelector {
break
}

return ObfuscatorPortSelectorResult(relays: relays, port: port)
return ObfuscatorPortSelection(relays: relays, port: port)
}

private func obfuscateShadowsocksRelays(tunnelSettings: LatestTunnelSettings) -> REST.ServerRelaysResponse {
Expand Down
27 changes: 19 additions & 8 deletions ios/MullvadREST/Relay/RelayPicking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import MullvadSettings
import MullvadTypes

protocol RelayPicking {
var obfuscation: ObfuscatorPortSelection { get }
var relays: REST.ServerRelaysResponse { get }
var constraints: RelayConstraints { get }
var connectionAttemptCount: UInt { get }
Expand All @@ -20,12 +21,13 @@ protocol RelayPicking {
extension RelayPicking {
func findBestMatch(
from candidates: [RelayWithLocation<REST.ServerRelay>],
closeTo location: Location? = nil
closeTo location: Location? = nil,
obfuscate: Bool
) throws -> SelectedRelay {
let match = try RelaySelector.WireGuard.pickCandidate(
from: candidates,
relays: relays,
portConstraint: constraints.port,
portConstraint: obfuscate ? obfuscation.port : constraints.port,
numberOfFailedAttempts: connectionAttemptCount,
closeTo: location
)
Expand All @@ -39,11 +41,15 @@ extension RelayPicking {
}

struct SinglehopPicker: RelayPicking {
let relays: REST.ServerRelaysResponse
let obfuscation: ObfuscatorPortSelection
let constraints: RelayConstraints
let connectionAttemptCount: UInt
let daitaSettings: DAITASettings

var relays: REST.ServerRelaysResponse {
obfuscation.relays
}

func pick() throws -> SelectedRelays {
do {
let exitCandidates = try RelaySelector.WireGuard.findCandidates(
Expand All @@ -53,14 +59,14 @@ struct SinglehopPicker: RelayPicking {
daitaEnabled: daitaSettings.daitaState.isEnabled
)

let match = try findBestMatch(from: exitCandidates)
let match = try findBestMatch(from: exitCandidates, obfuscate: true)
return SelectedRelays(entry: nil, exit: match, retryAttempt: connectionAttemptCount)
} catch let error as NoRelaysSatisfyingConstraintsError where error.reason == .noDaitaRelaysFound {
// If DAITA is on and Direct only is off, and no supported relays are found, we should try to find the nearest
// available relay that supports DAITA and use it as entry in a multihop selection.
if daitaSettings.isAutomaticRouting {
return try MultihopPicker(
relays: relays,
obfuscation: obfuscation,
constraints: constraints,
connectionAttemptCount: connectionAttemptCount,
daitaSettings: daitaSettings
Expand All @@ -73,11 +79,15 @@ struct SinglehopPicker: RelayPicking {
}

struct MultihopPicker: RelayPicking {
let relays: REST.ServerRelaysResponse
let obfuscation: ObfuscatorPortSelection
let constraints: RelayConstraints
let connectionAttemptCount: UInt
let daitaSettings: DAITASettings

var relays: REST.ServerRelaysResponse {
obfuscation.relays
}

func pick() throws -> SelectedRelays {
let exitCandidates = try RelaySelector.WireGuard.findCandidates(
by: constraints.exitLocations,
Expand Down Expand Up @@ -129,12 +139,13 @@ struct MultihopPicker: RelayPicking {
func exclude(
relay: SelectedRelay,
from candidates: [RelayWithLocation<REST.ServerRelay>],
closeTo location: Location? = nil
closeTo location: Location? = nil,
obfuscate: Bool
) throws -> SelectedRelay {
let filteredCandidates = candidates.filter { relayWithLocation in
relayWithLocation.relay.hostname != relay.hostname
}

return try findBestMatch(from: filteredCandidates, closeTo: location)
return try findBestMatch(from: filteredCandidates, closeTo: location, obfuscate: obfuscate)
}
}
13 changes: 5 additions & 8 deletions ios/MullvadREST/Relay/RelaySelectorWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,25 @@ public final class RelaySelectorWrapper: RelaySelectorProtocol {
tunnelSettings: LatestTunnelSettings,
connectionAttemptCount: UInt
) throws -> SelectedRelays {
let obfuscationResult = try ObfuscatorPortSelector(
let obfuscation = try ObfuscatorPortSelector(
relays: try relayCache.read().relays
).obfuscate(
tunnelSettings: tunnelSettings,
connectionAttemptCount: connectionAttemptCount
)

var constraints = tunnelSettings.relayConstraints
constraints.port = obfuscationResult.port

return switch tunnelSettings.tunnelMultihopState {
case .off:
try SinglehopPicker(
relays: obfuscationResult.relays,
constraints: constraints,
obfuscation: obfuscation,
constraints: tunnelSettings.relayConstraints,
connectionAttemptCount: connectionAttemptCount,
daitaSettings: tunnelSettings.daita
).pick()
case .on:
try MultihopPicker(
relays: obfuscationResult.relays,
constraints: constraints,
obfuscation: obfuscation,
constraints: tunnelSettings.relayConstraints,
connectionAttemptCount: connectionAttemptCount,
daitaSettings: tunnelSettings.daita
).pick()
Expand Down
4 changes: 1 addition & 3 deletions ios/MullvadSettings/TunnelSettingsStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ public struct TunnelSettingsStrategy: TunnelSettingsStrategyProtocol {
newSettings: LatestTunnelSettings
) -> Bool {
switch (oldSettings, newSettings) {
case let (old, new) where old.relayConstraints != new.relayConstraints,
let (old, new) where old.tunnelMultihopState != new.tunnelMultihopState,
let (old, new) where old.daita != new.daita:
case let (old, new) where old != new:
true
default:
false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,16 @@ class MultihopDecisionFlowTests: XCTestCase {

extension MultihopDecisionFlowTests {
var picker: MultihopPicker {
let obfuscation = try? ObfuscatorPortSelector(relays: sampleRelays)
.obfuscate(tunnelSettings: LatestTunnelSettings(), connectionAttemptCount: 0)

let constraints = RelayConstraints(
entryLocations: .only(UserSelectedRelays(locations: [.city("se", "sto")])),
exitLocations: .only(UserSelectedRelays(locations: [.city("se", "sto")]))
)

return MultihopPicker(
relays: sampleRelays,
obfuscation: obfuscation.unsafelyUnwrapped,
constraints: constraints,
connectionAttemptCount: 0,
daitaSettings: DAITASettings(daitaState: .off)
Expand Down
Loading

0 comments on commit 7432679

Please sign in to comment.