BIND

From HerzbubeWiki
Jump to: navigation, search

This page provides information on how to set up BIND for two scenarios:

  • To provide the DNS service within a small intranet such as my home LAN.
  • To provide a local DNS service on a hosted server that forwards most of the requests it gets to the hosting company's DNS servers, except for requests for a few specific DNSBL services. This is covered in this section.


Debian packages

The following Debian packages need to be installed:

bind9
dnsutils (not required but useful for debugging)


References

http://www.bind9.net/manual/ 
BIND9 Administrator Reference Manual
http://www.howtoforge.com/traditional_dns_howto 
Traditional DNS HOWTO. Essentially shows how to configure an authorative DNS server for one domain. Also provides valuable information to the novice about the basics of DNS, and explains some DNS jargon.
http://www.debian.org/doc/manuals/network-administrator/ch-bind.html 
Has much the same information as the above TODO, with an additional slant towards Debian.
http://www.howtoforge.com/two_in_one_dns_bind9_views 
"Two-in-one DNS server with BIND9" HOWTO. Explains how to setup a DNS server that serves different content to internal (LAN) and external (Internet) clients, depending on the IP address of the querying client.
http://en.wikipedia.org/wiki/Domain_Name_System 
The main Wikipedia page on DNS
http://en.wikipedia.org/wiki/DNS_zone 
Wikipedia page with a good definition of what a DNS zone is. Especially interesting is the section with the example of zone authority in DNS queries
http://en.wikipedia.org/wiki/Zone_file 
Wikipedia page with an example of a zone file. This is mainly interesting because it provides some discussion of TTL and the SOA record type.
http://en.wikipedia.org/wiki/List_of_DNS_record_types 
Good overview over the different DNS record types.
http://www.simpledns.com/help/ 
The help reference to the Windows DNS server "Simple DNS" contains a lot of good and understandable information
http://www.dnsstuff.com/reverse-dns-faq 
Responsibilities for setting up reverse DNS


Glossary

DNS 
Domain Name System
BIND 
Berkeley Internet Name Domain. The de-facto reference DNS implementation (includes both server and client).
Resolver 
The client side of DNS software
Root server 
One of the DNS servers that are at the root of the DNS tree hierarchy. A root server is represented by a period character ("."), e.g. in my own DNS configuration my IP address to name mapping ends with a period character.
TLD 
Top Level Domain. Traditional examples are com, net, org, etc. Another set of TLDs are the country-specific ones, for instance ch or de. A third set of TLDs are "new generation" such as info or travel. See the Wikipedia article
Infrastructure TLD 
There is exactly one infrastructure TLD, arpa
ccTLD 
Country-code TLD. See the Wikipedia article
gTLD 
Generic TLD. Any TLD that is not a ccTLD and not the arpa infrastructure TLD. Examples are com and info. Some gTLD such as com or org are unrestricted, i.e. they are available for registrations by any person or organization for any use. Other gTLD such as travel or jobs are restricted, i.e. registrations within them require proof of eligibility within the guidelines set for each.
Authorative server 
One of the DNS servers that are authorative for a specific domain (e.g. herzbube.ch). When a domain is registered, at least two authorative DNS servers must be specified to the registrar. The registrar will then delegate responsibility for the domain to the authorative DNS servers. Often the authorative servers are provided by the ISP that hosts the domain, however up until now I have used dyndns.org for that purpose. Note that both primary and secondary DNS servers of a zone are authorative.
Forward resolution 
Forward resolution is host name to IP address resolution.
Reverse resolution 
Reverse resolution is IP address to host name resolution. Reverse resolution must be configured by whomever controls the IP address - this usually is an Internet provider. The reverse DNS entry is a PTR record that points to a concrete host (i.e. not the "abstract" domain). Wikipedia says the PTR record should point to a "canonical name" (i.e. a CNAME). Stackoverflow has the advice, in relation to MTA configuration, to let the PTR record point to the name that is provided with HELO/EHLO, or more generally that the PTR must point to a name that resolves to the same IP address for which the reverse lookup was made.
named.conf 
The main configuration file for BIND. It references "zone" files.
DNS zone 
A portion of the global DNS namespace for which administrative responsibility has been delegated. Examples are the root zone, the local zone, or (at the lowest level) any domain such as my personal domain herzbube.ch. See the Wikipedia article. Another explanation attempt: A zone is a domain less any sub-domains delegated to other DNS servers.
Root zone 
The zone at the root of the DNS tree hierarchy. This zone is unnamed and represented by a period character ("."). The root zone contains all TLDs. Delegation is handed down to governments and various organizations that administer these TLDs.
Zone file 
A text file that describes a portion of the domain name system (DNS) called a DNS zone. See the Wikipedia article
Hints file 
One of the zone files. This file contains the names and addresses of the root servers on the Internet.
Local host file 
One of the zone files. Name servers are the masters of their own loopback domain (127.0.0.1). The point of creating local zone files for each aspect of your of localhost is to reduce traffic and allow the same software to work on your system as it does on the network.
Primary zone file 
One of the zone files. This file, also called the domain database, defines most of the information needed to resolve queries about the domain you administer. It maps names to IP addresses and provides information about the services offered by your Internet computer including your web and ftp server, email, telnet, name servers, etc. The zone file uses several record types, for instance SOA, MX or CNAME.
Reverse zone file 
One of the zone files. This file maps IP addresses to host names. It's a mirror image of the primary zone file.
Resource Record (RR) 
The basic data element in the DNS. Each record has a type (A, MX, etc.), an expiration time limit, a class, and some type-specific data. This Wikipedia article lists all the possible DNS record types.
SOA 
Record type "start of authority"; a SOA record must not refer to a CNAME. The SOA record identifies the primary DNS server of a zone.
NS 
Record type "name server"; an NS record must not refer to a CNAME, and it must not use an IP address. NS records identify the authorative DNS servers (primary and secondary) of a zone. It can be said that an NS record delegates a DNS zone to use the given authoritative name server.
Record type "address"; maps a host name to an IP address
PTR 
Record type "pointer"; maps an IP address to a host name
MX 
Record type "mail exchanger"; identifies the mail servers in the domain; an MX record must not refer to a CNAME, and it must not use an IP address.
CNAME 
Record type "canonical name"; defines an alias for a host name; a CNAME must always refer to an A record, never to another CNAME (to prevent circular references).
Host name 
Refers to a domain name that has one or more associated IP addresses. For instance, herzbube.ch is a host name, whereas ch is not.
Primary DNS server 
The server where the master copies of a domain's zone files are located
Secondary DNS server 
A server that has slave copies of a domain's zone files, obtained via a zone transfer
Zone transfer 
The process of transferring zone files from one system to another, usually from a primary to a secondary DNS server. A DNS server may specify which servers are authorized to do zone transfers.
Non-recursive query 
When a DNS server answers authoratively for one of its own domains, without consulting any other DNS server
Recursive query 
When a DNS server answers a query by querying other DNS servers
Stub resolver 
A simple-minded resolver that relies on a recursive DNS server to perform the work of finding information for them. In contrast, a normal resolver would itself perform each query, iterating through several DNS servers (starting with the root servers) to find the needed information
dig 
Domain Information Groper. Command line utility for querying DNS servers.
FQDN 
Fully qualified domain name. Sometimes referred to as an "absolute domain name". A domain name that specifies its exact location in the tree hierarchy of the DNS. It specifies all domain levels, including the top-level domain, relative to the root domain. A fully qualified domain name is distinguished by its unambiguity; it can only be interpreted one way. In the DNS, and most notably, in DNS zone files, a FQDN is specified with a trailing period character (".").
TTL 
Time to live. A value associated with DNS records that tells clients how long they may cache the record before the authorative DNS server has to be queried again.
Negative Cache TTL 
This special TTL, which is defined in the SOA record of a zone, is used for negative responses to queries, i.e. if a query is made for something that does not have a DNS record. The negative response may then be cached for the duration specified by the Negative Cache TTL.
DDNS 
Dynamic DNS. If a DNS server allows external clients (e.g. a DHCP server) to dynamically modify its zones.


