Setting up Unbound from scratch

Requirements

Libevent useful for 1000+ outgoing ports.

Slackware

slackpkg search libevent
ls -lF /var/log/packages/libevent*

Debian/Ubuntu

apt install libevent-dev
# libexpat1-dev

and make sure you do NOT have those installed or enabled

dpkg -l | grep dnsmasq
dpkg -l | grep resolvconf
systemctl status systemd-resolved
dpkg -l | grep network-manager

also clean-up the package in case you had it

systemctl stop unbound
apt purge unbound
ls -lF /var/lib/unbound/root.key
ls -lF /etc/unbound/unbound.conf
ls -alF /etc/unbound/unbound.conf.d/

Build

Build the latest version

ver=1.13.1
wget https://nlnetlabs.nl/downloads/unbound/unbound-$ver.tar.gz
sha1sum unbound-$ver.tar.gz
# 9932931d495248b4e45d278b4679efae29238772  unbound-1.10.1.tar.gz
# 561522b06943f6d1c33bd78132db1f7020fc4fd1  unbound-1.13.1.tar.gz
tar xzf unbound-$ver.tar.gz
cd unbound-$ver/
./configure --help | less

# slackware
./configure --with-libevent --disable-systemd

    # ubuntu
    ./configure --with-libevent
echo $MAKEFLAGS
make > ../unbound.log && echo BUILT
make install
ldconfig

Create a system user for Unbound to drop its priviledges

groupadd -g 499 unbound
useradd --system -M -d /var/chroot/unbound -s /sbin/nologin -g unbound -u 499 unbound

grep unbound /etc/passwd
grep unbound /etc/group

mkdir -p /var/chroot/unbound/db/
mkdir -p /var/chroot/unbound/etc/
chown unbound:unbound /var/chroot/unbound/db/
chmod 750 /var/chroot/unbound/db/

Optional – generate some key pairs for unbound-control to work

unbound-control-setup
ls -lF /usr/local/etc/unbound/unbound*.{key,pem}

Optional – otherwise using named pipe

ls -lF /var/unbound.control.pipe
mkfifo /var/unbound.control.pipe

Hints and trust anchor

Grab the one and only root anchor

unbound-anchor -a /var/chroot/unbound/db/root.key

this file gets updated by the daemon itself (see auto-trust-anchor-file). But I am not sure we need to fix the ownership – maybe unbound takes care of it during startup already.

chown unbound:unbound /var/chroot/unbound/db/root.key
# daemon will revert it to 644 anyway
#chmod 640 /var/chroot/unbound/db/root.key

Grab the root hints and signature

cd /var/chroot/unbound/
wget https://www.internic.net/domain/named.cache
wget https://www.internic.net/domain/named.cache.sig

also import InterNIC’s PGP pubkey and verify the file

gpg --version # 2.2.19
gpg --keyserver pgp.mit.edu --receive-key 937BB869E3A238C5
gpg --verify named.cache.sig
# F0CB 1A32 6BDF 3F3E FA3A  01FA 937B B869 E3A2 38C5

It’s best the hints remain with root ownership, as those aren’t managed by the daemon.

Prepare a log file with the right permissions within the chroot

touch /var/chroot/unbound/db/unbound.log
chown unbound:unbound /var/chroot/unbound/db/unbound.log
chmod 640 /var/chroot/unbound/db/unbound.log
ln -s /var/chroot/unbound/db/unbound.log /var/log/unbound.log

Caching and validating resolver setup

We’ve got a chroot and we need to keep a consistent path with the host system

mv /usr/local/etc/unbound/unbound.conf /usr/local/etc/unbound/unbound.con.dist
cd /var/chroot/unbound/etc/
grep -vE '^[[:space:]]*(#|$)' /usr/local/etc/unbound/unbound.conf.dist > unbound.conf

Handy symlinks

ln -s /var/chroot/unbound/etc/unbound.conf ~/unbound.conf
ln -s /var/chroot/unbound/etc/unbound.conf /etc/unbound.conf
ln -s /var/chroot/unbound/etc/unbound.conf /usr/local/etc/unbound/unbound.conf

How many cores do you have? And proceed

grep ^processor /proc/cpuinfo
vi /etc/unbound.conf

