2

I've recently started using iptables for the first time on my OpenWrt, Linux based router. Out of the box the OpenWrt firewall is very good, however, after wanting to do more advanced things with the firewall such as forced DNS, iptables looked like it was the only way to go.

So what I'm trying to do is force all DNS traffic through the router so that users connected to the network can't override the DNS servers by setting manual DNS settings on their devices. I have successfully done this for standard port 53 traffic using a redirection rule. 

I tested this by setting a DNS on my OpenWrt router and using 'dnsleaktest.com' to see what DNSs have been picked up. As expected I was using the DNS set in OpenWrt. Next, on Windows I set a manual DNS, different to the openwrt one and did the test again on 'dnsleaktest.com' and started to see some of the overridden DNSs show up. Finally I applied the iptables redirect rule and did the test a third time, and indeed this time the manual DNS set on the client weren't showing and instead the router's DNSs were coming through.

Additionally I have also blocked DNS over TLS (DoT) by dropping port 853. However, the one I'm having difficulty with is DNS over HTTPS (DoH).

I have read in a few places the only way to stop DoH is to block the IP's at port 443 (SSL). With this in mind I have made an entire list of public DNS over HTTPS servers such as Google, Adguard and Cloudflare. I have put the IP's into an ipset and loaded them into iptables but it doesn't seem to be working. 

For the testing of DoH I have been enabling the 'Enable DNS over HTTPS' checkbox under Mozilla Firefox's  Network Settings and testing with 'dnsleaktest.com'.

/etc/Block_DoH.txt (ipset)

create Block_DoH hash:ip,port
add Block_DoH 8.8.4.4,443
add Block_DoH 8.8.8.8,443
add Block_DoH 149.112.112.112,443
add Block_DoH 9.9.9.9,443
add Block_DoH 149.112.112.9,443
add Block_DoH 9.9.9.10,443
add Block_DoH 149.112.112.10,443
add Block_DoH 9.9.9.11,443
add Block_DoH 149.112.112.11,443
add Block_DoH 104.28.1.106,443
add Block_DoH 104.28.0.106,443
add Block_DoH 45.90.28.0,443
add Block_DoH 45.90.30.0,443
add Block_DoH 176.103.130.131,443
add Block_DoH 176.103.130.130,443
add Block_DoH 176.103.130.132,443
add Block_DoH 176.103.130.134,443
add Block_DoH 96.113.151.147,443
add Block_DoH 185.228.168.9,443
add Block_DoH 185.228.169.9,443
add Block_DoH 185.228.168.168,443
add Block_DoH 185.228.169.168,443
add Block_DoH 185.228.168.10,443
add Block_DoH 185.228.169.11,443
add Block_DoH 1.1.1.1,443
add Block_DoH 1.0.0.1,443
# Force DNS to router's DNS
iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT
iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT

# Block DNS over TLS
iptables -I INPUT -p tcp --sport 853 -j DROP
iptables -I INPUT -p udp --sport 853 -j DROP
iptables -I OUTPUT -p tcp --dport 853 -j DROP
iptables -I OUTPUT -p udp --dport 853 -j DROP

# Block DNS over HTTPS
iptables -I OUTPUT -m set --match-set Block_DoH src -j DROP
iptables -I INPUT -m set --match-set Block_DoH dst -j DROP

# Tried blocking Cloudflare with IPtables directly
iptables -I INPUT -s 1.1.1.1 -j DROP
iptables -I INPUT -s 1.0.0.1 -j DROP
iptables -I OUTPUT -d 1.1.1.1 -j DROP
iptables -I OUTPUT -d 1.0.0.1 -j DROP

