aboutsummaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorMateusz Poliwczak <mpoliwczak34@gmail.com>2023-08-01 18:02:54 +0000
committerGopher Robot <gobot@golang.org>2023-08-03 15:55:37 +0000
commit865760373194e358fefa4d1e45ebdf2141b77b59 (patch)
treeea13a2b9c52d55b57efc8f573d6953234691ebd8 /src/net
parent3ca90ed8669fc467ca7627f0e690040971233d8b (diff)
downloadgo-865760373194e358fefa4d1e45ebdf2141b77b59.tar.xz
net: use the extended RCode from EDNS(0) OPT resources
For a while now we support EDNS, but the current implementation only sends the OPT resource and doesn't do anything with the response OPT resource. For reference the miekg/dns updates the RCode in the header when there is a OPT resource: https://github.com/miekg/dns/blob/48f38ebef989eedc6b57f1869ae849ccc8f5fe29/msg.go#L868-L872 Change-Id: I0a7146aed3e50654f340a3925f48612561cb85f4 GitHub-Last-Rev: adc304167e0540cb1f066f07a249d67fad89182e GitHub-Pull-Request: golang/go#61695 Reviewed-on: https://go-review.googlesource.com/c/go/+/514835 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
Diffstat (limited to 'src/net')
-rw-r--r--src/net/dnsclient_unix.go27
-rw-r--r--src/net/dnsclient_unix_test.go31
2 files changed, 54 insertions, 4 deletions
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index dab5144e5d..ed32ba0280 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -205,7 +205,9 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
// checkHeader performs basic sanity checks on the header.
func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
- if h.RCode == dnsmessage.RCodeNameError {
+ rcode := extractExtendedRCode(*p, h)
+
+ if rcode == dnsmessage.RCodeNameError {
return errNoSuchHost
}
@@ -216,17 +218,17 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
// libresolv continues to the next server when it receives
// an invalid referral response. See golang.org/issue/15434.
- if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
+ if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
return errLameReferral
}
- if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError {
+ if rcode != dnsmessage.RCodeSuccess && rcode != dnsmessage.RCodeNameError {
// None of the error codes make sense
// for the query we sent. If we didn't get
// a name error and we didn't get success,
// the server is behaving incorrectly or
// having temporary trouble.
- if h.RCode == dnsmessage.RCodeServerFailure {
+ if rcode == dnsmessage.RCodeServerFailure {
return errServerTemporarilyMisbehaving
}
return errServerMisbehaving
@@ -253,6 +255,23 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
}
}
+// extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0))
+// If an OPT record is not found, the RCode from the hdr is returned.
+func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) dnsmessage.RCode {
+ p.SkipAllAnswers()
+ p.SkipAllAuthorities()
+ for {
+ ahdr, err := p.AdditionalHeader()
+ if err != nil {
+ return hdr.RCode
+ }
+ if ahdr.Type == dnsmessage.TypeOPT {
+ return ahdr.ExtendedRCode(hdr.RCode)
+ }
+ p.SkipAdditional()
+ }
+}
+
// Do a lookup for a single name, which must be rooted
// (otherwise answer will not find the answers).
func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 8d435a557f..9ae68f9a99 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -2598,3 +2598,34 @@ func TestLookupOrderFilesNoSuchHost(t *testing.T) {
}
}
}
+
+func TestExtendedRCode(t *testing.T) {
+ fake := fakeDNSServer{
+ rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
+ fraudSuccessCode := dnsmessage.RCodeSuccess | 1<<10
+
+ var edns0Hdr dnsmessage.ResourceHeader
+ edns0Hdr.SetEDNS0(maxDNSPacketSize, fraudSuccessCode, false)
+
+ return dnsmessage.Message{
+ Header: dnsmessage.Header{
+ ID: q.Header.ID,
+ Response: true,
+ RCode: fraudSuccessCode,
+ },
+ Questions: []dnsmessage.Question{q.Questions[0]},
+ Additionals: []dnsmessage.Resource{{
+ Header: edns0Hdr,
+ Body: &dnsmessage.OPTResource{},
+ }},
+ }, nil
+ },
+ }
+
+ r := &Resolver{PreferGo: true, Dial: fake.DialContext}
+ _, _, err := r.tryOneName(context.Background(), getSystemDNSConfig(), "go.dev.", dnsmessage.TypeA)
+ var dnsErr *DNSError
+ if !(errors.As(err, &dnsErr) && dnsErr.Err == errServerMisbehaving.Error()) {
+ t.Fatalf("r.tryOneName(): unexpected error: %v", err)
+ }
+}