Questions & Answers

How is DNS organized? 
DNS is a distributed database with multiple levels. Level 1 consists of the root servers, level 2 covers the TLDs, and level 3 is usually everything else (although there may be more levels if there are more DNS zones at level 3). A resolver that needs to find the IP address of google.com first queries one of the root servers, which refers the resolver to one of the servers for the TLD com, which finally refers the resolver to the authorative server 216.239.32.10 (ns1.google.com). The last server in the chain can then tell the resolver the actual IP address of google.com.
How does caching work in the DNS environment? 
An authorative DNS server (may be primary or secondary) of a zone assigns a TTL to each of its DNS records. The TTL specifies the maximum amount of time other DNS servers and applications should cache the record. They are, of course, free to query the primary DNS server again before TTL has been reached. Setting a DNS record's TTL value to zero, means that applications and DNS servers should not cache the record. When a DNS record is stored in the cache of a DNS server, the record's TTL is continuously reduced as time goes by, and when the TTL finally reaches zero the record is removed from the cache. When a DNS server passes DNS records from the cache along to applications and other DNS servers, it supplies the current TTL value - not the original. This way the original TTL is guaranteed no matter how many DNS servers the record passes through. Most DNS servers will not cache a DNS record for more than one week, regardless of the TTL. Special note on Negative Cache TTL: The last field in a zone's SOA record is the commonly called "Negative Cache TTL". If a query is made for something that does not have a DNS record, the client will receive a no domain or NXDOMAIN response with a Negative Cache TTL. Clients may thus cache negative responses in the same way as they would cache the result of a successful query.
How does recursive querying work? 
(Answer copied verbatim from this page) Client applications (such as Internet browsers) typically requests that the DNS server performs recursion for them by setting an RD (Recursion Desired) flag in the request packet. This is a recursive request. Client applications do this both because they do not posses the ability to resolve domain names themselves, and also to take advantage of centralized caching on the DNS server. However, when a DNS server sends requests to other DNS servers as part of the recursion process, these requests are typically non-recursive (the RD flag is not set). The DNS server indicates back to the client if it is willing to perform recursion by setting or not setting an RA (Recursion Available) flag in the DNS response packet. When a DNS server receives a recursive request from a client that it is willing to perform recursion for, it will go through the process of resolving the requested domain name by first asking the root servers, which respond with a referral to the top level DNS servers, then asking one of those servers, which respond with a referral to the next level DNS servers, etc. When a DNS server receives a non-recursive request or a request from a client that it is not willing to perform recursion for, it typically responds immediately with whatever local data it has available at the time without doing any additional processing. [...] A recursive DNS request requires much more processing by the server compared to a non-recursive request. So it is important to only offer recursion to trusted clients.
How can I create a zone for a sub-domain? 
A DNS server that is authorative for all records under the "xyz.com" domain can delegate responsibility for the sub-domain "abc.xyz.com" by defining an NS record for that sub-domain. The DNS server referenced by the NS record thus becomes authorative for the sub-domain, which effectively results in a new zone.


