Using IPTables to force all DNS queries to a Pi-Hole

Hopefully by now you have heard the good word about Pi-Hole, set one up in a Docker container and now enjoying a substantially ad-less and speedy internet experience across all your devices.

If you were one of the ones to configure your Pi-Hole at your routers end to have all the devices on your network use Pi-Hole then while 98% of the time this is enough, you may be surprised to learn that some off the shelf devices and/or software like to hardcode a DNS server of their choice. This means that even if your router is informing all clients via DHCP that they should use your Pi-Hole for DNS, they will be going around it and potentially leaking personal information or data you have chosen not to share.

One such device that is common across households is the humble Google Chromecast. Now, I love my Chromecast. It’s a fantastic device to bring quick, simple and easy video streaming to anything with a HDMI input. That said, it has Google’s DNS servers hardcoded into the device and thus bypasses the Pi-Hole when making DNS queries. Hell, even one of the creators of the DNS system voiced his displeasure about the leaking of information that could conspire.

Like anything in the world of IT, where there is a will, there is a way; Today, that is the way of iptables

For this little exercise, we are going to assume that you are either:

  • Utilising a router that runs OpenWRT
  • Utilising a router that runs another Linux distro, allows SSH access and includes iptables in its operating system

iptables for the uninitiated is a Linux applications that allows you to configure the Linux kernel firewall via a table or tables of chains & rules. Essentially each network packet that transfers through the Linux kernel is sent through various chains of rules depending upon it’s origins to correctly route it to it’s destination.

We will use iptables to ensure that all DNS query packets, no matter if they are explicitly configured to go around the Pi-Hole will be re-routed to the Pi-Hole for filtering or pass-through to our defined DNS provider.

List current rules in iptables

First off, SSH into your router and login to have administrative privileges.

Next, enter the following command to list all rules inside the NAT table inside iptables:

iptables -t nat -L --line-numbers

Take note of the current output of the PREROUTING chain.

Entering new rules in iptables

Next, we are going to add two rules; one rule for TCP packets and one rule for UDP packets by entering the following:

iptables -t nat -A PREROUTING -i br0 -p udp ! --source piholeaddress ! --destination piholeaddress --dport 53 -j DNAT --to piholeaddress

iptables -t nat -A PREROUTING -i br0 -p tcp ! --source piholeaddress ! --destination piholeaddress --dport 53 -j DNAT --to piholeaddress

Replace piholeipaddress with the IP address of your Pi-Hole before entering.

Before we go any further, let’s break down these rules to get an understanding of what is happening:

iptables -t nat

We are invoking iptables and addressing the NAT table

-A PREROUTING

and making an addition to the PREROUTING chain

-i br0 -p tcp
-i br0 -p udp

while listening on interface br0 (typical bridge interface that is your WAN port on your home router) for packets of the TCP or UDP protocol variety

! --source piholeaddress ! --destination piholeaddress --dport 53

and the source of the packet did NOT come from the Pi-Hole (to prevent loops) and is NOT heading to the Pi-Hole (precisely the traffic we want to capture and reroute) but it’s destination is port 53 (DNS port)

-j DNAT --to piholeaddress

jump (move to the next chain) and destination NAT the packet to the Pi-Hole.

There are almost limitless ways you could construct your rule but I found this is the most streamlined and efficient way to capture traffic that is attempting to go around the Pi-Hole for DNS lookups.

When you correctly enter the rule, you will receive no output/prompt from iptables. So let’s confirm ourselves by displaying the NAT table again:

Now we can see two DNAT rules under the PREROUTING chain.

At this point, all DNS queries bound for port 53 attempting to exit your router will be redirected to your Pi-Hole and filtered if necessary. Happy days!

Removing rules in iptables

But what do you do if you stuffed up the rule in iptables and now your internet is no longer functioning? We’ll discuss that in the next post.

Advertisements
James Written by:

9 Comments

  1. Shippy
    19/03/2019
    Reply

    James,

    Great JIT article ! I have the reverse issue so help me here:

    I have a SSH/iptables capable Linux distro ( LibreElec.tv, the Kodi JeOS) and I want to separate normal DNS queries from the couple going to geo unlocking proxies for Netflix, BBC iPlayer etc.

    So I need iptables, or just the config file, rules to say above:

    ——–
    If the DNS query is for Netflix, BBC iPlayer or similar (specifying the domain name list), then route to a specific IP address or addresses for the geo-unlocking proxy server(s);

    otherwise route all traffic to Google/CloudFlare/OpenDNS as chosen.
    ———-

    Of course one concern here is that a backup DNS server also need be specified e.g., for Google, both 8.8.8.8 and 8.8.4.4.

    Cheers,🐵🐵👺
    Shippy.

    • 25/03/2019
      Reply

      Hey Shippy,

      Fantastic question. You got my creative gear engaged in thinking about the best way to meet your requirements.

      The second part of the question is easy enough. If you have two destinations you want to route to, the use of the statistics module is the most appropriate way to tackle that. I’ll cover that in an upcoming post.

      The first part with regards to forwarding the request based upon the destination is better served by a forward proxy and not iptables. As you are dealing in hostnames and not IPs and Ports, it’s not something IPTables caters for.

  2. ChkF
    18/04/2019
    Reply

    Hi. Thanks for this. How does this work with multiple pi-holes? e.g. if I have 2 of them on the same network. My router allocates individual network devices get DNS from pihole1 or pihole2. I assume I add more entries to the commands? e.g. for the tcp one:

    iptables -t nat -A PREROUTING -i br0 -p tcp ! –source pihole1 ! –destination pihole1 ! –source pihole2 ! –destination pihole2 –dport 53 -j DNAT –to pihole1

    • 26/05/2019
      Reply

      Hey CHKF, funny you should ask! It seems to be a common setup, one that I’l be addressing in a upcoming blog post. So keep your eyes peeled 🙂

  3. 27/04/2019
    Reply

    I’m using this in my Pi Hole, as I have an Arris cable modem and can only specify what DNS IP address to use, which I made for my Pi Hole. Outside of a tcpdump/Wireshark capture, is there any way with nslookup or dig to confirm the rule is working? Great explanation too! I’m referencing this in my final paper for an IOT course.

    • 26/05/2019
      Reply

      Hey Robbie,

      Outside of putting a network tap between your cable modem and the wider web there is no way to be sure. Any device based method (like nslookup/dig or adblock websites) would only be relevant for that device and only if the applications respect the operating system settings.

      I’m humbled to be referenced in your IOT paper. I would love to give it a read once it’s complete. The world of IOT, the bridging of our physical and virtual worlds, fascinates me. This is what drew me to products such as the Raspberry Pi in the first place.

  4. 30/06/2019
    Reply

    Hi James,

    I had to fudge my paper a bit. I believe you are correct, the Chromecast will not respect the OS settings, even though I sinkholes 8.8.8.8 and 8.8.4.4. I have a long thread at the Pihole discourse, https://discourse.pi-hole.net/t/confirming-chromecast-is-blackholed-sinkholed/19457/25

    Firewalla support responded they can achieve this: https://help.firewalla.com/hc/en-us/community/posts/360029740373-does-Red-or-Blue-intercept-Chromecast-s-hard-coded-DNS-

Leave a Reply to ChkF Cancel reply