RFC 8020

NXDOMAIN: There Really Is Nothing Underneath

πŸ“… published November 2016, from ietf

RFC 8020: NXDOMAIN: There Really Is Nothing Underneath 🌸

okay bestie, here's the vibe check on this one πŸ’… It's an Internet Standards Track doc from the Internet Engineering Task Force (IETF), numbered 8020 and dated November 2016. The authors are S. Bortzmeyer (AFNIC) and S. Huque (Verisign Labs). The ISSN is 2070-1721, and it updates RFC 1034 and RFC 2308. πŸ¦‹

Abstract

so the big idea is this ✨ If a DNS resolver gets a response with the NXDOMAIN response code, that means the domain name being denied AND ALL THE NAMES UNDER IT don't exist. Nothing there. Zero. Not even a little bit πŸ’€

This doc clarifies RFC 1034 and tweaks a piece of RFC 2308, so it updates both of them πŸŽ€

Status of This Memo

this is an Internet Standards Track document 🌈

It comes from the Internet Engineering Task Force (IETF) and represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more about Internet Standards, check Section 2 of RFC 7841 🧚

For the current status, any errata, and how to send feedback, go to http://www.rfc-editor.org/info/rfc8020 πŸ’œ

Copyright (c) 2016 IETF Trust and the persons identified as the document authors. All rights reserved πŸ”’

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info), as in effect on the date this document was published. Please read these carefully, because they spell out your rights and restrictions for this document. Any Code Components pulled out of this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Simplified BSD License βš–οΈ

Table of Contents

1. Introduction and Background .....................................2
   1.1. Terminology ................................................3
2. Rules ...........................................................3
3. Updates to RFCs .................................................5
   3.1. Updates to RFC 1034 ........................................5
   3.2. Updates to RFC 2308 ........................................5
4. Benefits ........................................................5
5. Possible Issues .................................................6
6. Implementation Considerations ...................................6
7. Security Considerations .........................................7
8. References ......................................................7
   8.1. Normative References .......................................7
   8.2. Informative References .....................................8
Appendix A. Why can't we just use the owner name of the returned
            SOA? ...................................................9
Appendix B. Related Approaches .....................................9
Acknowledgments ....................................................9
Authors' Addresses ................................................10

1. Introduction and Background ✨

okay so the DNS protocol [RFC1035] says response code 3 is "Name Error", aka "NXDOMAIN" [RFC2308], which means the queried domain name does not exist in the DNS πŸ™ˆ Domain names are a tree of labels ([RFC1034], Section 3.1), so if a node doesn't exist, the entire subtree hanging off it doesn't exist either. it's literally a family tree 🌳

The DNS iterative resolution algorithm reads the NXDOMAIN signal exactly this way. If it runs into an NXDOMAIN response code from an authoritative server, it immediately stops iterating and hands the NXDOMAIN response back to the querier πŸƒβ€β™€οΈ

BUT, in most resolvers out there today, a cached nonexistence for a domain is not treated as "proof" that there are no child domains underneath 😭 This happens because of an ambiguity in [RFC1034], which didn't clearly tell apart Empty Non-Terminal (ENT) names ([RFC7719]) from nonexistent names (Section 3.1). It got a lot more important once DNSSEC came along, since DNSSEC provides proof of nonexistence. [RFC4035], Section 3.1.3.2, explains how security-aware authoritative name servers make the distinction, but no existing RFCs describe the behavior for recursive name servers. Main character problem, honestly πŸ‘‘

So this document says that an NXDOMAIN response for a domain name means no child domains underneath the queried name exist either. Resolvers should read cached nonexistence the same way. The domain names are organized in a tree, so this is just a simple consequence of the tree structure: nonexistence of a node implies nonexistence of the entire subtree rooted at that node πŸ¦‹

1.1. Terminology πŸŽ€

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119] πŸ”‘

"QNAME": defined in [RFC1034] and in [RFC1035], Section 4.1.2. But because [RFC2308] gives a different definition, we're repeating the original one here: the QNAME is the domain name in the question section πŸ’œ

"Denied name": the domain name whose existence has been denied by a response RCODE of NXDOMAIN. Most of the time it's the QNAME, but because of [RFC6604], that's not always the case πŸ™ˆ

Other terms are defined in [RFC1034], [RFC1035], and (like NXDOMAIN itself) in the more recent [RFC7719] 🧚