Goals of my local DNS setup

Summary

The goals, in descending order of importance, are:

  1. Hosts in the local network should be known under <hostname>.herzbube.ch, or simply <hostname>. In both cases, the name should resolve to an address in one of the local network (wired LAN = 192.168.1.0, WiFi = 192.168.2.0).
  2. IP addresses allocated by the DHCP server should be automatically added to the DNS database
  3. Hosts and their IP addresses should be administered in the LDAP directory
  4. Be responsible for my own DNS hosting on the Internet (i.e. get rid of DynDNS.org).


Solution for goal 1

Goal #1, as it is stated, requires that the DNS zone for herzbube.ch contains both public IP addresses (212.101.18.224) and private IP addresses (192.168.1.x or 192.168.2.x). In the current situation, with the DNS zone being hosted by DynDNS.org, I believe this is not a good idea - private IP addresses should not appear in a public, Internet context. If I were able to host the DNS zone myself (and optionally make DynDNS.org my secondary DNS server), I might be able to do a trick with the "views" feature of BIND9 (see the "Two-in-one DNS server with BIND9" HOWTO). Unfortunately, this is not possible - the domain registrar for the TLD ch does not accept my puny DNS server (see "Goal #4" implementation section below).


The solution I have come up with is the definition of three new DNS zones:

  • The local networks are placed under three new sub-domains: dmz.herzbube.ch, lan.herzbube.ch and wifi.herzbube.ch
    • Originally I had only a single sub-domain localnet.herzbube.ch, but after I added a WLAN to my intranet this solution became untenable
    • The problem was that some hosts were capable of connecting both via wired LAN and WiFi, which means that those hosts would appear under two different IP addresses
    • Forward DNS resolution would have been possible by defining two A records with different hostnames, but reverse DNS resolution would always have resulted in one or the other IP address
    • The only proper solution to this problem is to split the single sub-domain into three distinct sub-domains
  • The following DNS records are added to the zone for herzbube.ch (which is currently hosted by DynDNS.org):
    • One NS record per sub-domain. This effectively creates new DNS zones for the sub-domains, delegating control over the zones to the zones' primary DNS servers:
dmz.herzbube.ch. NS ns1.dmz.herzbube.ch.
lan.herzbube.ch. NS ns1.lan.herzbube.ch.
wifi.herzbube.ch. NS ns1.wifi.herzbube.ch.
    • One A record per sub-domain that defines where the new primary DNS server for that sub-domain's zone is located. These A records are so-called glue records.
ns1.dmz.herzbube.ch. A 192.168.0.2
ns1.lan.herzbube.ch. A 192.168.1.11
ns1.wifi.herzbube.ch. A 192.168.2.6
  • Because control over the new zones has been delegated to my own DNS servers (at 192.168.0.2, 192.168.1.11 and 192.168.2.6), I have now complete freedom in how to setup the new zones
  • Hostnames (and anything else) will be located under the new sub-domains (e.g. alcarondas.dmz.herzbube.ch, tharbad.lan.herzbube.ch, nargothrond.wifi.herzbube.ch)


This solution has two drawbacks:

  1. It still leaks one private IP address per private zone (192.168.0.2, 192.168.1.11 and 192.168.2.6) into the public DNS space. This is certainly not ideal, however leaking only a single IP address per private zone is definitely superior to the primitive solution of simply defining all the private addresses directly within the herzbube.ch zone (i.e. defining A records for the various hostnames). The "private zone" solution is also better in that it somewhat hides the structure of my private network from public eyes.
  2. Sub-domains don't look pretty, and more typing is necessary for a FQDN. I guess at the moment I have to accept that this is the price to pay for having a relatively cheap Internet connection. If I were willing to pay more, I am sure I could get a better solution directly from my ISP, but apart from being more expensive it would also become even harder to switch to another ISP (if I ever wanted to).


Solution for goal 2

An overview over the steps required:

  • The DNS server needs to be configured to accept updates for those DNS zones that need dynamic updates
  • The DHCP server needs to be configured to send updates to the DNS server
  • A shared secret needs to be established to secure the communication channel between the two servers. This is less important in my circumstances where both servers are located on the same machine, but it should still be implemented, both as a precaution and for learning purposes


An important note on the side: Once dynamic updates start to occur, the DNS server will periodically, or when it is shut down, flush its cached information to disk. The zone files are overwritten by this, so it doesn't make sense to put comments into them!


Solution for goal 3

Not yet solved.


Solution for goal 4

