By Ralph Dolmans
One of the new features in the recently released Unbound 1.7.0 is the implementation of aggressive use of the DNSSEC-Validated cache, or ‘Aggressive NSEC’. The implementation is based on efforts in the IETF DNSOP working group published in RFC 8198.
DNS relies heavily on caching. A lot of performance can be gained by storing answers to previous queries close to the client. If an authoritative name server would have to be queried for every single request, performance would be severely impacted. Besides caching the positive answer to queries, the negative answers are also cached. These negative answers are an acknowledgement from the name server that a name does not exist (an answer with the response code set to NXDOMAIN) or that the type in the query does not exist for the name in the query (an answer with the NODATA pseudo response code). These queries for non-existing records are caused by a combination of typos by users, browsers trying to work around DNS hijacking, pseudo random subdomain attacks and leaked queries intended for local use.
Generating NODATA answers using cached NSEC records
The traditional Unbound cache implementation is based on exactly matching cached messages to the query name, query type and query class. If a client asks for a TXT record for nlnetlabs.nl, the resolver will search the cache and if that fails go and look up the answer at the authoritative name server. This query to the authoritative name server will result in a response containing the existing TXT record. If the resolver now receives a query for the same name but for the TLSA type, the resolver will check its cache, in this case can not find a matching record in the cache and will therefore send a query to the authoritative name server. That name server will now reply with a NODATA answer, indicating that the nlnetlabs.nl name does exist, but there is no record for that name with the TLSA record. A third query for the same name for another non-existing type, say SRV, will once again not result in a cache hit and will generate yet another query with again a NODATA answer as result. Because the nlnetlabs.nl zone is DNSSEC signed the absence of these records need to be proven using NSEC records.
As explained in an earlier blog post, NSEC (next secure) records indicate which types exist for a name and which names exist in a zone. These NSEC records have a cryptographic signature which make them tamper proof. By knowing the existing record and types in a zone, a DNSSEC validator can prove that the combination of query name and query type indeed does not exist.
The NODATA answer for the nlnetlabs.nl name with the TLSA query type contains this NSEC record:
nlnetlabs.nl. 3600 IN NSEC !.nlnetlabs.nl. A NS SOA MX TXT AAAA NAPTR RRSIG NSEC DNSKEY
This record proves which types exist for nlnetlabs.nl (A, NS, SOA etc.) and thereby proves that the TLSA record indeed does not exist. The NODATA response to the third query in above example (the SRV query for nlnetlabs.nl) will contain exactly the same NSEC record to prove the absence of the SRV record. Because this NSEC record was already cached after the lookup for the TLSA record we could have used that already obtained NSEC record to generate a DNSSEC secure answer, without the need to send another query to the authoritative name server.
The feature to use already cached NSEC records to generate responses can be enabled in Unbound using the aggressive-nsec option in unbound.conf:
Generating NXDOMAIN answers using cached NSEC records
An answer with the NXDOMAIN response code indicates that a name does not exist at all, which is also proven using an NSEC record. If nlnetlabs.nl contains these alphabetically sorted records (some simplification ahead):
nlnetlabs.nl. IN SOA [..] IN NS astinos.nlnetlabs.nl. astinos.nlnetlabs.nl. IN A 198.51.100.52 stelios.nlnetlabs.nl. IN A 198.51.100.98
then DNSSEC would make sure these NSEC records are inserted and signed:
nlnetlabs.nl. IN NSEC astinos.nlnetlabs.nl. NS SOA DNSKEY astinos.nlnetlabs.nl. IN NSEC stelios.nlnetlabs.nl. A stelios.nlnetlabs.nl. IN NSEC nlnetlabs.nl. A
They attest that no name exists between astinos.nlnetlabs.nl and stelios.nlnetlabs.nl. So if you query for leonidas.nlnetlabs.nl, you will get back the NXDOMAIN from the authoritative name server, as well as the NSEC record for astinos.nlnetlabs.nl — stelios.nlnetlabs.nl as proof that the query name does not exist and the NSEC record for nlnetlabs.nl — astinos.nlnetlabs.nl as proof that the *.nlnetlabs.nl wildcard record does not exist.
If the user now queries for for daxos.nlnetlabs.nl, resolvers would normally ask the authoritative server again because there is no message cached for that name. But because the NSEC records for astinos.nlnetlabs.nl — stelios.nlnetlabs.nl and nlnetlabs.nl — astinos.nlnetlabs.nl are already cached, the implementation of RFC 8198 will allow Unbound to deduce that it doesn’t need to fire off a new query. It is already able to prove that the name doesn’t exist and immediately, or aggressively if you will, returns an NXDOMAIN answer.
Generating wildcard answers using cached NSEC records
There is one more type of message that can be generated using cached NSEC records, namely wildcard answers. A DNSSEC validator only accepts a wildcard answer when there is proof that there is no record for the query name. When we have this zone containing a wildcard record:
nlnetlabs.nl. IN SOA [..] IN NS astinos.nlnetlabs.nl. *.nlnetlabs.nl. IN TXT "A wildcard record" astinos.nlnetlabs.nl. IN A 198.51.100.52 stelios.nlnetlabs.nl. IN A 198.51.100.98
then a TXT query for daxos.nlnetlabs.nl will be answered with the following records, indicating that there is no direct match for the query name but that there is a matching wildcard record:
;; ANSWER SECTION: daxos.nlnetlabs.nl. IN TXT "A wildcard record" daxos.nlnetlabs.nl. IN RRSIG TXT 8 2 [..] ;; AUTHORITY SECTION: astinos.nlnetlabs.nl. IN NSEC stelios.nlnetlabs.nl. A
The astinos.nlnetlabs.nl — stalios.nlnetlabs.nl NSEC record indicates that there is no daxos.nlnetlabs.nl record. The labels field in the signature indicates that the returned TXT record is expanded using the *.nlnetlabs.nl record.
Unbound uses this knowledge to store the wildcard RRset also under the original owner name, containing the wildcard record, when aggressive use of NSEC is enabled. After receiving a query for ephialtes.nlnetlabs.nl Unbound finds the NSEC record proving the absence in its cache. Unbound will then look in the cache for a *.nlnetlabs.nl TXT record, which also exists. These records are then used to generate an answer without sending a query to the name server.
The potential impact of this new functionality shouldn’t be underestimated. The reduction of traffic will have benefits on all levels of the DNS hierarchy but it will be most noticeable at the root, where up to 65% of all responses are NXDOMAIN, as seen on for example K-Root.
If aggressive use of the DNSSEC-validated cache gets deployed widely, the size of the red block in this graph could be reduced dramatically. Decreased load on the name server means more responsiveness and helps operators who currently have to rely more and more on complex, anycasted setups to optimise response times. Ultimately, the result is a better user experience.
Another benefit of a wide deployment of aggressive NSEC is the incentive to DNSSEC sign your zone. You don’t want to have all these queries for non-existing records at your name server? Then start signing your zone!