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)