gargoyle icon indicating copy to clipboard operation
gargoyle copied to clipboard

'Force Clients To Use Router DNS Servers' breaks when using a local DNS server

Open dquam opened this issue 6 years ago • 16 comments

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?

dquam avatar Feb 28 '19 03:02 dquam

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?

lantis1008 avatar Feb 28 '19 03:02 lantis1008

Exactly.

dquam avatar Feb 28 '19 03:02 dquam

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.

lantis1008 avatar Feb 28 '19 03:02 lantis1008

Yes, well spotted.

dquam avatar Feb 28 '19 04:02 dquam

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

dquam avatar Feb 28 '19 04:02 dquam

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.

lantis1008 avatar Feb 28 '19 04:02 lantis1008

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.

dquam avatar Feb 28 '19 12:02 dquam

Thanks, please let me know outcomes of additional tests.

lantis1008 avatar Feb 28 '19 21:02 lantis1008

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?

dquam avatar Mar 01 '19 04:03 dquam

No, not quite. Packers from the second dns server will fail the first set of rules.

lantis1008 avatar Mar 01 '19 04:03 lantis1008

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 .

dquam avatar Mar 01 '19 04:03 dquam

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?

dquam avatar Mar 01 '19 04:03 dquam

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.

dquam avatar Mar 01 '19 04:03 dquam

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

lantis1008 avatar Mar 01 '19 04:03 lantis1008

Ok, I’ll look at that tomorrow. Thanks for the continued feedback.

dquam avatar Mar 01 '19 04:03 dquam

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.

lantis1008 avatar Apr 23 '19 09:04 lantis1008