Delegate network settings to ad-hoc builder (#292)
* Delegate network settings to ad-hoc builder - Assert network settings nil or non-empty, NOT precondition - Fix log about local DNS, only if not gateway - Remove non-working block-local code Fixes #289, fixes #290 * Unmask safe and helpful network settings
This commit is contained in:
parent
195f885ee4
commit
31db8ebb9d
|
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- Upgrade OpenSSL to 1.1.1q.
|
||||
- Use natively async methods from NetworkExtension. [#284](https://github.com/passepartoutvpn/tunnelkit/pull/284)
|
||||
- OpenVPN: Unmask PUSH_REPLY and network settings in logs.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
//
|
||||
// NetworkSettingsBuilder.swift
|
||||
// TunnelKit
|
||||
//
|
||||
// Created by Davide De Rosa on 10/21/22.
|
||||
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of TunnelKit.
|
||||
//
|
||||
// TunnelKit 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.
|
||||
//
|
||||
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import NetworkExtension
|
||||
import TunnelKitCore
|
||||
import TunnelKitOpenVPNCore
|
||||
import SwiftyBeaver
|
||||
|
||||
private let log = SwiftyBeaver.self
|
||||
|
||||
struct NetworkSettingsBuilder {
|
||||
let remoteAddress: String
|
||||
|
||||
let localOptions: OpenVPN.Configuration
|
||||
|
||||
let remoteOptions: OpenVPN.Configuration
|
||||
|
||||
init(remoteAddress: String, localOptions: OpenVPN.Configuration, remoteOptions: OpenVPN.Configuration) {
|
||||
self.remoteAddress = remoteAddress
|
||||
self.localOptions = localOptions
|
||||
self.remoteOptions = remoteOptions
|
||||
}
|
||||
|
||||
func build() -> NEPacketTunnelNetworkSettings {
|
||||
let ipv4Settings = computedIPv4Settings
|
||||
let ipv6Settings = computedIPv6Settings
|
||||
let dnsSettings = computedDNSSettings
|
||||
let proxySettings = computedProxySettings
|
||||
|
||||
// add direct routes to DNS servers
|
||||
if !isGateway {
|
||||
for server in dnsSettings?.servers ?? [] {
|
||||
if server.contains(":") {
|
||||
ipv6Settings?.includedRoutes?.insert(NEIPv6Route(destinationAddress: server, networkPrefixLength: 128), at: 0)
|
||||
} else {
|
||||
ipv4Settings?.includedRoutes?.insert(NEIPv4Route(destinationAddress: server, subnetMask: "255.255.255.255"), at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: remoteAddress)
|
||||
settings.ipv4Settings = ipv4Settings
|
||||
settings.ipv6Settings = ipv6Settings
|
||||
settings.dnsSettings = dnsSettings
|
||||
settings.proxySettings = proxySettings
|
||||
if let mtu = localOptions.mtu, mtu > 0 {
|
||||
settings.mtu = NSNumber(value: mtu)
|
||||
}
|
||||
return settings
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkSettingsBuilder {
|
||||
private var pullRoutes: Bool {
|
||||
!(localOptions.noPullMask?.contains(.routes) ?? false)
|
||||
}
|
||||
|
||||
private var pullDNS: Bool {
|
||||
!(localOptions.noPullMask?.contains(.dns) ?? false)
|
||||
}
|
||||
|
||||
private var pullProxy: Bool {
|
||||
!(localOptions.noPullMask?.contains(.proxy) ?? false)
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkSettingsBuilder {
|
||||
var isGateway: Bool {
|
||||
isIPv4Gateway || isIPv6Gateway
|
||||
}
|
||||
|
||||
private var routingPolicies: [OpenVPN.RoutingPolicy]? {
|
||||
pullRoutes ? (remoteOptions.routingPolicies ?? localOptions.routingPolicies) : localOptions.routingPolicies
|
||||
}
|
||||
|
||||
private var isIPv4Gateway: Bool {
|
||||
routingPolicies?.contains(.IPv4) ?? false
|
||||
}
|
||||
|
||||
private var isIPv6Gateway: Bool {
|
||||
routingPolicies?.contains(.IPv6) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkSettingsBuilder {
|
||||
|
||||
// IPv4/6 address/mask MUST come from server options
|
||||
// routes, instead, can both come from server and local options
|
||||
//
|
||||
// FIXME: routes from local options are ignored (#278)
|
||||
|
||||
private var computedIPv4Settings: NEIPv4Settings? {
|
||||
guard let ipv4 = remoteOptions.ipv4 else {
|
||||
return nil
|
||||
}
|
||||
let ipv4Settings = NEIPv4Settings(addresses: [ipv4.address], subnetMasks: [ipv4.addressMask])
|
||||
if pullRoutes {
|
||||
var routes: [NEIPv4Route] = []
|
||||
|
||||
// route all traffic to VPN?
|
||||
if isIPv4Gateway {
|
||||
let defaultRoute = NEIPv4Route.default()
|
||||
defaultRoute.gatewayAddress = ipv4.defaultGateway
|
||||
routes.append(defaultRoute)
|
||||
log.info("Routing.IPv4: Setting default gateway to \(ipv4.defaultGateway)")
|
||||
}
|
||||
|
||||
for r in ipv4.routes {
|
||||
let ipv4Route = NEIPv4Route(destinationAddress: r.destination, subnetMask: r.mask)
|
||||
ipv4Route.gatewayAddress = r.gateway
|
||||
routes.append(ipv4Route)
|
||||
log.info("Routing.IPv4: Adding route \(r.destination)/\(r.mask) -> \(r.gateway)")
|
||||
}
|
||||
|
||||
ipv4Settings.includedRoutes = routes
|
||||
ipv4Settings.excludedRoutes = []
|
||||
}
|
||||
return ipv4Settings
|
||||
}
|
||||
|
||||
private var computedIPv6Settings: NEIPv6Settings? {
|
||||
guard let ipv6 = remoteOptions.ipv6 else {
|
||||
return nil
|
||||
}
|
||||
let ipv6Settings = NEIPv6Settings(addresses: [ipv6.address], networkPrefixLengths: [ipv6.addressPrefixLength as NSNumber])
|
||||
if pullRoutes {
|
||||
var routes: [NEIPv6Route] = []
|
||||
|
||||
// route all traffic to VPN?
|
||||
if isIPv6Gateway {
|
||||
let defaultRoute = NEIPv6Route.default()
|
||||
defaultRoute.gatewayAddress = ipv6.defaultGateway
|
||||
routes.append(defaultRoute)
|
||||
log.info("Routing.IPv6: Setting default gateway to \(ipv6.defaultGateway)")
|
||||
}
|
||||
|
||||
for r in ipv6.routes {
|
||||
let ipv6Route = NEIPv6Route(destinationAddress: r.destination, networkPrefixLength: r.prefixLength as NSNumber)
|
||||
ipv6Route.gatewayAddress = r.gateway
|
||||
routes.append(ipv6Route)
|
||||
log.info("Routing.IPv6: Adding route \(r.destination)/\(r.prefixLength) -> \(r.gateway)")
|
||||
}
|
||||
|
||||
ipv6Settings.includedRoutes = routes
|
||||
ipv6Settings.excludedRoutes = []
|
||||
}
|
||||
return ipv6Settings
|
||||
}
|
||||
|
||||
var hasGateway: Bool {
|
||||
var hasGateway = false
|
||||
if isIPv4Gateway && computedIPv4Settings != nil {
|
||||
hasGateway = true
|
||||
}
|
||||
if isIPv6Gateway && computedIPv6Settings != nil {
|
||||
hasGateway = true
|
||||
}
|
||||
return hasGateway
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkSettingsBuilder {
|
||||
private var computedDNSSettings: NEDNSSettings? {
|
||||
guard localOptions.isDNSEnabled ?? true else {
|
||||
return nil
|
||||
}
|
||||
var dnsSettings: NEDNSSettings?
|
||||
var dnsServers: [String] = []
|
||||
if #available(iOS 14, macOS 11, *) {
|
||||
switch localOptions.dnsProtocol {
|
||||
case .https:
|
||||
dnsServers = localOptions.dnsServers ?? []
|
||||
guard let serverURL = localOptions.dnsHTTPSURL else {
|
||||
break
|
||||
}
|
||||
let specific = NEDNSOverHTTPSSettings(servers: dnsServers)
|
||||
specific.serverURL = serverURL
|
||||
dnsSettings = specific
|
||||
log.info("DNS over HTTPS: Using servers \(dnsServers)")
|
||||
log.info("\tHTTPS URL: \(serverURL)")
|
||||
|
||||
case .tls:
|
||||
dnsServers = localOptions.dnsServers ?? []
|
||||
guard let serverName = localOptions.dnsTLSServerName else {
|
||||
break
|
||||
}
|
||||
let specific = NEDNSOverTLSSettings(servers: dnsServers)
|
||||
specific.serverName = serverName
|
||||
dnsSettings = specific
|
||||
log.info("DNS over TLS: Using servers \(dnsServers)")
|
||||
log.info("\tTLS server name: \(serverName)")
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// fall back
|
||||
if dnsSettings == nil {
|
||||
dnsServers = (pullDNS ? (remoteOptions.dnsServers ?? localOptions.dnsServers) : localOptions.dnsServers) ?? []
|
||||
if !dnsServers.isEmpty {
|
||||
log.info("DNS: Using servers \(dnsServers)")
|
||||
dnsSettings = NEDNSSettings(servers: dnsServers)
|
||||
} else {
|
||||
// log.warning("DNS: No servers provided, using fall-back servers: \(fallbackDNSServers)")
|
||||
// dnsSettings = NEDNSSettings(servers: fallbackDNSServers)
|
||||
if isGateway {
|
||||
log.warning("DNS: No settings provided")
|
||||
} else {
|
||||
log.warning("DNS: No settings provided, using current network settings")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "hack" for split DNS (i.e. use VPN only for DNS)
|
||||
if !isGateway {
|
||||
dnsSettings?.matchDomains = [""]
|
||||
}
|
||||
|
||||
if let searchDomains = pullDNS ? (remoteOptions.searchDomains ?? localOptions.searchDomains) : localOptions.searchDomains {
|
||||
log.info("DNS: Using search domains \(searchDomains)")
|
||||
dnsSettings?.domainName = searchDomains.first
|
||||
dnsSettings?.searchDomains = searchDomains
|
||||
if !isGateway {
|
||||
dnsSettings?.matchDomains = dnsSettings?.searchDomains
|
||||
}
|
||||
}
|
||||
|
||||
return dnsSettings
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkSettingsBuilder {
|
||||
private var computedProxySettings: NEProxySettings? {
|
||||
guard localOptions.isProxyEnabled ?? true else {
|
||||
return nil
|
||||
}
|
||||
var proxySettings: NEProxySettings?
|
||||
if let httpsProxy = pullProxy ? (remoteOptions.httpsProxy ?? localOptions.httpsProxy) : localOptions.httpsProxy {
|
||||
proxySettings = NEProxySettings()
|
||||
proxySettings?.httpsServer = httpsProxy.neProxy()
|
||||
proxySettings?.httpsEnabled = true
|
||||
log.info("Routing: Setting HTTPS proxy \(httpsProxy.address):\(httpsProxy.port)")
|
||||
}
|
||||
if let httpProxy = pullProxy ? (remoteOptions.httpProxy ?? localOptions.httpProxy) : localOptions.httpProxy {
|
||||
if proxySettings == nil {
|
||||
proxySettings = NEProxySettings()
|
||||
}
|
||||
proxySettings?.httpServer = httpProxy.neProxy()
|
||||
proxySettings?.httpEnabled = true
|
||||
log.info("Routing: Setting HTTP proxy \(httpProxy.address):\(httpProxy.port)")
|
||||
}
|
||||
if let pacURL = pullProxy ? (remoteOptions.proxyAutoConfigurationURL ?? localOptions.proxyAutoConfigurationURL) : localOptions.proxyAutoConfigurationURL {
|
||||
if proxySettings == nil {
|
||||
proxySettings = NEProxySettings()
|
||||
}
|
||||
proxySettings?.proxyAutoConfigurationURL = pacURL
|
||||
proxySettings?.autoProxyConfigurationEnabled = true
|
||||
log.info("Routing: Setting PAC \(pacURL)")
|
||||
}
|
||||
|
||||
// only set if there is a proxy (proxySettings set to non-nil above)
|
||||
if let bypass = pullProxy ? (remoteOptions.proxyBypassDomains ?? localOptions.proxyBypassDomains) : localOptions.proxyBypassDomains {
|
||||
proxySettings?.exceptionList = bypass
|
||||
log.info("Routing: Setting proxy by-pass list: \(bypass)")
|
||||
}
|
||||
return proxySettings
|
||||
}
|
||||
}
|
||||
|
||||
private extension Proxy {
|
||||
func neProxy() -> NEProxyServer {
|
||||
return NEProxyServer(address: address, port: Int(port))
|
||||
}
|
||||
}
|
|
@ -524,7 +524,7 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
|
|||
|
||||
cfg._appexSetServerConfiguration(session.serverConfiguration() as? OpenVPN.Configuration)
|
||||
|
||||
bringNetworkUp(remoteAddress: remoteAddress, localOptions: session.configuration, options: options) { (error) in
|
||||
bringNetworkUp(remoteAddress: remoteAddress, localOptions: session.configuration, remoteOptions: options) { (error) in
|
||||
|
||||
// FIXME: XPC queue
|
||||
|
||||
|
@ -565,266 +565,52 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
|
|||
socket?.shutdown()
|
||||
}
|
||||
|
||||
private func bringNetworkUp(remoteAddress: String, localOptions: OpenVPN.Configuration, options: OpenVPN.Configuration, completionHandler: @escaping (Error?) -> Void) {
|
||||
let pullMask = localOptions.pullMask
|
||||
let pullRoutes = pullMask?.contains(.routes) ?? false
|
||||
let pullDNS = pullMask?.contains(.dns) ?? false
|
||||
let pullProxy = pullMask?.contains(.proxy) ?? false
|
||||
private func bringNetworkUp(remoteAddress: String, localOptions: OpenVPN.Configuration, remoteOptions: OpenVPN.Configuration, completionHandler: @escaping (Error?) -> Void) {
|
||||
let newSettings = NetworkSettingsBuilder(remoteAddress: remoteAddress, localOptions: localOptions, remoteOptions: remoteOptions)
|
||||
|
||||
let routingPolicies = pullRoutes ? options.routingPolicies : localOptions.routingPolicies
|
||||
let isIPv4Gateway = routingPolicies?.contains(.IPv4) ?? false
|
||||
let isIPv6Gateway = routingPolicies?.contains(.IPv6) ?? false
|
||||
let isGateway = isIPv4Gateway || isIPv6Gateway
|
||||
|
||||
var ipv4Settings: NEIPv4Settings?
|
||||
if let ipv4 = options.ipv4 {
|
||||
var routes: [NEIPv4Route] = []
|
||||
|
||||
// route all traffic to VPN?
|
||||
if isIPv4Gateway {
|
||||
let defaultRoute = NEIPv4Route.default()
|
||||
defaultRoute.gatewayAddress = ipv4.defaultGateway
|
||||
routes.append(defaultRoute)
|
||||
// for network in ["0.0.0.0", "128.0.0.0"] {
|
||||
// let route = NEIPv4Route(destinationAddress: network, subnetMask: "128.0.0.0")
|
||||
// route.gatewayAddress = ipv4.defaultGateway
|
||||
// routes.append(route)
|
||||
// }
|
||||
log.info("Routing.IPv4: Setting default gateway to \(ipv4.defaultGateway.maskedDescription)")
|
||||
}
|
||||
|
||||
if pullRoutes {
|
||||
for r in ipv4.routes {
|
||||
let ipv4Route = NEIPv4Route(destinationAddress: r.destination, subnetMask: r.mask)
|
||||
ipv4Route.gatewayAddress = r.gateway
|
||||
routes.append(ipv4Route)
|
||||
log.info("Routing.IPv4: Adding route \(r.destination.maskedDescription)/\(r.mask) -> \(r.gateway)")
|
||||
}
|
||||
}
|
||||
|
||||
ipv4Settings = NEIPv4Settings(addresses: [ipv4.address], subnetMasks: [ipv4.addressMask])
|
||||
ipv4Settings?.includedRoutes = routes
|
||||
ipv4Settings?.excludedRoutes = []
|
||||
}
|
||||
|
||||
var ipv6Settings: NEIPv6Settings?
|
||||
if let ipv6 = options.ipv6 {
|
||||
var routes: [NEIPv6Route] = []
|
||||
|
||||
// route all traffic to VPN?
|
||||
if isIPv6Gateway {
|
||||
let defaultRoute = NEIPv6Route.default()
|
||||
defaultRoute.gatewayAddress = ipv6.defaultGateway
|
||||
routes.append(defaultRoute)
|
||||
// for network in ["2000::", "3000::"] {
|
||||
// let route = NEIPv6Route(destinationAddress: network, networkPrefixLength: 4)
|
||||
// route.gatewayAddress = ipv6.defaultGateway
|
||||
// routes.append(route)
|
||||
// }
|
||||
log.info("Routing.IPv6: Setting default gateway to \(ipv6.defaultGateway.maskedDescription)")
|
||||
}
|
||||
|
||||
if pullRoutes {
|
||||
for r in ipv6.routes {
|
||||
let ipv6Route = NEIPv6Route(destinationAddress: r.destination, networkPrefixLength: r.prefixLength as NSNumber)
|
||||
ipv6Route.gatewayAddress = r.gateway
|
||||
routes.append(ipv6Route)
|
||||
log.info("Routing.IPv6: Adding route \(r.destination.maskedDescription)/\(r.prefixLength) -> \(r.gateway)")
|
||||
}
|
||||
}
|
||||
|
||||
ipv6Settings = NEIPv6Settings(addresses: [ipv6.address], networkPrefixLengths: [ipv6.addressPrefixLength as NSNumber])
|
||||
ipv6Settings?.includedRoutes = routes
|
||||
ipv6Settings?.excludedRoutes = []
|
||||
}
|
||||
|
||||
// shut down if default gateway is not attainable
|
||||
var hasGateway = false
|
||||
if isIPv4Gateway && (ipv4Settings != nil) {
|
||||
hasGateway = true
|
||||
}
|
||||
if isIPv6Gateway && (ipv6Settings != nil) {
|
||||
hasGateway = true
|
||||
}
|
||||
guard !isGateway || hasGateway else {
|
||||
guard !newSettings.isGateway || newSettings.hasGateway else {
|
||||
session?.shutdown(error: OpenVPNProviderError.gatewayUnattainable)
|
||||
return
|
||||
}
|
||||
|
||||
var dnsSettings: NEDNSSettings?
|
||||
if localOptions.isDNSEnabled ?? true {
|
||||
var dnsServers: [String] = []
|
||||
if #available(iOS 14, macOS 11, *) {
|
||||
switch localOptions.dnsProtocol {
|
||||
case .https:
|
||||
dnsServers = localOptions.dnsServers ?? []
|
||||
guard let serverURL = localOptions.dnsHTTPSURL else {
|
||||
break
|
||||
}
|
||||
let specific = NEDNSOverHTTPSSettings(servers: dnsServers)
|
||||
specific.serverURL = serverURL
|
||||
dnsSettings = specific
|
||||
log.info("DNS over HTTPS: Using servers \(dnsServers.maskedDescription)")
|
||||
log.info("\tHTTPS URL: \(serverURL.maskedDescription)")
|
||||
|
||||
case .tls:
|
||||
dnsServers = localOptions.dnsServers ?? []
|
||||
guard let serverName = localOptions.dnsTLSServerName else {
|
||||
break
|
||||
}
|
||||
let specific = NEDNSOverTLSSettings(servers: dnsServers)
|
||||
specific.serverName = serverName
|
||||
dnsSettings = specific
|
||||
log.info("DNS over TLS: Using servers \(dnsServers.maskedDescription)")
|
||||
log.info("\tTLS server name: \(serverName.maskedDescription)")
|
||||
// // block LAN if desired
|
||||
// if routingPolicies?.contains(.blockLocal) ?? false {
|
||||
// let table = RoutingTable()
|
||||
// if isIPv4Gateway,
|
||||
// let gateway = table.defaultGateway4()?.gateway(),
|
||||
// let route = table.broadestRoute4(matchingDestination: gateway) {
|
||||
//
|
||||
// route.partitioned()?.forEach {
|
||||
// let destination = $0.network()
|
||||
// guard let netmask = $0.networkMask() else {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// log.info("Block local: Suppressing IPv4 route \(destination)/\($0.prefix())")
|
||||
//
|
||||
// let included = NEIPv4Route(destinationAddress: destination, subnetMask: netmask)
|
||||
// included.gatewayAddress = options.ipv4?.defaultGateway
|
||||
// ipv4Settings?.includedRoutes?.append(included)
|
||||
// }
|
||||
// }
|
||||
// if isIPv6Gateway,
|
||||
// let gateway = table.defaultGateway6()?.gateway(),
|
||||
// let route = table.broadestRoute6(matchingDestination: gateway) {
|
||||
//
|
||||
// route.partitioned()?.forEach {
|
||||
// let destination = $0.network()
|
||||
// let prefix = $0.prefix()
|
||||
//
|
||||
// log.info("Block local: Suppressing IPv6 route \(destination)/\($0.prefix())")
|
||||
//
|
||||
// let included = NEIPv6Route(destinationAddress: destination, networkPrefixLength: prefix as NSNumber)
|
||||
// included.gatewayAddress = options.ipv6?.defaultGateway
|
||||
// ipv6Settings?.includedRoutes?.append(included)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that non-nil arrays also imply non-empty
|
||||
if let array = options.dnsServers {
|
||||
precondition(!array.isEmpty)
|
||||
}
|
||||
if let array = options.searchDomains {
|
||||
precondition(!array.isEmpty)
|
||||
}
|
||||
if let array = options.proxyBypassDomains {
|
||||
precondition(!array.isEmpty)
|
||||
}
|
||||
if let array = cfg.configuration.dnsServers {
|
||||
precondition(!array.isEmpty)
|
||||
}
|
||||
if let array = cfg.configuration.searchDomains {
|
||||
precondition(!array.isEmpty)
|
||||
}
|
||||
if let array = cfg.configuration.proxyBypassDomains {
|
||||
precondition(!array.isEmpty)
|
||||
}
|
||||
|
||||
// fall back
|
||||
if dnsSettings == nil {
|
||||
dnsServers = (pullDNS ? options.dnsServers : localOptions.dnsServers) ?? []
|
||||
if !dnsServers.isEmpty {
|
||||
log.info("DNS: Using servers \(dnsServers.maskedDescription)")
|
||||
dnsSettings = NEDNSSettings(servers: dnsServers)
|
||||
} else {
|
||||
// log.warning("DNS: No servers provided, using fall-back servers: \(fallbackDNSServers.maskedDescription)")
|
||||
// dnsSettings = NEDNSSettings(servers: fallbackDNSServers)
|
||||
if isGateway {
|
||||
log.warning("DNS: No settings provided, using current network settings")
|
||||
} else {
|
||||
log.warning("DNS: No settings provided")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "hack" for split DNS (i.e. use VPN only for DNS)
|
||||
if !isGateway {
|
||||
dnsSettings?.matchDomains = [""]
|
||||
}
|
||||
|
||||
if let searchDomains = pullDNS ? options.searchDomains : localOptions.searchDomains {
|
||||
log.info("DNS: Using search domains \(searchDomains.maskedDescription)")
|
||||
dnsSettings?.domainName = searchDomains.first
|
||||
dnsSettings?.searchDomains = searchDomains
|
||||
if !isGateway {
|
||||
dnsSettings?.matchDomains = dnsSettings?.searchDomains
|
||||
}
|
||||
}
|
||||
|
||||
// add direct routes to DNS servers
|
||||
if !isGateway {
|
||||
for server in dnsServers {
|
||||
if server.contains(":") {
|
||||
ipv6Settings?.includedRoutes?.insert(NEIPv6Route(destinationAddress: server, networkPrefixLength: 128), at: 0)
|
||||
} else {
|
||||
ipv4Settings?.includedRoutes?.insert(NEIPv4Route(destinationAddress: server, subnetMask: "255.255.255.255"), at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var proxySettings: NEProxySettings?
|
||||
if localOptions.isProxyEnabled ?? true {
|
||||
if let httpsProxy = pullProxy ? options.httpsProxy : localOptions.httpsProxy {
|
||||
proxySettings = NEProxySettings()
|
||||
proxySettings?.httpsServer = httpsProxy.neProxy()
|
||||
proxySettings?.httpsEnabled = true
|
||||
log.info("Routing: Setting HTTPS proxy \(httpsProxy.address.maskedDescription):\(httpsProxy.port)")
|
||||
}
|
||||
if let httpProxy = pullProxy ? options.httpProxy : localOptions.httpProxy {
|
||||
if proxySettings == nil {
|
||||
proxySettings = NEProxySettings()
|
||||
}
|
||||
proxySettings?.httpServer = httpProxy.neProxy()
|
||||
proxySettings?.httpEnabled = true
|
||||
log.info("Routing: Setting HTTP proxy \(httpProxy.address.maskedDescription):\(httpProxy.port)")
|
||||
}
|
||||
if let pacURL = pullProxy ? options.proxyAutoConfigurationURL : localOptions.proxyAutoConfigurationURL {
|
||||
if proxySettings == nil {
|
||||
proxySettings = NEProxySettings()
|
||||
}
|
||||
proxySettings?.proxyAutoConfigurationURL = pacURL
|
||||
proxySettings?.autoProxyConfigurationEnabled = true
|
||||
log.info("Routing: Setting PAC \(pacURL.maskedDescription)")
|
||||
}
|
||||
|
||||
// only set if there is a proxy (proxySettings set to non-nil above)
|
||||
if let bypass = pullProxy ? options.proxyBypassDomains : localOptions.proxyBypassDomains {
|
||||
proxySettings?.exceptionList = bypass
|
||||
log.info("Routing: Setting proxy by-pass list: \(bypass.maskedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
// block LAN if desired
|
||||
if routingPolicies?.contains(.blockLocal) ?? false {
|
||||
let table = RoutingTable()
|
||||
if isIPv4Gateway,
|
||||
let gateway = table.defaultGateway4()?.gateway(),
|
||||
let route = table.broadestRoute4(matchingDestination: gateway) {
|
||||
|
||||
route.partitioned()?.forEach {
|
||||
let destination = $0.network()
|
||||
guard let netmask = $0.networkMask() else {
|
||||
return
|
||||
}
|
||||
|
||||
log.info("Block local: Suppressing IPv4 route \(destination)/\($0.prefix())")
|
||||
|
||||
let included = NEIPv4Route(destinationAddress: destination, subnetMask: netmask)
|
||||
included.gatewayAddress = options.ipv4?.defaultGateway
|
||||
ipv4Settings?.includedRoutes?.append(included)
|
||||
}
|
||||
}
|
||||
if isIPv6Gateway,
|
||||
let gateway = table.defaultGateway6()?.gateway(),
|
||||
let route = table.broadestRoute6(matchingDestination: gateway) {
|
||||
|
||||
route.partitioned()?.forEach {
|
||||
let destination = $0.network()
|
||||
let prefix = $0.prefix()
|
||||
|
||||
log.info("Block local: Suppressing IPv6 route \(destination)/\($0.prefix())")
|
||||
|
||||
let included = NEIPv6Route(destinationAddress: destination, networkPrefixLength: prefix as NSNumber)
|
||||
included.gatewayAddress = options.ipv6?.defaultGateway
|
||||
ipv6Settings?.includedRoutes?.append(included)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let newSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: remoteAddress)
|
||||
newSettings.ipv4Settings = ipv4Settings
|
||||
newSettings.ipv6Settings = ipv6Settings
|
||||
newSettings.dnsSettings = dnsSettings
|
||||
newSettings.proxySettings = proxySettings
|
||||
if let mtu = localOptions.mtu, mtu > 0 {
|
||||
newSettings.mtu = NSNumber(value: mtu)
|
||||
}
|
||||
|
||||
setTunnelNetworkSettings(newSettings, completionHandler: completionHandler)
|
||||
setTunnelNetworkSettings(newSettings.build(), completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -948,12 +734,6 @@ extension OpenVPNTunnelProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private extension Proxy {
|
||||
func neProxy() -> NEProxyServer {
|
||||
return NEProxyServer(address: address, port: Int(port))
|
||||
}
|
||||
}
|
||||
|
||||
private extension NEPacketTunnelProvider {
|
||||
func forceExitOnMac() {
|
||||
#if os(macOS)
|
||||
|
|
|
@ -732,6 +732,28 @@ extension OpenVPN {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: Post-processing
|
||||
|
||||
// prepend search domains with main domain (if set)
|
||||
if let domain = optDomain {
|
||||
if optSearchDomains == nil {
|
||||
optSearchDomains = [domain]
|
||||
} else {
|
||||
optSearchDomains?.insert(domain, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that non-nil network settings also imply non-empty
|
||||
if let array = optDNSServers {
|
||||
assert(!array.isEmpty)
|
||||
}
|
||||
if let array = optSearchDomains {
|
||||
assert(!array.isEmpty)
|
||||
}
|
||||
if let array = optProxyBypass {
|
||||
assert(!array.isEmpty)
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var sessionBuilder = ConfigurationBuilder()
|
||||
|
@ -887,15 +909,6 @@ extension OpenVPN {
|
|||
)
|
||||
}
|
||||
|
||||
// prepend search domains with main domain (if set)
|
||||
if let domain = optDomain {
|
||||
if optSearchDomains == nil {
|
||||
optSearchDomains = [domain]
|
||||
} else {
|
||||
optSearchDomains?.insert(domain, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
sessionBuilder.dnsServers = optDNSServers
|
||||
sessionBuilder.searchDomains = optSearchDomains
|
||||
sessionBuilder.httpProxy = optHTTPProxy
|
||||
|
|
|
@ -944,7 +944,7 @@ public class OpenVPNSession: Session {
|
|||
return
|
||||
}
|
||||
reply = optionalReply
|
||||
log.debug("Received PUSH_REPLY: \"\(reply.maskedDescription)\"")
|
||||
log.debug("Received PUSH_REPLY: \"\(reply)\"")
|
||||
|
||||
if let framing = reply.options.compressionFraming, let compression = reply.options.compressionAlgorithm {
|
||||
switch compression {
|
||||
|
|
Loading…
Reference in New Issue