unbound Logo

DNS Resolver

Unbound is a validating, recursive, and caching DNS server software product from NLnet Labs, VeriSign Inc., Nominet, and Kirei. It is distributed free of charge in open source form under the BSD license.

Unbound is designed as a set of modular components that incorporate modern features, such as enhanced security (DNSSEC) validation, Internet Protocol Version 6 (IPv6), and a client resolver application programming interface library as an integral part of the architecture. Originally written for POSIX- compatible Unix-like operating system, it runs on FreeBSD, OpenBSD, NetBSD, OS X, and Linux, as well as Microsoft Windows.

OpenWrt uses dnsmasq as default pre-installed software as DHCP server and DNS resolver.

Since we already run Unbound as our DNS resolver of choice on other servers and synchronize its configuration, we want to use Unbound instead of dnsmasq on our OpenWrt router too.

Installation

$ opkg update
$ opkg install unbound-daemon-heavy unbound-anchor unbound-control

Prerequisites

Disable dnsmasq Resolver

Disable the default dnsmasq resolver, by settting the TCP listening port to 0. This way only the DNS server is disabled, while it still might be used as DCHP and TFTP services:

In /etc/config/dhcp:

config dnsmasq
    option port '0'

OpenWrt Integration

OpenWrt’s unified configuration interface (UCI) does a lot of things with Unbound. See /etc/init.d/unbound. One reason is, the preservation of CPU resources, memory and file-space on smaller devices, another is the conservation of the flash memory, by limiting write operations, and finally it intergrates the unbound services with OpenWrt’s own upstream IPS DNS resolvers, leased out DCHP server addresses and other things.

In our case, we don’t need any of this. We therefore run unbound in “unmanaged” mode.

In /etc/config/unbound:

config unbound
    option manual_conf '1'
    option root_age '9'
    option unbound_control '1'

In this manual mode, our unbound configuration in /etc/unbound/ is, for the most part, left untouched.

Remote Control Setup

Unbound remote server control utility unbound-control performs remote administration on the unbound DNS server. It reads the configuration file, contacts the unbound server over a TLS encrypted connection, sends the command and displays the result.

The connection requirees a set of self-signed certificates and private keys for unbound-control client and the unbound server. The script unbuond-control-setup creates these:

$ unbound-control-setup

Remote control still needs to be activated in the configuration. See under “Remote Control” further down.

Root Server Updates

The “root hints file” contains the names and IP addresses of the root servers, so that a resolver can bootstrap the DNS resolution process. The list is built-in most DNS server software, but changes from time to time, it’s therefore considered as good practice to provide regularly updated root hints.

The following script /root/root-hints-update checks for newer versions online, downloads and installs if necessary.

 1#!/bin/ash
 2#
 3# Refresh list of Internet root servers from Internic
 4# See https://www.iana.org/domains/root/files
 5#
 6# Allow echo with -n parameter: 
 7# shellcheck disable=SC2039
 8# shellcheck shell=dash
 9
10# Vars
11REMOTE_URL='https://www.internic.net/domain/named.cache'
12LOCAL_FILE='/etc/unbound/root-hints.cache'
13FILE_USER=unbound
14FILE_GROUP=unbound
15
16# Make a temporary file to download the blocklist to
17TEMP_FILE=$(mktemp /tmp/$(basename ${LOCAL_FILE}).XXXXXX)
18
19# Download the file, if its newer then what we already have installed
20echo -n "Checking Internic for root zone server updates since "
21echo -n "$( date -r ${LOCAL_FILE} ) ... "
22if curl --fail --silent --show-error --location --remote-time \
23    --time-cond ${LOCAL_FILE} \
24    --output "${TEMP_FILE}" \
25    ${REMOTE_URL}
26then
27    echo "Done."
28else
29    echo Download failed!
30    exit
31fi
32
33# Do we have a download (file exists and is greater then zero)?
34if [ -s "${TEMP_FILE}" ]; then
35
36    echo "Downloaded fresh root-hints from $( date -r "${TEMP_FILE}" )."
37    echo -n 'Installing new root-hints ... '
38
39    # Install the file
40    cp -p -f -u "${TEMP_FILE}" "${LOCAL_FILE}" 
41    touch -r "${TEMP_FILE}" "${LOCAL_FILE}" 
42    chown ${FILE_USER}:${FILE_GROUP} "${LOCAL_FILE}"
43    chmod 644 "${LOCAL_FILE}"
44    echo 'Done.'
45
46    # Check configuration
47    cd /etc/unbound || exit
48    echo -n 'Checking configuration ... '
49    if unbound-checkconf /etc/unbound/unbound.conf > /dev/null
50    then
51
52        echo Ok
53
54        # Reload configuration
55        echo -n 'Restart the local server ... '
56        /etc/init.d/unbound restart && echo Done
57        echo -n 'Checking local server status ... '
58        sleep 10 && unbound-control status -q && echo Ok
59
60    else
61        echo 'unbound server configuration has errors!'
62        exit 1
63    fi
64else
65    echo 'No new updates.'
66fi
67
68# Clean-up
69rm "${TEMP_FILE}"
70
71# -*- mode: sh; tab-width: 4; indent-tabs-mode: nil -*-

Let’s call the script once manually:

$ /root/root-hints-update

Let’s call this on a random weekday and time with cron:

$ min="$(awk 'BEGIN{srand();print int(rand()*59)}')"
$ hour=$(awk 'BEGIN{srand();print int(rand()*23)}')
$ wday=$(awk 'BEGIN{srand();print int(rand()*7)}')
echo "$min   $hour   *    *     $wday    /root/root-hints-update" >> /etc/crontabs/root

Local Settings

Note

