]> Cypherpunks repositories - gostls13.git/commitdiff
net: add GODEBUG=netedns0=0 to disable sending EDNS0 header
authorIan Lance Taylor <iant@golang.org>
Tue, 11 Jun 2024 16:36:49 +0000 (09:36 -0700)
committerGopher Robot <gobot@golang.org>
Wed, 12 Jun 2024 17:31:13 +0000 (17:31 +0000)
It reportedly breaks the DNS server on some modems.

For #6464
For #21160
For #44135
For #51127
For #51153
Fixes #67925

Change-Id: I54a11906159f00246d08a54cc8be7327e9ebfd2c
Reviewed-on: https://go-review.googlesource.com/c/go/+/591995
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
doc/godebug.md
doc/next/6-stdlib/99-minor/net/67925.md [new file with mode: 0644]
src/internal/godebugs/table.go
src/net/dnsclient_unix.go
src/net/dnsclient_unix_test.go
src/net/net.go
src/runtime/metrics/doc.go

index 071acf98cfbe8775468aaae67bdd41df688cdfb7..41f88caa013606062668c04059706658b22156e6 100644 (file)
@@ -327,6 +327,13 @@ Go 1.19 made it an error for path lookups to resolve to binaries in the current
 controlled by the [`execerrdot` setting](/pkg/os/exec#hdr-Executables_in_the_current_directory).
 There is no plan to remove this setting.
 
+Go 1.19 started sending EDNS0 additional headers on DNS requests.
+This can reportedly break the DNS server provided on some routers,
+such as CenturyLink Zyxel C3000Z.
+This can be changed by the [`netedns0` setting](/pkg/net#hdr-Name_Resolution).
+This setting is available in Go 1.21.12, Go 1.22.5, Go 1.23, and later.
+There is no plan to remove this setting.
+
 ### Go 1.18
 
 Go 1.18 removed support for SHA1 in most X.509 certificates,
diff --git a/doc/next/6-stdlib/99-minor/net/67925.md b/doc/next/6-stdlib/99-minor/net/67925.md
new file mode 100644 (file)
index 0000000..e43f0cd
--- /dev/null
@@ -0,0 +1,3 @@
+The new `GODEBUG` setting `netedns0=0` disables sending EDNS0
+additional headers on DNS requests, as they reportedly break the DNS
+server on some modems.
index df99334cb0830501b4b4e96b4fc8e0674ce2c9c7..b44fc7874f02a6ad46292bfe5eff058194cc11d9 100644 (file)
@@ -43,6 +43,7 @@ var All = []Info{
        {Name: "multipartmaxparts", Package: "mime/multipart"},
        {Name: "multipathtcp", Package: "net"},
        {Name: "netdns", Package: "net", Opaque: true},
+       {Name: "netedns0", Package: "net", Changed: 19, Old: "0"},
        {Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
        {Name: "randautoseed", Package: "math/rand"},
        {Name: "tarinsecurepath", Package: "archive/tar"},
index 8193189cc76f9dfffa56712b8cc4ab7dd3e87a51..54c7dc83bac6654844b4e5d5c03894b81a2bf652 100644 (file)
@@ -16,6 +16,7 @@ import (
        "context"
        "errors"
        "internal/bytealg"
+       "internal/godebug"
        "internal/itoa"
        "io"
        "os"
@@ -51,6 +52,9 @@ var (
        errServerTemporarilyMisbehaving = &temporaryError{"server misbehaving"}
 )
 
+// netedns0 controls whether we send an EDNS0 additional header.
+var netedns0 = godebug.New("netedns0")
+
 func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byte, err error) {
        id = uint16(randInt())
        b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true, AuthenticData: ad})
@@ -61,16 +65,20 @@ func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byt
                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
+       if netedns0.Value() == "0" {
+               netedns0.IncNonDefault()
+       } else {
+               // 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()
index a8874851335d83d888a87d40c5ee6d43d7bc6b7e..31677573c0b22a5d89eb5717c092600a6bc27494 100644 (file)
@@ -2382,19 +2382,34 @@ func testGoLookupIPCNAMEOrderHostsAliases(t *testing.T, mode hostLookupOrder, lo
 // This isn't a great test as it just tests the dnsmessage package
 // against itself.
 func TestDNSPacketSize(t *testing.T) {
+       t.Run("enabled", func(t *testing.T) {
+               testDNSPacketSize(t, false)
+       })
+       t.Run("disabled", func(t *testing.T) {
+               testDNSPacketSize(t, true)
+       })
+}
+
+func testDNSPacketSize(t *testing.T, disable bool) {
        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))
+                       if disable {
+                               if len(q.Additionals) > 0 {
+                                       t.Error("unexpected additional record")
+                               }
                        } 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)
+                               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)
+                                       }
                                }
                        }
 
@@ -2427,6 +2442,10 @@ func TestDNSPacketSize(t *testing.T) {
                },
        }
 
+       if disable {
+               t.Setenv("GODEBUG", "netedns0=0")
+       }
+
        r := &Resolver{PreferGo: true, Dial: fake.DialContext}
        if _, err := r.LookupIPAddr(context.Background(), "go.dev"); err != nil {
                t.Errorf("lookup failed: %v", err)
index 02687edbe6a8c648df1ed87896bc4378fc72895a..f8b5834acba56a9a8101be3ae35fde1843cc7ade 100644 (file)
@@ -74,6 +74,12 @@ to print debugging information about its decisions.
 To force a particular resolver while also printing debugging information,
 join the two settings by a plus sign, as in GODEBUG=netdns=go+1.
 
+The Go resolver will send an EDNS0 additional header with a DNS request,
+to signal a willingness to accept a larger DNS packet size.
+This can reportedly cause sporadic failures with the DNS server run
+by some modems and routers. Setting GODEBUG=netedns0=0 will disable
+sending the additional header.
+
 On macOS, if Go code that uses the net package is built with
 -buildmode=c-archive, linking the resulting archive into a C program
 requires passing -lresolv when linking the C code.
index c89e1769863b0d2e90a6c6d4b2688f3820622d3b..85db5742d9defc7a94a3c314e111f582fd1a8ce0 100644 (file)
@@ -285,6 +285,10 @@ Below is the full list of supported metrics, ordered lexicographically.
                The number of non-default behaviors executed by the net package
                due to a non-default GODEBUG=multipathtcp=... setting.
 
+       /godebug/non-default-behavior/netedns0:events
+               The number of non-default behaviors executed by the net package
+               due to a non-default GODEBUG=netedns0=... setting.
+
        /godebug/non-default-behavior/panicnil:events
                The number of non-default behaviors executed by the runtime
                package due to a non-default GODEBUG=panicnil=... setting.