Each network is different. I did this for my network which has multiple subnets and internal DNS servers sitting on the "server" subnet. The "server" subnet is excluded, since devices in there are more tightly controlled (and it would create a routing loop).
Granted, it may not be the best way, but here is how I did it:
- Create Firewall Alias group (type: hosts) with IP addresses of internal DNS servers (PiHoles, in my case).
- Create Firewall Alis group (type: URL Table IPs) for external DNS over HTTPs servers (content: https://raw.githubusercontent.com/jpgpi250/piholemanual/master/DOHipv4.txt)
- Create NAT Port Forward to route all traffic on port 53 to the alias (TCP/UDP, source: network, destination: !network on port 53, redirect target: DNS alias, redirect port: 53) for each network
- Each network (except the "server" network) has the below rule set (order is important)
- Allow TCP/UDP 53 to DNS alias
- Drop all TCP/UDP 53
- Drop all TCP/UDP 853
- Drop all TCP/UDP 443 traffic to external DNS over HTTPs alias group
Since NAT port forward rules are processed before interface/network rules, any device using port 53 for DNS (regardless of the IP address they have set) will automatically (and transparently) get redirected to my PiHole servers. The drops are in place so devices that try to use other common DNS methods are blocked. Generally, those devices will then default to the DHCP DNS servers.
I have been running this config for a few years and have found a few downsides:
- You can't visit websites that have the same addresses as their DNS hosts, ie: https://1.1.1.1
- Although https://github.com/jpgpi250/piholemanual is updated regularly, it has contained the odd false-positive (GitHub pages had a weird overlap at one point) breaking legitimate HTTPS traffic
- My PiHole servers are configured to allow queries from all origins (theoretical security risk)
Hope this helps! And remember to be careful when messing with DNS and clear those caches when testing.