The init-script of OpenWrt will copy your configuration files from /etc/unbound/* to /var/lib/unbound/ before the service starts, but without any subdirectories. The unbound binaries provided in OpenWrt have hard-coded /var/lib/unbound/ as their configuration directory. Keep that in mind when including configuration files in Unbonud for OpenWrt.

This is to minimise strain on the flash memory chips, because unbound rewrites part of its configuration files, like encryption keys, periodically.

Main Configuration File

/etc/unbound/unbound.conf

  1#
  2# Unbound configuration file for OpenWrt.
  3#
  4# Unbound Version Version 1.11.0 (released 27 July, 2020)
  5# Linked libs: pluggable-libevent 2.1.11-stable (it uses epoll), 
  6#               OpenSSL 1.1.1h  22 Sep 2020
  7# Linked modules: dns64 respip validator iterator
  8# TCP Fastopen feature available
  9#
 10# See https://unbound.net/documentation/unbound.conf.html
 11
 12#
 13# OpenWrt specific notes:
 14#   
 15# Files are stored and maintened in /etc/unbound but copied to /var/lib/unbound 
 16# at runtine. While subdirectories of /etc/unbound will NOT be copied.
 17# Keep that in mind when including configuration files in Unbonud for OpenWrt.
 18
 19
 20#=============================================
 21# Server Settings
 22#=============================================
 23
 24server:
 25
 26    #----------------------------------------
 27    # Server Modules Settings
 28    #----------------------------------------
 29
 30    # Module configuration, a list of module names separated by spaces,
 31    # surround the string with quotes (""). The modules can be validator,
 32    # iterator. Setting this to "iterator" will result in a non-validating
 33    # server. Setting this to "validator iterator" will turn on DNSSEC
 34    # validation. The ordering of the modules is important.You must also set
 35    # trust-anchors for validation to be useful.
 36    module-config: "validator iterator"
 37
 38    # Permit unbound to open this port or range of ports for use to send
 39    # queries. A larger number of permitted outgoing ports increases resilience
 40    # against spoofing attempts. Make sure these ports are not needed by other
 41    # daemons. By default only ports above 1024 that have not been assigned by
 42    # IANA are used. Give a port number or a range of the form "low-high",
 43    # without spaces.
 44    # The outgoing-port-permit and outgoing-port-avoid statements are processed
 45    # in the line order of the config file, adding the permitted ports and
 46    # subtracting the avoided ports from the set of allowed ports. The
 47    # processing starts with the non IANA allocated ports above 1024 in the set
 48    # of allowed ports.
 49    # OpenWrt default: "10240-65335"
 50    outgoing-port-permit: 38866-39680
 51
 52    # Do not permit unbound to open this port or range of ports for use to send
 53    # queries. Use this to make sure unbound does not grab a port that another
 54    # daemon needs. The port is avoided on all outgoing interfaces, both IP4 and
 55    # IP6. By default only ports above 1024 that have not been assigned by IANA
 56    # are used. Give a port number or a range of the form "low-high", without
 57    # spaces.
 58    # Ports above 1'024
 59    outgoing-port-avoid: 1194 #; OpenVPN UDP port
 60    outgoing-port-avoid: 5060-5061 #; SIP Signaling UDP port
 61    outgoing-port-avoid: 9001 #; TOR Relay
 62    outgoing-port-avoid: 9030 #; TOR Relay
 63    # Ports above 10'000
 64    outgoing-port-avoid: 55867 #; Our WireGuard Port 
 65    outgoing-port-avoid: 29170-29998 #; Outgoing ports of our primary server
 66    outgoing-port-avoid: 51414 #; BitTorrent UDP port we use.
 67    outgoing-port-avoid: 64000-65535 #; MicoTik RouterOS bandwidth tests
 68    outgoing-port-avoid: 64738 #; Mumble Server UDP port
 69
 70    # Number of outgoing TCP buffers to allocate per thread. If set to 0, or if
 71    # do-tcp is "no", no TCP queries to authoritative servers are done. For larger
 72    # installations increasing this value is a good idea.
 73    # Default: 10. OpenWrt default: 1
 74    outgoing-num-tcp: 4
 75
 76    # Number of incoming TCP buffers to allocate per thread. If set to 0, or if
 77    # do-tcp is "no", no  TCP  queries  from clients are accepted. For larger
 78    # installations increasing this value is a good idea.
 79    # Default: 10. OpenWrt default: 1
 80    incoming-num-tcp: 4
 81
 82    # Detect source interface on UDP queries and copy them to replies. This
 83    # feature is experimental, and needs support in your OS for particular
 84    # socket options.
 85    # Default: no
 86    #interface-automatic: no
 87
 88    # Number of bytes size to advertise as the EDNS reassembly buffer size. This
 89    # is the value put into datagrams over UDP towards peers. The actual buffer
 90    # size is determined by msg-buffer-size (both for TCP and UDP). Do not set
 91    # higher than that value. Default is 4096 which is RFC recommended. If you
 92    # have fragmentation reassembly problems, usually seen as timeouts, then a
 93    # value of 1472 can fix it. Setting to 512 bypasses even the most stringent
 94    # path MTU problems, but is seen as extreme, since the amount of TCP
 95    # fallback generated is excessive (probably also for this resolver, consider
 96    # tuning the outgoing tcp number).
 97    # Default; 4096
 98    #edns-buffer-size: 4096
 99
100    # Number of bytes size of the message buffers. The default of 65552 bytes is
101    # enough for 64 Kb packets, the maximum DNS message size. No message larger
102    # than this can be sent or received. Can be reduced to use less memory, but
103    # some requests for DNS data, such as for huge resource records, will result
104    # in a SERVFAIL reply to the client.
105    # Default: 65552, OpenWrt default: 8192
106    msg-buffer-size: 65552
107
108
109#=============================================
110# Configuration Files to include
111#=============================================
112
113# Local system resources, performance and cache settings
114include: "tuning.conf"
115
116# Root Zone Hint Configuration
117include: "root-hints.conf"
118
119# Common configuration settings
120include: "/etc/unbound/unbound.conf.d/*.conf"
121
122# Local zones (private subnets, domains and public keys)
123include: "/etc/unbound/local-zones.d/*.conf"
124
125# Adservers and other blacklists and blocklists
126include: "/etc/unbound/adservers.d/*.conf"
127
128# Root Forward Zone (upstream DNS providers)
129include: "/etc/unbound/upstream-resolvers.d/init7.conf"
130
131# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Performance Tuning

/etc/unbound/tuning.conf

  1#
  2# Unbound configuration file for OpenWrt.
  3#
  4
  5#=============================================
  6# Server Settings
  7#=============================================
  8
  9server:
 10
 11    #------------------------------------------
 12    # System Resources and Performance Settings
 13    #------------------------------------------
 14
 15    # The number of threads to create to serve clients.
 16    # Use 1 for no threading.
 17    # OpenWrt default: 1
 18    num-threads: 1
 19
 20    # Number of ports to open. This number of file descriptors can be
 21    # opened per thread. Must be at least 1. Default depends on com-
 22    # pile options. Larger numbers need extra resources from the oper-
 23    # ating system. For performance a very large value is best, use
 24    # libevent to make this possible.
 25    # OpenWrt default: 60
 26    #outgoing-range: 60
 27
 28    # The number of queries that every thread will service  simultaneously. If
 29    # more queries  arrive  that  need servicing, and no queries can be jostled
 30    # out (see jostle-timeout), then the queries are dropped. This forces the
 31    # client to resend after a timeout; allowing the server time to work on the
 32    # existing queries.
 33    # Default depends on compile options, 512 or 1024. OpenWrt default: 30
 34    num-queries-per-thread: 64
 35
 36    # If not 0, then set the SO_RCVBUF socket option to get more buffer space on
 37    # UDP port 53 incoming queries. So that short spikes on busy servers do not
 38    # drop packets (see counter in netstat -su). Otherwise, the number of bytes
 39    # to ask for, try "4m" on a busy server. The OS caps it at a maximum, on
 40    # linux unbound needs root permission to bypass the limit, or the admin can
 41    # use sysctl net.core.rmem_max.
 42    # Default is 0 (use system value).
 43    #so-rcvbuf: 0
 44
 45    # If not 0, then set the SO_SNDBUF socket option to get more buffer space on
 46    # UDP port 53 outgoing queries. This for very busy servers handles spikes in
 47    # answer traffic, otherwise 'send: resource temporarily unavailable' can get
 48    # logged, the buffer overrun is also visible by netstat -su. Specify the
 49    # number of bytes to ask for, try "4m" on a very busy server. The OS caps it
 50    # at a maximum, on linux unbound needs root permission to bypass the limit,
 51    # or the admin can use sysctl net.core.wmem_max.
 52    # Default is 0 (use system value).
 53    #so-sndbuf: 0
 54
 55    # If yes, then open dedicated listening sockets for incoming queries for
 56    # each thread and try to set the SO_REUSEPORT socket option on each socket.
 57    # May distribute incoming queries to threads more evenly. Default is no. On
 58    # Linux it is supported in  kernels >= 3.9. On other systems, FreeBSD, OSX
 59    # it may also work.You can enable it (on any platform and kernel), it then
 60    # attempts to open the port and passes the option if it was available at
 61    # compile time, if that works it is used, if it fails, it continues silently
 62    # (unless verbosity 3) without the option.
 63    # Default: no
 64    so-reuseport: yes
 65
 66    # If yes, Unbound rotates RRSet order in response (the random number is
 67    # taken from the query ID, for speed and thread safety).
 68    # Default: no
 69    rrset-roundrobin: yes
 70
 71    # If yes, Unbound doesn't insert authority/additional sections into response
 72    # messages when those sections are not required. This reduces response size
 73    # significantly, and may avoid TCP fallback for some responses. This may
 74    # cause a slight speedup. The default is no, because the DNS protocol RFCs
 75    # mandate these sections, and the additional content could be of use and
 76    # save roundtrips for clients.
 77    # Default: no
 78    minimal-responses: yes
 79
 80    #----------------------------------------
 81    # Cache Settings
 82    #----------------------------------------
 83
 84    #----------------------------------------
 85    # Message Cache Settings
 86
 87    # Number of bytes size of the message cache. A plain number is in bytes,
 88    # append 'k', 'm'  or  'g' for kilobytes, megabytes or gigabytes (1024*1024
 89    # bytes in a megabyte).
 90    # Default: 4m, OpenWrt default: 100k
 91    msg-cache-size:4m
 92
 93    # Number of slabs in the message cache. Slabs reduce lock contention by
 94    # threads. Must be set to a power of 2. Setting (close) to the number of
 95    # cpus is a reasonable guess.
 96    # OpenWrt default: 1
 97    msg-cache-slabs: 1
 98
 99    # If yes, message cache elements are prefetched before they expire to keep
100    # the cache up to date. Default is no. Turning it on gives about 10 percent
101    # more traffic and load on the machine, but popular items do not expire from
102    # the cache.
103    # Default: no
104    prefetch: yes
105
106    # If enabled, unbound attempts to serve old responses from cache with a TTL
107    # of 0 in the response without waiting for the actual resolution to finish.
108    # The actual resolution answer ends up in the cache later on.
109    # Default: no
110    serve-expired: yes
111
112    #----------------------------------------
113    # Resource Records Cache Settings
114
115    # Number of bytes size of the RRset cache. Default is 4 megabytes. A plain
116    # number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes or
117    # gigabytes (1024*1024 bytes in a megabyte).
118    # Default: 4m, OpenWrt default: 100k
119    rrset-cache-size: 4m
120
121    # Number of slabs in the RRset cache. Slabs reduce lock contention by
122    # threads, but fragment memory usage. Must be set to a power of 2.
123    # OpenWrt default: 1
124    rrset-cache-slabs: 1
125
126    # Time to live maximum for RRsets and messages in the cache. If the maximum
127    # kicks in, responses to clients still get decrementing TTLs based on the
128    # original (larger) values. When the internal TTL expires, the cache item has
129    # expired. Can be set lower to force the resolver to query for data often, and
130    # not trust (very large) TTL values.
131    # Default: 86400 (1 day)
132    #cache-max-ttl: 86400
133
134    # Time to live minimum for RRsets and messages in the cache. If the minimum
135    # kicks in, the data is cached for longer than the domain owner intended,
136    # and thus less queries are made to look up the data. Zero makes sure the
137    # data in the cache is as the domain owner intended, higher values,
138    # especially more than an hour or so, can lead to trouble as the data in the
139    # cache does not match up with the actual data any more.
140    # Default: 0
141    cache-min-ttl: 900 # 15 min
142
143    #----------------------------------------
144    # Negative Answers Cache Settings
145
146    # Number of bytes size of the aggressive negative cache. A plain number is
147    # in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes or gigabytes
148    # (1024*1024 bytes in a megabyte).
149    # Default: 1m. OpenWRT default: 10k
150    neg-cache-size: 500k
151
152    # Time to live maximum for negative responses, these have a SOA in
153    # the authority section that is limited in time.
154    # Default: 3600 (1 hour)
155    #cache-max-negative-ttl: 3600
156
157    # Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN and
158    # other denials, using information from previous NXDOMAINs answers. It
159    # helps to reduce the query rate towards targets that get a very high
160    # nonexistent name lookup rate.
161    # Default: no
162    # Added in unbound 1.7.0
163    #aggressive-nsec: yes
164
165    #----------------------------------------
166    # Infrastructure Cache Settings
167
168    # Number of slabs in the infrastructure cache. Slabs reduce lock contention
169    # by threads. Must be set to a power of 2.
170    # OpenWrt default: 1
171    infra-cache-slabs: 1
172
173    # Time to live in seconds for entries in the host cache. The host cache
174    # contains roundtrip timing, lameness and EDNS support information.
175    # Default: 900.
176    # infra-host-ttl: 900
177
178    # Number of hosts for which information is cached.
179    # Default: 10,000. OpenWrt default: 200
180    infra-cache-numhosts: 2500
181
182    # Time to live in seconds for entries in the host cache. The host cache
183    # contains roundtrip timing, lameness and EDNS support information.
184    # Default: 900.
185    infra-host-ttl: 900
186
187    # Lower limit in milliseconds for dynamic retransmit timeout calculation in
188    # infrastructure cache. Increase this value if using forwarders that need
189    # more time to do recursive name resolution.
190    # Default is 50
191    #infra-cache-min-rtt: 50
192
193    #----------------------------------------
194    # Key Cache Settings
195
196    # Number of bytes size of the key cache. A plain number is in bytes, append
197    # 'k', 'm' or 'g' for kilobytes, megabytes or gigabytes (1024*1024 bytes in
198    # a megabyte).
199    # Default: 4m. OpenWRT default: 100k
200    key-cache-size: 1m
201
202    # Number of slabs in the key cache. Slabs reduce lock contention by threads.
203    # Must be set to a power of 2. Setting (close) to the number of cpus is a
204    # reasonable guess.
205    # OpenWrt default: 1
206    key-cache-slabs: 1
207
208    # If yes, fetch the DNSKEYs earlier in the validation process, when a DS
209    # record is encountered. This lowers the latency of requests. It does use a
210    # little more CPU. Also if the cache is set to 0, it is no use.
211    # Default: no.
212    prefetch-key: yes

Root Hints

/etc/unbound/root-hints.conf

 1#=============================================
 2# Server Settings
 3#=============================================
 4
 5server:
 6
 7    #----------------------------------------
 8    # Root Zone Hints
 9    #----------------------------------------
10
11    # Read the root hints from this file. Default is nothing, using
12    # builtin hints for the IN class. The file has the format of zone
13    # files, with root nameserver names and addresses only. The
14    # default may become outdated, when servers change, therefore it
15    # is good practice to use a root-hints file.
16    # See https://www.iana.org/domains/root/files
17    # Default: none
18    root-hints: "root-hints.cache"
19
20# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Common Settings

Access Control

/etc/unbound/unbound.conf.d/access-control.conf

 1#=============================================
 2# Unbound Server Settings for OpenWrt
 3#=============================================
 4
 5server:
 6
 7    #----------------------------------------
 8    # Access Control Settings
 9    #----------------------------------------
10
11    # Default: Only localhost is allowed, the rest is refused.
12    # OpenWrt default: 0.0.0.0/0 allow, ::0/0 allow
13
14    # Deny all IPv4
15    access-control: 0.0.0.0/0 refuse
16    # Allow IPv4 localhost
17    access-control: 127.0.0.0/8 allow
18    # Allow private IPv4 addresses (RFC 1918)
19    access-control: 10.0.0.0/8 allow
20    access-control: 172.16.0.0/12 allow
21    access-control: 192.168.0.0/16 allow
22    # Allow link-local IPv4 addresses (RFC 6890 and RFC 3927)
23    access-control: 169.254.0.0/16 allow
24    access-control: 169.254.0.0/24 refuse
25    access-control: 169.254.255.0/24 refuse
26
27    # Deny all IPV6
28    access-control: ::0/0 refuse
29    # Allow IPv6 localhost
30    access-control: ::1 allow
31    access-control: ::ffff:127.0.0.1 allow
32    # Allow link-local IPv6 addresses (RFC 4862 and RFC 4291)
33    access-control: fe80::/10 allow
34    # Allow private IPv6 addresses (RFC 4193)
35    access-control: fc00::/7 allow
36    # Allow our global public IPv6 prefix assigned to us (from our ISP)
37    access-control: 2001:db8:3414::/48 allow
38    # Allow our global private IPv6 prefix
39    access-control: fdc1:d89e:b128::/48 allow
40
41# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

DNS-over-TLS (DoT)

/etc/unbound/unbound.conf.d/dns-over-tls.conf

 1#=============================================
 2# Unbound Server Settings for OpenWrt
 3#=============================================
 4
 5server:
 6
 7    #----------------------------------------
 8    # TLS Client Connections Settings
 9    #----------------------------------------
10
11    # Service clients over SSL (on the TCP sockets), with plain DNS inside the
12    # SSL stream. Give the certificate to use and private key. Requires a full
13    # restart to take effect.
14    # Default: "" (disabled)
15    # ssl-service-key: "path/to/privatekeyfile.key"
16    # ssl-service-pem: "path/to/publiccertfile.pem"
17    # tls-port: 853
18
19# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

DNSSEC

/etc/unbound/unbound.conf.d/dnssec.conf

  1#=============================================
  2# Unbound Server Settings for OpenWrt
  3#=============================================
  4
  5server:
  6
  7    #----------------------------------------
  8    # DNSSEC Settings
  9    #----------------------------------------
 10
 11    # If true, disables the DNSSEC lameness check in the iterator. This check
 12    # sees if RRSIGs are present in the answer, when dnssec is expected, and
 13    # retries another authority if RRSIGs are unexpectedly missing. The
 14    # validator will insist in RRSIGs for DNSSEC signed domains regardless of
 15    # this setting, if a trust anchor is loaded.
 16    disable-dnssec-lame-check: no
 17
 18    # File with trust anchor for one zone, which is tracked with RFC5011
 19    # probes. The probes are several times per month, thus the machine must be
 20    # online frequently. The initial file can be one with contents as
 21    # described in trust-anchor-file. The file is written to when the anchor
 22    # is updated, so the unbound user must have write permission. Write
 23    # permission to the file, but also to the directory it is in (to create a
 24    # temporary file, which is necessary to deal with filesystem full events),
 25    # it must also be inside the chroot (if that is used).
 26    # Default: "", OpenWrt default: "/var/lib/unbound/root.key"
 27    auto-trust-anchor-file: "/var/lib/unbound/root.key"
 28
 29    # Send RFC8145 key tag query after trust anchor priming.
 30    # Default; yes
 31    #trust-anchor-signaling: yes
 32
 33    # Root key trust anchor sentinel. 
 34    # Default: yes
 35    # root-key-sentinel: yes
 36
 37    # Minimum number of seconds of clock skew to apply to validated signatures.
 38    # A value of 10% of the signature lifetime (expiration - inception) is used,
 39    # capped by this setting. Default is 3600 (1  hour) which allows for
 40    # daylight savings differences. Lower this value for more strict checking of
 41    # short lived signa-tures.
 42    # Default: 3600
 43    #val-sig-skew-min: 3600
 44
 45    # Maximum number of seconds of clock skew to apply to validated signatures.
 46    # A value of 10% of the signature lifetime (expiration - inception)  is
 47    # used, capped by this setting. Default is 86400 (24 hours) which allows for
 48    # timezone setting problems in stable  domains. Setting both min and max
 49    # very low  disables the clock skew allowances. Setting both min and max
 50    # very high makes the validator check the signature timestamps less
 51    # strictly.
 52    # Default: 86400
 53    #val-sig-skew-max: 86400
 54
 55    # The time to live for bogus data. This is data that has failed validation;
 56    # due to invalid signatures or other checks. The TTL from that data cannot
 57    # be trusted, and this value is used instead. The value is in seconds,
 58    # default 60. The time interval prevents repeated revalidation of bogus
 59    # data.
 60    # Default: 60
 61    #val-bogus-ttl: 60
 62
 63    # Instruct the validator to remove data from the additional section of
 64    # secure messages that are not signed properly. Messages that are insecure,
 65    # bogus, indeterminate or unchecked are not affected. Default is yes. Use
 66    # this setting to protect the users that rely on this validator for
 67    # authentication from potentially bad data in the additional section.
 68    # Default: yes
 69    #val-clean-additional: yes
 70
 71    # Have the validator print validation failures to the log. Regardless of the
 72    # verbosity setting. Default is 0, off. At 1, for every user query that
 73    # fails a line is printed to the logs. This way you can monitor what happens
 74    # with validation. Use a diagnosis tool, such as dig or drill, to find out
 75    # why validation is failing for these queries. At 2, not only the query that
 76    # failed is printed but also the reason why unbound thought it was wrong and
 77    # which server sent the faulty data.
 78    # Default: 0
 79    #val-log-level: 0
 80
 81    # Instruct the validator to mark bogus messages as indeterminate. The
 82    # security checks are performed, but if the result is bogus (failed
 83    # security), the reply is not withheld from the client with SERVFAIL as
 84    # usual. The client receives the bogus data. For messages that are found to
 85    # be secure the AD bit is set in replies. Also logging is performed as for
 86    # full validation. The default value is "no".
 87    # Default: no
 88    #val-permissive-mode: no
 89
 90    # Instruct unbound to ignore the CD flag from clients and refuse to return
 91    # bogus answers to them. Thus, the CD (Checking Disabled)   flag does not
 92    # disable checking any more. This is useful with legacy (Window 2008
 93    # servers) that set the CD flag but cannot validate  DNSSEC  themselves.
 94    # Like this Unbound still provides them with DNSSEC protection.
 95    # Default: no
 96    #ignore-cd-flag: no
 97
 98    # List of keysize and iteration count values, separated by spaces,
 99    # surrounded by quotes. This determines the maximum allowed NSEC3 iteration
100    # count before a message is simply marked insecure instead of performing the
101    # many hashing iterations. The list must be in ascending order and have at
102    # least one entry. If you set it to "1024 65535" there is no restriction  to
103    # NSEC3 iteration values. This table must be kept short; a very long list
104    # could cause slower operation.
105    # Default: "1024 150 2048 500 4096 2500"
106    #val-nsec3-keysize-iterations: "1024 150 2048 500 4096  2500"
107
108    # Instruct the auto-trust-anchor-file probe mechanism for RFC5011 autotrust
109    # updates to add new trust anchors only after they have been visible for this
110    # time. Default is 30 days as per the RFC.
111    # Default: 2629800
112    #add-holddown: 2629800
113
114    # Instruct the auto-trust-anchor-file probe mechanism for RFC5011 autotrust
115    # updates to remove revoked trust anchors after they have been kept in the
116    # revoked list for this long. Default is 30 days as per the RFC.
117    # Default: 2629800
118    #del-holddown: 2629800
119
120    # Instruct the auto-trust-anchor-file probe mechanism for RFC5011 autotrust
121    # updates to remove missing trust anchors after they have been unseen for
122    # this long. This cleans up the state file if the target zone does not
123    # perform trust anchor revocation, so this makes the auto probe mechanism
124    # work with zones that perform regular (non-5011) rollovers. The default is
125    # 366 days. The value 0 does not remove missing anchors, as per the RFC.
126    # Default: 31536000
127    #keep-missing: 31536000
128
129    # Debug option that allows the autotrust 5011 rollover timers to assume very
130    # small values.
131    # Default: no
132    #permit-small-holddown: no
133
134# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Remote Control

/etc/unbound/unbound.conf.d/remote-control.conf

 1#=============================================
 2# Remote Control Settings
 3#=============================================
 4
 5remote-control:
 6
 7    # Set up the keys and certificates with unbound-control-setup.
 8
 9    # Enable remote control.
10    # Default: no
11    control-enable: yes
12
13    # IPv4, IPv6 addresses or local socket to listen for control commands.
14    # Default: localhost
15    #control-interface: 127.0.0.1
16    #control-interface: ::1
17
18    # port number for remote control operations.
19    # control-port: 8953
20
21    # unbound server key file.
22    server-key-file: "unbound_server.key"
23
24    # unbound server certificate file.
25    server-cert-file: "unbound_server.pem"
26
27    # unbound-control key file.
28    control-key-file: "unbound_control.key"
29
30    # unbound-control certificate file.
31    control-cert-file: "unbound_control.pem"
32
33# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Security and Privacy

/etc/unbound/unbound.conf.d/security.conf

  1#=============================================
  2# Unbound Server Settings for OpenWrt
  3#=============================================
  4
  5server:
  6    #----------------------------------------
  7    # Security and Privacy Settings
  8    #----------------------------------------
  9
 10    # Timeout in milliseconds used when the server is very busy. Set to a value
 11    # that usually results in one roundtrip to the authority servers. If too
 12    # many queries arrive, then 50% of the queries are allowed to run to
 13    # completion, and the other 50% are replaced with the new incoming query if
 14    # they have already spent more than their allowed time. This protects
 15    # against denial of service by slow queries or high query rates. Default 200
 16    # milliseconds. The effect is that the qps for long-lasting queries is
 17    # about  (num- queries- per-thread / 2) / (average time for such long
 18    # queries) qps. The qps for short queries can be about (num-queries- per-
 19    # thread / 2) / (jostle-timeout in whole seconds) qps per thread, about
 20    # (1024/2)*5 = 2560 qps by default.
 21    # Deafault: 200
 22    #jostle-timeout: 200
 23
 24    # If enabled id.server and hostname.bind queries are refused.
 25    hide-identity: yes
 26
 27    # Set the identity to report. If set to "", the default, then the hostname
 28    # of the server is returned.
 29    # Default: "" (server hostname)
 30    identity: ""
 31
 32    # If enabled version.server and version.bind queries are refused.
 33    hide-version: yes
 34
 35    # Set the version to report. If set to "", the default,  then  the package
 36    # version is returned.
 37    version: ""
 38
 39    # If enabled trustanchor.unbound queries are refused.
 40    hide-trustanchor: yes
 41
 42    # Set the target fetch policy used by unbound to determine if it should
 43    # fetch nameserver target addresses opportunistically.The policy is
 44    # described per dependency depth.
 45    # The number of values determines the maximum dependency depth that unbound
 46    # will pursue in answering a query. A value of -1 means to fetch all targets
 47    # opportunistically for that dependency depth. A value of 0 means to fetch
 48    # on demand only. A positive value fetches that many targets
 49    # opportunistically.
 50    # Enclose the list between quotes ("") and put spaces between numbers. The
 51    # default is "3 2 1 0 0". Setting all zeroes, "0 0 0 0 0" gives behaviour
 52    # closer to that of BIND 9, while setting "-1 -1 -1 -1 -1" gives behaviour
 53    # rumoured to be closer to that of BIND 8.
 54    # Default: "3 2 1 0 0", OpenWrt default: "2 1 0 0 0 0"
 55    target-fetch-policy: "3 2 1 0 0"
 56
 57    # Very small EDNS buffer sizes from queries are ignored. Default
 58    # is off, since it is legal protocol wise to send these, and
 59    # unbound tries to give very small answers to these queries, where
 60    # possible.
 61    # Default: no. OpenWRT Default: yes
 62    harden-short-bufsize: no
 63
 64    # Very large queries are ignored. Default is off, since it is
 65    # legal protocol wise to send these, and could be necessary for
 66    # operation if TSIG or EDNS payload is very large.
 67    # Default: no. OpenWrt default: yes
 68    harden-large-queries: no
 69
 70    # Will trust glue only if it is within the servers authority.
 71    # Default: yes.
 72    harden-glue: yes
 73
 74    # Require DNSSEC data for trust-anchored zones, if such data is absent, the
 75    # zone becomes bogus. If turned  off, and no DNSSEC data is received (or the
 76    # DNSKEY data fails to validate), then the zone is made insecure, this
 77    # behaves like there is no trust anchor. You could turn this off if you are
 78    # sometimes behind an intrusive firewall (of some sort) that removes DNSSEC
 79    # data from packets, or a zone changes from signed to unsigned to badly
 80    # signed often. If turned off you run the risk of a downgrade attack that
 81    # disables security for a zone.
 82    # Default: yes
 83    harden-dnssec-stripped: yes
 84
 85    # From RFC 8020 (with title "NXDOMAIN: There Really Is Nothing Underneath"),
 86    # returns nxdomain to queries for a name below another  name that is already
 87    # known to be nxdomain. DNSSEC mandates  noerror for empty nonterminals,
 88    # hence this is possible. Very old software might return nxdomain for empty
 89    # nonterminals (that usually happen for reverse IP address lookups), and
 90    # thus may be incompatible with this. To try to avoid this only DNSSEC-
 91    # secure nxdomains are used, because the old software does not have DNSSEC.
 92    # Default is off. The nxdomain must be secure, this means nsec3 with optout
 93    # is insufficient.
 94    # Default: no
 95    harden-below-nxdomain:yes
 96
 97    # Harden the referral path by performing additional queries for
 98    # infrastructure data. Validates the replies if trust anchors are configured
 99    # and the zones are signed. This enforces DNSSEC validation on nameserver NS
100    # sets and the nameserver addresses that are encountered on the referral
101    # path to the answer. Default off, because it burdens the authority servers,
102    # and it is not RFC standard, and could lead to performance problems because
103    # of the extra query load that is generated. Experimental option. If you
104    # enable it consider adding more numbers after the target-fetch-policy  to
105    # increase the max depth that is checked to.
106    # Default: no
107    harden-referral-path: no
108
109    # Harden against algorithm downgrade when multiple algorithms are advertised
110    # in the DS record. If no, allows the weakest algorithm to validate the
111    # zone. Default is no. Zone signers must produce zones that allow this
112    # feature to work, but sometimes they do not, and turning this option off
113    # avoids that validation failure.
114    # Default: no
115    harden-algo-downgrade: no
116
117    # Use 0x20-encoded random bits in the query to foil spoof attempts. This
118    # perturbs the lowercase and uppercase of query names sent to authority
119    # servers and checks if the reply still has the correct casing. Disabled by
120    # default. This feature is an experimental implementation of draft dns-0x20.
121    # Default: no
122    use-caps-for-id: yes
123
124    # Whitelist the domain so that it does not receive caps-for-id perturbed
125    # queries. For domains that do not support 0x20 and also fail with fallback
126    # because they keep sending different answers, like some load balancers. Can
127    # be given multiple times, for different domains.
128    #caps-whitelist:
129
130    # Send minimum amount of information to upstream servers to enhance privacy.
131    # Only sent minimum required labels of the QNAME and set QTYPE to NS when
132    # possible. Best effort approach; full QNAME and original QTYPE will be sent
133    # when upstream replies with a RCODE other than NOERROR, except when
134    # receiving NXDOMAIN from a DNSSEC signed zone.
135    # Default: no
136    qname-minimisation: yes
137
138    # QNAME minimisation in strict mode. Do not fall-back to sending
139    # full QNAME to potentially broken nameservers. A lot of domains
140    # will not be resolvable when this option in enabled. Only use if
141    # you know what you are doing. This option only has effect when
142    # qname-minimisation is enabled.
143    # Default: no
144    qname-minimisation-strict: no
145
146    # Give IPv4 of IPv6 addresses or classless subnets. These are addresses on
147    # your private network, and are not allowed to be returned for public
148    # internet names. Any occurrence of such addresses are removed from DNS
149    # answers. Additionally, the DNSSEC validator may mark the answers bogus.
150    # This protects against so-called DNS Rebinding, where a user browser is
151    # turned into a network proxy, allowing remote access through the browser to
152    # other parts of your private network. Some names can be allowed to contain
153    # your private addresses, by default all the local-data that you configured
154    # is allowed to, and you can specify additional names using private-domain.
155    # No private addresses are enabled by default. We consider to enable this
156    # for the RFC1918 private IP address space by default in later releases.
157    # That would enable private addresses for 10.0.0.0/8, 172.16.0.0/12
158    # 192.168.0.0/16, 169.254.0.0/16 fd00::/8 and fe80::/10, since the RFC
159    # standards say these addresses should not be visible on the public
160    # internet. Turning on 127.0.0.0/8 would hinder many spam- blocklists as
161    # they use that.
162    # Private IPv4 addresses (RFC 1918)
163    private-address: 10.0.0.0/8
164    private-address: 172.16.0.0/12
165    private-address: 192.168.0.0/16
166    # Private IPv6 addresses (RFC 4193)
167    private-address: fc00::/7;
168    # Link-local IPv4 addresses (RFC 6890 and RFC 3927)
169    private-address: 169.254.0.0/16
170    # Link-local IPv6 addresses (RFC 4862 and RFC 4291)
171    private-address: fe80::/10
172    private-address: fd00::/8
173    # Stop IPv4-mapped IPv6 addresses from bypassing the filter.
174    private-address: ::ffff:0:0/96
175
176    # If set, a total number of unwanted replies is kept track of in every
177    # thread. When it reaches the threshold, a defensive action is taken and a
178    # warning is printed to the log. The defensive action is to clear the rrset
179    # and message caches, hopefully flushing away any poison. A value of 10
180    # million is suggested.
181    # Default: 0 (turned off).
182    unwanted-reply-threshold: 10000000
183
184    # Do not query the given IP address. Can be IP4 or IP6. Append
185    # /num to indicate a classless delegation netblock, for example
186    # like 10.2.3.4/24 or 2001::11/64.
187    #do-not-query-address:
188
189    # If yes, localhost is added to the do-not-query-address entries, both IP6
190    # ::1 and IP4 127.0.0.1/8. If no, then localhost can be used to send queries
191    # to.
192    # Default: yes
193    #do-not-query-localhost: yes
194
195# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Upstream Settings

/etc/unbound/unbound.conf.d/upstream.conf

 1server:
 2
 3    #----------------------------------------
 4    # Upstream Server Connections Settings
 5    #----------------------------------------
 6
 7    # upstream connections use TCP only (and no UDP), "yes" or "no"
 8    # useful for tunneling scenarios, 
 9    # Default is no.
10    #tcp-upstream: no
11
12    # Enable udp upstream even if do-udp is no. This does not change anything.
13    # Useful for TLS service providers, that want no udp downstream but use udp to
14    # fetch data upstream. 
15    # Default is no.
16    #udp-upstream-without-downstream: no
17
18    # Enabled or disable whether the upstream queries use TLS only for transport.
19    # Useful in tunneling scenarios. The TLS contains plain DNS in TCP wireformat. The
20    # other server must support this (see tls-service-key). If you enable this, also
21    # configure a tls-cert-bundle or use tls-win-cert to load CA certs, otherwise the
22    # connections cannot be authenticated. This option enables TLS for all of them,
23    # but if you do not set this you can configure TLS specifically for some forward
24    # zones with forward-tls-upstream. And also with stub-tls-upstream.
25    # Default is no.
26    #tls-upstream: <yes or no>

Upstream Resolvers

/etc/unbound/upstream-resolvers.d/init7.conf

 1#===============================================================
 2#
 3# Unbound Root Zone Forwarding
 4# Using non-public DNS resolvers recommended for Init7 customers.
 5# See https://www.init7.net/en/support/faq/dns-resolver/
 6#===============================================================
 7forward-zone:
 8
 9    # A forward-zone entry with name "." and a "forward-addr:" will forward all
10    # queries to that server (unless it can answer from the cache).
11    name: .
12
13    # IP address of server to forward to. Can be IP 4 or IP 6. To use a 
14    # nondefault port for DNS communication append '@' with the port number.
15    forward-addr: 2001:1620:2777:1::10
16    forward-addr: 2001:1620:2777:2::20
17    forward-addr: 213.144.129.20
18    forward-addr: 77.109.128.2	
19
20    # If set to "yes", queries are sent to the upstream servers first. If the
21    # forwarded query returns a SERVFAIL error, unbound tries to resolve the
22    # query again by itself, bypassing the upstream servers.
23    # If set to "no", unbound first tries to resolve queries directly by itself,
24    # without involment of upstream servers. Upstream servers are queried only
25    # if direct resolution failed.
26    # Default: no
27    forward-first: yes
28
29    # If enabled, data inside the forward is not cached. This is
30    # useful when you want immediate changes to be visible.
31    # Default: no
32    #forward-no-cache: no
33
34    # Enabled or disable whether the queries to this forwarder use TLS for
35    # transport. If you enable this, also configure a tls-cert-bundle or use
36    # tls-winload CA certs, otherwise the connections cannot be authenticated.
37    # Default: no
38    #forward-tls-upstream: no
39
40# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Local and Private Zones

Private Domains

Hostnames and domains which resolve to private IP addresses (e.g. 192.168.0.1) are considered dangerous for so-called DNS-rebinding attacks. Therefore Unbound does not pass down DNS answers to its clients, which contain private addresses.

The definition of which addreses are considered “private” is set with the “private-address” configuration. See the section “Security and Privacy” where the security.conf file listing is found.

The “private-domain” configuration setting, allows to define domains, which are allowed to contain private addreses.

We add our location specific subdomains, which a reachable on LAN and VPN connections only,

/etc/unbound/local-zones.d/home.example.net.conf

 1#=============================================
 2# Server Settings
 3#=============================================
 4
 5server:
 6
 7    #----------------------------------------
 8    # Private Domains for example.net
 9    #----------------------------------------
10
11    # Allow this domain, and all its subdomains to contain private addresses.
12    # Give multiple times to allow multiple domain names to contain private
13    # addresses.
14    # Default: none.
15    private-domain: home.example.net
16    private-domain: office.example.net
17    private-domain: mama.example.net
18    private-domain: vpn.example.net
19
20# -*- mode: ini; indent-tabs-mode: nil; tab-width: 4; -*-

Stub Zones

For some zones (aka Internet domains and subdomains), its difficult or not possible to get a proper domain registration or DNSSEC delegation.

Some examples:

  • Reverse DNS for private IPs;

  • Upstream is not secured with DNSSEC, and therefore also can’t delegate;

On our own network, we still want these domains to be resolvable, reverse lookups possible and all of this secured by DNSSEC.

With Unbound’s “stub-zones”, specific authoritative name servers can be set for a domain. All queries about this domain will then direcly be asked to one of these servers, instead of the usual lookups at the root and TLD servers.

If you also want to have DNSSEC validation for these a domaiin, you need to define trust-anchors.

To get the trust-anchor from your trusted authoritative name server:

$ dig @dns1.example.net +nosplit -t DNSKEY 27.172.in-addr.arpa.
27.172.in-addr.arpa.        40176   IN      DNSKEY  256 3 5 AwEAAa......xkenu7

/etc/unbound/local-zones.d/172.27.conf

  1#=============================================
  2# Stub Zones
  3#=============================================
  4
  5# There may be multiple "stub-zone:" clauses. Each with a "name:" and zero or
  6# more hostnames or IP addresses. For the stub zone this list of name-servers is
  7# used. Class "IN" is assumed. The servers should be authority servers, not
  8# recursors; unbound  performs the recursive processing itself for stub
  9# zones.
 10#
 11# The stub zone can be used to configure authoritative data to be used by the
 12# resolver that cannot be accessed using the public internet servers. This is
 13# useful for company-local data or private zones. Setup an authoritative server
 14# on a different host (or different port). Enter a config entry for unbound
 15# with "stub-addr: <ip address of host[@port]>". The unbound resolver can then
 16# access the data, without referring to the public internet for it.
 17#
 18# This setup allows DNSSEC signed zones to be served by that authoritative
 19# server, in which case a trusted key entry with the public key can be put in
 20# config, so that unbound can validate the data and set the "AD" bit on replies
 21# for the private zone (authoritative servers do not set the "AD" bit). This
 22# setup makes unbound capable of answering queries for the private zone, and can
 23# even set the "AD" bit ('authentic'), but the "AA" ('authoritative') bit is not
 24# set on these replies.
 25#
 26# Consider adding "server:" statements for "domain-insecure:" and for "local-
 27# zone: name nodefault" for the zone if it is a locally served zone. The
 28# insecure clause stops DNSSEC from invalidating the zone. The "local-zone:
 29# nodefault"  (or transparent) clause makes the (reverse-) zone bypass unbound's
 30# filtering of RFC1918 zones.
 31
 32
 33#----------------------------------------
 34# Stub Zone urown.net
 35#----------------------------------------
 36
 37stub-zone:
 38
 39    # Name of the stub zone.
 40    name: 27.172.in-addr.arpa.
 41
 42    # This option is by default off. If enabled it performs NS set priming,
 43    # which is similar to root hints, where it starts using the list of
 44    # nameservers currently published by the zone. Thus, if the hint list is
 45    # slightly outdated, the resolver picks up a correct list online.
 46    # Default: no
 47    #stub-prime: no
 48
 49    # If enabled, a query is attempted without the stub clause if it fails. The
 50    # data could not be retrieved and would have caused SERVFAIL because the
 51    # servers are unreachable, instead it is tried without this clause.
 52    # Default: no.
 53    #stub-first: no
 54
 55    # Enable or disable whether the queries to this stub use SSL for transport.
 56    # Default: no.
 57    #stub-ssl-upstream: no
 58
 59    # IP addresses of stub zone nameservers. Can be IP 4 or IP 6. To use a
 60    # non-default port for DNS communication append '@' with the port number.
 61
 62    # Our primary authoritative name server
 63    stub-addr: 192.0.2.41
 64    stub-addr: 2001:db8::41
 65    
 66    # Our secondary authoritative name server
 67    stub-addr: 192.0.2.42
 68    stub-addr: 2001:db8::42
 69
 70    # Name of stub zone nameserver. Is itself resolved before it isused.
 71    stub-host: dns1.example.net
 72    stub-host: dns2.example.net
 73
 74
 75#=============================================
 76# Server Settings
 77#=============================================
 78
 79server:
 80
 81    # --------------------------------------------------------------
 82    # No upstream DNSSEC for 27.172.in-addr.arpa.
 83    # 172.16.0.0/12 is for use in a private networks (RFC 1918)
 84    # --------------------------------------------------------------
 85
 86    # Sets domain name to be insecure, DNSSEC chain of trust is ignored towards
 87    # the domain name. So a trust anchor above the domain name can not make the
 88    # domain secure with a DS record, such a DS record is then ignored. Also
 89    # keys from DLV are ignored for the domain. Can be given multiple times to
 90    # specify multiple domains that are treated as if unsigned. If you set trust
 91    # anchors for the domain they override this setting (and the domain is
 92    # secured).
 93    #
 94    # This can be useful if you want to make sure a trust anchor for external
 95    # lookups does not affect an (unsigned) internal domain. A DS record
 96    # externally can create validation failures for that internal domain.
 97    domain-insecure: '27.172.in-addr.arpa.'
 98
 99    # A DS or DNSKEY RR for a key to use for validation. Multiple entries can be
100    # given to specify multiple trusted keys, in addition to the trust-anchor-
101    # files. The resource record is entered in the same format as 'dig' or
102    # 'drill' prints them, the same format as in the zone file. Has to be on a
103    # single line, with "" around it. A TTL can be specified for ease of cut and
104    # paste, but is ignored. A class can be specified, but class IN is default.
105    trust-anchor: "27.172.in-addr.arpa. DNSKEY 256 3 5 AwEAAa.......xkenu7"
106
107    #--------------------------------------------
108    #  Local Reverse DNS Zone for 172.27.0.0/16
109    #  27.172.in-addr.arpa
110    #--------------------------------------------
111
112    # Used to turn off default contents for AS112 zones. The other types also
113    # turn off default contents for the zone. The 'nodefault' option has no
114    # other effect than turning off default contents for the given zone. Use
115    # 'nodefault' if you use exactly that zone, if you want to use a subzone,
116    # use 'transparent'.
117    local-zone: "27.172.in-addr.arpa." transparent
118
119    # Allow this domain, and all its subdomains to contain private addresses.
120    # Give multiple times to allow multiple domain names to contain private
121    # addresses.
122    # Default: none.
123    private-domain: "27.172.in-addr.arpa."
124
125# -*- mode: ini; indent-tabs-mode: nil; tab-width: 4; -*-

Overrides

Another special case are domains who’s servers are picky from where they allow to be queried.

The the spam DNS blacklist barracudacentral.org is one such example. For understandable reasons. They require you to register a user profile and provide the addresses of your servers, which require access to their data.

Of course DNS queries trough your usual upstream provider will no longer work. Therefore we need to tell Unbound resolver to query their servers directly:

/etc/unbound/local-zones.d/barracudacentral.org.conf

  1#=============================================
  2# Stub Zones
  3#=============================================
  4
  5# There may be multiple "stub-zone:" clauses. Each with a "name:" and zero or
  6# more hostnames or IP addresses. For the stub zone this list of name-servers is
  7# used. Class "IN" is assumed. The servers should be authority servers, not
  8# recursors; unbound  performs the recursive processing itself for stub
  9# zones.
 10#
 11# The stub zone can be used to configure authoritative data to be used by the
 12# resolver that cannot be accessed using the public internet servers. This is
 13# useful for company-local data or private zones. Setup an authoritative server
 14# on a different host (or different port). Enter a config entry for unbound
 15# with "stub-addr: <ip address of host[@port]>". The unbound resolver can then
 16# access the data, without referring to the public internet for it.
 17#
 18# This setup allows DNSSEC signed zones to be served by that authoritative
 19# server, in which case a trusted key entry with the public key can be put in
 20# config, so that unbound can validate the data and set the "AD" bit on replies
 21# for the private zone (authoritative servers do not set the "AD" bit). This
 22# setup makes unbound capable of answering queries for the private zone, and can
 23# even set the "AD" bit ('authentic'), but the "AA" ('authoritative') bit is not
 24# set on these replies.
 25#
 26# Consider adding "server:" statements for "domain-insecure:" and for "local-
 27# zone: name nodefault" for the zone if it is a locally served zone. The
 28# insecure clause stops DNSSEC from invalidating the zone. The "local-zone:
 29# nodefault"  (or transparent) clause makes the (reverse-) zone bypass unbound's
 30# filtering of RFC1918 zones.
 31
 32
 33#----------------------------------------
 34# Stub Zone b.barracudacentral.org.
 35#----------------------------------------
 36
 37stub-zone:
 38
 39    # Name of the stub zone.
 40    name: b.barracudacentral.org.
 41
 42    # This option is by default off. If enabled it performs NS set priming,
 43    # which is similar to root hints, where it starts using the list of
 44    # nameservers currently published by the zone. Thus, if the hint list is
 45    # slightly outdated, the resolver picks up a correct list online.
 46    # Default: no
 47    stub-prime: yes
 48
 49    # If enabled, a query is attempted without the stub clause if it fails. The
 50    # data could not be retrieved and would have caused SERVFAIL because the
 51    # servers are unreachable, instead it is tried without this clause.
 52    # Default: no.
 53    #stub-first: no
 54
 55    # Enable or disable whether the queries to this stub use SSL for transport.
 56    # Default: no.
 57    #stub-ssl-upstream: no
 58
 59    # Name of stub zone nameserver. Is itself resolved before it isused.
 60    stub-host: blacklist-ns-az1.bci.aws.cudaops.com.
 61    stub-host: blacklist-ns-az2.bci.aws.cudaops.com.
 62    stub-host: blacklist-ns-az3.bci.aws.cudaops.com.
 63
 64    # IP addresses of stub zone nameservers. Can be IP 4 or IP 6. To use a
 65    # non-default port for DNS communication append '@' with the port number.
 66
 67    # blacklist-ns-az1.bci.aws.cudaops.com
 68    stub-addr: 3.13.7.254
 69
 70    # blacklist-ns-az2.bci.aws.cudaops.com
 71    stub-addr: 3.130.175.225
 72
 73    # blacklist-ns-az3.bci.aws.cudaops.com
 74    stub-addr: 52.15.140.229
 75
 76
 77#=============================================
 78# Server Settings
 79#=============================================
 80
 81server:
 82
 83    #----------------------------------------
 84    # Private Domains for example.net
 85    #----------------------------------------
 86
 87    # Allow this domain, and all its subdomains to contain private addresses.
 88    # Give multiple times to allow multiple domain names to contain private
 89    # addresses.
 90    # Default: none.
 91    private-domain: b.barracudacentral.org.
 92
 93    # Sets domain name to be insecure, DNSSEC chain of trust is ignored towards
 94    # the domain name. So a trust anchor above the domain name can not make the
 95    # domain secure with a DS record, such a DS record is then ignored. Also
 96    # keys from DLV are ignored for the domain. Can be given multiple times to
 97    # specify multiple domains that are treated as if unsigned. If you set trust
 98    # anchors for the domain they override this setting (and the domain is
 99    # secured).
100    #
101    # This can be useful if you want to make sure a trust anchor for external
102    # lookups does not affect an (unsigned) internal domain. A DS record
103    # externally can create validation failures for that internal domain.
104    domain-insecure: b.barracudacentral.org.
105
106    # Used to turn off default contents for AS112 zones. The other types also
107    # turn off default contents for the zone. The 'nodefault' option has no
108    # other effect than turning off default contents for the given zone. Use
109    # 'nodefault' if you use exactly that zone, if you want to use a subzone,
110    # use 'transparent'.
111    local-zone: b.barracudacentral.org. nodefault
112
113# -*- mode: ini; indent-tabs-mode: nil; tab-width: 4; -*-