diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2019-12-04 12:13:13 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2019-12-04 18:55:19 +0100 |
| commit | dd4ce2c1acd786bc896a32388062941d7007cd6d (patch) | |
| tree | 73607dca29e2e1144ae248a13c196b715e778c34 /ios/MullvadVPN | |
| parent | 0ad5a7b18853d0abfb873553082515a0c0e259ad (diff) | |
| download | mullvadvpn-dd4ce2c1acd786bc896a32388062941d7007cd6d.tar.xz mullvadvpn-dd4ce2c1acd786bc896a32388062941d7007cd6d.zip | |
Add naive relay selector
Diffstat (limited to 'ios/MullvadVPN')
| -rw-r--r-- | ios/MullvadVPN/MullvadEndpoint.swift | 19 | ||||
| -rw-r--r-- | ios/MullvadVPN/RelaySelector+RelayCache.swift | 21 | ||||
| -rw-r--r-- | ios/MullvadVPN/RelaySelector.swift | 129 |
3 files changed, 169 insertions, 0 deletions
diff --git a/ios/MullvadVPN/MullvadEndpoint.swift b/ios/MullvadVPN/MullvadEndpoint.swift new file mode 100644 index 0000000000..e61fea7475 --- /dev/null +++ b/ios/MullvadVPN/MullvadEndpoint.swift @@ -0,0 +1,19 @@ +// +// MullvadEndpoint.swift +// MullvadVPN +// +// Created by pronebird on 12/06/2019. +// Copyright © 2019 Amagicom AB. All rights reserved. +// + +import Foundation +import Network + +/// Contains server data needed to connect to a single mullvad endpoint +struct MullvadEndpoint { + let ipv4Relay: NWEndpoint + let ipv6Relay: NWEndpoint? + let ipv4Gateway: IPv4Address + let ipv6Gateway: IPv6Address + let publicKey: Data +} diff --git a/ios/MullvadVPN/RelaySelector+RelayCache.swift b/ios/MullvadVPN/RelaySelector+RelayCache.swift new file mode 100644 index 0000000000..b82507ba23 --- /dev/null +++ b/ios/MullvadVPN/RelaySelector+RelayCache.swift @@ -0,0 +1,21 @@ +// +// RelaySelector+RelayCache.swift +// MullvadVPN +// +// Created by pronebird on 07/11/2019. +// Copyright © 2019 Amagicom AB. All rights reserved. +// + +import Combine +import Foundation + +extension RelaySelector { + + static func loadedFromRelayCache() -> AnyPublisher<RelaySelector, RelayCacheError> { + return RelayCache.withDefaultLocation().publisher + .flatMap { $0.read() } + .map { RelaySelector(relayList: $0.relayList) } + .eraseToAnyPublisher() + } + +} diff --git a/ios/MullvadVPN/RelaySelector.swift b/ios/MullvadVPN/RelaySelector.swift new file mode 100644 index 0000000000..255502446c --- /dev/null +++ b/ios/MullvadVPN/RelaySelector.swift @@ -0,0 +1,129 @@ +// +// RelaySelector.swift +// PacketTunnel +// +// Created by pronebird on 11/06/2019. +// Copyright © 2019 Amagicom AB. All rights reserved. +// + +import Foundation +import Network + +struct RelaySelectorResult { + var relay: RelayList.Hostname + var tunnel: RelayList.WireguardTunnel + var endpoint: MullvadEndpoint +} + +struct RelaySelector { + + private let relayList: RelayList + + init(relayList: RelayList) { + self.relayList = relayList + } + + /// Produce a `RelayList` satisfying the given constraints + private func applyConstraints(_ constraints: RelayConstraints) -> RelayList { + let filteredCountries = relayList.countries.filter { (country) -> Bool in + switch constraints.location { + case .any: + return true + case .only(let constraint): + switch constraint { + case .country(let countryCode): + return countryCode == country.code + case .city(let countryCode, _): + return countryCode == country.code + case .hostname(let countryCode, _, _): + return countryCode == country.code + } + } + }.map { (country) -> RelayList.Country in + var filteredCountry = country + filteredCountry.cities = country.cities.filter { (city) -> Bool in + switch constraints.location { + case .any: + return true + case .only(let constraint): + switch constraint { + case .country: + return true + case .city(_, let cityCode): + return cityCode == city.code + case .hostname(_, let cityCode, _): + return cityCode == city.code + } + } + }.map { (city) -> RelayList.City in + var filteredCity = city + filteredCity.relays = city.relays.filter { (relay) -> Bool in + switch constraints.location { + case .any: + return true + case .only(let constraint): + switch constraint { + case .country, .city: + return true + case .hostname(_, _, let hostname): + return hostname == relay.hostname + } + } + } + .map({ (relay) -> RelayList.Hostname in + var filteredRelay = relay + filteredRelay.tunnels?.wireguard = relay.tunnels?.wireguard? + .filter { !$0.portRanges.isEmpty } + + return filteredRelay + }).filter { (relay) -> Bool in + guard let wireguardTunnels = relay.tunnels?.wireguard else { return false } + + return relay.active && !wireguardTunnels.isEmpty + } + + return filteredCity + }.filter({ (city) -> Bool in + return !city.relays.isEmpty + }) + + return filteredCountry + }.filter { (country) -> Bool in + return !country.cities.isEmpty + } + + return RelayList(countries: filteredCountries) + } + + func evaluate(with constraints: RelayConstraints) -> RelaySelectorResult? { + let filteredRelayList = applyConstraints(constraints) + + guard let randomRelay = filteredRelayList.countries.randomElement()? + .cities.randomElement()? + .relays.randomElement() else { + return nil + } + + guard let randomTunnel = randomRelay.tunnels?.wireguard?.randomElement() else { + return nil + } + + guard let randomPort = randomTunnel.portRanges.randomElement()?.randomElement() else { + return nil + } + + let networkPort = NWEndpoint.Port(integerLiteral: randomPort) + let ipv4Endpoint = NWEndpoint.hostPort(host: .ipv4(randomRelay.ipv4AddrIn), port: networkPort) + + let endpoint = MullvadEndpoint( + ipv4Relay: ipv4Endpoint, + ipv6Relay: nil, + ipv4Gateway: randomTunnel.ipv4Gateway, + ipv6Gateway: randomTunnel.ipv6Gateway, + publicKey: randomTunnel.publicKey + ) + + return RelaySelectorResult(relay: randomRelay, tunnel: randomTunnel, endpoint: endpoint) + } + +} |
