Skip to content

Commit aaf8e84

Browse files
kkHAIKEgopherbot
authored andcommitted
net: prevent unintended retries upon receiving an empty answer response from the DNS server.
CL https://golang.org/cl/37879 migrates DNS message parsing to the golang.org/x/net/dns/dnsmessage package. However, during the modification of the "lame referral" error check introduced by CL https://golang.org/cl/22428, a condition was overlooked. This omission results in unexpected retries when a DNS server returns an empty response (not an invalid response, but one that includes an additional section). Fixes golang#57697 Fixes golang#64783 Change-Id: I203896aa2902c305569005c1712fd2f9f13a9b6b Reviewed-on: https://go-review.googlesource.com/c/go/+/550435 LUCI-TryBot-Result: Go LUCI <[email protected]> Commit-Queue: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Reviewed-by: Dexter Ouyang <[email protected]>
1 parent e5f4c68 commit aaf8e84

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

src/net/dnsclient_unix.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
211211

212212
// checkHeader performs basic sanity checks on the header.
213213
func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
214-
rcode := extractExtendedRCode(*p, h)
214+
rcode, hasAdd := extractExtendedRCode(*p, h)
215215

216216
if rcode == dnsmessage.RCodeNameError {
217217
return errNoSuchHost
@@ -224,7 +224,7 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
224224

225225
// libresolv continues to the next server when it receives
226226
// an invalid referral response. See golang.org/issue/15434.
227-
if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
227+
if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone && !hasAdd {
228228
return errLameReferral
229229
}
230230

@@ -263,16 +263,19 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
263263

264264
// extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0))
265265
// If an OPT record is not found, the RCode from the hdr is returned.
266-
func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) dnsmessage.RCode {
266+
// Another return value indicates whether an additional resource was found.
267+
func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) (dnsmessage.RCode, bool) {
267268
p.SkipAllAnswers()
268269
p.SkipAllAuthorities()
270+
hasAdd := false
269271
for {
270272
ahdr, err := p.AdditionalHeader()
273+
hasAdd = hasAdd || err != dnsmessage.ErrSectionDone
271274
if err != nil {
272-
return hdr.RCode
275+
return hdr.RCode, hasAdd
273276
}
274277
if ahdr.Type == dnsmessage.TypeOPT {
275-
return ahdr.ExtendedRCode(hdr.RCode)
278+
return ahdr.ExtendedRCode(hdr.RCode), hasAdd
276279
}
277280
p.SkipAdditional()
278281
}

src/net/dnsclient_unix_test.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,13 +803,25 @@ func TestIgnoreLameReferrals(t *testing.T) {
803803
},
804804
}
805805
}
806+
} else if s == "192.0.2.1:53" {
807+
if q.Questions[0].Type == dnsmessage.TypeA && strings.HasPrefix(q.Questions[0].Name.String(), "empty.com.") {
808+
var edns0Hdr dnsmessage.ResourceHeader
809+
edns0Hdr.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false)
810+
811+
r.Additionals = []dnsmessage.Resource{
812+
{
813+
Header: edns0Hdr,
814+
Body: &dnsmessage.OPTResource{},
815+
},
816+
}
817+
}
806818
}
807819

808820
return r, nil
809821
}}
810822
r := Resolver{PreferGo: true, Dial: fake.DialContext}
811823

812-
addrs, err := r.LookupIPAddr(context.Background(), "www.golang.org")
824+
addrs, err := r.LookupIP(context.Background(), "ip4", "www.golang.org")
813825
if err != nil {
814826
t.Fatal(err)
815827
}
@@ -821,6 +833,15 @@ func TestIgnoreLameReferrals(t *testing.T) {
821833
if got, want := addrs[0].String(), "192.0.2.1"; got != want {
822834
t.Fatalf("got address %v, want %v", got, want)
823835
}
836+
837+
_, err = r.LookupIP(context.Background(), "ip4", "empty.com")
838+
de, ok := err.(*DNSError)
839+
if !ok {
840+
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
841+
}
842+
if de.Err != errNoSuchHost.Error() {
843+
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
844+
}
824845
}
825846

826847
func BenchmarkGoLookupIP(b *testing.B) {

0 commit comments

Comments
 (0)