net/dns/resolver: support magic resolution of via-<siteid>.<ip4> domains

Updates #3616

Signed-off-by: Tom DNetto <tom@tailscale.com>
pull/4501/head
Tom DNetto 2 years ago committed by Tom
parent 910ae68e0b
commit 78fededaa5

@ -17,6 +17,7 @@ import (
"os"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
@ -633,6 +634,10 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
return tsaddr.TailscaleServiceIPv6(), dns.RCodeSuccess
}
}
// Special-case: 'via-<siteid>.<ipv4>' queries.
if ip, ok := r.parseViaDomain(domain, typ); ok {
return ip, dns.RCodeSuccess
}
r.mu.Lock()
hosts := r.hostToIP
@ -708,6 +713,46 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
}
}
// parseViaDomain synthesizes an IP address for quad-A DNS requests of
// the form 'via-<X>.<IPv4-address>', where X is a decimal, or hex-encoded
// number with a '0x' prefix.
//
// This exists as a convenient mapping into Tailscales 'Via Range'.
func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP, bool) {
fqdn := string(domain.WithoutTrailingDot())
if typ != dns.TypeAAAA {
return netaddr.IP{}, false
}
if len(fqdn) < len("via-X.0.0.0.0") {
return netaddr.IP{}, false // too short to be valid
}
if !strings.HasPrefix(fqdn, "via-") {
return netaddr.IP{}, false
}
firstDot := strings.Index(fqdn, ".")
if firstDot < 0 {
return netaddr.IP{}, false // missing dot delimiters
}
siteID := fqdn[len("via-"):firstDot]
ip4Str := fqdn[firstDot+1:]
ip4, err := netaddr.ParseIP(ip4Str)
if err != nil {
return netaddr.IP{}, false // badly formed, dont respond
}
prefix, err := strconv.ParseUint(siteID, 0, 32)
if err != nil {
return netaddr.IP{}, false // badly formed, dont respond
}
// MapVia will never error when given an ipv4 netaddr.IPPrefix.
out, _ := tsaddr.MapVia(uint32(prefix), netaddr.IPPrefixFrom(ip4, ip4.BitLen()))
return out.IP(), true
}
// resolveReverse returns the unique domain name that maps to the given address.
func (r *Resolver) resolveLocalReverse(name dnsname.FQDN) (dnsname.FQDN, dns.RCode) {
var ip netaddr.IP

@ -348,6 +348,9 @@ func TestResolveLocal(t *testing.T) {
{"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},
{"via_hex", dnsname.FQDN("via-0xff.1.2.3.4."), dns.TypeAAAA, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:ff:102:304"), dns.RCodeSuccess},
{"via_dec", dnsname.FQDN("via-1.10.0.0.1."), dns.TypeAAAA, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:1:a00:1"), dns.RCodeSuccess},
{"via_invalid", dnsname.FQDN("via-."), dns.TypeA, netaddr.IP{}, dns.RCodeRefused},
}
for _, tt := range tests {

Loading…
Cancel
Save