diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index a2741aab5..37cd42934 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1750,6 +1750,25 @@ func (b *LocalBackend) authReconfig() { for _, peer := range nm.Peers { set(peer.Name, peer.Addresses) } + for _, rec := range nm.DNS.ExtraRecords { + switch rec.Type { + case "", "A", "AAAA": + // Treat these all the same for now: infer from the value + default: + // TODO: more + continue + } + ip, err := netaddr.ParseIP(rec.Value) + if err != nil { + // Ignore. + continue + } + fqdn, err := dnsname.ToFQDN(rec.Name) + if err != nil { + continue + } + dcfg.Hosts[fqdn] = append(dcfg.Hosts[fqdn], ip) + } if uc.CorpDNS { addDefault := func(resolvers []tailcfg.DNSResolver) { diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 27d14424c..e915dd8cf 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -44,7 +44,8 @@ // 19: 2021-04-21: MapResponse.Debug.SleepSeconds // 20: 2021-06-11: MapResponse.LastSeen used even less (https://github.com/tailscale/tailscale/issues/2107) // 21: 2021-06-15: added MapResponse.DNSConfig.CertDomains -const CurrentMapRequestVersion = 21 +// 22: 2021-06-16: added MapResponse.DNSConfig.ExtraRecords +const CurrentMapRequestVersion = 22 type StableID string @@ -882,6 +883,28 @@ type DNSConfig struct { // These names are FQDNs without trailing periods, and without // any "_acme-challenge." prefix. CertDomains []string `json:",omitempty"` + + // ExtraRecords contains extra DNS records to add to the + // MagicDNS config. + ExtraRecords []DNSRecord `json:",omitempty"` +} + +// DNSRecord is an extra DNS record to add to MagicDNS. +type DNSRecord struct { + // Name is the fully qualified domain name of + // the record to add. The trailing dot is optional. + Name string + + // Type is the DNS record type. + // Empty means A or AAAA, depending on value. + // Other values are currently ignored. + Type string `json:",omitempty"` + + // Value is the IP address in string form. + // TODO(bradfitz): if we ever add support for record types + // with non-UTF8 binary data, add ValueBytes []byte that + // would take precedence. + Value string } // PingRequest is a request to send an HTTP request to prove the diff --git a/tailcfg/tailcfg_clone.go b/tailcfg/tailcfg_clone.go index 36f33ffb5..706ac2981 100644 --- a/tailcfg/tailcfg_clone.go +++ b/tailcfg/tailcfg_clone.go @@ -205,6 +205,7 @@ func (src *DNSConfig) Clone() *DNSConfig { dst.Domains = append(src.Domains[:0:0], src.Domains...) dst.Nameservers = append(src.Nameservers[:0:0], src.Nameservers...) dst.CertDomains = append(src.CertDomains[:0:0], src.CertDomains...) + dst.ExtraRecords = append(src.ExtraRecords[:0:0], src.ExtraRecords...) return dst } @@ -219,6 +220,7 @@ func (src *DNSConfig) Clone() *DNSConfig { Nameservers []netaddr.IP PerDomain bool CertDomains []string + ExtraRecords []DNSRecord }{}) // Clone makes a deep copy of DNSResolver.