Authentication
DNSSEC Explained: How the Chain of Trust Works, What a Validating Resolver Checks and How to Check It
A forged DNS answer is just a few bytes that arrive before the real ones, and plain DNS cannot tell them apart. DNSSEC fixes that by signing records at the source, so a resolver can check that an answer comes from the domain’s owner. The standard is a trio of RFCs, 4033, 4034 and 4035, published in March 2005.
What DNSSEC proves, and what it never hides
RFC 4033 lists three services. Data origin authentication shows a record was published by the zone that owns it. Data integrity shows nobody changed it on the way. Authenticated denial of existence lets a resolver prove that a name or record type really does not exist, so an attacker cannot fake a “no such domain” answer either.
The same RFC is just as clear about the limits. By deliberate design, the extensions do not provide confidentiality, and they do not protect against denial of service. Every signed query and answer still crosses the network in plain text, so anyone on the path can read which names you look up. Encrypted transports fill that gap.
That distinction trips up a lot of comparisons. Authentication answers “is this data genuine?” Encryption answers “who can read this?” A signed answer delivered over plain UDP is genuine but public. An encrypted answer from a resolver that never checked signatures is private but only as trustworthy as that resolver. The encrypted DNS overview covers the second half.
The chain of trust, from the root down
Signatures are worthless unless you trust the key that made them. RFC 4033 solves that with a chain of trust. A resolver starts with at least one trust anchor, a key it knows in advance, normally at the root. Each zone vouches for the next one down, using four record types that RFC 4034 defines:
- DNSKEY holds a zone’s public keys.
- RRSIG holds the signature over a set of records of the same name and type.
- DS (delegation signer) sits in the parent zone and contains a hash of the child’s key, linking parent to child.
- NSEC proves that a name or type does not exist, signed like everything else.
A resolver checking www.example.org therefore walks a path: the root’s DNSKEY verifies the DS for org, which matches the DNSKEY of org, which verifies the DS for example.org, and so on until the RRSIG on the final record checks out. A single missing or expired link breaks the chain of trust, and the answer becomes bogus.
What a validating resolver does with the result
A validating resolver performs that walk on your behalf. RFC 4035 sets the rules for reporting the outcome. The resolver may set the AD (Authenticated Data) bit only when it considers every record set in the answer and authority sections authentic. Stub resolvers on laptops and phones normally do not check signatures themselves; they rely on that single bit.
When validation fails, the rule is strict. For bogus data on a recursive query, the server must return RCODE 2, server failure, instead of the broken answer. The one exception is a query with the CD (Checking Disabled) bit set, which tells the validating resolver that the client does its own checking and wants the raw data.
How to check DNSSEC with dig
BIND’s dig makes the bits visible. Adding +dnssec sets the DNSSEC OK (DO) bit, so the server returns the signature records with the answer. The flags line at the top of the output shows ad when the resolver validated the data. According to the BIND manual, dig sets the AD bit in the query by default.
Run the query twice to learn more. First ask a validating resolver, for example dig +dnssec example.org @9.9.9.9, and look for ad in the flags and RRSIG lines in the answer. Then add +cd to switch validation off. If a name returns SERVFAIL normally but resolves with +cd, its signatures are broken and the refusal was correct.
Resolvers that check signatures
| Resolver | What the operator documents |
|---|---|
| Google Public DNS | Full support since January 2013, rejects responses without correct signatures |
| Cloudflare 1.1.1.1 | Described as a validating resolver; sends the DO flag on every query |
| Quad9 | A domain fails to resolve with SERVFAIL when authentication fails |
On a Linux machine running systemd-resolved, the DNSSEC= option in resolved.conf decides whether the local stub validates too. yes validates every lookup locally, allow-downgrade validates only when the upstream server supports it, and no skips it. The default is allow-downgrade, and the manual itself warns that this mode is open to downgrade attacks.
Why DNSSEC and DNSCrypt belong together
DNSCrypt and signature validation protect different stretches of the path. DNSCrypt encrypts and authenticates the hop between your machine and the resolver, so nobody on the local network can read or forge that answer. Signatures protect the data from the domain’s servers to the resolver. The DNSCrypt FAQ pairs the two for that reason.
The FAQ is also frank that signing has seen limited adoption and does not stop traffic from being monitored. Many domains are simply unsigned, and for those validation adds nothing. That is why encryption is the baseline and signature checking the second layer, rather than the other way round. The comparison table shows both properties for every protocol.
dnscrypt-proxy lets you combine them in one line. Setting require_dnssec = true in its configuration keeps only resolvers that support the extensions in the server list, and the example file recommends validating resolvers for bootstrap too. One caveat from the same file: if dnsmasq sits in front of the proxy and you use filtering, switch off dnsmasq’s own dnssec option.
When a signed domain fails to resolve
A sudden SERVFAIL on one domain, while everything else works, is the classic sign of a signing mistake there: an expired RRSIG, or a DS in the parent zone that no longer matches the child’s DNSKEY. Test with +cd as described above. If the name resolves with checking disabled, the fault sits with the domain operator, not your setup.
Resist the urge to switch validation off globally to make one site load. Use a non-validating resolver only for that test, report the problem to the domain owner, and keep checking enabled for everything else. To find DNSCrypt resolvers that validate, filter the resolver directory, and read the DNS spoofing page for the attacks this layer stops.
Frequently asked questions
Does DNSSEC encrypt my DNS queries?
No. RFC 4033 states that the extensions deliberately do not provide confidentiality. Queries and answers stay readable to anyone on the network path. Encryption comes from a transport such as DNSCrypt, DNS over HTTPS or DNS over TLS. A signed answer sent over plain UDP is genuine but public, so the two layers complement each other.
What does the ad flag in a dig answer mean?
It is the Authenticated Data bit. A validating resolver sets it only when it considers every record set in the answer and authority sections authentic. If you see the flag, the resolver checked the signatures; if it is missing, the data was unsigned or the resolver did not validate. dig shows it as ad in the flags line.
Why does a domain return SERVFAIL on one resolver and work on another?
A validating resolver must answer with server failure when signatures do not check out, as RFC 4035 requires. A resolver that does not validate passes the same broken data through. So SERVFAIL on Quad9 or 1.1.1.1 with an answer elsewhere usually points to a signing error at the domain. Repeat the query with the +cd flag to confirm.
Do I need DNSSEC if I already use DNSCrypt?
They answer different questions. DNSCrypt proves the answer came unaltered from the resolver you chose. Signature validation proves the resolver got the real data from the domain's own servers. Choosing a DNSCrypt resolver that also validates gives you both. Many domains are unsigned, so encryption is the baseline and validation the second layer.
Which public resolvers validate signatures?
Google Public DNS has fully supported validation since January 2013, Cloudflare describes 1.1.1.1 as a validating resolver, and Quad9 documents that a domain fails to resolve when authentication fails. In dnscrypt-proxy the require_dnssec option filters the server list to resolvers that support it. Keep validation enabled even when a single signed domain fails to resolve.
Sources
- RFC 4033: DNS Security Introduction and Requirements
- RFC 4034: Resource Records for the DNS Security Extensions
- RFC 4035: Protocol Modifications for the DNS Security Extensions
- BIND 9 manual pages: dig
- Google Public DNS: Security benefits
- Cloudflare 1.1.1.1 FAQ
- Quad9 FAQ
- systemd: resolved.conf
- dnscrypt-proxy example configuration
- DNSCrypt FAQ