Skip to content

Commit ee4a42b

Browse files
ianlancetaylorgopherbot
authored andcommitted
net: add GODEBUG=netedns0=0 to disable sending EDNS0 header
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>
1 parent b589478 commit ee4a42b

File tree

7 files changed

+68
-20
lines changed

7 files changed

+68
-20
lines changed

doc/godebug.md

+7
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,13 @@ Go 1.19 made it an error for path lookups to resolve to binaries in the current
327327
controlled by the [`execerrdot` setting](/pkg/os/exec#hdr-Executables_in_the_current_directory).
328328
There is no plan to remove this setting.
329329

330+
Go 1.19 started sending EDNS0 additional headers on DNS requests.
331+
This can reportedly break the DNS server provided on some routers,
332+
such as CenturyLink Zyxel C3000Z.
333+
This can be changed by the [`netedns0` setting](/pkg/net#hdr-Name_Resolution).
334+
This setting is available in Go 1.21.12, Go 1.22.5, Go 1.23, and later.
335+
There is no plan to remove this setting.
336+
330337
### Go 1.18
331338

332339
Go 1.18 removed support for SHA1 in most X.509 certificates,
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The new `GODEBUG` setting `netedns0=0` disables sending EDNS0
2+
additional headers on DNS requests, as they reportedly break the DNS
3+
server on some modems.

src/internal/godebugs/table.go

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ var All = []Info{
4343
{Name: "multipartmaxparts", Package: "mime/multipart"},
4444
{Name: "multipathtcp", Package: "net"},
4545
{Name: "netdns", Package: "net", Opaque: true},
46+
{Name: "netedns0", Package: "net", Changed: 19, Old: "0"},
4647
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
4748
{Name: "randautoseed", Package: "math/rand"},
4849
{Name: "tarinsecurepath", Package: "archive/tar"},

src/net/dnsclient_unix.go

+18-10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"context"
1717
"errors"
1818
"internal/bytealg"
19+
"internal/godebug"
1920
"internal/itoa"
2021
"io"
2122
"os"
@@ -51,6 +52,9 @@ var (
5152
errServerTemporarilyMisbehaving = &temporaryError{"server misbehaving"}
5253
)
5354

55+
// netedns0 controls whether we send an EDNS0 additional header.
56+
var netedns0 = godebug.New("netedns0")
57+
5458
func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byte, err error) {
5559
id = uint16(randInt())
5660
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
6165
return 0, nil, nil, err
6266
}
6367

64-
// Accept packets up to maxDNSPacketSize. RFC 6891.
65-
if err := b.StartAdditionals(); err != nil {
66-
return 0, nil, nil, err
67-
}
68-
var rh dnsmessage.ResourceHeader
69-
if err := rh.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false); err != nil {
70-
return 0, nil, nil, err
71-
}
72-
if err := b.OPTResource(rh, dnsmessage.OPTResource{}); err != nil {
73-
return 0, nil, nil, err
68+
if netedns0.Value() == "0" {
69+
netedns0.IncNonDefault()
70+
} else {
71+
// Accept packets up to maxDNSPacketSize. RFC 6891.
72+
if err := b.StartAdditionals(); err != nil {
73+
return 0, nil, nil, err
74+
}
75+
var rh dnsmessage.ResourceHeader
76+
if err := rh.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false); err != nil {
77+
return 0, nil, nil, err
78+
}
79+
if err := b.OPTResource(rh, dnsmessage.OPTResource{}); err != nil {
80+
return 0, nil, nil, err
81+
}
7482
}
7583

7684
tcpReq, err = b.Finish()

src/net/dnsclient_unix_test.go

+29-10
Original file line numberDiff line numberDiff line change
@@ -2382,19 +2382,34 @@ func testGoLookupIPCNAMEOrderHostsAliases(t *testing.T, mode hostLookupOrder, lo
23822382
// This isn't a great test as it just tests the dnsmessage package
23832383
// against itself.
23842384
func TestDNSPacketSize(t *testing.T) {
2385+
t.Run("enabled", func(t *testing.T) {
2386+
testDNSPacketSize(t, false)
2387+
})
2388+
t.Run("disabled", func(t *testing.T) {
2389+
testDNSPacketSize(t, true)
2390+
})
2391+
}
2392+
2393+
func testDNSPacketSize(t *testing.T, disable bool) {
23852394
fake := fakeDNSServer{
23862395
rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2387-
if len(q.Additionals) == 0 {
2388-
t.Error("missing EDNS record")
2389-
} else if opt, ok := q.Additionals[0].Body.(*dnsmessage.OPTResource); !ok {
2390-
t.Errorf("additional record type %T, expected OPTResource", q.Additionals[0])
2391-
} else if len(opt.Options) != 0 {
2392-
t.Errorf("found %d Options, expected none", len(opt.Options))
2396+
if disable {
2397+
if len(q.Additionals) > 0 {
2398+
t.Error("unexpected additional record")
2399+
}
23932400
} else {
2394-
got := int(q.Additionals[0].Header.Class)
2395-
t.Logf("EDNS packet size == %d", got)
2396-
if got != maxDNSPacketSize {
2397-
t.Errorf("EDNS packet size == %d, want %d", got, maxDNSPacketSize)
2401+
if len(q.Additionals) == 0 {
2402+
t.Error("missing EDNS record")
2403+
} else if opt, ok := q.Additionals[0].Body.(*dnsmessage.OPTResource); !ok {
2404+
t.Errorf("additional record type %T, expected OPTResource", q.Additionals[0])
2405+
} else if len(opt.Options) != 0 {
2406+
t.Errorf("found %d Options, expected none", len(opt.Options))
2407+
} else {
2408+
got := int(q.Additionals[0].Header.Class)
2409+
t.Logf("EDNS packet size == %d", got)
2410+
if got != maxDNSPacketSize {
2411+
t.Errorf("EDNS packet size == %d, want %d", got, maxDNSPacketSize)
2412+
}
23982413
}
23992414
}
24002415

@@ -2427,6 +2442,10 @@ func TestDNSPacketSize(t *testing.T) {
24272442
},
24282443
}
24292444

2445+
if disable {
2446+
t.Setenv("GODEBUG", "netedns0=0")
2447+
}
2448+
24302449
r := &Resolver{PreferGo: true, Dial: fake.DialContext}
24312450
if _, err := r.LookupIPAddr(context.Background(), "go.dev"); err != nil {
24322451
t.Errorf("lookup failed: %v", err)

src/net/net.go

+6
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ to print debugging information about its decisions.
7474
To force a particular resolver while also printing debugging information,
7575
join the two settings by a plus sign, as in GODEBUG=netdns=go+1.
7676
77+
The Go resolver will send an EDNS0 additional header with a DNS request,
78+
to signal a willingness to accept a larger DNS packet size.
79+
This can reportedly cause sporadic failures with the DNS server run
80+
by some modems and routers. Setting GODEBUG=netedns0=0 will disable
81+
sending the additional header.
82+
7783
On macOS, if Go code that uses the net package is built with
7884
-buildmode=c-archive, linking the resulting archive into a C program
7985
requires passing -lresolv when linking the C code.

src/runtime/metrics/doc.go

+4
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ Below is the full list of supported metrics, ordered lexicographically.
285285
The number of non-default behaviors executed by the net package
286286
due to a non-default GODEBUG=multipathtcp=... setting.
287287
288+
/godebug/non-default-behavior/netedns0:events
289+
The number of non-default behaviors executed by the net package
290+
due to a non-default GODEBUG=netedns0=... setting.
291+
288292
/godebug/non-default-behavior/panicnil:events
289293
The number of non-default behaviors executed by the runtime
290294
package due to a non-default GODEBUG=panicnil=... setting.

0 commit comments

Comments
 (0)