Skip to content

Commit

Permalink
Add DAITA into TunnelSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
mojganii authored and buggmagnet committed Aug 15, 2024
1 parent 1283882 commit bdfd397
Show file tree
Hide file tree
Showing 34 changed files with 449 additions and 349 deletions.
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

0 comments on commit bdfd397

Please sign in to comment.