mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-30 07:43:42 +00:00
wgengine/router: split off windows dns
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This commit is contained in:
parent
f09a4bde65
commit
26a3fc6641
@ -864,7 +864,10 @@ func (b *LocalBackend) authReconfig() {
|
|||||||
}
|
}
|
||||||
// Per-domain DNS is enabled only when proxying with no nameservers in the netmap:
|
// 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.
|
// 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{
|
rcfg.DNS = dns.Config{
|
||||||
Disabled: !uc.CorpDNS,
|
Disabled: !uc.CorpDNS,
|
||||||
PerDomain: perDomain,
|
PerDomain: perDomain,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !linux,!freebsd,!openbsd
|
// +build !linux,!freebsd,!openbsd,!windows
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
72
wgengine/router/dns/manager_windows.go
Normal file
72
wgengine/router/dns/manager_windows.go
Normal 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})
|
||||||
|
}
|
@ -21,7 +21,6 @@ import (
|
|||||||
"github.com/tailscale/wireguard-go/device"
|
"github.com/tailscale/wireguard-go/device"
|
||||||
"github.com/tailscale/wireguard-go/tun"
|
"github.com/tailscale/wireguard-go/tun"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
"golang.org/x/sys/windows/registry"
|
|
||||||
"tailscale.com/wgengine/winnet"
|
"tailscale.com/wgengine/winnet"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -157,28 +156,6 @@ func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTu
|
|||||||
return cb, nil
|
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) {
|
func setFirewall(ifcGUID *windows.GUID) (bool, error) {
|
||||||
c := ole.Connection{}
|
c := ole.Connection{}
|
||||||
err := c.Initialize()
|
err := c.Initialize()
|
||||||
@ -262,8 +239,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
setDNSDomains(guid, cfg.DNS.Domains)
|
|
||||||
|
|
||||||
routes := []winipcfg.RouteData{}
|
routes := []winipcfg.RouteData{}
|
||||||
var firstGateway4 *net.IP
|
var firstGateway4 *net.IP
|
||||||
var firstGateway6 *net.IP
|
var firstGateway6 *net.IP
|
||||||
@ -358,16 +333,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
|||||||
errAcc = err
|
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)
|
ipif, err := iface.GetIpInterface(winipcfg.AF_INET)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("getipif: %v\n", err)
|
log.Printf("getipif: %v\n", err)
|
||||||
|
@ -160,13 +160,20 @@ func (r *userspaceBSDRouter) Close() error {
|
|||||||
if err := r.dns.Down(); err != nil {
|
if err := r.dns.Down(); err != nil {
|
||||||
r.logf("dns down: %v", err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanup(logf logger.Logf, interfaceName string) {
|
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 {
|
if out, err := cmd(ifup...).CombinedOutput(); err != nil {
|
||||||
logf("ifconfig down: %v\n%s", err, out)
|
logf("ifconfig destroy: %v\n%s", err, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,13 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"fmt"
|
||||||
|
|
||||||
winipcfg "github.com/tailscale/winipcfg-go"
|
winipcfg "github.com/tailscale/winipcfg-go"
|
||||||
"github.com/tailscale/wireguard-go/device"
|
"github.com/tailscale/wireguard-go/device"
|
||||||
"github.com/tailscale/wireguard-go/tun"
|
"github.com/tailscale/wireguard-go/tun"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/wgengine/router/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
type winRouter struct {
|
type winRouter struct {
|
||||||
@ -19,6 +20,7 @@ type winRouter struct {
|
|||||||
nativeTun *tun.NativeTun
|
nativeTun *tun.NativeTun
|
||||||
wgdev *device.Device
|
wgdev *device.Device
|
||||||
routeChangeCallback *winipcfg.RouteChangeCallback
|
routeChangeCallback *winipcfg.RouteChangeCallback
|
||||||
|
dns *dns.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUserspaceRouter(logf logger.Logf, wgdev *device.Device, tundev tun.Device) (Router, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nativeTun := tundev.(*tun.NativeTun)
|
||||||
|
guid := nativeTun.GUID().String()
|
||||||
|
mconfig := dns.ManagerConfig{
|
||||||
|
Logf: logf,
|
||||||
|
InterfaceName: guid,
|
||||||
|
}
|
||||||
|
|
||||||
return &winRouter{
|
return &winRouter{
|
||||||
logf: logf,
|
logf: logf,
|
||||||
wgdev: wgdev,
|
wgdev: wgdev,
|
||||||
tunname: tunname,
|
tunname: tunname,
|
||||||
nativeTun: tundev.(*tun.NativeTun),
|
nativeTun: nativeTun,
|
||||||
|
dns: dns.NewManager(mconfig),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +51,7 @@ func (r *winRouter) Up() error {
|
|||||||
var err error
|
var err error
|
||||||
r.routeChangeCallback, err = monitorDefaultRoutes(r.wgdev, true, r.nativeTun)
|
r.routeChangeCallback, err = monitorDefaultRoutes(r.wgdev, true, r.nativeTun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("MonitorDefaultRoutes: %v\n", err)
|
return fmt.Errorf("MonitorDefaultRoutes: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -52,13 +63,20 @@ func (r *winRouter) Set(cfg *Config) error {
|
|||||||
|
|
||||||
err := configureInterface(cfg, r.nativeTun)
|
err := configureInterface(cfg, r.nativeTun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logf("ConfigureInterface: %v\n", err)
|
return fmt.Errorf("ConfigureInterface: %w", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := r.dns.Set(cfg.DNS); err != nil {
|
||||||
|
return fmt.Errorf("dns set: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *winRouter) Close() error {
|
func (r *winRouter) Close() error {
|
||||||
|
if err := r.dns.Down(); err != nil {
|
||||||
|
return fmt.Errorf("dns down: %w", err)
|
||||||
|
}
|
||||||
if r.routeChangeCallback != nil {
|
if r.routeChangeCallback != nil {
|
||||||
r.routeChangeCallback.Unregister()
|
r.routeChangeCallback.Unregister()
|
||||||
}
|
}
|
||||||
|
@ -581,6 +581,8 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config)
|
|||||||
}
|
}
|
||||||
e.mu.Unlock()
|
e.mu.Unlock()
|
||||||
|
|
||||||
|
e.resolver.SetNameservers([]string{"9.9.9.9:53"})
|
||||||
|
|
||||||
engineChanged := updateSig(&e.lastEngineSig, cfg)
|
engineChanged := updateSig(&e.lastEngineSig, cfg)
|
||||||
routerChanged := updateSig(&e.lastRouterSig, routerCfg)
|
routerChanged := updateSig(&e.lastRouterSig, routerCfg)
|
||||||
if !engineChanged && !routerChanged {
|
if !engineChanged && !routerChanged {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user