NSD DNS server

Supporting External Domains

Make config file for external domains
[ -f /var/nsd/etc/nsdext.cnf ]&&cpytobak /var/nsd/etc/nsdext.cnf
echo ${VISUAL}
sudoedit /var/nsd/etc/nsdext.cnf

Here is a sample version of the /var/nsd/etc/nsdext.cnf file. The “server:” section can probably get by without needing to customize this section. Then, there should be one “zone:” section for each domain, and each such “zone:” will need to be customized.

server:
port: 54
server-count: 1
database: ""
zonelistfile: "/var/nsd/db/zoneext.list"
username: _nsd
logfile: "/var/log/nsdext.log"
pidfile: "/var/nsd/run/nsdext.pid"
# xfrdfile: "/var/nsd/run/xfrdext.state"
xfrdfile: ""
# identity: "" (is this better blank, for security, or is this not given out publicly?)
verbosity: 2

zone:
name: example.zz.
zonefile: "/var/nsd/zones/examplzz"

zone:
name: sample.zz.
zonefile: "/var/nsd/zones/samplezz"
  • The port is intentionally not 53. IANA has port 54 reserved. Review indicates that a conflict seems unlikely to be common.
[ -f /var/nsd/etc/nsdext.cnf ]&&sudo chown _nsd:_nsd /var/nsd/etc/nsdext.cnf
Zone

Place zone file where it needs to go.

(At the moment, details on the zone file are at: BIND.) (Information may be migrated soon... for now, just check the BIND section for the details about creating the actual master “zone” files.)

Firewall configuration
Configuration on the DNS server
OpenBSD PF
cpytobak /etc/pf.conf
echo | sudo -n tee -a /etc/pf.conf
echo \# Enable DNS to main \(public/external\) authoritative DNS server| sudo -n tee -a /etc/pf.conf
echo pass quick proto udp to self port 54 keep state| sudo -n tee -a /etc/pf.conf
echo ${VISUAL}
sudoedit /etc/pf.conf

(No further changes are needed... this is just a chance to review, and easily make changes if needed.)

sudo pfctl -nf /etc/pf.conf
echo ${?}
sudo pfctl -nf /etc/pf.conf&&sudo pfctl -ef /etc/pf.conf
Configuration on main “firewall” “virtual machine”
OpenBSD PF
cpytobak /etc/pf.conf
echo | sudo -n tee -a /etc/pf.conf
echo \# Enable DNS to main \(public/external\) DNS server| sudo -n tee -a /etc/pf.conf
echo pass quick proto udp to self port 54 keep state| sudo -n tee -a /etc/pf.conf
echo ${VISUAL}
sudoedit /etc/pf.conf

(No further changes are needed... this is just a chance to review, and easily make changes if needed.)

sudo pfctl -nf /etc/pf.conf
echo ${?}
sudo pfctl -nf /etc/pf.conf&&sudo pfctl -ef /etc/pf.conf
On Physical Machine
OpenBSD PF
HTML/CSS needed...
# redirect DNS traffic to internal DNS server
pass in on $ext_if inet6 proto udp from any to self port domain \
        rdr-to 2001:db8:1::1 keep state
pass in on $ext_if inet proto udp from any to self port domain \
        rdr-to 198.51.100.1 keep state
Run:
sudo nsd -c /var/nsd/etc/nsdext.cnf
echo ${?}
netstat -na | grep \.54

Sample log view

