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>
This commit is contained in:
Ian Lance Taylor 2024-06-11 09:36:49 -07:00 committed by Gopher Robot
parent b589478af7
commit ee4a42bd58
7 changed files with 68 additions and 20 deletions

View 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,

View File

@ -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.

View 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"},

View 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,6 +65,9 @@ func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byt
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
@ -72,6 +79,7 @@ func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byt
if err := b.OPTResource(rh, dnsmessage.OPTResource{}); err != nil {
return 0, nil, nil, err
}
}
tcpReq, err = b.Finish()
if err != nil {

View File

@ -2382,8 +2382,22 @@ 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 disable {
if len(q.Additionals) > 0 {
t.Error("unexpected additional record")
}
} else {
if len(q.Additionals) == 0 {
t.Error("missing EDNS record")
} else if opt, ok := q.Additionals[0].Body.(*dnsmessage.OPTResource); !ok {
@ -2397,6 +2411,7 @@ func TestDNSPacketSize(t *testing.T) {
t.Errorf("EDNS packet size == %d, want %d", got, maxDNSPacketSize)
}
}
}
// Hand back a dummy answer to verify that
// LookupIPAddr completes.
@ -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)

View 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.

View 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.