Skip to content

Commit

Permalink
net/dns: do not wait for the interface registry key to appear if the …
Browse files Browse the repository at this point in the history
…windowsManager is being closed

The WinTun adapter may have been removed by the time we're closing
the dns.windowsManager, and its associated interface registry key might
also have been deleted. We shouldn't use winutil.OpenKeyWait and wait
for the interface key to appear when performing a cleanup as a part of
the windowsManager shutdown.

Updates tailscale#11222

Signed-off-by: Nick Khyl <nickk@tailscale.com>
  • Loading branch information
nickkhyl committed Feb 26, 2024
1 parent 82c569a commit b42b981
Showing 1 changed file with 40 additions and 5 deletions.
45 changes: 40 additions & 5 deletions net/dns/manager_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"path/filepath"
"sort"
"strings"
"sync"
"syscall"
"time"

Expand All @@ -38,6 +39,9 @@ type windowsManager struct {
guid string
nrptDB *nrptRuleDatabase
wslManager *wslManager

mu sync.Mutex
closing bool
}

func NewOSConfigurator(logf logger.Logf, interfaceName string) (OSConfigurator, error) {
Expand All @@ -64,14 +68,37 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (OSConfigurator,
}

func (m *windowsManager) openInterfaceKey(pfx winutil.RegistryPathPrefix) (registry.Key, error) {
var key registry.Key
var err error
path := pfx.WithSuffix(m.guid)
key, err := winutil.OpenKeyWait(registry.LOCAL_MACHINE, path, registry.SET_VALUE)

m.mu.Lock()
closing := m.closing
m.mu.Unlock()
if closing {
// Do not wait for the interface key to appear if the manager is being closed.
// If it's being closed due to the removal of the wintun adapter,
// the key would already be gone by now and will not reappear until tailscaled is restarted.
key, err = registry.OpenKey(registry.LOCAL_MACHINE, string(path), registry.SET_VALUE)
} else {
key, err = winutil.OpenKeyWait(registry.LOCAL_MACHINE, path, registry.SET_VALUE)
}
if err != nil {
return 0, fmt.Errorf("opening %s: %w", path, err)
}
return key, nil
}

func (m *windowsManager) muteKeyNotFoundIfClosing(err error) error {
m.mu.Lock()
defer m.mu.Unlock()
if !m.closing || (err != windows.ERROR_FILE_NOT_FOUND && err != windows.ERROR_PATH_NOT_FOUND) {
return err
}

return nil
}

func delValue(key registry.Key, name string) error {
if err := key.DeleteValue(name); err != nil && err != registry.ErrNotExist {
return err
Expand Down Expand Up @@ -205,7 +232,7 @@ func (m *windowsManager) setPrimaryDNS(resolvers []netip.Addr, domains []dnsname

key4, err := m.openInterfaceKey(winutil.IPv4TCPIPInterfacePrefix)
if err != nil {
return err
return m.muteKeyNotFoundIfClosing(err)
}
defer key4.Close()

Expand All @@ -227,7 +254,7 @@ func (m *windowsManager) setPrimaryDNS(resolvers []netip.Addr, domains []dnsname

key6, err := m.openInterfaceKey(winutil.IPv6TCPIPInterfacePrefix)
if err != nil {
return err
return m.muteKeyNotFoundIfClosing(err)
}
defer key6.Close()

Expand Down Expand Up @@ -387,6 +414,14 @@ func (m *windowsManager) SupportsSplitDNS() bool {
}

func (m *windowsManager) Close() error {
m.mu.Lock()
if m.closing {
m.mu.Unlock()
return nil
}
m.closing = true
m.mu.Unlock()

err := m.SetDNS(OSConfig{})
if m.nrptDB != nil {
m.nrptDB.Close()
Expand All @@ -407,7 +442,7 @@ func (m *windowsManager) disableDynamicUpdates() error {
for _, prefix := range prefixen {
k, err := m.openInterfaceKey(prefix)
if err != nil {
return err
return m.muteKeyNotFoundIfClosing(err)
}
defer k.Close()

Expand All @@ -426,7 +461,7 @@ func (m *windowsManager) disableDynamicUpdates() error {
func (m *windowsManager) setSingleDWORD(prefix winutil.RegistryPathPrefix, value string, data uint32) error {
k, err := m.openInterfaceKey(prefix)
if err != nil {
return err
return m.muteKeyNotFoundIfClosing(err)
}
defer k.Close()
return k.SetDWordValue(value, data)
Expand Down

0 comments on commit b42b981

Please sign in to comment.