Skip to content

Instantly share code, notes, and snippets.

@Nilpo
Last active September 18, 2024 13:52
Show Gist options
  • Save Nilpo/1a70ebca988ad0743ea533d747445148 to your computer and use it in GitHub Desktop.
Save Nilpo/1a70ebca988ad0743ea533d747445148 to your computer and use it in GitHub Desktop.
How to configure BIND 9 to act as a caching nameserver or as the nameserver for a local domain.

BIND for the SMALL LAN

How to configure BIND 9 to act as a caching nameserver or as the nameserver for a local domain.

Contents

Note: This article was written at the request of Carla Schroder, and portions of it appear by permission in edited form in her very fine volume, The Linux Cookbook (O’Reilly, 2004).

Why serve DNS locally?

There are two good reasons for putting a DNS server on your local network, even if your local server isn’t answering queries about your network coming from other hosts on the Internet:

  1. It can speed up network operations like web browsing that involve frequent hostname lookups.

  2. It can provide your network with a central repository of local machine information without having to copy files all around the network.

There’s a third reason: it can be educational and fun. Running a local server will teach you at least a little bit about DNS operations—learning that could possibly come in handy during job interviews—and it provides some satisfaction to those who like to build things themselves.

Building a caching nameserver

The easiest project is setting up BIND to do nothing but cache DNS information locally. A caching server doesn’t provide any authoritative information; it just remembers the answers to previous lookups in case the same lookup is performed again.

Consider the typical small office. It’s a good hunch that, during a typical workday, nearly every workstation will want to know the address of popular hosts like www.google.com. Rather than having every workstation ask Google’s name server for that information, they can ask the local caching nameserver, which only needs to ask for that information once every so often.

A caching nameserver handles three duties:

  1. It looks up host information on the Internet and passes it back to the local network.

  2. It tells your network clients the address of localhost.

  3. It tells your network clients the hostname associated with the address 127.0.0.1.

On a Linux host, the information for the last two items are typically managed by /etc/hosts, but it’s prudent to provide information about the loopback interface via DNS as well.

Using BIND, a caching nameserver will require four configuration files: the main configuration file for named, a list of the root name servers, a definition of localhost, and a definition of the loopback address, 127.0.0.1.

BIND configuration: named.conf

The main BIND configuration file is typically called named.conf; it usually lives in /etc or thereabouts. Red Hat packages install it as /etc/named.conf. Gentoo, on the other hand, installs it as /etc/bind/named.conf.

BIND configuration is a subject unto itself, and this example configuration file will not employ all of BIND’s bells and whistles, but it will get you going.

The sample below defines where named should find its configuration files, the networks for which it can provide authoritative answers, and how to find information for other networks.

//
// sample BIND configuration file
//

options {
  // tell named where to find files mentioned below
  directory "/var/named";
  // on a multi-homed host, you might want to tell named
  // to listen for queries only on certain interfaces
  listen-on { 127.0.0.1; 10.11.12.0/24; };
};

// The single dot (.) is the root of all DNS namespace, so
// this zone tells named where to start looking for any
// name on the Internet
zone "." IN {
  // a hint type means that we've got to look elsewhere
  // for authoritative information
  type hint;
  file "named.root";
};

// Where the localhost hostname is defined
zone "localhost" IN {
  // a master type means that this server needn't look
  // anywhere else for information; the localhost buck
  // stops here.
  type master;
  file "zone.localhost";
  // don't allow dynamic DNS clients to update info
  // about the localhost zone
  allow-update { none; };
};

// Where the 127.0.0.0 network is defined
zone "0.0.127.in-addr.arpa" IN {
  type master;
  file "revp.127.0.0";
  allow-update { none; };
};

The root nameservers: named.root

The first zone definition listed in the example named.conf tells named how to find information about foreign networks. In the example, the file is called named.root, though you can give it any name you like. It lists the names and addresses of all the root name servers.

Unlike the other configuration files in this example, this file is maintained by someone other than you. The folks at InterNIC make it available via ftp: ftp://ftp.internic.net/domain/named.root. This file doesn’t change all that often, but you’ll want to check ftp.internic.net every so often just to make sure.

