mirror of
https://github.com/golang/go
synced 2024-11-26 04:37:59 -07:00
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 #57697 Fixes #64783 Change-Id: I203896aa2902c305569005c1712fd2f9f13a9b6b Reviewed-on: https://go-review.googlesource.com/c/go/+/550435 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Commit-Queue: Ian Lance Taylor <iant@golang.org> Auto-Submit: Ian Lance Taylor <iant@golang.org> Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Dexter Ouyang <kkhaike@gmail.com>
This commit is contained in:
parent
e5f4c68c44
commit
aaf8e844ed
@ -211,7 +211,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
|
|||||||
|
|
||||||
// checkHeader performs basic sanity checks on the header.
|
// checkHeader performs basic sanity checks on the header.
|
||||||
func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
|
func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
|
||||||
rcode := extractExtendedRCode(*p, h)
|
rcode, hasAdd := extractExtendedRCode(*p, h)
|
||||||
|
|
||||||
if rcode == dnsmessage.RCodeNameError {
|
if rcode == dnsmessage.RCodeNameError {
|
||||||
return errNoSuchHost
|
return errNoSuchHost
|
||||||
@ -224,7 +224,7 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
|
|||||||
|
|
||||||
// libresolv continues to the next server when it receives
|
// libresolv continues to the next server when it receives
|
||||||
// an invalid referral response. See golang.org/issue/15434.
|
// an invalid referral response. See golang.org/issue/15434.
|
||||||
if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
|
if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone && !hasAdd {
|
||||||
return errLameReferral
|
return errLameReferral
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,16 +263,19 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
|
|||||||
|
|
||||||
// extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0))
|
// 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.
|
// If an OPT record is not found, the RCode from the hdr is returned.
|
||||||
func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) dnsmessage.RCode {
|
// Another return value indicates whether an additional resource was found.
|
||||||
|
func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) (dnsmessage.RCode, bool) {
|
||||||
p.SkipAllAnswers()
|
p.SkipAllAnswers()
|
||||||
p.SkipAllAuthorities()
|
p.SkipAllAuthorities()
|
||||||
|
hasAdd := false
|
||||||
for {
|
for {
|
||||||
ahdr, err := p.AdditionalHeader()
|
ahdr, err := p.AdditionalHeader()
|
||||||
|
hasAdd = hasAdd || err != dnsmessage.ErrSectionDone
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hdr.RCode
|
return hdr.RCode, hasAdd
|
||||||
}
|
}
|
||||||
if ahdr.Type == dnsmessage.TypeOPT {
|
if ahdr.Type == dnsmessage.TypeOPT {
|
||||||
return ahdr.ExtendedRCode(hdr.RCode)
|
return ahdr.ExtendedRCode(hdr.RCode), hasAdd
|
||||||
}
|
}
|
||||||
p.SkipAdditional()
|
p.SkipAdditional()
|
||||||
}
|
}
|
||||||
|
@ -803,13 +803,25 @@ func TestIgnoreLameReferrals(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if s == "192.0.2.1:53" {
|
||||||
|
if q.Questions[0].Type == dnsmessage.TypeA && strings.HasPrefix(q.Questions[0].Name.String(), "empty.com.") {
|
||||||
|
var edns0Hdr dnsmessage.ResourceHeader
|
||||||
|
edns0Hdr.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false)
|
||||||
|
|
||||||
|
r.Additionals = []dnsmessage.Resource{
|
||||||
|
{
|
||||||
|
Header: edns0Hdr,
|
||||||
|
Body: &dnsmessage.OPTResource{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r, nil
|
return r, nil
|
||||||
}}
|
}}
|
||||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||||
|
|
||||||
addrs, err := r.LookupIPAddr(context.Background(), "www.golang.org")
|
addrs, err := r.LookupIP(context.Background(), "ip4", "www.golang.org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -821,6 +833,15 @@ func TestIgnoreLameReferrals(t *testing.T) {
|
|||||||
if got, want := addrs[0].String(), "192.0.2.1"; got != want {
|
if got, want := addrs[0].String(), "192.0.2.1"; got != want {
|
||||||
t.Fatalf("got address %v, want %v", got, want)
|
t.Fatalf("got address %v, want %v", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = r.LookupIP(context.Background(), "ip4", "empty.com")
|
||||||
|
de, ok := err.(*DNSError)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
|
||||||
|
}
|
||||||
|
if de.Err != errNoSuchHost.Error() {
|
||||||
|
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGoLookupIP(b *testing.B) {
|
func BenchmarkGoLookupIP(b *testing.B) {
|
||||||
|
Loading…
Reference in New Issue
Block a user