wgengine/router: split off windows dns

Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This commit is contained in:
Dmytro Shynkevych 2020-07-17 06:47:00 -04:00
parent f09a4bde65
commit 26a3fc6641
No known key found for this signature in database
GPG Key ID: FF5E2F3DAD97EA23
7 changed files with 112 additions and 45 deletions

View File

@ -864,7 +864,10 @@ func (b *LocalBackend) authReconfig() {
}
// Per-domain DNS is enabled only when proxying with no nameservers in the netmap:
// finding fallback servers is unreliable in this case, so we want to avoid it if possible.
perDomain := proxied && (len(nm.DNS) == 0)
perDomain := proxied && len(nm.DNS) == 0
if proxied {
nm.DNS = []wgcfg.IP{wgcfg.IPv4(100, 100, 100, 100)}
}
rcfg.DNS = dns.Config{
Disabled: !uc.CorpDNS,
PerDomain: perDomain,

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !linux,!freebsd,!openbsd
// +build !linux,!freebsd,!openbsd,!windows
package dns

View File

@ -0,0 +1,72 @@
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dns
import (
"fmt"
"strings"
"golang.org/x/sys/windows/registry"
)
type windowsManager struct {
interfaceName string
}
func newManager(mconfig ManagerConfig) managerImpl {
return &windowsManager{
interfaceName: mconfig.InterfaceName,
}
}
func setRegistry(path, nameservers, domains string) error {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, path, registry.READ|registry.SET_VALUE)
if err != nil {
return fmt.Errorf("opening %s: %w", path, err)
}
defer key.Close()
err = key.SetStringValue("NameServer", nameservers)
if err != nil {
return fmt.Errorf("setting %s/NameServer: %w", path, err)
}
err = key.SetStringValue("Domain", domains)
if err != nil {
return fmt.Errorf("setting %s/Domain: %w", path, err)
}
return nil
}
func (m *windowsManager) Up(config Config) error {
var ipsv4 []string
var ipsv6 []string
for _, ip := range config.Nameservers {
if ip.Is4() {
ipsv4 = append(ipsv4, ip.String())
} else {
ipsv6 = append(ipsv6, ip.String())
}
}
nsv4 := strings.Join(ipsv4, ",")
nsv6 := strings.Join(ipsv6, ",")
domains := strings.Join(config.Domains, ";")
v4Path := `SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\` + m.interfaceName
if err := setRegistry(v4Path, nsv4, domains); err != nil {
return err
}
v6Path := `SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\Interfaces\` + m.interfaceName
if err := setRegistry(v6Path, nsv6, domains); err != nil {
return err
}
return nil
}
func (m *windowsManager) Down() error {
return m.Up(Config{Nameservers: nil, Domains: nil})
}

View File

@ -21,7 +21,6 @@ import (
"github.com/tailscale/wireguard-go/device"
"github.com/tailscale/wireguard-go/tun"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
"tailscale.com/wgengine/winnet"
)
@ -157,28 +156,6 @@ func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTu
return cb, nil
}
func setDNSDomains(g windows.GUID, dnsDomains []string) {
gs := g.String()
log.Printf("setDNSDomains(%v) guid=%v\n", dnsDomains, gs)
p := `SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\` + gs
key, err := registry.OpenKey(registry.LOCAL_MACHINE, p, registry.READ|registry.SET_VALUE)
if err != nil {
log.Printf("setDNSDomains(%v): open: %v\n", p, err)
return
}
defer key.Close()
// Windows only supports a single per-interface DNS domain.
dom := ""
if len(dnsDomains) > 0 {
dom = dnsDomains[0]
}
err = key.SetStringValue("Domain", dom)
if err != nil {
log.Printf("setDNSDomains(%v): SetStringValue: %v\n", p, err)
}
}
func setFirewall(ifcGUID *windows.GUID) (bool, error) {
c := ole.Connection{}
err := c.Initialize()
@ -262,8 +239,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
}
}()
setDNSDomains(guid, cfg.DNS.Domains)
routes := []winipcfg.RouteData{}
var firstGateway4 *net.IP
var firstGateway6 *net.IP
@ -358,16 +333,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
errAcc = err
}
var dnsIPs []net.IP
for _, ip := range cfg.DNS.Nameservers {
dnsIPs = append(dnsIPs, ip.IPAddr().IP)
}
err = iface.SetDNS(dnsIPs)
if err != nil && errAcc == nil {
log.Printf("setdns: %v\n", err)
errAcc = err
}
ipif, err := iface.GetIpInterface(winipcfg.AF_INET)
if err != nil {
log.Printf("getipif: %v\n", err)

View File

@ -160,13 +160,20 @@ func (r *userspaceBSDRouter) Close() error {
if err := r.dns.Down(); err != nil {
r.logf("dns down: %v", err)
}
cleanup(r.logf, r.tunname)
ifup := []string{"ifconfig", r.tunname, "down"}
if out, err := cmd(ifup...).CombinedOutput(); err != nil {
r.logf("ifconfig down: %v\n%s", err, out)
}
return nil
}
func cleanup(logf logger.Logf, interfaceName string) {
ifup := []string{"ifconfig", interfaceName, "down"}
// If the interface was left behind, ifconfig down will not remove it.
// In fact, this will leave a system in a tainted state where starting tailscaled
// will result in "interface tailscale0 already exists"
// until the defunct interface is ifconfig-destroyed.
ifup := []string{"ifconfig", interfaceName, "destroy"}
if out, err := cmd(ifup...).CombinedOutput(); err != nil {
logf("ifconfig down: %v\n%s", err, out)
logf("ifconfig destroy: %v\n%s", err, out)
}
}

View File

@ -5,12 +5,13 @@
package router
import (
"log"
"fmt"
winipcfg "github.com/tailscale/winipcfg-go"
"github.com/tailscale/wireguard-go/device"
"github.com/tailscale/wireguard-go/tun"
"tailscale.com/types/logger"
"tailscale.com/wgengine/router/dns"
)
type winRouter struct {
@ -19,6 +20,7 @@ type winRouter struct {
nativeTun *tun.NativeTun
wgdev *device.Device
routeChangeCallback *winipcfg.RouteChangeCallback
dns *dns.Manager
}
func newUserspaceRouter(logf logger.Logf, wgdev *device.Device, tundev tun.Device) (Router, error) {
@ -26,11 +28,20 @@ func newUserspaceRouter(logf logger.Logf, wgdev *device.Device, tundev tun.Devic
if err != nil {
return nil, err
}
nativeTun := tundev.(*tun.NativeTun)
guid := nativeTun.GUID().String()
mconfig := dns.ManagerConfig{
Logf: logf,
InterfaceName: guid,
}
return &winRouter{
logf: logf,
wgdev: wgdev,
tunname: tunname,
nativeTun: tundev.(*tun.NativeTun),
nativeTun: nativeTun,
dns: dns.NewManager(mconfig),
}, nil
}
@ -40,7 +51,7 @@ func (r *winRouter) Up() error {
var err error
r.routeChangeCallback, err = monitorDefaultRoutes(r.wgdev, true, r.nativeTun)
if err != nil {
log.Fatalf("MonitorDefaultRoutes: %v\n", err)
return fmt.Errorf("MonitorDefaultRoutes: %w", err)
}
return nil
}
@ -52,13 +63,20 @@ func (r *winRouter) Set(cfg *Config) error {
err := configureInterface(cfg, r.nativeTun)
if err != nil {
r.logf("ConfigureInterface: %v\n", err)
return err
return fmt.Errorf("ConfigureInterface: %w", err)
}
if err := r.dns.Set(cfg.DNS); err != nil {
return fmt.Errorf("dns set: %w", err)
}
return nil
}
func (r *winRouter) Close() error {
if err := r.dns.Down(); err != nil {
return fmt.Errorf("dns down: %w", err)
}
if r.routeChangeCallback != nil {
r.routeChangeCallback.Unregister()
}

View File

@ -581,6 +581,8 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config)
}
e.mu.Unlock()
e.resolver.SetNameservers([]string{"9.9.9.9:53"})
engineChanged := updateSig(&e.lastEngineSig, cfg)
routerChanged := updateSig(&e.lastRouterSig, routerCfg)
if !engineChanged && !routerChanged {