;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;
;       This file is made available by InterNIC 
;       under anonymous FTP as
;           file                /domain/named.root
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:    Jan 29, 2004
;       related version of root zone:   2004012900
;
;
; formerly NS.INTERNIC.NET
;
.                        3600000  IN  NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
;
; formerly NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     192.228.79.201
;
; formerly C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
;
; formerly TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     128.8.10.90
;
; formerly NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
;
; formerly NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
;
; formerly NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
;
; formerly AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     128.63.2.53
;
; formerly NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
;
; operated by VeriSign, Inc.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
;
; operated by RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129 
;
; operated by ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     198.32.64.12
;
; operated by WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
; End of File

Defining localhost

The third configuration file is much more cryptic than the first two. In this example, it’s called zone.localhost, but that name is arbitrary. You could call it linux.rocks if you were so inclined. It tells named that the address of localhost is 127.0.0.1.

;
; loopback/localhost zone file
;
$TTL 1D
$ORIGIN localhost.
@              IN  SOA   @  root (
                         1   ; Serial
                         8H  ; Refresh
                         15M ; Retry
                         1W  ; Expire
                         1D) ; Minimum TTL
               IN   NS   @
               IN   A    127.0.0.1

Defining 127.0.0.1

The last config file tells named that the hostname associated with the IP address 127.0.0.1 is localhost.

;
; reverse pointers for localhost
;
$TTL 1D
$ORIGIN 0.0.127.in-addr.arpa.
@    IN   SOA  localhost. root.localhost. (
               1    ; serial
               8H   ; refresh
               15M  ; retry
               1W   ; expire
               1D ) ; minimum
     IN   NS   localhost.
1    IN   PTR  localhost.

That’s about it. Put those files in place, start up named and you’ve got yourself a caching nameserver.

Running a local domain

If your local network consists only of a few stationary Unix hosts, then the easiest way to distribute information about local hostnames is by pushing a customized /etc/hosts to each machine.

There are a few common situations in which that simple solution might not meet your needs:

You have transitory machines like laptops or LAN-party hosts that occasionally pop up on your network, and you want to manage their network presence with DHCP.

Your local network also contains a sprinking of machines running Microsoft Windows, and the local users don’t want to be bothered by copying some obscure text file deep into the bowels of their filesystem.

Your network is getting too big to push files around manually.

People off your network need your DNS information.

Once you’ve got a caching nameserver up and running, adding information about your domain is fairly straightforward. You need to modify named.conf to tell it about your local domain, and you’ll need two files to define the names and addresses of your hosts.

Our sample network

The following samples are based on a ficticious domain named schroder.net that lives on the 10.11.12.0 subnet. There are five hosts on our network:

