AdGuardHome/PiHole in a IPv6 world (plus parental controls)

I debated myself as to whether this belongs under off topic or here. I decided to make it a solution because I know a lot of users use PiHole or AdguardHome for ad blocking and parental controls on their LAN and because Matter requires IPv6, openHAB users that use Matter could benefit.

Goals

Create LAN wide DNS blocking (malware, parental controls, ad/tracker blocking) in a dual stack IPv4/IPv6 network.

Assumptions

These instructions will be written from an opnSense plus AdGuardHome perspective all hosted on the same machine. You should be able to translate these to your router/firewall and DNS server of choice.

I chose opnSense because I used to use pfSense but didn’t like the directions they were moving in as a company. I chose AdGuardHome (AGH) because there’s an easily installable plug-in for opnSense and I like how easy it is to block whole services (e.g. all of Facebook). I chose Kea over Dnsmasq because Dnsmasq simply wasn’t working properly and Kea has better integration with Unbound.

If you already have opnSense configured with ISC or Dnsmasq with a bunch of mac to IP address mappings, you can export the mappings to a CSV file and then import them into Kea. This saved a ton of time. It also means you could problably use a tool like a spreadsheet to create your mappings manually. Just make sure to use simple all lower case hostnames.

Visually a DNS query will appear as follows:

Internet DNS request
[ client ] -> [ AGH ] -> [ Unbound ] -> [ 1.1.1.1 ]

LAN Device
[ client ] -> [ AGH ] -> [ Unbound ] -> [ Kea ]

Manually configured DNS on client
[ client ] -> [ firewall NAT rule ] -> [ AGH ] -> [ Unbound ] -> [ 1.1.1.1 ]

Client manually configured DoT
[ client ] -> [ firewall ] # blocked

Client using IPv6 address for DNS server
[ client ] -> [ firewall ] # blocked

Client using DNS over HTTPS
[client ] -> [ AGH ] # blocked

In the above, the arrow between Unbound and the upstream DNS server is DoT.

DNS over HTTPS can be enabled on a client by client basis in AGH if required.

Note: Google Gemini was critical in my being able to figure all this out. But, even with AI support, it took a lot of trial and error to get right. Below is a summary tutorial generated mostly by Gemini with some editing by me. It’s a little spare so if there are any specific questions you have please ask away and I’ll do my best to answer.


This tutorial reflects your final, high-performance configuration for OPNsense 26.1 (Witty Woodpecker). It ensures that Matter (IPv6) works seamlessly while every DNS query—even those attempting to bypass your settings—is captured, identified, and filtered by AdGuard Home.


The “DNS Hotel California” Strategy

Core Concept: Devices can “check in” to any DNS server they want (Google, Cloudflare), but they can never leave your network. They are silently redirected to AdGuard Home.

Phase 1: The Foundation (DHCP & IPv6)

  1. Kea DHCPv4: Assign static IPv4 addresses to all critical devices (your son’s tablet, Nest hubs, etc.) in Services > Kea DHCP > Subnets. These IPs act as the permanent “Client Identifiers” in AdGuard Home. I can provide more details on how I fully configured Kea DHCPv4. Do not configure Kea DHCPv6 and leave disabled.
  2. Muted IPv6: Go to Services > Router Advertisements > [LAN].
    • Mode: Stateless.
    • DNS Settings: Uncheck “Enable DNS” and leave the DNS/DNSSL fields empty.
    • Result: Devices get IPv6 for data (Matter/Streaming) but are forced to use the IPv4 path for DNS queries. This is important because AGH cannot see the MAC address in the DNS requests, only the IP. And reverse DNS only works for IPv4. Therefore we need to force all DNS traffic to IPv4.

Phase 2: Plugging the Loopholes (OPNsense Firewall)

Standard DNS is Port 53. Encrypted bypasses use Port 853 (DoT) or Port 443 (DoH).

1. The “Hook”: Force Redirect Port 53 (Destination NAT)

  1. Go to Firewall > NAT > Destination NAT.
  2. Add Rule:
    • Interface: LAN
    • Protocol: TCP/UDP
    • Destination / Invert: Check the box (Means: “Any address NOT this firewall”).
    • Destination: LAN address.
    • Destination Port: 53 (DNS).
    • Translation / Target IP: 127.0.0.1 (The local AdGuard Home).
    • Translation / Target Port: 53.
    • Action: pass (Automatically creates the necessary firewall rule).

