Andrew Mercer
on this page

Local DNS Resolution Failure Caused by OpenWrt Router Advertisements

Symptom

Mobile devices (Android/Pixel) on the LAN could not resolve internal hostnames served by OPNsense/Unbound and dnsmasq, while wired clients resolved them without issue. The phone's Wi-Fi DNS settings correctly showed OPNsense as the DNS server, but lookups for internal hostnames failed and public domains resolved via an unexpected upstream (8.8.8.8) instead of the expected resolver.

Environment

  • Firewall/router: OPNsense, using the dnsmasq DNS & DHCP plugin (not the legacy ISC DHCP + Unbound combination) for the LAN interface
  • Access points: two OpenWrt devices (prettyfly, wutanglan) configured as "dumb" bridged APs, with DHCPv4 (dhcp.lan.ignore=1) disabled on both
  • Client: Google Pixel phone (Android), IPv6-preferring by default

Diagnostic path

Ruled out, in order, before finding the actual cause:

  1. Android Private DNS (Settings → Network & internet → Private DNS) — confirmed off. Not the cause.
  2. VPN or DNS-filtering apps (AdGuard, NextDNS, etc.) intercepting DNS via Android's VPN API — none active.
  3. Static IP / hardcoded DNS on the Wi-Fi network config — confirmed set to DHCP, not static.
  4. OPNsense DHCP/DNS configuration — checked in order: - Services → DHCPv4 → LAN: no entry (LAN was already migrated to dnsmasq; ISC DHCP only had a leftover WAN entry) - Services → Dnsmasq DNS & DHCP → General/DHCP ranges: DNS server fields empty - System → Settings → General → DNS Servers: empty and unchecked - /conf/config.xml: grep -A2 -B2 "8.8.8.8" returned nothing — 8.8.8.8 was not hardcoded anywhere in the OPNsense config - Confirmed OPNsense's DHCP lease table did list the phone, so OPNsense's dnsmasq was in fact issuing the lease (not losing a DHCP race to a second server)
  5. A rogue/second DHCP server on the LAN — checked both OpenWrt APs' /etc/config/dhcp; neither had 8.8.8.8 in config, and no evidence of a competing DHCPv4 server.
  6. dnsmasq running on the APs themselves — this is what broke it open:

ps | grep dnsmasq netstat -lnp | grep :53

Both APs had dnsmasq actively listening on their own LAN IPv4 address and on unique-local IPv6 addresses (fdxx:.../64 ULA and link-local fe80::/64), even though each was intended to be a plain bridged access point with DHCPv4 disabled.

Root cause

Disabling DHCPv4 on an OpenWrt interface via dhcp.lan.ignore='1' stops the device from leasing IPv4 addresses, but does not disable Router Advertisements (RA). RA is controlled independently by dhcp.lan.ra, which defaults to 'server' if not explicitly set.

With RA still active (odhcpd running), both APs were advertising themselves as a DNS resolver over IPv6 via RDNSS, regardless of the IPv4 DHCP configuration. Android's Pixel prefers IPv6 when both stacks are available, so it picked up an AP's own IPv6 address as its DNS server from the RA — bypassing OPNsense's dnsmasq entirely and querying the AP's local dnsmasq instance instead, which forwarded upstream to 8.8.8.8. Because that path is IPv6 and per-RA rather than IPv4/DHCP, it never showed up in any of the IPv4-focused config locations checked earlier (OPNsense's config, the AP's /etc/config/dhcp DNS fields, Android's own DHCP/gateway details).

Confirmed on both APs:

uci get dhcp.lan.ra
# server

ps | grep odhcpd
# odhcpd running

Fix

On each OpenWrt AP, explicitly disable RA and DHCPv6 rather than relying on ignore (which only covers DHCPv4):

uci set dhcp.lan.ra='disabled'
uci set dhcp.lan.dhcpv6='disabled'
uci commit dhcp
/etc/init.d/odhcpd restart
/etc/init.d/dnsmasq restart

On the client, forget and rejoin the Wi-Fi network (or toggle Wi-Fi off and on) to flush any cached RA-derived IPv6 DNS server before retesting.

Verification

From a terminal on the client (e.g. Termux):

dig <internal-hostname>

Confirm the responding server matches OPNsense's LAN IP and that internal hostnames resolve correctly.

Notes / prevention

  • On OpenWrt, dhcp.lan.ignore='1' (disable DHCPv4) and RA are separate settings. A "dumb AP" configuration needs both DHCPv4 and RA/DHCPv6 explicitly disabled to fully stop the device from answering network-configuration or DNS queries.
  • When troubleshooting DNS-resolves-to-wrong-server issues on dual-stack networks, check IPv6 RA/RDNSS sources as early as checking DHCPv4, especially with IPv6-preferring clients like modern Android devices — the symptom (wrong DNS server used, correct one shown in UI) looks identical to a DHCPv4 problem but lives entirely on the IPv6 side.
  • ps | grep dnsmasq / ps | grep odhcpd plus netstat -lnp | grep :53 on each network device is a fast way to confirm whether something is actually listening and answering, independent of what its config files claim.
  • This was a longstanding OPNsense dnsmasq DNS/DHCP setup (migrated from ISC DHCP + Unbound), which meant guidance assuming Unbound was authoritative for DHCP needed to be redirected mid-troubleshoot to the dnsmasq plugin instead.