wgengine/tsdns: delegate bonjour service rdns requests

While we're here, parseQuery into a plain function.
This is helpful for fuzzing. (Which I did a bit of. Didn't find anything.)

And clean up a few minor things.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
pull/788/head
Josh Bleecher Snyder 4 years ago committed by Josh Bleecher Snyder
parent 2d0ed99672
commit 1fd10061fd

@ -299,7 +299,7 @@ type response struct {
}
// parseQuery parses the query in given packet into a response struct.
func (r *Resolver) parseQuery(query []byte, resp *response) error {
func parseQuery(query []byte, resp *response) error {
var parser dns.Parser
var err error
@ -423,6 +423,35 @@ const (
rdnsv6Suffix = ".ip6.arpa."
)
// hasRDNSBonjourPrefix reports whether name has a Bonjour Service Prefix..
//
// https://tools.ietf.org/html/rfc6763 lists
// "five special RR names" for Bonjour service discovery:
//
// b._dns-sd._udp.<domain>.
// db._dns-sd._udp.<domain>.
// r._dns-sd._udp.<domain>.
// dr._dns-sd._udp.<domain>.
// lb._dns-sd._udp.<domain>.
func hasRDNSBonjourPrefix(s string) bool {
// Even the shortest name containing a Bonjour prefix is long,
// so check length (cheap) and bail early if possible.
if len(s) < len("*._dns-sd._udp.0.0.0.0.in-addr.arpa.") {
return false
}
dot := strings.IndexByte(s, '.')
if dot == -1 {
return false // shouldn't happen
}
switch s[:dot] {
case "b", "db", "r", "dr", "lb":
default:
return false
}
return strings.HasPrefix(s[dot:], "._dns-sd._udp.")
}
// rawNameToLower converts a raw DNS name to a string, lowercasing it.
func rawNameToLower(name []byte) string {
var sb strings.Builder
@ -502,9 +531,12 @@ func rdnsNameToIPv6(name string) (ip netaddr.IP, ok bool) {
// respondReverse returns a DNS response to a PTR query.
// It is assumed that resp.Question is populated by respond before this is called.
func (r *Resolver) respondReverse(query []byte, name string, resp *response) ([]byte, error) {
if hasRDNSBonjourPrefix(name) {
return nil, errNotOurName
}
var ip netaddr.IP
var ok bool
var err error
switch {
case strings.HasSuffix(name, rdnsv4Suffix):
ip, ok = rdnsNameToIPv4(name)
@ -521,6 +553,7 @@ func (r *Resolver) respondReverse(query []byte, name string, resp *response) ([]
return nil, errNotOurName
}
var err error
resp.Name, resp.Header.RCode, err = r.ResolveReverse(ip)
if err != nil {
r.logf("resolving rdns: %v", ip, err)
@ -540,7 +573,7 @@ func (r *Resolver) respond(query []byte) ([]byte, error) {
// ParseQuery is sufficiently fast to run on every DNS packet.
// This is considerably simpler than extracting the name by hand
// to shave off microseconds in case of delegation.
err := r.parseQuery(query, resp)
err := parseQuery(query, resp)
// We will not return this error: it is the sender's fault.
if err != nil {
r.logf("parsing query: %v", err)
@ -551,7 +584,7 @@ func (r *Resolver) respond(query []byte) ([]byte, error) {
name := rawNameToLower(rawName)
// Always try to handle reverse lookups; delegate inside when not found.
// This way, queries for exitent nodes do not leak,
// This way, queries for existent nodes do not leak,
// but we behave gracefully if non-Tailscale nodes exist in CGNATRange.
if resp.Question.Type == dns.TypePTR {
return r.respondReverse(query, name, resp)

@ -684,6 +684,29 @@ func TestAllocs(t *testing.T) {
}
}
func TestTrimRDNSBonjourPrefix(t *testing.T) {
tests := []struct {
in string
want bool
}{
{"b._dns-sd._udp.0.10.20.172.in-addr.arpa.", true},
{"db._dns-sd._udp.0.10.20.172.in-addr.arpa.", true},
{"r._dns-sd._udp.0.10.20.172.in-addr.arpa.", true},
{"dr._dns-sd._udp.0.10.20.172.in-addr.arpa.", true},
{"lb._dns-sd._udp.0.10.20.172.in-addr.arpa.", true},
{"qq._dns-sd._udp.0.10.20.172.in-addr.arpa.", false},
{"0.10.20.172.in-addr.arpa.", false},
{"i-have-no-dot", false},
}
for _, test := range tests {
got := hasRDNSBonjourPrefix(test.in)
if got != test.want {
t.Errorf("trimRDNSBonjourPrefix(%q) = %v, want %v", test.in, got, test.want)
}
}
}
func BenchmarkFull(b *testing.B) {
dnsHandleFunc("test.site.", resolveToIP(testipv4, testipv6, "dns.test.site."))

Loading…
Cancel
Save