diff --git a/net/dns/resolver/tsdns.go b/net/dns/resolver/tsdns.go index 19576c91e..e8d85d77f 100644 --- a/net/dns/resolver/tsdns.go +++ b/net/dns/resolver/tsdns.go @@ -34,6 +34,8 @@ import ( "tailscale.com/wgengine/monitor" ) +const dnsSymbolicFQDN = "magicdns.localhost-tailscale-daemon." + // maxResponseBytes is the maximum size of a response from a Resolver. The // actual buffer size will be one larger than this so that we can detect // truncation in a platform-agnostic way. @@ -553,6 +555,18 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP, return netaddr.IP{}, dns.RCodeNameError } + // We return a symbolic domain if someone does a reverse lookup on the + // DNS endpoint. To round out this special case, we also do the inverse + // (returning the endpoint IP if someone looks up the symbolic domain). + if domain == dnsSymbolicFQDN { + switch typ { + case dns.TypeA: + return tsaddr.TailscaleServiceIP(), dns.RCodeSuccess + case dns.TypeAAAA: + return tsaddr.TailscaleServiceIPv6(), dns.RCodeSuccess + } + } + r.mu.Lock() hosts := r.hostToIP localDomains := r.localDomains @@ -644,6 +658,14 @@ func (r *Resolver) resolveLocalReverse(name dnsname.FQDN) (dnsname.FQDN, dns.RCo return "", dns.RCodeRefused } + // If someone curiously does a reverse lookup on the DNS IP, we + // return a domain that helps indicate that Tailscale is using + // this IP for a special purpose and it is not a node on their + // tailnet. + if ip == tsaddr.TailscaleServiceIP() || ip == tsaddr.TailscaleServiceIPv6() { + return dnsSymbolicFQDN, dns.RCodeSuccess + } + r.mu.Lock() defer r.mu.Unlock() ret, ok := r.ipToHost[ip] diff --git a/net/dns/resolver/tsdns_test.go b/net/dns/resolver/tsdns_test.go index 1665c2373..9f62eaa68 100644 --- a/net/dns/resolver/tsdns_test.go +++ b/net/dns/resolver/tsdns_test.go @@ -344,6 +344,7 @@ func TestResolveLocal(t *testing.T) { {"mx-nxdomain", "test3.ipn.dev.", dns.TypeMX, netaddr.IP{}, dns.RCodeNameError}, {"ns-nxdomain", "test3.ipn.dev.", dns.TypeNS, netaddr.IP{}, dns.RCodeNameError}, {"onion-domain", "footest.onion.", dns.TypeA, netaddr.IP{}, dns.RCodeNameError}, + {"magicdns", dnsSymbolicFQDN, dns.TypeA, netaddr.MustParseIP("100.100.100.100"), dns.RCodeSuccess}, } for _, tt := range tests { @@ -377,6 +378,7 @@ func TestResolveLocalReverse(t *testing.T) { {"ipv4_nxdomain", dnsname.FQDN("5.3.2.1.in-addr.arpa."), "", dns.RCodeNameError}, {"ipv6_nxdomain", dnsname.FQDN("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa."), "", dns.RCodeNameError}, {"nxdomain", dnsname.FQDN("2.3.4.5.in-addr.arpa."), "", dns.RCodeRefused}, + {"magicdns", dnsname.FQDN("100.100.100.100.in-addr.arpa."), dnsSymbolicFQDN, dns.RCodeSuccess}, } for _, tt := range tests {