This goal seems to be impossible to achieve. The reason for this is that the domain name registrar for the TLD ch (Switch) does not accept arbitrary DNS servers for delegation. The DNS server must be specially registered with the registrar, and at the moment it appears that only ISPs can do such a registration. Since I cannot deploy my own primary DNS server for herzbube.ch, I am stuck with the public DNS server of DynDNS.org.


TODO: Investigate the exact requirements that Switch has for a primary DNS server. See the issue tracker for a status of this investigation.


Static implementation

The zone files

Overview

This section first discusses some general aspects of zone files and their content. It then lists the actual, current content of my zone files. Only the static records are listed, dynamically added content is treated in a separate chapter "Dynamic implementation" further down.


Default TTL

A zone file should start with the definition of a default TTL:

$TTL 1d

This TTL will be applied to all DNS records that do not specify their own explicit TTL.


SOA record

SOA means "start of authority". This record has authorative information about the DNS zone in general. An example with (probably/hopefully) useful values:

@ IN SOA ns1.herzbube.ch. zone-admin.herzbube.ch. (
  2009091601  ; Serial
          1d  ; Refresh  
          1h  ; Retry     
          7d  ; Expire  
          1h) ; Negative Cache TTL

Discussion:

A shorthand reference to the "current origin", which means the zone used in /etc/bind/named.conf.local to refer to this zone file. Thus, if the zone file was referenced inside the clause zone "herzbube.ch" { ... }, the current origin would be herzbube.ch.
IN 
Specifies that the class of this record is "Internet". The other classes exist for non Internet protocols and functions, so they are not relevant for us and we will always use "IN".
SOA 
Specifies that the type of this record is "Start of Authority".
ns1.herzbube.ch. 
The FQDN of the primary DNS server of the zone, i.e. the DNS server who has authority for the zone. The zone should contain an NS record as well as an A record for this DNS server. Note the trailing period character (".").
zone-admin.herzbube.ch. 
The email address of the domain administrator. In this example the address is zone-admin@herzbube.ch. Note the trailing period character (".").
2009091601 
Serial number. This is just a common name, the field basically contains a numeric value that designates the version of the zone file. A larger value means a newer version. When the zone is edited, the serial number must be updated so that secondary DNS servers will notice that something has changed and can update their records (= zone transfer). The convention is that the serial number format is YYYYMMDD with an incremented double digit number tagged to the end. Thus, there can be up to 100 changes during a single day.
1d 
This field tells a secondary DNS server how often it should check its primary DNS server whether an update (= zone transfer) is necessary. The unit is seconds.
1h 
This field tells a secondary DNS server how much time should elapse between retries to connect to its primary DNS server in the event of a connection failure. The unit is seconds.
7d 
Total amount of time a secondary DNS server should retry to contact its primary DNS server before expiring the data it contains. Or, in other words, the length of time that the slave server should continue to respond to queries even if it cannot update the zone file. Future references will be directed towards the root servers. Note that an expiration period exists under the theory that out of date data is worse than no data at all. The unit is seconds.
1h 
Negative Cache TTL for this zone. If a query is made for something that has no DNS record, the negative response to that query may be cached by clients for the duration specified by the Negative Cache TTL. The unit is seconds.


Note: Even though the internal unit for all time values in a SOA record is seconds, BIND9 allows to specify the values in more convenient notations such as "1h" (1 hour, 3600 seconds), "1d" (1 day, 86'400 seconds) or "1w" (1 week, 604'800 seconds).


Zone file location

To distinguish my zone files from the default zone files provided by the Debian package, I place them in a special directory:

/etc/bind/zones

Underneath that directory each zone has its own sub-directory. For instance, the files for zone wifi.herzbube.ch go into

/etc/bind/zones/wifi.herzbube.ch


Forward zone for dmz.herzbube.ch

The forward zone file for dmz.herzbube.ch is located in /etc/bind/zones/dmz.herzbube.ch/db.dmz.herzbube.ch. Its content:

; Default TTL
$TTL 1d

; Start of authority (must not refer to a CNAME)
@ IN SOA ns1.dmz.herzbube.ch. zone-admin.herzbube.ch. (
  2009111501  ; Serial
          1d  ; Refresh
          1h  ; Retry
          7d  ; Expire
          1h) ; Negative Cache TTL

; Name servers (must not refer to a CNAME)
@ IN NS ns1

; The nameserver A record
ns1 IN A 192.168.0.2

; A records
alcarondas IN A 192.168.0.1
pelargir   IN A 192.168.0.2

Notes:

  • Currently none


Reverse zone for dmz.herzbube.ch

The reverse zone file for dmz.herzbube.ch is located in /etc/bind/zones/dmz.herzbube.ch/db.0.168.192.in-addr.arpa. Its content:

; Default TTL
$TTL 1d

; Start of authority (must not refer to a CNAME)
@ IN SOA ns1.dmz.herzbube.ch. zone-admin.herzbube.ch. (
  2009111501  ; Serial
          1d  ; Refresh
          1h  ; Retry
          7d  ; Expire
          1h) ; Negative Cache TTL

; Name servers (must not refer to a CNAME)
@ NS ns1.dmz.herzbube.ch.

; Addresses
1 PTR alcarondas.dmz.herzbube.ch.
2 PTR pelargir.dmz.herzbube.ch.

