net/dns/resolver: add support for <IPv4>.via-<site-id>

Currently we only support "via-<site-id>.<IPv4>", however that does not
work with Google Chrome which parses `http://via-1.10.0.0.1` as a search
string and not as a URL. This commit introduces "<IPv4>.via-<site-id>"
(`http://10.0.0.1.via-1`) which is parsed correctly by Chrome.

Updates #3616

Signed-off-by: Maisem Ali <maisem@tailscale.com>
pull/4780/head
Maisem Ali 3 years ago committed by Maisem Ali
parent 69b535c01f
commit 80157f3f37

@ -261,7 +261,6 @@ func (r *Resolver) Close() {
// bound on per-query resource usage.
const dnsQueryTimeout = 10 * time.Second
func (r *Resolver) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) {
metricDNSQueryLocal.Add(1)
select {
@ -617,11 +616,16 @@ 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.
// parseViaDomain synthesizes an IP address for quad-A DNS requests of the form
// `<IPv4-address>.via-<X>` and the deprecated 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'.
//
// TODO(maisem/bradfitz/tom): `<IPv4-address>.via-<X>` was introduced
// (2022-06-02) to work around an issue in Chrome where it would treat
// "http://via-1.1.2.3.4" as a search string instead of a URL. We should rip out
// the old format in early 2023.
func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP, bool) {
fqdn := string(domain.WithoutTrailingDot())
if typ != dns.TypeAAAA {
@ -630,17 +634,28 @@ func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP
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
}
var siteID string
var ip4Str string
if strings.HasPrefix(fqdn, "via-") {
firstDot := strings.Index(fqdn, ".")
if firstDot < 0 {
return netaddr.IP{}, false // missing dot delimiters
}
siteID := fqdn[len("via-"):firstDot]
ip4Str := fqdn[firstDot+1:]
siteID = fqdn[len("via-"):firstDot]
ip4Str = fqdn[firstDot+1:]
} else {
lastDot := strings.LastIndex(fqdn, ".")
if lastDot < 0 {
return netaddr.IP{}, false // missing dot delimiters
}
suffix := fqdn[lastDot+1:]
if !strings.HasPrefix(suffix, "via-") {
return netaddr.IP{}, false
}
siteID = suffix[len("via-"):]
ip4Str = fqdn[:lastDot]
}
ip4, err := netaddr.ParseIP(ip4Str)
if err != nil {

@ -343,9 +343,12 @@ 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},
{"via_hex", dnsname.FQDN("via-0xff.1.2.3.4."), dns.TypeAAAA, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:ff:1.2.3.4"), dns.RCodeSuccess},
{"via_dec", dnsname.FQDN("via-1.10.0.0.1."), dns.TypeAAAA, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:1:10.0.0.1"), dns.RCodeSuccess},
{"x_via_hex", dnsname.FQDN("4.3.2.1.via-0xff."), dns.TypeAAAA, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:ff:4.3.2.1"), dns.RCodeSuccess},
{"x_via_dec", dnsname.FQDN("1.0.0.10.via-1."), dns.TypeAAAA, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:1:1.0.0.10"), dns.RCodeSuccess},
{"via_invalid", dnsname.FQDN("via-."), dns.TypeAAAA, netaddr.IP{}, dns.RCodeRefused},
{"via_invalid_2", dnsname.FQDN("2.3.4.5.via-."), dns.TypeAAAA, netaddr.IP{}, dns.RCodeRefused},
}
for _, tt := range tests {

Loading…
Cancel
Save