Returns DNS Error NSDOMAIN when DC does not exists (#8103)

This will allow to increase cache value when DC is not valid (aka
return SOA to avoid too many consecutive requests) and will
distinguish DC being temporarily not available from DC not existing.

Implements https://github.com/hashicorp/consul/issues/8102
This commit is contained in:
Pierre Souchay 2020-06-22 15:01:48 +02:00 committed by GitHub
parent 22239b8f6d
commit 35d852fd9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 8 deletions

View File

@ -819,6 +819,18 @@ func (d *DNSServer) trimDomain(query string) string {
return strings.TrimSuffix(query, shorter)
}
// computeRCode Return the DNS Error code from Consul Error
func (d *DNSServer) computeRCode(err error) int {
if err == nil {
return dns.RcodeSuccess
}
dErr := err.Error()
if dErr == structs.ErrNoDCPath.Error() || dErr == consul.ErrQueryNotFound.Error() {
return dns.RcodeNameError
}
return dns.RcodeServerFailure
}
// nodeLookup is used to handle a node query
func (d *DNSServer) nodeLookup(cfg *dnsConfig, network, datacenter, node string, req, resp *dns.Msg, maxRecursionLevel int) {
// Only handle ANY, A, AAAA, and TXT type requests
@ -839,7 +851,11 @@ func (d *DNSServer) nodeLookup(cfg *dnsConfig, network, datacenter, node string,
out, err := d.lookupNode(cfg, args)
if err != nil {
d.logger.Error("rpc error", "error", err)
resp.SetRcode(req, dns.RcodeServerFailure)
rCode := d.computeRCode(err)
if rCode == dns.RcodeNameError {
d.addSOA(cfg, resp)
}
resp.SetRcode(req, rCode)
return
}
@ -1203,7 +1219,11 @@ func (d *DNSServer) serviceLookup(cfg *dnsConfig, lookup serviceLookup, req, res
out, err := d.lookupServiceNodes(cfg, lookup)
if err != nil {
d.logger.Error("rpc error", "error", err)
resp.SetRcode(req, dns.RcodeServerFailure)
rCode := d.computeRCode(err)
if rCode == dns.RcodeNameError {
d.addSOA(cfg, resp)
}
resp.SetRcode(req, rCode)
return
}
@ -1297,12 +1317,12 @@ func (d *DNSServer) preparedQueryLookup(cfg *dnsConfig, network, datacenter, que
// If they give a bogus query name, treat that as a name error,
// not a full on server error. We have to use a string compare
// here since the RPC layer loses the type information.
if err != nil && err.Error() == consul.ErrQueryNotFound.Error() {
if err != nil {
rCode := d.computeRCode(err)
if rCode == dns.RcodeNameError {
d.addSOA(cfg, resp)
resp.SetRcode(req, dns.RcodeNameError)
return
} else if err != nil {
resp.SetRcode(req, dns.RcodeServerFailure)
}
resp.SetRcode(req, rCode)
return
}

View File

@ -5790,6 +5790,27 @@ func TestDNS_AddressLookupIPV6(t *testing.T) {
}
}
func TestDNS_NonExistingDC(t *testing.T) {
t.Parallel()
a := NewTestAgent(t, "")
defer a.Shutdown()
testrpc.WaitForLeader(t, a.RPC, "dc1")
// lookup a non-existing node, we should receive a SOA
m := new(dns.Msg)
m.SetQuestion("consul.dc2.consul.", dns.TypeANY)
c := new(dns.Client)
in, _, err := c.Exchange(m, a.DNSAddr())
if err != nil {
t.Fatalf("err: %v", err)
}
if in.Rcode != dns.RcodeNameError {
t.Fatalf("Expected RCode: %#v, had: %#v", dns.RcodeNameError, in.Rcode)
}
}
func TestDNS_NonExistingLookup(t *testing.T) {
t.Parallel()
a := NewTestAgent(t, "")