Notes:

  • The SOA record is exactly the same as the one in the forward zone file
  • It is necessary to always specify the FQDN because the origin in this zone will be set to "0.168.192.in-addr.arpa". I didn't attempt to set $ORIGIN, as was suggested in one of the HOWTOs I have read, because I don't want to invite trouble.
  • It is vital that the zone file contain an NS record, otherwise BIND will refuse to load the file (named-checkconf -z prints a "bad zone" message, but if the daemon is restarted without this check, it will silently ignore the error!)


Note that does not refer to the zone file above: If the addresses in a reverse zone require more than a single octet, remember to write the addresses in reverse notation. For instance, if the zone origin is "168.192.in-addr.arpa" and you want to refer to the address "192.168.0.1", the address must be written as "1.0".


Forward zone for lan.herzbube.ch

The forward zone file for lan.herzbube.ch is located in /etc/bind/zones/lan.herzbube.ch/db.lan.herzbube.ch. Its content:

; Default TTL
$TTL 1d

; Start of authority (must not refer to a CNAME)
@ IN SOA ns1.lan.herzbube.ch. zone-admin.herzbube.ch. (
  2009111501  ; Serial
          1d  ; Refresh
          1h  ; Retry
          7d  ; Expire
          1h) ; Negative Cache TTL

; Name servers (must not refer to a CNAME)
@ IN NS ns1

; The nameserver for the internal network (reverse lookup of the IP
; address currently results in pelargir.lan.herzbube.ch instead
; of ns1.lan.herzbube.ch)
ns1 IN A 192.168.1.11

; A records
pelargir      IN A 192.168.1.11
laserjet1300n IN A 192.168.1.126

; Aliases
gw      CNAME pelargir
test    CNAME pelargir
davical CNAME pelargir

Notes:

  • See the section about the forward zone for dmz.herzbube.ch


Reverse zone for lan.herzbube.ch

The reverse zone file for lan.herzbube.ch is located in /etc/bind/zones/lan.herzbube.ch/db.1.168.192.in-addr.arpa. Its content:

; Default TTL
$TTL 1d

; Start of authority (must not refer to a CNAME)
@ IN SOA ns1.lan.herzbube.ch. zone-admin.herzbube.ch. (
  2009111501  ; Serial
          1d  ; Refresh
          1h  ; Retry
          7d  ; Expire
          1h) ; Negative Cache TTL

; Name servers (must not refer to a CNAME)
@ NS ns1.lan.herzbube.ch.

; Addresses
11  PTR pelargir.lan.herzbube.ch.
126 PTR laserjet1300n.lan.herzbube.ch.

Notes:

  • See the section about the reverse zone for dmz.herzbube.ch


Forward zone for wifi.herzbube.ch

The forward zone file for wifi.herzbube.ch is located in /etc/bind/zones/wifi.herzbube.ch/db.wifi.herzbube.ch. Its content:

; Default TTL
$TTL 1d

; Start of authority (must not refer to a CNAME)
@ IN SOA ns1.wifi.herzbube.ch. zone-admin.herzbube.ch. (
  2009111501  ; Serial
          1d  ; Refresh
          1h  ; Retry
          7d  ; Expire
          1h) ; Negative Cache TTL

; Name servers (must not refer to a CNAME)
@ IN NS ns1

; The nameserver A record
ns1 IN A 192.168.2.6

; A records
pelargir  IN A 192.168.2.6
landroval IN A 192.168.2.2

; Aliases
gw CNAME pelargir

Notes:

  • See the section about the forward zone for dmz.herzbube.ch


Reverse zone for wifi.herzbube.ch

The reverse zone file for wifi.herzbube.ch is located in /etc/bind/zones/wifi.herzbube.ch/db.2.168.192.in-addr.arpa. Its content:

; Default TTL
$TTL 1d

; Start of authority (must not refer to a CNAME)
@ IN SOA ns1.wifi.herzbube.ch. zone-admin.herzbube.ch. (
  2009111501  ; Serial
          1d  ; Refresh
          1h  ; Retry
          7d  ; Expire
          1h) ; Negative Cache TTL

; Name servers (must not refer to a CNAME)
@ NS ns1.wifi.herzbube.ch.

; Addresses
6 PTR pelargir.wifi.herzbube.ch.
2 PTR landroval.wifi.herzbube.ch.

Notes:

  • See the section about the reverse zone for dmz.herzbube.ch


named.conf

Overview

Configuration of the BIND DNS server is located in

/etc/bind

If the BIND configuration or one of the zones is changed, the BIND daemon needs to be restarted to make these changes effective. Before you do this, don't forget to check whether the changes make sense. See "checking the configuration" further down.

/etc/init.d/bind9 restart


Debian specifics

/usr/share/doc/bind9/README.Debian.gz provides basic information about the structure of BIND configuration files in Debian. Essentially the idea is this:

  • All conf files for the primary server are located in /etc/bind, possibly in subdirectories if the configuration is very complex
  • Primary server conf files are referenced in named.conf using full path names
  • Secondary server configuration in named.conf should refer to its zone files with simple filenames, so that the data files will be stored relative to BIND's working directory (defaults to /var/cache/bind)
  • Zones subject to automatic updates via DHCP should be stored in /var/lib/bind, and specified with full pathnames


/etc/bind/named.conf uses an include syntax to refer to various sub-configuration files:

