Every recommendation on this site rests on operator statements and on measurements. Statements can be quoted; measurements can be repeated. This section shows how.
All commands were run on 7 September 2026 on an ordinary Linux machine, and the outputs described are what actually came back. Where output can differ, it says so. You need nothing but dig, curl and openssl; all three are present on most systems. On Windows, the Windows Subsystem for Linux provides the same tools.
One note up front, because it is the most common source of error: always query the resolver directly, using @ and its address. Without @ you get an answer from your operating system's local service, and that answer says little about the resolver itself.
Does my resolver validate DNSSEC?
Three commands answer this question, and they answer it beyond doubt. What matters is querying the resolver
directly, using @ and its address. Without @ you are asking the operating system's local stub,
which often swallows the decisive detail.
The positive control
Does the resolver mark a correctly signed answer as verified?
dig +dnssec @9.9.9.9 sigok.ippacket.stream A
The line ;; flags: must contain ad alongside qr rd ra, and the
status must be NOERROR. Measured on 7 September 2026: status: NOERROR and
flags: qr rd ra ad. The ad stands for “authentic data”. RFC 4035 permits a server to set this
bit only if it has verified every record in the answer itself.
Replace 9.9.9.9 with the address you want to test.
The negative control
Does the resolver reject a deliberately mis-signed answer?
dig @9.9.9.9 sigfail.ippacket.stream A
dig @9.9.9.9 dnssec-failed.org A
Both must return status: SERVFAIL and an empty answer section. Measured on
7 September 2026: both SERVFAIL. If NOERROR comes back with an IP address instead, this
resolver does not validate. Two independent test domains, because either one can go away at any time.
Proof that DNSSEC was really the reason
A SERVFAIL can have many causes. How do I rule the others out?
dig +cd @9.9.9.9 sigfail.ippacket.stream A
With the CD bit set, meaning “checking disabled”, the same query must now return NOERROR
and an address. Measured on 7 September 2026: without +cd SERVFAIL, with +cd NOERROR. That
switch is the proof: the resolver checked first and refused for that reason, not because the domain was broken or the
server overloaded.
Reading the reason in plain text
Does the resolver also say why it refused?
dig @9.9.9.9 sigfail.ippacket.stream A | grep EDE
A line of the form ; EDE: 6 (DNSSEC Bogus). That is exactly what was measured on
7 September 2026. Extended DNS Errors per RFC 8914 give a machine-readable reason instead of a bare SERVFAIL. If no EDE
line appears, the resolver does not support the extension; on its own that says nothing about its validation.
The pitfall that ruins most tests
Why is the ad flag missing even though the resolver validates?
dig +dnssec sigok.ippacket.stream A
dig +dnssec @9.9.9.9 sigok.ippacket.stream A
The difference is the @. Without an address you are asking the operating system's local
service. On the test machine the first command returned flags: qr rd ra without ad on
7 September 2026, the second flags: qr rd ra ad. So the upstream does validate, the local stub simply does
not pass the marking through. Anyone unaware of this will mistake a validating resolver for a broken one.
On Linux, resolvectl status shows what the system service is doing.
Which resolver am I actually using?
What is configured and what is used are two different things. Routers, VPN software, browsers with their own DoH
and the system service all interfere. These commands show who really answers in the end, and which part of your address
they pass on.
Who answers, and what do they pass on about me?
Does the authoritative server see my address, or only the resolver's?
dig +short TXT whoami.ds.akahelp.net
This Akamai service answers with up to three pairs. ns is the address of the resolver that
actually asked. If ecs appears as well, part of your own address was sent along. Measured on
7 September 2026 through the system resolver: only "ns", no ecs. So nothing of the client
address was passed on.
One provider, two addresses, two outcomes
What does the difference between with and without EDNS Client Subnet actually look like?
dig +short TXT whoami.ds.akahelp.net @9.9.9.9
dig +short TXT whoami.ds.akahelp.net @9.9.9.11
Measured on 7 September 2026. Via 9.9.9.9 only "ns" came back with the resolver
address. Via 9.9.9.11 there were additionally "ip" and
"ecs" "203.0.113.0/24/24", meaning your own network with a truncated address. Same operator, same privacy
policy, one character of difference in the address. This is the cleanest demonstration of ECS, because every other
condition stays the same.
The network shown is an example. Your own output will contain your own network.
Which node of an anycast network answers
Anycast means many servers, one address. Which one is it right now?
dig +nsid @9.9.9.9 example.com A
In the OPT PSEUDOSECTION a line appears reading
; NSID: ... ("res701.qfra3"). That is what was measured on 7 September 2026; the identifier points to a
location in Frankfurt. If the line is missing, the server sends no identifier. The advantage over the older query
dig @server CH TXT id.server is that the identifier travels along with the normal answer.
Is the answer really encrypted?
An encrypted connection on its own means nothing as long as nobody checks who is at the other end. That is the
most common mistake in guides: they show a successful handshake and call it security.
DNS over TLS in one command
Does the answer really arrive through the TLS channel?
dig +tls @dns.quad9.net example.com A
The decisive line is the penultimate one. Measured on 7 September 2026:
;; SERVER: 149.112.112.112#853(dns.quad9.net) (TLS). The (TLS) and port 853 are
the evidence. If (TLS) is absent, the query ran in the clear.
The most common mistake: encrypted but unverified
Encryption without certificate checking protects against whom exactly?
echo QUIT | openssl s_client -connect dns.quad9.net:853 \
-servername dns.quad9.net -alpn dot 2>&1 \
| grep -E 'subject=|Verification|ALPN protocol'
Three lines must come together. Measured on 7 September 2026:
subject=C=CH, ST=Zurich, L=Zürich, O=Quad9, CN=dns.quad9.net, then Verification: OK, then
ALPN protocol: dot. Only all three together establish encrypted, correct counterpart, correct protocol. A
handshake alone establishes only that somebody answered.
With kdig from the package knot-dnsutils (Debian, Ubuntu) or
knot-utils (Fedora, RHEL) the same thing is shorter:
kdig -d @dns.quad9.net +tls-ca +tls-host=dns.quad9.net example.com A. Note that +tls on its
own does not verify the certificate; that requires +tls-ca.
The counter-test that has to fail
Does my tool really check, or does it wave everything through?
echo QUIT | openssl s_client -connect 9.9.9.9:853 \
-servername dns.quad9.net -alpn dot -verify_return_error \
-verify_hostname wrong.example.com 2>&1 | grep -iE 'verif|error' | head -3
This command has to fail. Expected is a line reporting a verification error about the hostname. If a
successful verification comes back here, all your other checks are worthless. A negative control that does not fail
measures nothing.
Checking DNS over QUIC
Does the endpoint really speak DoQ, or only almost?
openssl s_client -quic -alpn doq -connect dns.quad9.net:853 \
-servername dns.quad9.net < /dev/null 2>&1 \
| grep -E 'ALPN protocol|Verification'
Measured on 7 September 2026: Verification: OK and ALPN protocol: doq. A word
on interpretation: a negotiated doq proves only that the server accepts the protocol. Whether an answer
follows is a separate question. That very difference showed up at UncensoredDNS, where the handshake succeeded but a
real query went unanswered.
Requires OpenSSL 3.5 or newer. Check with openssl version.
DNS over HTTPS, the convenient way and the exact way
Does the DoH endpoint answer the way RFC 8484 requires?
dig +https @dns.quad9.net example.com A
curl -sS -o antwort.bin -w '%{http_code} %{content_type} %{size_download}\n' \
-H 'accept: application/dns-message' \
'https://dns.quad9.net/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB'
The first command is the convenient one: dig speaks DoH itself and shows a readable answer.
The second shows what actually goes over the wire. Measured on 7 September 2026:
200 application/dns-message 65. The file contains a binary DNS message, not JSON. The first bytes read
00 00 81 80 00 01 00 02: identifier zero as RFC 8484 requires, response bit set, one question, two
answers.
The base64 string in the example appears verbatim in RFC 8484 itself and asks for
www.example.com. Some providers additionally offer a JSON interface; it is convenient, but it is not a
standard and does not behave the same everywhere.
Why the test domains have no website
A note on the test domains: sigok.ippacket.stream, sigfail.ippacket.stream, dnssec-failed.org and qnamemintest.internet.nl have no website you could visit. They exist only in the DNS. With dnssec-failed.org that is even necessary: if your resolver is doing its job it cannot resolve the name at all, so no page can open. Here the absence of the page is the proof, not the fault.