Setting up a DNS adblocker on a FreeBSD jail

4 minute read Published:

Setting up a local DNS adblocker to get rid of ads, trackers, telemetry, and malware on a FreeBSD jail
Table of Contents

We all heard about adblocking at DNS level, implemented by services like Pi-hole, or maybe just setting an external custom DNS server like Cloudflare's (fast & more private, not necessarily blocking requests), or Quad9.

These are all great options, but in my opinion they all lack a little bit of something, or provide too much. For example, external, custom DNS servers are good for a quick & easy setup, but you lack the ability of customizing the sources or manually whitelisting or blacklisting domains, and so on. On the other hand, a service like Pi-hole is great, it allows you to set up custom sources, you can whitelist and blacklist custom domains, you can set your own provider for the upstream DNS server, but it kinda requires a Debian-based distro in order to offer an easy setup via their own installer, in order to get the web ui.


As I previously mentioned, this is all going to happen in a FreeBSD jail. I’m using ezjail for jail-related setup & configuration. I assume you’re already having a working jail with an IP address in the LAN, and configured for network access.

Note: the dnsmasq setup is the same on all distros (Linux or BSD), but the filesystem structure and running scripts are different.

Installing the required packages

We only need dnsmasq on the system, and the package inside the official repositories (and not ports) is more than enough for our use case.

Just as a note, I am always installing vim-console on every jail, as I find vi a bit cumbersome. Feel free to use your preferred editor.

After installing dnsmasq, we need to enable the service via rc.conf:

echo dnsmasq_enable="YES" >> /etc/rc.conf

Configuring dnsmasq

In order to get dnsmasq to log queries to a file, we’re also going to edit the rc script for it, /var/local/etc/rc.d/dnsmasq. More specific, add a parameter to the command_args variable to tell it to set the logging facility to a file. This way we can get some statistics from the logfile using grep, awk, etc.

Next step is to make a little structure for the files we’re going to as as config & hosts, and edit the package’s config file. Personally, for dnsmasq I use the default structure of the package; config file situated at /usr/local/etc/dnsmasq.conf, and the custom config files in /usr/local/etc/dnsmasq.conf.d. As for the hosts, I make a directory at /usr/local/etc/hosts.d and put all the custom hosts files over there.

# create required directories
mkdir /usr/local/etc/{dnsmasq.conf,hosts}.d

# create a new file for hosts & addresses
touch /usr/local/etc/dnsmasq.conf.d/10-custom.conf

Now open up /usr/local/etc/dnsmasq.conf in your preferred editor and make the following changes:

domain-needed   # never forward plain names
bogus-priv      # never forward addresses on non-routed addresses
no-hosts        # don't use system-wide hosts file
no-resolv       # don't use system-wide resolv file, required custom server
cache-size=1000 # use 1k hosts in the cache
log-queries     # log every dns query

# include all files in the specified dir, ending in `.conf'

# forward queries to Cloudflare
server= # IPv4
server=2606:4700:4700::1111 # IPv6

# forward queries to Google
server= # IPv4
server=2001:4860:4860::8888 # IPv6

Note: all options are explained in the default config file, as well as in the manual page. If you think you need to edit some of them, you are more than welcome to do it.

Now, let’s add some custom sources for domain blocking. I find FilterLists to be more than enough as a starting point. I will proceed to grab a couple of dnsmasq configurations, and a couple of hosts files.

# grab some configs
wget -O /usr/local/etc/dnsmasq.conf.d/20-adblock.conf
wget -O /usr/local/etc/dnsmasq.conf.d/21-ads01.conf
wget -O /usr/local/etc/dnsmasq.conf.d/22-blocklists.conf

# grab some hosts
wget -O /usr/local/etc/hosts.d/adguard
wget -O /usr/local/etc/hosts.d/adguard-mobile

The config files are going to be loaded automatically by the main dnsmasq config, so we only need to specify the hosts files in the custom config we previously created. Open /usr/local/etc/dnsmasq.conf.d/10-custom.conf and add the following lines:


# you can specify custom domains via `address'
# for example, I found my laptop querying for the following domain,
# which was not present in any of the files I used

Test and check

Now that we finished configuring dnsmasq, we can start checking the validity of the config, and if it works or not. We can do that by running dnsmasq --test.

We can see that it is working by using drill to query the local DNS server.

Next step is to set up the jail’s IP as the DNS server on the router serving your LAN, to serve all the connected devices.