DNS Pollution vs DNS Hijacking: How to Tell with dig and nslookup

Blog / Troubleshooting

DNS Pollution vs DNS Hijacking: How to Tell with dig and nslookup

DNS pollution and DNS hijacking both end the same way: a domain resolves to an IP it should not. The difference is where the tampering happens. Pollution happens in transit: some device on the path of your query sends a forged reply before the real resolver can answer. Hijacking happens at an endpoint: your hosts file, your router, or your ISP's resolver itself returns a modified result. To tell them apart, send the same domain to your local resolver, several public resolvers and encrypted DNS, compare the answers, then use RDAP to see who owns the IP in the reply. The table below lays out the differences, and the commands after it let you check for yourself.

What is the difference between DNS pollution and DNS hijacking?

AspectDNS pollutionDNS hijacking
Where the tampering happensAn off-path device on the transmission linkLocal hosts file, router, ISP resolver, or replaced DNS settings
How it worksSees the query and sends a forged reply first; the real reply arrives late and is droppedThe resolver returns a modified record directly, or redirects your port 53 traffic to a different resolver
Switching to another plaintext public DNSOften still wrong, because the query crosses the same linkIf only the local resolver was modified, switching usually fixes it; transparent redirection is the exception
Querying over TCP or encrypted DNSEncrypted DNS generally returns the correct resultEncrypted DNS bypasses the modified resolver and is usually correct too
Querying an IP that does not run DNSMay still get an "answer", which is a classic sign of pollutionUsually times out, unless transparent redirection is in place
ScopeEveryone whose traffic crosses that link, usually for specific domainsOne device, one home network, or one ISP's users
Typical reply signaturesReply arrives faster than the round trip to the resolver; two replies to one queryA nonexistent domain resolves to an ad-page IP; replies of 0.0.0.0, 127.0.0.1 or a private address

Both can be present at once, so the procedure below rules things out one segment at a time.

Before you start: confirm the problem is really DNS

Many "won't load" problems have nothing to do with resolution. Start with the cdnping online speed test. Its "first connect" figure includes DNS and the TLS handshake, and "round trip" is the median of 3 requests over a reused connection. If first connect is slow but round trip is normal, the problem may be in resolution or the handshake. If the round trip itself is slow, it looks more like a link problem; continue with How to read traceroute and mtr results. If a particular AI service won't open, you can also rule out a server-side outage first with Is ChatGPT down? Three steps to tell a service outage from your own network.

Also remember that inconsistent results do not prove tampering. All of the following are normal:

  • The domain uses a CDN or location-based routing (GeoDNS), so different resolvers and different cities get different IPs by design.
  • The resolver passes along client subnet information (ECS) and returns a node near you.
  • A record was just changed and the TTL cached by various resolvers has not expired yet. Sync delays at a DNS provider can also cause short-lived inconsistency. For example, among the events cdnping syncs from the Cloudflare official status page, there is a "DNS Update Delays" incident starting 2026-10-15 15:33 (UTC), severity minor, lasting about 165 minutes (source: cdnping /status, which syncs the official status page every 15 minutes, window since September 17, 2026). During that period a freshly changed record could look different on different resolvers, but that is not pollution.

So what matters is whether the IP's ownership makes sense and who sent the reply. Whether two IPs are identical tells you little.

Step 1: Compare your local resolver with several public resolvers

Below, example.com stands for the domain you are checking. The IPs in the commands are public resolver addresses (223.5.5.5 is AliDNS and 119.29.29.29 is DNSPod, two widely used public resolvers in China; 1.1.1.1 is Cloudflare and 8.8.8.8 is Google).

macOS / Linux:

D=example.com
# System default resolver (the one your router or ISP hands out)
dig +short $D A
# A few public resolvers over plaintext UDP port 53
for s in 223.5.5.5 119.29.29.29 1.1.1.1 8.8.8.8; do
  echo "== $s"; dig +short +time=3 +tries=1 @$s $D A
done

Windows (PowerShell):

$D = "example.com"
Resolve-DnsName $D -Type A -DnsOnly
foreach ($s in "223.5.5.5","119.29.29.29","1.1.1.1","8.8.8.8") {
  "== $s"; Resolve-DnsName $D -Type A -Server $s -DnsOnly -QuickTimeout
}

If you only have nslookup, write nslookup example.com 223.5.5.5 and swap in each server address in turn.

First check whether the local machine has been modified. If cat /etc/hosts (on Windows, C:\Windows\System32\drivers\etc\hosts) contains an entry for this domain, the query is never sent at all. That is a "hijack" at the machine level, and it may have been written by you or by some piece of software.

How to read the results:

  • Only the system default resolver gives a strange answer and the public resolvers all agree: most likely a problem with the router or ISP resolver, leaning toward hijacking.
  • Every plaintext query returns the same suspicious IP: could be pollution on the link, or port 53 being transparently redirected. Step 2 separates the two.
  • The answers all differ but all belong to the same CDN: usually normal; confirm with RDAP in Step 4.

Step 2: Confirm your query actually reached the resolver you chose

dig @1.1.1.1 does not guarantee the packet really reached 1.1.1.1. Some routers or networks redirect all UDP port 53 traffic to their own resolver. You can verify this using the "identify yourself" records that resolver operators provide:

# Cloudflare returns the code of the data center that handled the query; when redirected, you usually get nothing or a malformed answer
dig +short @1.1.1.1 id.server CH TXT
# Google returns the egress IP of the resolver that queried the authoritative servers for you
dig +short @8.8.8.8 o-o.myaddr.l.google.com TXT
# Use the default resolver and see who is actually doing the work
dig +short whoami.akamai.net A

