net/dns/resolver: add yet another 4via6 DNS form that's hopefully more robust

$ dig +short @100.100.100.100 aaaa 10-2-5-3-via-7.foo-bar.ts.net
fd7a:115c:a1e0:b1a:0:7:a02:503

$ dig +short @100.100.100.100 aaaa 10-2-5-3-via-7
fd7a:115c:a1e0:b1a:0:7:a02:503

$ ping 10-2-5-3-via-7
PING 10-2-5-3-via-7(fd7a:115c:a1e0:b1a:0:7:a02:503 (fd7a:115c:a1e0:b1a:0:7:a02:503)) 56 data bytes
...

Change-Id: Ice8f954518a6a2fca8b2c04da7f31f61d78cdec4
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/6291/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent e0cd9e9dec
commit 66b4a363bd

@ -550,7 +550,7 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netip.Addr,
return tsaddr.TailscaleServiceIPv6(), dns.RCodeSuccess
}
}
// Special-case: 'via-<siteid>.<ipv4>' queries.
// Special-case: 4via6 DNS names.
if ip, ok := r.parseViaDomain(domain, typ); ok {
return ip, dns.RCodeSuccess
}
@ -630,7 +630,9 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netip.Addr,
}
// 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>`,
// `<IPv4-address-with-hypens-instead-of-dots>-via-<siteid>[.*]`. Two prior formats that
// didn't pan out (due to a Chrome issue and DNS search ndots issues) were
// `<IPv4-address>.via-<X>` and the older `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'.
@ -650,14 +652,28 @@ func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netip.Addr
var siteID string
var ip4Str string
if strings.HasPrefix(fqdn, "via-") {
switch {
case strings.Contains(fqdn, "-via-"):
// Format number 3: "192-168-1-2-via-7" or "192-168-1-2-via-7.foo.ts.net."
// Third time's a charm. The earlier two formats follow after this block.
firstLabel, domain, _ := strings.Cut(fqdn, ".") // "192-168-1-2-via-7"
if !(domain == "" || dnsname.HasSuffix(domain, "ts.net") || dnsname.HasSuffix(domain, "tailscale.net")) {
return netip.Addr{}, false
}
v4hyphens, suffix, ok := strings.Cut(firstLabel, "-via-")
if !ok {
return netip.Addr{}, false
}
siteID = suffix
ip4Str = strings.ReplaceAll(v4hyphens, "-", ".")
case strings.HasPrefix(fqdn, "via-"):
firstDot := strings.Index(fqdn, ".")
if firstDot < 0 {
return netip.Addr{}, false // missing dot delimiters
}
siteID = fqdn[len("via-"):firstDot]
ip4Str = fqdn[firstDot+1:]
} else {
default:
lastDot := strings.LastIndex(fqdn, ".")
if lastDot < 0 {
return netip.Addr{}, false // missing dot delimiters
@ -672,12 +688,12 @@ func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netip.Addr
ip4, err := netip.ParseAddr(ip4Str)
if err != nil {
return netip.Addr{}, false // badly formed, dont respond
return netip.Addr{}, false // badly formed, don't respond
}
prefix, err := strconv.ParseUint(siteID, 0, 32)
if err != nil {
return netip.Addr{}, false // badly formed, dont respond
return netip.Addr{}, false // badly formed, don't respond
}
// MapVia will never error when given an ipv4 netip.Prefix.

@ -350,6 +350,18 @@ func TestResolveLocal(t *testing.T) {
{"x_via_dec", dnsname.FQDN("1.0.0.10.via-1."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:1.0.0.10"), dns.RCodeSuccess},
{"via_invalid", dnsname.FQDN("via-."), dns.TypeAAAA, netip.Addr{}, dns.RCodeRefused},
{"via_invalid_2", dnsname.FQDN("2.3.4.5.via-."), dns.TypeAAAA, netip.Addr{}, dns.RCodeRefused},
// Hyphenated 4via6 format.
// Without any suffix domain:
{"via_form3_hex_bare", dnsname.FQDN("1-2-3-4-via-0xff."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:ff:1.2.3.4"), dns.RCodeSuccess},
{"via_form3_dec_bare", dnsname.FQDN("1-2-3-4-via-1."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:1.2.3.4"), dns.RCodeSuccess},
// With a Tailscale domain:
{"via_form3_dec_ts.net", dnsname.FQDN("1-2-3-4-via-1.foo.ts.net."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:1.2.3.4"), dns.RCodeSuccess},
{"via_form3_dec_tailscale.net", dnsname.FQDN("1-2-3-4-via-1.foo.tailscale.net."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:1.2.3.4"), dns.RCodeSuccess},
// Non-Tailscale domain suffixes aren't allowed for now: (the allowed
// suffixes are currently hard-coded and not plumbed via the netmap)
{"via_form3_dec_example.com", dnsname.FQDN("1-2-3-4-via-1.example.com."), dns.TypeAAAA, netip.Addr{}, dns.RCodeRefused},
{"via_form3_dec_examplets.net", dnsname.FQDN("1-2-3-4-via-1.examplets.net."), dns.TypeAAAA, netip.Addr{}, dns.RCodeRefused},
}
for _, tt := range tests {

Loading…
Cancel
Save