Response (or Status) Codes in DNS
CompletedWhen you make a DNS query, the DNS server you ask returns a "response code", also referred to as "status code", which tells whether the query succeeded, and if not, something about why it failed. There are several of these codes; the original list is found in RFC1035, one of the original documents defining the DNS system. There have been some additions, but they mostly relate to dynamic DNS updates, which UltraDNS doesn't support. (UltraDNS is intended for external DNS, which generally doesn't use dynamic updates...) If you're interested in more, here's a link to RFC1035: https://datatracker.ietf.org/doc/html/rfc1035
In section 4.1.1, it defines the "RCODE" (or Response CODE) field, which is commonly referred to as the status code. The codes it defines are:
- code 0: no errors, usually referred to as NOERR
- code 1: Format Error, usually referred to as FORMERR
- code 2: Server Failure, usually referred to as SERVFAIL
- code 3: Name Error, usually referred to as NXDOMAIN
- code 4: Not implemented, usually referred to as NOTIMP
- code 5: Refused
I'm going to describe these codes, then, toward the bottom of this note, I'll give examples of how to produce each, and what each returns.
Ideally you would only see code 0, or NOERROR. NOERROR means that the server found some information about the qname (Query NAME, which means "the name of the record which was requested.") Responses with NOERROR status will typically return 1 or more answers, which are the "rdata" for the requested record(s). If there are records for the qname, but they don't include the requested record type, you would get a NOERROR status code, but the number of answers would be set to zero.
FORMERR is a status code you don't want to see; it means that the DNS request didn't make sense to the server, so it had to give up. As an example, when DNS was extended by adding the EDNS0 extended options, older servers which didn't understand the EDNS0 options would return FORMERR. (At that point, the DNS client could resend the request without asking for the extended options and would normally receive a good answer.)
SERVFAIL means that the server was unable to return a valid answer. Currently, the most common reason for this to happen is probably a DNSSEC issue. DNSSEC is a mechanism to allow verifying that DNS responses come from a valid server, and that the data in the response are correct. If a recursive server that tries to use DNSSEC to validate the response gets an answer with a missing or invalid DNSSEC signature the recursive server will return SERVFAIL, indicating that it was unable to return a valid response.
"Name Error" is usually referred to as "NXDOMAIN". It is a response that means "there are no records with the qname you requested". This is different from the "NOERROR / NOANSWER" mentioned earlier; that indicates that there are records for the qname, but they aren't of the requested type. NXDOMAIN indicates "there are no records of any type with that name". I'll give examples of both sorts of responses below.
REFUSED means "The server refuses to answer that request." Common reasons you might see that are the request was directed to a server which doesn't know about the zone that should contain records for the qname, or simply that there is an ACL which prevents responding to this particular request.
I'll give examples of queries and responses to illustrate these status codes. I'll use "dig", which is probably the best way to make DNS requests and see the full response, including status code, etc. Dig should be available on Macs and Linux machines out of the box; there used to be a version built for Windows, but that's no longer maintained. If you're working on a Windows system, one solution would be to use WSL and use the dig command from the Linux subsystem.
Dig tends to produce a lot of information; since I'm focusing on status codes and numbers of answers, I will show the dig command I give, but the output I'll show will generally be abbreviated to just the lines which illustrate what I'm trying to show. Usually I won't even show the actual answer, just the status part of the response.
To make it easier to duplicate what I'm showing here, almost all queries I show are directed to Google's open recursive server (which is the "@8.8.8.8" part in each example).
First, a query that works as expected. I'll ask for the address of "www.example.com":
dig @8.8.8.8 www.example.comreturns:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7257
;; ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1In this response, I got "status: NOERROR" (the authoritative server was able to answer the query) and "ANSWER: 1"; the combination of NOERROR and one or more answers means the query worked, and the server was able to return the record(s) with the data requested. I won't show actual records in most of these examples, but for this one I'll show what it looks like:
;; ANSWER SECTION:
www.example.com. 2024 IN A 93.184.215.14You can also get status code NOERROR, but with 0 answers. I just showed that there is an A record for "www.example.com"; if I request a MX record for the same qname ("www.example.com"):
dig @8.8.8.8 www.example.com MXthe server returns status NOERROR, but returns 0 answers:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 47517
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1which means “There are records for 'www.example.com', but none are MX records.”
Next I'll show a query for a qname which has no records at all:
dig @8.8.8.8 nosuchqname.example.comwhich returns:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 47517
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1Note that there are 0 answers, but this time, the status code is NXDOMAIN. This is different from the previous example, where there are records for the qname, just none of the requested type (that returned NOERROR / 0 ANSWERS); in this case, because there are no records at all with that qname, the response code is NXDOMAIN.
To show a SERVFAIL, I'll ask Google's 8.8.8.8 recursive resolver to resolve "dnssec-failed.org" (as you can guess, queries to the domain dnssec-failed.org intentionally fail the DNSSEC checks):
dig @8.8.8.8 dnssec-failed.orgreturns:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 65363
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
; EDE: 9 (DNSKEY Missing): (No DNSKEY matches DS RRs of dnssec-failed.org)(I showed a bit more than I usually do, so you can see the part of the response that says it couldn't find a valid key for the domain...) Note that there are no answers, and the status is SERVFAIL.
It's also worth noting that if you want to override the DNSSEC checks when using dig, you can add the "+cdflag" option, which says to disable the DNSSEC checks. But you're asking for trouble; presumably if it fails the DNSSEC check, you should mistrust the data! If you add that flag:
dig @8.8.8.8 +cdflag dnssec-failed.orgyou will get an answer, with status NOERROR and 1 answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21524
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1and it returns the requested A record.
I rarely see NOTIMP response codes, at least on UltraDNS. Typically they occur when some client attempts a dynamic update to a zone on a server that doesn't support dynamic updates. (UltraDNS is for external DNS, so it doesn't support dynamic updates.) I did use nsupdate to try to do a dynamic update to an UltraDNS server, and got the response code:
;; ->>HEADER<<- opcode: UPDATE, status: NOTIMP, id: 17850
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0Given that UltraDNS doesn't do dynamic updates, people don't normally use dynamic updates, so it isn't very likely that you'd ever see a NOTIMP response like this from an UltraDNS server.
A DNS server can refuse to answer a query. If you query an UltraDNS server for a domain that isn't configured, it will respond with a REFUSED status code. There are other ways this can occur. For example, many DNS servers can use an ACL list to block queries from some addresses), but you aren't likely to see REFUSED from UltraDNS unless you asked about a zone which isn't configured. Here's an example:
dig @pdns1.ultradns.net nosuchdomain.comproduces:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 918
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1(Note that I had to specifically ask an UltraDNS server get this code; if you asked a recursive server, it would either find the answer from a server that does handle the domain, or it would return an NXDOMAIN. In this case, "nosuchdomain.com" actually does exist, and if you ask 8.8.8.8 instead of a UltraDNS authoritative server, you would actually get an answer.)