From: Ian Lance Taylor Date: Fri, 11 Feb 2022 04:09:07 +0000 (-0800) Subject: net: send EDNS(0) packet length in DNS query X-Git-Tag: go1.18rc1~32 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=f14ad78e844d7dff286421754c462886336b1eb6;p=gostls13.git net: send EDNS(0) packet length in DNS query We used to only accept up to 512 bytes in a DNS packet, per RFC 1035. Increase the size we accept to 1232 bytes, per https://dnsflagday.net/2020/, and advertise that larger limit in a EDNS(0) OPT record. Fixes #6464 Fixes #21160 Fixes #44135 Fixes #51127 Change-Id: I496a294e9a8015de4161cbc1825b0dc5b4e9f5d8 Reviewed-on: https://go-review.googlesource.com/c/go/+/385035 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gopher Robot Reviewed-by: Matthew Dempsky --- diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index 21aa91f665..fae78ae1b1 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -30,6 +30,10 @@ const ( // to be used as a useTCP parameter to exchange useTCPOnly = true useUDPOrTCP = false + + // Requested DNS packet size. + // Value taken from https://dnsflagday.net/2020/. + maxDNSPacketSize = 1232 ) var ( @@ -56,6 +60,19 @@ func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err er if err := b.Question(q); err != nil { return 0, nil, nil, err } + + // Accept packets up to maxDNSPacketSize. RFC 6891. + if err := b.StartAdditionals(); err != nil { + return 0, nil, nil, err + } + var rh dnsmessage.ResourceHeader + if err := rh.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false); err != nil { + return 0, nil, nil, err + } + if err := b.OPTResource(rh, dnsmessage.OPTResource{}); err != nil { + return 0, nil, nil, err + } + tcpReq, err = b.Finish() udpReq = tcpReq[2:] l := len(tcpReq) - 2 @@ -82,7 +99,7 @@ func dnsPacketRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) return dnsmessage.Parser{}, dnsmessage.Header{}, err } - b = make([]byte, 512) // see RFC 1035 + b = make([]byte, maxDNSPacketSize) for { n, err := c.Read(b) if err != nil { diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 14366eca8c..e5f01dba2a 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -881,7 +881,7 @@ func (f *fakeDNSPacketConn) Close() error { func TestIgnoreDNSForgeries(t *testing.T) { c, s := Pipe() go func() { - b := make([]byte, 512) + b := make([]byte, maxDNSPacketSize) n, err := s.Read(b) if err != nil { t.Error(err) @@ -2161,3 +2161,58 @@ func TestRootNS(t *testing.T) { t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0]) } } + +// Test that we advertise support for a larger DNS packet size. +// This isn't a great test as it just tests the dnsmessage package +// against itself. +func TestDNSPacketSize(t *testing.T) { + fake := fakeDNSServer{ + rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + if len(q.Additionals) == 0 { + t.Error("missing EDNS record") + } else if opt, ok := q.Additionals[0].Body.(*dnsmessage.OPTResource); !ok { + t.Errorf("additional record type %T, expected OPTResource", q.Additionals[0]) + } else if len(opt.Options) != 0 { + t.Errorf("found %d Options, expected none", len(opt.Options)) + } else { + got := int(q.Additionals[0].Header.Class) + t.Logf("EDNS packet size == %d", got) + if got != maxDNSPacketSize { + t.Errorf("EDNS packet size == %d, want %d", got, maxDNSPacketSize) + } + } + + // Hand back a dummy answer to verify that + // LookupIPAddr completes. + r := dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.Header.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + }, + Questions: q.Questions, + } + if q.Questions[0].Type == dnsmessage.TypeA { + r.Answers = []dnsmessage.Resource{ + { + Header: dnsmessage.ResourceHeader{ + Name: q.Questions[0].Name, + Type: dnsmessage.TypeA, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.AResource{ + A: TestAddr, + }, + }, + } + } + return r, nil + }, + } + + r := &Resolver{PreferGo: true, Dial: fake.DialContext} + if _, err := r.LookupIPAddr(context.Background(), "go.dev"); err != nil { + t.Errorf("lookup failed: %v", err) + } +}