From b42b9817b0fa7c209c495949e40a3337d0570f2f Mon Sep 17 00:00:00 2001 From: Nick Khyl Date: Fri, 23 Feb 2024 19:39:15 -0600 Subject: [PATCH] net/dns: do not wait for the interface registry key to appear if the 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 #11222 Signed-off-by: Nick Khyl --- net/dns/manager_windows.go | 45 +++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/net/dns/manager_windows.go b/net/dns/manager_windows.go index 3b0039894..55e2660cf 100644 --- a/net/dns/manager_windows.go +++ b/net/dns/manager_windows.go @@ -14,6 +14,7 @@ import ( "path/filepath" "sort" "strings" + "sync" "syscall" "time" @@ -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) { @@ -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 @@ -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() @@ -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() @@ -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() @@ -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() @@ -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)