The domain name space is conceptually defined as a tree structure. A DNS resolver/cache MAY use a tree or other data structures to implement that. The cache is a subset of the data in the domain name space, so it's way easier to reason about it as a tree and describe things in those terms (names under/above, descendant names, subtrees, etc.). Honestly, [RFC1034] already assumes the cache is a tree in its DNS algorithm description. See its Section 4.3.2, which says "The following algorithm assumes that the RRs are organized in several tree structures, one for each zone, and another for the cache..." So the precedent is already well established ✨ In this document, whenever we talk about a tree or tree operations, we mean the model, not the actual implementation 🌸

2. Rules πŸ’…

okay this is the main part bestie πŸ”₯ When an iterative caching DNS resolver receives an NXDOMAIN response, it SHOULD store it in its cache, and then all names and resource record sets (RRsets) at or below that node SHOULD be considered unreachable. Later queries for those names SHOULD elicit an NXDOMAIN response 🚫

But if a resolver has cached data under the NXDOMAIN cut, it MAY keep sending that data as a reply (until the TTL of the cached data expires), since this may skip some extra processing when a query comes in. Section 6 has more on this ✨

There's one more exception: a validating resolver MAY decide to implement the "NXDOMAIN cut" behavior (described in the first paragraph of this section) only when the NXDOMAIN response has been validated with DNSSEC. See Section 7 for the reasoning πŸ”

The fact that a subtree doesn't exist isn't forever, though. [RFC2308], Section 3, already describes how long an NXDOMAIN response may be cached (the "negative TTL") ⏰

If the NXDOMAIN response from a cached nonexistence comes from a DNSSEC-signed zone, it will come with NSEC or NSEC3 records that authenticate the nonexistence of the name. For a descendant name of the original NXDOMAIN name, that same set of NSEC or NSEC3 records proves the descendant doesn't exist either. The iterative, caching resolver MUST return these NSEC or NSEC3 records in the response to the triggering query if that query had the DNSSEC OK (DO) bit set 🫢

Warning: if there's a chain of CNAME (or DNAME), the name that does not exist is the last one in the chain ([RFC6604]), not the QNAME. The NXDOMAIN stored in the cache is for the denied name, not always for the QNAME 😱

Here's an example. Say there are two successive queries to a resolver for a nonexistent domain foo.example. The first is for foo.example (which gets an NXDOMAIN) and the second is for bar.foo.example (which also gets an NXDOMAIN). Lots of resolvers today will forward both queries. But following the rules in this doc ("NXDOMAIN cut"), a resolver would cache the first NXDOMAIN response as a sign of nonexistence, and then immediately return an NXDOMAIN for the second query without sending it to an authoritative server 🏎️

Now if the first request is for bar.foo.example and the second is for baz.foo.example, the first NXDOMAIN response won't tell us anything about baz.foo.example. So the second query gets sent out just like it was before the "NXDOMAIN cut" optimization (see Appendix A) πŸ€·β€β™€οΈ

3. Updates to RFCs πŸ¦‹

3.1. Updates to RFC 1034 πŸ’–

This document clears up possible ambiguities in [RFC1034] that didn't clearly separate Empty Non-Terminal (ENT) names ([RFC7719]) from nonexistent names, and it points to later documents that do. ENTs are nodes in the DNS that have no resource record sets attached to them but do have descendant nodes that do. The correct response to an ENT is NODATA (i.e., a response code of NOERROR and an empty answer section). More clarifying language on these points is in Section 7.16 of [RFC2136] and in Sections 2.2.2 and 2.2.3 of [RFC4592] 🌈

3.2. Updates to RFC 2308 πŸ“

The second paragraph of Section 5 in [RFC2308] says:

A negative answer that resulted from a name error (NXDOMAIN) should be cached such that it can be retrieved and returned in response to another query for the same <QNAME, QCLASS> that resulted in the cached negative response.

This document revises that paragraph to say:

A negative answer that resulted from a name error (NXDOMAIN) should be cached such that it can be retrieved and returned in response to another query for the same <QNAME, QCLASS> that resulted in the cached negative response, or where the QNAME is a descendant of the original QNAME and the QCLASS is the same.

Section 2 above elaborates on the revised rule and specifies when it may be reasonable to relax or ignore it πŸŽ€

4. Benefits ✨

okay so the big win here is that caches get way more efficient 🧠 In the example from earlier, the resolver only sends ONE query instead of two, because the second answer just comes straight from the cache πŸ’… That helps the whole DNS ecosystem, since the authoritative name servers have way less pointless traffic to deal with 🫢

This behaviour is what [RFC1034] was already going for, just spelled out more clearly here πŸŽ€ It's especially iconic when you pair it with QNAME minimization [RFC7816], because the resolver can stop searching the second it hits an NXDOMAIN πŸ›‘

