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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/bin/ash
#
# Refresh list of Internet root servers from Internic
# See https://www.iana.org/domains/root/files
#
# Allow echo with -n parameter: 
# shellcheck disable=SC2039
# shellcheck shell=dash

# Vars
REMOTE_URL='https://www.internic.net/domain/named.cache'
LOCAL_FILE='/etc/unbound/root-hints.cache'
FILE_USER=unbound
FILE_GROUP=unbound

# Make a temporary file to download the blocklist to
TEMP_FILE=$(mktemp /tmp/$(basename ${LOCAL_FILE}).XXXXXX)

# Download the file, if its newer then what we already have installed
echo -n "Checking Internic for root zone server updates since "
echo -n "$( date -r ${LOCAL_FILE} ) ... "
if curl --fail --silent --show-error --location --remote-time \
    --time-cond ${LOCAL_FILE} \
    --output "${TEMP_FILE}" \
    ${REMOTE_URL}
then
    echo "Done."
else
    echo Download failed!
    exit
fi

# Do we have a download (file exists and is greater then zero)?
if [ -s "${TEMP_FILE}" ]; then

    echo "Downloaded fresh root-hints from $( date -r "${TEMP_FILE}" )."
    echo -n 'Installing new root-hints ... '

    # Install the file
    cp -p -f -u "${TEMP_FILE}" "${LOCAL_FILE}" 
    touch -r "${TEMP_FILE}" "${LOCAL_FILE}" 
    chown ${FILE_USER}:${FILE_GROUP} "${LOCAL_FILE}"
    chmod 644 "${LOCAL_FILE}"
    echo 'Done.'

    # Check configuration
    cd /etc/unbound || exit
    echo -n 'Checking configuration ... '
    if unbound-checkconf /etc/unbound/unbound.conf > /dev/null
    then

        echo Ok

        # Reload configuration
        echo -n 'Restart the local server ... '
        /etc/init.d/unbound restart && echo Done
        echo -n 'Checking local server status ... '
        sleep 10 && unbound-control status -q && echo Ok

    else
        echo 'unbound server configuration has errors!'
        exit 1
    fi
else
    echo 'No new updates.'
fi

# Clean-up
rm "${TEMP_FILE}"

# -*- 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
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#
# Unbound configuration file for OpenWrt.
#
# Unbound Version Version 1.11.0 (released 27 July, 2020)
# Linked libs: pluggable-libevent 2.1.11-stable (it uses epoll), 
#               OpenSSL 1.1.1h  22 Sep 2020
# Linked modules: dns64 respip validator iterator
# TCP Fastopen feature available
#
# See https://unbound.net/documentation/unbound.conf.html

#
# OpenWrt specific notes:
#   
# Files are stored and maintened in /etc/unbound but copied to /var/lib/unbound 
# at runtine. While subdirectories of /etc/unbound will NOT be copied.
# Keep that in mind when including configuration files in Unbonud for OpenWrt.


#=============================================
# Server Settings
#=============================================

server:

    #----------------------------------------
    # Server Modules Settings
    #----------------------------------------

    # Module configuration, a list of module names separated by spaces,
    # surround the string with quotes (""). The modules can be validator,
    # iterator. Setting this to "iterator" will result in a non-validating
    # server. Setting this to "validator iterator" will turn on DNSSEC
    # validation. The ordering of the modules is important.You must also set
    # trust-anchors for validation to be useful.
    module-config: "validator iterator"

    # Permit unbound to open this port or range of ports for use to send
    # queries. A larger number of permitted outgoing ports increases resilience
    # against spoofing attempts. Make sure these ports are not needed by other
    # daemons. By default only ports above 1024 that have not been assigned by
    # IANA are used. Give a port number or a range of the form "low-high",
    # without spaces.
    # The outgoing-port-permit and outgoing-port-avoid statements are processed
    # in the line order of the config file, adding the permitted ports and
    # subtracting the avoided ports from the set of allowed ports. The
    # processing starts with the non IANA allocated ports above 1024 in the set
    # of allowed ports.
    # OpenWrt default: "10240-65335"
    outgoing-port-permit: 38866-39680

    # Do not permit unbound to open this port or range of ports for use to send
    # queries. Use this to make sure unbound does not grab a port that another
    # daemon needs. The port is avoided on all outgoing interfaces, both IP4 and
    # IP6. By default only ports above 1024 that have not been assigned by IANA
    # are used. Give a port number or a range of the form "low-high", without
    # spaces.
    # Ports above 1'024
    outgoing-port-avoid: 1194 #; OpenVPN UDP port
    outgoing-port-avoid: 5060-5061 #; SIP Signaling UDP port
    outgoing-port-avoid: 9001 #; TOR Relay
    outgoing-port-avoid: 9030 #; TOR Relay
    # Ports above 10'000
    outgoing-port-avoid: 55867 #; Our WireGuard Port 
    outgoing-port-avoid: 29170-29998 #; Outgoing ports of our primary server
    outgoing-port-avoid: 51414 #; BitTorrent UDP port we use.
    outgoing-port-avoid: 64000-65535 #; MicoTik RouterOS bandwidth tests
    outgoing-port-avoid: 64738 #; Mumble Server UDP port

    # Number of outgoing TCP buffers to allocate per thread. If set to 0, or if
    # do-tcp is "no", no TCP queries to authoritative servers are done. For larger
    # installations increasing this value is a good idea.
    # Default: 10. OpenWrt default: 1
    outgoing-num-tcp: 4

    # Number of incoming TCP buffers to allocate per thread. If set to 0, or if
    # do-tcp is "no", no  TCP  queries  from clients are accepted. For larger
    # installations increasing this value is a good idea.
    # Default: 10. OpenWrt default: 1
    incoming-num-tcp: 4

    # Detect source interface on UDP queries and copy them to replies. This
    # feature is experimental, and needs support in your OS for particular
    # socket options.
    # Default: no
    #interface-automatic: no

    # Number of bytes size to advertise as the EDNS reassembly buffer size. This
    # is the value put into datagrams over UDP towards peers. The actual buffer
    # size is determined by msg-buffer-size (both for TCP and UDP). Do not set
    # higher than that value. Default is 4096 which is RFC recommended. If you
    # have fragmentation reassembly problems, usually seen as timeouts, then a
    # value of 1472 can fix it. Setting to 512 bypasses even the most stringent
    # path MTU problems, but is seen as extreme, since the amount of TCP
    # fallback generated is excessive (probably also for this resolver, consider
    # tuning the outgoing tcp number).
    # Default; 4096
    #edns-buffer-size: 4096

    # Number of bytes size of the message buffers. The default of 65552 bytes is
    # enough for 64 Kb packets, the maximum DNS message size. No message larger
    # than this can be sent or received. Can be reduced to use less memory, but
    # some requests for DNS data, such as for huge resource records, will result
    # in a SERVFAIL reply to the client.
    # Default: 65552, OpenWrt default: 8192
    msg-buffer-size: 65552


