Split DNS done right: 2 servers; NSD and BIND9
Open recursors are a problem. They can be used by attackers to amplify a packet stream to a victim. As such you should only be running a recursor on your internal network and an authoritative server on your interfaces facing the big, bad Internet.
You can run BIND9 with a split view (also called ‘split brain’), or use my setup: a NSD serving the outside world, and using BIND9 as recursor for your internal network.
Zones⌗
I’m the owner of multiple domains, among which miek.nl
is just one. For the purpose
of this article I will pretend this is the only domain I have. The goal here is to
have this domain available both inside my network and on the outside. And to have
recursion on the inside, but not on the outside.
Internet side⌗
The config for miek.nl
looks like this. This does assume how to read these kind
of files. The zone file is relatively short and nothing fancy happens.
For completeness, I’m using puppet for my
/etc/
configuration – you should too! :)
;
; NSD data file for miek.nl for public use
; ## configured with puppet ##
;
$TTL 1D
$ORIGIN miek.nl.
@ IN SOA open.nlnetlabs.nl. miekg.atoom.net. (
2007032000 ; Serial
4H ; Refresh
1H ; Retry
7D ; Expire
1D ) ; Negative Cache TTL
IN NS open.nlnetlabs.nl.
IN NS omval.tednet.nl.
IN NS elektron.atoom.net.
IN MX 20 mail.atoom.net.
IN MX 30 sol.nlnetlabs.nl.
miek.nl. IN A 80.127.17.126
localhost IN A 127.0.0.1
a IN A 80.127.17.126
www IN CNAME a
This zonefile contains real IP addresses, which can be resolved on the Internet.
Internal side For internal use I’m using a slightly different zone (the joy of NAT), which looks like this:
;
; BIND data file for miek.nl for internal use
;
$TTL 1H
@ IN SOA elektron.atoom.net. miekg.atoom.net. (
2005060700 ; Serial
6H ; Refresh
2H ; Retry
7D ; Expire
1H ) ; Negative Cache TTL
@ IN NS elektron.atoom.net.
@ IN MX 10 elektron.atoom.net.
@ IN A 192.168.1.2
localhost IN A 127.0.0.1
a IN A 192.168.1.2
www IN CNAME a
And you can see that only RFC1918 addresses are used here.
Setup⌗
So how do you actually perform the setup so that you have two servers running? First install the software packages you’ll need (This is on Ubuntu/Debian):
Install nsd:
apt-get install nsd
Install bind9
apt-get install bind9
Configuration⌗
BIND
Well, BIND
is pretty well known and you can find loads of howtos on how to setup this daemon.
I’m only interested in making is listening on the intranet interfaces, in my
case (i’m only showing the relevant parts of the named.conf
configuration file):
// This is the primary configuration file for the BIND DNS server named.
// ## configured with puppet ##
options {
directory "/var/cache/bind";
recursion yes;
listen-on { 127.0.0.1; 192.168.1.2; ::1; 10.0.0.1; };
};
Note the recursion yes
, without this I wouldn’t be able to resolve names on my internal
network.
My /etc/resolv.conf
ofcourse lists my own server as nameserver:
# ## configured with puppet ##
nameserver 127.0.0.1
search atoom.net. dmz.atoom.net.
So this takes care of my internal needs.
NSD
For NSD (version 2) I need to configure which zones are to be loaded. This is done in the
nsd.zones
file:
; ## configured with puppet ##
; forward
zone miek.nl zones/db.miek.nl notify 213.154.224.1 213.154.224.17
Next I need to tell NSD
that it should listen on my external network interfaces.
On debian/Ubuntu this is handled in the file /etc/default/nsd
. On my system it looks like this
(only the relevant parts are shown):
# Flags to pass to nsd on startup
flags="-u nsd -a 80.127.17.126 -a 2001:7b8:2ff:c8::2"
This tells NSD
to listen on my external IPv4 and IPv6 addresses. Setting up and requesting
a domain name goes beyond this article.
Restart the services⌗
Basicly that was it… now BIND9 is only used on my internal network, and NSD is used for the outside. Just the way I like it; just the way it should be.
Just restart the services and you should be done:
/etc/init.d/nsd restart && /etc/init.d/bind9 restart
Check /var/log/messages/
and /var/log/daemon.log
for any errors you might get.