'Force Clients To Use Router DNS Servers' breaks when using a local DNS server
When using Force Clients To Use Router DNS Servers configured with a local DNS server, DNS requests get trapped in a loop per these firewall rules. Is there any appetite to change these rules to something more akin to:
iptables -t nat -I zone_lan_prerouting !-s [DNS_SERVER1] -p tcp --dport 53 -j DNAT --to [DNS_SERVER1]
iptables -t nat -I zone_lan_prerouting !-s [DNS_SERVER1] -p udp --dport 53 -j DNAT --to [DNS_SERVER1]
//repeat for all DNS servers entered
Or would adding logic to the shell script to only apply the above rules for local DNS servers and use the REDIRECT rules by default be more appropriate?
Just for my understanding, you’re saying that in the case where a local DNS server is used (not on the router, and not somewhere on the WAN side):
- the client sends request to router
- router redirects to local DNS
- local DNS sends request to remote DNS
- router redirects to local DNS
Is that the gist?
Exactly.
Should the rule still be REDIRECT? The router should still be the end point.
The DNAT rule would only apply under Option 6 right?
This would make the rule much simpler.
Yes, well spotted.
To be clear, you mean the rules should read:
iptables -t nat -I zone_lan_prerouting !-s [DNS_SERVER1] -p tcp --dport 53 -j REDIRECT
//etc
Yes, however in the case of multiple servers, we can comma separate them under the source field. If we don’t do this, we need to do packet marking.
I think this rule can be applied at all times, as the source should never be outside the LAN subnet in that table/chain. So this probably simplifies the shell logic also.
If you’re in a position to test this, that would be good.
I’m running the REDIRECT version with just my lone internal DNS right now and it’s working. I’ll test adding external DNS servers with an internal DNS server and just external DNS servers tonight. Thanks for the help.
Thanks, please let me know outcomes of additional tests.
So I ran into a problem in my other tests:
iptables v1.4.21: ! not allowed with multiple source or destination IP addresses
Try `iptables -h' or 'iptables --help' for more information.
I tried adding a new chain just to test:
force_router_dns()
{
force_router_dns=$(uci get firewall.@defaults[0].force_router_dns 2> /dev/null)
if [ "$force_router_dns" = "1" ] ; then
iptables -t nat -N dns_list
dnslist=$(uci get network.lan.dns 2> /dev/null)
for dns in $dnslist ; do
iptables -t nat -I zone_lan_prerouting ! -s "$dns" -p tcp --dport 53 -j dns_list
iptables -t nat -I zone_lan_prerouting ! -s "$dns" -p udp --dport 53 -j dns_list
done
iptables -t nat -A dns_list -j REDIRECT
fi
}
This worked in all configurations, but I haven't tested extensively. Is this reasonable?
No, not quite. Packers from the second dns server will fail the first set of rules.
Ah of course. I didn’t realize how dependent I am on my boolean ANDs and ORs.
On Thu, Feb 28, 2019 at 10:20 PM Michael [email protected] wrote:
No, not quite. Packers from the second dns server will fail the first set of rules.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ericpaulbishop/gargoyle/issues/794#issuecomment-468537180, or mute the thread https://github.com/notifications/unsubscribe-auth/ACh0tw8vHVdRo4oZq7oNosd02Ev6MFBpks5vSKqhgaJpZM4bV7Np .
I need to ACCEPT all my port 53 traffic from my dns servers. And then add a rule to REDIRECT the rest of port 53 traffic. How’s that?
force_router_dns()
{
force_router_dns=$(uci get firewall.@defaults[0].force_router_dns 2> /dev/null)
if [ "$force_router_dns" = "1" ] ; then
dnslist=$(uci get network.lan.dns 2> /dev/null)
for dns in $dnslist ; do
iptables -t nat -I zone_lan_prerouting -s "$dns" -p tcp --dport 53 -j ACCEPT
iptables -t nat -I zone_lan_prerouting -s "$dns" -p udp --dport 53 -j ACCEPT
done
iptables -t nat -I zone_lan_prerouting -p udp --dport 53 -j REDIRECT
iptables -t nat -I zone_lan_prerouting -p tcp --dport 53 -j REDIRECT
fi
}
I probably need to flip that order or change to append but that’s the gist.
Potentially bad, as this causes the packets to finish the chain early. I’m not sure if there are other things in that chain that come afterwards that would be needed? I think the correct method is to mark the packets based on source, check the mark and redirect if necessary, then clear the mark
Ok, I’ll look at that tomorrow. Thanks for the continued feedback.
IPSets are a potential solution to this problem, however the ipset kmod is not currently required on all targets (it is a dependency of Tor, which is not installed by default on all targets). However, i am working on another change which would make ipset kmod mandatory for all targets, which might then make this ok.