This commit is contained in:
bluepython508 committed 2026-10-22 12:27:19 +01:00
1 parent 3530afb854
commit 6903fcff27
2146 files changed
+112256 -190703

No files matched your search

+28 -34
View File
@@ -1,4 +1,4 @@
// Copyright (c) Tailscale Inc & AUTHORS
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
package dns
@@ -7,7 +7,6 @@ import (
"fmt"
"strings"
"sync"
"sync/atomic"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
@@ -19,7 +18,6 @@ import (
)
const (
dnsBaseGP = `SOFTWARE\Policies\Microsoft\Windows NT\DNSClient`
nrptBaseLocal = `SYSTEM\CurrentControlSet\Services\Dnscache\Parameters\DnsPolicyConfig`
nrptBaseGP = `SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig`
@@ -53,13 +51,12 @@ const (
// nrptRuleDatabase encapsulates access to the Windows Name Resolution Policy
// Table (NRPT).
type nrptRuleDatabase struct {
logf logger.Logf
watcher *gp.ChangeWatcher
isGPRefreshPending atomic.Bool
mu sync.Mutex // protects the fields below
ruleIDs []string
isGPDirty bool
writeAsGP bool
logf logger.Logf
watcher *gp.ChangeWatcher
mu sync.Mutex // protects the fields below
ruleIDs []string
isGPDirty bool
writeAsGP bool
}
func newNRPTRuleDatabase(logf logger.Logf) *nrptRuleDatabase {
@@ -141,6 +138,12 @@ func (db *nrptRuleDatabase) detectWriteAsGP() {
writeAsGP = len(gpSubkeyMap) > 0
}
func regKeyHasNoValues(ki *registry.KeyInfo) bool {
// Either the key has no values, or there is one value: an empty default value.
return ki.ValueCount == 0 ||
ki.ValueCount == 1 && ki.MaxValueNameLen == 0 && ki.MaxValueLen == 0
}
// DelAllRuleKeys removes any and all NRPT rules that are owned by Tailscale.
func (db *nrptRuleDatabase) DelAllRuleKeys() error {
db.mu.Lock()
@@ -171,7 +174,7 @@ func (db *nrptRuleDatabase) delRuleKeys(nrptRuleIDs []string) error {
keyNameGP := nrptBaseGP + `\` + rid
err := registry.DeleteKey(registry.LOCAL_MACHINE, keyNameGP)
if err == nil {
// If this deleted subkey existed under the GP key, we will need to refresh.
// If this deleted subkey existed under the GP key, we will need to notify.
db.isGPDirty = true
} else if err != registry.ErrNotExist {
db.logf("Error deleting NRPT rule key %q: %v", keyNameGP, err)
@@ -193,8 +196,8 @@ func (db *nrptRuleDatabase) delRuleKeys(nrptRuleIDs []string) error {
return registry.DeleteKey(registry.LOCAL_MACHINE, nrptBaseGP)
}
// isPolicyConfigSubkeyEmpty returns true if and only if the nrptBaseGP exists
// and does not contain any values or subkeys.
// isPolicyConfigSubkeyEmpty returns whether the nrptBaseGP exists and does not
// contain any values or subkeys.
func isPolicyConfigSubkeyEmpty() (bool, error) {
subKey, err := registry.OpenKey(registry.LOCAL_MACHINE, nrptBaseGP, registry.READ)
if err != nil {
@@ -210,7 +213,7 @@ func isPolicyConfigSubkeyEmpty() (bool, error) {
return false, err
}
return (ki.ValueCount == 0 && ki.SubKeyCount == 0), nil
return regKeyHasNoValues(ki) && ki.SubKeyCount == 0, nil
}
func (db *nrptRuleDatabase) WriteSplitDNSConfig(servers []string, domains []dnsname.FQDN) error {
@@ -277,26 +280,22 @@ func (db *nrptRuleDatabase) WriteSplitDNSConfig(servers []string, domains []dnsn
return nil
}
// Refresh notifies the Windows group policy engine when policies have changed.
func (db *nrptRuleDatabase) Refresh() {
// NotifyPolicyChanged notifies the Windows group policy engine when policies have changed.
func (db *nrptRuleDatabase) NotifyPolicyChanged() {
db.mu.Lock()
defer db.mu.Unlock()
db.refreshLocked()
db.notifyPolicyChangedLocked()
}
func (db *nrptRuleDatabase) refreshLocked() {
func (db *nrptRuleDatabase) notifyPolicyChangedLocked() {
if !db.isGPDirty {
return
}
// Record that we are about to initiate a refresh.
// (*nrptRuleDatabase).watchForGPChanges() checks this value to avoid false
// positives.
db.isGPRefreshPending.Store(true)
if err := gp.RefreshMachinePolicy(true); err != nil {
db.logf("RefreshMachinePolicy failed: %v", err)
db.logf("Calling NotifyMachinePolicyChange")
if err := gp.NotifyMachinePolicyChange(); err != nil {
db.logf("NotifyMachinePolicyChange failed: %v", err)
return
}
@@ -318,7 +317,7 @@ func (db *nrptRuleDatabase) writeNRPTRule(ruleID string, servers, doms []string)
}
defer key.Close()
if err := writeNRPTValues(key, strings.Join(servers, "; "), doms); err != nil {
if err := writeNRPTValues(key, strings.Join(servers, ";"), doms); err != nil {
return err
}
}
@@ -355,12 +354,7 @@ func writeNRPTValues(key registry.Key, servers string, doms []string) error {
func (db *nrptRuleDatabase) watchForGPChanges() {
watchHandler := func() {
// Do not invoke detectWriteAsGP when we ourselves were responsible for
// initiating the group policy refresh.
if db.isGPRefreshPending.CompareAndSwap(true, false) {
return
}
db.logf("Computer group policies refreshed, reconfiguring NRPT rule database.")
db.logf("Received machine group policy change notification. Reconfiguring NRPT rule database.")
db.detectWriteAsGP()
}
@@ -380,8 +374,8 @@ func (db *nrptRuleDatabase) watchForGPChanges() {
// db.mu must already be locked.
func (db *nrptRuleDatabase) updateGroupPoliciesLocked(writeAsGP bool) {
// Since we're updating the group policy NRPT table, we need
// to refresh once this updateGroupPoliciesLocked is done.
defer db.refreshLocked()
// to notify once this updateGroupPoliciesLocked is done.
defer db.notifyPolicyChangedLocked()
for _, id := range db.ruleIDs {
if writeAsGP {