diff --git a/ipn/ipnlocal/dnsconfig_test.go b/ipn/ipnlocal/dnsconfig_test.go index 2e2e37e9f..4f6a32224 100644 --- a/ipn/ipnlocal/dnsconfig_test.go +++ b/ipn/ipnlocal/dnsconfig_test.go @@ -64,9 +64,8 @@ func TestDNSConfigForNetmap(t *testing.T) { nm: &netmap.NetworkMap{}, prefs: &ipn.Prefs{}, want: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: map[dnsname.FQDN][]netip.Addr{}, - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: map[dnsname.FQDN][]netip.Addr{}, }, }, { @@ -103,7 +102,6 @@ func TestDNSConfigForNetmap(t *testing.T) { "peera.net.": ips("100.102.0.1", "100.102.0.2"), "v6-only.net.": ips("fe75::3"), }, - SubdomainHosts: map[dnsname.FQDN]bool{}, }, }, { @@ -136,10 +134,7 @@ func TestDNSConfigForNetmap(t *testing.T) { "peer-with-cap.net.": ips("100.102.0.1"), "peer-without-cap.net.": ips("100.102.0.2"), }, - SubdomainHosts: map[dnsname.FQDN]bool{ - "myname.net.": true, - "peer-with-cap.net.": true, - }, + SubdomainHosts: set.Of[dnsname.FQDN]("myname.net.", "peer-with-cap.net."), }, }, { @@ -180,7 +175,6 @@ func TestDNSConfigForNetmap(t *testing.T) { "peera.net.": ips("fe75::1001"), "v6-only.net.": ips("fe75::3"), }, - SubdomainHosts: map[dnsname.FQDN]bool{}, }, }, { @@ -206,7 +200,6 @@ func TestDNSConfigForNetmap(t *testing.T) { "foo.com.": ips("1.2.3.4"), "bar.com.": ips("1::6"), }, - SubdomainHosts: map[dnsname.FQDN]bool{}, }, }, { @@ -297,7 +290,6 @@ func TestDNSConfigForNetmap(t *testing.T) { "foo.com.", "bar.com.", }, - SubdomainHosts: map[dnsname.FQDN]bool{}, }, }, { @@ -332,7 +324,6 @@ func TestDNSConfigForNetmap(t *testing.T) { Routes: map[dnsname.FQDN][]*dnstype.Resolver{ "foo.com.": {{Addr: "1.2.3.4"}}, }, - SubdomainHosts: map[dnsname.FQDN]bool{}, }, }, { @@ -354,7 +345,6 @@ func TestDNSConfigForNetmap(t *testing.T) { DefaultResolvers: []*dnstype.Resolver{ {Addr: "8.8.4.4"}, }, - SubdomainHosts: map[dnsname.FQDN]bool{}, }, }, { @@ -370,9 +360,8 @@ func TestDNSConfigForNetmap(t *testing.T) { CorpDNS: true, }, want: &dns.Config{ - Hosts: map[dnsname.FQDN][]netip.Addr{}, - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - SubdomainHosts: map[dnsname.FQDN]bool{}, + Hosts: map[dnsname.FQDN][]netip.Addr{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, }, }, { diff --git a/ipn/ipnlocal/node_backend.go b/ipn/ipnlocal/node_backend.go index c6a6e2ba6..ebec0542c 100644 --- a/ipn/ipnlocal/node_backend.go +++ b/ipn/ipnlocal/node_backend.go @@ -694,9 +694,8 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, peers map[tailcfg.NodeID]tailcfg. } dcfg := &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: map[dnsname.FQDN][]netip.Addr{}, - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: map[dnsname.FQDN][]netip.Addr{}, } // selfV6Only is whether we only have IPv6 addresses ourselves. @@ -752,14 +751,16 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, peers map[tailcfg.NodeID]tailcfg. set(nm.SelfName(), nm.GetAddresses()) if nm.AllCaps.Contains(tailcfg.NodeAttrDNSSubdomainResolve) { if fqdn, err := dnsname.ToFQDN(nm.SelfName()); err == nil { - dcfg.SubdomainHosts[fqdn] = true + dcfg.SubdomainHosts.Make() + dcfg.SubdomainHosts.Add(fqdn) } } for _, peer := range peers { set(peer.Name(), peer.Addresses()) if peer.CapMap().Contains(tailcfg.NodeAttrDNSSubdomainResolve) { if fqdn, err := dnsname.ToFQDN(peer.Name()); err == nil { - dcfg.SubdomainHosts[fqdn] = true + dcfg.SubdomainHosts.Make() + dcfg.SubdomainHosts.Add(fqdn) } } } diff --git a/ipn/ipnlocal/state_test.go b/ipn/ipnlocal/state_test.go index 1dac83fce..27d53fe01 100644 --- a/ipn/ipnlocal/state_test.go +++ b/ipn/ipnlocal/state_test.go @@ -1300,9 +1300,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) { Routes: routesWithQuad100(), }, wantDNSCfg: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: hostsFor(node1), - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: hostsFor(node1), }, }, { @@ -1357,9 +1356,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) { Routes: routesWithQuad100(), }, wantDNSCfg: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: hostsFor(node2), - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: hostsFor(node2), }, }, { @@ -1406,9 +1404,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) { Routes: routesWithQuad100(), }, wantDNSCfg: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: hostsFor(node1), - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: hostsFor(node1), }, }, { @@ -1439,9 +1436,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) { Routes: routesWithQuad100(), }, wantDNSCfg: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: hostsFor(node3), - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: hostsFor(node3), }, }, { @@ -1504,9 +1500,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) { Routes: routesWithQuad100(), }, wantDNSCfg: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: hostsFor(node1), - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: hostsFor(node1), }, }, { @@ -1534,9 +1529,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) { Routes: routesWithQuad100(), }, wantDNSCfg: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: hostsFor(node1), - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: hostsFor(node1), }, }, { @@ -1566,9 +1560,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) { Routes: routesWithQuad100(), }, wantDNSCfg: &dns.Config{ - Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, - Hosts: hostsFor(node1), - SubdomainHosts: map[dnsname.FQDN]bool{}, + Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, + Hosts: hostsFor(node1), }, }, { diff --git a/net/dns/config.go b/net/dns/config.go index b3fb208ee..af9567a15 100644 --- a/net/dns/config.go +++ b/net/dns/config.go @@ -21,6 +21,7 @@ import ( "tailscale.com/net/tsaddr" "tailscale.com/types/dnstype" "tailscale.com/util/dnsname" + "tailscale.com/util/set" ) // Config is a DNS configuration. @@ -52,7 +53,7 @@ type Config struct { // resolve subdomain queries to the same IPs. For example, if // "node.tailnet.ts.net" is in SubdomainHosts, then queries for // "anything.node.tailnet.ts.net" will resolve to node's IPs. - SubdomainHosts map[dnsname.FQDN]bool + SubdomainHosts set.Set[dnsname.FQDN] // OnlyIPv6, if true, uses the IPv6 service IP (for MagicDNS) // instead of the IPv4 version (100.100.100.100). OnlyIPv6 bool diff --git a/net/dns/dns_clone.go b/net/dns/dns_clone.go index 2d242abc2..2c3e1679b 100644 --- a/net/dns/dns_clone.go +++ b/net/dns/dns_clone.go @@ -11,6 +11,7 @@ import ( "tailscale.com/types/dnstype" "tailscale.com/util/dnsname" + "tailscale.com/util/set" ) // Clone makes a deep copy of Config. @@ -54,7 +55,7 @@ var _ConfigCloneNeedsRegeneration = Config(struct { Routes map[dnsname.FQDN][]*dnstype.Resolver SearchDomains []dnsname.FQDN Hosts map[dnsname.FQDN][]netip.Addr - SubdomainHosts map[dnsname.FQDN]bool + SubdomainHosts set.Set[dnsname.FQDN] OnlyIPv6 bool }{}) diff --git a/net/dns/dns_view.go b/net/dns/dns_view.go index d83ad683f..d82df1595 100644 --- a/net/dns/dns_view.go +++ b/net/dns/dns_view.go @@ -15,6 +15,7 @@ import ( "tailscale.com/types/dnstype" "tailscale.com/types/views" "tailscale.com/util/dnsname" + "tailscale.com/util/set" ) //go:generate go run tailscale.com/cmd/cloner -clonefunc=true -type=Config @@ -127,7 +128,7 @@ func (v ConfigView) Hosts() views.MapSlice[dnsname.FQDN, netip.Addr] { // resolve subdomain queries to the same IPs. For example, if // "node.tailnet.ts.net" is in SubdomainHosts, then queries for // "anything.node.tailnet.ts.net" will resolve to node's IPs. -func (v ConfigView) SubdomainHosts() views.Map[dnsname.FQDN, bool] { +func (v ConfigView) SubdomainHosts() views.Map[dnsname.FQDN, struct{}] { return views.MapOf(v.ж.SubdomainHosts) } @@ -142,6 +143,6 @@ var _ConfigViewNeedsRegeneration = Config(struct { Routes map[dnsname.FQDN][]*dnstype.Resolver SearchDomains []dnsname.FQDN Hosts map[dnsname.FQDN][]netip.Addr - SubdomainHosts map[dnsname.FQDN]bool + SubdomainHosts set.Set[dnsname.FQDN] OnlyIPv6 bool }{}) diff --git a/net/dns/resolver/tsdns.go b/net/dns/resolver/tsdns.go index 97a19d43b..da9b97e65 100644 --- a/net/dns/resolver/tsdns.go +++ b/net/dns/resolver/tsdns.go @@ -39,6 +39,7 @@ import ( "tailscale.com/util/clientmetric" "tailscale.com/util/cloudenv" "tailscale.com/util/dnsname" + "tailscale.com/util/set" ) const dnsSymbolicFQDN = "magicdns.localhost-tailscale-daemon." @@ -84,7 +85,7 @@ type Config struct { // "sub.node.tailnet.ts.net" doesn't match Hosts directly, and // "node.tailnet.ts.net" is in SubdomainHosts, the query resolves // to the IPs for "node.tailnet.ts.net". - SubdomainHosts map[dnsname.FQDN]bool + SubdomainHosts set.Set[dnsname.FQDN] } // WriteToBufioWriter write a debug version of c for logs to w, omitting @@ -224,7 +225,7 @@ type Resolver struct { localDomains []dnsname.FQDN hostToIP map[dnsname.FQDN][]netip.Addr ipToHost map[netip.Addr]dnsname.FQDN - subdomainHosts map[dnsname.FQDN]bool + subdomainHosts set.Set[dnsname.FQDN] } type ForwardLinkSelector interface { @@ -656,7 +657,7 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netip.Addr, addrs, found := hosts[domain] if !found { for parent := domain.Parent(); parent != ""; parent = parent.Parent() { - if subdomainHosts[parent] { + if subdomainHosts.Contains(parent) { addrs, found = hosts[parent] break } diff --git a/net/dns/resolver/tsdns_test.go b/net/dns/resolver/tsdns_test.go index 1faf14882..5adf3b466 100644 --- a/net/dns/resolver/tsdns_test.go +++ b/net/dns/resolver/tsdns_test.go @@ -32,6 +32,7 @@ import ( "tailscale.com/types/logger" "tailscale.com/util/dnsname" "tailscale.com/util/eventbus/eventbustest" + "tailscale.com/util/set" ) var ( @@ -439,11 +440,8 @@ func TestResolveLocalSubdomain(t *testing.T) { "test1.ipn.dev.": {testipv4}, "test2.ipn.dev.": {testipv6}, }, - LocalDomains: []dnsname.FQDN{"ipn.dev."}, - SubdomainHosts: map[dnsname.FQDN]bool{ - "test1.ipn.dev.": true, // test1 allows subdomain resolution - // test2 does NOT allow subdomain resolution - }, + LocalDomains: []dnsname.FQDN{"ipn.dev."}, + SubdomainHosts: set.Of[dnsname.FQDN]("test1.ipn.dev."), } r.SetConfig(cfg)