mirror of
https://github.com/passepartoutvpn/passepartout-apple.git
synced 2025-02-01 21:42:10 +00:00
Update Kit
- Move NetworkSettingsBuilder to OpenVPN/OpenSSL - Fix flaky tests
This commit is contained in:
parent
a2720d2dfc
commit
3510f2b153
@ -1 +1 @@
|
||||
Subproject commit e18a9eb1ae90d9555bd44297e230998afd6613c7
|
||||
Subproject commit 038af19bd26c08ac36569632ba25c80afcd65840
|
@ -0,0 +1,323 @@
|
||||
//
|
||||
// NetworkSettingsBuilder.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 3/16/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PassepartoutKit is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
#if !PP_FRAMEWORK
|
||||
import PassepartoutCore
|
||||
import PassepartoutOpenVPN
|
||||
#endif
|
||||
|
||||
extension OpenVPN {
|
||||
|
||||
/// Merges local and remote settings.
|
||||
///
|
||||
/// OpenVPN settings may be set locally, but may also received from a remote server. This object merges the local and remote ``OpenVPN/Configuration`` into a digestible list of `Module`.
|
||||
struct NetworkSettingsBuilder {
|
||||
|
||||
/// The client options.
|
||||
let localOptions: Configuration
|
||||
|
||||
/// The server options.
|
||||
let remoteOptions: Configuration
|
||||
|
||||
init(localOptions: Configuration, remoteOptions: Configuration) {
|
||||
self.localOptions = localOptions
|
||||
self.remoteOptions = remoteOptions
|
||||
}
|
||||
|
||||
/// A list of `Module` mapped from ``localOptions`` and ``remoteOptions``.
|
||||
func modules() -> [Module] {
|
||||
pp_log(.openvpn, .info, "Build modules from local/remote options")
|
||||
|
||||
return [
|
||||
ipModule,
|
||||
dnsModule,
|
||||
httpProxyModule
|
||||
].compactMap { $0 }
|
||||
}
|
||||
|
||||
func print() {
|
||||
pp_log(.openvpn, .notice, "Negotiated options (remote overrides local)")
|
||||
if let negCipher = remoteOptions.cipher {
|
||||
pp_log(.openvpn, .notice, "\tCipher: \(negCipher.rawValue)")
|
||||
}
|
||||
if let negFraming = remoteOptions.compressionFraming {
|
||||
pp_log(.openvpn, .notice, "\tCompression framing: \(negFraming)")
|
||||
}
|
||||
if let negCompression = remoteOptions.compressionAlgorithm {
|
||||
pp_log(.openvpn, .notice, "\tCompression algorithm: \(negCompression)")
|
||||
}
|
||||
if let negPing = remoteOptions.keepAliveInterval {
|
||||
pp_log(.openvpn, .notice, "\tKeep-alive interval: \(negPing.asTimeString)")
|
||||
}
|
||||
if let negPingRestart = remoteOptions.keepAliveTimeout {
|
||||
pp_log(.openvpn, .notice, "\tKeep-alive timeout: \(negPingRestart.asTimeString)")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Pull
|
||||
|
||||
private extension OpenVPN.NetworkSettingsBuilder {
|
||||
var pullRoutes: Bool {
|
||||
!(localOptions.noPullMask?.contains(.routes) ?? false)
|
||||
}
|
||||
|
||||
var pullDNS: Bool {
|
||||
!(localOptions.noPullMask?.contains(.dns) ?? false)
|
||||
}
|
||||
|
||||
var pullProxy: Bool {
|
||||
!(localOptions.noPullMask?.contains(.proxy) ?? false)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Overall
|
||||
|
||||
private extension OpenVPN.NetworkSettingsBuilder {
|
||||
var isGateway: Bool {
|
||||
isIPv4Gateway || isIPv6Gateway
|
||||
}
|
||||
|
||||
var routingPolicies: [OpenVPN.RoutingPolicy]? {
|
||||
pullRoutes ? (remoteOptions.routingPolicies ?? localOptions.routingPolicies) : localOptions.routingPolicies
|
||||
}
|
||||
|
||||
var isIPv4Gateway: Bool {
|
||||
routingPolicies?.contains(.IPv4) ?? false
|
||||
}
|
||||
|
||||
var isIPv6Gateway: Bool {
|
||||
routingPolicies?.contains(.IPv6) ?? false
|
||||
}
|
||||
|
||||
var allRoutes4: [Route] {
|
||||
var routes = localOptions.routes4 ?? []
|
||||
if pullRoutes, let remoteRoutes = remoteOptions.routes4 {
|
||||
routes.append(contentsOf: remoteRoutes)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
var allRoutes6: [Route] {
|
||||
var routes = localOptions.routes6 ?? []
|
||||
if pullRoutes, let remoteRoutes = remoteOptions.routes6 {
|
||||
routes.append(contentsOf: remoteRoutes)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
var allDNSServers: [String] {
|
||||
var servers = localOptions.dnsServers ?? []
|
||||
if pullDNS, let remoteServers = remoteOptions.dnsServers {
|
||||
servers.append(contentsOf: remoteServers)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
var dnsDomain: String? {
|
||||
var domain = localOptions.dnsDomain
|
||||
if pullDNS, let remoteDomain = remoteOptions.dnsDomain {
|
||||
domain = remoteDomain
|
||||
}
|
||||
return domain
|
||||
}
|
||||
|
||||
var allDNSSearchDomains: [String] {
|
||||
var searchDomains = localOptions.searchDomains ?? []
|
||||
if pullDNS, let remoteSearchDomains = remoteOptions.searchDomains {
|
||||
searchDomains.append(contentsOf: remoteSearchDomains)
|
||||
}
|
||||
return searchDomains
|
||||
}
|
||||
|
||||
var allProxyBypassDomains: [String] {
|
||||
var bypass = localOptions.proxyBypassDomains ?? []
|
||||
if pullProxy, let remoteBypass = remoteOptions.proxyBypassDomains {
|
||||
bypass.append(contentsOf: remoteBypass)
|
||||
}
|
||||
return bypass
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - IP
|
||||
|
||||
private extension OpenVPN.NetworkSettingsBuilder {
|
||||
|
||||
// IPv4/6 address/mask MUST come from server options
|
||||
// routes, instead, can both come from server and local options
|
||||
|
||||
var ipModule: Module? {
|
||||
let ipv4 = ipv4Settings
|
||||
let ipv6 = ipv6Settings
|
||||
let mtu: Int?
|
||||
if let localMTU = localOptions.mtu, localMTU > 0 {
|
||||
mtu = localMTU
|
||||
} else {
|
||||
mtu = nil
|
||||
}
|
||||
guard ipv4 != nil || ipv6 != nil || mtu != nil else {
|
||||
return nil
|
||||
}
|
||||
return IPModule.Builder(
|
||||
ipv4: ipv4,
|
||||
ipv6: ipv6,
|
||||
mtu: mtu
|
||||
).tryBuild()
|
||||
}
|
||||
|
||||
var ipv4Settings: IPSettings? {
|
||||
guard let ipv4 = remoteOptions.ipv4 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepend main routes
|
||||
var target = allRoutes4
|
||||
target.insert(contentsOf: ipv4.includedRoutes, at: 0)
|
||||
|
||||
let routes: [Route] = target.compactMap { route in
|
||||
let ipv4Route = Route(route.destination, route.gateway)
|
||||
if route.destination == nil {
|
||||
guard isIPv4Gateway, let gw = route.gateway else {
|
||||
return nil
|
||||
}
|
||||
pp_log(.openvpn, .info, "\tIPv4: Set default gateway to \(gw)")
|
||||
} else {
|
||||
pp_log(.openvpn, .info, "\tIPv4: Add route \(route.destination?.description ?? "default") -> \(route.gateway?.description ?? "*")")
|
||||
}
|
||||
return ipv4Route
|
||||
}
|
||||
return ipv4.including(routes: routes)
|
||||
}
|
||||
|
||||
var ipv6Settings: IPSettings? {
|
||||
guard let ipv6 = remoteOptions.ipv6 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepend main routes
|
||||
var target = allRoutes6
|
||||
target.insert(contentsOf: ipv6.includedRoutes, at: 0)
|
||||
|
||||
let routes: [Route] = target.compactMap { route in
|
||||
let ipv6Route = Route(route.destination, route.gateway)
|
||||
if route.destination == nil {
|
||||
guard isIPv6Gateway, let gw = route.gateway else {
|
||||
return nil
|
||||
}
|
||||
pp_log(.openvpn, .info, "\tIPv6: Set default gateway to \(gw)")
|
||||
} else {
|
||||
pp_log(.openvpn, .info, "\tIPv6: Add route \(route.destination?.description ?? "default") -> \(route.gateway?.description ?? "*")")
|
||||
}
|
||||
return ipv6Route
|
||||
}
|
||||
return ipv6.including(routes: routes)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - DNS
|
||||
|
||||
private extension OpenVPN.NetworkSettingsBuilder {
|
||||
private var dnsModule: Module? {
|
||||
let dnsServers = allDNSServers
|
||||
guard !dnsServers.isEmpty else {
|
||||
if isGateway {
|
||||
pp_log(.openvpn, .error, "DNS: No settings provided")
|
||||
} else {
|
||||
pp_log(.openvpn, .error, "DNS: No settings provided, use system settings")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
pp_log(.openvpn, .info, "\tDNS: Set servers \(dnsServers.map(\.asSensitiveAddress))")
|
||||
var dnsSettings = DNSModule.Builder(servers: dnsServers)
|
||||
|
||||
if let domain = dnsDomain {
|
||||
pp_log(.openvpn, .info, "\tDNS: Set domain: \(domain.asSensitiveAddress)")
|
||||
dnsSettings.domainName = domain
|
||||
}
|
||||
|
||||
let searchDomains = allDNSSearchDomains
|
||||
if !searchDomains.isEmpty {
|
||||
pp_log(.openvpn, .info, "\tDNS: Set search domains: \(searchDomains.map(\.asSensitiveAddress))")
|
||||
dnsSettings.searchDomains = searchDomains
|
||||
}
|
||||
|
||||
do {
|
||||
return try dnsSettings.tryBuild()
|
||||
} catch {
|
||||
pp_log(.openvpn, .error, "DNS: Unable to build settings: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - HTTP Proxy
|
||||
|
||||
private extension OpenVPN.NetworkSettingsBuilder {
|
||||
private var httpProxyModule: Module? {
|
||||
var proxySettings: HTTPProxyModule.Builder?
|
||||
|
||||
if let httpsProxy = pullProxy ? (remoteOptions.httpsProxy ?? localOptions.httpsProxy) : localOptions.httpsProxy {
|
||||
proxySettings = HTTPProxyModule.Builder()
|
||||
proxySettings?.secureAddress = httpsProxy.address.rawValue
|
||||
proxySettings?.securePort = httpsProxy.port
|
||||
pp_log(.openvpn, .info, "\tHTTPProxy: Set HTTPS proxy \(httpsProxy.asSensitiveAddress)")
|
||||
}
|
||||
if let httpProxy = pullProxy ? (remoteOptions.httpProxy ?? localOptions.httpProxy) : localOptions.httpProxy {
|
||||
if proxySettings == nil {
|
||||
proxySettings = HTTPProxyModule.Builder()
|
||||
}
|
||||
proxySettings?.address = httpProxy.address.rawValue
|
||||
proxySettings?.port = httpProxy.port
|
||||
pp_log(.openvpn, .info, "\tHTTPProxy: Set HTTP proxy \(httpProxy.asSensitiveAddress)")
|
||||
}
|
||||
if let pacURL = pullProxy ? (remoteOptions.proxyAutoConfigurationURL ?? localOptions.proxyAutoConfigurationURL) : localOptions.proxyAutoConfigurationURL {
|
||||
if proxySettings == nil {
|
||||
proxySettings = HTTPProxyModule.Builder()
|
||||
}
|
||||
proxySettings?.pacURLString = pacURL.absoluteString
|
||||
pp_log(.openvpn, .info, "\tHTTPProxy: Set PAC \(pacURL.absoluteString.asSensitiveAddress)")
|
||||
}
|
||||
|
||||
// only set if there is a proxy (proxySettings set to non-nil above)
|
||||
if proxySettings != nil {
|
||||
let bypass = allProxyBypassDomains
|
||||
if !bypass.isEmpty {
|
||||
proxySettings?.bypassDomains = bypass
|
||||
pp_log(.openvpn, .info, "\tHTTPProxy: Set by-pass list: \(bypass.map(\.asSensitiveAddress))")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
return try proxySettings?.tryBuild()
|
||||
} catch {
|
||||
pp_log(.openvpn, .error, "HTTPProxy: Unable to build settings: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,313 @@
|
||||
//
|
||||
// NetworkSettingsBuilderTests.swift
|
||||
// PassepartoutKit
|
||||
//
|
||||
// Created by Davide De Rosa on 4/12/24.
|
||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of PassepartoutKit.
|
||||
//
|
||||
// PassepartoutKit is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PassepartoutKit is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with PassepartoutKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutKit
|
||||
@testable import PassepartoutOpenVPNOpenSSL
|
||||
import XCTest
|
||||
|
||||
final class NetworkSettingsBuilderTests: XCTestCase {
|
||||
|
||||
// MARK: IP
|
||||
|
||||
func test_givenSettings_whenBuildIPModule_thenRequiresRemoteIP() throws {
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
|
||||
remoteOptions.ipv4 = nil
|
||||
remoteOptions.ipv6 = nil
|
||||
XCTAssertNil(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
remoteOptions.ipv4 = IPSettings(subnet: Subnet(rawValue: "100.1.2.3/32")!)
|
||||
XCTAssertNotNil(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
|
||||
remoteOptions.ipv4 = nil
|
||||
remoteOptions.ipv6 = nil
|
||||
XCTAssertNil(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
remoteOptions.ipv6 = IPSettings(subnet: Subnet(rawValue: "100:1:2::3/32")!)
|
||||
XCTAssertNotNil(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
}
|
||||
|
||||
func test_givenSettings_whenBuildIPModule_thenMergesRoutes() throws {
|
||||
var sut: IPModule
|
||||
let allRoutes4 = [
|
||||
Route(Subnet(rawValue: "1.1.1.1/16")!, nil),
|
||||
Route(Subnet(rawValue: "2.2.2.2/8")!, nil),
|
||||
Route(Subnet(rawValue: "3.3.3.3/24")!, nil),
|
||||
Route(Subnet(rawValue: "4.4.4.4/32")!, nil)
|
||||
]
|
||||
let allRoutes6 = [
|
||||
Route(Subnet(rawValue: "::1/16")!, nil),
|
||||
Route(Subnet(rawValue: "::2/8")!, nil),
|
||||
Route(Subnet(rawValue: "::3/24")!, nil),
|
||||
Route(Subnet(rawValue: "::4/32")!, nil)
|
||||
]
|
||||
let localRoutes4 = Array(allRoutes4.prefix(2))
|
||||
let localRoutes6 = Array(allRoutes6.prefix(2))
|
||||
let remoteRoutes4 = Array(allRoutes4.suffix(from: 2))
|
||||
let remoteRoutes6 = Array(allRoutes6.suffix(from: 2))
|
||||
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
localOptions.routes4 = localRoutes4
|
||||
localOptions.routes6 = localRoutes6
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
remoteOptions.ipv4 = IPSettings(subnet: Subnet(rawValue: "100.1.2.3/32")!)
|
||||
remoteOptions.ipv6 = IPSettings(subnet: Subnet(rawValue: "100:1:2::3/32")!)
|
||||
remoteOptions.routes4 = remoteRoutes4
|
||||
remoteOptions.routes6 = remoteRoutes6
|
||||
|
||||
sut = try XCTUnwrap(try builtModule(ofType: IPModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.ipv4?.includedRoutes, allRoutes4)
|
||||
XCTAssertEqual(sut.ipv6?.includedRoutes, allRoutes6)
|
||||
|
||||
localOptions.noPullMask = [.routes]
|
||||
sut = try XCTUnwrap(try builtModule(ofType: IPModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.ipv4?.includedRoutes, localOptions.routes4)
|
||||
XCTAssertEqual(sut.ipv6?.includedRoutes, localOptions.routes6)
|
||||
}
|
||||
|
||||
func test_givenSettings_whenBuildIPModule_thenFollowsRoutingPolicies() throws {
|
||||
var sut: IPModule
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
remoteOptions.ipv4 = IPSettings(
|
||||
subnet: Subnet(try XCTUnwrap(Address(rawValue: "1.1.1.1")), 16)
|
||||
)
|
||||
.including(
|
||||
routes: [
|
||||
Route(defaultWithGateway: try XCTUnwrap(Address(rawValue: "6.6.6.6")))
|
||||
]
|
||||
)
|
||||
remoteOptions.ipv6 = IPSettings(
|
||||
subnet: Subnet(try XCTUnwrap(Address(rawValue: "1:1::1")), 72)
|
||||
)
|
||||
.including(
|
||||
routes: [
|
||||
Route(defaultWithGateway: try XCTUnwrap(Address(rawValue: "::6")))
|
||||
]
|
||||
)
|
||||
|
||||
sut = try XCTUnwrap(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
XCTAssertEqual(sut.ipv4?.subnet?.rawValue, "1.1.1.1/16")
|
||||
XCTAssertEqual(sut.ipv6?.subnet?.rawValue, "1:1::1/72")
|
||||
XCTAssertNil(sut.ipv4?.defaultGateway?.rawValue)
|
||||
XCTAssertNil(sut.ipv6?.defaultGateway?.rawValue)
|
||||
|
||||
remoteOptions.routingPolicies = [.IPv4]
|
||||
sut = try XCTUnwrap(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
XCTAssertEqual(sut.ipv4?.defaultGateway?.rawValue, "6.6.6.6")
|
||||
XCTAssertNil(sut.ipv6?.defaultGateway?.rawValue)
|
||||
|
||||
remoteOptions.routingPolicies = [.IPv6]
|
||||
sut = try XCTUnwrap(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
XCTAssertNil(sut.ipv4?.defaultGateway?.rawValue)
|
||||
XCTAssertEqual(sut.ipv6?.defaultGateway?.rawValue, "::6")
|
||||
|
||||
remoteOptions.routingPolicies = [.IPv4, .IPv6]
|
||||
sut = try XCTUnwrap(try builtModule(ofType: IPModule.self, with: remoteOptions))
|
||||
XCTAssertEqual(sut.ipv4?.defaultGateway?.rawValue, "6.6.6.6")
|
||||
XCTAssertEqual(sut.ipv6?.defaultGateway?.rawValue, "::6")
|
||||
}
|
||||
|
||||
// MARK: DNS
|
||||
|
||||
func test_givenSettings_whenBuildDNSModule_thenRequiresServers() throws {
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
|
||||
XCTAssertNil(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.dnsServers = ["1.1.1.1"]
|
||||
remoteOptions.dnsServers = nil
|
||||
XCTAssertNotNil(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.dnsServers = nil
|
||||
remoteOptions.dnsServers = ["1.1.1.1"]
|
||||
XCTAssertNotNil(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.dnsServers = []
|
||||
remoteOptions.dnsServers = []
|
||||
XCTAssertNil(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
}
|
||||
|
||||
func test_givenSettings_whenBuildDNSModule_thenMergesServers() throws {
|
||||
var sut: DNSModule
|
||||
let allServers = [
|
||||
Address(rawValue: "1.1.1.1")!,
|
||||
Address(rawValue: "2.2.2.2")!,
|
||||
Address(rawValue: "3.3.3.3")!
|
||||
]
|
||||
let localServers = Array(allServers.prefix(2))
|
||||
let remoteServers = Array(allServers.suffix(from: 2))
|
||||
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
localOptions.dnsServers = localServers.map(\.rawValue)
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
remoteOptions.dnsServers = remoteServers.map(\.rawValue)
|
||||
|
||||
sut = try XCTUnwrap(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.servers, allServers)
|
||||
|
||||
localOptions.noPullMask = [.dns]
|
||||
sut = try XCTUnwrap(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.servers, localServers)
|
||||
}
|
||||
|
||||
func test_givenSettings_whenBuildDNSModule_thenMergesDomains() throws {
|
||||
var sut: DNSModule
|
||||
let allDomains = [
|
||||
Address(rawValue: "one.com")!,
|
||||
Address(rawValue: "two.com")!,
|
||||
Address(rawValue: "three.com")!
|
||||
]
|
||||
let localDomains = Array(allDomains.prefix(2))
|
||||
let remoteDomains = Array(allDomains.suffix(from: 2))
|
||||
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
localOptions.dnsServers = ["1.1.1.1"]
|
||||
localOptions.searchDomains = localDomains.map(\.rawValue)
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
remoteOptions.searchDomains = remoteDomains.map(\.rawValue)
|
||||
|
||||
sut = try XCTUnwrap(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.searchDomains, allDomains)
|
||||
|
||||
localOptions.noPullMask = [.dns]
|
||||
sut = try XCTUnwrap(try builtModule(ofType: DNSModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.searchDomains, localDomains)
|
||||
}
|
||||
|
||||
// MARK: Proxy
|
||||
|
||||
func test_givenSettings_whenBuildHTTPProxyModule_thenRequiresEndpoint() throws {
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
|
||||
XCTAssertNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.httpProxy = Endpoint(rawValue: "1.1.1.1:8080")!
|
||||
remoteOptions.httpProxy = nil
|
||||
XCTAssertNotNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
localOptions.httpsProxy = Endpoint(rawValue: "1.1.1.1:8080")!
|
||||
XCTAssertNotNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.httpProxy = nil
|
||||
remoteOptions.httpProxy = Endpoint(rawValue: "1.1.1.1:8080")!
|
||||
XCTAssertNotNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
remoteOptions.httpsProxy = Endpoint(rawValue: "1.1.1.1:8080")!
|
||||
XCTAssertNotNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.httpProxy = nil
|
||||
remoteOptions.httpProxy = nil
|
||||
XCTAssertNotNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
localOptions.httpsProxy = nil
|
||||
remoteOptions.httpsProxy = nil
|
||||
XCTAssertNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
}
|
||||
|
||||
func test_givenSettings_whenBuildACProxyModule_thenRequiresURL() throws {
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
|
||||
XCTAssertNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.proxyAutoConfigurationURL = URL(string: "https://www.gogle.com")!
|
||||
remoteOptions.proxyAutoConfigurationURL = nil
|
||||
XCTAssertNotNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.proxyAutoConfigurationURL = nil
|
||||
remoteOptions.proxyAutoConfigurationURL = URL(string: "https://www.gogle.com")!
|
||||
XCTAssertNotNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
|
||||
localOptions.proxyAutoConfigurationURL = nil
|
||||
remoteOptions.proxyAutoConfigurationURL = nil
|
||||
XCTAssertNil(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
}
|
||||
|
||||
func test_givenSettings_whenBuildProxyModule_thenMergesBypassDomains() throws {
|
||||
var sut: HTTPProxyModule
|
||||
let allDomains = [
|
||||
Address(rawValue: "one.com")!,
|
||||
Address(rawValue: "two.com")!,
|
||||
Address(rawValue: "three.com")!
|
||||
]
|
||||
let localDomains = Array(allDomains.prefix(2))
|
||||
let remoteDomains = Array(allDomains.suffix(from: 2))
|
||||
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
localOptions.httpProxy = Endpoint(rawValue: "1.1.1.1:8080")!
|
||||
localOptions.proxyBypassDomains = localDomains.map(\.rawValue)
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
remoteOptions.proxyBypassDomains = remoteDomains.map(\.rawValue)
|
||||
|
||||
sut = try XCTUnwrap(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.bypassDomains, allDomains)
|
||||
|
||||
localOptions.noPullMask = [.proxy]
|
||||
sut = try XCTUnwrap(try builtModule(ofType: HTTPProxyModule.self, with: remoteOptions, localOptions: localOptions))
|
||||
XCTAssertEqual(sut.bypassDomains, localDomains)
|
||||
}
|
||||
|
||||
// MARK: MTU
|
||||
|
||||
func test_givenSettings_whenBuildMTU_thenReturnsLocalMTU() throws {
|
||||
var sut: OpenVPN.NetworkSettingsBuilder
|
||||
var localOptions = OpenVPN.Configuration.Builder()
|
||||
var remoteOptions = OpenVPN.Configuration.Builder()
|
||||
|
||||
localOptions.mtu = 1200
|
||||
sut = try newBuilder(with: remoteOptions, localOptions: localOptions)
|
||||
XCTAssertEqual((sut.modules().first as? IPModule)?.mtu, localOptions.mtu)
|
||||
|
||||
remoteOptions.mtu = 1400
|
||||
sut = try newBuilder(with: remoteOptions, localOptions: localOptions)
|
||||
XCTAssertEqual((sut.modules().first as? IPModule)?.mtu, localOptions.mtu)
|
||||
|
||||
localOptions.mtu = nil
|
||||
sut = try newBuilder(with: remoteOptions, localOptions: localOptions)
|
||||
XCTAssertNil((sut.modules().first as? IPModule)?.mtu)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private extension NetworkSettingsBuilderTests {
|
||||
func builtModule<T>(
|
||||
ofType type: T.Type,
|
||||
with remoteOptions: OpenVPN.Configuration.Builder,
|
||||
localOptions: OpenVPN.Configuration.Builder? = nil
|
||||
) throws -> T? where T: Module {
|
||||
try newBuilder(with: remoteOptions, localOptions: localOptions)
|
||||
.modules()
|
||||
.first(ofType: type)
|
||||
}
|
||||
|
||||
func newBuilder(
|
||||
with remoteOptions: OpenVPN.Configuration.Builder,
|
||||
localOptions: OpenVPN.Configuration.Builder? = nil
|
||||
) throws -> OpenVPN.NetworkSettingsBuilder {
|
||||
OpenVPN.NetworkSettingsBuilder(
|
||||
localOptions: try (localOptions ?? OpenVPN.Configuration.Builder()).tryBuild(isClient: false),
|
||||
remoteOptions: try remoteOptions.tryBuild(isClient: false)
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user