This rule reroutes all DNS requests to AGH regardless of the IP address used. That keeps devices with a manually configured DNS from bypassing DNS.

2. The “Shield”: Block Port 853 (DNS-over-TLS)

  1. Go to Firewall > Rules > LAN.
  2. Add Rule (at the top):
    • Action: Block | Direction: in | Protocol: TCP/UDP.
    • Destination Port: 853.
    • Description: Block DoT Bypass.

Because TLS prevents man-in-the-middle intercepts we cannot reroute the traffic same as we do for unencrypted DNS on port 53. Therefore we just block it. But our upstream Unbound uses DoT so all DNS traffic leaving the LAN will still be encrypted.

3. The “Wall”: Block IPv6 DNS Bypass

  1. Go to Firewall > Rules > LAN.
  2. Add Rule (top):
    • Action: Block | IP Version: IPv6 | Protocol: TCP/UDP.
    • Destination Port: 53.
    • Description: Kill native IPv6 DNS bypass.

Optionally, you could modify this rule to just block all IPv6 traffic out of your LAN. I’ve done that in the past without problem but others have reported problems. YMMV.

The router advertisements above prevent any DNS configruation from going out to IPv6 clients. But if the clients have their own IPv6 DNS server addresses configured, this firewall rule prevents that from working, forcing the clients back to IPv4 DNS network traffic.


Phase 3: Upstream (Unbound Configuration)

  1. Non-standard port: Set the port to 53053
  2. Enable Reverse DNS: Enable “Register DHCP Static Mappings”
  3. Configure Upstream: Under “DNS over TLS” add as many upstream DNS servers as you prefer. All of the major servers support TLS (e.g. 1.1.1.1, 9.9.9.9, 4.4.4.4, etc). Use port 853.

This configures Unbound to resolve local hostnames and forward other DNS requests to the upstream DNS servers.


Phase 4: The Brain (AdGuard Home Configuration)

AGH filters the web, while Unbound (on port 53053) handles the local koshak.lan “phonebook.”

  1. Upstream Settings: Set Settings > DNS Settings > Upstream DNS Severs, Bootstrap DNS Servers, and Private reverse DNS servers to 127.0.0.1:53053. Ensure “Enable reverse DNS resolution” and “Ue reverse DNS servers” is checked.
  2. Client Identification: In Settings > Client Settings, add each device using its Static IPv4, MAC Address, and hostname as identifiers. You can use just the hostname in some cases but do not do so for devices that need exceptions to the blocking rules or additional blocking applied. The user can always change their hostname.
  3. Encrypted DNS Blocklist (The DoH Killer):
    • Go to Filters > DNS Blocklists.
    • Click Add Blocklist > Add a custom list.
    • Name: HaGeZi - Encrypted DNS Bypass.
    • URL: https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/doh-vpn-proxy-bypass.txt
    • Result: This prevents browsers from finding the “Front Door” to Google or Cloudflare’s Encrypted DNS servers, forcing them back to your filtered Port 53.

Phase 5: Verification (The “Acid Test”)

  1. Standard Test: On a Linux computer, run nmcli dev show | grep DNS. It should only show your OPNsense IPv4. This shows no IPv6 DNS addresses are being served.
  2. Redirect Test: Manually set your laptop DNS to 8.8.8.8. Browse the web. If your queries appear in the AGH log, the Destination NAT Hook is working.
  3. DoT Test: Run openssl s_client -connect 8.8.8.8:853. If it times out or just hangs, the Port 853 Shield is working.
  4. DoH Test: Try to visit dns.google in your browser. If it’s blocked, the HaGeZi Wall is working.

Final Configuration Layout

Traffic Type Destination Action Result
Standard DNS External IP Destination NAT Redirected to AdGuard Home
DoT (Encrypted) Any Firewall Block Fails; falls back to Standard DNS
DoH (HTTPS) Provider Domain AGH Blocklist Domain blocked; falls back to Standard DNS
Local DNS *.koshak.lan AGH → Unbound Resolved to local hostnames

Your network is now officially “Parent-Hardened” while remaining 100% compatible with modern IPv6/Matter smart home standards.

Which blocklists to use and your overall approach to parental controls is up to you. I recommend putting the most strict controls as the default. Then identify those devices which have exceptions to the controls. These devices will need a statically assigned IP from Kea meaning MAC randomization for your LAN needs to be turned off.

9 Likes

Note, since writing this tutorial I disconnected that the HaGeZi blocklist includes Tailscale. If you use Tailscale you may need to add exceptions to allow that to work.