server:
        verbosity: 2
        num-threads: HOW_MANY_CORES
        interface: 0.0.0.0
        #interface: ::0
        access-control: 0.0.0.0/0 allow
        #access-control: ::/0 allow
        pidfile: "/var/run/unbound.pid" # not within chroot
        hide-identity: yes
        hide-version: yes
        #rrset-roundrobin: yes
        qname-minimisation: yes
        do-not-query-localhost: no

    username: "unbound"
    chroot: "/var/chroot/unbound"
    # pathes within chroot
    directory: "/"
    root-hints: "/named.cache"
    auto-trust-anchor-file: "/db/root.key"
    logfile: "/db/unbound.log"

remote-control:
        control-enable: no

otherwise

remote-control:
        control-enable: yes
        control-interface: /var/unbound.control.pipe

sample domain

assuming an authoritative server to bind to on alternate port 5353

        domain-insecure: "example.local"
        domain-insecure: "1.1.10.in-addr.arpa"
        #local-zone: "example.local" transparent
        #local-zone: "1.1.10.in-addr.arpa" transparent

stub-zone:
        name: "example.local"
        stub-addr: ::1@5353

stub-zone:
        name: "1.1.10.in-addr.arpa"
        stub-addr: ::1@5353

Ready to go (standalone)

read the logs

tail -n50 -F /var/log/unbound.log

check the configuration

unbound-checkconf /etc/unbound.conf

start and enable at boot time

vi /etc/rc.local

echo -n unbound...
unbound -c /etc/unbound.conf && echo done || echo FAILED

status – main process runs as unbound user

cat /var/run/unbound.pid
pgrep -a unbound
ps auxfww | grep unbound | grep -vE 'grep|tail'
netstat -lntup | grep unbound

stop

pkill unbound && rm -f /var/run/unbound.pid

Ready to go (remote control)

start and enable at boot time

echo -n unbound-control...
rm -f /var/unbound.control.pipe
/usr/bin/mkfifo /var/unbound.control.pipe
# same path within chroot
unbound-control -c /etc/unbound.conf start && echo done || echo FAIL

you will notice the perms are updated by the daemon as such

ls -lF /var/unbound.control.pipe

srw-rw---- 1 unbound unbound 0 Oct  2 12:53 /var/unbound.control.pipe=

status (no need to enforce the config path here)

unbound-control status
unbound-control stats_noreset

reload (idem)

unbound-control reload

Acceptance

locally

The managed dnssec root key is in da place (there’s no way to make it 640?)

ls -lhF /var/chroot/unbound/db/root.key
cat /var/chroot/unbound/db/root.key

Testing local-zone

host localhost localhost
host 127.0.0.1 localhost

Testing cached public zone

host nethence.com localhost
host 62.210.110.7 localhost

Testing cashed stub-zone

host example.local localhost
host INTERNAL-IP localhost

Tracing iterative queries

dig nethence.com +trace @localhost

Testing DNSSEC (do and ad flags)

dig nethence.com +dnssec @localhost

More options

+multiline

remotely

nmap -sU -p 53 DNS-SERVER
nmap -p 53 DNS-SERVER

and re-iterate a few tests from above.

Maintenance

Flush the cache against a specific zone

unbound-control flush_zone example.local

Flush the overall cache

unbound-control reload

Analyze the cache

unbound-control dump_cache > cache.dump
less cache.dump

Easy family-shield forwarder

    #root-hints: "/named.cache"

    forward-zone:
            name: "."
    # OpenDNS Family Shield
            forward-addr: 208.67.222.123
            forward-addr: 208.67.220.123
    # CleanBrowsing Family Filter
            # 185.228.168.168
            # 185.228.169.168

acceptance

host some-pr0n-website

should return

146.112.61.106
::ffff:146.112.61.106
106.61.112.146.in-addr.arpa domain name pointer hit-adult.opendns.com.

oh and when ever your browser connects there, it will get an un-trusted certificate

srv=hit-adult.opendns.com
port=443

echo Q | openssl s_client -servername $srv -connect $srv:$port 2>&1 | openssl x509 -noout -text

Keep the cache upon reboot

BEFORE you kill the daemon

vi /etc/rc.local_shutdown

echo -n dumping dns cache...
unbound-control dump_cache > /var/tmp/cache.dump && echo done || echo FAIL

echo -n shutting down unbound...
pkill unbound && echo done || echo FAIL

AFTER you start the daemon

vi /etc/rc.local

