mirror of
https://github.com/SagerNet/sing-tun.git
synced 2025-04-03 20:07:40 +03:00
119 lines
3.9 KiB
Go
119 lines
3.9 KiB
Go
/* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (C) 2019-2022 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"
|
|
netshCmdTemplateFlush6 = "interface ipv6 set dnsservers name=%d source=static address=none validate=no"
|
|
netshCmdTemplateAdd4 = "interface ipv4 add dnsservers name=%d address=%s validate=no"
|
|
netshCmdTemplateAdd6 = "interface ipv6 add dnsservers name=%d address=%s validate=no"
|
|
netshCmdTemplateDisableRegistration = "interface ipv6 set dnsservers name=%d register=none"
|
|
)
|
|
|
|
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 := 0; i < len(dnses); i++ {
|
|
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
|
|
}
|
|
|
|
func (luid LUID) fallbackDisableDNSRegistration() error {
|
|
// the DNS registration setting is shared for both IPv4 and IPv6
|
|
ipif, err := luid.IPInterface(windows.AF_INET)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cmd := fmt.Sprintf(netshCmdTemplateDisableRegistration, ipif.InterfaceIndex)
|
|
return runNetsh([]string{cmd})
|
|
}
|