Redirect Dns via Iptables

Redirect Dns via Iptables

Background

I've been stuggling to get a redirection working via iptables - a combination of restrictive capabilities of the s/w versions on DD-WRT and (more likely) my shoddy script.

We have a very limited bandwidth out to the internet on the network in question, and so I've deployed a number of measures to make utilisation more efficient e.g. ad blocking & replacement technology, traffic filtering, QoS prioritisation

I have the ISP-supplied router as the outer router, and an inner router running WiFi, LANs & VPN out to the internet.

Specific Problem

Among the list of enhancements is DNS caching on a dedicated server node, and redirection of all DNS requests to this server. Most of this is done via network settings in the dhcp servers, but some mobile & desktop apps are overriding this.

I use DNS upstream servers as targets from the LAN DNS server which I know are trustworthy. The inner router has a firewall script which is designed to apply a vpn killswitch and allow sticky IP's access outside of the VPN / straight out via our ISP (thanks a bunch Netflix).

However I'm struggling to get the DNS traffic redirection working on DD-WRT - I tested it on a combination of servers and desktops using dig and tcpdump, simulating a request being made to server A, redirected to server B, and the client getting a DNS response accordingly. That appeared to work as expected, but when I applied the same configuration to the inner router it has no effect. I can't see any traffic arriving at the DNS server when I fire a request out to a public resolver e.g. Cloudflare.

In fact the request is still blocked.

lanDns="dns server IP"

iptables -I FORWARD -s ! $lanDns -p tcp --dport 53 -j ACCEPT
iptables -I FORWARD -s ! $lanDns -p udp --dport 53 -j ACCEPT
iptables -t nat -A PREROUTING -s ! $lanDns -p tcp --dport 53 -j DNAT --to $lanDns:53
iptables -t nat -A PREROUTING -s ! $lanDns -p udp --dport 53 -j DNAT --to $lanDns:53

iptables -I FORWARD -s ! $lanDns -p tcp --dport 5353 -j ACCEPT
iptables -I FORWARD -s ! $lanDns -p udp --dport 5353 -j ACCEPT
iptables -t nat -A PREROUTING -s ! $lanDns -p tcp --dport 5353 -j DNAT --to $lanDns:53
iptables -t nat -A PREROUTING -s ! $lanDns -p udp --dport 5353 -j DNAT --to $lanDns:53

# secure DNS - TODO letsencrypt certificate for <servername>
iptables -t nat -A PREROUTING -s ! $lanDns -p tcp --dport 853 -j DNAT --to $lanDns:853
# allow direct DNS traffic from the LAN DNS server, don't need to drop as well as this will only interfere
iptables -A FORWARD -p tcp --dport 53 -s $lanDns -j ACCEPT
iptables -A FORWARD -p udp --dport 53 -s $lanDns -j ACCEPT

iptables output looks ok, but what am I missing? Is it as simple as ordering or just my poor iptables usage? :)

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DNAT       udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:53 to:[DNS server ip] 
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:53 to:[DNS server ip] 
DNAT       tcp  -- ![DNS server ip]       0.0.0.0/0           tcp dpt:53 to:[DNS server ip]:53 
DNAT       udp  -- ![DNS server ip]       0.0.0.0/0           udp dpt:53 to:[DNS server ip]:53 
DNAT       tcp  -- ![DNS server ip]       0.0.0.0/0           tcp dpt:5353 to:[DNS server ip]:53 
DNAT       udp  -- ![DNS server ip]       0.0.0.0/0           udp dpt:5353 to:[DNS server ip]:53 

iptables version on DD-WRT (Kong Ac): 1.3.7

Maya Lin-Takahashi
Author

Maya Lin-Takahashi

Maya is a hardware enthusiast who tests and reviews smart home devices, smartphones, wearables, and audio gear. She focuses on practical consumer value and build quality.