# Tried to redirect to DNS running on router
iptables -t nat -I OUTPUT -p tcp -s 1.1.1.1 --sport 443 -d 192.168.1.1 --dport 53 -j REDIRECT
iptables -t nat -I OUTPUT -p udp -s 1.1.1.1 --sport 443 -d 192.168.1.1 --dport 53 -j REDIRECT
iptables -t nat -I OUTPUT -p tcp -s 1.0.0.1 --sport 443 -d 192.168.1.1 --dport 53 -j REDIRECT
iptables -t nat -I OUTPUT -p udp -s 1.0.0.1 --sport 443 -d 192.168.1.1 --dport 53 -j REDIRECT

Any ideas?

Many thanks in advance.

UPDATE 1

@hardillb The lines I'm focussing on is the #Block DNS over HTTPS. I'm explicitly trying to block DoH so that the client will fallback to standard DNS.

willowen100
  • 31
  • 2
  • 10
  • 3
    You can't redirect DoH to native DNS(UDP on port 53), it just won't work (they are two totally different protocols). The only thing you can do is block it and the browser will fall back to native. p.s. Anybody who really wants to use an alternate DNS will just use a VPN (or IP over DNS) to tunnel past your router. – hardillb Dec 22 '19 at 21:38
  • 1
    @hardillb Blocking DoH is what I'm trying to do so that when DoH becomes unavailable it will fall back to standard DNS. I'm not to concerned about VPNs as a client actually has to setup and connect manually to a VPN server. The reason I'm trying to force all DNS traffic through my router is a lot of programs and devices are being embedded with DoH. – willowen100 Dec 23 '19 at 08:09
  • 3
    The last 4 lines of you script are trying to redirect DoH to native DNS, that really won't work. What problem are you actually trying to solve here, why do you actually want to block access to other DNS servers? – hardillb Dec 23 '19 at 09:19
  • 1
    Why would we want to block DNS? You can be a parent and want control over your kids’ Internet use. Yes, even large enterprise block DoT and DoH. – John Greene Dec 25 '19 at 23:41

3 Answers3

1

It's hard or even impossible to block DoH protocol on a router. DoH cannot be easily blocked, because it uses TCP port 443, which happens to be the same port used for HTTPS. You could block such IPs:443, but some of those servers use it for both DoH and content. For example, the DoH server dns.cloudflare.com has the same IP(s) as cdnjs.cloudflare.com, the later is used to serve some scripts, used by several websites, such as linuxquestions.org

So you could block only some DoH servers.

As an option you could setup an own DoH server in lan using dnscrypt2 / H2O / Simple AdBlock etc. But an application may or may not want to use it.

Force redirecting traffic to own DoH server won't work, because of cryptography protection

svv
  • 11
  • 1
0

What you want, as @hardillb says well, cannot be done. As your answer, from my point of view, it has no solution, because they are different protocols, I think the only thing you can do is filter the port. For example, create your own dns and allow queries only for your dns and block all other requests. The following example (bash iptables) is with google dns, but you must do it with your dns (replace variables):

PS: this is not a good solution, but it can help eventually

# UDP: DNS Public (53) and DNS over TLS (853)
dns="8.8.8.8 8.8.4.4"
# local interface
lan=enp2s0 
# internet interface
internet=enp2s1

for ip in $dns; do
    iptables -A INPUT -s $ip -i $internet -p udp -m multiport --sports 53,853 -m state --state ESTABLISHED -j ACCEPT
    iptables -A OUTPUT -d $ip -o $internet -p udp -m multiport --dports 53,853 -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT
    iptables -A FORWARD -i $lan -p udp -m multiport --dports 53,853 -d $ip -o $internet -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT
done
iptables -A INPUT -i $lan -p udp -m multiport --dports 53,853 -j DROP
iptables -A FORWARD -i $lan -p udp -m multiport --dports 53,853 -j DROP`

Other alternative is to filter the traffic with tools, for example pi-hole or ipset, but this type of filtering slows down the traffic a lot

acgbox
  • 376
  • 1
  • 5
  • 21
0

Please use ipset, see https://ipset.netfilter.org/. For such huge list, you don't need to have so many rules, ie. one per IP.

Jiri B
  • 547
  • 2
  • 15