From e11de8481c4c349456125e5ad6782d82d423a5b9 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 29 Jan 2021 22:29:22 +0100 Subject: winipcfg: move to undocumented DNS function Signed-off-by: Jason A. Donenfeld --- tunnel/winipcfg/netsh.go | 65 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) (limited to 'tunnel/winipcfg/netsh.go') diff --git a/tunnel/winipcfg/netsh.go b/tunnel/winipcfg/netsh.go index 803a9a35..1f3d12d0 100644 --- a/tunnel/winipcfg/netsh.go +++ b/tunnel/winipcfg/netsh.go @@ -7,25 +7,25 @@ package winipcfg import ( "bytes" + "errors" "fmt" "io" + "net" "os/exec" "path/filepath" "strings" "syscall" "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" ) -// I wish we didn't have to do this. netiohlp.dll (what's used by netsh.exe) has some nice tricks with writing directly -// to the registry and the nsi kernel object, but it's not clear copying those makes for a stable interface. WMI doesn't -// work with v6. CMI isn't in Windows 7. func runNetsh(cmds []string) error { system32, err := windows.GetSystemDirectory() if err != nil { return err } - cmd := exec.Command(filepath.Join(system32, "netsh.exe")) // I wish we could append (, "-f", "CONIN$") but Go sets up the process context wrong. + cmd := exec.Command(filepath.Join(system32, "netsh.exe")) cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} stdin, err := cmd.StdinPipe() @@ -49,3 +49,60 @@ func runNetsh(cmds []string) error { } 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 []net.IP) 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 := 0; i < len(dnses); i++ { + if v4 := dnses[i].To4(); v4 != nil && family == windows.AF_INET { + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd4, ipif.InterfaceIndex, v4.String())) + } else if v6 := dnses[i].To16(); v4 == nil && v6 != nil && family == windows.AF_INET6 { + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd6, ipif.InterfaceIndex, v6.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 +} -- cgit v1.2.3-59-g8ed1b