echo -n loading dns cache...
unbound-control load_cache < /var/tmp/cache.dump && echo done || echo FAIL

it’s worth noting an empty cache db looks as such

START_RRSET_CACHE
END_RRSET_CACHE
START_MSG_CACHE
END_MSG_CACHE
EOF

Troubleshooting

If Unbound service is listening but refusing to answer queries, fix access-control: as shown in the example above.

With verbosity 3, if you get

configured stub servers failed -- returning SERVFAIL

==> check do-not-query-localhost

Against a stub zone too, if you get

info: query response was nodata ANSWER

==> if it is not signed, domain-insecure helps

Resources

unbound.conf - Unbound configuration file. https://nlnetlabs.nl/documentation/unbound/unbound.conf/

build

Unbound-1.9.1 http://www.linuxfromscratch.org/blfs/view/svn/server/unbound.html

hints and anchors

Root Files https://www.iana.org/domains/root/files

Trust Anchors and Keys https://www.iana.org/dnssec/files

unbound-anchor - Unbound anchor utility. https://nlnetlabs.nl/documentation/unbound/unbound-anchor/

Howto enable DNSSEC https://nlnetlabs.nl/documentation/unbound/howto-anchor/

guides

Unbound https://wiki.archlinux.org/title/Unbound

unbound/doc/example.conf.in https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in old http://unbound.nlnetlabs.nl/svn/trunk/doc/example.conf.in

[Unbound-users] reverse lookup stub zone https://www.unbound.net/pipermail/unbound-users/2009-May/000583.html

maintenance

Unbound DNS Server Cache Control https://abridge2devnull.com/posts/2016/03/unbound-dns-server-cache-control/

Unbound DNS Server Cache Control https://abridge2devnull.com/posts/2016/03/unbound-dns-server-cache-control/

dnssec

How to test and validate DNSSEC using dig command line https://www.cyberciti.biz/faq/unix-linux-test-and-validate-dnssec-using-dig-command-line/

A Short Practical Tutorial of dig, DNS and DNSSEC https://metebalci.com/blog/a-short-practical-tutorial-of-dig-dns-and-dnssec/

How To Test Recursive Server (So You Think You Are Validating) https://dnsinstitute.com/documentation/dnssec-guide/ch03s02.html

What are all the flags in a dig response? https://serverfault.com/questions/729025/what-are-all-the-flags-in-a-dig-response/729121

upon reboot

Preserving unbound cache across reboots https://misc.openbsd.narkive.com/gk9c44Ga/preserving-unbound-cache-across-reboots

[SOLVED] Can unbound dns server use persistent caching? https://bbs.archlinux.org/viewtopic.php?id=205494

family-shield

Configuring Unbound as a simple forwarding DNS server https://www.redhat.com/sysadmin/forwarding-dns-2

Configure DNS forwarding on Unbound https://learn.akamai.com/en-us/webhelp/enterprise-threat-protector/enterprise-threat-protector/GUID-50A942A0-B474-488E-9A79-3ED0E5E88226.html

8 Free DNS Services to Block Porn Sites without Installing Software https://www.raymond.cc/blog/how-to-block-pornographic-websites-without-spending-money-on-software/

HOW TO BLOCK PORN ON ANY DEVICE. FOR FREE. https://protectyoungeyes.com/how-to-block-porn-on-any-device-for-free/

Anyone know of a good blocklist for porn / adult content? https://www.reddit.com/r/pihole/comments/a6crei/anyone_know_of_a_good_blocklist_for_porn_adult/

5 DNS Services to Block Porn Sites without Installing Software https://jamiat.org.za/5-dns-services-to-block-porn-sites-without-installing-software/

How does DNS blacklisting work https://superuser.com/questions/1144929/how-does-dns-blacklisting-work –> DIY

About Blacklists https://docs.infoblox.com/display/NAG8/About+Blacklists –> DIY

Add porn blocking to your Pi-hole https://mangolassi.it/topic/16905/add-porn-blocking-to-your-pi-hole –> DIY

todo

Config for running Unbound as a caching DNS forwarder (performance settings optimized for Raspberry Pi 2). https://gist.github.com/MatthewVance/5051bf45cfed6e4a2a2ed9bb014bcd72 –> forward-tls-upstream: yes


GUIDES | LECTURES | BENCHMARKS | SMTP HEALTH