Ever since FreeBSD 5?6? I’ve always wanted to get FreeBSD jails working. Only recently I’ve gotten it working, and I couldn’t be prouder. I built a “personal pi-hole” with DNSMasq with an inspiration of a few other blogposts.

Let’s start by setting up the actual jail.

FreeBSD Jail

First thing first, you “install” the Jail source code with bsdinstall like the following:

bsdinstall jail /usr/home/jails/dnshole

Next you need to create a /etc/jail.conf.d/<jailname>.conf where jailname is the name of jail like dnshole.

dnshole {
        host.hostname = dnshole.tardis; # hostname
        ip4.addr = "192.168.0.3/24";
        interface = lo1;
        path = "/usr/home/jails/dnshole";       # path to jail
        devfs_ruleset = 2; # devfs ruleset
        mount.devfs;                    # mount devfs inside
        #allow.raw_sockets=1;
        exec.start = "/bin/sh /etc/rc"; # start command
        exec.stop = "/bin/sh /etc/rc.shutdown"; # stop command
}

After that you need to confirm your host machine’s rc.conf you will probably need to add something like:

gateway_enable="yes"
ipv6_gateway_enable="yes"
jail_enable="YES"
pf_enable="YES"
cloned_interfaces="lo1"
ipv4_addrs_lo1="192.168.0.2-20/24"

And finally you’ll need to add routing rules for pf.conf, this is just a start, but hopefully it’ll make some sense:

IP_PUB="192.168.86.116"
IP_JAIL="192.168.0.2"
DNS_JAIL="192.168.0.3"
NET_JAIL="192.168.0.0/24"
PORT_WWW="{80,443,2020}"
scrub in all
nat pass on re0 from $NET_JAIL to any -> $IP_PUB
rdr pass on re0 proto tcp from any to $IP_PUB port $PORT_WWW -> $IP_JAIL
rdr pass on re0 proto { udp, tcp } from any to $IP_PUB port 53 -> $DNS_JAIL

NOTE: The DNS Jail is 0.3 but the 0.2 was a test one, but you can see you can forward ports like 80, 443, 2020 if you want.

Now you can spin up your jail with:

service jail start dnshole

And check the status with jls, and get “into” the jail with jexec 1 sh

DNSMasq

Now that you’ve gotten a jail running, you need to install some software. This is pretty straight foward:

pkg install dnsmasq

Next edit the jail’s rc.conf

dnsmasq_enable="YES"

If you want to debug the dns lookups, edit /usr/local/etc/rc.d/dnsmasq to add logging.

#command_args="-x $pidfile -C $dnsmasq_conf"
command_args="-x $pidfile -C $dnsmasq_conf --log-facility=/var/log/dnsmasq.log"

Next back up the dnsconf.conf and create a dnsmasq.conf.d directory:

cp /usr/local/etc/dnsmasq.conf /usr/local/etc/dnsmasq.conf.org
mkdir /usr/local/etc/dnsmasq.conf.d/

Copy this “sane” default in of all the setting (at least I want) into /usr/local/etc/dnsmasq.conf

domain-needed
bogus-priv
no-resolv
listen-address=0.0.0.0
bind-interfaces
no-hosts
cache-size=1000
log-queries
conf-dir=/usr/local/etc/dnsmasq.conf.d/,*.conf
server=8.8.4.4
server=2001:4860:4860::8844

Finall pull down some adblocking:

cd /usr/local/etc/dnsmasq.conf.d
fetch https://raw.githubusercontent.com/acidwars/AdBlock-Lists/master/adblock.conf
fetch https://raw.githubusercontent.com/acidwars/AdBlock-Lists/master/ads01.conf
dnsmasq --test
service dnsmasq restart

Then test your dnshole from another machine!

dig @192.168.86.116 freebsd.org