#=============================================
# Configuration Files to include
#=============================================

# Local system resources, performance and cache settings
include: "tuning.conf"

# Root Zone Hint Configuration
include: "root-hints.conf"

# Common configuration settings
include: "/etc/unbound/unbound.conf.d/*.conf"

# Local zones (private subnets, domains and public keys)
include: "/etc/unbound/local-zones.d/*.conf"

# Adservers and other blacklists and blocklists
include: "/etc/unbound/adservers.d/*.conf"

# Root Forward Zone (upstream DNS providers)
include: "/etc/unbound/upstream-resolvers.d/init7.conf"

# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Performance Tuning

/etc/unbound/tuning.conf

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#
# Unbound configuration file for OpenWrt.
#

#=============================================
# Server Settings
#=============================================

server:

    #------------------------------------------
    # System Resources and Performance Settings
    #------------------------------------------

    # The number of threads to create to serve clients.
    # Use 1 for no threading.
    # OpenWrt default: 1
    num-threads: 1

    # Number of ports to open. This number of file descriptors can be
    # opened per thread. Must be at least 1. Default depends on com-
    # pile options. Larger numbers need extra resources from the oper-
    # ating system. For performance a very large value is best, use
    # libevent to make this possible.
    # OpenWrt default: 60
    #outgoing-range: 60

    # The number of queries that every thread will service  simultaneously. If
    # more queries  arrive  that  need servicing, and no queries can be jostled
    # out (see jostle-timeout), then the queries are dropped. This forces the
    # client to resend after a timeout; allowing the server time to work on the
    # existing queries.
    # Default depends on compile options, 512 or 1024. OpenWrt default: 30
    num-queries-per-thread: 64

    # If not 0, then set the SO_RCVBUF socket option to get more buffer space on
    # UDP port 53 incoming queries. So that short spikes on busy servers do not
    # drop packets (see counter in netstat -su). Otherwise, the number of bytes
    # to ask for, try "4m" on a busy server. The OS caps it at a maximum, on
    # linux unbound needs root permission to bypass the limit, or the admin can
    # use sysctl net.core.rmem_max.
    # Default is 0 (use system value).
    #so-rcvbuf: 0

    # If not 0, then set the SO_SNDBUF socket option to get more buffer space on
    # UDP port 53 outgoing queries. This for very busy servers handles spikes in
    # answer traffic, otherwise 'send: resource temporarily unavailable' can get
    # logged, the buffer overrun is also visible by netstat -su. Specify the
    # number of bytes to ask for, try "4m" on a very busy server. The OS caps it
    # at a maximum, on linux unbound needs root permission to bypass the limit,
    # or the admin can use sysctl net.core.wmem_max.
    # Default is 0 (use system value).
    #so-sndbuf: 0

    # If yes, then open dedicated listening sockets for incoming queries for
    # each thread and try to set the SO_REUSEPORT socket option on each socket.
    # May distribute incoming queries to threads more evenly. Default is no. On
    # Linux it is supported in  kernels >= 3.9. On other systems, FreeBSD, OSX
    # it may also work.You can enable it (on any platform and kernel), it then
    # attempts to open the port and passes the option if it was available at
    # compile time, if that works it is used, if it fails, it continues silently
    # (unless verbosity 3) without the option.
    # Default: no
    so-reuseport: yes

    # If yes, Unbound rotates RRSet order in response (the random number is
    # taken from the query ID, for speed and thread safety).
    # Default: no
    rrset-roundrobin: yes

    # If yes, Unbound doesn't insert authority/additional sections into response
    # messages when those sections are not required. This reduces response size
    # significantly, and may avoid TCP fallback for some responses. This may
    # cause a slight speedup. The default is no, because the DNS protocol RFCs
    # mandate these sections, and the additional content could be of use and
    # save roundtrips for clients.
    # Default: no
    minimal-responses: yes

    #----------------------------------------
    # Cache Settings
    #----------------------------------------

    #----------------------------------------
    # Message Cache Settings

    # Number of bytes size of the message cache. A plain number is in bytes,
    # append 'k', 'm'  or  'g' for kilobytes, megabytes or gigabytes (1024*1024
    # bytes in a megabyte).
    # Default: 4m, OpenWrt default: 100k
    msg-cache-size:4m

    # Number of slabs in the message cache. Slabs reduce lock contention by
    # threads. Must be set to a power of 2. Setting (close) to the number of
    # cpus is a reasonable guess.
    # OpenWrt default: 1
    msg-cache-slabs: 1

    # If yes, message cache elements are prefetched before they expire to keep
    # the cache up to date. Default is no. Turning it on gives about 10 percent
    # more traffic and load on the machine, but popular items do not expire from
    # the cache.
    # Default: no
    prefetch: yes

    # If enabled, unbound attempts to serve old responses from cache with a TTL
    # of 0 in the response without waiting for the actual resolution to finish.
    # The actual resolution answer ends up in the cache later on.
    # Default: no
    serve-expired: yes

    #----------------------------------------
    # Resource Records Cache Settings

    # Number of bytes size of the RRset cache. Default is 4 megabytes. A plain
    # number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes or
    # gigabytes (1024*1024 bytes in a megabyte).
    # Default: 4m, OpenWrt default: 100k
    rrset-cache-size: 4m

    # Number of slabs in the RRset cache. Slabs reduce lock contention by
    # threads, but fragment memory usage. Must be set to a power of 2.
    # OpenWrt default: 1
    rrset-cache-slabs: 1

    # Time to live maximum for RRsets and messages in the cache. If the maximum
    # kicks in, responses to clients still get decrementing TTLs based on the
    # original (larger) values. When the internal TTL expires, the cache item has
    # expired. Can be set lower to force the resolver to query for data often, and
    # not trust (very large) TTL values.
    # Default: 86400 (1 day)
    #cache-max-ttl: 86400

    # Time to live minimum for RRsets and messages in the cache. If the minimum
    # kicks in, the data is cached for longer than the domain owner intended,
    # and thus less queries are made to look up the data. Zero makes sure the
    # data in the cache is as the domain owner intended, higher values,
    # especially more than an hour or so, can lead to trouble as the data in the
    # cache does not match up with the actual data any more.
    # Default: 0
    cache-min-ttl: 900 # 15 min

    #----------------------------------------
    # Negative Answers Cache Settings

    # Number of bytes size of the aggressive negative cache. A plain number is
    # in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes or gigabytes
    # (1024*1024 bytes in a megabyte).
    # Default: 1m. OpenWRT default: 10k
    neg-cache-size: 500k

    # Time to live maximum for negative responses, these have a SOA in
    # the authority section that is limited in time.
    # Default: 3600 (1 hour)
    #cache-max-negative-ttl: 3600

    # Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN and
    # other denials, using information from previous NXDOMAINs answers. It
    # helps to reduce the query rate towards targets that get a very high
    # nonexistent name lookup rate.
    # Default: no
    # Added in unbound 1.7.0
    #aggressive-nsec: yes

    #----------------------------------------
    # Infrastructure Cache Settings

    # Number of slabs in the infrastructure cache. Slabs reduce lock contention
    # by threads. Must be set to a power of 2.
    # OpenWrt default: 1
    infra-cache-slabs: 1

    # Time to live in seconds for entries in the host cache. The host cache
    # contains roundtrip timing, lameness and EDNS support information.
    # Default: 900.
    # infra-host-ttl: 900

    # Number of hosts for which information is cached.
    # Default: 10,000. OpenWrt default: 200
    infra-cache-numhosts: 2500

    # Time to live in seconds for entries in the host cache. The host cache
    # contains roundtrip timing, lameness and EDNS support information.
    # Default: 900.
    infra-host-ttl: 900

    # Lower limit in milliseconds for dynamic retransmit timeout calculation in
    # infrastructure cache. Increase this value if using forwarders that need
    # more time to do recursive name resolution.
    # Default is 50
    #infra-cache-min-rtt: 50

    #----------------------------------------
    # Key Cache Settings

    # Number of bytes size of the key cache. A plain number is in bytes, append
    # 'k', 'm' or 'g' for kilobytes, megabytes or gigabytes (1024*1024 bytes in
    # a megabyte).
    # Default: 4m. OpenWRT default: 100k
    key-cache-size: 1m

    # Number of slabs in the key cache. Slabs reduce lock contention by threads.
    # Must be set to a power of 2. Setting (close) to the number of cpus is a
    # reasonable guess.
    # OpenWrt default: 1
    key-cache-slabs: 1

    # If yes, fetch the DNSKEYs earlier in the validation process, when a DS
    # record is encountered. This lowers the latency of requests. It does use a
    # little more CPU. Also if the cache is set to 0, it is no use.
    # Default: no.
    prefetch-key: yes

