|
|
|
|
@ -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 |
|
|
|
|
|