From 6ad44f9fdf509e6a34ff07491e4bbe441f417e99 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 2 Apr 2021 00:34:32 -0700 Subject: [PATCH] wgengine: take in dns.Config, split out to resolver.Config and dns.OSConfig. Stepping stone towards having the DNS package handle the config splitting. Signed-off-by: David Anderson --- ipn/ipnlocal/local.go | 50 +++++++++++++++++++++----------------- net/dns/config.go | 7 ------ wgengine/router/router.go | 1 + wgengine/userspace.go | 40 ++++++++++++++++++------------ wgengine/userspace_test.go | 3 ++- wgengine/watchdog.go | 5 ++-- wgengine/wgengine.go | 3 ++- 7 files changed, 61 insertions(+), 48 deletions(-) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 1455d9fd4..86b104886 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1442,35 +1442,41 @@ func (b *LocalBackend) authReconfig() { rcfg := routerConfig(cfg, uc) - // If CorpDNS is false, rcfg.DNS remains the zero value. + var dcfg dns.Config + + // If CorpDNS is false, dcfg remains the zero value. if uc.CorpDNS { proxied := nm.DNS.Proxied if proxied && len(nm.DNS.Nameservers) == 0 { b.logf("[unexpected] dns proxied but no nameservers") proxied = false } - rcfg.DNS = dns.OSConfig{ - Nameservers: nm.DNS.Nameservers, - Domains: nm.DNS.Domains, - Proxied: proxied, + for _, ip := range nm.DNS.Nameservers { + dcfg.DefaultResolvers = append(dcfg.DefaultResolvers, netaddr.IPPort{ + IP: ip, + Port: 53, + }) + } + dcfg.SearchDomains = nm.DNS.Domains + dcfg.AuthoritativeSuffixes = magicDNSRootDomains(nm) + set := func(name string, addrs []netaddr.IPPrefix) { + if len(addrs) == 0 || name == "" { + return + } + var ips []netaddr.IP + for _, addr := range addrs { + ips = append(ips, addr.IP) + } + dcfg.Hosts[name] = ips + } + dcfg.Hosts = map[string][]netaddr.IP{} + set(nm.Name, nm.Addresses) + for _, peer := range nm.Peers { + set(peer.Name, peer.Addresses) } } - nameToIP := make(map[string][]netaddr.IP) - set := func(name string, addrs []netaddr.IPPrefix) { - if len(addrs) == 0 || name == "" { - return - } - for _, addr := range addrs { - nameToIP[name] = append(nameToIP[name], addr.IP) - } - } - for _, peer := range nm.Peers { - set(peer.Name, peer.Addresses) - } - set(nm.Name, nm.Addresses) - - err = b.e.Reconfig(cfg, rcfg, nameToIP, magicDNSRootDomains(nm)) + err = b.e.Reconfig(cfg, rcfg, &dcfg) if err == wgengine.ErrNoChanges { return } @@ -1725,7 +1731,7 @@ func (b *LocalBackend) enterState(newState ipn.State) { b.blockEngineUpdates(true) fallthrough case ipn.Stopped: - err := b.e.Reconfig(&wgcfg.Config{}, &router.Config{}, nil, nil) + err := b.e.Reconfig(&wgcfg.Config{}, &router.Config{}, &dns.Config{}) if err != nil { b.logf("Reconfig(down): %v", err) } @@ -1817,7 +1823,7 @@ func (b *LocalBackend) stateMachine() { // a status update that predates the "I've shut down" update. func (b *LocalBackend) stopEngineAndWait() { b.logf("stopEngineAndWait...") - b.e.Reconfig(&wgcfg.Config{}, &router.Config{}, nil, nil) + b.e.Reconfig(&wgcfg.Config{}, &router.Config{}, &dns.Config{}) b.requestEngineStatusAndWait() b.logf("stopEngineAndWait: done.") } diff --git a/net/dns/config.go b/net/dns/config.go index 06e0fffe1..b73667980 100644 --- a/net/dns/config.go +++ b/net/dns/config.go @@ -42,18 +42,11 @@ type OSConfig struct { Nameservers []netaddr.IP // Domains are the search domains to use. Domains []string - // Proxied indicates whether DNS requests are proxied through a dns.Resolver. - // This enables MagicDNS. - Proxied bool } // Equal determines whether its argument and receiver // represent equivalent DNS configurations (then DNS reconfig is a no-op). func (lhs OSConfig) Equal(rhs OSConfig) bool { - if lhs.Proxied != rhs.Proxied { - return false - } - if len(lhs.Nameservers) != len(rhs.Nameservers) { return false } diff --git a/wgengine/router/router.go b/wgengine/router/router.go index 5d05ee811..6fe63212e 100644 --- a/wgengine/router/router.go +++ b/wgengine/router/router.go @@ -58,6 +58,7 @@ type Config struct { // this node has chosen to use. Routes []netaddr.IPPrefix + // Set internally by wgengine, must not be set elsewhere. DNS dns.OSConfig // Linux-only things below, ignored on other platforms. diff --git a/wgengine/userspace.go b/wgengine/userspace.go index a8c8b3752..3f28998d4 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -29,6 +29,7 @@ import ( "tailscale.com/health" "tailscale.com/internal/deepprint" "tailscale.com/ipn/ipnstate" + "tailscale.com/net/dns" "tailscale.com/net/dns/resolver" "tailscale.com/net/flowtrack" "tailscale.com/net/interfaces" @@ -912,10 +913,13 @@ func genLocalAddrFunc(addrs []netaddr.IPPrefix) func(netaddr.IP) bool { return func(t netaddr.IP) bool { return m[t] } } -func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, hosts map[string][]netaddr.IP, localDomains []string) error { +func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCfg *dns.Config) error { if routerCfg == nil { panic("routerCfg must not be nil") } + if dnsCfg == nil { + panic("dnsCfg must not be nil") + } e.isLocalAddr.Store(genLocalAddrFunc(routerCfg.LocalAddrs)) @@ -932,7 +936,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, e.mu.Unlock() engineChanged := deepprint.UpdateHash(&e.lastEngineSigFull, cfg) - routerChanged := deepprint.UpdateHash(&e.lastRouterSig, routerCfg, hosts, localDomains) + routerChanged := deepprint.UpdateHash(&e.lastRouterSig, routerCfg, dnsCfg) if !engineChanged && !routerChanged { return ErrNoChanges } @@ -979,22 +983,28 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, if routerChanged { resolverCfg := resolver.Config{ - Hosts: hosts, - LocalDomains: localDomains, + Hosts: dnsCfg.Hosts, + LocalDomains: dnsCfg.AuthoritativeSuffixes, Routes: map[string][]netaddr.IPPort{}, } - if routerCfg.DNS.Proxied { - ips := routerCfg.DNS.Nameservers - upstreams := make([]netaddr.IPPort, len(ips)) - for i, ip := range ips { - upstreams[i] = netaddr.IPPort{ - IP: ip, - Port: 53, - } - } - resolverCfg.Routes["."] = upstreams - routerCfg.DNS.Nameservers = []netaddr.IP{tsaddr.TailscaleServiceIP()} + // We must proxy through quad-100 if MagicDNS hosts are in + // use, or there are any per-domain routes. + mustProxy := len(dnsCfg.Hosts) > 0 || len(dnsCfg.Routes) > 0 + routerCfg.DNS = dns.OSConfig{ + Domains: dnsCfg.SearchDomains, } + if mustProxy { + routerCfg.DNS.Nameservers = []netaddr.IP{tsaddr.TailscaleServiceIP()} + resolverCfg.Routes["."] = dnsCfg.DefaultResolvers + for suffix, resolvers := range dnsCfg.Routes { + resolverCfg.Routes[suffix] = resolvers + } + } else { + for _, resolver := range dnsCfg.DefaultResolvers { + routerCfg.DNS.Nameservers = append(routerCfg.DNS.Nameservers, resolver.IP) + } + } + routerCfg.DNS.Domains = dnsCfg.SearchDomains e.resolver.SetConfig(resolverCfg) // TODO: check error and propagate to health pkg e.logf("wgengine: Reconfig: configuring router") err := e.router.Set(routerCfg) diff --git a/wgengine/userspace_test.go b/wgengine/userspace_test.go index 62aaa4433..8c65b52a0 100644 --- a/wgengine/userspace_test.go +++ b/wgengine/userspace_test.go @@ -13,6 +13,7 @@ import ( "go4.org/mem" "inet.af/netaddr" + "tailscale.com/net/dns" "tailscale.com/net/tstun" "tailscale.com/tailcfg" "tailscale.com/types/key" @@ -108,7 +109,7 @@ func TestUserspaceEngineReconfig(t *testing.T) { }, } - err = e.Reconfig(cfg, routerCfg, nil, nil) + err = e.Reconfig(cfg, routerCfg, &dns.Config{}) if err != nil { t.Fatal(err) } diff --git a/wgengine/watchdog.go b/wgengine/watchdog.go index 3f8ea85cd..8db843d7d 100644 --- a/wgengine/watchdog.go +++ b/wgengine/watchdog.go @@ -14,6 +14,7 @@ import ( "inet.af/netaddr" "tailscale.com/ipn/ipnstate" + "tailscale.com/net/dns" "tailscale.com/net/tstun" "tailscale.com/tailcfg" "tailscale.com/types/netmap" @@ -73,8 +74,8 @@ func (e *watchdogEngine) watchdog(name string, fn func()) { }) } -func (e *watchdogEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, hosts map[string][]netaddr.IP, localDomains []string) error { - return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg, hosts, localDomains) }) +func (e *watchdogEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCfg *dns.Config) error { + return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg, dnsCfg) }) } func (e *watchdogEngine) GetLinkMonitor() *monitor.Mon { return e.wrap.GetLinkMonitor() diff --git a/wgengine/wgengine.go b/wgengine/wgengine.go index 4ec01d609..fc25072ed 100644 --- a/wgengine/wgengine.go +++ b/wgengine/wgengine.go @@ -9,6 +9,7 @@ import ( "inet.af/netaddr" "tailscale.com/ipn/ipnstate" + "tailscale.com/net/dns" "tailscale.com/tailcfg" "tailscale.com/types/netmap" "tailscale.com/wgengine/filter" @@ -56,7 +57,7 @@ type Engine interface { // sends an updated network map. // // The returned error is ErrNoChanges if no changes were made. - Reconfig(*wgcfg.Config, *router.Config, map[string][]netaddr.IP, []string) error + Reconfig(*wgcfg.Config, *router.Config, *dns.Config) error // GetFilter returns the current packet filter, if any. GetFilter() *filter.Filter