Root Hints

/etc/unbound/root-hints.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#=============================================
# Server Settings
#=============================================

server:

    #----------------------------------------
    # Root Zone Hints
    #----------------------------------------

    # Read the root hints from this file. Default is nothing, using
    # builtin hints for the IN class. The file has the format of zone
    # files, with root nameserver names and addresses only. The
    # default may become outdated, when servers change, therefore it
    # is good practice to use a root-hints file.
    # See https://www.iana.org/domains/root/files
    # Default: none
    root-hints: "root-hints.cache"

# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Common Settings

Access Control

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#=============================================
# Unbound Server Settings for OpenWrt
#=============================================

server:

    #----------------------------------------
    # Access Control Settings
    #----------------------------------------

    # Default: Only localhost is allowed, the rest is refused.
    # OpenWrt default: 0.0.0.0/0 allow, ::0/0 allow

    # Deny all IPv4
    access-control: 0.0.0.0/0 refuse
    # Allow IPv4 localhost
    access-control: 127.0.0.0/8 allow
    # Allow private IPv4 addresses (RFC 1918)
    access-control: 10.0.0.0/8 allow
    access-control: 172.16.0.0/12 allow
    access-control: 192.168.0.0/16 allow
    # Allow link-local IPv4 addresses (RFC 6890 and RFC 3927)
    access-control: 169.254.0.0/16 allow
    access-control: 169.254.0.0/24 refuse
    access-control: 169.254.255.0/24 refuse

    # Deny all IPV6
    access-control: ::0/0 refuse
    # Allow IPv6 localhost
    access-control: ::1 allow
    access-control: ::ffff:127.0.0.1 allow
    # Allow link-local IPv6 addresses (RFC 4862 and RFC 4291)
    access-control: fe80::/10 allow
    # Allow private IPv6 addresses (RFC 4193)
    access-control: fc00::/7 allow
    # Allow our global public IPv6 prefix assigned to us (from our ISP)
    access-control: 2001:db8:3414::/48 allow
    # Allow our global private IPv6 prefix
    access-control: fdc1:d89e:b128::/48 allow

# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

DNS-over-TLS (DoT)

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#=============================================
# Unbound Server Settings for OpenWrt
#=============================================

server:

    #----------------------------------------
    # TLS Client Connections Settings
    #----------------------------------------

    # Service clients over SSL (on the TCP sockets), with plain DNS inside the
    # SSL stream. Give the certificate to use and private key. Requires a full
    # restart to take effect.
    # Default: "" (disabled)
    # ssl-service-key: "path/to/privatekeyfile.key"
    # ssl-service-pem: "path/to/publiccertfile.pem"
    # tls-port: 853

# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

DNSSEC

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#=============================================
# Unbound Server Settings for OpenWrt
#=============================================

server:

    #----------------------------------------
    # DNSSEC Settings
    #----------------------------------------

    # If true, disables the DNSSEC lameness check in the iterator. This check
    # sees if RRSIGs are present in the answer, when dnssec is expected, and
    # retries another authority if RRSIGs are unexpectedly missing. The
    # validator will insist in RRSIGs for DNSSEC signed domains regardless of
    # this setting, if a trust anchor is loaded.
    disable-dnssec-lame-check: no

    # File with trust anchor for one zone, which is tracked with RFC5011
    # probes. The probes are several times per month, thus the machine must be
    # online frequently. The initial file can be one with contents as
    # described in trust-anchor-file. The file is written to when the anchor
    # is updated, so the unbound user must have write permission. Write
    # permission to the file, but also to the directory it is in (to create a
    # temporary file, which is necessary to deal with filesystem full events),
    # it must also be inside the chroot (if that is used).
    # Default: "", OpenWrt default: "/var/lib/unbound/root.key"
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

    # Send RFC8145 key tag query after trust anchor priming.
    # Default; yes
    #trust-anchor-signaling: yes

    # Root key trust anchor sentinel. 
    # Default: yes
    # root-key-sentinel: yes

    # Minimum number of seconds of clock skew to apply to validated signatures.
    # A value of 10% of the signature lifetime (expiration - inception) is used,
    # capped by this setting. Default is 3600 (1  hour) which allows for
    # daylight savings differences. Lower this value for more strict checking of
    # short lived signa-tures.
    # Default: 3600
    #val-sig-skew-min: 3600

    # Maximum number of seconds of clock skew to apply to validated signatures.
    # A value of 10% of the signature lifetime (expiration - inception)  is
    # used, capped by this setting. Default is 86400 (24 hours) which allows for
    # timezone setting problems in stable  domains. Setting both min and max
    # very low  disables the clock skew allowances. Setting both min and max
    # very high makes the validator check the signature timestamps less
    # strictly.
    # Default: 86400
    #val-sig-skew-max: 86400

    # The time to live for bogus data. This is data that has failed validation;
    # due to invalid signatures or other checks. The TTL from that data cannot
    # be trusted, and this value is used instead. The value is in seconds,
    # default 60. The time interval prevents repeated revalidation of bogus
    # data.
    # Default: 60
    #val-bogus-ttl: 60

    # Instruct the validator to remove data from the additional section of
    # secure messages that are not signed properly. Messages that are insecure,
    # bogus, indeterminate or unchecked are not affected. Default is yes. Use
    # this setting to protect the users that rely on this validator for
    # authentication from potentially bad data in the additional section.
    # Default: yes
    #val-clean-additional: yes

    # Have the validator print validation failures to the log. Regardless of the
    # verbosity setting. Default is 0, off. At 1, for every user query that
    # fails a line is printed to the logs. This way you can monitor what happens
    # with validation. Use a diagnosis tool, such as dig or drill, to find out
    # why validation is failing for these queries. At 2, not only the query that
    # failed is printed but also the reason why unbound thought it was wrong and
    # which server sent the faulty data.
    # Default: 0
    #val-log-level: 0

    # Instruct the validator to mark bogus messages as indeterminate. The
    # security checks are performed, but if the result is bogus (failed
    # security), the reply is not withheld from the client with SERVFAIL as
    # usual. The client receives the bogus data. For messages that are found to
    # be secure the AD bit is set in replies. Also logging is performed as for
    # full validation. The default value is "no".
    # Default: no
    #val-permissive-mode: no

    # Instruct unbound to ignore the CD flag from clients and refuse to return
    # bogus answers to them. Thus, the CD (Checking Disabled)   flag does not
    # disable checking any more. This is useful with legacy (Window 2008
    # servers) that set the CD flag but cannot validate  DNSSEC  themselves.
    # Like this Unbound still provides them with DNSSEC protection.
    # Default: no
    #ignore-cd-flag: no

    # List of keysize and iteration count values, separated by spaces,
    # surrounded by quotes. This determines the maximum allowed NSEC3 iteration
    # count before a message is simply marked insecure instead of performing the
    # many hashing iterations. The list must be in ascending order and have at
    # least one entry. If you set it to "1024 65535" there is no restriction  to
    # NSEC3 iteration values. This table must be kept short; a very long list
    # could cause slower operation.
    # Default: "1024 150 2048 500 4096 2500"
    #val-nsec3-keysize-iterations: "1024 150 2048 500 4096  2500"

    # Instruct the auto-trust-anchor-file probe mechanism for RFC5011 autotrust
    # updates to add new trust anchors only after they have been visible for this
    # time. Default is 30 days as per the RFC.
    # Default: 2629800
    #add-holddown: 2629800

    # Instruct the auto-trust-anchor-file probe mechanism for RFC5011 autotrust
    # updates to remove revoked trust anchors after they have been kept in the
    # revoked list for this long. Default is 30 days as per the RFC.
    # Default: 2629800
    #del-holddown: 2629800

    # Instruct the auto-trust-anchor-file probe mechanism for RFC5011 autotrust
    # updates to remove missing trust anchors after they have been unseen for
    # this long. This cleans up the state file if the target zone does not
    # perform trust anchor revocation, so this makes the auto probe mechanism
    # work with zones that perform regular (non-5011) rollovers. The default is
    # 366 days. The value 0 does not remove missing anchors, as per the RFC.
    # Default: 31536000
    #keep-missing: 31536000

    # Debug option that allows the autotrust 5011 rollover timers to assume very
    # small values.
    # Default: no
    #permit-small-holddown: no

# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Remote Control

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#=============================================
# Remote Control Settings
#=============================================

remote-control:

    # Set up the keys and certificates with unbound-control-setup.

    # Enable remote control.
    # Default: no
    control-enable: yes

    # IPv4, IPv6 addresses or local socket to listen for control commands.
    # Default: localhost
    #control-interface: 127.0.0.1
    #control-interface: ::1

    # port number for remote control operations.
    # control-port: 8953

    # unbound server key file.
    server-key-file: "unbound_server.key"

    # unbound server certificate file.
    server-cert-file: "unbound_server.pem"

    # unbound-control key file.
    control-key-file: "unbound_control.key"

    # unbound-control certificate file.
    control-cert-file: "unbound_control.pem"

# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Security and Privacy

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#=============================================
# Unbound Server Settings for OpenWrt
#=============================================

server:
    #----------------------------------------
    # Security and Privacy Settings
    #----------------------------------------

    # Timeout in milliseconds used when the server is very busy. Set to a value
    # that usually results in one roundtrip to the authority servers. If too
    # many queries arrive, then 50% of the queries are allowed to run to
    # completion, and the other 50% are replaced with the new incoming query if
    # they have already spent more than their allowed time. This protects
    # against denial of service by slow queries or high query rates. Default 200
    # milliseconds. The effect is that the qps for long-lasting queries is
    # about  (num- queries- per-thread / 2) / (average time for such long
    # queries) qps. The qps for short queries can be about (num-queries- per-
    # thread / 2) / (jostle-timeout in whole seconds) qps per thread, about
    # (1024/2)*5 = 2560 qps by default.
    # Deafault: 200
    #jostle-timeout: 200

    # If enabled id.server and hostname.bind queries are refused.
    hide-identity: yes

    # Set the identity to report. If set to "", the default, then the hostname
    # of the server is returned.
    # Default: "" (server hostname)
    identity: ""

    # If enabled version.server and version.bind queries are refused.
    hide-version: yes

    # Set the version to report. If set to "", the default,  then  the package
    # version is returned.
    version: ""

    # If enabled trustanchor.unbound queries are refused.
    hide-trustanchor: yes

    # Set the target fetch policy used by unbound to determine if it should
    # fetch nameserver target addresses opportunistically.The policy is
    # described per dependency depth.
    # The number of values determines the maximum dependency depth that unbound
    # will pursue in answering a query. A value of -1 means to fetch all targets
    # opportunistically for that dependency depth. A value of 0 means to fetch
    # on demand only. A positive value fetches that many targets
    # opportunistically.
    # Enclose the list between quotes ("") and put spaces between numbers. The
    # default is "3 2 1 0 0". Setting all zeroes, "0 0 0 0 0" gives behaviour
    # closer to that of BIND 9, while setting "-1 -1 -1 -1 -1" gives behaviour
    # rumoured to be closer to that of BIND 8.
    # Default: "3 2 1 0 0", OpenWrt default: "2 1 0 0 0 0"
    target-fetch-policy: "3 2 1 0 0"

    # Very small EDNS buffer sizes from queries are ignored. Default
    # is off, since it is legal protocol wise to send these, and
    # unbound tries to give very small answers to these queries, where
    # possible.
    # Default: no. OpenWRT Default: yes
    harden-short-bufsize: no

    # Very large queries are ignored. Default is off, since it is
    # legal protocol wise to send these, and could be necessary for
    # operation if TSIG or EDNS payload is very large.
    # Default: no. OpenWrt default: yes
    harden-large-queries: no

    # Will trust glue only if it is within the servers authority.
    # Default: yes.
    harden-glue: yes

    # Require DNSSEC data for trust-anchored zones, if such data is absent, the
    # zone becomes bogus. If turned  off, and no DNSSEC data is received (or the
    # DNSKEY data fails to validate), then the zone is made insecure, this
    # behaves like there is no trust anchor. You could turn this off if you are
    # sometimes behind an intrusive firewall (of some sort) that removes DNSSEC
    # data from packets, or a zone changes from signed to unsigned to badly
    # signed often. If turned off you run the risk of a downgrade attack that
    # disables security for a zone.
    # Default: yes
    harden-dnssec-stripped: yes

    # From RFC 8020 (with title "NXDOMAIN: There Really Is Nothing Underneath"),
    # returns nxdomain to queries for a name below another  name that is already
    # known to be nxdomain. DNSSEC mandates  noerror for empty nonterminals,
    # hence this is possible. Very old software might return nxdomain for empty
    # nonterminals (that usually happen for reverse IP address lookups), and
    # thus may be incompatible with this. To try to avoid this only DNSSEC-
    # secure nxdomains are used, because the old software does not have DNSSEC.
    # Default is off. The nxdomain must be secure, this means nsec3 with optout
    # is insufficient.
    # Default: no
    harden-below-nxdomain:yes

    # Harden the referral path by performing additional queries for
    # infrastructure data. Validates the replies if trust anchors are configured
    # and the zones are signed. This enforces DNSSEC validation on nameserver NS
    # sets and the nameserver addresses that are encountered on the referral
    # path to the answer. Default off, because it burdens the authority servers,
    # and it is not RFC standard, and could lead to performance problems because
    # of the extra query load that is generated. Experimental option. If you
    # enable it consider adding more numbers after the target-fetch-policy  to
    # increase the max depth that is checked to.
    # Default: no
    harden-referral-path: no

    # Harden against algorithm downgrade when multiple algorithms are advertised
    # in the DS record. If no, allows the weakest algorithm to validate the
    # zone. Default is no. Zone signers must produce zones that allow this
    # feature to work, but sometimes they do not, and turning this option off
    # avoids that validation failure.
    # Default: no
    harden-algo-downgrade: no

    # Use 0x20-encoded random bits in the query to foil spoof attempts. This
    # perturbs the lowercase and uppercase of query names sent to authority
    # servers and checks if the reply still has the correct casing. Disabled by
    # default. This feature is an experimental implementation of draft dns-0x20.
    # Default: no
    use-caps-for-id: yes

    # Whitelist the domain so that it does not receive caps-for-id perturbed
    # queries. For domains that do not support 0x20 and also fail with fallback
    # because they keep sending different answers, like some load balancers. Can
    # be given multiple times, for different domains.
    #caps-whitelist:

    # Send minimum amount of information to upstream servers to enhance privacy.
    # Only sent minimum required labels of the QNAME and set QTYPE to NS when
    # possible. Best effort approach; full QNAME and original QTYPE will be sent
    # when upstream replies with a RCODE other than NOERROR, except when
    # receiving NXDOMAIN from a DNSSEC signed zone.
    # Default: no
    qname-minimisation: yes

    # QNAME minimisation in strict mode. Do not fall-back to sending
    # full QNAME to potentially broken nameservers. A lot of domains
    # will not be resolvable when this option in enabled. Only use if
    # you know what you are doing. This option only has effect when
    # qname-minimisation is enabled.
    # Default: no
    qname-minimisation-strict: no

    # Give IPv4 of IPv6 addresses or classless subnets. These are addresses on
    # your private network, and are not allowed to be returned for public
    # internet names. Any occurrence of such addresses are removed from DNS
    # answers. Additionally, the DNSSEC validator may mark the answers bogus.
    # This protects against so-called DNS Rebinding, where a user browser is
    # turned into a network proxy, allowing remote access through the browser to
    # other parts of your private network. Some names can be allowed to contain
    # your private addresses, by default all the local-data that you configured
    # is allowed to, and you can specify additional names using private-domain.
    # No private addresses are enabled by default. We consider to enable this
    # for the RFC1918 private IP address space by default in later releases.
    # That would enable private addresses for 10.0.0.0/8, 172.16.0.0/12
    # 192.168.0.0/16, 169.254.0.0/16 fd00::/8 and fe80::/10, since the RFC
    # standards say these addresses should not be visible on the public
    # internet. Turning on 127.0.0.0/8 would hinder many spam- blocklists as
    # they use that.
    # Private IPv4 addresses (RFC 1918)
    private-address: 10.0.0.0/8
    private-address: 172.16.0.0/12
    private-address: 192.168.0.0/16
    # Private IPv6 addresses (RFC 4193)
    private-address: fc00::/7;
    # Link-local IPv4 addresses (RFC 6890 and RFC 3927)
    private-address: 169.254.0.0/16
    # Link-local IPv6 addresses (RFC 4862 and RFC 4291)
    private-address: fe80::/10
    private-address: fd00::/8
    # Stop IPv4-mapped IPv6 addresses from bypassing the filter.
    private-address: ::ffff:0:0/96

    # If set, a total number of unwanted replies is kept track of in every
    # thread. When it reaches the threshold, a defensive action is taken and a
    # warning is printed to the log. The defensive action is to clear the rrset
    # and message caches, hopefully flushing away any poison. A value of 10
    # million is suggested.
    # Default: 0 (turned off).
    unwanted-reply-threshold: 10000000

    # Do not query the given IP address. Can be IP4 or IP6. Append
    # /num to indicate a classless delegation netblock, for example
    # like 10.2.3.4/24 or 2001::11/64.
    #do-not-query-address:

    # If yes, localhost is added to the do-not-query-address entries, both IP6
    # ::1 and IP4 127.0.0.1/8. If no, then localhost can be used to send queries
    # to.
    # Default: yes
    #do-not-query-localhost: yes

# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*-

Upstream Settings

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server:

    #----------------------------------------
    # Upstream Server Connections Settings
    #----------------------------------------

    # upstream connections use TCP only (and no UDP), "yes" or "no"
    # useful for tunneling scenarios, 
    # Default is no.
    #tcp-upstream: no

    # Enable udp upstream even if do-udp is no. This does not change anything.
    # Useful for TLS service providers, that want no udp downstream but use udp to
    # fetch data upstream. 
    # Default is no.
    #udp-upstream-without-downstream: no

    # Enabled or disable whether the upstream queries use TLS only for transport.
    # Useful in tunneling scenarios. The TLS contains plain DNS in TCP wireformat. The
    # other server must support this (see tls-service-key). If you enable this, also
    # configure a tls-cert-bundle or use tls-win-cert to load CA certs, otherwise the
    # connections cannot be authenticated. This option enables TLS for all of them,
    # but if you do not set this you can configure TLS specifically for some forward
    # zones with forward-tls-upstream. And also with stub-tls-upstream.
    # Default is no.
    #tls-upstream: <yes or no>

Upstream Resolvers

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#===============================================================
#
# Unbound Root Zone Forwarding
# Using non-public DNS resolvers recommended for Init7 customers.
# See https://www.init7.net/en/support/faq/dns-resolver/
#===============================================================
forward-zone:

    # A forward-zone entry with name "." and a "forward-addr:" will forward all
    # queries to that server (unless it can answer from the cache).
    name: .

    # IP address of server to forward to. Can be IP 4 or IP 6. To use a 
    # nondefault port for DNS communication append '@' with the port number.
    forward-addr: 2001:1620:2777:1::10
    forward-addr: 2001:1620:2777:2::20
    forward-addr: 213.144.129.20
    forward-addr: 77.109.128.2	

    # If set to "yes", queries are sent to the upstream servers first. If the
    # forwarded query returns a SERVFAIL error, unbound tries to resolve the
    # query again by itself, bypassing the upstream servers.
    # If set to "no", unbound first tries to resolve queries directly by itself,
    # without involment of upstream servers. Upstream servers are queried only
    # if direct resolution failed.
    # Default: no
    forward-first: yes

    # If enabled, data inside the forward is not cached. This is
    # useful when you want immediate changes to be visible.
    # Default: no
    #forward-no-cache: no

    # Enabled or disable whether the queries to this forwarder use TLS for
    # transport. If you enable this, also configure a tls-cert-bundle or use
    # tls-winload CA certs, otherwise the connections cannot be authenticated.
    # Default: no
    #forward-tls-upstream: no

