From 80157f3f371d66bae253d1e62c1c5bb332d78430 Mon Sep 17 00:00:00 2001 From: Maisem Ali Date: Thu, 2 Jun 2022 22:58:46 +0500 Subject: [PATCH] net/dns/resolver: add support for .via- Currently we only support "via-.", 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 ".via-" (`http://10.0.0.1.via-1`) which is parsed correctly by Chrome. Updates #3616 Signed-off-by: Maisem Ali --- net/dns/resolver/tsdns.go | 41 +++++++++++++++++++++++----------- net/dns/resolver/tsdns_test.go | 9 +++++--- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/net/dns/resolver/tsdns.go b/net/dns/resolver/tsdns.go index b1ee65142..38d6ec73f 100644 --- a/net/dns/resolver/tsdns.go +++ b/net/dns/resolver/tsdns.go @@ -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-.', 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 +// `.via-` and the deprecated form `via-.`, +// 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): `.via-` 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,18 +634,29 @@ 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 - } - firstDot := strings.Index(fqdn, ".") - if firstDot < 0 { - return netaddr.IP{}, false // missing dot delimiters + 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:] + } 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] } - 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 diff --git a/net/dns/resolver/tsdns_test.go b/net/dns/resolver/tsdns_test.go index fd43078eb..cb8a000ed 100644 --- a/net/dns/resolver/tsdns_test.go +++ b/net/dns/resolver/tsdns_test.go @@ -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 {