:.: unbound

Oh hai, so this one is my first "log" entry, typos and shitty english are for free.

Today I want to write a bit about DNS, more precise about unbound(8) which is a caching DNS resolver.

I have a bit tricky environment at home but still I like to keep things as simple as I can and using just base software with OpenBSD. If you have internet at home, and you want to surf the interwebz, you need a DNS, to resolv domains, your own and the others, right? Right.

I use unbound(8), you can find the config file unbound.conf(5) inside the default chroot at /var/unbound, should work almost by default, but I added my own hosts and an ads blocker.

My internal DNS only allows queries from my lan 10.0.0.0/24 and I refuse the rest, also is only open in pf.conf for my lan:

...
## My DNSs
pass in on $isp inet proto udp from any \
	to $isp port 53 rdr-to $isp port 53
...

In my case $isp it is my ethernet connected to the ISP router, it doesn't get a public IP, but it is my servers gateway, so everything goes out from there.

I have a local-zone called x61.local with static entries for my own hosts inside my lan, this DNS will be deployed by my dhcpd(8). My unbound.conf(5) looks like:

server:
	interface: 0.0.0.0
        
	extended-statistics: yes
	statistics-cumulative: no
	statistics-interval: 0

	hide-identity: yes
	hide-version: yes

	verbosity: 2
        
	access-control: 0.0.0.0/0 refuse
	access-control: 127.0.0.0/8 allow
	access-control: 10.0.0.0/24 allow
	access-control: ::0/0 refuse
	access-control: ::1 allow

	private-domain: "x61.local"
	domain-insecure: "x61.local"
	insecure-lan-zones: yes
	unblock-lan-zones: yes

	auto-trust-anchor-file: "/var/unbound/db/root.key"
	val-log-level: 2
	aggressive-nsec: yes
	root-hints: "/var/unbound/etc/named.cache"

	include: "/var/unbound/etc/ads.conf"
        
	private-domain: "x61.local"

local-zone: "x61.local" static
	local-data: "gw.x61.local.	IN A 10.0.0.1"
	local-data: "gw.x61.local.	IN A 10.0.0.2"
	local-data: "bob.x61.local.	IN A 10.0.0.10"
	local-data: "ai.x61.local.	IN A 10.0.0.250"

	local-data-ptr: "10.0.0.1	gw"
	local-data-ptr: "10.0.0.2	gw"
	local-data-ptr: "10.0.0.10	bob"
	local-data-ptr: "10.0.0.250	ai"

auth-zone:
	name: "."
	zonefile: /db/root.zone
	master: 199.9.14.201	# b.root-servers.net
	master: 199.7.91.13	# d.root-servers.net
	master: 192.5.5.241	# f.root-servers.net
	master: 192.112.36.4	# g.root-servers.net
	master: 193.0.14.129	# k.root-servers.net
	master: 192.0.32.132	# xfr.lax.dns.icann.org
	master: 192.0.47.132	# xfr.cjr.dns.icann.org
        
	fallback-enabled: yes
	for-downstream: no

remote-control:
	control-enable: yes
	control-interface: 127.0.0.1
	control-port: 953
	server-key-file: "/var/unbound/etc/unbound_server.key"
	server-cert-file: "/var/unbound/etc/unbound_server.pem"
	control-key-file: "/var/unbound/etc/unbound_control.key"
	control-cert-file: "/var/unbound/etc/unbound_control.pem"

As you can see, I have an include with an ads blocker in my conf:

...
include: "/var/unbound/etc/ads.conf"
...

I generated this file with an script I found somewhere and I modifed a bit to make it works with my setup, but here is it:

#!/bin/sh
#
ADS_CONF=/var/unbound/etc/ads.conf
TMPFILE=$( mktemp get_dns_blacklists-XXXXXXXXX )
trap 'rm -f $TMPFILE; exit 1' EXIT KILL INT QUIT TERM

(
 ftp -VM -o- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts | grep ^0.0.0.0 | awk '{ print $2 }'
 ftp -VM -o- http://sysctl.org/cameleon/hosts | grep ^127.0.0.1 | awk '{ print $2 }'
 ftp -VM -o- https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
 ftp -VM -o- https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
 ftp -VM -o- https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-blocklist.txt | awk '{ print $1 }'
) | tr -d "\r" | tr 'A-Z' 'a-z' | sed -e 's/\.$//' |
 grep -v -e '^#' | grep '\.' | sort -u |
while read domain; do
 echo local-zone: \"$domain\" redirect
 echo local-data: \"$domain. A 0.0.0.0\"
done > $TMPFILE

mv $TMPFILE $ADS_CONF
chown _unbound:_unbound $ADS_CONF
rcctl reload unbound

I have it running every night in a cronjob to keep it up-to-date. Now, let's continue with the final setup:

# unbound-control-setup
setup in directory /var/unbound/etc
generating unbound_server.key
Generating RSA private key, 3072 bit long modulus
...............................++
.......................................++
e is 65537 (0x10001)
generating unbound_control.key
Generating RSA private key, 3072 bit long modulus
............++
.............................++
e is 65537 (0x10001)
create unbound_server.pem (self signed certificate)
create unbound_control.pem (signed client certificate)
Signature ok
subject=/CN=unbound-control
Getting CA Private Key
Setup success. Certificates created.
Enable in unbound.conf file to use

Now we are ready to go, we need to start our new resolver:

$ doas rcctl start unbound
unbound(ok)

Let's check if it works with a simple query:

$ dig @127.0.0.1 openbsd.org A +short                                                                                                              
129.128.5.194
$ dig @10.0.0.1 openbsdfoundation.org A +short
184.70.180.50

Now we enable unbound to start at boot time and we are done:

$ doas rcctl enable unbound
unbound(ok)

Remeber if you want to resolve your own hostname inside your network you probably want to add the follow to your /etc/resolv.conf:

$ doas cat /etc/resolv.conf
search x61.local
nameserver 127.0.0.1
nameserver 10.0.0.10
lookup file bind

Have fun!