Recently I have noticed that there’s an uptick in spamvertising on my home network, and as such, I decided to spend some time investigating using a Raspberry Pi to host a DNS service which would filter such spam sites out.
I initially looked at Pi-Hole which provides a really simple out-of-the-box experience for doing DNS blocking, with a nifty user interface for adding black or whitelist hosts on the fly, and a report of how well the DNS is working. For those with limited technical experience, it’s an easy-to-use experience and I can recommend it on those points. Version 5 has just been released as I write this, so you may want to look at that.
Pi-Hole has some advantages – for example, it doesn’t just run on a Raspberry PI – and it has some built-in lists that it uses to do ad blocking, which is a good start.
However, after using it for a while, it became clear to me that in essence it’s a soft fork of dnsmasq which is available on many upstream repositories already. The Pi-Hole fork of dnsmasq is called pihole-FTL and is, in essence, a dnsmasq process running inside something with a network front end for doing querying and dynamic reloading of data.
The other problem with Pi-Hole is that it is, in essence, a bunch of PHP web pages (potentially running as root) in a server and communicating via a binary protocol to the local daemon, so there’s a lot of potential places where security issues could occur. It also fires up a lightweight HTTP server running on the host (there’s a configuration option to turn it off) which again increases the chance of something going wrong.
As a result, I decided to move away from the Pi-Hole configuration, and use a vanilla dnsmasq implementation instead; which has the following advantages:
- Less custom code running in dnsmasq, so less potential for security issues
- Supported by upstream repositories natively, rather than an add-on
- All of the hard work by Pi-Hole is actually handled by dnsmasq anyway
- Less maintenance to worry about in the future
There are of course disadvantages – it doesn’t provide a helpful webpage
which says “This domain is blocked; click here to unblock it”, but I didn’t
want that anyway. The other minor disadvantage is that the hosts parsing
format supports a missing address, which is parsed as
NXDOMAIN – this
doesn’t apply to the vanilla dnsmasq daemon.
The default configuration for dnsmasq is pretty well commented, and there’s a great manpage with all the configuration options defined in there. However, I thought I would split it up into different sections that you could enable or customise what you want, and I’ve made it available on GitHub.
Despite the name, dnsmasq also handles TFTP, PXE and DHCP operations on both IPv6 and IPv4 addresses. I have customised mine to allow for DHCP and DNS on both IPv4 and IPv6 at the moment, but I’m going to investigate the boot options at a later stage.
Some of the defaults have been updated to allow sensible values in place; they are all commented in the individual files which you can pick-and-choose from. For example, there are multiple options for the DNS server:
- Upstream name servers for Google 22.214.171.124
- Upstream name servers for Cloudflare 126.96.36.199
- Trigger Firefox to use DNS instead of DNS-over-HTTP
- Enabling DNSSEC out of the box
Recently, Cloudflare has announced
“Cloudflare for Families”
which builds on the
188.8.131.52 name server with a
184.108.40.206 name server
that blocks malware attempts, and a
220.127.116.11 that also blocks porn. These
may be useful for families, and over time, I expect the range of blocks to
grow rather than fade – which will be especially useful for fast-moving
targets like those trying to fool you into handing over your Apple/Facebook
logins. I’ve set up a
for those as well.
The idea is that you can clone the example repository, adjust it for your
local environment, and then run it in your
The main reason I did this was to block hosts. In dnsmasq, the syntax for blocking a host is:
which roughly translated means ‘For domains ending in
the result to
NXDOMAIN. You can also specify a particular address; other
block hosts use
0.0.0.0 as a host:
Secondly, there’s a form that can read in a hosts file (man 5 hosts) that
can be used to serve
0.0.0.0 addresses (but not
The advantage of an additional hosts file is that a
SIGHUP will ask the
dnsmasq daemon to reload the hosts file dynamically without stopping and
starting the service.
If you want to ensure that a local domain doesn’t get forwarded out, or you
have an alternative server, then you can use the
server option instead:
This will delegate all
mynet domains to the 192.168.1.1 server, but then
cache the results and serve them to clients quicker.
Finally, if you want to blackhole entire TLDs, you can do so with either the
local directive (i.e. make the machine responsible for the domain) or with
address=/.biz/ directive. Many newer TLDs are full of spam sites, and
countries that you don’t regularly visit or shop from could be on this list.
Dnsmasq provides a DHCP service for you, in case you want to use it to allocate your hosts on demand. One advantage of having this wired into the server is that it will give you a mapping between the DHCP allocated hosts and DNS names for free, so you only have to have them in one place.
The DHCP hosts have a range that you can specify along with a lease time:
You can configure the DHCP server to send out its address for the router, for both IPv4 and IPv6, which means that hosts using DHCP will automatically pick up the host:
You can specify the
host-record for binding a particular name, and a
dhcp-host for setting a machine based on its mac address:
It is also possible to have a cname record, but only for those hosts that are already known to dnsmasq … so it’s not possible, for example, to have a cname pointing to a host elsewhere.
There are other configuration options, such as setting an
auth-zone along with an
auth-soa which will synthesise records for the
SOA name type; these are left to the reader’s investigation. For those using
zeroconf/bonjour/mDNS or SPF, you can also add generic SRV and TXT records to
the DNS zones hosted. These are left as an exercise for the reader.
Pi-Hole is a great out-of-the-box experience, but has a wider security attack area and drags in interpreted languages, which may not be appropriate on a DMZ hosts. Using dnsmasq is perfectly capable, provided that you can curate your own blacklists for domains, or write scripts that do that for you. (An older version of Pi-Hole used native dnsmasq, but was replaced to give stats that could otherwise be grepped from the lookup logs.)
Hopefully the partitioned configuration files in https://github.com/alblue/dnsmasq-example will give you a start point to run your own DNS/DHCP server, optionally with blocking capabilities.