How to Check If Your ISP Is Hijacking DNS (Switching to 1.1.1.1 Won't Fix It)
Karthikey Hegde's Podman container couldn't reach a site. Almost all of their plaintext lookups, through Google DNS, Cloudflare and others, returned the same IP, and that IP belonged to their ISP. Cloudflare's DoH endpoint returned the real address.
So if a site won't load on your connection but works elsewhere, and a forum told you to set your DNS to 1.1.1.1 or 8.8.8.8, that advice may have changed nothing. These commands check whether your ISP is hijacking your DNS, and the table further down ranks the fixes that still work when it is.
Why changing DNS to 1.1.1.1 or 8.8.8.8 does nothing here
A plaintext query to 1.1.1.1 is a UDP packet to port 53 with no authentication. The IP in @1.1.1.1 is only a destination address. Anything on the path can catch that packet and reply while pretending to be Cloudflare, and dig has no way to tell. As bityard put it in the Lobsters thread, UDP DNS interception and rewriting is trivial.
That means several resolvers agreeing proves very little, because you may be talking to one box with several names. Hegde says in the same thread that their ISP tampers with all DNS traffic over port 53, which also catches a self-hosted recursive Unbound.
Hegde's post only has screenshots, so these are the standard commands for the same test.
How to check if your ISP is hijacking DNS
Use the domain that fails for you. Don't bother with google.com, because an ISP filtering a blocklist leaves it alone.
D=example.com # the domain that fails for you
# 1. Plaintext, against several public resolvers
for r in 1.1.1.1 8.8.8.8 9.9.9.9; do
echo "== $r"; dig +short +time=2 +tries=1 "$D" @"$r"
done
# 2. Same question over HTTPS, which the ISP can't rewrite in transit
curl -s -H 'accept: application/dns-json' \
"https://cloudflare-dns.com/dns-query?name=$D&type=A" | jq -r '.Answer[]?.data'
# 3. Who owns the plaintext answer? Paste the IP from step 1.
whois 203.0.113.7 | grep -iE '^(orgname|org-name|netname|descr):'
The DoH endpoint and accept header come from Cloudflare's docs. 203.0.113.7 is a placeholder. dig +short may print CNAMEs before the IPs, and the order of multiple A records changes between queries, so compare the set of IPs.
Interception can also be partial. One Let's Encrypt forum user found their ISP only touched 53/udp, and a Lobsters commenter saw IPv4 and IPv6 behave differently on the same ISP. Test both:
dig +short +tcp "$D" @1.1.1.1
dig +short -6 "$D" @2606:4700:4700::1111
If the second command says network unreachable, your machine has no IPv6 route, so that test tells you nothing.
How to read the result: tampering or just a CDN?
A mismatch alone proves nothing. CDNs hand out different IPs by location, and Cloudflare doesn't send EDNS Client Subnet, so its answers can differ from a resolver that does. OONI warns about the same false positives in its own measurements. Start with whois, then use the certificate check under the table if the IP belongs to your ISP.
| Plaintext vs DoH | Owner of the plaintext IP | What it means |
|---|---|---|
| Same | Anyone | No sign of tampering on this name. Look elsewhere. |
| Different | A CDN or the site's host | Probably geography, so you have no case |
| Different | Your ISP | Probably tampering, same as Hegde's case. Run the certificate check. |
| Plaintext fails, DoH answers | n/a | Interference or a broken path. Run the whoami test below. |
| DoH fails too | n/a | Your ISP may block DoH as well. Try another endpoint. |
An ISP-owned IP can still be legitimate, because CDNs such as Netflix and Google put cache servers inside ISP networks. So make that IP prove it can serve the site over TLS:
IP=203.0.113.7 # the plaintext answer
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 10 --resolve "$D:443:$IP" "https://$D/"
Any HTTP status means the box holds a valid certificate for that name. A curl: (60) certificate error means it doesn't, and that's what you get pointing example.com at 8.8.8.8. As Psentee notes in the Lobsters thread, most ISPs can't easily mint certs for any domain. A timeout is weaker evidence, since it could be a dead box or a block on that IP.
Check the path itself with whoami.ds.akahelp.net
The domain test only catches tampering on that one name. Akamai's debug hostname tests the path:
dig +short TXT whoami.ds.akahelp.net @1.1.1.1
dig +short TXT whoami.ds.akahelp.net @8.8.8.8
The ns field is the address that reached Akamai's server. Big resolvers contact authoritative servers from their own ranges, so a Cloudflare query should show a Cloudflare address. The ns lines from a clean connection look like this, and whois puts them at Cloudflare and Google LLC:
"ns" "2400:cb00:523:1024::ac47:6d93"
"ns" "172.253.235.19"
In the forum thread above, a query to 1.1.1.1 came back with "ns" "151.5.216.254", and whois traced that to WIND, the poster's network operator.
A reply with no ecs field is also suspicious. mnordhoff gives that rule for 8.8.8.8 in the thread, and Cloudflare's FAQ names this hostname as its one ECS exception, so it should apply to 1.1.1.1 too. A clean result doesn't clear your ISP, though, because "an improbably clever interceptor could lie". If you want a measurement you can compare against a control server, OONI does that, and robalex recommends it in the Lobsters thread.
DNSSEC detects this on about 7% of domains
The usual reply is "just use DNSSEC". The November 2026 Defaults.Exposed census counts 23,854,462 of 334,831,177 graded domains as DNSSEC signed and valid, 7.1%. Hegde's post cites the October edition at 7.03%. That's a count of domains, dead ones included, so it says nothing about what share of your traffic is covered.
Without a valid chain, a validator has nothing to catch a forged answer with. On the signed minority, you only benefit if you validate locally, because a validating 1.1.1.1 does nothing for you when the ISP answers in its place. And a failed validation gets you SERVFAIL rather than the real IP. You learn about the tampering and the site stays down. DNSSEC also doesn't encrypt anything, so the ISP still reads your queries.
Fixes for ISP DNS hijacking, ranked
| Fix | Beats port 53 interception? | The catch |
|---|---|---|
| dnscrypt-proxy behind AdGuard | Yes, for the whole LAN | Most setup |
| Unbound with a DoT forward-zone | Yes | Port 853 is easy to block |
| systemd-resolved with DoT | Yes, one machine | Same port 853 problem |
| Browser DoH | Yes, that browser only | Containers and CLI tools still use port 53 |
| Plain recursive Unbound | No | Its queries are usually plaintext UDP |
| DNSSEC alone | No, it only detects | About 7% of domains, and you get SERVFAIL |
My pick is the first row. Hegde hit this because a Podman container couldn't reach a site, and a browser toggle never touches that traffic. Their setup is AdGuard as local DNS with dnscrypt-proxy handling upstream. Move the proxy off port 53, since AdGuard needs it. Avoid 5353 as well, because that's the mDNS port and dnscrypt-proxy dies with bind: address already in use if Avahi or anything else holds it. Change these two lines in your copy of the example config:
# dnscrypt-proxy.toml
listen_addresses = ['127.0.0.1:5300']
server_names = ['cloudflare']
# AdGuardHome.yaml
dns:
upstream_dns:
- 127.0.0.1:5300
The example config lists plaintext bootstrap_resolvers, and that looks alarming until you read the comment above them. They're for one-shot bootstrap lookups, and your queries are never sent to them. The cloudflare entry is DoH, so this runs over port 443 and doesn't care about a block on 853. Point DHCP at AdGuard, then rerun dig +short "$D" @<adguard-ip> and compare with the DoH answer.
If you already run Unbound, forward it over TLS. Without a CA bundle, the connection can't be authenticated. The bundle path below is Debian's, and the hostname is Cloudflare's documented one.
server:
tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
forward-zone:
name: "."
forward-tls-upstream: yes
forward-addr: 1.1.1.1@853#one.one.one.one
forward-addr: 1.0.0.1@853#one.one.one.one
Both proxies were tested with these exact settings: dnscrypt-proxy 2.1.20 logged [cloudflare] OK (DoH) and Unbound 1.26.2 answered queries through that forward-zone. The test connection had no tampering, so that shows the configs work and says nothing about a given ISP's blocks.
On a single Linux box, systemd-resolved needs three lines in /etc/systemd/resolved.conf:
[Resolve]
DNS=1.1.1.1#one.one.one.one 1.0.0.1#one.one.one.one
DNSOverTLS=yes
Domains=~.
Before committing to DoT, check that port 853 is reachable with Cloudflare's own test: kdig -d @1.1.1.1 +tls-ca +tls-host=one.one.one.one example.com. bazzargh reports in the Lobsters thread that Virgin Media in the UK tampers with port 53, blocks DoT outright and blocks DoH to some well-known servers. They got out by finding a DoH server Virgin hadn't blocked and running Pi-hole with Unbound. If you can't find one either, Hegde's suggestion in that thread is to tunnel DNS over WireGuard to a relay.
What encrypted DNS still doesn't fix
The resolver operator can still alter answers, so you're picking who gets to lie to you. I'd still choose a company with a published policy over an ISP doing it silently. vpr's preference for ODoH through dnscrypt-proxy is reasonable. Hegde uses Anonymized DNSCrypt instead, and is skeptical of ODoH because Apple and Cloudflare started it, and because of some relay providers' privacy policies.
Your ISP also still sees the hostname through SNI unless the browser and the site both use ECH, and it can sometimes infer the site from the destination IP. If the site stays unreachable after DNS comes back correct, the block has moved down a layer and no resolver will help. Hegde runs Mullvad through a Tailscale exit node for this, which hands the same trust question to the VPN provider.
The live argument in the thread is about DoH itself. bityard objects that DoT and DoH let software bypass local network controls, xetera says DoH is the real offender because DoT on 853 is easy to block, and Psentee doubts the two problems can be reconciled at all. My view: a filter on a network you run should be enforced on the devices you run. Losing a network-level DNS filter is a fair price for making silent rewrites by a carrier harder.
If you think DoH does more harm than the rewriting it stops, make that case below. And once you've run the check: is your ISP tampering with your DNS, and which ISP is it?
Sources
- So my ISP was hijacking my DNS, Karthikey Hegde
- Lobsters discussion
- Defaults.Exposed domain security census
- How to detect MITM on DNS?, Let's Encrypt community
- unbound.conf manual
- dnscrypt-proxy example config
- AdGuard Home configuration
- Cloudflare 1.1.1.1 FAQ
- OONI Web Connectivity
Mentions
8.0.4のSockFilterを使ってるといろんなアプリで不具合が出るらしい →AdguardForWindows#6308 とりあえずWFPドライバなら大丈夫だそうで次のアプデまでの回避策としてこれしかないかー
How to Check If Your ISP Is Hijacking DNS (Switching to 1.1.1.1 Won't Fix It) Karthikey Hegde's Podman container couldn't reach a site. Almost all of their plaintext lookups, through Google DNS, Cloudflare and others, returned the same IP, and that IP belonged to their ISP. Cloudflare's DoH endpoint returned the real address. So if a site won't load on your connection but works elsewhere, and a forum told you to set your DNS to 1.1.1.1 or 8.8.8.8, that advice may have changed nothing. These commands check whether your ISP is hijacking your DNS, and the table further down ranks the fixes that still work when it is. Why changing DNS to 1.1.1.1 or 8.8.8.8 does nothing here A plaintext query to 1.1.1.1 is a UDP packet to port 53 with no authentication. The IP in @1.1.1.1 is only a destination address. Anything on the path can catch that packet and reply while pretending to be Cloudflare, and dig has no way to tell. As bityard put it in the Lobsters thread, UDP DNS interception and rewriting is trivial. That means several resolvers agreeing proves very little, because you may be talking to one box with several names. Hegde says in the same thread that their ISP tampers with all DNS traffic over port 53, which also catches a self-hosted recursive Unbound. Hegde's post only has screenshots, so these are the standard commands for the same test. How to check if your ISP is hijacking DNS Use the domain that fails for you. Don't bother with google.com, because an ISP filtering a blocklist leaves it alone. D=example.com # the domain that fails for you # 1. Plaintext, against several public resolvers for r in 1.1.1.1 8.8.8.8 9.9.9.9; do echo "== $r"; dig +short +time=2 +tries=1 "$D" @"$r" done # 2. Same question over HTTPS, which the ISP can't rewrite in transit curl -s -H 'accept: application/dns-json' \ "https://cloudflare-dns.com/dns-query?name=$D&type=A" | jq -r '.Answer[]?.data' # 3. Who owns the plaintext answer? Paste the IP from step 1. whois 203.0.113.7 | grep -iE '^(orgname|org-name|netname|descr):' The DoH endpoint and accept header come from Cloudflare's docs. 203.0.113.7 is a placeholder. dig +short may print CNAMEs before the IPs, and the order of multiple A records changes between queries, so compare the set of IPs. Interception can also be partial. One Let's Encrypt forum user found their ISP only touched 53/udp, and a Lobsters commenter saw IPv4 and IPv6 behave differently on the same ISP. Test both: dig +short +tcp "$D" @1.1.1.1 dig +short -6 "$D" @2606:4700:4700::1111 If the second command says network unreachable, your machine has no IPv6 route, so that test tells you nothing. How to read the result: tampering or just a CDN? A mismatch alone proves nothing. CDNs hand out different IPs by location, and Cloudflare doesn't send EDNS Client Subnet, so its answers can differ from a resolver that does. OONI warns about the same false positives in its own measurements. Start with whois, then use the certificate check under the table if the IP belongs to your ISP. | Plaintext vs DoH | Owner of the plaintext IP | What it means | |---|---|---| | Same | Anyone | No sign of tampering on this name. Look elsewhere. | | Different | A CDN or the site's host | Probably geography, so you have no case | | Different | Your ISP | Probably tampering, same as Hegde's case. Run the certificate check. | | Plaintext fails, DoH answers | n/a | Interference or a broken path. Run the whoami test below. | | DoH fails too | n/a | Your ISP may block DoH as well. Try another endpoint. | An ISP-owned IP can still be legitimate, because CDNs such as Netflix and Google put cache servers inside ISP networks. So make that IP prove it can serve the site over TLS: IP=203.0.113.7 # the plaintext answer curl -sS -o /dev/null -w '%{http_code}\n' --max-time 10 --resolve "$D:443:$IP" "https://$D/" Any HTTP status means the box holds a valid certificate for that name. A curl: (60) certificate error means it doesn't, and that's what you get pointing example.com at 8.8.8.8. As Psentee notes in the Lobsters thread, most ISPs can't easily mint certs for any domain. A timeout is weaker evidence, since it could be a dead box or a block on that IP. Check the path itself with whoami.ds.akahelp.net The domain test only catches tampering on that one name. Akamai's debug hostname tests the path: dig +short TXT whoami.ds.akahelp.net @1.1.1.1 dig +short TXT whoami.ds.akahelp.net @8.8.8.8 The ns field is the address that reached Akamai's server. Big resolvers contact authoritative servers from their own ranges, so a Cloudflare query should show a Cloudflare address. The ns lines from a clean connection look like this, and whois puts them at Cloudflare and Google LLC: "ns" "2400:cb00:523:1024::ac47:6d93" "ns" "172.253.235.19" In the forum thread above, a query to 1.1.1.1 came back with "ns" "151.5.216.254", and whois traced that to WIND, the poster's network operator. A reply with no ecs field is also suspicious. mnordhoff gives that rule for 8.8.8.8 in the thread, and Cloudflare's FAQ names this hostname as its one ECS exception, so it should apply to 1.1.1.1 too. A clean result doesn't clear your ISP, though, because "an improbably clever interceptor could lie". If you want a measurement you can compare against a control server, OONI does that, and robalex recommends it in the Lobsters thread. DNSSEC detects this on about 7% of domains The usual reply is "just use DNSSEC". The November 2026 Defaults.Exposed census counts 23,854,462 of 334,831,177 graded domains as DNSSEC signed and valid, 7.1%. Hegde's post cites the October edition at 7.03%. That's a count of domains, dead ones included, so it says nothing about what share of your traffic is covered. Without a valid chain, a validator has nothing to catch a forged answer with. On the signed minority, you only benefit if you validate locally, because a validating 1.1.1.1 does nothing for you when the ISP answers in its place. And a failed validation gets you SERVFAIL rather than the real IP. You learn about the tampering and the site stays down. DNSSEC also doesn't encrypt anything, so the ISP still reads your queries. Fixes for ISP DNS hijacking, ranked | Fix | Beats port 53 interception? | The catch | |---|---|---| | dnscrypt-proxy behind AdGuard | Yes, for the whole LAN | Most setup | | Unbound with a DoT forward-zone | Yes | Port 853 is easy to block | | systemd-resolved with DoT | Yes, one machine | Same port 853 problem | | Browser DoH | Yes, that browser only | Containers and CLI tools still use port 53 | | Plain recursive Unbound | No | Its queries are usually plaintext UDP | | DNSSEC alone | No, it only detects | About 7% of domains, and you get SERVFAIL | My pick is the first row. Hegde hit this because a Podman container couldn't reach a site, and a browser toggle never touches that traffic. Their setup is AdGuard as local DNS with dnscrypt-proxy handling upstream. Move the proxy off port 53, since AdGuard needs it. Avoid 5353 as well, because that's the mDNS port and dnscrypt-proxy dies with bind: address already in use if Avahi or anything else holds it. Change these two lines in your copy of the example config: # dnscrypt-proxy.toml listen_addresses = ['127.0.0.1:5300'] server_names = ['cloudflare'] # AdGuardHome.yaml dns: upstream_dns: - 127.0.0.1:5300 The example config lists plaintext bootstrap_resolvers, and that looks alarming until you read the comment above them. They're for one-shot bootstrap lookups, and your queries are never sent to them. The cloudflare entry is DoH, so this runs over port 443 and doesn't care about a block on 853. Point DHCP at AdGuard, then rerun dig +short "$D" @<adguard-ip> and compare with the DoH answer. If you already run Unbound, forward it over TLS. Without a CA bundle, the connection can't be authenticated. The bundle path below is Debian's, and the hostname is Cloudflare's documented one. server: tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt forward-zone: name: "." forward-tls-upstream: yes forward-addr: 1.1.1.1@853#one.one.one.one forward-addr: 1.0.0.1@853#one.one.one.one Both proxies were tested with these exact settings: dnscrypt-proxy 2.1.20 logged [cloudflare] OK (DoH) and Unbound 1.26.2 answered queries through that forward-zone. The test connection had no tampering, so that shows the configs work and says nothing about a given ISP's blocks. On a single Linux box, systemd-resolved needs three lines in /etc/systemd/resolved.conf: [Resolve] DNS=1.1.1.1#one.one.one.one 1.0.0.1#one.one.one.one DNSOverTLS=yes Domains=~. Before committing to DoT, check that port 853 is reachable with Cloudflare's own test: kdig -d @1.1.1.1 +tls-ca +tls-host=one.one.one.one example.com. bazzargh reports in the Lobsters thread that Virgin Media in the UK tampers with port 53, blocks DoT outright and blocks DoH to some well-known servers. They got out by finding a DoH server Virgin hadn't blocked and running Pi-hole with Unbound. If you can't find one either, Hegde's suggestion in that thread is to tunnel DNS over WireGuard to a relay. What encrypted DNS still doesn't fix The resolver operator can still alter answers, so you're picking who gets to lie to you. I'd still choose a company with a published policy over an ISP doing it silently. vpr's preference for ODoH through dnscrypt-proxy is reasonable. Hegde uses Anonymized DNSCrypt instead, and is skeptical of ODoH because Apple and Cloudflare started it, and because of some relay providers' privacy policies. Your ISP also still sees the hostname through SNI unless the browser and the site both use ECH, and it can sometimes infer the site from the destination IP. If the site stays unreachable after DNS comes back correct, the block has moved down a layer and no resolver will help. Hegde runs Mullvad through a Tailscale exit node for this, which hands the same trust question to the VPN provider. The live argument in the thread is about DoH itself. bityard objects that DoT and DoH let software bypass local network controls, xetera says DoH is the real offender because DoT on 853 is easy to block, and Psentee doubts the two problems can be reconciled at all. My view: a filter on a network you run should be enforced on the devices you run. Losing a network-level DNS filter is a fair price for making silent rewrites by a carrier harder. If you think DoH does more harm than the rewriting it stops, make that case below. And once you've run the check: is your ISP tampering with your DNS, and which ISP is it? Sources - So my ISP was hijacking my DNS, Karthikey Hegde - Lobsters discussion - Defaults.Exposed domain security census - How to detect MITM on DNS?, Let's Encrypt community - unbound.conf manual - dnscrypt-proxy example config - AdGuard Home configuration - Cloudflare 1.1.1.1 FAQ - OONI Web Connectivity
Updated AdGuard Home to v0.107.80 on home DNS servers. github.com/AdguardTeam/AdGuardHome/releases/tag/v…
LOL someone tried to get my website added to Adguard content blockers because I have "subscribe to my RSS" (as a single line of text, no less!) AdguardFilters#244083
@Kdroidwin1 gigazine. net · Issue #104224 · AdguardTeam/AdguardFilters AdguardFilters#104224 すいません、このIssuesと勘違いして記憶していたようです
Huge props to @AdGuard for this absolute masterpiece of network-wide blocking—the zero-overhead DNS-level routing combined with that slick admin dashboard is a total game changer 🛡️ 🔗 项目地址:AdguardTeam/AdGuardHome
Adguard + Adguard VPN + Local Home Assistant and Android setting question I've got Adguard and Adguard VPN enabled trough this setup. Proxy/SOCKS5. It works fine, been using it for a few months. I have it configerd like that because I want to use the Android VPN settings: Always-on VPN and Block connections without VPN. Here comes the funny bit... With everything enabled I can't access my Local Home Assistant, when I disable the Android VPN setting Block connections wtihout VPN, it works. I'm able to access my HA. I tried SO much stuff, enable certain settings/ excluding HA. I just can't find the sollution. And might just think it's something that Android (Block connections without VPN) is doing. Since it's the setting that messes it up.
AdGuard Homeのクライアント設定が効かない? 症状 クライアント設定をしたところ、Androidスマートフォンには設定した通りの効果が出るが、WindowsPCの方では何故か設定の効果が出ない、正確に言うとIPv4での問い合わせでは期待通りの設定が効いているが、IPv6での問い合わせでは効果が出ない。 環境 AdGuard Home: v0.107.79 稼働環境(自宅サーバ): Debian(6.1.0-54-amd64)上のDocker クライアント: デスクトップPC(Windows11), Androidスマートフォン 原因 AdGuardHomeの既知の不具合 リンクローカルIPv6の「ゾーン」処理に関する既知バグのようです。 リンクローカルIPv6(fe80::…)からのDNS問い合わせは、AdGuard Home内部では送信元アドレスにゾーン(インターフェース名)が付いた形、たとえば fe80::xxxx%eth0 として処理されます。 このため識別子として登録した fe80::xxxx:xxxx:xxxx:xxxx と完全一致せず、設定が適用されません。 (ちなみに、クエリログの名前表示についてはゾーンを剥がして照合するため、ゾーンなしで登録した fe80::xxxx… に完全一致し、設定したクライアント名が表示されます。) 参考リンク 不具合 修正PR 回避策 識別子を /128 CIDR で登録 設定適用時のCIDR照合はゾーンを剥がして行われるため ※リンクローカルアドレスの値はテキトーな数値に置き換えています。 補足 AdGuard Homeのバージョンが上がれば問題は解消されると思います。
YouTube player always enables captions on iOS 27 Hello! I was wondering if anyone had found a way to get captions to stop enabling for every video when sharing from the YouTube app on iOS. This was introduced by a change in the behavior of the system accessibility apis in iOS 27 (see AdguardForiOS#2539) I know this isn’t something AdGuard can fix so I was curious if anyone had found a way to set up their iOS device settings which resulted in this not happening
AdGuard is starting to use AI to develop filters AdguardTeam/FiltersAgent They are using it in AdguardFilters repo.