mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-09 17:41:14 +10:00
Add DNS-over-HTTPS (DoH) support (#4856)
* feat: Add DoH templates for DNS providers in configuration * feat: Implement DoH support for DNS configuration and management * feat(pester): enhance DNS tests to include DoH server address handling and template application * fix: address codex feedback * fix: update existing DoH server entries * fix: enable DoH auto-upgrade * fix: handle DNS setup failures * fix: remove DoH state on DHCP reset
This commit is contained in:
+16
-8
@@ -3,48 +3,56 @@
|
|||||||
"Primary": "8.8.8.8",
|
"Primary": "8.8.8.8",
|
||||||
"Secondary": "8.8.4.4",
|
"Secondary": "8.8.4.4",
|
||||||
"Primary6": "2001:4860:4860::8888",
|
"Primary6": "2001:4860:4860::8888",
|
||||||
"Secondary6": "2001:4860:4860::8844"
|
"Secondary6": "2001:4860:4860::8844",
|
||||||
|
"DohTemplate": "https://dns.google/dns-query"
|
||||||
},
|
},
|
||||||
"Cloudflare":{
|
"Cloudflare":{
|
||||||
"Primary": "1.1.1.1",
|
"Primary": "1.1.1.1",
|
||||||
"Secondary": "1.0.0.1",
|
"Secondary": "1.0.0.1",
|
||||||
"Primary6": "2606:4700:4700::1111",
|
"Primary6": "2606:4700:4700::1111",
|
||||||
"Secondary6": "2606:4700:4700::1001"
|
"Secondary6": "2606:4700:4700::1001",
|
||||||
|
"DohTemplate": "https://cloudflare-dns.com/dns-query"
|
||||||
},
|
},
|
||||||
"Cloudflare_Malware":{
|
"Cloudflare_Malware":{
|
||||||
"Primary": "1.1.1.2",
|
"Primary": "1.1.1.2",
|
||||||
"Secondary": "1.0.0.2",
|
"Secondary": "1.0.0.2",
|
||||||
"Primary6": "2606:4700:4700::1112",
|
"Primary6": "2606:4700:4700::1112",
|
||||||
"Secondary6": "2606:4700:4700::1002"
|
"Secondary6": "2606:4700:4700::1002",
|
||||||
|
"DohTemplate": "https://security.cloudflare-dns.com/dns-query"
|
||||||
},
|
},
|
||||||
"Cloudflare_Malware_Adult":{
|
"Cloudflare_Malware_Adult":{
|
||||||
"Primary": "1.1.1.3",
|
"Primary": "1.1.1.3",
|
||||||
"Secondary": "1.0.0.3",
|
"Secondary": "1.0.0.3",
|
||||||
"Primary6": "2606:4700:4700::1113",
|
"Primary6": "2606:4700:4700::1113",
|
||||||
"Secondary6": "2606:4700:4700::1003"
|
"Secondary6": "2606:4700:4700::1003",
|
||||||
|
"DohTemplate": "https://family.cloudflare-dns.com/dns-query"
|
||||||
},
|
},
|
||||||
"Open_DNS":{
|
"Open_DNS":{
|
||||||
"Primary": "208.67.222.222",
|
"Primary": "208.67.222.222",
|
||||||
"Secondary": "208.67.220.220",
|
"Secondary": "208.67.220.220",
|
||||||
"Primary6": "2620:119:35::35",
|
"Primary6": "2620:119:35::35",
|
||||||
"Secondary6": "2620:119:53::53"
|
"Secondary6": "2620:119:53::53",
|
||||||
|
"DohTemplate": "https://doh.opendns.com/dns-query"
|
||||||
},
|
},
|
||||||
"Quad9":{
|
"Quad9":{
|
||||||
"Primary": "9.9.9.9",
|
"Primary": "9.9.9.9",
|
||||||
"Secondary": "149.112.112.112",
|
"Secondary": "149.112.112.112",
|
||||||
"Primary6": "2620:fe::fe",
|
"Primary6": "2620:fe::fe",
|
||||||
"Secondary6": "2620:fe::9"
|
"Secondary6": "2620:fe::9",
|
||||||
|
"DohTemplate": "https://dns.quad9.net/dns-query"
|
||||||
},
|
},
|
||||||
"AdGuard_Ads_Trackers":{
|
"AdGuard_Ads_Trackers":{
|
||||||
"Primary": "94.140.14.14",
|
"Primary": "94.140.14.14",
|
||||||
"Secondary": "94.140.15.15",
|
"Secondary": "94.140.15.15",
|
||||||
"Primary6": "2a10:50c0::ad1:ff",
|
"Primary6": "2a10:50c0::ad1:ff",
|
||||||
"Secondary6": "2a10:50c0::ad2:ff"
|
"Secondary6": "2a10:50c0::ad2:ff",
|
||||||
|
"DohTemplate": "https://dns.adguard-dns.com/dns-query"
|
||||||
},
|
},
|
||||||
"AdGuard_Ads_Trackers_Malware_Adult":{
|
"AdGuard_Ads_Trackers_Malware_Adult":{
|
||||||
"Primary": "94.140.14.15",
|
"Primary": "94.140.14.15",
|
||||||
"Secondary": "94.140.15.16",
|
"Secondary": "94.140.15.16",
|
||||||
"Primary6": "2a10:50c0::bad1:ff",
|
"Primary6": "2a10:50c0::bad1:ff",
|
||||||
"Secondary6": "2a10:50c0::bad2:ff"
|
"Secondary6": "2a10:50c0::bad2:ff",
|
||||||
|
"DohTemplate": "https://family.adguard-dns.com/dns-query"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,23 +33,71 @@ function Set-WinUtilDNS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dohSupported = [bool](Get-Command Add-DnsClientDohServerAddress -ErrorAction SilentlyContinue)
|
||||||
|
$dnscacheBase = "HKLM:\System\CurrentControlSet\Services\Dnscache\InterfaceSpecificParameters"
|
||||||
|
|
||||||
Foreach ($Adapter in $Adapters) {
|
Foreach ($Adapter in $Adapters) {
|
||||||
|
$interfaceParams = "$dnscacheBase\$($Adapter.InterfaceGuid)"
|
||||||
|
|
||||||
if($DNSProvider -eq "DHCP") {
|
if($DNSProvider -eq "DHCP") {
|
||||||
Write-WinUtilLog -Component "DNS" -Message "Resetting DNS to DHCP on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex))."
|
Write-WinUtilLog -Component "DNS" -Message "Resetting DNS to DHCP on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex))."
|
||||||
Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ResetServerAddresses
|
Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ResetServerAddresses
|
||||||
netsh interface ip set dnsservers name="$($Adapter.Name)" source=dhcp
|
netsh interface ip set dnsservers name="$($Adapter.Name)" source=dhcp
|
||||||
netsh interface ipv6 set dnsservers name="$($Adapter.Name)" source=dhcp
|
netsh interface ipv6 set dnsservers name="$($Adapter.Name)" source=dhcp
|
||||||
|
|
||||||
|
$dohInterfaceSettings = "$interfaceParams\DohInterfaceSettings"
|
||||||
|
if (Test-Path $dohInterfaceSettings) {
|
||||||
|
if ($dohSupported) {
|
||||||
|
$dohServerAddresses = @(
|
||||||
|
Get-ChildItem -Path "$dohInterfaceSettings\Doh" -ErrorAction SilentlyContinue
|
||||||
|
Get-ChildItem -Path "$dohInterfaceSettings\Doh6" -ErrorAction SilentlyContinue
|
||||||
|
) | Select-Object -ExpandProperty PSChildName -Unique
|
||||||
|
|
||||||
|
foreach ($ip in $dohServerAddresses) {
|
||||||
|
if (Get-DnsClientDohServerAddress -ServerAddress $ip -ErrorAction SilentlyContinue) {
|
||||||
|
Write-WinUtilLog -Component "DNS" -Message "Removing DoH registration for $ip."
|
||||||
|
Remove-DnsClientDohServerAddress -ServerAddress $ip -Confirm:$false -ErrorAction Stop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Remove-Item -Path $dohInterfaceSettings -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-WinUtilLog -Component "DNS" -Message "Setting IPv4 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($dns.Primary), $($dns.Secondary)."
|
Write-WinUtilLog -Component "DNS" -Message "Setting IPv4 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($dns.Primary), $($dns.Secondary)."
|
||||||
Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ($dns.Primary, $dns.Secondary)
|
Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ($dns.Primary, $dns.Secondary)
|
||||||
Write-WinUtilLog -Component "DNS" -Message "Setting IPv6 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($dns.Primary6), $($dns.Secondary6)."
|
Write-WinUtilLog -Component "DNS" -Message "Setting IPv6 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($dns.Primary6), $($dns.Secondary6)."
|
||||||
Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ($dns.Primary6, $dns.Secondary6)
|
Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ($dns.Primary6, $dns.Secondary6)
|
||||||
|
|
||||||
|
if ($dohSupported -and $dns.DohTemplate) {
|
||||||
|
$ips = @($dns.Primary, $dns.Secondary, $dns.Primary6, $dns.Secondary6) | Where-Object { $_ }
|
||||||
|
foreach ($ip in $ips) {
|
||||||
|
$existing = Get-DnsClientDohServerAddress -ServerAddress $ip -ErrorAction SilentlyContinue
|
||||||
|
if ($existing) {
|
||||||
|
Set-DnsClientDohServerAddress -ServerAddress $ip -DohTemplate $dns.DohTemplate -AllowFallbackToUdp $false -AutoUpgrade $true -ErrorAction Stop
|
||||||
|
} else {
|
||||||
|
Write-WinUtilLog -Component "DNS" -Message "Registering DoH template for $ip."
|
||||||
|
Add-DnsClientDohServerAddress -ServerAddress $ip -DohTemplate $dns.DohTemplate -AllowFallbackToUdp $false -AutoUpgrade $true -ErrorAction Stop
|
||||||
|
}
|
||||||
|
|
||||||
|
$leaf = if ($ip.Contains(':')) { 'Doh6' } else { 'Doh' }
|
||||||
|
$regPath = "$interfaceParams\DohInterfaceSettings\$leaf\$ip"
|
||||||
|
|
||||||
|
if (-not (Test-Path $regPath)) {
|
||||||
|
New-Item -Path $regPath -Force -ErrorAction Stop | Out-Null
|
||||||
|
}
|
||||||
|
New-ItemProperty -Path $regPath -Name "DohFlags" -Value 1 -PropertyType QWord -Force -ErrorAction Stop | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($DNSProvider -ne "DHCP" -and $dohSupported -and $dns.DohTemplate) {
|
||||||
|
Clear-DnsClientCache
|
||||||
|
}
|
||||||
Write-WinUtilLog -Component "DNS" -Message "DNS provider change completed: $DNSProvider"
|
Write-WinUtilLog -Component "DNS" -Message "DNS provider change completed: $DNSProvider"
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "Unable to set DNS Provider due to an unhandled exception."
|
Write-Warning "DNS provider $DNSProvider was not completed because an error occurred."
|
||||||
Write-Warning $psitem.Exception.StackTrace
|
Write-Warning $psitem.Exception.Message
|
||||||
Write-WinUtilLog -Level "ERROR" -Component "DNS" -Message "Unable to set DNS provider $DNSProvider`: $($psitem.Exception.Message)"
|
Write-WinUtilLog -Level "ERROR" -Component "DNS" -Message "DNS provider $DNSProvider was not completed: $($psitem.Exception.Message)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-3
@@ -23,6 +23,20 @@ BeforeAll {
|
|||||||
param($Message, $Level, $Component)
|
param($Message, $Level, $Component)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Add-DnsClientDohServerAddress {
|
||||||
|
param($ServerAddress, $DohTemplate, $AllowFallbackToUdp, $AutoUpgrade, $ErrorAction)
|
||||||
|
}
|
||||||
|
function Set-DnsClientDohServerAddress {
|
||||||
|
param($ServerAddress, $DohTemplate, $AllowFallbackToUdp, $AutoUpgrade, $ErrorAction)
|
||||||
|
}
|
||||||
|
function Get-DnsClientDohServerAddress {
|
||||||
|
param($ServerAddress, $ErrorAction)
|
||||||
|
}
|
||||||
|
function Remove-DnsClientDohServerAddress {
|
||||||
|
param($ServerAddress, $Confirm, $ErrorAction)
|
||||||
|
}
|
||||||
|
function Clear-DnsClientCache { }
|
||||||
|
|
||||||
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilDNS.ps1")
|
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilDNS.ps1")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +50,7 @@ Describe "Set-WinUtilDNS" {
|
|||||||
Secondary = "1.0.0.1"
|
Secondary = "1.0.0.1"
|
||||||
Primary6 = "2606:4700:4700::1111"
|
Primary6 = "2606:4700:4700::1111"
|
||||||
Secondary6 = "2606:4700:4700::1001"
|
Secondary6 = "2606:4700:4700::1001"
|
||||||
|
DohTemplate = "https://cloudflare-dns.com/dns-query"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,6 +61,7 @@ Describe "Set-WinUtilDNS" {
|
|||||||
Name = "Ethernet"
|
Name = "Ethernet"
|
||||||
Status = "Up"
|
Status = "Up"
|
||||||
ifIndex = 7
|
ifIndex = 7
|
||||||
|
InterfaceGuid = "{1234-5678-90AB-CDEF}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mock Set-DnsClientServerAddress { }
|
Mock Set-DnsClientServerAddress { }
|
||||||
@@ -53,13 +69,25 @@ Describe "Set-WinUtilDNS" {
|
|||||||
Mock Write-WinUtilLog { }
|
Mock Write-WinUtilLog { }
|
||||||
Mock Write-Warning { }
|
Mock Write-Warning { }
|
||||||
Mock Write-Host { }
|
Mock Write-Host { }
|
||||||
|
|
||||||
|
Mock Get-Command { return $true } -ParameterFilter { $Name -eq "Add-DnsClientDohServerAddress" }
|
||||||
|
Mock Add-DnsClientDohServerAddress { }
|
||||||
|
Mock Set-DnsClientDohServerAddress { }
|
||||||
|
Mock Get-DnsClientDohServerAddress { return $null }
|
||||||
|
Mock Remove-DnsClientDohServerAddress { }
|
||||||
|
Mock Test-Path { return $false }
|
||||||
|
Mock Get-ChildItem { }
|
||||||
|
Mock New-Item { }
|
||||||
|
Mock New-ItemProperty { }
|
||||||
|
Mock Remove-Item { }
|
||||||
|
Mock Clear-DnsClientCache { }
|
||||||
}
|
}
|
||||||
|
|
||||||
AfterEach {
|
AfterEach {
|
||||||
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
It "sets IPv4 and IPv6 DNS server addresses separately" {
|
It "sets IPv4 and IPv6 DNS server addresses separately and applies DoH templates" {
|
||||||
Set-WinUtilDNS -DNSProvider "Cloudflare"
|
Set-WinUtilDNS -DNSProvider "Cloudflare"
|
||||||
|
|
||||||
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter {
|
||||||
@@ -77,9 +105,51 @@ Describe "Set-WinUtilDNS" {
|
|||||||
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 0 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 0 -Exactly -ParameterFilter {
|
||||||
$ServerAddresses.Count -eq 4
|
$ServerAddresses.Count -eq 4
|
||||||
}
|
}
|
||||||
|
Should -Invoke -CommandName Add-DnsClientDohServerAddress -Times 4 -Exactly
|
||||||
|
Should -Invoke -CommandName New-ItemProperty -Times 4 -ParameterFilter {
|
||||||
|
$Name -eq "DohFlags" -and $Value -eq 1
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Clear-DnsClientCache -Times 1 -Exactly
|
||||||
}
|
}
|
||||||
|
|
||||||
It "resets DNS to DHCP for IPv4 and IPv6" {
|
It "updates an existing DoH entry with the selected provider settings" {
|
||||||
|
Mock Get-DnsClientDohServerAddress {
|
||||||
|
if ($ServerAddress -eq "1.1.1.1") {
|
||||||
|
return [pscustomobject]@{ ServerAddress = $ServerAddress }
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-WinUtilDNS -DNSProvider "Cloudflare"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Set-DnsClientDohServerAddress -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ServerAddress -eq "1.1.1.1" -and
|
||||||
|
$DohTemplate -eq "https://cloudflare-dns.com/dns-query" -and
|
||||||
|
$AllowFallbackToUdp -eq $false -and
|
||||||
|
$AutoUpgrade -eq $true
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Add-DnsClientDohServerAddress -Times 3 -Exactly
|
||||||
|
}
|
||||||
|
|
||||||
|
It "resets DNS to DHCP and removes the applied DoH configuration" {
|
||||||
|
Mock Test-Path { return $true } -ParameterFilter { $Path -like "*DohInterfaceSettings*" }
|
||||||
|
Mock Get-ChildItem {
|
||||||
|
if ($Path -like "*\Doh6") {
|
||||||
|
return @(
|
||||||
|
[pscustomobject]@{ PSChildName = "2606:4700:4700::1111" }
|
||||||
|
[pscustomobject]@{ PSChildName = "2606:4700:4700::1001" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return @(
|
||||||
|
[pscustomobject]@{ PSChildName = "1.1.1.1" }
|
||||||
|
[pscustomobject]@{ PSChildName = "1.0.0.1" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Mock Get-DnsClientDohServerAddress {
|
||||||
|
[pscustomobject]@{ ServerAddress = $ServerAddress }
|
||||||
|
}
|
||||||
|
|
||||||
Set-WinUtilDNS -DNSProvider "DHCP"
|
Set-WinUtilDNS -DNSProvider "DHCP"
|
||||||
|
|
||||||
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter {
|
||||||
@@ -102,6 +172,10 @@ Describe "Set-WinUtilDNS" {
|
|||||||
$Arguments[4] -eq "name=Ethernet" -and
|
$Arguments[4] -eq "name=Ethernet" -and
|
||||||
$Arguments[5] -eq "source=dhcp"
|
$Arguments[5] -eq "source=dhcp"
|
||||||
}
|
}
|
||||||
|
Should -Invoke -CommandName Remove-Item -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Path -like "*DohInterfaceSettings*" -and $Recurse -eq $true -and $Force -eq $true
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Remove-DnsClientDohServerAddress -Times 4 -Exactly
|
||||||
}
|
}
|
||||||
|
|
||||||
It "catches DNS setter failures so the tweak runspace can continue" {
|
It "catches DNS setter failures so the tweak runspace can continue" {
|
||||||
@@ -112,7 +186,7 @@ Describe "Set-WinUtilDNS" {
|
|||||||
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
$Level -eq "ERROR" -and
|
$Level -eq "ERROR" -and
|
||||||
$Component -eq "DNS" -and
|
$Component -eq "DNS" -and
|
||||||
$Message -like "Unable to set DNS provider Cloudflare*"
|
$Message -like "DNS provider Cloudflare was not completed: *"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user