"NXDOMAIN cut" might also help with certain random QNAME attacks, as seen in [joost-dnsterror] and [balakrichenan-dafa888] 😭 Here the bad actors send resolvers queries with a fixed suffix that basically never exists ("dafa888.wf" in one of the articles above), plus a random prefix that changes every single request. The resolver has to pass each one along to the authoritative servers. With "NXDOMAIN cut", a system administrator only has to send the resolver one query for that fixed suffix. The resolver gets an NXDOMAIN and stops forwarding the junk πŸ™…β€β™€οΈ (It would be better if the SOA record in the NXDOMAIN response were enough to find the nonexisting domain, but it isn't, see Appendix A πŸ₯Ί)


5. Possible Issues πŸ™ˆ

Let's say the Top-Level Domain (TLD) example exists, but foobar.example is not delegated. That means the example's name servers will reply NXDOMAIN for a query about anything.foobar.example 🧐 Now a system administrator decides to name the internal machines of his organization under office.foobar.example, and uses a trick in his resolver to forward requests about this zone to his local authoritative name servers. "NXDOMAIN cut" would cause problems here πŸ’€ Depending on the order of requests to the resolver, it may have cached the nonexistence from example, and then it would "delete" everything under it. This document assumes that a setup like this is rare and doesn't need to be supported πŸ€·β€β™€οΈ

Today there's another possible issue too πŸ‘€ We see authoritative name servers that reply to ENT ([RFC7719], Section 6) with NXDOMAIN, when they should be giving the normal NODATA ([RFC7719], Section 3).

Those name servers are definitely wrong, and they always have been 😀 Their behaviour is incompatible with DNSSEC. Given how great "NXDOMAIN cut" is, there's very little reason to support this behavior πŸ™…β€β™€οΈ


6. Implementation Considerations 🧚

This section is non-normative, so think of it as a grab bag of tips that might be useful for implementors πŸ“ A recursive resolver can build its cache in lots of ways. The most obvious one is a tree data structure, because it fits the data model of domain names. In practice though, other implementations are possible, along with various optimizations (like a tree augmented by an index of some common domain names) 🌸

If a resolver implements its cache as a tree, without any optimization, one way to follow the rules in Section 2 looks like this: when it receives the NXDOMAIN, it prunes the subtree of positive cache entries at that node, or deletes all the individual cache entries for names below that node 🌳 Then, when it searches downward in its cache, this iterative caching DNS resolver will stop searching if it runs into a cached nonexistence πŸ›‘

Some resolvers have a cache that is NOT organized as a tree (more like a dictionary, for instance), so they have a reason to ignore the rules of Section 2 πŸ€” That's why these rules use SHOULD and not MUST 🫢


7. Security Considerations πŸ’€

The technique in this document may help against a denial-of-service attack called "random qnames", which is described in Section 4 😀

If a resolver doesn't validate the answers with DNSSEC, or if the zone isn't signed, the resolver can totally get poisoned with a false NXDOMAIN 😱 That means it could "delete" a whole part of the domain name tree. This denial-of-service attack is already possible without the rules in this document, but "NXDOMAIN cut" may make its effects worse πŸ“‰ The only real solution is to use DNSSEC πŸ”


8. References πŸ“š

8.1. Normative References

[RFC1034]  Mockapetris, P., "Domain names - concepts and facilities",
           STD 13, RFC 1034, DOI 10.17487/RFC1034, November 1987,
           <http://www.rfc-editor.org/info/rfc1034>.

[RFC1035]  Mockapetris, P., "Domain names - implementation and
           specification", STD 13, RFC 1035, DOI 10.17487/RFC1035,
           November 1987, <http://www.rfc-editor.org/info/rfc1035>.

[RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
           Requirement Levels", BCP 14, RFC 2119,
           DOI 10.17487/RFC2119, March 1997,
           <http://www.rfc-editor.org/info/rfc2119>.

[RFC2136]  Vixie, P., Ed., Thomson, S., Rekhter, Y., and J. Bound,
           "Dynamic Updates in the Domain Name System (DNS UPDATE)",
           RFC 2136, DOI 10.17487/RFC2136, April 1997,
           <http://www.rfc-editor.org/info/rfc2136>.

[RFC2308]  Andrews, M., "Negative Caching of DNS Queries (DNS
           NCACHE)", RFC 2308, DOI 10.17487/RFC2308, March 1998,
           <http://www.rfc-editor.org/info/rfc2308>.

[RFC4592]  Lewis, E., "The Role of Wildcards in the Domain Name
           System", RFC 4592, DOI 10.17487/RFC4592, July 2006,
           <http://www.rfc-editor.org/info/rfc4592>.

[RFC6604]  Eastlake 3rd, D., "xNAME RCODE and Status Bits
           Clarification", RFC 6604, DOI 10.17487/RFC6604, April
           2012, <http://www.rfc-editor.org/info/rfc6604>.

8.2. Informative References

[RFC4035]  Arends, R., Austein, R., Larson, M., Massey, D., and S.
           Rose, "Protocol Modifications for the DNS Security
           Extensions", RFC 4035, DOI 10.17487/RFC4035, March 2005,
           <http://www.rfc-editor.org/info/rfc4035>.

[RFC7719]  Hoffman, P., Sullivan, A., and K. Fujiwara, "DNS
           Terminology", RFC 7719, DOI 10.17487/RFC7719, December
           2015, <http://www.rfc-editor.org/info/rfc7719>.

[RFC7816]  Bortzmeyer, S., "DNS Query Name Minimisation to Improve
           Privacy", RFC 7816, DOI 10.17487/RFC7816, March 2016,
           <http://www.rfc-editor.org/info/rfc7816>.

[DNSRRR]   Vixie, P., Joffe, R., and F. Neves, "Improvements to DNS
           Resolvers for Resiliency, Robustness, and Responsiveness",
           Work in Progress, draft-vixie-dnsext-resimprove-00, June
           2010.

[NSEC]     Fujiwara, K., Kato, A., and W. Kumari, "Aggressive use of
           NSEC/NSEC3", Work in Progress, draft-ietf-dnsop-nsec-
           aggressiveuse-04, September 2016.

[joost-dnsterror]
           Joost, M., "About DNS Attacks and ICMP Destination
           Unreachable Reports", December 2014,
           <http://www.michael-joost.de/dnsterror.html>.

[balakrichenan-dafa888]
           Balakrichenan, S., "Disturbance in the DNS - "Random
           qnames", the dafa888 DoS attack"", October 2014,
           <https://indico.dns-oarc.net/event/20/session/3/
           contribution/3>.

Appendix A. Why can't we just use the owner name of the returned SOA? πŸ€”

In this document, we only deduce that a domain doesn't exist for NXDOMAIN answers where the denied name was the exact domain 🎯 Say a resolver sends a query to the name servers of the TLD example, asking for the mail exchange (MX) record for www.foobar.example, and then gets an NXDOMAIN. All it can register is that www.foobar.example (and everything underneath it) doesn't exist. That's true whether or not the accompanying SOA record is for the domain example only πŸ’… You can't infer that foobar.example is nonexistent. The accompanying SOA record shows the apex of the zone, not the closest existing domain name. So using the owner name of the SOA record in the authority section to deduce "NXDOMAIN cuts" is currently definitely not OK πŸ™…β€β™€οΈ

Deducing the nonexistence of a node from the SOA in the NXDOMAIN reply may certainly help with random qnames attacks, but that's out-of-scope for this document 🧒 It would mean addressing the problems mentioned in the first paragraph of this section. A possible solution is this: when a resolver receives a NXDOMAIN with a SOA that's more than one label up in the tree, it sends requests for the domains that sit between the QNAME and the owner name of the SOA. (A resolver that does DNSSEC validation or QNAME minimization will need to do it anyway ✨)

The document [NSEC] covers another way to tackle some of the same concerns, like cutting down traffic for nonexisting domain names πŸ’œ Unlike "NXDOMAIN cut", it requires DNSSEC, but it's more powerful, since it can synthesize NXDOMAINs for domains that were never even queried πŸ‘‘

Acknowledgments 🫢

The main idea in this document comes from [DNSRRR], Section 3, "Stopping Downward Cache Search on NXDOMAIN" πŸ™Œ Huge thanks to its authors, Paul Vixie, Rodney Joffe, and Frederico Neves. Tony Finch, Ted Lemon, John Levine, Jinmei Tatuya, Bob Harold, and Duane Wessels also gave valuable feedback and suggestions, so they're absolutely iconic too 🌈

Authors' Addresses πŸŽ€

Stephane Bortzmeyer
AFNIC
1, rue Stephenson
Montigny-le-Bretonneux  78180
France

Phone: +33 1 39 30 83 46
Email: bortzmeyer+ietf@nic.fr
URI:   https://www.afnic.fr/


Shumon Huque
Verisign Labs
12061 Bluemont Way
Reston, VA  20190
United States of America

Email: shuque@verisign.com
URI:   http://www.verisignlabs.com/
πŸ“¦ where this page comes from