$ sudo tail /var/log/nsdext.log
[YYYY-MM-DD hh:mm:ss.???] nsd[PID##]: info: zone example.zz. read with no errors
[YYYY-MM-DD hh:mm:ss.???] nsd[PID##]: info: zone sample.zz. read with no errors
[YYYY-MM-DD hh:mm:ss.???] nsd[PID##]: info: zone example3.zz. read with no errors
[YYYY-MM-DD hh:mm:ss.???] nsd[PID##]: notice: nsd started (NSD #.#.#), pid ####
$

(In that last line, the PID at the end of the message's content does not match the PID shown in brackets.)

Sample tests

nslookup -po=54 example.zz 127.0.0.1
dig @127.0.0.1 -p 54 example.zz

Supporting Internal Domains

Make config file for internal domains

The goal here is going to be to support internal zone files. Initially, this will only work for localhost from the DNS server (because that is simplest to set up, without creating additional steps overall). Then, support for other internal systems will be added.
[ -f /var/nsd/etc/nsdint.cnf ]&&cpytobak /var/nsd/etc/nsdint.cnf
echo ${VISUAL}
sudoedit /var/nsd/etc/nsdint.cnf

Here is a sample version of the /var/nsd/etc/nsdint.cnf file. The “server:” section can probably get by without needing to customize this section. Then, there should be one “zone:” section for each domain, and each such “zone:” will need to be customized.

server:
port: 53
ip-address: ::1 # IPv6 loopback
ip-address: 127.0.0.1 # IPv4 loopback
server-count: 1
database: ""
zonelistfile: "/var/nsd/db/zoneint.list"
username: _nsd
logfile: "/var/log/nsdint.log"
pidfile: "/var/nsd/run/nsdint.pid"
# xfrdfile: "/var/nsd/run/xfrdint.state"
xfrdfile: ""
# identity: "" (is this better blank, for security, or is this not given out publicly?)
verbosity: 2
#control-port: 8952

zone:
name: example.zz.
zonefile: "/var/nsd/zones/internal/iexamplzz"

zone:
name: sample.zz.
zonefile: "/var/nsd/zones/internal/isamplezz"

zone:
name: justinternal.zz.
zonefile: "/var/nsd/zones/internal/ijstintzz"

(The sample shown supports all of the same domains as the public DNS server, plus another domain which is used internally.)

Make the new file readable by the necessary user.

[ -f /var/nsd/etc/nsdint.cnf ]&&sudo chown _nsd /var/nsd/etc/nsdint.cnf

Test:

[ -f /var/nsd/etc/nsdint.cnf ]&&sudo -u _nsd nsd-checkconf /var/nsd/etc/nsdint.cnf
echo ${?}
Zone

Place zone file where it needs to go.

(At the moment, details on the zone file are at: BIND.) (Information may be migrated soon... for now, just check the BIND section for the details about creating the actual master “zone” files.)

Firewall configuration
Configuration on the DNS server
OpenBSD PF
cpytobak /etc/pf.conf
echo | sudo -n tee -a /etc/pf.conf
echo \# Enable DNS to internal authoritative DNS server| sudo -n tee -a /etc/pf.conf
echo pass quick proto udp to self port domain keep state| sudo -n tee -a /etc/pf.conf
echo ${VISUAL}
sudoedit /etc/pf.conf

One item to note: The above firewall rule permits incoming traffic to self but all that is really needed is incoming traffic to the loopback interface (loopback, localhost addresses). However, other addresses should become enabled at a later stage, so this guide simplifies things by making a rule that will cover later requirements as well, reducing the number of steps that need to be performed.

sudo pfctl -nf /etc/pf.conf
echo ${?}
sudo pfctl -nf /etc/pf.conf&&sudo pfctl -ef /etc/pf.conf
Run:
nsd -c /var/nsd/etc/nsdint.cnf
echo ${?}
netstat -na | grep \.53

Supporting Internal Lookups

For lookups on the internal network, other than from localhost addresses (::1 and 127.0.0.1) on the DNS server itself, this guide is not recommending to use NSD for those lookups. Instead, follow the virtual machine: Unbound server guide to set up that software.

Firewall Handling for internal lookups

There might not be any steps that are necessary for handling firewall traffic, because rules that permit the desired traffic might already exist. However, if traffic for internal lookups is needed, then such details are discussed by the virtual machine: Unbound server guide.

Testing

From the machine running the “DNS server” software, perform a query to the external NIC's IP address.

nslookup example.zz 2001:db8:1::4
dig @2001:db8:1::4 example.zz

Make sure to query both an internal domain name, and a domain name on the Internet. (That is bare minimum of what is recommended... a more thorough process would be to send a testing query about every single internal domain.)

Then, verify the “firewall” virtual machine's rules permit traffic from the physical machine.

More/Follow-Up

Post-reboot survival
OpenBSD
OpenBSD (5.6 and newer)

NSD and Unbound have been included in OpenBSD 5.6, and one of the updates mentioned on OpenBSD 5.7's home page was, “BIND has been retired, encouraging use of nsd(8) and unbound(8).”

[ -f /etc/rc.conf.local ]&&cpytobak /etc/rc.conf.local
echo | sudo -n tee -a /etc/rc.conf.local
echo nsd_flags=\"-c /var/nsd/etc/nsdint.cnf\"| sudo -n tee -a /etc/rc.conf.local

Also, take care of this section about supporting the external domains.

[ -f /etc/rc.local ]&&cpytobak /etc/rc.local
echo | sudo -n tee -a /etc/rc.local
echo nsd -c /var/nsd/etc/nsdext.cnf| sudo -n tee -a /etc/rc.local

(Note: For users who use both NSD and another DNS server, that only covers the Post-reboot survivability of NSD.)