diff --git a/agent/dns.go b/agent/dns.go index 314ffdef0325..952e66ad1d96 100644 --- a/agent/dns.go +++ b/agent/dns.go @@ -818,6 +818,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 @@ -838,7 +850,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 } @@ -1202,7 +1218,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 } @@ -1296,12 +1316,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() { - d.addSOA(cfg, resp) - resp.SetRcode(req, dns.RcodeNameError) - return - } else if err != nil { - resp.SetRcode(req, dns.RcodeServerFailure) + if err != nil { + rCode := d.computeRCode(err) + if rCode == dns.RcodeNameError { + d.addSOA(cfg, resp) + } + resp.SetRcode(req, rCode) return } diff --git a/agent/dns_test.go b/agent/dns_test.go index fb0f1a8cc3b7..984621e8a688 100644 --- a/agent/dns_test.go +++ b/agent/dns_test.go @@ -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, "")