Why I Still Received DNS Replies from a Documentation Address
Why I Still Received DNS Replies from a Documentation Address
Running nslookup www.youtube.com 8.8.8.8 and seeing Server: 8.8.8.8 is reassuring. It identifies the destination and the claimed source of the accepted reply, however, rather than authenticating who generated it. Plain UDP/53 provides no such authentication.
On September 27, 2026, I tested this from an iStoreOS router. The strongest observation was a matching DNS response to a query addressed to an IP reserved for documentation, where no public recursive resolver should exist.
Verify that the query leaves the WAN
The router runs PassWall2. During the first attempt, nslookup returned plausible answers but eth0 captured no corresponding UDP/53 traffic. Local TProxy interception made that attempt unsuitable for measuring the direct upstream path.
Router-local query → OUTPUT/TProxy → eth0 (WAN capture)
↓
Modem/upstream path
↓
Selected DNS targetFor the subsequent test, I applied a temporary exception only to router-local UDP/53 traffic for the selected targets. It used an existing mark 0xff return rule. The counter reached 112 and the outgoing packets appeared on the WAN. That mark belongs to this deployment; it is not a portable OpenWrt setting.
Neither an explicit resolver argument nor ip route get alone proves which path the DNS packet actually takes.
The 112-query experiment
Each target received A queries for 16 domains. Six public resolvers produced 96 transactions; the control added 16.
| Destination | No overlap with Google DoH | Some overlap |
|---|---|---|
Google 8.8.8.8 | 15/16 | 1/16 |
Cloudflare 1.1.1.1 | 15/16 | 1/16 |
Quad9 9.9.9.9 | 14/16 | 2/16 |
OpenDNS 208.67.222.222 | 14/16 | 2/16 |
AdGuard 94.140.14.14 | 14/16 | 2/16 |
Control D 76.76.2.0 | 14/16 | 2/16 |
| Total | 86/96 | 10/96 |
“No overlap” compares the returned A-address sets. CDNs, caches, geography, and timing can legitimately change those sets. 86/96 is not a measured poisoning rate. Google DoH was the sole reference, rather than a provider-specific baseline for each resolver.
The documentation-address control
The control was 203.0.113.53, within RFC 5737’s TEST-NET-3 documentation block. It should not serve as a public recursive DNS destination.RFC 5737
All 16 control queries received responses. One simplified pair, with the client port omitted, was:
192.168.1.4:<port> > 203.0.113.53:53 A? www.youtube.com.
203.0.113.53:53 > 192.168.1.4:<port> www.youtube.com. A 31.13.92.37The transaction ID, question name, and client port matched; this pair took about 8.51 ms. Across the capture, all 224 frames paired into 112 queries and 112 replies.
This supports transparent answering or source-address spoofing somewhere along the path. It does not establish that a forged reply beat a genuine reply: there was no simultaneous capture at the destination. A single WAN observation also cannot identify the modem, access network, or upstream device responsible.
Every reply had TTL 64, and median response time was about 8.23 ms. These are clues, not attribution. Likewise, an outgoing bad udp cksum can result from TX checksum offload and is not evidence of manipulation.
Pair transactions before attributing responders
The 16-bit DNS ID is not globally unique. Pair client/target addresses, UDP ports, ID, question name/type, and a bounded time window. Retries and concurrent requests can reuse individual fields. Inspect QR, RCODE, answer type, question section, and truncation rather than extracting one address.
This analysis command reads an existing capture without querying the network:
tshark -r dns-direct.pcap -Y dns -T fields \
-E header=y -E separator=, -E quote=d \
-e frame.number -e frame.time_epoch \
-e ip.src -e ip.dst -e udp.srcport -e udp.dstport \
-e dns.id -e dns.flags.response -e dns.flags.rcode \
-e dns.qry.name -e dns.qry.type -e dns.aIdentical, overlapping, and disjoint A sets differ; ordering alone is irrelevant. Preserve CNAMEs, empty answers, timeouts, and error RCODEs separately. Multiple responses to one request matter even if the client displays one. This capture does not include a second genuine-server response, so it does not establish a race.
| Observation | Next check | Limit |
|---|---|---|
| Client answer without WAN request | OUTPUT, proxy, capture point | No direct-upstream inference yet |
| WAN request and matching reply | Tuple, question, timestamp | Boundary-level exchange observed |
| Documentation destination also replies | All control transactions and local routing/rules | Transparent answer/spoofing supported, node unidentified |
| UDP and DoH sets differ | Concurrent queries, multiple resolvers, full responses | Legitimate variation remains possible |
Archive a reproducible comparison next time
DoH/DoT authenticates transport to a trusted resolver; it does not make every result uniquely correct. Save request parameters, HTTP status, JSON, time, resolver, and exit path alongside near-concurrent plaintext queries. HTTP success and the DNS Status inside JSON are different checks.
Today's query cannot reconstruct missing historical DoH JSON. Preserve the capture, row-level data, and analysis commands for independent transaction recounting, and identify comparisons that cannot be reconstructed. A larger sample without better timing and provenance does not automatically strengthen attribution.
Reproduce a small sample
Check the capture interface, route, and local interception rules first. Capture on the router and run the queries in a second session:
tcpdump -i eth0 -nn -s0 -U -w /tmp/dns-direct.pcap \
'udp port 53 and (host 8.8.8.8 or host 203.0.113.53)'
nslookup -type=a www.youtube.com 8.8.8.8
nslookup -type=a www.youtube.com 203.0.113.53If the request is absent from the WAN, investigate local interception before drawing upstream conclusions. The control address must never become a system DNS server. Avoid disabling the entire production proxy for this test.
On the analysis machine, inspect responses and then pair them with requests by transaction ID, question name, and client UDP port:
tshark -r dns-direct.pcap -Y 'dns.flags.response == 1' \
-T fields -e ip.src -e ip.ttl -e dns.id -e dns.qry.name -e dns.aRemove only the temporary rules added for the experiment, stop capture processes, and verify the original proxy and DNS services afterward.
Evidence and limits
The per-query TSV contains the 112 results. The original pcap remains locally archived with SHA-256:
d8786dc025569fb5cb427bd8ac25abb90ca6499498a7a450fc8905fae271e9eaRaw network packets are not published here; the checked results and reproduction method are provided instead. Historical DoH JSON was not separately archived, so today’s lookups cannot precisely reconstruct the original 86/96 comparison. The documentation-address replies remain independently verifiable from the original capture.
The useful troubleshooting habit is to establish where the query went before interpreting its answer. Locating the answering device requires synchronized observations at multiple network boundaries.
References
The article date is the main KB’s first Git commit date, 2026-09-27 (UTC+8), commit 907fcee. Experiment dates are stated separately. No production systems were accessed or changed while preparing this article.
