Add options to explicitly enable/disable DNS/proxy

DNS/proxy settings, when missing from configuration, fall back to
whatever the server pushes.

With isDNSEnabled/isProxyEnabled it's now possible to override this
behavior.
This commit is contained in:
Davide De Rosa 2022-03-26 17:15:36 +01:00
parent 4bfa0b4e74
commit f046bcd629
3 changed files with 112 additions and 91 deletions

View File

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- OpenVPN: Parse authentication requirement from `--auth-user-pass`.
- OpenVPN: Handle multiple `--remote` options correctly.
- OpenVPN: Explicitly enable/disable DNS/proxy settings.
### Changed

View File

@ -644,112 +644,116 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
return
}
var dnsServers: [String] = []
var dnsSettings: NEDNSSettings?
if #available(iOS 14, macOS 11, *) {
switch cfg.configuration.dnsProtocol {
case .https:
dnsServers = cfg.configuration.dnsServers ?? []
guard let serverURL = cfg.configuration.dnsHTTPSURL else {
if cfg.configuration.isDNSEnabled ?? true {
var dnsServers: [String] = []
if #available(iOS 14, macOS 11, *) {
switch cfg.configuration.dnsProtocol {
case .https:
dnsServers = cfg.configuration.dnsServers ?? []
guard let serverURL = cfg.configuration.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:
guard let dnsServers = cfg.configuration.dnsServers else {
session?.shutdown(error: OpenVPNProviderError.dnsFailure)
return
}
guard let serverName = cfg.configuration.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)")
default:
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:
guard let dnsServers = cfg.configuration.dnsServers else {
session?.shutdown(error: OpenVPNProviderError.dnsFailure)
return
// fall back
if dnsSettings == nil {
dnsServers = []
if let servers = cfg.configuration.dnsServers,
!servers.isEmpty {
dnsServers = servers
} else if let servers = options.dnsServers {
dnsServers = servers
}
guard let serverName = cfg.configuration.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)")
default:
break
}
}
// fall back
if dnsSettings == nil {
dnsServers = []
if let servers = cfg.configuration.dnsServers,
!servers.isEmpty {
dnsServers = servers
} else if let servers = options.dnsServers {
dnsServers = servers
}
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)
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 = cfg.configuration.searchDomains ?? options.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)
if !dnsServers.isEmpty {
log.info("DNS: Using servers \(dnsServers.maskedDescription)")
dnsSettings = NEDNSSettings(servers: dnsServers)
} else {
ipv4Settings?.includedRoutes?.insert(NEIPv4Route(destinationAddress: server, subnetMask: "255.255.255.255"), at: 0)
// log.warning("DNS: No servers provided, using fall-back servers: \(fallbackDNSServers.maskedDescription)")
// dnsSettings = NEDNSSettings(servers: fallbackDNSServers)
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 = cfg.configuration.searchDomains ?? options.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 let httpsProxy = cfg.configuration.httpsProxy ?? options.httpsProxy {
proxySettings = NEProxySettings()
proxySettings?.httpsServer = httpsProxy.neProxy()
proxySettings?.httpsEnabled = true
log.info("Routing: Setting HTTPS proxy \(httpsProxy.address.maskedDescription):\(httpsProxy.port)")
}
if let httpProxy = cfg.configuration.httpProxy ?? options.httpProxy {
if proxySettings == nil {
if cfg.configuration.isProxyEnabled ?? true {
if let httpsProxy = cfg.configuration.httpsProxy ?? options.httpsProxy {
proxySettings = NEProxySettings()
proxySettings?.httpsServer = httpsProxy.neProxy()
proxySettings?.httpsEnabled = true
log.info("Routing: Setting HTTPS proxy \(httpsProxy.address.maskedDescription):\(httpsProxy.port)")
}
proxySettings?.httpServer = httpProxy.neProxy()
proxySettings?.httpEnabled = true
log.info("Routing: Setting HTTP proxy \(httpProxy.address.maskedDescription):\(httpProxy.port)")
}
if let pacURL = cfg.configuration.proxyAutoConfigurationURL ?? options.proxyAutoConfigurationURL {
if proxySettings == nil {
proxySettings = NEProxySettings()
if let httpProxy = cfg.configuration.httpProxy ?? options.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 = cfg.configuration.proxyAutoConfigurationURL ?? options.proxyAutoConfigurationURL {
if proxySettings == nil {
proxySettings = NEProxySettings()
}
proxySettings?.proxyAutoConfigurationURL = pacURL
proxySettings?.autoProxyConfigurationEnabled = true
log.info("Routing: Setting PAC \(pacURL.maskedDescription)")
}
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 = cfg.configuration.proxyBypassDomains ?? options.proxyBypassDomains {
proxySettings?.exceptionList = bypass
log.info("Routing: Setting proxy by-pass list: \(bypass.maskedDescription)")
// only set if there is a proxy (proxySettings set to non-nil above)
if let bypass = cfg.configuration.proxyBypassDomains ?? options.proxyBypassDomains {
proxySettings?.exceptionList = bypass
log.info("Routing: Setting proxy by-pass list: \(bypass.maskedDescription)")
}
}
// block LAN if desired

View File

@ -252,6 +252,9 @@ extension OpenVPN {
/// The settings for IPv6. `OpenVPNSession` only evaluates this server-side.
public var ipv6: IPv6Settings?
/// Set false to ignore DNS settings, even when pushed.
public var isDNSEnabled: Bool?
/// The DNS protocol, defaults to `.plain` (iOS 14+ / macOS 11+).
public var dnsProtocol: DNSProtocol?
@ -282,6 +285,9 @@ extension OpenVPN {
/// The Proxy Auto-Configuration (PAC) url.
public var proxyAutoConfigurationURL: URL?
/// Set false to ignore proxy settings, even when pushed.
public var isProxyEnabled: Bool?
/// The HTTP proxy.
public var httpProxy: Proxy?
@ -341,11 +347,13 @@ extension OpenVPN {
peerId: peerId,
ipv4: ipv4,
ipv6: ipv6,
isDNSEnabled: isDNSEnabled,
dnsProtocol: dnsProtocol,
dnsServers: dnsServers,
dnsHTTPSURL: dnsHTTPSURL,
dnsTLSServerName: dnsTLSServerName,
searchDomains: searchDomains,
isProxyEnabled: isProxyEnabled,
httpProxy: httpProxy,
httpsProxy: httpsProxy,
proxyAutoConfigurationURL: proxyAutoConfigurationURL,
@ -436,6 +444,9 @@ extension OpenVPN {
/// - Seealso: `ConfigurationBuilder.ipv6`
public let ipv6: IPv6Settings?
/// - Seealso: `ConfigurationBuilder.isDNSEnabled`
public let isDNSEnabled: Bool?
/// - Seealso: `ConfigurationBuilder.dnsProtocol`
public let dnsProtocol: DNSProtocol?
@ -451,6 +462,9 @@ extension OpenVPN {
/// - Seealso: `ConfigurationBuilder.searchDomains`
public let searchDomains: [String]?
/// - Seealso: `ConfigurationBuilder.isProxyEnabled`
public let isProxyEnabled: Bool?
/// - Seealso: `ConfigurationBuilder.httpProxy`
public let httpProxy: Proxy?
@ -519,11 +533,13 @@ extension OpenVPN.Configuration {
builder.peerId = peerId
builder.ipv4 = ipv4
builder.ipv6 = ipv6
builder.isDNSEnabled = isDNSEnabled
builder.dnsProtocol = dnsProtocol
builder.dnsServers = dnsServers
builder.dnsHTTPSURL = dnsHTTPSURL
builder.dnsTLSServerName = dnsTLSServerName
builder.searchDomains = searchDomains
builder.isProxyEnabled = isProxyEnabled
builder.httpProxy = httpProxy
builder.httpsProxy = httpsProxy
builder.proxyAutoConfigurationURL = proxyAutoConfigurationURL