Skip to content

Commit

Permalink
Show the correct port of the endpoint the device is connected to
Browse files Browse the repository at this point in the history
  • Loading branch information
buggmagnet committed Dec 6, 2023
1 parent 2d026de commit 8ab686c
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
relayConstraints: try SettingsManager.readSettings().relayConstraints,
networkReachability: .reachable,
connectionAttemptCount: 0,
transportLayer: .udp
transportLayer: .udp,
remotePort: selectedRelay.endpoint.ipv4Relay.port
)
)
} catch {
Expand Down
13 changes: 1 addition & 12 deletions ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,25 +145,14 @@ final class TunnelControlView: UIView {
func update(with model: TunnelControlViewModel) {
viewModel = model
let tunnelState = model.tunnelStatus.state
connectionPanel.dataSource = model.connectionPanel
secureLabel.text = model.secureLabelText
secureLabel.textColor = tunnelState.textColorForSecureLabel
selectLocationButtonBlurView.isEnabled = model.enableButtons
connectButtonBlurView.isEnabled = model.enableButtons
cityLabel.attributedText = attributedStringForLocation(string: model.city)
countryLabel.attributedText = attributedStringForLocation(string: model.country)
connectionPanel.connectedRelayName = model.connectedRelayName

if let tunnelRelay = model.tunnelStatus.state.relay {
var protocolLayer = ""
if case let .connected(state) = model.tunnelStatus.observedState {
protocolLayer = state.transportLayer == .tcp ? "TCP" : "UDP"
}
connectionPanel.dataSource = ConnectionPanelData(
inAddress: "\(tunnelRelay.endpoint.ipv4Relay) \(protocolLayer)",
outAddress: model.connectionPanel.outAddress
)
}
connectionPanel.dataSource = model.connectionPanel

updateSecureLabel(tunnelState: tunnelState)
updateActionButtons(tunnelState: tunnelState)
Expand Down
34 changes: 17 additions & 17 deletions ios/MullvadVPN/View controllers/Tunnel/TunnelControlViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,6 @@ struct TunnelControlViewModel {
self.connectedRelayName = connectedRelayName
}

init(from other: TunnelControlViewModel) {
self.init(
tunnelStatus: other.tunnelStatus,
secureLabelText: other.secureLabelText,
connectionPanel: other.connectionPanel,
enableButtons: other.enableButtons,
city: other.city,
country: other.country,
connectedRelayName: other.connectedRelayName
)
}

func update(status: TunnelStatus) -> TunnelControlViewModel {
TunnelControlViewModel(
tunnelStatus: status,
Expand All @@ -60,13 +48,25 @@ struct TunnelControlViewModel {
}

func update(outgoingConnectionInfo: OutgoingConnectionInfo) -> TunnelControlViewModel {
TunnelControlViewModel(
let inPort = tunnelStatus.observedState.connectionState?.remotePort ?? 0

var connectionPanelData = ConnectionPanelData(inAddress: "")
if let tunnelRelay = tunnelStatus.state.relay {
var protocolLayer = ""
if case let .connected(state) = tunnelStatus.observedState {
protocolLayer = state.transportLayer == .tcp ? "TCP" : "UDP"
}

connectionPanelData = ConnectionPanelData(
inAddress: "\(tunnelRelay.endpoint.ipv4Relay.ip):\(inPort) \(protocolLayer)",
outAddress: outgoingConnectionInfo.outAddress
)
}

return TunnelControlViewModel(
tunnelStatus: tunnelStatus,
secureLabelText: secureLabelText,
connectionPanel: ConnectionPanelData(
inAddress: "\(tunnelStatus.state.relay?.endpoint.ipv4Relay.description ?? "no info")",
outAddress: outgoingConnectionInfo.outAddress
),
connectionPanel: connectionPanelData,
enableButtons: enableButtons,
city: city,
country: country,
Expand Down
4 changes: 4 additions & 0 deletions ios/PacketTunnelCore/Actor/ObservedState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public struct ObservedConnectionState: Equatable, Codable {
public var networkReachability: NetworkReachability
public var connectionAttemptCount: UInt
public var transportLayer: TransportLayer
public var remotePort: UInt16
public var lastKeyRotation: Date?

public var isNetworkReachable: Bool {
Expand All @@ -41,13 +42,15 @@ public struct ObservedConnectionState: Equatable, Codable {
networkReachability: NetworkReachability,
connectionAttemptCount: UInt,
transportLayer: TransportLayer,
remotePort: UInt16,
lastKeyRotation: Date? = nil
) {
self.selectedRelay = selectedRelay
self.relayConstraints = relayConstraints
self.networkReachability = networkReachability
self.connectionAttemptCount = connectionAttemptCount
self.transportLayer = transportLayer
self.remotePort = remotePort
self.lastKeyRotation = lastKeyRotation
}
}
Expand Down Expand Up @@ -89,6 +92,7 @@ extension ConnectionState {
networkReachability: networkReachability,
connectionAttemptCount: connectionAttemptCount,
transportLayer: transportLayer,
remotePort: remotePort,
lastKeyRotation: lastKeyRotation
)
}
Expand Down
122 changes: 42 additions & 80 deletions ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -287,53 +287,56 @@ extension PacketTunnelActor {
settings: Settings,
reason: ReconnectReason
) throws -> ConnectionState? {
switch state {
case .initial:
return try makeConnectionStateInner(
var keyPolicy: KeyPolicy = .useCurrent
var networkReachability = defaultPathObserver.defaultPath?.networkReachability ?? .undetermined
var lastKeyRotation: Date?

let callRelaySelector = { [self] maybeCurrentRelay, connectionCount in
try self.selectRelay(
nextRelay: nextRelay,
settings: settings,
keyPolicy: .useCurrent,
networkReachability: defaultPathObserver.defaultPath?.networkReachability ?? .undetermined,
lastKeyRotation: nil
relayConstraints: settings.relayConstraints,
currentRelay: maybeCurrentRelay,
connectionAttemptCount: connectionCount
)
}

case var .connecting(connState), var .reconnecting(connState):
switch reason {
case .connectionLoss:
// Increment attempt counter when reconnection is requested due to connectivity loss.
connState.incrementAttemptCount()
case .userInitiated:
break
switch state {
case .initial:
break
case var .connecting(connectionState), var .reconnecting(connectionState):
if reason == .connectionLoss {
connectionState.incrementAttemptCount()
}
// Explicit fallthrough
fallthrough

case var .connected(connState):
let relayConstraints = settings.relayConstraints

connState.selectedRelay = try selectRelay(
nextRelay: nextRelay,
relayConstraints: relayConstraints,
currentRelay: connState.selectedRelay,
connectionAttemptCount: connState.connectionAttemptCount
case var .connected(connectionState):
let selectedRelay = try callRelaySelector(
connectionState.selectedRelay,
connectionState.connectionAttemptCount
)
connState.relayConstraints = relayConstraints
connState.currentKey = settings.privateKey

return connState

connectionState.selectedRelay = selectedRelay
connectionState.relayConstraints = settings.relayConstraints
connectionState.currentKey = settings.privateKey
return connectionState
case let .error(blockedState):
return try makeConnectionStateInner(
nextRelay: nextRelay,
settings: settings,
keyPolicy: blockedState.keyPolicy,
networkReachability: blockedState.networkReachability,
lastKeyRotation: blockedState.lastKeyRotation
)

keyPolicy = blockedState.keyPolicy
lastKeyRotation = blockedState.lastKeyRotation
networkReachability = blockedState.networkReachability
case .disconnecting, .disconnected:
return nil
}
let selectedRelay = try callRelaySelector(nil, 0)
return ConnectionState(
selectedRelay: selectedRelay,
relayConstraints: settings.relayConstraints,
currentKey: settings.privateKey,
keyPolicy: keyPolicy,
networkReachability: networkReachability,
connectionAttemptCount: 0,
lastKeyRotation: lastKeyRotation,
connectedEndpoint: selectedRelay.endpoint,
transportLayer: .udp,
remotePort: selectedRelay.endpoint.ipv4Relay.port
)
}

private func obfuscateConnection(
Expand All @@ -360,48 +363,8 @@ extension PacketTunnelActor {
connectionAttemptCount: connectionState.connectionAttemptCount,
lastKeyRotation: connectionState.lastKeyRotation,
connectedEndpoint: obfuscatedEndpoint,
transportLayer: transportLayer
)
}

/**
Create a connection state when `State` is either `.inital` or `.error`.

- Parameters:
- nextRelay: Next relay to connect to.
- settings: Current settings.
- keyPolicy: Current key that should be used by the tunnel.
- networkReachability: Network connectivity outside of tunnel.
- lastKeyRotation: Last time packet tunnel rotated the key.

- Returns: New connection state, or `nil` if new relay cannot be selected.
*/
private func makeConnectionStateInner(
nextRelay: NextRelay,
settings: Settings,
keyPolicy: KeyPolicy,
networkReachability: NetworkReachability,
lastKeyRotation: Date?
) throws -> ConnectionState? {
let relayConstraints = settings.relayConstraints
let privateKey = settings.privateKey

let selectedRelay = try selectRelay(
nextRelay: nextRelay,
relayConstraints: relayConstraints,
currentRelay: nil,
connectionAttemptCount: 0
)
return ConnectionState(
selectedRelay: selectedRelay,
relayConstraints: relayConstraints,
currentKey: privateKey,
keyPolicy: keyPolicy,
networkReachability: networkReachability,
connectionAttemptCount: 0,
lastKeyRotation: lastKeyRotation,
connectedEndpoint: selectedRelay.endpoint,
transportLayer: .udp
transportLayer: transportLayer,
remotePort: protocolObfuscator.remotePort
)
}

Expand Down Expand Up @@ -444,5 +407,4 @@ extension PacketTunnelActor {
}

extension PacketTunnelActor: PacketTunnelActorProtocol {}

// swiftlint:disable:this file_length
8 changes: 6 additions & 2 deletions ios/PacketTunnelCore/Actor/ProtocolObfuscator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import TunnelObfuscation
public protocol ProtocolObfuscation {
func obfuscate(_ endpoint: MullvadEndpoint, settings: Settings, retryAttempts: UInt) -> MullvadEndpoint
var transportLayer: TransportLayer? { get }
var remotePort: UInt16 { get }
}

public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscation {
Expand All @@ -30,12 +31,14 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat
/// - retryAttempts: The number of times a connection was attempted to `endpoint`
/// - Returns: `endpoint` if obfuscation is disabled, or an obfuscated endpoint otherwise.
public var transportLayer: TransportLayer? {
guard let tunnelObfuscator else { return nil }
return tunnelObfuscator.transportLayer
return tunnelObfuscator?.transportLayer
}

private(set) public var remotePort: UInt16 = 0

public func obfuscate(_ endpoint: MullvadEndpoint, settings: Settings, retryAttempts: UInt = 0) -> MullvadEndpoint {
var obfuscatedEndpoint = endpoint
remotePort = endpoint.ipv4Relay.port
let shouldObfuscate = switch settings.obfuscation.state {
case .automatic:
retryAttempts % 4 == 2 || retryAttempts % 4 == 3
Expand All @@ -57,6 +60,7 @@ public class ProtocolObfuscator<Obfuscator: TunnelObfuscation>: ProtocolObfuscat
remoteAddress: obfuscatedEndpoint.ipv4Relay.ip,
tcpPort: tcpPort.portValue
)
remotePort = tcpPort.portValue
obfuscator.start()
tunnelObfuscator = obfuscator

Expand Down
3 changes: 3 additions & 0 deletions ios/PacketTunnelCore/Actor/State.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ struct ConnectionState {
public let connectedEndpoint: MullvadEndpoint
/// Via which transport protocol was the connection made to the relay
public let transportLayer: TransportLayer

/// The remote port that was chosen to connect to `connectedEndpoint`
public let remotePort: UInt16
}

/// Data associated with error state.
Expand Down
2 changes: 2 additions & 0 deletions ios/PacketTunnelCoreTests/Mocks/ProtocolObfuscationStub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import Foundation
@testable import PacketTunnelCore

struct ProtocolObfuscationStub: ProtocolObfuscation {
var remotePort: UInt16 { 42 }

func obfuscate(_ endpoint: MullvadEndpoint, settings: Settings, retryAttempts: UInt) -> MullvadEndpoint {
endpoint
}
Expand Down
3 changes: 3 additions & 0 deletions ios/TunnelObfuscation/UDPOverTCPObfuscator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public protocol TunnelObfuscation {
func start()
func stop()
var localUdpPort: UInt16 { get }
var remotePort: UInt16 { get }

var transportLayer: TransportLayer { get }
}
Expand All @@ -35,6 +36,8 @@ public final class UDPOverTCPObfuscator: TunnelObfuscation {
return stateLock.withLock { proxyHandle.port }
}

public var remotePort: UInt16 { tcpPort }

public var transportLayer: TransportLayer { .tcp }

/// Initialize tunnel obfuscator with remote server address and TCP port where udp2tcp is running.
Expand Down

0 comments on commit 8ab686c

Please sign in to comment.