Artemis | Blog | Portfolio | About & Contact

2019 / 11 / 11

Dnsmasq-based DNS blocking

Ads and trackers sucks (nothing new).

They destroy websites, slow down the web, exclude mobile / low power computer users, and trace users in a way no sec. agency could achieve.

I've been using Pihole1 for a long time, but I really have some issues with their tool:

For this reason, I decided to re-do my DNS-based ad blocking setup and go for a raw dnsmasq2 server, coupled with the hosts-blocklists project.

This article documents my setup.

# Server setup and configuration

As said, I'm using dnsmasq, and the hosts-blocklists project.

The first step is to create a directory in which I'll put the domains and host names.

$ mkdir /usr/lib/blocklists

The README provides the two direct raw links towards the list, which is nice. I'm putting both links in a file, one link per line, at /etc/blocklists-sources.txt, then I'm downloading them into my local directory.

$ cat <<EOF > /etc/blocklists-sources.txt
https://raw.githubusercontent.com/notracking/hosts-blocklists/master/hostnames.txt
https://raw.githubusercontent.com/notracking/hosts-blocklists/master/domains.txt
EOF
$ wget -i /etc/blocklists-sources.txt -P /usr/lib/blocklists

Since I never used dnsmasq on this server, I can just destroy the entire configuration file, and make an almost-empty one with what I want.

$ mv /etc/dnsmasq.conf{,.original}
$ cat <<EOF > /etc/dnsmasq.conf
conf-file=/usr/lib/blocklists/domains.txt
addn-hosts=/usr/lib/blocklists/hostnames.txt
EOF

I can now restart the dnsmasq server.

$ systemctl stop dnsmasq
$ systemctl start dnsmasq

And just to keep it up even after a restart, I'll enable it.

$ systemctl enable dnsmasq

Now we can test it!

Works fine for my own DN.

$ dig @127.0.0.1 artemix.org

; <<>> DiG 9.11.5-P4-5.1-Raspbian <<>> @127.0.0.1 artemix.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56331
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;artemix.org.            IN    A

;; ANSWER SECTION:
artemix.org.        3600    IN    A    104.198.14.52

;; Query time: 155 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Nov 11 18:47:14 GMT 2019
;; MSG SIZE  rcvd: 56

And successfully blocks the cancer that is Google!

$ dig @127.0.0.1 googletagmanager.com

; <<>> DiG 9.11.5-P4-5.1-Raspbian <<>> @127.0.0.1 googletagmanager.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48980
;; flags: qr aa rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;googletagmanager.com.        IN    A

;; ANSWER SECTION:
googletagmanager.com.    0    IN    A    0.0.0.0

;; Query time: 32 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Nov 11 18:47:18 GMT 2019
;; MSG SIZE  rcvd: 65

# Automating updates

Now I want to be kept up to date, and I don't want to bother with ssh'ing every time.

A quick script called by cron can easily do the job. Note that there is no file ownership control going on here.

#!/usr/bin/env bash

SOURCE_FILES=/etc/blocklists-sources.txt
CACHE_DIR=/usr/lib/blocklists/
DNS_SERVICE=dnsmasq

# Cleanup
rm -rf /usr/lib/blocklists/*.txt
# Download
wget -i $SOURCE_FILES -P $CACHE_DIR
# Service restart
systemctl restart $DNS_SERVICE

Now, I can make it executable and add a cron job for it.

$ chmod +x /usr/bin/update-blocklists
$ crontab -l > $HOME/tmp-crontab
$ echo "0 * * * * /usr/bin/update-blocklists" >> $HOME/tmp-crontab
$ crontab $HOME/tmp-crontab
$ rm $HOME/tmp-crontab

Note that dealing with temporary files is better done with mktemp3 instead of by hand. I didn't, for convenience, and instead created the temporary file in the user's home directory.

Now, I have an easy-to-setup, easy-to-maintain ad-blocking server!