summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Crawshaw <crawshaw@tailscale.com>2023-01-28 16:44:53 -0800
committerDavid Crawshaw <crawshaw@tailscale.com>2023-01-28 16:46:02 -0800
commita795ea8cee2d3b9d37ae15888210413e964d39c1 (patch)
treef7961ac018a790e4605dc4c3a3bf90764804a91c
parente51cf1b09d0de6319c776c456e8b23be426a1b74 (diff)
downloadtailscale-crawshaw/ondemanddomains.tar.xz
tailscale-crawshaw/ondemanddomains.zip
tailcfg, etc: plumb OnDemandDomains from the servercrawshaw/ondemanddomains
This lets the server tell macOS/iOS that tailscale should be started to handle any "ts.net" domains. Updates #1534 Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
-rw-r--r--ipn/ipnlocal/dnsconfig_test.go16
-rw-r--r--ipn/ipnlocal/local.go5
-rw-r--r--net/dns/config.go8
-rw-r--r--net/dns/osconfig.go22
-rw-r--r--tailcfg/tailcfg.go9
-rw-r--r--tailcfg/tailcfg_clone.go2
-rw-r--r--tailcfg/tailcfg_view.go4
7 files changed, 63 insertions, 3 deletions
diff --git a/ipn/ipnlocal/dnsconfig_test.go b/ipn/ipnlocal/dnsconfig_test.go
index 5b0a7e387..96395fc09 100644
--- a/ipn/ipnlocal/dnsconfig_test.go
+++ b/ipn/ipnlocal/dnsconfig_test.go
@@ -305,6 +305,22 @@ func TestDNSConfigForNetmap(t *testing.T) {
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
},
},
+ {
+ name: "on_demand_domains",
+ nm: &netmap.NetworkMap{
+ DNS: tailcfg.DNSConfig{
+ OnDemandDomains: []string{"ts.net"},
+ },
+ },
+ prefs: &ipn.Prefs{
+ CorpDNS: true,
+ },
+ want: &dns.Config{
+ Hosts: map[dnsname.FQDN][]netip.Addr{},
+ Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
+ OnDemandDomains: []string{"ts.net"},
+ },
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go
index 4bbd97876..2f8385680 100644
--- a/ipn/ipnlocal/local.go
+++ b/ipn/ipnlocal/local.go
@@ -2965,8 +2965,9 @@ func shouldUseOneCGNATRoute(nm *netmap.NetworkMap, logf logger.Logf, versionOS s
// a runtime.GOOS.
func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs ipn.PrefsView, logf logger.Logf, versionOS string) *dns.Config {
dcfg := &dns.Config{
- Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
- Hosts: map[dnsname.FQDN][]netip.Addr{},
+ Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
+ Hosts: map[dnsname.FQDN][]netip.Addr{},
+ OnDemandDomains: append([]string(nil), nm.DNS.OnDemandDomains...),
}
// selfV6Only is whether we only have IPv6 addresses ourselves.
diff --git a/net/dns/config.go b/net/dns/config.go
index 9c55f6d73..f70b137d0 100644
--- a/net/dns/config.go
+++ b/net/dns/config.go
@@ -44,6 +44,14 @@ type Config struct {
// OnlyIPv6, if true, uses the IPv6 service IP (for MagicDNS)
// instead of the IPv4 version (100.100.100.100).
OnlyIPv6 bool
+ // OnDemandDomains are the set of domain names for which the OS
+ // should enable the tailscale client, if it is not already running.
+ //
+ // This is plumbed through to the onDemand rules of
+ // NETunnelProviderManager on macOS/iOS.
+ //
+ // The typical OnDemandDomains is ["ts.net"].
+ OnDemandDomains []string `json:",omitempty"`
}
func (c *Config) serviceIP() netip.Addr {
diff --git a/net/dns/osconfig.go b/net/dns/osconfig.go
index b12e6418b..aef357eb9 100644
--- a/net/dns/osconfig.go
+++ b/net/dns/osconfig.go
@@ -63,10 +63,18 @@ type OSConfig struct {
// from the OS, which will only work with OSConfigurators that
// report SupportsSplitDNS()=true.
MatchDomains []dnsname.FQDN
+ // OnDemandDomains are the set of domain names for which the OS
+ // should enable the tailscale client, if it is not already running.
+ //
+ // This is plumbed through to the onDemand rules of
+ // NETunnelProviderManager on macOS/iOS.
+ //
+ // The typical OnDemandDomains is ["ts.net"].
+ OnDemandDomains []string
}
func (o OSConfig) IsZero() bool {
- return len(o.Nameservers) == 0 && len(o.SearchDomains) == 0 && len(o.MatchDomains) == 0
+ return len(o.Nameservers) == 0 && len(o.SearchDomains) == 0 && len(o.MatchDomains) == 0 && len(o.OnDemandDomains) == 0
}
func (a OSConfig) Equal(b OSConfig) bool {
@@ -95,6 +103,11 @@ func (a OSConfig) Equal(b OSConfig) bool {
return false
}
}
+ for i := range a.OnDemandDomains {
+ if a.OnDemandDomains[i] != b.OnDemandDomains[i] {
+ return false
+ }
+ }
return true
}
@@ -126,6 +139,13 @@ func (a OSConfig) Format(f fmt.State, verb rune) {
}
fmt.Fprintf(w, "%+v", domain)
}
+ w.WriteString(`] OnDemandDomains:[`)
+ for i, domain := range a.OnDemandDomains {
+ if i != 0 {
+ w.WriteString(" ")
+ }
+ fmt.Fprintf(w, "%+v", domain)
+ }
w.WriteString(`] Hosts:[`)
for i, host := range a.Hosts {
if i != 0 {
diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go
index 9b8905647..45e72c1cb 100644
--- a/tailcfg/tailcfg.go
+++ b/tailcfg/tailcfg.go
@@ -1190,6 +1190,15 @@ type DNSConfig struct {
//
// Matches are case insensitive.
ExitNodeFilteredSet []string
+
+ // OnDemandDomains are the set of domain names for which the OS
+ // should enable the tailscale client, if it is not already running.
+ //
+ // This is plumbed through to the onDemand rules of
+ // NETunnelProviderManager on macOS/iOS.
+ //
+ // The typical OnDemandDomains is ["ts.net"].
+ OnDemandDomains []string `json:",omitempty"`
}
// DNSRecord is an extra DNS record to add to MagicDNS.
diff --git a/tailcfg/tailcfg_clone.go b/tailcfg/tailcfg_clone.go
index 689b57771..dada5348d 100644
--- a/tailcfg/tailcfg_clone.go
+++ b/tailcfg/tailcfg_clone.go
@@ -234,6 +234,7 @@ func (src *DNSConfig) Clone() *DNSConfig {
dst.CertDomains = append(src.CertDomains[:0:0], src.CertDomains...)
dst.ExtraRecords = append(src.ExtraRecords[:0:0], src.ExtraRecords...)
dst.ExitNodeFilteredSet = append(src.ExitNodeFilteredSet[:0:0], src.ExitNodeFilteredSet...)
+ dst.OnDemandDomains = append(src.OnDemandDomains[:0:0], src.OnDemandDomains...)
return dst
}
@@ -248,6 +249,7 @@ var _DNSConfigCloneNeedsRegeneration = DNSConfig(struct {
CertDomains []string
ExtraRecords []DNSRecord
ExitNodeFilteredSet []string
+ OnDemandDomains []string
}{})
// Clone makes a deep copy of RegisterResponse.
diff --git a/tailcfg/tailcfg_view.go b/tailcfg/tailcfg_view.go
index 463cc3620..50f38d64d 100644
--- a/tailcfg/tailcfg_view.go
+++ b/tailcfg/tailcfg_view.go
@@ -533,6 +533,9 @@ func (v DNSConfigView) ExtraRecords() views.Slice[DNSRecord] { return views.Slic
func (v DNSConfigView) ExitNodeFilteredSet() views.Slice[string] {
return views.SliceOf(v.ж.ExitNodeFilteredSet)
}
+func (v DNSConfigView) OnDemandDomains() views.Slice[string] {
+ return views.SliceOf(v.ж.OnDemandDomains)
+}
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _DNSConfigViewNeedsRegeneration = DNSConfig(struct {
@@ -545,6 +548,7 @@ var _DNSConfigViewNeedsRegeneration = DNSConfig(struct {
CertDomains []string
ExtraRecords []DNSRecord
ExitNodeFilteredSet []string
+ OnDemandDomains []string
}{})
// View returns a readonly view of RegisterResponse.