The third command returns the resolver's egress IP, not your own. Take it to Step 4 and look it up in RDAP. If it belongs to an ISP or an unfamiliar entity you never configured, your default resolution path is not what you think it is. A browser can show similar information: the DNS leak test on cdnping /ip lists the IPs and owners of the resolvers actually querying for you; the background is covered in DNS leaks and WebRTC leaks.

Then test a domain that cannot exist:

dig +short nx-$(date +%s).example.com A

The normal result is empty (status NXDOMAIN). If it returns an IP, the default resolver rewrote "does not exist" into some page's address, which is clear evidence of resolver-level hijacking. To see the full status, drop +short and look at the status: line.

Step 3: Compare UDP, TCP and encrypted DNS

Most on-path forged replies target UDP. Query the same resolver over UDP, TCP and DoH (DNS over HTTPS) and compare all three:

D=example.com
dig +short @1.1.1.1 $D A          # UDP
dig +short +tcp @1.1.1.1 $D A     # TCP
curl -s -H 'accept: application/dns-json' \
  "https://cloudflare-dns.com/dns-query?name=$D&type=A"   # DoH, JSON format
curl -s "https://dns.alidns.com/resolve?name=$D&type=1"   # DoH, JSON format

On Windows, query over TCP with Resolve-DnsName $D -Server 1.1.1.1 -TcpOnly, or nslookup -vc example.com 1.1.1.1.

UDP resultTCP resultDoH resultLikely conclusion
SuspiciousNormalNormalA device on the link is forging UDP replies; leans toward pollution
SuspiciousSuspiciousNormalPlaintext port 53 is being redirected or tampered with across the board
SuspiciousSuspiciousSuspiciousSuspect the domain's own records or CDN routing first, then check RDAP
NormalNormalNormalResolution is fine; go back and troubleshoot the connection layer

There is also a direct test for pollution: send a query to an overseas host that you are sure runs no DNS service, such as one of your own cloud servers with port 53 closed.

dig +time=3 +tries=1 @<your-host-IP> example.com A

Normally this should time out. If you get a reply containing an IP, that reply can only have come from a device along the path. A packet capture makes it clearer:

sudo tcpdump -n -i any udp port 53 and host 1.1.1.1

In another terminal, run dig @1.1.1.1 example.com once. If one query gets two replies and the first to arrive disagrees with the DoH result, you are being raced by a forged reply.

Step 4: Use RDAP to see who owns the reply IP, and check reply timing

Once you have a suspicious IP, don't just judge whether it "looks right". Look up whose name it is registered under. RDAP is the structured replacement for WHOIS and returns JSON. The rdap.org service used below redirects the request to the RDAP server of the Regional Internet Registry (RIR) responsible for that range:

IP=203.0.113.10   # example address; replace with the IP you got
curl -sL "https://rdap.org/ip/$IP" | jq '{handle, name, country, startAddress, endAddress}'

How to judge:

  • The IP's range belongs to the site or to a CDN it publicly uses: the result is trustworthy, and the different IPs are just routing differences.
  • The range belongs to an entity unrelated to the site, or to your ISP: the result has likely been modified.
  • The reply is an address like 0.0.0.0, 127.0.0.1, 10.0.0.0/8 or 192.168.0.0/16: it could be a forged reply on the link, or a local or ISP filtering policy. A lookup that finds no public ownership in RDAP is itself a signal.

The egress IP intelligence on cdnping /ip also shows range registration info via RDAP, so you can use it to cross-check the command-line results.

Reply timing is useful too. The Query time at the end of dig output is how long that query took. Run ping 1.1.1.1 and note the round-trip time. If a query's Query time is clearly shorter than that round trip, the reply cannot have come from that resolver; it must have come from a device along the path. This rule only compares two numbers taken at the same moment, so you don't need to memorize any fixed threshold.

A checklist you can copy

  1. Check the hosts file to rule out hard-coded local records.
  2. Query the same domain with the system default resolver and 3 to 4 public resolvers, and note the answers.
  3. Use id.server, o-o.myaddr and whoami.akamai.net to confirm the query actually reached the intended resolver.
  4. Query a random nonexistent subdomain and check that you get NXDOMAIN.
  5. Query the same resolver over UDP, TCP and DoH and compare against the table.
  6. Send a query to a host that does not run DNS and see whether you get a reply.
  7. Look up the suspicious IP in RDAP, and judge it together with Query time and the ping round trip.
  8. Save screenshots or text of all of the above so you can report it to your ISP or network administrator.

What to do once you know

If the conclusion is hijacking, the target is clear: delete the entry from hosts; set the DNS settings in your router back to a resolver you trust, and change the router's default admin password while you are at it; if the ISP resolver is rewriting NXDOMAIN, report it to the ISP or switch to a trusted encrypted DNS. Setup steps are in the DNS over HTTPS setup guide. Afterward, go back to /en/ip and check that the resolver listed in the DNS leak test is now the one you configured.

If the conclusion is pollution on the link, this article stops at confirmation. It is not on your device or router, so changing local settings alone may not fix it; what you do about it should follow the laws and network service terms where you are. For development work, the more practical move is to note it in your troubleshooting log and keep checking the other layers. If a development tool can't connect, follow the four-layer checklist in Troubleshooting Claude Code connection timeouts and errors; for the full self-check order, see Developer network self-check checklist (2026 edition).

Related articles

Keep reading