$_ BSDHowTo.ch
How To... Why not..? Scripts RSS logo

How to build internal DNS using unbound(8) and nsd(8)

Last update: 2018-08-30

Introduction

OpenBSD comes with unbound(8) and nsd(8) in base. This post shows you how to combine these two tools to provide DNS for an internal network including an internal DNS zone.

Configuration of nsd(8)

In this first part you will configure nsd(8) as the authoritative name server for forward and reverse lookup zones of your internal network. I will call the forward zone example.net and the reverse zone 2.0.192.in-addr.arpa. The following entries belong into /var/nsd/etc/nsd.conf:

server:
	hide-version: yes
	ip-address: 127.0.0.1
	server-count: 1

remote-control:
	control-enable: yes

zone:
	name: "example.net"
	zonefile: "/var/nsd/zones/master/%s.dns"

zone:
	name: "2.0.192.in-addr.arpa."
	zonefile: "/var/nsd/zones/master/%s.dns"

Remote control for nsd(8)

The remote control tool nsd-control(8) let you send commands to the running nsd(8), e. g. to reread a changed zone file without restarting the whole daemon. You need to run a setup tool once to generate the certificates and keys for nsd-control(8):

$ doas nsd-control-setup

The zone files for nsd(8)

The next step is to write the zone files for nsd(8). First the forward lookup zone example.net:

$ORIGIN .
$TTL 3600	; 1 hour
example.net	IN SOA	dns.example.net. admin.example.net. (
			1   ; serial
			86400   ; refresh (1 day)
			3600    ; retry (1 hour)
			604800  ; expire (1 week)
			3600    ; minimum (1 hour)
			)
		NS	dns.example.net.
$ORIGIN example.net.
dns		A	192.0.2.11
router		A	192.0.2.1
server		A	192.0.2.80
www		CNAME	server

Save this zone file as /var/nsd/zones/master/example.net.dns. Second, the reverse lookup zone 2.0.192.in-addr.arpa.:

$ORIGIN .
$TTL 3600	; 1 hour
2.0.192.in-addr.arpa	IN SOA	dns.example.net. admin.example.net. (
				1   ; serial
				86400   ; refresh (1 day)
				3600    ; retry (1 hour)
				604800  ; expire (1 week)
				3600    ; minimum (1 hour)
				)
			NS	dns.example.net.
$ORIGIN 2.0.192.in-addr.arpa.
1			PTR	router.example.net.
11			PTR	dns.example.net.
80			PTR	server.example.net.

Save this zone file as /var/nsd/zones/master/2.0.192.in-addr.arpa.dns.

Configuration of unbound(8)

The configuration of unbound(8) I show you in this post turns unbound(8) into a iterative, caching and validating resolver. The content of the file /var/unbound/etc/unbound.conf is:

server:
	access-control: 192.0.2.0/24 allow
	auto-trust-anchor-file: "/var/unbound/db/root.key"
	domain-insecure: example.net
	domain-insecure: 2.0.192.in-addr.arpa
	hide-identity: yes
	hide-version: yes
	insecure-lan-zones: yes
	interface: 192.0.2.11
	num-threads: 1
	prefetch: yes
	private-domain: example.net
	private-domain: 2.0.192.in-addr.arpa
	root-hints: "/var/unbound/db/root.hints"
	qname-minimisation: yes
	unblock-lan-zones: yes

remote-control:
	control-enable: yes
	control-interface: 192.0.2.11

stub-zone:
	name: "example.net"
	stub-addr: 127.0.0.1

Remote control for unbound(8)

The remote control tool unbound-control(8) let you send commands to the running unbound(8), e. g. to flush the cache without restarting the whole daemon. You need to run a setup tool once to generate the certificates and keys for unbound-control(8):

$ doas unbound-control-setup

Configuration check and start

Both nsd(8) and unbound(8) bring along a tool to check the configuration file before you start or reload the daemon. You should start with nsd(8):

$ doas nsd-checkconf

Any errors are reported, so no news are good news. You can go ahead and start nsd(8):

$ doas rcctl enable nsd
$ doas rcctl start nsd

Now repeat the dance for unbound(8). First check the configuration file for errors:

$ doas unbound-checkconf
unbound-checkconf: no errors in /var/unbound/etc/unbound.conf

Time to start unbound(8);

$ doas rcctl enable unbound
$ doas rcctl start unbound

If you want the server to use unbound(8) itself you must adapt resolv.conf(5) to use the IP address unbound(8) is listening on:

search example.net
nameserver 192.0.2.11
lookup file bind