Repository navigation
Windows: stale catch-all NRPT rule after disconnect kills DNS machine-wide and deadlocks the client #7620
Replies: 1 comment
|
Thanks for the deep analisys @TobiKr, I've done a few tests and what decides if Windows DNS client recovers is the presence or not of the GPO group policy store registry key That part is a Windows mechanism: when the key is absent, a deletion applies immiediately as the local store is read directly and a change applies at once. Conversely, when the key exists the client's rules go into the group policy store, and a change there (adding or removing a rule) reaches the resolver only when the policy engine next applies DNS client policy; writing or deleting the registry key does not by itself trigger that. The interesting point is that the client does request a policy refresh on teardown (in Aside that, #7563, merged on 22 September, removes an empty group policy store before deciding where rules In the meantime this addresses the condition directly and might even be pushed via MDM once proved it's solving your situation (requires Netbird not running to take effect): # Mirrors what the client will do from the next release on: remove the group
# policy DNS policy store only when it is completely empty, so the local store
# becomes authoritative again. A store holding anything — rules, values, other
# subkeys — is left alone, and the parent DNSClient key is never touched.
$gpo = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig'
$svc = Get-Service NetBird -ErrorAction SilentlyContinue
$wasRunning = $svc -and $svc.Status -eq 'Running'
if ($wasRunning) { Stop-Service NetBird }
$key = Get-Item $gpo -ErrorAction SilentlyContinue
if ($key -and $key.SubKeyCount -eq 0 -and $key.ValueCount -eq 0) {
Remove-Item $gpo -Force
Write-Output 'removed empty GPO DNS policy store'
} else {
Write-Output 'GPO DNS policy store absent or not empty: nothing to do'
}
if ($wasRunning) { Start-Service NetBird }
Please let me know if this is working for your machines. |
Uh oh!
There was an error while loading. Please reload this page.
Before posting
Affected area
Client / Agent
Deployment type
Self-hosted - advanced/custom deployment
Operating system or environment
Windows
NetBird version and upgrade status
Did this work before?
Yes, this worked before
Regression details
merged before the v0.78.0 tag. Confirmed broken on 0.78.1 and 0.79.0.
No server-side, network, firewall or IdP changes. The nameserver group that marks NetBird
the primary resolver has been unchanged for months and was already in place throughout the
working period on 0.77.x.
Summary
On Windows, the catch-all NRPT rule added in #7071 is left enforced after the client
disconnects.
restoreHostDNSdeletes the NRPT registry keys, but the Windows DNS client keepsserving the rules from its in-memory effective policy table, so every DNS query on the machine
is still routed to the NetBird stub resolver on an interface that no longer exists.
The client then cannot resolve its own management host, so it can never reconnect and never
gets a chance to rewrite the rules. The state is self-sustaining until reboot, because the
keys are volatile and only discarded then.
This takes out DNS for the entire machine, not just NetBird.
Current behavior
netbird upfails, indefinitely:The message does not mention DNS. The actual failure is only visible in the daemon log:
CreateConnectionusesgrpc.WithBlock()withoutFailOnNonTempDialErrororWithReturnConnectionError(client/grpc/dialer.go:46-62), so every underlying dial failure —DNS, refused, TLS, firewall — is flattened into the same 30s deadline.
All other name resolution on the machine fails at the same time: browsing, Teams, and MDM
check-in included. The only recovery is a reboot, or a temporary hosts-file entry for the
management host to break the deadlock.
Expected behavior
After a disconnect, the NRPT rules the client installed should stop being enforced, not just
be deleted from the registry. In particular the client must never end up unable to resolve its
own management host, since that makes the failure unrecoverable without operator intervention.
Steps to reproduce
client computes
RouteAll = trueand installs the catch-all.Get-DnsClientNrptPolicy -Effective | Where-Object Namespace -eq '.'netbird down, or sleep/resume, network change, or a service restart..:Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters\DnsPolicyConfig'Get-ChildItem 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig'Get-DnsClientNrptPolicy -EffectiveResolve-DnsName microsoft.comfails.netbird upfails with the error above and neverrecovers.
For intermittent issues
netbird down, sleep/resume, docking or Wi-Fi change, service restart, client upgrade.no such hostevents across recurring multi-hour windows over two days. The same log covers five weeks on
0.77.0/0.77.1 with only isolated transient blips and no sustained window.
routing every namespace through <resolver>: DNS resolution is now exclusive to NetBirdappears 7 seconds after the first 0.78.1 sessionstarts (2026-09-21 10:40:50 → 10:40:57), and sustained outage windows begin the same
afternoon. On a second peer, a 35-minute unrecoverable outage across repeated
netbird upattempts, ended only by reboot.
Environment and topology
restriction — the same machine reaches the management host normally as soon as DNS works.
store present, so the client logs
detected GPO DNS policy configuration, using policy storeand writes to both stores. AD DNS servers supplied by DHCP.
Primary (hence
RouteAll), ~169 match domains including internal AD zones and reverselookup zones.
disableServerRoutes=trueandblockInbound=trueapplied via MDM. No posturechecks or SSH rules involved.
implicated — the failure occurs before any authentication is attempted.
Self-hosted details, if available
rels://<mgmt-host>:443/relayconnected during the affected windows. The failure is entirely client-side DNS.
Logs, status output, or debug evidence
The routing table is clean: a single default route over Wi-Fi, no stale VPN interface, so
interface selection is not involved.
Cleanup ran and reported success.
removeDNSMatchPoliciescallsrefreshGroupPolicy()(RefreshPolicyEx) unconditionally, and
restoreHostDNSthen flushes the DNS cache. Neithermade the resolver drop the deleted rules — a cache flush clears cached answers, not policy.
Root cause pointers
restoreHostDNS(client/internal/dns/host_windows.go:601) removes the keys and flushes thecache, but nothing forces the DNS client to reload its policy table. Two comments in the tree
already describe this failure mode:
host_windows.go:624— "a rule left behind keeps resolving names over an interface that isgone, until reboot discards the volatile key"
debug_windows.go:113-115— "it keeps being enforced after its key is gone until theresolver reloads its policy"
Before #7071 the leftover rules only covered the configured match domains, so the management
host still resolved and the client always recovered on its own. The catch-all
.rule turnsthe same leftover state into a total DNS outage plus an unrecoverable client.
Also note
mgmt.Resolver.osLookup(client/internal/dns/mgmt/mgmt.go:414) usesnet.DefaultResolver, which is itself subject to NRPT, so it provides no bootstrap path out.All reactions