mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-15 01:53:08 -04:00
Every netmap change, including an incremental delta of a single peer, rebuilt the full MagicDNS state twice: dnsConfigForNetmap walked all peers to build the dns.Config.Hosts map, and resolver.SetConfig then walked that map again to build its reverse (PTR) index. On a tailnet with 10k peers that is a lot of garbage per delta. Instead, add a resolver.MagicDNSHosts hook, installed once by LocalBackend, that the quad-100 resolver consults on demand at query time. It is backed by nodeBackend's nodeByName, nodeByAddr, and peers indexes, which are already maintained incrementally as netmap deltas arrive. The subdomain-resolve capability check also moves to the hook (checking the node's CapMap at query time), so dns.Config's SubdomainHosts is no longer populated. dns.Config.Hosts remains for control's DNS.ExtraRecords, which are few and which feed the split-DNS decisions in dns.Manager's compileConfig, and on Windows it still carries every node's records because the hosts-file fallback path (compileHostEntries) needs the complete enumerable set. Those compileConfig decisions also consulted the per-node Hosts entries (hasHostsWithoutSplitDNSRoutes), so a new Config.MagicDNSHostsUnrouted bit preserves that signal now that node records are not listed: with MagicDNS names present but MagicDNS domain routing off, quad-100 stays in the OS resolver path. One small behavior change: reverse (PTR) lookups now also answer for node addresses whose forward records are filtered out by the IPv6-suppression rule (issue #1152), since nodeByAddr indexes all node addresses. Previously such addresses were absent from the pushed Hosts map and thus from the reverse index. Updates #12542 Updates tailscale/corp#43949 Change-Id: I63b99199c2b3b124c08cb8bbaea1f63165095294 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Code generated by tailscale.com/cmd/cloner; DO NOT EDIT.
|
|
|
|
package dns
|
|
|
|
import (
|
|
"net/netip"
|
|
|
|
"tailscale.com/types/dnstype"
|
|
"tailscale.com/util/dnsname"
|
|
"tailscale.com/util/set"
|
|
)
|
|
|
|
// Clone makes a deep copy of Config.
|
|
// The result aliases no memory with the original.
|
|
func (src *Config) Clone() *Config {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(Config)
|
|
*dst = *src
|
|
if src.DefaultResolvers != nil {
|
|
dst.DefaultResolvers = make([]*dnstype.Resolver, len(src.DefaultResolvers))
|
|
for i := range dst.DefaultResolvers {
|
|
if src.DefaultResolvers[i] == nil {
|
|
dst.DefaultResolvers[i] = nil
|
|
} else {
|
|
dst.DefaultResolvers[i] = src.DefaultResolvers[i].Clone()
|
|
}
|
|
}
|
|
}
|
|
if dst.Routes != nil {
|
|
dst.Routes = map[dnsname.FQDN][]*dnstype.Resolver{}
|
|
for k, sv := range src.Routes {
|
|
if sv == nil {
|
|
dst.Routes[k] = nil
|
|
continue
|
|
}
|
|
dst.Routes[k] = make([]*dnstype.Resolver, len(sv))
|
|
for i := range sv {
|
|
if sv[i] == nil {
|
|
dst.Routes[k][i] = nil
|
|
} else {
|
|
dst.Routes[k][i] = sv[i].Clone()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dst.SearchDomains = append(src.SearchDomains[:0:0], src.SearchDomains...)
|
|
if dst.Hosts != nil {
|
|
dst.Hosts = map[dnsname.FQDN][]netip.Addr{}
|
|
for k := range src.Hosts {
|
|
dst.Hosts[k] = append([]netip.Addr{}, src.Hosts[k]...)
|
|
}
|
|
}
|
|
dst.SubdomainHosts = src.SubdomainHosts.Clone()
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _ConfigCloneNeedsRegeneration = Config(struct {
|
|
AcceptDNS bool
|
|
DefaultResolvers []*dnstype.Resolver
|
|
Routes map[dnsname.FQDN][]*dnstype.Resolver
|
|
SearchDomains []dnsname.FQDN
|
|
Hosts map[dnsname.FQDN][]netip.Addr
|
|
SubdomainHosts set.Set[dnsname.FQDN]
|
|
OnlyIPv6 bool
|
|
MagicDNSHostsUnrouted bool
|
|
}{})
|
|
|
|
// Clone duplicates src into dst and reports whether it succeeded.
|
|
// To succeed, <src, dst> must be of types <*T, *T> or <*T, **T>,
|
|
// where T is one of Config.
|
|
func Clone(dst, src any) bool {
|
|
switch src := src.(type) {
|
|
case *Config:
|
|
switch dst := dst.(type) {
|
|
case *Config:
|
|
*dst = *src.Clone()
|
|
return true
|
|
case **Config:
|
|
*dst = src.Clone()
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|