Merge pull request #196 from passepartoutvpn/secure-dns

DNS over HTTPS/TLS
This commit is contained in:
Davide De Rosa 2021-01-26 10:02:47 +01:00 committed by GitHub
commit 9567be7563
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 122 additions and 6 deletions

View File

@ -18,6 +18,7 @@ custom_categories:
children: children:
- BidirectionalState - BidirectionalState
- ConfigurationError - ConfigurationError
- DNSProtocol
- DNSResolver - DNSResolver
- DNSRecord - DNSRecord
- EndpointProtocol - EndpointProtocol

View File

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Handle `--data-ciphers` and `data-ciphers-fallback` from OpenVPN 2.5 - Handle `--data-ciphers` and `data-ciphers-fallback` from OpenVPN 2.5
- Support DNS over HTTPS (DoH) and TLS (DoT).
## 3.2.0 (2021-01-07) ## 3.2.0 (2021-01-07)

View File

@ -186,6 +186,8 @@
0E749F622178911D00BB2701 /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; }; 0E749F622178911D00BB2701 /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; };
0E7F3F6A246ABA0F006BE77F /* IPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F3F69246ABA0F006BE77F /* IPHeader.swift */; }; 0E7F3F6A246ABA0F006BE77F /* IPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F3F69246ABA0F006BE77F /* IPHeader.swift */; };
0E7F3F6B246ABA0F006BE77F /* IPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F3F69246ABA0F006BE77F /* IPHeader.swift */; }; 0E7F3F6B246ABA0F006BE77F /* IPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F3F69246ABA0F006BE77F /* IPHeader.swift */; };
0E94E8EA25BACEBD0040BC30 /* DNSProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E94E8E925BACEBD0040BC30 /* DNSProtocol.swift */; };
0E94E8EB25BACEBD0040BC30 /* DNSProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E94E8E925BACEBD0040BC30 /* DNSProtocol.swift */; };
0EA82A282190B220007960EB /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E3251C51F95770D00C108D9 /* TunnelKit.framework */; }; 0EA82A282190B220007960EB /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E3251C51F95770D00C108D9 /* TunnelKit.framework */; };
0EA82A3E2190B2BC007960EB /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; }; 0EA82A3E2190B2BC007960EB /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; };
0EAC57372494277A00D0FCE0 /* OpenVPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57312494277A00D0FCE0 /* OpenVPNProvider.swift */; }; 0EAC57372494277A00D0FCE0 /* OpenVPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EAC57312494277A00D0FCE0 /* OpenVPNProvider.swift */; };
@ -567,6 +569,7 @@
0E749F612178911C00BB2701 /* pia-2048.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = "pia-2048.pem"; sourceTree = "<group>"; }; 0E749F612178911C00BB2701 /* pia-2048.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = "pia-2048.pem"; sourceTree = "<group>"; };
0E7F3F69246ABA0F006BE77F /* IPHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPHeader.swift; sourceTree = "<group>"; }; 0E7F3F69246ABA0F006BE77F /* IPHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPHeader.swift; sourceTree = "<group>"; };
0E85A25B202CCA3D0059E9F9 /* Host.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Host.entitlements; sourceTree = "<group>"; }; 0E85A25B202CCA3D0059E9F9 /* Host.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Host.entitlements; sourceTree = "<group>"; };
0E94E8E925BACEBD0040BC30 /* DNSProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSProtocol.swift; sourceTree = "<group>"; };
0EA82A232190B220007960EB /* TunnelKitTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "TunnelKitTests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 0EA82A232190B220007960EB /* TunnelKitTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "TunnelKitTests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0EAC57312494277A00D0FCE0 /* OpenVPNProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNProvider.swift; sourceTree = "<group>"; }; 0EAC57312494277A00D0FCE0 /* OpenVPNProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNProvider.swift; sourceTree = "<group>"; };
0EAC57322494277A00D0FCE0 /* MockVPNProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockVPNProvider.swift; sourceTree = "<group>"; }; 0EAC57322494277A00D0FCE0 /* MockVPNProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockVPNProvider.swift; sourceTree = "<group>"; };
@ -1074,6 +1077,7 @@
0EFEB4432006D3C800F81029 /* Data+Manipulation.swift */, 0EFEB4432006D3C800F81029 /* Data+Manipulation.swift */,
0E411B992271F90700E0852C /* DNS.h */, 0E411B992271F90700E0852C /* DNS.h */,
0E411B9A2271F90700E0852C /* DNS.m */, 0E411B9A2271F90700E0852C /* DNS.m */,
0E94E8E925BACEBD0040BC30 /* DNSProtocol.swift */,
0EE2F9E522918DA100F56F49 /* DNSResolver.swift */, 0EE2F9E522918DA100F56F49 /* DNSResolver.swift */,
0E011F7C2196D97200BA59EE /* EndpointProtocol.swift */, 0E011F7C2196D97200BA59EE /* EndpointProtocol.swift */,
0EFEB4362006D3C800F81029 /* Errors.h */, 0EFEB4362006D3C800F81029 /* Errors.h */,
@ -2036,6 +2040,7 @@
0E23B44122982AF800304C30 /* OpenVPNSession+PIA.swift in Sources */, 0E23B44122982AF800304C30 /* OpenVPNSession+PIA.swift in Sources */,
0E23B42D22982AF800304C30 /* ControlChannelSerializer.swift in Sources */, 0E23B42D22982AF800304C30 /* ControlChannelSerializer.swift in Sources */,
0EE2F9F622918DA100F56F49 /* NEUDPSocket.swift in Sources */, 0EE2F9F622918DA100F56F49 /* NEUDPSocket.swift in Sources */,
0E94E8EA25BACEBD0040BC30 /* DNSProtocol.swift in Sources */,
0EE2F96E2291636B00F56F49 /* IPv4Settings.swift in Sources */, 0EE2F96E2291636B00F56F49 /* IPv4Settings.swift in Sources */,
0EFEB4662006D3C800F81029 /* ZeroingData.swift in Sources */, 0EFEB4662006D3C800F81029 /* ZeroingData.swift in Sources */,
0EE2FA0622918DA100F56F49 /* Utils.swift in Sources */, 0EE2FA0622918DA100F56F49 /* Utils.swift in Sources */,
@ -2125,6 +2130,7 @@
0E23B44222982AF800304C30 /* OpenVPNSession+PIA.swift in Sources */, 0E23B44222982AF800304C30 /* OpenVPNSession+PIA.swift in Sources */,
0E23B42E22982AF800304C30 /* ControlChannelSerializer.swift in Sources */, 0E23B42E22982AF800304C30 /* ControlChannelSerializer.swift in Sources */,
0EE2F9F722918DA100F56F49 /* NEUDPSocket.swift in Sources */, 0EE2F9F722918DA100F56F49 /* NEUDPSocket.swift in Sources */,
0E94E8EB25BACEBD0040BC30 /* DNSProtocol.swift in Sources */,
0EE2F96F2291636B00F56F49 /* IPv4Settings.swift in Sources */, 0EE2F96F2291636B00F56F49 /* IPv4Settings.swift in Sources */,
0EFEB49C2006D7F300F81029 /* Data+Manipulation.swift in Sources */, 0EFEB49C2006D7F300F81029 /* Data+Manipulation.swift in Sources */,
0EE2FA0722918DA100F56F49 /* Utils.swift in Sources */, 0EE2FA0722918DA100F56F49 /* Utils.swift in Sources */,

