Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DAITA into TunnelSettings #6605

Merged
merged 1 commit into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,14 @@ import WireGuardKitTypes

/// Relay selector stub that accepts a block that can be used to provide custom implementation.
public final class RelaySelectorStub: RelaySelectorProtocol {
var selectedRelaysResult: (RelayConstraints, UInt) throws -> SelectedRelays
var selectedRelaysResult: (UInt) throws -> SelectedRelays

init(selectedRelaysResult: @escaping (RelayConstraints, UInt) throws -> SelectedRelays) {
init(selectedRelaysResult: @escaping (UInt) throws -> SelectedRelays) {
self.selectedRelaysResult = selectedRelaysResult
}

public func selectRelays(
with constraints: RelayConstraints,
connectionAttemptCount: UInt
) throws -> SelectedRelays {
return try selectedRelaysResult(constraints, connectionAttemptCount)
public func selectRelays(connectionAttemptCount: UInt) throws -> SelectedRelays {
return try selectedRelaysResult(connectionAttemptCount)
}
}

Expand All @@ -31,7 +28,7 @@ extension RelaySelectorStub {
public static func nonFallible() -> RelaySelectorStub {
let publicKey = PrivateKey().publicKey.rawValue

return RelaySelectorStub { _, _ in
return RelaySelectorStub { _ in
let cityRelay = SelectedRelay(
endpoint: MullvadEndpoint(
ipv4Relay: IPv4Endpoint(ip: .loopback, port: 1300),
Expand Down Expand Up @@ -60,7 +57,7 @@ extension RelaySelectorStub {

/// Returns a relay selector that cannot satisfy constraints .
public static func unsatisfied() -> RelaySelectorStub {
return RelaySelectorStub { _, _ in
return RelaySelectorStub { _ in
throw NoRelaysSatisfyingConstraintsError()
}
}
Expand Down
3 changes: 2 additions & 1 deletion ios/MullvadREST/Relay/RelaySelectorProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
//

import Foundation
import MullvadSettings
import MullvadTypes

/// Protocol describing a type that can select a relay.
public protocol RelaySelectorProtocol {
func selectRelays(with constraints: RelayConstraints, connectionAttemptCount: UInt) throws -> SelectedRelays
func selectRelays(connectionAttemptCount: UInt) throws -> SelectedRelays
}

/// Struct describing the selected relay.
Expand Down
26 changes: 13 additions & 13 deletions ios/MullvadREST/Relay/RelaySelectorWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,51 @@ import MullvadTypes

public final class RelaySelectorWrapper: RelaySelectorProtocol {
let relayCache: RelayCacheProtocol
let multihopUpdater: MultihopUpdater
private var multihopState: MultihopState = .off
private var observer: MultihopObserverBlock!

let tunnelSettingsUpdater: SettingsUpdater
private var tunnelSettings = LatestTunnelSettings()
private var observer: SettingsObserverBlock!

deinit {
self.multihopUpdater.removeObserver(observer)
self.tunnelSettingsUpdater.removeObserver(observer)
}

public init(
relayCache: RelayCacheProtocol,
multihopUpdater: MultihopUpdater
tunnelSettingsUpdater: SettingsUpdater
) {
self.relayCache = relayCache
self.multihopUpdater = multihopUpdater
self.tunnelSettingsUpdater = tunnelSettingsUpdater

self.addObserver()
}

public func selectRelays(
with constraints: RelayConstraints,
connectionAttemptCount: UInt
) throws -> SelectedRelays {
let relays = try relayCache.read().relays

switch multihopState {
switch tunnelSettings.tunnelMultihopState {
case .off:
return try SinglehopPicker(
constraints: constraints,
constraints: tunnelSettings.relayConstraints,
relays: relays,
connectionAttemptCount: connectionAttemptCount
).pick()
case .on:
return try MultihopPicker(
constraints: constraints,
constraints: tunnelSettings.relayConstraints,
relays: relays,
connectionAttemptCount: connectionAttemptCount
).pick()
}
}

private func addObserver() {
self.observer = MultihopObserverBlock(didUpdateMultihop: { [weak self] _, multihopState in
self?.multihopState = multihopState
self.observer = SettingsObserverBlock(didUpdateSettings: { [weak self] latestTunnelSettings in
self?.tunnelSettings = latestTunnelSettings
})

multihopUpdater.addObserver(observer)
tunnelSettingsUpdater.addObserver(observer)
}
}
51 changes: 23 additions & 28 deletions ios/MullvadREST/Transport/Shadowsocks/ShadowsocksLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,42 @@ public protocol ShadowsocksLoaderProtocol {
public class ShadowsocksLoader: ShadowsocksLoaderProtocol {
let cache: ShadowsocksConfigurationCacheProtocol
let relaySelector: ShadowsocksRelaySelectorProtocol
let constraintsUpdater: RelayConstraintsUpdater
let multihopUpdater: MultihopUpdater
private var multihopState: MultihopState = .off
private var observer: MultihopObserverBlock!
let settingsUpdater: SettingsUpdater

private var observer: SettingsObserverBlock!
private var tunnelSettings = LatestTunnelSettings()
private let settingsStrategy = TunnelSettingsStrategy()

deinit {
self.multihopUpdater.removeObserver(observer)
self.settingsUpdater.removeObserver(observer)
}

private var relayConstraints = RelayConstraints()

public init(
cache: ShadowsocksConfigurationCacheProtocol,
relaySelector: ShadowsocksRelaySelectorProtocol,
constraintsUpdater: RelayConstraintsUpdater,
multihopUpdater: MultihopUpdater
settingsUpdater: SettingsUpdater
) {
self.cache = cache
self.relaySelector = relaySelector
self.constraintsUpdater = constraintsUpdater
self.multihopUpdater = multihopUpdater
self.settingsUpdater = settingsUpdater
self.addObservers()
}

private func addObservers() {
// The constraints gets updated a lot when observing the tunnel, clear the cache if the constraints have changed.
constraintsUpdater.onNewConstraints = { [weak self] newConstraints in
if self?.relayConstraints != newConstraints {
self?.relayConstraints = newConstraints
try? self?.clear()
}
}

// The multihop state gets updated a lot when observing the tunnel, clear the cache if the multihop settings have changed.
self.observer = MultihopObserverBlock(didUpdateMultihop: { [weak self] _, newMultihopState in
if self?.multihopState != newMultihopState {
self?.multihopState = newMultihopState
try? self?.clear()
}
})
multihopUpdater.addObserver(self.observer)
observer =
SettingsObserverBlock(
didUpdateSettings: { [weak self] latestTunnelSettings in
guard let self else { return }
if settingsStrategy.shouldReconnectToNewRelay(
oldSettings: tunnelSettings,
newSettings: latestTunnelSettings
) {
try? clear()
}
tunnelSettings = latestTunnelSettings
}
)
settingsUpdater.addObserver(self.observer)
}

public func clear() throws {
Expand All @@ -81,7 +76,7 @@ public class ShadowsocksLoader: ShadowsocksLoaderProtocol {
/// Returns a randomly selected shadowsocks configuration.
private func create() throws -> ShadowsocksConfiguration {
let bridgeConfiguration = try relaySelector.getBridges()
let closestRelay = try relaySelector.selectRelay(with: relayConstraints, multihopState: multihopState)
let closestRelay = try relaySelector.selectRelay(with: tunnelSettings)

guard let bridgeAddress = closestRelay?.ipv4AddrIn,
let bridgeConfiguration else { throw POSIXError(.ENOENT) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ import MullvadSettings
import MullvadTypes

public protocol ShadowsocksRelaySelectorProtocol {
func selectRelay(
with constraints: RelayConstraints,
multihopState: MultihopState
) throws -> REST.BridgeRelay?
func selectRelay(with settings: LatestTunnelSettings) throws -> REST.BridgeRelay?

func getBridges() throws -> REST.ServerShadowsocks?
}
Expand All @@ -28,21 +25,18 @@ final public class ShadowsocksRelaySelector: ShadowsocksRelaySelectorProtocol {
self.relayCache = relayCache
}

public func selectRelay(
with constraints: RelayConstraints,
multihopState: MultihopState
) throws -> REST.BridgeRelay? {
public func selectRelay(with settings: LatestTunnelSettings) throws -> REST.BridgeRelay? {
let cachedRelays = try relayCache.read().relays

let locationConstraint = switch multihopState {
case .on: constraints.entryLocations
case .off: constraints.exitLocations
let locationConstraint = switch settings.tunnelMultihopState {
case .on: settings.relayConstraints.entryLocations
case .off: settings.relayConstraints.exitLocations
}

return RelaySelector.Shadowsocks.closestRelay(
location: locationConstraint,
port: constraints.port,
filter: constraints.filter,
port: settings.relayConstraints.port,
filter: settings.relayConstraints.filter,
in: cachedRelays
)
}
Expand Down
27 changes: 27 additions & 0 deletions ios/MullvadSettings/DAITASettings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// DAITASettings.swift
// MullvadSettings
//
// Created by Mojgan on 2024-08-08.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import Foundation

/// Whether DAITA is enabled
public enum DAITAState: Codable {
case on
case off

public var isEnabled: Bool {
self == .on
}
}

public struct DAITASettings: Codable, Equatable {
public let state: DAITAState

public init(state: DAITAState = .off) {
self.state = state
}
}
56 changes: 0 additions & 56 deletions ios/MullvadSettings/MultihopSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,6 @@
import Foundation
import MullvadTypes

public protocol MultihopPropagation {
typealias MultihopHandler = (MultihopState) -> Void
var onNewMultihop: MultihopHandler? { get set }
}

public protocol MultihopObserver: AnyObject {
func multihop(_ object: MultihopPropagation, didUpdateMultihop state: MultihopState)
}

public class MultihopObserverBlock: MultihopObserver {
public typealias DidUpdateMultihopHandler = (MultihopPropagation, MultihopState) -> Void
public var onNewState: DidUpdateMultihopHandler

public init(didUpdateMultihop: @escaping DidUpdateMultihopHandler) {
self.onNewState = didUpdateMultihop
}

public func multihop(_ object: MultihopPropagation, didUpdateMultihop state: MultihopState) {
self.onNewState(object, state)
}
}

public final class MultihopStateListener: MultihopPropagation {
public var onNewMultihop: MultihopHandler?

public init(onNewMultihop: MultihopHandler? = nil) {
self.onNewMultihop = onNewMultihop
}
}

public class MultihopUpdater {
/// Observers.
private let observerList = ObserverList<MultihopObserver>()
private var listener: MultihopPropagation

public init(listener: MultihopPropagation) {
self.listener = listener
self.listener.onNewMultihop = { [weak self] state in
guard let self else { return }
self.observerList.notify {
$0.multihop(listener, didUpdateMultihop: state)
}
}
}

// MARK: - Multihop observations

public func addObserver(_ observer: MultihopObserver) {
observerList.append(observer)
}

public func removeObserver(_ observer: MultihopObserver) {
observerList.remove(observer)
}
}

/// Whether Multi-hop is enabled
public enum MultihopState: Codable {
case on
Expand Down
11 changes: 8 additions & 3 deletions ios/MullvadSettings/TunnelSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

/// Alias to the latest version of the `TunnelSettings`.
public typealias LatestTunnelSettings = TunnelSettingsV5
public typealias LatestTunnelSettings = TunnelSettingsV6

/// Protocol all TunnelSettings must adhere to, for upgrade purposes.
public protocol TunnelSettings: Codable {
Expand All @@ -33,13 +33,17 @@ public enum SchemaVersion: Int, Equatable {
/// V4 format with multi-hop options, stored as `TunnelSettingsV5`.
case v5 = 5

/// V5 format with DAITA settings, stored as `TunnelSettingsV6`.
case v6 = 6

var settingsType: any TunnelSettings.Type {
switch self {
case .v1: return TunnelSettingsV1.self
case .v2: return TunnelSettingsV2.self
case .v3: return TunnelSettingsV3.self
case .v4: return TunnelSettingsV4.self
case .v5: return TunnelSettingsV5.self
case .v6: return TunnelSettingsV6.self
}
}

Expand All @@ -49,10 +53,11 @@ public enum SchemaVersion: Int, Equatable {
case .v2: return .v3
case .v3: return .v4
case .v4: return .v5
case .v5: return .v5
case .v5: return .v6
case .v6: return .v6
}
}

/// Current schema version.
public static let current = SchemaVersion.v5
public static let current = SchemaVersion.v6
}
Loading
Loading