/etc/bind/named.conf.options 
The "options" part of the BIND configuration
/etc/bind/named.conf.default-zones 
References various concrete zone files that define default zones (e.g. the root zone)
/etc/bind/named.conf.local 
Local configuration, empty by default.


Various pre-configured default zone files referenced in /etc/bind/named.conf.default-zones are:

/etc/bind/db.root 
Root zone, i.e. lists root servers (hints file)
/etc/bind/db.local 
Local zone file, i.e. configuration for the local loopback interface
/etc/bind/db.127 
Reverse zone file for the local zone (db.local)
/etc/bind/db.0 
Reverse zone file for the broadcast zone of the local loopback interface
/etc/bind/db.255 
ditto


Conventions:

  • Zone files are prefixed with db.


Checking the configuration

Before activating a configuration, it should be syntax-checked using

named-checkconf -z

Notes:

  • The utility by default checks /etc/bind/named.conf
  • The -z option is required so that the utility actually tries to load the zone files. If this is not specified, zone files that do not exist (e.g. because a wrong file name was specified accidentally) are not detected


To check a zone (the lan.herzbube.ch zone in this example), use this utility:

named-checkzone lan.herzbube.ch /etc/bind/zones/lan.herzbube.ch/db.lan.herzbube.ch


The actual configuration

To activate a zone (lan.herzbube.ch in this example), the following lines need to be added to /etc/bind/named.conf.local:

zone "lan.herzbube.ch" {
  type master;
  file "/etc/bind/zones/lan.herzbube.ch/db.lan.herzbube.ch";
};
zone "1.168.192.in-addr.arpa" {
  type master;
  file "/etc/bind/zones/lan.herzbube.ch/db.1.168.192.in-addr.arpa";
};

Notes:

  • I don't restrict zone transfers because there is no one that could attempt it (the ADSL router blocks the DNS port). For the record: Restricting zone transfers would require the option allow-transfer to specify the IP addresses that are allowed to do a zone transfer.
  • I don't run my DNS server chroot'ed because it's too much trouble, and it's not really a security risk (again, the ADSL router blocks the DNS port)


In addition, to make sure that the DNS server is well behaved, I activate the default configuration for RFC 1918 zones, which is conveniently provided by the Debian package:

  • To activate the RFC 1918 zones, the comment characters ("//") need to be removed from the following line in /etc/bind/named.conf.local:
include "/etc/bind/zones.rfc1918";
  • However, in order to prevent a conflict with local zones that actually use addresses in the 192.168.0.0 range, the following line needs to be commented out in /etc/bind/zones.rfc1918:
// PN 17.09.2009
// Disabled because I use addresses from this zone in my local sub-domains
//
// zone "168.192.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };


Additional configuration

Situation before deploying DNS

The ADSL router acts as the DHCP server for pelargir:

  • The router hands out the domain moser-naef.ch (configured in menu 1)
  • The router hands out the primary and secondary DNS servers of the ISP (configured in menu 3.2)
  • pelargir sets its /etc/resolv.conf to this information

pelargir acts as the DHCP server for hosts in the local network:

  • pelargir hands out the domain herzbube.ch (configured in /etc/dhcp3/dhcpd.conf)
  • pelargir hands out the primary and secondary DNS servers of the ISP (configured in /etc/dhcp3/dhcpd.conf)
  • Hosts in the local network set their /etc/resolv.conf to this information

Result:

  • Everybody queries the DNS servers of the ISP


Modifications

Changes to the ADSL router configuration:

  • The router now hands out domain dmz.herzbube.ch
  • The router now hands out 192.168.0.2 as the primary DNS server, and the ISP's primary DNS server as the secondary DNS server
  • To activate the change on pelargir, renew the DHCP lease (e.g. ifdown followed by ifup)

Changes to the DHCP server on pelargir (in /etc/dhcp3/dhcpd.conf):

  • Change the domain name handed out so that it depends on the subnet where the client requests its IP address (option domain-name)
  • Change the DNS servers handed out so that the front most entry refers to the DNS server pelargir. The IP address depends on the subnet where the client requests its IP address (option domain-name-servers)
  • To activate the change on clients, renew their DHCP leases and (if necessary) clear their DNS caches.

Result:

  • Everybody (including pelargir) first queries the DNS server on pelargir before they query the ISP's DNS server
  • Hostnames are recognized with or without FQDN (e.g. tharbad is recognized as well as tharbad.lan.herzbube.ch)

The content of /etc/resolv.conf on a client in the lan.herzbube.ch sub-domain should look like this:

domain lan.herzbube.ch
search lan.herzbube.ch
nameserver 192.168.1.11
nameserver 212.101.0.10
nameserver 212.101.4.253


Dynamic implementation

Authentication secret file

A client that wants to dynamically update DNS records must authenticate itself to the DNS server. The authentication mechanism requires a shared secred between DDNS client and DNS server. The file with the shared authentication secret looks like this:

key dhcp-updater {
  algorithm hmac-md5;
  secret "pRP5FapFoJ95JEL06sv4PQ==";
};

