[PATCH] Add DNSMatchDomains property to Interface (wireguard-apple)

Robert Oschwald robertoschwald at gmail.com
Fri Apr 5 12:34:11 UTC 2024


Is in the GH mirror as PR since a while. Would be great if one can apply it. https://github.com/WireGuard/wireguard-apple/pull/11




From bf396fb47ea5dfca7d86f014281fff0015cee675 Mon Sep 17 00:00:00 2001
From: Frank Riley <fhriley at gmail.com>
Date: Thu, 4 Mar 2021 16:30:01 -0800
Subject: [PATCH] Add DNSMatchDomains property to Interface

Based on the work of Stephen Larew <stephen at slarew.net>.

This adds split DNS capability. MacOS and iOS don't fully support the separation of search domains and match domains so a best effort is made to implement to what the configuration intends.

Signed-off-by: Frank Riley <fhriley at gmail.com>
---
.../TunnelConfiguration+WgQuickConfig.swift | 11 ++++++++--
.../Base.lproj/Localizable.strings | 1 +
.../TunnelConfiguration+UapiConfig.swift | 1 +
Sources/WireGuardApp/UI/TunnelViewModel.swift | 8 +++++++
.../TunnelDetailTableViewController.swift | 2 +-
.../TunnelEditTableViewController.swift | 5 ++++-
.../WireGuardApp/UI/macOS/View/highlighter.c | 9 ++++++++
.../TunnelDetailTableViewController.swift | 2 +-
.../WireGuardKit/InterfaceConfiguration.swift | 4 +++-
.../PacketTunnelSettingsGenerator.swift | 21 ++++++++++++++++++-
10 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/Sources/Shared/Model/TunnelConfiguration+WgQuickConfig.swift b/Sources/Shared/Model/TunnelConfiguration+WgQuickConfig.swift
index 5d5216cb..368ba1e1 100644
--- a/Sources/Shared/Model/TunnelConfiguration+WgQuickConfig.swift
+++ b/Sources/Shared/Model/TunnelConfiguration+WgQuickConfig.swift
@@ -61,7 +61,7 @@ extension TunnelConfiguration {
let keyWithCase = trimmedLine[..<equalsIndex].trimmingCharacters(in: .whitespacesAndNewlines)
let key = keyWithCase.lowercased()
let value = trimmedLine[trimmedLine.index(equalsIndex, offsetBy: 1)...].trimmingCharacters(in: .whitespacesAndNewlines)
- let keysWithMultipleEntriesAllowed: Set<String> = ["address", "allowedips", "dns"]
+ let keysWithMultipleEntriesAllowed: Set<String> = ["address", "allowedips", "dns", "dnsmatchdomains"]
if let presentValue = attributes[key] {
if keysWithMultipleEntriesAllowed.contains(key) {
attributes[key] = presentValue + "," + value
@@ -71,7 +71,7 @@ extension TunnelConfiguration {
} else {
attributes[key] = value
}
- let interfaceSectionKeys: Set<String> = ["privatekey", "listenport", "address", "dns", "mtu"]
+ let interfaceSectionKeys: Set<String> = ["privatekey", "listenport", "address", "dns", "dnsmatchdomains", "mtu"]
let peerSectionKeys: Set<String> = ["publickey", "presharedkey", "allowedips", "endpoint", "persistentkeepalive"]
if parserState == .inInterfaceSection {
guard interfaceSectionKeys.contains(key) else {
@@ -139,6 +139,10 @@ extension TunnelConfiguration {
let dnsString = dnsLine.joined(separator: ", ")
output.append("DNS = \(dnsString)\n")
}
+ if !interface.dnsMatchDomains.isEmpty {
+ let dnsMatchString = interface.dnsMatchDomains.joined(separator: ", ")
+ output.append("DNSMatchDomains = \(dnsMatchString)\n")
+ }
if let mtu = interface.mtu {
output.append("MTU = \(mtu)\n")
}
@@ -201,6 +205,9 @@ extension TunnelConfiguration {
interface.dns = dnsServers
interface.dnsSearch = dnsSearch
}
+ if let dnsMatchString = attributes["dnsmatchdomains"] {
+ interface.dnsMatchDomains = dnsMatchString.splitToArray(trimmingCharacters: .whitespacesAndNewlines)
+ }
if let mtuString = attributes["mtu"] {
guard let mtu = UInt16(mtuString) else {
throw ParseError.interfaceHasInvalidMTU(mtuString)
diff --git a/Sources/WireGuardApp/Base.lproj/Localizable.strings b/Sources/WireGuardApp/Base.lproj/Localizable.strings
index 40023ecb..0eb308c0 100644
--- a/Sources/WireGuardApp/Base.lproj/Localizable.strings
+++ b/Sources/WireGuardApp/Base.lproj/Localizable.strings
@@ -82,6 +82,7 @@
"tunnelInterfaceListenPort" = "Listen port";
"tunnelInterfaceMTU" = "MTU";
"tunnelInterfaceDNS" = "DNS servers";
+"tunnelInterfaceDNSMatchDomains" = "DNS match domains";
"tunnelInterfaceStatus" = "Status";

"tunnelSectionTitlePeer" = "Peer";
diff --git a/Sources/WireGuardApp/Tunnel/TunnelConfiguration+UapiConfig.swift b/Sources/WireGuardApp/Tunnel/TunnelConfiguration+UapiConfig.swift
index cdc81cee..f2ff7633 100644
--- a/Sources/WireGuardApp/Tunnel/TunnelConfiguration+UapiConfig.swift
+++ b/Sources/WireGuardApp/Tunnel/TunnelConfiguration+UapiConfig.swift
@@ -75,6 +75,7 @@ extension TunnelConfiguration {
interfaceConfiguration?.addresses = base?.interface.addresses ?? []
interfaceConfiguration?.dns = base?.interface.dns ?? []
interfaceConfiguration?.dnsSearch = base?.interface.dnsSearch ?? []
+ interfaceConfiguration?.dnsMatchDomains = base?.interface.dnsMatchDomains ?? []
interfaceConfiguration?.mtu = base?.interface.mtu

if let interfaceConfiguration = interfaceConfiguration {
diff --git a/Sources/WireGuardApp/UI/TunnelViewModel.swift b/Sources/WireGuardApp/UI/TunnelViewModel.swift
index b65c8ccf..23b4f4d3 100644
--- a/Sources/WireGuardApp/UI/TunnelViewModel.swift
+++ b/Sources/WireGuardApp/UI/TunnelViewModel.swift
@@ -14,6 +14,7 @@ class TunnelViewModel {
case listenPort
case mtu
case dns
+ case dnsMatchDomains
case status
case toggleStatus

@@ -27,6 +28,7 @@ class TunnelViewModel {
case .listenPort: return tr("tunnelInterfaceListenPort")
case .mtu: return tr("tunnelInterfaceMTU")
case .dns: return tr("tunnelInterfaceDNS")
+ case .dnsMatchDomains: return tr("tunnelInterfaceDNSMatchDomains")
case .status: return tr("tunnelInterfaceStatus")
case .toggleStatus: return ""
}
@@ -144,6 +146,9 @@ class TunnelViewModel {
dns.append(contentsOf: config.dnsSearch)
scratchpad[.dns] = dns.joined(separator: ", ")
}
+ if !config.dnsMatchDomains.isEmpty {
+ scratchpad[.dnsMatchDomains] = config.dnsMatchDomains.joined(separator: ", ")
+ }
return scratchpad
}

@@ -207,6 +212,9 @@ class TunnelViewModel {
config.dns = dnsServers
config.dnsSearch = dnsSearch
}
+ if let dnsMatchString = scratchpad[.dnsMatchDomains] {
+ config.dnsMatchDomains = dnsMatchString.splitToArray(trimmingCharacters: .whitespacesAndNewlines)
+ }

guard errorMessages.isEmpty else { return .error(errorMessages.first!) }

diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift
index 196de0c6..1f2c1f95 100644
--- a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift
+++ b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift
@@ -15,7 +15,7 @@ class TunnelDetailTableViewController: UITableViewController {

static let interfaceFields: [TunnelViewModel.InterfaceField] = [
.name, .publicKey, .addresses,
- .listenPort, .mtu, .dns
+ .listenPort, .mtu, .dns, .dnsMatchDomains
]

static let peerFields: [TunnelViewModel.PeerField] = [
diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelEditTableViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelEditTableViewController.swift
index e44cf8d4..508caa6f 100644
--- a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelEditTableViewController.swift
+++ b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelEditTableViewController.swift
@@ -34,7 +34,7 @@ class TunnelEditTableViewController: UITableViewController {
let interfaceFieldsBySection: [[TunnelViewModel.InterfaceField]] = [
[.name],
[.privateKey, .publicKey, .generateKeyPair],
- [.addresses, .listenPort, .mtu, .dns]
+ [.addresses, .listenPort, .mtu, .dns, .dnsMatchDomains]
]

let peerFields: [TunnelViewModel.PeerField] = [
@@ -246,6 +246,9 @@ extension TunnelEditTableViewController {
case .dns:
cell.placeholderText = tunnelViewModel.peersData.contains(where: { $0.shouldStronglyRecommendDNS }) ? tr("tunnelEditPlaceholderTextStronglyRecommended") : tr("tunnelEditPlaceholderTextOptional")
cell.keyboardType = .numbersAndPunctuation
+ case .dnsMatchDomains:
+ cell.placeholderText = tr("tunnelEditPlaceholderTextOptional")
+ cell.keyboardType = .numbersAndPunctuation
case .listenPort, .mtu:
cell.placeholderText = tr("tunnelEditPlaceholderTextAutomatic")
cell.keyboardType = .numberPad
diff --git a/Sources/WireGuardApp/UI/macOS/View/highlighter.c b/Sources/WireGuardApp/UI/macOS/View/highlighter.c
index d89feda1..5caa09d3 100644
--- a/Sources/WireGuardApp/UI/macOS/View/highlighter.c
+++ b/Sources/WireGuardApp/UI/macOS/View/highlighter.c
@@ -343,6 +343,7 @@ enum field {
ListenPort,
Address,
DNS,
+ DNSMatchDomains,
MTU,
#ifndef MOBILE_WGQUICK_SUBSET
FwMark,
@@ -377,6 +378,7 @@ static enum field get_field(string_span_t s)
check_enum(ListenPort);
check_enum(Address);
check_enum(DNS);
+ check_enum(DNSMatchDomains);
check_enum(MTU);
check_enum(PublicKey);
check_enum(PresharedKey);
@@ -453,6 +455,12 @@ static void highlight_multivalue_value(struct highlight_span_array *ret, const s
else
append_highlight_span(ret, parent.s, s, HighlightError);
break;
+ case DNSMatchDomains:
+ if (is_valid_hostname(s))
+ append_highlight_span(ret, parent.s, s, HighlightHost);
+ else
+ append_highlight_span(ret, parent.s, s, HighlightError);
+ break;
case Address:
case AllowedIPs: {
size_t slash;
@@ -563,6 +571,7 @@ static void highlight_value(struct highlight_span_array *ret, const string_span_
}
case Address:
case DNS:
+ case DNSMatchDomains:
case AllowedIPs:
highlight_multivalue(ret, parent, s, section);
break;
diff --git a/Sources/WireGuardApp/UI/macOS/ViewController/TunnelDetailTableViewController.swift b/Sources/WireGuardApp/UI/macOS/ViewController/TunnelDetailTableViewController.swift
index 6ad8cf3f..2d87659c 100644
--- a/Sources/WireGuardApp/UI/macOS/ViewController/TunnelDetailTableViewController.swift
+++ b/Sources/WireGuardApp/UI/macOS/ViewController/TunnelDetailTableViewController.swift
@@ -35,7 +35,7 @@ class TunnelDetailTableViewController: NSViewController {

static let interfaceFields: [TunnelViewModel.InterfaceField] = [
.name, .status, .publicKey, .addresses,
- .listenPort, .mtu, .dns, .toggleStatus
+ .listenPort, .mtu, .dns, .dnsMatchDomains, .toggleStatus
]

static let peerFields: [TunnelViewModel.PeerField] = [
diff --git a/Sources/WireGuardKit/InterfaceConfiguration.swift b/Sources/WireGuardKit/InterfaceConfiguration.swift
index 4fb8f1b4..521d4b88 100644
--- a/Sources/WireGuardKit/InterfaceConfiguration.swift
+++ b/Sources/WireGuardKit/InterfaceConfiguration.swift
@@ -11,6 +11,7 @@ public struct InterfaceConfiguration {
public var mtu: UInt16?
public var dns = [DNSServer]()
public var dnsSearch = [String]()
+ public var dnsMatchDomains = [String]()

public init(privateKey: PrivateKey) {
self.privateKey = privateKey
@@ -27,6 +28,7 @@ extension InterfaceConfiguration: Equatable {
lhs.listenPort == rhs.listenPort &&
lhs.mtu == rhs.mtu &&
lhs.dns == rhs.dns &&
- lhs.dnsSearch == rhs.dnsSearch
+ lhs.dnsSearch == rhs.dnsSearch &&
+ lhs.dnsMatchDomains == rhs.dnsMatchDomains
}
}
diff --git a/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift b/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift
index c53a82cd..b059510f 100644
--- a/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift
+++ b/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift
@@ -87,9 +87,28 @@ class PacketTunnelSettingsGenerator {
let dnsServerStrings = tunnelConfiguration.interface.dns.map { $0.stringRepresentation }
let dnsSettings = NEDNSSettings(servers: dnsServerStrings)
dnsSettings.searchDomains = tunnelConfiguration.interface.dnsSearch
+ 
if !tunnelConfiguration.interface.dns.isEmpty {
- dnsSettings.matchDomains = [""] // All DNS queries must first go through the tunnel's DNS
+ dnsSettings.matchDomainsNoSearch = true
+ if tunnelConfiguration.interface.dnsMatchDomains.isEmpty {
+ // Add "" so that all DNS queries must first go through the tunnel's DNS.
+ // NEDNSSettings.searchDomains does not work so we add the searches to matchDomains,
+ // which does work.
+ dnsSettings.matchDomains = [""] + tunnelConfiguration.interface.dnsSearch
+ dnsSettings.matchDomainsNoSearch = false
+ } else {
+ // Don't add dnsSearch here because that would cause domains that aren't
+ // in dnsMatchDomains to be matched.
+ dnsSettings.matchDomains = tunnelConfiguration.interface.dnsMatchDomains
+ for domain in tunnelConfiguration.interface.dnsMatchDomains {
+ if tunnelConfiguration.interface.dnsSearch.contains(domain) {
+ dnsSettings.matchDomainsNoSearch = false
+ break
+ }
+ }
+ }
}
+ 
networkSettings.dnsSettings = dnsSettings
}



More information about the WireGuard mailing list