net/dns/resolver: clamp EDNS size

This change (subject to some limitations) looks for the EDNS OPT record
in queries and responses, clamping the size field to fit within our DNS
receive buffer. If the size field is smaller than the DNS receive buffer
then it is left unchanged.

I think we will eventually need to transition to fully processing the
DNS queries to handle all situations, but this should cover the most
common case.

Mostly fixes #2066

Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
This commit is contained in:
Adrian Dewhurst
2021-06-24 10:36:23 -04:00
committed by Adrian Dewhurst
parent c69d30cdd7
commit bcaae3e074
3 changed files with 288 additions and 82 deletions

View File

@@ -68,7 +68,7 @@ func resolveToIP(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc {
// resolveToTXT returns a handler function which responds to queries of type TXT
// it receives with the strings in txts.
func resolveToTXT(txts []string) dns.HandlerFunc {
func resolveToTXT(txts []string, ednsMaxSize uint16) dns.HandlerFunc {
return func(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg)
m.SetReply(req)
@@ -93,6 +93,27 @@ func resolveToTXT(txts []string) dns.HandlerFunc {
}
m.Answer = append(m.Answer, ans)
queryInfo := &dns.TXT{
Hdr: dns.RR_Header{
Name: "query-info.test.",
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
},
}
if edns := req.IsEdns0(); edns == nil {
queryInfo.Txt = []string{"EDNS=false"}
} else {
queryInfo.Txt = []string{"EDNS=true", fmt.Sprintf("maxSize=%v", edns.UDPSize())}
}
m.Extra = append(m.Extra, queryInfo)
if ednsMaxSize > 0 {
m.SetEdns0(ednsMaxSize, false)
}
if err := w.WriteMsg(m); err != nil {
panic(err)
}