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 <danderson@tailscale.com>
This commit is contained in:
David Anderson 2021-04-02 00:34:32 -07:00 committed by Dave Anderson
parent 2edb57dbf1
commit 6ad44f9fdf
7 changed files with 61 additions and 48 deletions

View File

@ -1442,35 +1442,41 @@ func (b *LocalBackend) authReconfig() {
rcfg := routerConfig(cfg, uc) 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 { if uc.CorpDNS {
proxied := nm.DNS.Proxied proxied := nm.DNS.Proxied
if proxied && len(nm.DNS.Nameservers) == 0 { if proxied && len(nm.DNS.Nameservers) == 0 {
b.logf("[unexpected] dns proxied but no nameservers") b.logf("[unexpected] dns proxied but no nameservers")
proxied = false proxied = false
} }
rcfg.DNS = dns.OSConfig{ for _, ip := range nm.DNS.Nameservers {
Nameservers: nm.DNS.Nameservers, dcfg.DefaultResolvers = append(dcfg.DefaultResolvers, netaddr.IPPort{
Domains: nm.DNS.Domains, IP: ip,
Proxied: proxied, Port: 53,
})
} }
} dcfg.SearchDomains = nm.DNS.Domains
dcfg.AuthoritativeSuffixes = magicDNSRootDomains(nm)
nameToIP := make(map[string][]netaddr.IP)
set := func(name string, addrs []netaddr.IPPrefix) { set := func(name string, addrs []netaddr.IPPrefix) {
if len(addrs) == 0 || name == "" { if len(addrs) == 0 || name == "" {
return return
} }
var ips []netaddr.IP
for _, addr := range addrs { for _, addr := range addrs {
nameToIP[name] = append(nameToIP[name], addr.IP) 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 { for _, peer := range nm.Peers {
set(peer.Name, peer.Addresses) 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 { if err == wgengine.ErrNoChanges {
return return
} }
@ -1725,7 +1731,7 @@ func (b *LocalBackend) enterState(newState ipn.State) {
b.blockEngineUpdates(true) b.blockEngineUpdates(true)
fallthrough fallthrough
case ipn.Stopped: 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 { if err != nil {
b.logf("Reconfig(down): %v", err) 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. // a status update that predates the "I've shut down" update.
func (b *LocalBackend) stopEngineAndWait() { func (b *LocalBackend) stopEngineAndWait() {
b.logf("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.requestEngineStatusAndWait()
b.logf("stopEngineAndWait: done.") b.logf("stopEngineAndWait: done.")
} }

View File

@ -42,18 +42,11 @@ type OSConfig struct {
Nameservers []netaddr.IP Nameservers []netaddr.IP
// Domains are the search domains to use. // Domains are the search domains to use.
Domains []string 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 // Equal determines whether its argument and receiver
// represent equivalent DNS configurations (then DNS reconfig is a no-op). // represent equivalent DNS configurations (then DNS reconfig is a no-op).
func (lhs OSConfig) Equal(rhs OSConfig) bool { func (lhs OSConfig) Equal(rhs OSConfig) bool {
if lhs.Proxied != rhs.Proxied {
return false
}
if len(lhs.Nameservers) != len(rhs.Nameservers) { if len(lhs.Nameservers) != len(rhs.Nameservers) {
return false return false
} }

View File

@ -58,6 +58,7 @@ type Config struct {
// this node has chosen to use. // this node has chosen to use.
Routes []netaddr.IPPrefix Routes []netaddr.IPPrefix
// Set internally by wgengine, must not be set elsewhere.
DNS dns.OSConfig DNS dns.OSConfig
// Linux-only things below, ignored on other platforms. // Linux-only things below, ignored on other platforms.

View File

@ -29,6 +29,7 @@ import (
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/internal/deepprint" "tailscale.com/internal/deepprint"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/dns"
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/flowtrack" "tailscale.com/net/flowtrack"
"tailscale.com/net/interfaces" "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] } 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 { if routerCfg == nil {
panic("routerCfg must not be nil") panic("routerCfg must not be nil")
} }
if dnsCfg == nil {
panic("dnsCfg must not be nil")
}
e.isLocalAddr.Store(genLocalAddrFunc(routerCfg.LocalAddrs)) e.isLocalAddr.Store(genLocalAddrFunc(routerCfg.LocalAddrs))
@ -932,7 +936,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
e.mu.Unlock() e.mu.Unlock()
engineChanged := deepprint.UpdateHash(&e.lastEngineSigFull, cfg) engineChanged := deepprint.UpdateHash(&e.lastEngineSigFull, cfg)
routerChanged := deepprint.UpdateHash(&e.lastRouterSig, routerCfg, hosts, localDomains) routerChanged := deepprint.UpdateHash(&e.lastRouterSig, routerCfg, dnsCfg)
if !engineChanged && !routerChanged { if !engineChanged && !routerChanged {
return ErrNoChanges return ErrNoChanges
} }
@ -979,22 +983,28 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
if routerChanged { if routerChanged {
resolverCfg := resolver.Config{ resolverCfg := resolver.Config{
Hosts: hosts, Hosts: dnsCfg.Hosts,
LocalDomains: localDomains, LocalDomains: dnsCfg.AuthoritativeSuffixes,
Routes: map[string][]netaddr.IPPort{}, Routes: map[string][]netaddr.IPPort{},
} }
if routerCfg.DNS.Proxied { // We must proxy through quad-100 if MagicDNS hosts are in
ips := routerCfg.DNS.Nameservers // use, or there are any per-domain routes.
upstreams := make([]netaddr.IPPort, len(ips)) mustProxy := len(dnsCfg.Hosts) > 0 || len(dnsCfg.Routes) > 0
for i, ip := range ips { routerCfg.DNS = dns.OSConfig{
upstreams[i] = netaddr.IPPort{ Domains: dnsCfg.SearchDomains,
IP: ip,
Port: 53,
} }
} if mustProxy {
resolverCfg.Routes["."] = upstreams
routerCfg.DNS.Nameservers = []netaddr.IP{tsaddr.TailscaleServiceIP()} 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.resolver.SetConfig(resolverCfg) // TODO: check error and propagate to health pkg
e.logf("wgengine: Reconfig: configuring router") e.logf("wgengine: Reconfig: configuring router")
err := e.router.Set(routerCfg) err := e.router.Set(routerCfg)

View File

@ -13,6 +13,7 @@ import (
"go4.org/mem" "go4.org/mem"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/net/dns"
"tailscale.com/net/tstun" "tailscale.com/net/tstun"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -14,6 +14,7 @@ import (
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/dns"
"tailscale.com/net/tstun" "tailscale.com/net/tstun"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/netmap" "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 { 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, hosts, localDomains) }) return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg, dnsCfg) })
} }
func (e *watchdogEngine) GetLinkMonitor() *monitor.Mon { func (e *watchdogEngine) GetLinkMonitor() *monitor.Mon {
return e.wrap.GetLinkMonitor() return e.wrap.GetLinkMonitor()

View File

@ -9,6 +9,7 @@ import (
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/dns"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
@ -56,7 +57,7 @@ type Engine interface {
// sends an updated network map. // sends an updated network map.
// //
// The returned error is ErrNoChanges if no changes were made. // 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 returns the current packet filter, if any.
GetFilter() *filter.Filter GetFilter() *filter.Filter