# -*- 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
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#=============================================
# Server Settings
#=============================================

server:

    #----------------------------------------
    # Private Domains for example.net
    #----------------------------------------

    # Allow this domain, and all its subdomains to contain private addresses.
    # Give multiple times to allow multiple domain names to contain private
    # addresses.
    # Default: none.
    private-domain: home.example.net
    private-domain: office.example.net
    private-domain: mama.example.net
    private-domain: vpn.example.net

# -*- 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
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#=============================================
# Stub Zones
#=============================================

# There may be multiple "stub-zone:" clauses. Each with a "name:" and zero or
# more hostnames or IP addresses. For the stub zone this list of name-servers is
# used. Class "IN" is assumed. The servers should be authority servers, not
# recursors; unbound  performs the recursive processing itself for stub
# zones.
#
# The stub zone can be used to configure authoritative data to be used by the
# resolver that cannot be accessed using the public internet servers. This is
# useful for company-local data or private zones. Setup an authoritative server
# on a different host (or different port). Enter a config entry for unbound
# with "stub-addr: <ip address of host[@port]>". The unbound resolver can then
# access the data, without referring to the public internet for it.
#
# This setup allows DNSSEC signed zones to be served by that authoritative
# server, in which case a trusted key entry with the public key can be put in
# config, so that unbound can validate the data and set the "AD" bit on replies
# for the private zone (authoritative servers do not set the "AD" bit). This
# setup makes unbound capable of answering queries for the private zone, and can
# even set the "AD" bit ('authentic'), but the "AA" ('authoritative') bit is not
# set on these replies.
#
# Consider adding "server:" statements for "domain-insecure:" and for "local-
# zone: name nodefault" for the zone if it is a locally served zone. The
# insecure clause stops DNSSEC from invalidating the zone. The "local-zone:
# nodefault"  (or transparent) clause makes the (reverse-) zone bypass unbound's
# filtering of RFC1918 zones.


#----------------------------------------
# Stub Zone urown.net
#----------------------------------------

stub-zone:

    # Name of the stub zone.
    name: 27.172.in-addr.arpa.

    # This option is by default off. If enabled it performs NS set priming,
    # which is similar to root hints, where it starts using the list of
    # nameservers currently published by the zone. Thus, if the hint list is
    # slightly outdated, the resolver picks up a correct list online.
    # Default: no
    #stub-prime: no

    # If enabled, a query is attempted without the stub clause if it fails. The
    # data could not be retrieved and would have caused SERVFAIL because the
    # servers are unreachable, instead it is tried without this clause.
    # Default: no.
    #stub-first: no

    # Enable or disable whether the queries to this stub use SSL for transport.
    # Default: no.
    #stub-ssl-upstream: no

    # IP addresses of stub zone nameservers. Can be IP 4 or IP 6. To use a
    # non-default port for DNS communication append '@' with the port number.

    # Our primary authoritative name server
    stub-addr: 192.0.2.41
    stub-addr: 2001:db8::41
    
    # Our secondary authoritative name server
    stub-addr: 192.0.2.42
    stub-addr: 2001:db8::42

    # Name of stub zone nameserver. Is itself resolved before it isused.
    stub-host: dns1.example.net
    stub-host: dns2.example.net


#=============================================
# Server Settings
#=============================================