View File

@ -0,0 +1,42 @@
//
// DNSProtocol.swift
// TunnelKit
//
// Created by Davide De Rosa on 1/22/21.
// Copyright (c) 2021 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
/// The protocol used in DNS servers.
public enum DNSProtocol: String, Codable {
/// The value to fall back to when unset.
public static let fallback: DNSProtocol = .plain
/// Standard plaintext DNS (port 53).
case plain
/// DNS over HTTPS.
case https
/// DNS over TLS (port 853).
case tls
}

View File

@ -692,10 +692,35 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
dnsServers = fallbackDNSServers dnsServers = fallbackDNSServers
} }
let dnsSettings = NEDNSSettings(servers: dnsServers) var dnsSettings = NEDNSSettings(servers: dnsServers)
if #available(iOS 14, macOS 11, *) {
switch cfg.sessionConfiguration.dnsProtocol {
case .https:
guard let serverURL = cfg.sessionConfiguration.dnsHTTPSURL else {
break
}
let specific = NEDNSOverHTTPSSettings(servers: dnsServers)
specific.serverURL = serverURL
dnsSettings = specific
case .tls:
guard let serverName = cfg.sessionConfiguration.dnsTLSServerName else {
break
}
let specific = NEDNSOverTLSSettings(servers: dnsServers)
specific.serverName = serverName
dnsSettings = specific
default:
break
}
}
// "hack" for split DNS (i.e. use VPN only for DNS)
if !isGateway { if !isGateway {
dnsSettings.matchDomains = [""] dnsSettings.matchDomains = [""]
} }
if let searchDomains = cfg.sessionConfiguration.searchDomains ?? options.searchDomains { if let searchDomains = cfg.sessionConfiguration.searchDomains ?? options.searchDomains {
log.info("DNS: Using search domains \(searchDomains.maskedDescription)") log.info("DNS: Using search domains \(searchDomains.maskedDescription)")
dnsSettings.domainName = searchDomains.first dnsSettings.domainName = searchDomains.first

View File

@ -258,9 +258,18 @@ extension OpenVPN {
/// The settings for IPv6. `OpenVPNSession` only evaluates this server-side. /// The settings for IPv6. `OpenVPNSession` only evaluates this server-side.
public var ipv6: IPv6Settings? public var ipv6: IPv6Settings?
/// The DNS servers. /// The DNS protocol, defaults to `.plain` (iOS 14+ / macOS 11+).
public var dnsProtocol: DNSProtocol?
/// The DNS servers if `dnsProtocol = .plain` or nil.
public var dnsServers: [String]? public var dnsServers: [String]?
/// The server URL if `dnsProtocol = .https`.
public var dnsHTTPSURL: URL?
/// The server name if `dnsProtocol = .tls`.
public var dnsTLSServerName: String?
/// The search domain. /// The search domain.
@available(*, deprecated, message: "Use searchDomains instead") @available(*, deprecated, message: "Use searchDomains instead")
public var searchDomain: String? { public var searchDomain: String? {
@ -327,7 +336,10 @@ extension OpenVPN {
peerId: peerId, peerId: peerId,
ipv4: ipv4, ipv4: ipv4,
ipv6: ipv6, ipv6: ipv6,
dnsProtocol: dnsProtocol,
dnsServers: dnsServers, dnsServers: dnsServers,
dnsHTTPSURL: dnsHTTPSURL,
dnsTLSServerName: dnsTLSServerName,
searchDomains: searchDomains, searchDomains: searchDomains,
httpProxy: httpProxy, httpProxy: httpProxy,
httpsProxy: httpsProxy, httpsProxy: httpsProxy,
@ -438,9 +450,18 @@ extension OpenVPN {
/// - Seealso: `ConfigurationBuilder.ipv6` /// - Seealso: `ConfigurationBuilder.ipv6`
public let ipv6: IPv6Settings? public let ipv6: IPv6Settings?
/// - Seealso: `ConfigurationBuilder.dnsProtocol`
public let dnsProtocol: DNSProtocol?
/// - Seealso: `ConfigurationBuilder.dnsServers` /// - Seealso: `ConfigurationBuilder.dnsServers`
public let dnsServers: [String]? public let dnsServers: [String]?
/// - Seealso: `ConfigurationBuilder.dnsHTTPSURL`
public let dnsHTTPSURL: URL?
/// - Seealso: `ConfigurationBuilder.dnsTLSServerName`
public let dnsTLSServerName: String?
/// - Seealso: `ConfigurationBuilder.searchDomains` /// - Seealso: `ConfigurationBuilder.searchDomains`
public let searchDomains: [String]? public let searchDomains: [String]?
@ -514,7 +535,10 @@ extension OpenVPN.Configuration {
builder.peerId = peerId builder.peerId = peerId
builder.ipv4 = ipv4 builder.ipv4 = ipv4
builder.ipv6 = ipv6 builder.ipv6 = ipv6
builder.dnsProtocol = dnsProtocol
builder.dnsServers = dnsServers builder.dnsServers = dnsServers
builder.dnsHTTPSURL = dnsHTTPSURL
builder.dnsTLSServerName = dnsTLSServerName
builder.searchDomains = searchDomains builder.searchDomains = searchDomains
builder.httpProxy = httpProxy builder.httpProxy = httpProxy
builder.httpsProxy = httpsProxy builder.httpsProxy = httpsProxy
@ -589,10 +613,27 @@ extension OpenVPN.Configuration {
} else { } else {
log.info("\tGateway: not configured") log.info("\tGateway: not configured")
} }
if let dnsServers = dnsServers, !dnsServers.isEmpty { switch dnsProtocol {
log.info("\tDNS: \(dnsServers.maskedDescription)") case .https:
} else { if let dnsHTTPSURL = dnsHTTPSURL {
log.info("\tDNS: not configured") log.info("\tDNS over HTTPS: \(dnsHTTPSURL.maskedDescription)")
} else {
log.info("\tDNS: not configured")
}
case .tls:
if let dnsTLSServerName = dnsTLSServerName {
log.info("\tDNS over TLS: \(dnsTLSServerName.maskedDescription)")
} else {
log.info("\tDNS: not configured")
}
default:
if let dnsServers = dnsServers, !dnsServers.isEmpty {
log.info("\tDNS: \(dnsServers.maskedDescription)")
} else {
log.info("\tDNS: not configured")
}
} }
if let searchDomains = searchDomains, !searchDomains.isEmpty { if let searchDomains = searchDomains, !searchDomains.isEmpty {
log.info("\tSearch domains: \(searchDomains.maskedDescription)") log.info("\tSearch domains: \(searchDomains.maskedDescription)")