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
pull/8166/head
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) 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 // nodeLookup is used to handle a node query
func (d *DNSServer) nodeLookup(cfg *dnsConfig, network, datacenter, node string, req, resp *dns.Msg, maxRecursionLevel int) { 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 // 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) out, err := d.lookupNode(cfg, args)
if err != nil { if err != nil {
d.logger.Error("rpc error", "error", err) 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 return
} }
@ -1203,7 +1219,11 @@ func (d *DNSServer) serviceLookup(cfg *dnsConfig, lookup serviceLookup, req, res
out, err := d.lookupServiceNodes(cfg, lookup) out, err := d.lookupServiceNodes(cfg, lookup)
if err != nil { if err != nil {
d.logger.Error("rpc error", "error", err) 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 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, // 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 // not a full on server error. We have to use a string compare
// here since the RPC layer loses the type information. // here since the RPC layer loses the type information.
if err != nil && err.Error() == consul.ErrQueryNotFound.Error() { if err != nil {
d.addSOA(cfg, resp) rCode := d.computeRCode(err)
resp.SetRcode(req, dns.RcodeNameError) if rCode == dns.RcodeNameError {
return d.addSOA(cfg, resp)
} else if err != nil { }
resp.SetRcode(req, dns.RcodeServerFailure) resp.SetRcode(req, rCode)
return 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) { func TestDNS_NonExistingLookup(t *testing.T) {
t.Parallel() t.Parallel()
a := NewTestAgent(t, "") a := NewTestAgent(t, "")