diff options
| author | 2026-04-13 04:07:45 +0200 | |
|---|---|---|
| committer | 2026-04-13 19:32:53 +0200 | |
| commit | b7b300b88e8f825dd57d4b94bddd08b82b9d73c6 (patch) | |
| tree | bf341b1870b21e9670f6537d0c6014679a91b02f | |
| parent | global: format code (diff) | |
| download | wireguard-windows-master.tar.xz wireguard-windows-master.zip | |
And it turns out we can use SearchList on old Windows 10 too. This gets
total feature parity with the new DNS function.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to '')
| -rw-r--r-- | tunnel/winipcfg/luid.go | 38 | ||||
| -rw-r--r-- | tunnel/winipcfg/netsh.go | 108 |
2 files changed, 32 insertions, 114 deletions
diff --git a/tunnel/winipcfg/luid.go b/tunnel/winipcfg/luid.go index ade5a63f..f4c67f2b 100644 --- a/tunnel/winipcfg/luid.go +++ b/tunnel/winipcfg/luid.go @@ -7,10 +7,14 @@ package winipcfg import ( "errors" + "fmt" "net/netip" "strings" "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/mgr" ) // LUID represents a network interface. @@ -370,15 +374,37 @@ func (luid LUID) SetDNS(family AddressFamily, servers []netip.Addr, domains []st } // For < Windows 10 1809 - err = luid.fallbackSetDNSForFamily(family, servers) + var regPath string + switch family { + case windows.AF_INET: + regPath = fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%v", guid) + case windows.AF_INET6: + regPath = fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces\\%v", guid) + } + key, err := registry.OpenKey(registry.LOCAL_MACHINE, regPath, registry.SET_VALUE) if err != nil { - return err + return fmt.Errorf("opening interface registry key: %w", err) + } + defer key.Close() + if err := key.SetStringValue("NameServer", strings.Join(filteredServers, ",")); err != nil { + return fmt.Errorf("setting NameServer registry value: %w", err) + } + if err := key.SetStringValue("SearchList", strings.Join(domains, ",")); err != nil { + return fmt.Errorf("setting SearchList registry value: %w", err) } - if len(domains) > 0 { - return luid.fallbackSetDNSDomain(domains[0]) - } else { - return luid.fallbackSetDNSDomain("") + scm, err := mgr.Connect() + if err != nil { + return nil + } + defer scm.Disconnect() + s := mgr.Service{Name: "dnscache"} + s.Handle, err = windows.OpenService(scm.Handle, windows.StringToUTF16Ptr(s.Name), windows.SERVICE_PAUSE_CONTINUE) + if err != nil { + return nil } + defer s.Close() + s.Control(svc.ParamChange) + return nil } // FlushDNS method clears all DNS servers associated with the adapter. diff --git a/tunnel/winipcfg/netsh.go b/tunnel/winipcfg/netsh.go deleted file mode 100644 index 5f460957..00000000 --- a/tunnel/winipcfg/netsh.go +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2026 WireGuard LLC. All Rights Reserved. - */ - -package winipcfg - -import ( - "bytes" - "errors" - "fmt" - "io" - "net/netip" - "os/exec" - "path/filepath" - "strings" - "syscall" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" -) - -func runNetsh(cmds []string) error { - system32, err := windows.GetSystemDirectory() - if err != nil { - return err - } - cmd := exec.Command(filepath.Join(system32, "netsh.exe")) - cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} - - stdin, err := cmd.StdinPipe() - if err != nil { - return fmt.Errorf("runNetsh stdin pipe - %w", err) - } - go func() { - defer stdin.Close() - io.WriteString(stdin, strings.Join(append(cmds, "exit\r\n"), "\r\n")) - }() - output, err := cmd.CombinedOutput() - // Horrible kludges, sorry. - cleaned := bytes.ReplaceAll(output, []byte{'\r', '\n'}, []byte{'\n'}) - cleaned = bytes.ReplaceAll(cleaned, []byte("netsh>"), []byte{}) - cleaned = bytes.ReplaceAll(cleaned, []byte("There are no Domain Name Servers (DNS) configured on this computer."), []byte{}) - cleaned = bytes.TrimSpace(cleaned) - if len(cleaned) != 0 && err == nil { - return fmt.Errorf("netsh: %#q", string(cleaned)) - } else if err != nil { - return fmt.Errorf("netsh: %v: %#q", err, string(cleaned)) - } - return nil -} - -const ( - netshCmdTemplateFlush4 = "interface ipv4 set dnsservers name=%d source=static address=none validate=no register=both" - netshCmdTemplateFlush6 = "interface ipv6 set dnsservers name=%d source=static address=none validate=no register=both" - netshCmdTemplateAdd4 = "interface ipv4 add dnsservers name=%d address=%s validate=no" - netshCmdTemplateAdd6 = "interface ipv6 add dnsservers name=%d address=%s validate=no" -) - -func (luid LUID) fallbackSetDNSForFamily(family AddressFamily, dnses []netip.Addr) error { - var templateFlush string - if family == windows.AF_INET { - templateFlush = netshCmdTemplateFlush4 - } else if family == windows.AF_INET6 { - templateFlush = netshCmdTemplateFlush6 - } - - cmds := make([]string, 0, 1+len(dnses)) - ipif, err := luid.IPInterface(family) - if err != nil { - return err - } - cmds = append(cmds, fmt.Sprintf(templateFlush, ipif.InterfaceIndex)) - for i := range dnses { - if dnses[i].Is4() && family == windows.AF_INET { - cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd4, ipif.InterfaceIndex, dnses[i].String())) - } else if dnses[i].Is6() && family == windows.AF_INET6 { - cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd6, ipif.InterfaceIndex, dnses[i].String())) - } - } - return runNetsh(cmds) -} - -func (luid LUID) fallbackSetDNSDomain(domain string) error { - guid, err := luid.GUID() - if err != nil { - return fmt.Errorf("Error converting luid to guid: %w", err) - } - key, err := registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%v", guid), registry.QUERY_VALUE) - if err != nil { - return fmt.Errorf("Error opening adapter-specific TCP/IP network registry key: %w", err) - } - paths, _, err := key.GetStringsValue("IpConfig") - key.Close() - if err != nil { - return fmt.Errorf("Error reading IpConfig registry key: %w", err) - } - if len(paths) == 0 { - return errors.New("No TCP/IP interfaces found on adapter") - } - key, err = registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\%s", paths[0]), registry.SET_VALUE) - if err != nil { - return fmt.Errorf("Unable to open TCP/IP network registry key: %w", err) - } - err = key.SetStringValue("Domain", domain) - key.Close() - return err -} |
