
This morning I woke up to discover that none of my devices could reach the internet. My OpenWrt router could ping external IPs just fine, DNS resolved from the router itself, and yet every client on my LAN was dead in the water. What followed was a two-hour debugging session that uncovered not one but three layered problems — any one of which would have been straightforward on its own, but stacked together they created a deceptively tricky outage.
Here’s what happened, what I learned, and how to avoid the same trap.
The Setup
I run OpenWrt 25.12.1 on a Linksys WRT series router, sitting behind Starlink (which means CGNAT on IPv4 and a global IPv6 address on WAN). For DNS filtering, I use AdGuardHome listening on port 53 on the LAN interface (192.168.1.1), with dnsmasq pushed to port 5353 as a backend for DHCP and local hostname resolution.
This is a common setup in the OpenWrt + AdGuardHome community, and it had been working well — until it wasn’t.
Problem 1: AdGuardHome’s Upstream DNS Was Broken
The first thing I noticed was that AdGuardHome’s logs were full of errors like this:
[error] dnsproxy: exchange failed upstream=https://dns10.quad9.net:443/dns-query
err="unexpected EOF"
I had configured AdGuardHome with a single upstream: https://dns10.quad9.net/dns-query (DNS-over-HTTPS to Quad9). No fallbacks. When that one upstream started failing — likely a TLS issue between Quad9 and my Starlink IP range — every uncached DNS query died.
The fix: Add multiple upstreams and fallbacks in /etc/adguardhome/adguardhome.yaml:
upstream_dns:
- https://cloudflare-dns.com/dns-query
- https://dns10.quad9.net/dns-query
- 1.1.1.1
- 9.9.9.9
fallback_dns:
- 1.1.1.1
- 9.9.9.9
upstream_mode: load_balance
With load_balance mode, AdGuardHome uses whichever upstream responds fastest. If DoH to Quad9 fails, plain DNS to Cloudflare or Google picks up immediately.
Lesson: Never rely on a single upstream DNS provider, especially with DNS-over-HTTPS. DoH adds a TLS dependency that can fail independently of basic connectivity. Always have plain DNS fallbacks.
Problem 2: IPv6 Was Leaking Upstream DNS to Clients
Here’s where it got interesting. After fixing the upstream DNS, the router could resolve everything perfectly — but my Windows PC still couldn’t browse. When I overrode DNS manually to 1.1.1.1, it worked. DHCP-assigned DNS didn’t.
The culprit: IPv6 Router Advertisements were handing out Starlink’s upstream IPv6 DNS servers directly to my clients.
OpenWrt was running DHCPv6 and sending Router Advertisements (RA) with DNS information (RDNSS). These included Starlink’s own IPv6 nameservers, which my Windows PC was preferring over the IPv4 DNS server (192.168.1.1) assigned via DHCPv4. Those Starlink DNS servers weren’t going through AdGuardHome at all — they were direct upstream servers that my clients had no business using.
When Quad9’s DoH was failing and AdGuardHome was struggling, some queries might have worked via IPv6 DNS and some wouldn’t, creating an intermittent, confusing failure that looked like “the internet is slow” rather than “DNS is broken.”
The fix:
# Disable IPv6 DNS assignment to clients
uci set dhcp.lan.dhcpv6='disabled'
uci set dhcp.lan.ra='disabled'
# Explicitly tell dnsmasq to advertise the router as DNS
uci add_list dhcp.lan.dhcp_option='6,192.168.1.1'
uci commit dhcp
/etc/init.d/odhcpd restart
/etc/init.d/dnsmasq restart
This forces all clients to use IPv4 DHCP only, with 192.168.1.1 (AdGuardHome) as their sole DNS server.
Lesson: If you’re running a DNS filter like AdGuardHome or Pi-hole on your router, you need to make sure IPv6 RA/DHCPv6 isn’t silently advertising alternative DNS servers to your clients. This is especially common on dual-stack setups with ISPs (or Starlink) that provide their own IPv6 DNS. Windows will happily prefer an IPv6 DNS server over an IPv4 one, completely bypassing your carefully configured ad blocker.
If you want to keep IPv6 active, make sure the RA advertises your router’s LAN IPv6 address as the DNS server, not the upstream ones.
Problem 3: AdGuardHome PTR Lookups Hitting Localhost
While reviewing logs, I spotted another error pattern:
[error] dnsproxy: exchange failed upstream=127.0.0.1:53
err="connection refused"
AdGuardHome had use_private_ptr_resolvers: true but local_ptr_upstreams: [] (empty). When empty, it defaults to 127.0.0.1:53 and [::1]:53 — but nothing listens on port 53 on localhost. AdGuardHome listens on 192.168.1.1:53, and dnsmasq is on port 5353.
The fix: Point PTR lookups at dnsmasq:
use_private_ptr_resolvers: true
local_ptr_upstreams:
- 192.168.1.1:5353
This gives you proper reverse DNS resolution (IP → hostname) using dnsmasq’s knowledge of DHCP leases, and eliminates the error spam.
The Debugging Process
What made this tricky was the layering. Each problem masked the others:
- The router could resolve DNS (cached results in AdGuardHome), so
nslookup google.com 192.168.1.1from the router worked — making it look like DNS was fine. - Clients couldn’t resolve DNS, but because they were using IPv6 DNS servers that bypassed AdGuardHome entirely, the problem wasn’t where I expected it.
- The intermittent nature (some queries worked via IPv6, some didn’t) made it feel like a network performance issue rather than a DNS configuration issue.
The breakthrough was checking what DNS servers the Windows client was actually using (ipconfig /all) and seeing IPv6 addresses — not 192.168.1.1. That pointed directly at the RA/DHCPv6 leak.
Checklist: AdGuardHome on OpenWrt
If you’re running a similar setup, here’s what to verify:
- Multiple upstream DNS servers — never just one, and include plain DNS alongside DoH/DoT
- Fallback DNS configured — not just upstreams, but explicit fallbacks in AdGuardHome
- IPv6 DNS controlled — either disable DHCPv6/RA, or ensure they advertise the router’s own IPv6 address as DNS
- DHCP option 6 set — explicitly tell dnsmasq to advertise
192.168.1.1as DNS viadhcp_option - PTR upstreams configured — point
local_ptr_upstreamsat dnsmasq’s port if you want reverse DNS - Test from a client, not the router — the router resolving DNS doesn’t mean clients can
Final Thought
The combination of AdGuardHome, OpenWrt, IPv6, and Starlink’s CGNAT creates a setup with a lot of moving parts. Each component is well-documented individually, but the interactions between them — especially around IPv6 DNS advertisement — can catch you off guard. The key takeaway: when debugging DNS issues, always check what DNS servers your clients are actually using, not what you think they should be using.
