diff options
6 files changed, 48 insertions, 25 deletions
diff --git a/ios/PacketTunnelCore/Actor/ObservedState.swift b/ios/PacketTunnelCore/Actor/ObservedState.swift index 5aece77e56..83ea8f96a5 100644 --- a/ios/PacketTunnelCore/Actor/ObservedState.swift +++ b/ios/PacketTunnelCore/Actor/ObservedState.swift @@ -9,6 +9,7 @@ import Combine import Foundation import MullvadREST +import MullvadSettings import MullvadTypes import Network @preconcurrency import WireGuardKitTypes @@ -36,6 +37,7 @@ public struct ObservedConnectionState: Equatable, Codable, Sendable { public var lastKeyRotation: Date? public let isPostQuantum: Bool public let isDaitaEnabled: Bool + public let obfuscationMethod: WireGuardObfuscationState public var isNetworkReachable: Bool { networkReachability != .unreachable @@ -50,7 +52,8 @@ public struct ObservedConnectionState: Equatable, Codable, Sendable { remotePort: UInt16, lastKeyRotation: Date? = nil, isPostQuantum: Bool, - isDaitaEnabled: Bool + isDaitaEnabled: Bool, + obfuscationMethod: WireGuardObfuscationState = .off ) { self.selectedRelays = selectedRelays self.relayConstraints = relayConstraints @@ -61,6 +64,7 @@ public struct ObservedConnectionState: Equatable, Codable, Sendable { self.lastKeyRotation = lastKeyRotation self.isPostQuantum = isPostQuantum self.isDaitaEnabled = isDaitaEnabled + self.obfuscationMethod = obfuscationMethod } } @@ -111,7 +115,8 @@ extension State.ConnectionData { remotePort: remotePort, lastKeyRotation: lastKeyRotation, isPostQuantum: isPostQuantum, - isDaitaEnabled: isDaitaEnabled + isDaitaEnabled: isDaitaEnabled, + obfuscationMethod: obfuscationMethod ) } } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index e55cf1e8cb..bf4feac3c1 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -402,7 +402,8 @@ extension PacketTunnelActor { transportLayer: .udp, remotePort: connectedRelay.endpoint.ipv4Relay.port, isPostQuantum: settings.quantumResistance.isEnabled, - isDaitaEnabled: settings.daita.daitaState.isEnabled + isDaitaEnabled: settings.daita.daitaState.isEnabled, + obfuscationMethod: .off ) case .disconnecting, .disconnected: return nil @@ -426,7 +427,7 @@ extension PacketTunnelActor { guard let connectionState = try makeConnectionState(nextRelays: nextRelays, settings: settings, reason: reason) else { return nil } - let obfuscatedEndpoint = protocolObfuscator.obfuscate( + let obfuscated = protocolObfuscator.obfuscate( connectionState.connectedEndpoint, settings: settings.tunnelSettings, retryAttempts: connectionState.selectedRelays.retryAttempt @@ -441,11 +442,12 @@ extension PacketTunnelActor { networkReachability: connectionState.networkReachability, connectionAttemptCount: connectionState.connectionAttemptCount, lastKeyRotation: connectionState.lastKeyRotation, - connectedEndpoint: obfuscatedEndpoint, + connectedEndpoint: obfuscated.endpoint, transportLayer: transportLayer, remotePort: protocolObfuscator.remotePort, isPostQuantum: settings.quantumResistance.isEnabled, - isDaitaEnabled: settings.daita.daitaState.isEnabled + isDaitaEnabled: settings.daita.daitaState.isEnabled, + obfuscationMethod: obfuscated.method ) } diff --git a/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift b/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift index ca162f0919..2a0ed7bf06 100644 --- a/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift +++ b/ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift @@ -12,8 +12,17 @@ import MullvadRustRuntime import MullvadSettings import MullvadTypes +public struct ProtocolObfuscationResult { + let endpoint: MullvadEndpoint + let method: WireGuardObfuscationState +} + public protocol ProtocolObfuscation { - func obfuscate(_ endpoint: MullvadEndpoint, settings: LatestTunnelSettings, retryAttempts: UInt) -> MullvadEndpoint + func obfuscate( + _ endpoint: MullvadEndpoint, + settings: LatestTunnelSettings, + retryAttempts: UInt + ) -> ProtocolObfuscationResult var transportLayer: TransportLayer? { get } var remotePort: UInt16 { get } } @@ -38,7 +47,7 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat _ endpoint: MullvadEndpoint, settings: LatestTunnelSettings, retryAttempts: UInt = 0 - ) -> MullvadEndpoint { + ) -> ProtocolObfuscationResult { let obfuscationMethod = ObfuscationMethodSelector.obfuscationMethodBy( connectionAttemptCount: retryAttempts, tunnelSettings: settings @@ -48,7 +57,7 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat guard obfuscationMethod != .off else { tunnelObfuscator = nil - return endpoint + return .init(endpoint: endpoint, method: .off) } // At this point, the only possible obfuscation methods should be either `.udpOverTcp` or `.shadowsocks` @@ -61,11 +70,14 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat obfuscator.start() tunnelObfuscator = obfuscator - return MullvadEndpoint( - ipv4Relay: IPv4Endpoint(ip: .loopback, port: obfuscator.localUdpPort), - ipv4Gateway: endpoint.ipv4Gateway, - ipv6Gateway: endpoint.ipv6Gateway, - publicKey: endpoint.publicKey + return .init( + endpoint: MullvadEndpoint( + ipv4Relay: IPv4Endpoint(ip: .loopback, port: obfuscator.localUdpPort), + ipv4Gateway: endpoint.ipv4Gateway, + ipv6Gateway: endpoint.ipv6Gateway, + publicKey: endpoint.publicKey + ), + method: obfuscationMethod ) } } diff --git a/ios/PacketTunnelCore/Actor/State.swift b/ios/PacketTunnelCore/Actor/State.swift index 83ecd53145..3aac312490 100644 --- a/ios/PacketTunnelCore/Actor/State.swift +++ b/ios/PacketTunnelCore/Actor/State.swift @@ -9,6 +9,7 @@ import Foundation import MullvadREST import MullvadRustRuntime +import MullvadSettings import MullvadTypes @preconcurrency import WireGuardKitTypes @@ -153,6 +154,9 @@ extension State { /// True if Daita is enabled public let isDaitaEnabled: Bool + + /// The obfuscation method in force on the connection + public let obfuscationMethod: WireGuardObfuscationState } /// Data associated with error state. diff --git a/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift b/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift index 9acdf9f1d0..77087782a3 100644 --- a/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift @@ -18,8 +18,8 @@ struct ProtocolObfuscationStub: ProtocolObfuscation { _ endpoint: MullvadEndpoint, settings: LatestTunnelSettings, retryAttempts: UInt - ) -> MullvadEndpoint { - endpoint + ) -> ProtocolObfuscationResult { + .init(endpoint: endpoint, method: .off) } var transportLayer: TransportLayer? { .udp } diff --git a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift index 83491d18f8..318a451a7b 100644 --- a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift +++ b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift @@ -33,39 +33,39 @@ final class ProtocolObfuscatorTests: XCTestCase { func testObfuscateOffDoesNotChangeEndpoint() { let settings = settings(.off, obfuscationPort: .automatic) - let nonObfuscatedEndpoint = obfuscator.obfuscate(endpoint, settings: settings) + let nonObfuscated = obfuscator.obfuscate(endpoint, settings: settings) - XCTAssertEqual(endpoint, nonObfuscatedEndpoint) + XCTAssertEqual(endpoint, nonObfuscated.endpoint) } func testObfuscateUdpOverTcp() throws { let settings = settings(.udpOverTcp, obfuscationPort: .automatic) - let obfuscatedEndpoint = obfuscator.obfuscate(endpoint, settings: settings) + let obfuscated = obfuscator.obfuscate(endpoint, settings: settings) let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub) - validate(obfuscatedEndpoint, against: obfuscationProtocol) + validate(obfuscated.endpoint, against: obfuscationProtocol) } func testObfuscateShadowsocks() throws { let settings = settings(.shadowsocks, obfuscationPort: .automatic) - let obfuscatedEndpoint = obfuscator.obfuscate(endpoint, settings: settings) + let obfuscated = obfuscator.obfuscate(endpoint, settings: settings) let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub) - validate(obfuscatedEndpoint, against: obfuscationProtocol) + validate(obfuscated.endpoint, against: obfuscationProtocol) } func testObfuscateAutomatic() throws { let settings = settings(.automatic, obfuscationPort: .automatic) try (UInt(0) ... 3).forEach { attempt in - let obfuscatedEndpoint = obfuscator.obfuscate(endpoint, settings: settings, retryAttempts: attempt) + let obfuscated = obfuscator.obfuscate(endpoint, settings: settings, retryAttempts: attempt) switch attempt { case 0, 1: - XCTAssertEqual(endpoint, obfuscatedEndpoint) + XCTAssertEqual(endpoint, obfuscated.endpoint) case 2, 3: let obfuscationProtocol = try XCTUnwrap(obfuscator.tunnelObfuscator as? TunnelObfuscationStub) - validate(obfuscatedEndpoint, against: obfuscationProtocol) + validate(obfuscated.endpoint, against: obfuscationProtocol) default: XCTExpectFailure("Should not end up here, test setup is wrong") } |
