]> Cypherpunks repositories - gostls13.git/commitdiff
net: send EDNS(0) packet length in DNS query
authorIan Lance Taylor <iant@golang.org>
Fri, 11 Feb 2022 04:09:07 +0000 (20:09 -0800)
committerIan Lance Taylor <iant@golang.org>
Sat, 12 Feb 2022 05:44:16 +0000 (05:44 +0000)
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 <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/net/dnsclient_unix.go
src/net/dnsclient_unix_test.go

index 21aa91f665ad3d481bd3dd22672fd1903b0e0096..fae78ae1b19f9f191fbfb820328d528a322149cc 100644 (file)
@@ -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 {
index 14366eca8c63b100eb05c6a5cfefa12cc5f66c76..e5f01dba2adf02f342447de1c2f171e2263bb019 100644 (file)
@@ -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)
+       }
+}