torvalds (10.11.12.1) for DNS, Mail stallman aka depot (10.11.12.2) for NFS/Samba file services cert aka www (10.11.12.3), our web server wall (10.11.12.4), a workstation walsh (10.11.12.5, a workstation

Beefing up named.conf

The example named.conf listed above needs only two additional zone blocks in order to know that it’s the authoritative source of information about the schroder.net domain and the 10.11.12.0 subnet.

zone "schroder.net" IN {
  // this is the authoritative server for
  // schroder.net info
  type master;
  file "zone.net.schroder";
};

zone "12.11.10.in-addr.arpa" {
  // this is the authoritative server for
  // the 10.11.12.0 network
  type master;
  file "revp.10.11.12";
};

The net.schroder zone file

We’ve told named that it’s the authoritative data source for the schroder.net domain, so now it’s time to define it.

This zone file will be a bit more complex than the one we created for the localhost zone. It will have to have an entry for each host, plus it will have to define the name server and mail exchanges for the network.

;
; dns zone for for schroder.net
;
$ORIGIN schroder.net.
$TTL 1D
; any time you make a change to the domain, bump the
; "serial" setting below. the format is easy:
; YYYYMMDDI, with the I being an iterator in case you
; make more than one change during any one day
@     IN SOA   torvalds hostmaster (
                        200405191 ; serial
                        8H        ; refresh
                        4H        ; retry
                        4W        ; expire
                        1D )      ; minimum
; torvalds.schroder.net serves this domain as both the
; name server (NS) and mail exchange (MX)
                NS      torvalds
                MX      10 torvalds
; define domain functions with CNAMEs
depot           CNAME   stallman
www             CNAME   cerf
; just in case someone asks for localhost.schroder.net
localhost       A       127.0.0.1
; our hostnames, in alphabetical order
cerf            A       10.11.12.3
stallman        A       10.11.12.2
torvalds        A       10.11.12.1
wall            A       10.11.12.4
walsh           A       10.11.12.5

The 10.11.12.0 reverse pointers

The reverse pointer file ensures that each host’s IP address points back to the correct hostname. The in-addr.arpa domain was established to provide address-to-host mapping. A host’s IP address is reversed to form its hostname in this domain, so, e.g., 10.11.12.1 would become 1.12.11.10.in-addr.arpa.

For our example domain, we’ll set up reverse pointers for the 10.11.12.0 subnet.

;
; reverse pointers for 10.11.12.0 subnet
;
$ORIGIN 12.11.10.in-addr.arpa.
$TTL 1D
@     IN SOA  torvalds.schroder.net. hostmaster.schroder.net. (
              200405190  ; serial
              28800      ; refresh (8 hours)
              14400      ; retry (4 hours)
              2419200    ; expire (4 weeks)
              86400      ; minimum (1 day)
              )
; define the authoritative name server
              NS      torvalds.schroder.net.
; our hosts, in numeric order
1             PTR     torvalds.schroder.net.
2             PTR     stallman.schroder.net.
3             PTR     cerf.schroder.net.
4             PTR     wall.schroder.net.
5             PTR     walsh.schroder.net.

Putting it all together

You’ve now got the six configuration files necessary to run your nameserver:

named.conf, the main configuration file for named,

named.root, containing the names and addresses of the Internet’s root nameservers,

zone.localhost, containing the address for localhost,

revp.127.0.0, containing reverse pointers for the 127.0.0.0 network,

zone.net.schroder, containing the addresses and hostnames for our sample domain, and

revp.10.11.12, containing reverse pointers for our domain’s IP address space.

The named.conf gets installed into /etc or thereabouts, while the others all go into the the directory specified in named.conf, which in our example is /var/named.

Once they’re all in place, start up named and give it a whirl!

Adding a secondary nameserver

At some point, your network may grow large enough, or receive enough DNS traffic, that you’ll have to have a backup nameserver to relieve traffic on the main server and to have an alternative source for information when your primary nameserver is unavailable.

Once your primary nameserver is properly configured, adding a secondary isn’t terribly difficult. There are basically three steps:

Tweak the primary’s named.conf so that it’ll transfer information to the secondary and notify it when changes are made to the local domain.

Tweak the zone and reverse-pointer configs for the local domain so that the secondary is listed as one of the authoritative nameservers for the domain.

Get a caching nameserver running on the host that will serve as secondary and then tweak the configs so that it’s aware of its role as secondary.

Configuring named.conf to know about a secondary nameserver

Telling named about a secondary is very easy: just add an also-notify block to zones for the local domain. The only information you really need is the IP address of the secondary. For this example, we’ll make cerf, the web server, our secondary.

Whenever you made a change to the local domain, just bump the serial number and restart named or tell it to reload its config files. A notice will be sent, and the secondary, upon seeing a new, larger serial number, will ask for a zone transfer to bring itself up to date.

zone "schroder.net" IN {
  // this is the authoritative server for
  // schroder.net info
  type master;
  file "zone.net.schroder";
  // tell cerf when changes get made
  also-notify { 10.11.12.3; }
};

zone "12.11.10.in-addr.arpa" {
  // this is the authoritative server for
  // the 10.11.12.0 network
  type master;
  file "revp.10.11.12";
  also-notify { 10.11.12.3; }
};

Adding a second NS record

The second task in bringing a secondary online is to add a second NS record, letting everyone know that both the primary and the secondary nameservers are available to answer questions about your domain.

A simple one-line addition to both the zone and reverse-pointer configuration files is all that’s needed to define a second nameserver.

;
; dns zone for for schroder.net
;
$ORIGIN schroder.net.
$TTL 1D
; any time you make a change to the domain, bump the
; "serial" setting below. the format is easy:
; YYYYMMDDI, with the I being an iterator in case you
; make more than one change during any one day
@     IN SOA   torvalds hostmaster (
                        200405191 ; serial
                        8H        ; refresh
                        4H        ; retry
                        4W        ; expire
                        1D )      ; minimum
; torvalds and cerf are our name servers, while torvalds also
; serves as the mail exchange (MX)
                NS      torvalds
                NS      cerf
                MX      10 torvalds
; define domain functions with CNAMEs
depot           CNAME   stallman
www             CNAME   cerf
; just in case someone asks for localhost.schroder.net
localhost       A       127.0.0.1
; our hostnames, in alphabetical order
cerf            A       10.11.12.3
stallman        A       10.11.12.2
torvalds        A       10.11.12.1
wall            A       10.11.12.4
walsh           A       10.11.12.5
;
; reverse pointers for 10.11.12.0 subnet
;
$ORIGIN 12.11.10.in-addr.arpa.
$TTL 1D
@     IN SOA  torvalds.schroder.net. hostmaster.schroder.net. (
              200405190  ; serial
              28800      ; refresh (8 hours)
              14400      ; retry (4 hours)
              2419200    ; expire (4 weeks)
              86400      ; minimum (1 day)
              )
; define the authoritative name servers
              NS      torvalds.schroder.net.
              NS      cerf.schroder.net.
; our hosts, in numeric order
1             PTR     torvalds.schroder.net.
2             PTR     stallman.schroder.net.
3             PTR     cerf.schroder.net.
4             PTR     wall.schroder.net.
5             PTR     walsh.schroder.net.

Configuring the secondary

Finally, we need to configure the secondary nameserver. You’ll want to follow the instructions for getting a caching nameserver up and running. Once that’s done, you’ll add zone records for the domain and reverse-pointer information.

The major difference between this configuration and the primary’s is that the type is set to “slave” and we have to tell named where to find the primary. Otherwise, this named.conf looks similar to the one we wrote for the primary.

//
// sample BIND configuration file
//

options {
  // tell named where to find files mentioned below
  directory "/var/named";
  // on a multi-homed host, you might want to tell named
  // to listen for queries only on certain interfaces
  listen-on { 127.0.0.1; 10.11.12.0/24; }
}

// The single dot (.) is the root of all DNS namespace, so
// this zone tells named where to start looking for any
// name on the Internet
zone "." IN {
  // a hint type means that we've got to look elsewhere
  // for authoritative information
  type hint;
  file "named.root";
};

// Where the localhost hostname is defined
zone "localhost" IN {
  type master;
  file "zone.localhost";
  // don't allow dynamic DNS clients to update info
  // about the localhost zone
  allow-update { none; };
};

// Where the 127.0.0.0 network is defined
zone "0.0.127.in-addr.arpa" IN {
  type master;
  file "revp.127.0.0";
  allow-update { none; };
};

// serve as secondary for schroder.net domain
zone "schroder.net" IN {
  type slave;
  file "zone.net.schroder";
  // where the primary nameserver lives
  masters { 10.11.12.1; }
};

// serve as secondary for 10.11.12.0 net info
zone "12.11.10.in-addr.arpa" {
  type slave;
  file "revp.10.11.12";
  masters { 10.11.12.1; }
};

And so much more

BIND has features out of the reach of this short introduction. The man pages and documentation that come packaged with your distribution probably provide a good starting point.

As you might guess, the Internet is also a fine source of information. Two works stand out:

BIND 9 Administrator Reference Manual

[DNS HOWTO](DNS HOWTO)

O’Reilly & Associates has published the very fine DNS and BIND and the somewhat newer DNS & BIND Cookbook. Both of these titles are definitely worth a look-see.

CC by NC SA

@winny-
Copy link

winny- commented Apr 15, 2018

Thanks for the guide. It might be beneficial to include something about setting up forwarding to speed up cache misses. I found using the caching configuration by itself was prohibitively slow, but with forwarding I'm able to host an internal domain & cache external queries almost as fast as it'd be to get them directly from 8.8.8.8 or 1.1.1.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment