Jeremias' Blog
Home Git Blog
logo

Published on 2022-04-10

Using dnsmasq as a Network-Wide Adblocker

DNSMASQ

Why should you do this?

You have probably heard about Pi-Hole before. It is an ad blocker that works for your whole network via DNS.

Pi-hole is a cool project, but it might be a bit overkill for some people. It has a built in web interface for monitoring and all sort of other things I would never use anyways.

Luckily, setting up a DNS server that blocks a list of domains is rather easy to recreate with a number of different programs. We'll use dnsmasq here because it allows to read in host files (like the one you find in /etc/hosts).

There are many frequently updated ad blocking lists that we will be able to use in the end.

Prerequisites

If you want to use this, you are obviously going to need a device in your network that runs all day, or at least as long as you are going to use the internet. I am using a Quartz64 for this, but any Linux device should work for this.

Installing and configuring dnsmasq

First you'll need to install dnsmasq, I use Gentoo, so it is as simple as typing

emerge dnsmasq

Next, you'll want to change the following lines in the dnsmasq configuration file located at /etc/dnsmasq.conf :

To read in the hosts file that we'll create below, change

#addn-hosts=/etc/banner_add_hosts

to

addn-hosts=/etc/dnsmasq/adblock.hosts

To set the IP dnsmasq should listen on change

#listen-address=

to (Use the IP address of your server here. )

listen-address=192.168.1.5

Creating the hosts file

Next we are going to create the host file which is going to be read by dnsmasq. We will read the blocklists from the internet using a cronjob and change them the way we need. Most of the blocklists out there are one of two types:

1. Host file format

Example:

0.0.0.0 ads.google.at
0.0.0.0 ads.facebook.com

This is the format dnsmasq actually needs. The only thing missing is IPv6 addressees. We want it to look like this in the end:

0.0.0.0 ads.google.at
::1 ads.google.at
0.0.0.0 ads.facebook.com
::1 ads.facebook.com

2. Domain name only

Example:

ads.google.at
ads.facebook.com

Here we only have a list of names to block but, dnsmasq, being a DNS server, needs a corresponding IP address. In the end, the list is supposed to look the same as with the first type.

cron and awk

As you see, we will need some way to automatically edit the text of these block lists to make them compatible with dnsmasq. One way to do this is with awk. Here is a small awk command that you can pipe either of these lists to and it will format it the right way:

awk -F' ' '!a[$NF]++ {gsub(/^/,"0.0.0.0 ",$NF) ; print $NF ; gsub(/^0\.0\.0\.0/,"::1",$NF) ; print $NF}'

This will also remove any entries that might get piped to it more than once. Now we just combine it all together in a cronjob. You can simply copy this line into your /etc/crontab file. You can add as many block lists to the curl command as you want.

0  4  *  *  * root    curl "https://raw.githubusercontent.com/Ewpratten/youtube_ad_blocklist/master/blocklist.txt" "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" 2> /dev/null | awk -F' ' '!a[$NF]++ {gsub(/^/,"0.0.0.0 ",$NF) ; print $NF ; gsub(/^0\.0\.0\.0/,"::1",$NF) ; print $NF}' > /etc/dnsmasq/adblock.hosts && rc-service dnsmasq restart > /dev/null

This will download the list at 4 AM every night and then restart your dnsmasq service (replace the rc-service command with the command your distro uses to restart a service, likely systemctl! ). You can of course increase or decrease how often you want to fetch the list.

To populate the hosts file now you can just type the following:

curl "https://raw.githubusercontent.com/Ewpratten/youtube_ad_blocklist/master/blocklist.txt" "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" 2> /dev/null | awk -F' ' '!a[$NF]++ {gsub(/^/,"0.0.0.0 ",$NF) ; print $NF ; gsub(/^(127|0)\.0\.0\.(0|1)/,"::1",$NF) ; print $NF}' > /etc/dnsmasq/adblock.hosts

You can now cat the /etc/dnsmasq/adblock.hosts file and see if it is populated.

Starting the service and testing

Now we can start the dnsmasq service (on your distro you'll likelyuse systemctl for this):

rc-service dnsmasq start

To test if everything worked, we'll use the host command to check a domain that should be blocked:

host analytics.google.com <domain of your server here>

This will output something like this:

analytics.google.com has address 0.0.0.0
analytics.google.com has IPv6 address ::1

You'll know it worked if the IPv4 address is 0.0.0.0 and the IPv6 address is ::1.

I also decided to hop over to canyoublockit.com to test real world results:

With adblocking DNS disabled:

Disabled

With adblocking DNS enabled:

Disabled

So as you can see, this definitely works. Obviously this isn't as good as an adblocker in your browser as it can only block full domains, so you won't get spared from YouTube ads for example. Still, it is a vast improvement on mobile devices which don't allow you to install any form of adblockers! All you'll need to do now is set this DNS server as default on all your devices or change the DNS server your DHCP server advertises!

Written by Jeremias Stotter