From the "BIND 9 Administrator Reference Manual" (http://www.bind9.net/manuals):

The shared secret is simply a random sequence of bits, encoded in base-64. Most ASCII strings are valid base-64 strings (assuming the length is a multiple of 4 and only valid characters are used), so the shared secret can be manually generated.


The secret is generated like this and can then be added to the above file via copy&paste. Note that currently only the HMAC-MD5 algorithm is supported.

# Generate the secret. This writes two files:
# - one with the extension .key: Contains the public key
# - one with the extension .private: Contains the private key
# Public/private keys make sense only for asymmetric algorithms, but dnssec-keygen
# creates two files even if a symmetric algorithm such as HMAC-MD5 is used. In this
# case, both files simply contain the same secret.
dnssec-keygen -a HMAC-MD5 -b 128 -n USER dhcp-updater
# Get the secret. It is the last part of a line that looks something like this:
#   dhcp-updater. IN KEY 0 3 157 xhjomY+2e33haceeT5yKAw==
cat Kdhcp-updater*.key
# Cleanup, remove the generated files
rm Kdhcp-updater*.key Kdhcp-updater*.private


Because the file contains a secret key, it must be protected accordingly against unauthorized reads:

cd /etc/bind
touch dhcp-updater.key
chown root:bind dhcp-updater.key
chmod 640 dhcp-updater.key


Define which zones are updateable

Example for the zone that represents the lan.herzbube.ch sub-domain:

zone "lan.herzbube.ch" {
  [...]
  allow-update { key "dhcp-updater"; };
};
zone "1.168.192.in-addr.arpa" {
  [...]
  allow-update { key "dhcp-updater"; };
};

Discussion:

  • allow-update grants given clients the permission to update any record of any name in the zone
  • update-policy, not used here, allows more fine-grained control over what updates are allowed
  • Only clients presenting the given key are allowed to update the zone


Permissions for zone files and container directories

When the BIND9 server receives an update, it writes the request to a journal file in the directory where the zone file is located. This requires that the directory is setup with appropriate permissions. The following example is for a zone that represents the lan.herzbube.ch sub-domain:

cd /etc/bind/zones
chmod g+w lan.herzbube.ch
ls -ld lan.herzbube.ch

drwxrwsr-x 2 root bind 4096 2009-11-15 01:39 lan.herzbube.ch

Periodically, or when it is shut down, the BIND9 server flushes its cached information to disk. The zone files are overwritten, so it doesn't make sense to put comments into them!


Note: This chapter is relevant only because my setup violates the Debian policy of writing dynamically updateable DNS zones to /var/lib/bind.


Logging

It makes sense to write information about dynamic updates to specific log files. The following directives, added to /etc/bind/named.conf.local, achieve this:

logging {
  channel update_debug {
    file "/var/log/named/update-debug.log";
    severity  debug 3;
    print-category yes;
    print-severity yes;
    print-time     yes;
  };
  channel security_info {
    file "/var/log/named/named-auth.info";
    severity  info;
    print-category yes;
    print-severity yes;
    print-time     yes;
  };
  category update { update_debug; };
  category security { security_info; };
  # If a category is not defined, the logging options from the "default" category
  # are used (which basically logs to syslog). If a message could not be matched
  # to any category, it is logged with the options of the "unmatched" category
  # (which sends everything to /dev/null).
};


The directory needs to be created before the BIND server is restarted:

cd /var/log
mkdir named
chown bind named


Finally, the log files need to be added to /etc/logrotate.d/pelargir:

/var/log/named/*.log {
  size 1000k
  missingok
  rotate 10
  compress
  nocreate
}


Resolver

For a discussion on how the resolver works, see network configuration page on this wiki.

In addition, the NSS page (Name Service Switch) may also be interesting/important.


Remote administration

Defining the control channel

The control channel definition determines which clients are allowed to remotely control the DNS server.

controls {
  inet 127.0.0.1 allow { localhost; }
  keys { "rndc-key"; };
};

Discussion:

  • 127.0.0.1 defines the interface where to listen on
  • The default port to listen on is 953
  • Since the DHCP server lives on the same machine, the only source for updates can be the localhost; this is defined by the allow clause
  • The keys statement defines which secret key(s) must be presented by the connecting client. If this (or the entire controls section) is missing, BIND tries to load the key from /etc/bind/rndc.key
  • To disable the command channel, use an empty controls statement: controls { };


rndc

The command line utility to remotely administrate the DNS server is

rndc


More information: TODO...


Local DNS service forwarding all requests except DNSBL service requests

The goal for this setup is to have a local DNS server that forwards all requests to the DNS servers of green.ch (the hosting company), except for requests to a few DNSBL services. These services need to be contacted directly because they block requests coming via the green.ch DNS servers, because too many other machines send requests via green.ch.


Add this to named.conf.options to set up a forwarding DNS server:

  // ------------------------------------------------------------
  // Local configuration
  // ------------------------------------------------------------

  // Set up the hosts to which the server forwards queries.
  // These are the green.ch nameservers that were originally listed in resolv.conf.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-forward
  forwarders {
    146.228.101.20;
    146.228.101.28;
  };

  // only = The server only queries the forwarders and does not attempt to perform lookups on its own.
  // Important: A list with exceptions is defined in named.conf.local.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-forward
  forward only;

  // Specifies which hosts (an IP address list) are allowed to send queries to this resolver.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-allow-query
  // TODO: Do we need to add pelargir as well?
  allow-query     { localhost; };

  // Allow recursion and caching. This is already the default.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-recursion
  recursion yes;

  // Hosts that are allowed to perform recursive queries.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-allow-recursion
  allow-recursion { localhost; };

  // Hosts that are allowed to access the server's cache.
  // This usually needs not be set, it is defined implicitly by the values of recursion and allow-recursion.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-allow-query-cache
  allow-query-cache { localhost; };

  // Hosts that are allowed to transfer zones from this server.
  // We don't have zone files, so no zone transfer is needed.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-allow-transfer
  allow-transfer { none; };

  // Hosts that are allowed to send NOTIFY messages.
  // I took over this statement from an example without understanding the documentation.
  // https://bind9.readthedocs.io/en/latest/reference.html#namedconf-statement-allow-notify
  allow-notify { none; };


Add this to named.conf.local to define the DNSBL service exceptions:

// ------------------------------------------------------------
// Local configuration
// ------------------------------------------------------------

// Disable forwarding for DNSBL queries (used for SpamAssassin)
// https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=119541646
zone "multi.uribl.com" { type forward; forward first; forwarders {}; };
zone "dnsbl.sorbs.net" { type forward; forward first; forwarders {}; };
zone "combined.njabl.org" { type forward; forward first; forwarders {}; };
zone "activationcode.r.mail-abuse.com" { type forward; forward first; forwarders {}; };
zone "nonconfirm.mail-abuse.com" { type forward; forward first; forwarders {}; };
zone "iadb.isipp.com" { type forward; forward first; forwarders {}; };
zone "bl.spamcop.net" { type forward; forward first; forwarders {}; };
zone "fulldom.rfc-ignorant.org" { type forward; forward first; forwarders {}; };
zone "list.dnswl.org" { type forward; forward first; forwarders {}; };
zone "blackholes.mail-abuse.org" { type forward; forward first; forwarders {}; };
zone "bl.score.senderscore.com" { type forward; forward first; forwarders {}; };
zone "zen.spamhaus.org" { type forward; forward first; forwarders {}; };

include "/etc/bind/zones.rfc1918";


In theory this configuration should be able to satisfy all DNS queries on the hosted machine. This would mean that

  • In /etc/default/bind this can be set: RESOLVCONF=yes
  • In /etc/resolv.conf the green.ch nameservers can be replaced with this: nameserver 127.0.0.1


In practice it can't be done like this, because the hosted machine is embedded into the hosting company's network via DHCP. This means that /etc/resolv.conf must be left untouched because it would eventually be overwritten by the DHCP client. As a consequence, any services like SpamAssassin that want to make use of the local DNS service must be specifically configured. See the SpamAssassin wiki page for details.


dig

The Domain Information Groper (dig) command line utility is useful for troubleshooting and "debugging" a DNS server setup. This section contains a few brief examples on usage. Note that unless specified otherwise dig will use UDP (not TCP) for queries.


To get all the information about the domain name herzbube.ch from one of the DNS servers listed in /etc/resolv.conf:

dig herzbube.ch any

Note: At the end of the output, dig displays the IP address of the DNS server that was actually queried.


Same, but get information from a specific DNS server:

dig @ns1.mydyndns.org herzbube.ch any

Note: In this example, dig needs to lookup ns1.mydyndns.org first. It will do so behind the scene, by querying one of the DNS servers listed in /etc/resolv.conf


Get "MX" record information:

dig herzbube.ch mx

Get "A" record information:

dig herzbube.ch
dig herzbube.ch a

Get information about two domain names:

dig pelargir.herzbube.ch any www.moser-naef.ch any

Do not display TTL information in the query result:

dig herzbube.ch any +nottlid

Perform iterative queries, starting at the root DNS servers, and display the result of each query. This is useful to see the delegation path from the root DNS servers to the name being looked up. Note that in this use case the queries issued by dig are not recursive.

dig herzbube.ch any +trace

Reverse lookup an IP address:

dig -x 212.101.18.224

Perform a non-recursive query:

dig herzbube.ch any +norecurse

To check whom forward or reverse DNS is delegated to:

dig herzbube.ch ns                    # Forward DNS delegation for domain herzbube.ch
dig 224.18.101.212.in-addr.arpa ns    # Reverse DNS delegation for static public IP 212.101.18.224
dig 1.168.192.in-addr.arpa ns         # Reverse DNS delegation for private network 192.168.1.0


Troubleshooting

dig returns with SERVFAIL

If dig returns with SERVFAIL error, this means that the DNS server it queried was unable to answer the request due to some internal error. In my case I had the problem when I tried to perform a reverse lookup.

The problem was two-fold:

  • I tried to lookup the address 192.168.0.1, but my DNS server was mis-configured in a way so that it didn't know about either of the zones 168.192.in-addr.arpa or 0.168.192.in-addr.arpa
  • My DNS server was also not configured to forward the request to some other DNS server
  • The end result was that my DNS server could not answer the request, so the response was SERVFAIL

Interestingly enough, when I tried the utility host instead of dig I always received some sort of valid response. The reason for this is that host goes to the next DNS server if it receives a SERVFAIL, so after my own DNS server was unable to answer the request, host happily went on to query my ISP's DNS server (which of course was setup correctly). To prevent this, one can use the -s option:

host -s 192.168.0.1