A Pi-hole Block Reaches an AI Agent as an SSRF-Guard Error, Not a DNS Error¶
🛑 Problem¶
An AI coding agent (Claude Code, or anything with a web-fetch tool) refuses to fetch a perfectly ordinary URL:
Failed to fetch https://www.tecmint.com/...:
URL "www.tecmint.com" resolves to 0.0.0.0 — blocked
(link-local / IMDS / multicast / reserved)
This reads like a bug in the agent's fetch tool. It is not. It is a Pi-hole block, three layers of misdirection deep.
🔍 Why the Error Looks Like Something Else¶
Agent web-fetch tools ship an SSRF guard — they resolve the hostname before making a request and refuse to connect to addresses in reserved ranges (link-local, loopback, cloud metadata endpoints like 169.254.169.254, multicast). This is correct, important security behavior: it's what stops a prompt-injected agent from being aimed at internal infrastructure.
Pi-hole blocks a domain by answering 0.0.0.0.
0.0.0.0 is a reserved address. So the guard fires — correctly, on its own terms — and reports what it sees: a hostname resolving somewhere it refuses to go. It has no idea a DNS filter put it there. The error names the guard, never the block.
This is the same class of misdirection as a DNS block that looks like a TLS error, where a Pi-hole block surfaces in the browser as a bogus TLS warning. Different symptom, identical root cause, and in both cases the error message points away from DNS.
🩺 Diagnose¶
One command settles it. Ask the Pi-hole directly:
| Result | Meaning |
|---|---|
0.0.0.0 |
Pi-hole block. Stop debugging the agent. |
| Real IPs | Not DNS — look elsewhere. |
Find which list is responsible:
ssh majorpi "sudo pihole-FTL sqlite3 /etc/pihole/gravity.db \
\"SELECT a.address FROM gravity g JOIN adlist a ON g.adlist_id = a.id \
WHERE g.domain = 'www.tecmint.com';\""
On majorpi the usual culprits, by blast radius: HaGeZi TIF (~1.6M) > Super-SEO-Spam-Suppressor (~815k) > OISD (~485k) > uBlockOrigin HUGE AI. Ordinary tech-content sites (tecmint.com, www.thegamer.com) get swept up by the SEO-spam list; AI endpoints by the last two.
✅ Fix — Both Steps, Or It Regresses¶
1. Allow it live¶
Allow the apex and the www. variant — an agent fetching https://www.example.com is blocked by www.example.com even when the apex is allowed.
2. Codify it in Ansible — this step is not optional¶
pihole allow mutates the live gravity.db only.
On this fleet, gravity.db is fully reproducible from Ansible. A live-only allow is silently dropped on the next reflash or Teleporter restore — and it comes back as a symptom that doesn't look like DNS.
Add the domain to pihole_allowlist in group_vars/pihole/vars.yml, then verify Ansible agrees with the live state:
changed=0 here means the declared config already matches the Pi. If it reports a change, the two have drifted.
🔁 Quick Reference¶
# Is it Pi-hole? (the only question that matters first)
dig +short <domain> @192.168.50.238 # 0.0.0.0 = blocked
# Allow (live)
ssh majorpi "pihole allow <domain> www.<domain>"
# Codify (permanent) — MajorAnsible
# group_vars/pihole/vars.yml → pihole_allowlist
ansible-playbook pihole.yml --tags domainlist --check
Tip
Heuristic: any agent tool that reports a URL "resolving to 0.0.0.0", or refusing an address as reserved / link-local / IMDS, is describing a DNS block. Reach for dig before you file a bug against the tool.
See Also¶
- A DNS Block That Looks Like a TLS Error — same root cause, surfaces as a browser TLS warning
- Pi-hole AI Blocklist Blocks Claude Desktop — same root cause, surfaces as
ERR_CONNECTION_REFUSED - Pi-hole v6 Adlist Management via SQL — managing the adlists that cause these false positives
- obsidian-skills — Teaching Claude Code Obsidian's Syntax — the article this block was found while trying to read