Adding Mullvad to DNS (#4927)

* Update dns.json

* Fix Mullvad DNS review issues

* Add Mullvad secondary resolvers

* Register DoH before changing adapter DNS

* Report DNS failures to tweak workflow

* Handle non-terminating DNS assignment failures

* Preserve DNS fallback and document Mullvad options

---------

Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
Graham David
2026-08-09 19:43:19 -05:00
committed by GitHub
co-authored by Chris Titus
parent afc3e1eec2
commit 0aa4ab3a40
8 changed files with 262 additions and 29 deletions
+105 -5
View File
@@ -10,7 +10,8 @@ BeforeAll {
param(
$InterfaceIndex,
$ServerAddresses,
[switch]$ResetServerAddresses
[switch]$ResetServerAddresses,
$ErrorAction
)
}
function netsh {
@@ -52,6 +53,23 @@ Describe "Set-WinUtilDNS" {
Secondary6 = "2606:4700:4700::1001"
DohTemplate = "https://cloudflare-dns.com/dns-query"
}
Mullvad = [pscustomobject]@{
Primary = "194.242.2.2"
Secondary = "194.242.2.3"
Primary6 = "2a07:e340::2"
Secondary6 = "2a07:e340::3"
DohOnly = $true
DohTemplate = "https://dns.mullvad.net/dns-query"
SecondaryDohTemplate = "https://adblock.dns.mullvad.net/dns-query"
}
MullvadNoSecondary = [pscustomobject]@{
Primary = "194.242.2.2"
Secondary = ""
Primary6 = "2a07:e340::2"
Secondary6 = ""
DohOnly = $true
DohTemplate = "https://dns.mullvad.net/dns-query"
}
}
}
})
@@ -88,8 +106,9 @@ Describe "Set-WinUtilDNS" {
}
It "sets IPv4 and IPv6 DNS server addresses separately and applies DoH templates" {
Set-WinUtilDNS -DNSProvider "Cloudflare"
$result = Set-WinUtilDNS -DNSProvider "Cloudflare"
$result | Should -BeTrue
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter {
$InterfaceIndex -eq 7 -and
$ServerAddresses.Count -eq 2 -and
@@ -131,6 +150,79 @@ Describe "Set-WinUtilDNS" {
Should -Invoke -CommandName Add-DnsClientDohServerAddress -Times 3 -Exactly
}
It "filters empty DNS server addresses" {
Set-WinUtilDNS -DNSProvider "MullvadNoSecondary"
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter {
$InterfaceIndex -eq 7 -and
$ServerAddresses.Count -eq 1 -and
$ServerAddresses[0] -eq "194.242.2.2"
}
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter {
$InterfaceIndex -eq 7 -and
$ServerAddresses.Count -eq 1 -and
$ServerAddresses[0] -eq "2a07:e340::2"
}
Should -Invoke -CommandName Add-DnsClientDohServerAddress -Times 2 -Exactly
}
It "applies the matching DoH template to secondary resolvers" {
Set-WinUtilDNS -DNSProvider "Mullvad"
Should -Invoke -CommandName Add-DnsClientDohServerAddress -Times 2 -Exactly -ParameterFilter {
$ServerAddress -in @("194.242.2.2", "2a07:e340::2") -and
$DohTemplate -eq "https://dns.mullvad.net/dns-query"
}
Should -Invoke -CommandName Add-DnsClientDohServerAddress -Times 2 -Exactly -ParameterFilter {
$ServerAddress -in @("194.242.2.3", "2a07:e340::3") -and
$DohTemplate -eq "https://adblock.dns.mullvad.net/dns-query"
}
}
It "does not apply a DoH-only provider when DoH is unsupported" {
Mock Get-Command { return $null } -ParameterFilter { $Name -eq "Add-DnsClientDohServerAddress" }
$result = Set-WinUtilDNS -DNSProvider "Mullvad"
$result | Should -BeFalse
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 0 -Exactly
Should -Invoke -CommandName Add-DnsClientDohServerAddress -Times 0 -Exactly
Should -Invoke -CommandName Write-Warning -Times 1 -Exactly -ParameterFilter {
$Message -eq "DNS provider Mullvad requires DNS over HTTPS, which is not supported on this system."
}
}
It "does not change adapter DNS when DoH registration fails" {
Mock Add-DnsClientDohServerAddress { throw "DoH registration failed" }
$result = Set-WinUtilDNS -DNSProvider "Mullvad"
$result | Should -BeFalse
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 0 -Exactly
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
$Level -eq "ERROR" -and
$Component -eq "DNS" -and
$Message -like "DNS provider Mullvad was not completed: *"
}
}
It "falls back to plain DNS when optional DoH registration fails" {
Mock Add-DnsClientDohServerAddress { throw "DoH registration failed" }
$result = Set-WinUtilDNS -DNSProvider "Cloudflare"
$result | Should -BeTrue
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 2 -Exactly
Should -Invoke -CommandName Write-Warning -Times 1 -Exactly -ParameterFilter {
$Message -eq "DNS over HTTPS setup for provider Cloudflare failed; continuing with plain DNS."
}
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
$Level -eq "WARN" -and
$Component -eq "DNS" -and
$Message -like "DNS over HTTPS setup for provider Cloudflare failed; continuing with plain DNS: *"
}
}
It "resets DNS to DHCP and removes the applied DoH configuration" {
Mock Test-Path { return $true } -ParameterFilter { $Path -like "*DohInterfaceSettings*" }
Mock Get-ChildItem {
@@ -178,15 +270,23 @@ Describe "Set-WinUtilDNS" {
Should -Invoke -CommandName Remove-DnsClientDohServerAddress -Times 4 -Exactly
}
It "catches DNS setter failures so the tweak runspace can continue" {
Mock Set-DnsClientServerAddress { throw "DNS failed" }
It "catches non-terminating DNS setter failures so the tweak runspace can continue" {
Mock Set-DnsClientServerAddress { Write-Error "DNS failed" -ErrorAction $ErrorAction }
{ Set-WinUtilDNS -DNSProvider "Cloudflare" } | Should -Not -Throw
$result = Set-WinUtilDNS -DNSProvider "Cloudflare"
$result | Should -BeFalse
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
$Level -eq "ERROR" -and
$Component -eq "DNS" -and
$Message -like "DNS provider Cloudflare was not completed: *"
}
}
It "returns failure for an unknown DNS provider" {
$result = Set-WinUtilDNS -DNSProvider "Unknown"
$result | Should -BeFalse
Should -Invoke -CommandName Set-DnsClientServerAddress -Times 0 -Exactly
}
}