The subtleties between the NXDOMAIN, NOERROR and NODATA DNS response codes

This past weekend I spent some time troubleshooting a DNS timeout issue. During my debugging session I noticed some subtle differences when querying an A and AAAA record with dig:

$ dig  +answer @216.92.61.30 prefetch.net a
.......
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9624
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1

$ dig  +answer @216.92.61.30 prefetch.net aaaa
.......
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16528
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

When I was interpreting the results I was expecting dig to provide a response code of NODATA when I asked the DNS server for a resource record that didn’t exist. Obviously that didn’t happen. This led me to ask myself what is the technical difference between NODATA, NOERROR and NXDOMAIN? Let’s take a peak at the descriptions of each in RFC 1035:

RCODE           Response code - this 4 bit field is set as part of
                responses.  The values have the following
                interpretation:

                0               No error condition

                1               Format error - The name server was
                                unable to interpret the query.

                2               Server failure - The name server was
                                unable to process this query due to a
                                problem with the name server.

                3               Name Error - Meaningful only for
                                responses from an authoritative name
                                server, this code signifies that the
                                domain name referenced in the query does
                                not exist.

NXDOMAIN (RCODE 3 above) is pretty straight forward. When this code is present the record being requested doesn’t exist in any shape or form:

$ dig +answer @216.92.61.30 gak.prefetch.net a

;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 8782
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

Now what about NODATA and NOERROR? Well I found out there isn’t an RCODE associated with NODATA. This value is computed based on the answers to one or more questions and dig represents NODATA by displaying NOERROR with an ANSWER of zero. So what does NOERROR with an ANSWER of 0 actually represent? It means one or more resource records exist for this domain but there isn’t a record matching the resource record type (A, AAAA, MX, etc.). This was a useful clarification for me and helped me isolate and fix the issue I was debugging. Sometimes the devil is in the details.