Skip to content

Commit

Permalink
Enable custom Shadowsocks port selection on entry servers in multihop
Browse files Browse the repository at this point in the history
  • Loading branch information
rablador committed Dec 3, 2024
1 parent 862b958 commit a9a0189
Show file tree
Hide file tree
Showing 12 changed files with 48 additions and 41 deletions.
26 changes: 22 additions & 4 deletions ios/MullvadREST/Relay/ObfuscatorPortSelector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ import MullvadSettings
import MullvadTypes

struct ObfuscatorPortSelection {
let relays: REST.ServerRelaysResponse
let entryRelays: REST.ServerRelaysResponse
let exitRelays: REST.ServerRelaysResponse
let port: RelayConstraint<UInt16>
let method: WireGuardObfuscationState

var wireguard: REST.ServerWireguardTunnels {
exitRelays.wireguard
}
}

struct ObfuscatorPortSelector {
Expand All @@ -22,7 +27,9 @@ struct ObfuscatorPortSelector {
tunnelSettings: LatestTunnelSettings,
connectionAttemptCount: UInt
) throws -> ObfuscatorPortSelection {
var relays = relays
var entryRelays = relays
var exitRelays = relays

var port = tunnelSettings.relayConstraints.port
let obfuscationMethod = ObfuscationMethodSelector.obfuscationMethodBy(
connectionAttemptCount: connectionAttemptCount,
Expand All @@ -36,7 +43,13 @@ struct ObfuscatorPortSelector {
connectionAttemptCount: connectionAttemptCount
)
case .shadowsocks:
relays = obfuscateShadowsocksRelays(tunnelSettings: tunnelSettings)
let filteredRelays = obfuscateShadowsocksRelays(tunnelSettings: tunnelSettings)
if tunnelSettings.tunnelMultihopState.isEnabled {
entryRelays = filteredRelays
} else {
exitRelays = filteredRelays
}

port = obfuscateShadowsocksPort(
tunnelSettings: tunnelSettings,
shadowsocksPortRanges: relays.wireguard.shadowsocksPortRanges
Expand All @@ -45,7 +58,12 @@ struct ObfuscatorPortSelector {
break
}

return ObfuscatorPortSelection(relays: relays, port: port, method: obfuscationMethod)
return ObfuscatorPortSelection(
entryRelays: entryRelays,
exitRelays: exitRelays,
port: port,
method: obfuscationMethod
)
}

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

protocol RelayPicking {
var obfuscation: ObfuscatorPortSelection { get }
var relays: REST.ServerRelaysResponse { get }
var constraints: RelayConstraints { get }
var connectionAttemptCount: UInt { get }
var daitaSettings: DAITASettings { get }
Expand All @@ -27,7 +26,7 @@ extension RelayPicking {
) throws -> SelectedRelay {
var match = try RelaySelector.WireGuard.pickCandidate(
from: candidates,
relays: relays,
wireguard: obfuscation.wireguard,
portConstraint: useObfuscatedPortIfAvailable ? obfuscation.port : constraints.port,
numberOfFailedAttempts: connectionAttemptCount,
closeTo: location
Expand All @@ -46,7 +45,7 @@ extension RelayPicking {

private func applyShadowsocksIpAddress(in match: RelaySelectorMatch) -> RelaySelectorMatch {
let port = match.endpoint.ipv4Relay.port
let portRanges = RelaySelector.parseRawPortRanges(relays.wireguard.shadowsocksPortRanges)
let portRanges = RelaySelector.parseRawPortRanges(obfuscation.wireguard.shadowsocksPortRanges)
let portIsWithinRange = portRanges.contains(where: { $0.contains(port) })

var endpoint = match.endpoint
Expand Down Expand Up @@ -76,15 +75,11 @@ struct SinglehopPicker: RelayPicking {
let connectionAttemptCount: UInt
let daitaSettings: DAITASettings

var relays: REST.ServerRelaysResponse {
obfuscation.relays
}

func pick() throws -> SelectedRelays {
do {
let exitCandidates = try RelaySelector.WireGuard.findCandidates(
by: constraints.exitLocations,
in: relays,
in: obfuscation.exitRelays,
filterConstraint: constraints.filter,
daitaEnabled: daitaSettings.daitaState.isEnabled
)
Expand Down Expand Up @@ -114,14 +109,10 @@ struct MultihopPicker: RelayPicking {
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,
in: relays,
in: obfuscation.exitRelays,
filterConstraint: constraints.filter,
daitaEnabled: false
)
Expand Down Expand Up @@ -153,7 +144,7 @@ struct MultihopPicker: RelayPicking {
do {
let entryCandidates = try RelaySelector.WireGuard.findCandidates(
by: daitaSettings.isAutomaticRouting ? .any : constraints.entryLocations,
in: relays,
in: obfuscation.entryRelays,
filterConstraint: constraints.filter,
daitaEnabled: daitaSettings.daitaState.isEnabled
)
Expand Down
16 changes: 8 additions & 8 deletions ios/MullvadREST/Relay/RelaySelector+Wireguard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ extension RelaySelector {
/// Picks a random relay from a list.
public static func pickCandidate(
from relayWithLocations: [RelayWithLocation<REST.ServerRelay>],
relays: REST.ServerRelaysResponse,
wireguard: REST.ServerWireguardTunnels,
portConstraint: RelayConstraint<UInt16>,
numberOfFailedAttempts: UInt,
closeTo referenceLocation: Location? = nil
) throws -> RelaySelectorMatch {
let port = try evaluatePort(
relays: relays,
portConstraint: portConstraint,
rawPortRanges: wireguard.portRanges,
numberOfFailedAttempts: numberOfFailedAttempts
)

Expand All @@ -54,7 +54,7 @@ extension RelaySelector {
throw NoRelaysSatisfyingConstraintsError(.relayConstraintNotMatching)
}

return createMatch(for: relayWithLocation, port: port, relays: relays)
return createMatch(for: relayWithLocation, port: port, wireguard: wireguard)
}

public static func closestRelay(
Expand Down Expand Up @@ -96,13 +96,13 @@ extension RelaySelector {
}

private static func evaluatePort(
relays: REST.ServerRelaysResponse,
portConstraint: RelayConstraint<UInt16>,
rawPortRanges: [[UInt16]],
numberOfFailedAttempts: UInt
) throws -> UInt16 {
let port = applyPortConstraint(
portConstraint,
rawPortRanges: relays.wireguard.portRanges,
rawPortRanges: rawPortRanges,
numberOfFailedAttempts: numberOfFailedAttempts
)

Expand All @@ -116,16 +116,16 @@ extension RelaySelector {
private static func createMatch(
for relayWithLocation: RelayWithLocation<REST.ServerRelay>,
port: UInt16,
relays: REST.ServerRelaysResponse
wireguard: REST.ServerWireguardTunnels
) -> RelaySelectorMatch {
let endpoint = MullvadEndpoint(
ipv4Relay: IPv4Endpoint(
ip: relayWithLocation.relay.ipv4AddrIn,
port: port
),
ipv6Relay: nil,
ipv4Gateway: relays.wireguard.ipv4Gateway,
ipv6Gateway: relays.wireguard.ipv6Gateway,
ipv4Gateway: wireguard.ipv4Gateway,
ipv6Gateway: wireguard.ipv6Gateway,
publicKey: relayWithLocation.relay.publicKey
)

Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4251,12 +4251,12 @@
7ACE19102C1C349200260BB6 /* MultihopDecisionFlow.swift */,
F0F3161A2BF358590078DBCF /* NoRelaysSatisfyingConstraintsError.swift */,
7AD63A3A2CD5278900445268 /* ObfuscationMethodSelector.swift */,
7AD63A382CD520FD00445268 /* ObfuscatorPortSelector.swift */,
5820675A26E6576800655B05 /* RelayCache.swift */,
7A3AD5002C1068A800E9AD90 /* RelayPicking.swift */,
F0DDE4282B220A15006B57A7 /* RelaySelector.swift */,
F0B894F42BF7528700817A42 /* RelaySelector+Shadowsocks.swift */,
F0B894F22BF7526700817A42 /* RelaySelector+Wireguard.swift */,
7AD63A382CD520FD00445268 /* ObfuscatorPortSelector.swift */,
5824037F2A827DF300163DE8 /* RelaySelectorProtocol.swift */,
F0F316182BF3572B0078DBCF /* RelaySelectorResult.swift */,
7AEBA5292C2179F20018BEC5 /* RelaySelectorWrapper.swift */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,12 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
}

static var wireGuardObfuscation: [Item] {
var items: [Item] = [
[
.wireGuardObfuscationAutomatic,
.wireGuardObfuscationShadowsocks,
.wireGuardObfuscationUdpOverTcp,
.wireGuardObfuscationOff,
]

return items
}

static var wireGuardObfuscationPort: [Item] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ final class ObfuscatorPortSelectorTests: XCTestCase {
!relay.shadowsocksExtraAddrIn.isNil
}

XCTAssertEqual(obfuscationResult.relays.wireguard.relays.count, relaysWithExtraAddresses.count)
XCTAssertEqual(obfuscationResult.wireguard.relays.count, relaysWithExtraAddresses.count)
}

func testObfuscateShadowsocksRelayFilteringWithPortInsideDefaultRanges() throws {
Expand All @@ -172,6 +172,6 @@ final class ObfuscatorPortSelectorTests: XCTestCase {
connectionAttemptCount: 0
)

XCTAssertEqual(obfuscationResult.relays.wireguard.relays.count, sampleRelays.wireguard.relays.count)
XCTAssertEqual(obfuscationResult.wireguard.relays.count, sampleRelays.wireguard.relays.count)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ extension RelaySelectorTests {

return try RelaySelector.WireGuard.pickCandidate(
from: candidates,
relays: relays,
wireguard: relays.wireguard,
portConstraint: constraints.port,
numberOfFailedAttempts: failedAttemptCount
)
Expand Down
2 changes: 1 addition & 1 deletion ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ final class AppMessageHandlerTests: XCTestCase {

let match = try RelaySelector.WireGuard.pickCandidate(
from: candidates,
relays: ServerRelaysResponseStubs.sampleRelays,
wireguard: ServerRelaysResponseStubs.sampleRelays.wireguard,
portConstraint: relayConstraints.port,
numberOfFailedAttempts: 0
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase {
filterConstraint: relayConstraints.filter,
daitaEnabled: false
),
relays: ServerRelaysResponseStubs.sampleRelays,
wireguard: ServerRelaysResponseStubs.sampleRelays.wireguard,
portConstraint: relayConstraints.port,
numberOfFailedAttempts: 0
)
Expand All @@ -43,7 +43,7 @@ final class EphemeralPeerExchangingPipelineTests: XCTestCase {
filterConstraint: relayConstraints.filter,
daitaEnabled: false
),
relays: ServerRelaysResponseStubs.sampleRelays,
wireguard: ServerRelaysResponseStubs.sampleRelays.wireguard,
portConstraint: relayConstraints.port,
numberOfFailedAttempts: 0
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ final class MultiHopEphemeralPeerExchangerTests: XCTestCase {
filterConstraint: relayConstraints.filter,
daitaEnabled: false
),
relays: ServerRelaysResponseStubs.sampleRelays,
wireguard: ServerRelaysResponseStubs.sampleRelays.wireguard,
portConstraint: relayConstraints.port,
numberOfFailedAttempts: 0
)
Expand All @@ -42,7 +42,7 @@ final class MultiHopEphemeralPeerExchangerTests: XCTestCase {
filterConstraint: relayConstraints.filter,
daitaEnabled: false
),
relays: ServerRelaysResponseStubs.sampleRelays,
wireguard: ServerRelaysResponseStubs.sampleRelays.wireguard,
portConstraint: relayConstraints.port,
numberOfFailedAttempts: 0
)
Expand Down
4 changes: 2 additions & 2 deletions ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ final class ProtocolObfuscatorTests: XCTestCase {
let settings = settings(.automatic, obfuscationPort: .automatic)

try (UInt(0) ... 3).forEach { attempt in
var obfuscatedEndpoint = obfuscator.obfuscate(endpoint, settings: settings, retryAttempts: attempt)
let obfuscatedEndpoint = obfuscator.obfuscate(endpoint, settings: settings, retryAttempts: attempt)

switch attempt {
case 0, 1:
XCTAssertEqual(endpoint, obfuscatedEndpoint)
case 2, 3:
var obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub)
let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub)
validate(obfuscatedEndpoint, against: obfuscationProtocol)
default:
XCTExpectFailure("Should not end up here, test setup is wrong")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ final class SingleHopEphemeralPeerExchangerTests: XCTestCase {

let match = try RelaySelector.WireGuard.pickCandidate(
from: candidates,
relays: ServerRelaysResponseStubs.sampleRelays,
wireguard: ServerRelaysResponseStubs.sampleRelays.wireguard,
portConstraint: relayConstraints.port,
numberOfFailedAttempts: 0
)
Expand Down

0 comments on commit a9a0189

Please sign in to comment.