server:

    # --------------------------------------------------------------
    # No upstream DNSSEC for 27.172.in-addr.arpa.
    # 172.16.0.0/12 is for use in a private networks (RFC 1918)
    # --------------------------------------------------------------

    # Sets domain name to be insecure, DNSSEC chain of trust is ignored towards
    # the domain name. So a trust anchor above the domain name can not make the
    # domain secure with a DS record, such a DS record is then ignored. Also
    # keys from DLV are ignored for the domain. Can be given multiple times to
    # specify multiple domains that are treated as if unsigned. If you set trust
    # anchors for the domain they override this setting (and the domain is
    # secured).
    #
    # This can be useful if you want to make sure a trust anchor for external
    # lookups does not affect an (unsigned) internal domain. A DS record
    # externally can create validation failures for that internal domain.
    domain-insecure: '27.172.in-addr.arpa.'

    # A DS or DNSKEY RR for a key to use for validation. Multiple entries can be
    # given to specify multiple trusted keys, in addition to the trust-anchor-
    # files. The resource record is entered in the same format as 'dig' or
    # 'drill' prints them, the same format as in the zone file. Has to be on a
    # single line, with "" around it. A TTL can be specified for ease of cut and
    # paste, but is ignored. A class can be specified, but class IN is default.
    trust-anchor: "27.172.in-addr.arpa. DNSKEY 256 3 5 AwEAAa.......xkenu7"

    #--------------------------------------------
    #  Local Reverse DNS Zone for 172.27.0.0/16
    #  27.172.in-addr.arpa
    #--------------------------------------------

    # Used to turn off default contents for AS112 zones. The other types also
    # turn off default contents for the zone. The 'nodefault' option has no
    # other effect than turning off default contents for the given zone. Use
    # 'nodefault' if you use exactly that zone, if you want to use a subzone,
    # use 'transparent'.
    local-zone: "27.172.in-addr.arpa." transparent

    # Allow this domain, and all its subdomains to contain private addresses.
    # Give multiple times to allow multiple domain names to contain private
    # addresses.
    # Default: none.
    private-domain: "27.172.in-addr.arpa."

# -*- 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
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#=============================================
# Stub Zones
#=============================================

# There may be multiple "stub-zone:" clauses. Each with a "name:" and zero or
# more hostnames or IP addresses. For the stub zone this list of name-servers is
# used. Class "IN" is assumed. The servers should be authority servers, not
# recursors; unbound  performs the recursive processing itself for stub
# zones.
#
# The stub zone can be used to configure authoritative data to be used by the
# resolver that cannot be accessed using the public internet servers. This is
# useful for company-local data or private zones. Setup an authoritative server
# on a different host (or different port). Enter a config entry for unbound
# with "stub-addr: <ip address of host[@port]>". The unbound resolver can then
# access the data, without referring to the public internet for it.
#
# This setup allows DNSSEC signed zones to be served by that authoritative
# server, in which case a trusted key entry with the public key can be put in
# config, so that unbound can validate the data and set the "AD" bit on replies
# for the private zone (authoritative servers do not set the "AD" bit). This
# setup makes unbound capable of answering queries for the private zone, and can
# even set the "AD" bit ('authentic'), but the "AA" ('authoritative') bit is not
# set on these replies.
#
# Consider adding "server:" statements for "domain-insecure:" and for "local-
# zone: name nodefault" for the zone if it is a locally served zone. The
# insecure clause stops DNSSEC from invalidating the zone. The "local-zone:
# nodefault"  (or transparent) clause makes the (reverse-) zone bypass unbound's
# filtering of RFC1918 zones.


#----------------------------------------
# Stub Zone b.barracudacentral.org.
#----------------------------------------

stub-zone:

    # Name of the stub zone.
    name: b.barracudacentral.org.

    # This option is by default off. If enabled it performs NS set priming,
    # which is similar to root hints, where it starts using the list of
    # nameservers currently published by the zone. Thus, if the hint list is
    # slightly outdated, the resolver picks up a correct list online.
    # Default: no
    stub-prime: yes

    # If enabled, a query is attempted without the stub clause if it fails. The
    # data could not be retrieved and would have caused SERVFAIL because the
    # servers are unreachable, instead it is tried without this clause.
    # Default: no.
    #stub-first: no

    # Enable or disable whether the queries to this stub use SSL for transport.
    # Default: no.
    #stub-ssl-upstream: no

    # Name of stub zone nameserver. Is itself resolved before it isused.
    stub-host: blacklist-ns-az1.bci.aws.cudaops.com.
    stub-host: blacklist-ns-az2.bci.aws.cudaops.com.
    stub-host: blacklist-ns-az3.bci.aws.cudaops.com.

    # IP addresses of stub zone nameservers. Can be IP 4 or IP 6. To use a
    # non-default port for DNS communication append '@' with the port number.

    # blacklist-ns-az1.bci.aws.cudaops.com
    stub-addr: 3.13.7.254

    # blacklist-ns-az2.bci.aws.cudaops.com
    stub-addr: 3.130.175.225

    # blacklist-ns-az3.bci.aws.cudaops.com
    stub-addr: 52.15.140.229


#=============================================
# Server Settings
#=============================================

server:

    #----------------------------------------
    # Private Domains for example.net
    #----------------------------------------

    # Allow this domain, and all its subdomains to contain private addresses.
    # Give multiple times to allow multiple domain names to contain private
    # addresses.
    # Default: none.
    private-domain: b.barracudacentral.org.

    # Sets domain name to be insecure, DNSSEC chain of trust is ignored towards
    # the domain name. So a trust anchor above the domain name can not make the
    # domain secure with a DS record, such a DS record is then ignored. Also
    # keys from DLV are ignored for the domain. Can be given multiple times to
    # specify multiple domains that are treated as if unsigned. If you set trust
    # anchors for the domain they override this setting (and the domain is
    # secured).
    #
    # This can be useful if you want to make sure a trust anchor for external
    # lookups does not affect an (unsigned) internal domain. A DS record
    # externally can create validation failures for that internal domain.
    domain-insecure: b.barracudacentral.org.

    # Used to turn off default contents for AS112 zones. The other types also
    # turn off default contents for the zone. The 'nodefault' option has no
    # other effect than turning off default contents for the given zone. Use
    # 'nodefault' if you use exactly that zone, if you want to use a subzone,
    # use 'transparent'.
    local-zone: b.barracudacentral.org. nodefault

# -*- mode: ini; indent-tabs-mode: nil; tab-width: 4; -*-