DNS & DHCP Setup

Introduction

This document describes how DNS and DHCP work on the Arda Network. I’ve managed to use many of the features of DNS and DHCP in my setup so this document should provide a fairly comprehensive guide as to how to get things working. Features you’ll find described here include:

  • Dynamic updates between DHCP and DNS
  • Control of DNS using rndc
  • Secure DNS operations using TSIG
  • Access control lists
  • Views
  • CIDR networks
  • Classless in-addr.arpa delegation, sort of

This document does not presume to be a tutorial on how DNS or DHCP work. It does not even presume to teach how to use the particular software described. This document provides an example of a working DNS/DHCP setup. If you are new to DNS or DHCP, you will almost certainly need to reference additional resources to understand what will be presented here. Don’t panic, since DNS and DHCP are fundamental to the operation of IP networks, such resources are easy to come by.

Take note! This is an updated version of my DNS & DHCP Setup Doc. You can find the original version here.

Preliminaries

I chose to use the Internet Systems Consortium’s (ISC) implementations of DNS and DHCP for the Arda Network. Why you ask? Because they are both in wide use so I thought I would be able to find a lot of resources to assist me in setting up the software. It turned out that I was correct in this assumption. In particular, I relied on an excellent book from O’Reilly Press called ‘DNS and BIND’. This book provides much useful information; I highly recommend it.

The particular versions of software I use are:

  • BIND 9.9.6
  • ISC DHCP 4.2.6

Knowing the software versions is especially important. For BIND, configuration syntax has changed dramatically between versions so what you see described here can be reliably applied only to BIND 9.

You will find an overview, including a very nice diagram, of the Arda Network here.

Why have I gone to the trouble to set up DNS and DHCP on my network you ask? Well, the simplest answer is because I wanted to. The more involved answer is in two parts. I find updating host files tedious and having DNS allows me to update two zone files on the master DNS server whenever something changes on my network. I also sometimes bring home a laptop from work and I wanted to be able to plug it into my home network to do things like transfer files to and from it. Since it uses DHCP at work, I thought I’d set things up that way at home too. I could have simply used the DNS and DHCP capabilities of my home router but that wouldn’t have given me the opportunity to learn much about how these protocols work. It also wouldn’t have given me the flexibility I needed to get DNS and DHCP to behave quite the way I wanted.

One thing to keep in mind when reading this document is that DNS on the Arda Network is set up to serve machines on my local network only. I have not set up DNS to serve zone data to the outside world and, in fact, I have options in my DNS configuration files specifically to prevent the outside world from reading my zone data. If you want to serve zone data from your domain to the internet at large, you’ll have to do some things differently than what I describe here. If all you want to do is create a DNS cache (a server that caches the results of DNS queries but does not serve zone data), have a look at the DNS cache I’ve set up on Phoebe using djbdns.

DNS

DNS on the Arda Network is handled mostly by Mimas. Right now, I only have a single BIND server handling zone data for my network. For a small home network like mine, a single server has more than enough horsepower for my needs but it does lack redundancy which means I lose DNS service during software or hardware upgrades. My plan is to set up a second DNS server running BIND to eliminate this problem. It will also allow me to set up zone transfers secured by TSIG. In the meantime BIND on Mimas is dynamically updated by DHCP and these updates are TSIG secured. I also use a TSIG key to secure communication between BIND and the rndc program.

TSIG keys were generated using this command.

dnssec-keygen -a HMAC-MD5 -b 256 -n HOST <key name>

Keys were copied and pasted into configuration files as appropriate. In the configuration files listed below, when two keys in different files are referred to by the same name, it is because the same key is used in both files.

Two domains are described in my DNS setup, arda.homeunix.net and arda.homelinux.net. The first domain is your typical DNS domain. All the machines on my home network are part of this domain. The second domain is a so-called virtual domain. It is used by Phoebe, my mail server, so that I can route email addressed to this domain. No actual machines belong to the arda.homelinux.net domain. Although I include only one virtual domain in this document, I am not limited to one. I could have as many virtual domains set up as I want simply by adding the appropriate zone files and updating the named.conf files of my DNS server.

Master DNS Server

My master DNS server, Mimas, runs FreeBSD as the operating system. FreeBSD releases prior to 10 include BIND as part of their base installation but I’m not using that here. I replaced the installed BIND in favour of one available through the ports tree. I did this so that it would be easier to perform upgrades and to have more control of what options were compiled into BIND. One of the options I was given when installing the port was to replace the BIND installation already present. I selected this option so I wouldn’t have two versions of BIND installed on Mimas at once.

Configuration Files

Because I’m using TSIG to secure such things as dynamic DNS updates and rndc, getting the permissions on the various configuration files right is very important. Here are the ownership and permissions of the various configuration files on Mimas. Take note of the ownership and permissions of the file containing my TSIG keys, named.key. It is set up this way so that named can read this file but only a process with root privileges can change it.

File Name Owner Permissions
/var/named/etc/namedb/named.conf root:wheel 644
/var/named/etc/namedb/named.key bind:wheel 440
/var/named/etc/namedb/rndc.conf root:wheel 440
/etc/resolv.conf root:wheel 644

Here is my named.conf file.

// $FreeBSD: release/8.4.0/etc/namedb/named.conf 224278 2011-07-22 21:45:12Z dougb $
//
// Refer to the named.conf(5) and named(8) man pages, and the documentation
// in /usr/share/doc/bind9 for more details.
//
// If you are going to set up an authoritative server, make sure you
// understand the hairy details of how DNS works.  Even with
// simple mistakes, you can break connectivity for affected parties,
// or cause huge amounts of useless Internet traffic.

include "/etc/namedb/named.key";

acl "internal-net" { 192.168.10/26; 127.0.0.1; };

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

logging {
        channel "named_log" {
                // send most BIND logs to a dedicated log file
                file "/var/log/named.log" versions 5 size 2m;
                severity dynamic;
                print-category yes;
                print-severity yes;
                print-time yes;
        };

        channel "query_log" {
                // query logs go to a separate file
                file "/var/log/query.log" versions 5 size 2m;
                severity debug;
                print-severity yes;
                print-time yes;
        };

        channel "update_log" {
                file "/var/log/update.log" versions 2 size 1m;
                severity debug 3;
                print-category yes;
                print-severity yes;
                print-time yes;
        };

        category default { named_log; };
        category queries { query_log; };
        category update { update_log; };
};

options {
	// All file and path names are relative to the chroot directory,
	// if any, and should be fully qualified.
	directory	"/etc/namedb/working";
	pid-file	"/var/run/named/pid";
	dump-file	"/var/dump/named_dump.db";
	statistics-file	"/var/stats/named.stats";
	allow-query { "internal-net"; };
	allow-transfer { none; };
	notify no;
	acache-enable yes;

// If named is being used only as a local resolver, this is a safe default.
// For named to be accessible to the network, comment this option, specify
// the proper IP address, or delete this option.
	listen-on	{ 192.168.10.11; };

// If you have IPv6 enabled on this system, uncomment this option for
// use as a local resolver.  To give access to the network, specify
// an IPv6 address, or the keyword "any".
//	listen-on-v6	{ ::1; };

// These zones are already covered by the empty zones listed below.
// If you remove the related empty zones below, comment these lines out.
	disable-empty-zone "255.255.255.255.IN-ADDR.ARPA";
	disable-empty-zone "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA";
	disable-empty-zone "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA";

// If you've got a DNS server around at your upstream provider, enter
// its IP address here, and enable the line below.  This will make you
// benefit from its cache, thus reduce overall DNS traffic in the Internet.
// Upstream DNS caches.
	forwarders {
		<ISP DNS Server 1>; <ISP DNS Server 2>;
	};

// If the 'forwarders' clause is not empty the default is to 'forward first'
// which will fall back to sending a query from your local server if the name
// servers in 'forwarders' do not have the answer.  Alternatively you can
// force your name server to never initiate queries of its own by enabling the
// following line:
//	forward only;

// If you wish to have forwarding configured automatically based on
// the entries in /etc/resolv.conf, uncomment the following line and
// set named_auto_forward=yes in /etc/rc.conf.  You can also enable
// named_auto_forward_only (the effect of which is described above).
//	include "/etc/namedb/auto_forward.conf";

	/*
	   Modern versions of BIND use a random UDP port for each outgoing
	   query by default in order to dramatically reduce the possibility
	   of cache poisoning.  All users are strongly encouraged to utilize
	   this feature, and to configure their firewalls to accommodate it.

	   AS A LAST RESORT in order to get around a restrictive firewall
	   policy you can try enabling the option below.  Use of this option
	   will significantly reduce your ability to withstand cache poisoning
	   attacks, and should be avoided if at all possible.

	   Replace NNNNN in the example with a number between 49160 and 65530.
	*/
	// query-source address * port NNNNN;
};

view "standard-in" in {

// The traditional root hints mechanism. Use this, OR the slave zones below.
zone "." { type hint; file "/etc/namedb/named.root"; };

/*	Serving the following zones locally will prevent any queries
	for these zones leaving your network and going to the root
	name servers.  This has two significant advantages:
	1. Faster local resolution for your users
	2. No spurious traffic will be sent from your network to the roots
*/
// RFCs 1912, 5735 and 6303 (and BCP 32 for localhost)
zone "localhost"	{ type master; file "/etc/namedb/master/localhost-forward.db"; };
zone "127.in-addr.arpa"	{ type master; file "/etc/namedb/master/localhost-reverse.db"; };
zone "255.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };

// RFC 1912-style zone for IPv6 localhost address (RFC 6303)
zone "0.ip6.arpa"	{ type master; file "/etc/namedb/master/localhost-reverse.db"; };

// "This" Network (RFCs 1912, 5735 and 6303)
zone "0.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };

// Private Use Networks (RFCs 1918, 5735 and 6303)
zone "10.in-addr.arpa"	   { type master; file "/etc/namedb/master/empty.db"; };
zone "16.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "17.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "18.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "19.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "20.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "21.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "22.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "23.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "24.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "25.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "26.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "27.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "28.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "29.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "30.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "31.172.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "168.192.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };

// Link-local/APIPA (RFCs 3927, 5735 and 6303)
zone "254.169.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };

// IETF protocol assignments (RFCs 5735 and 5736)
zone "0.0.192.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };

// TEST-NET-[1-3] for Documentation (RFCs 5735, 5737 and 6303)
zone "2.0.192.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "100.51.198.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "113.0.203.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };

// IPv6 Example Range for Documentation (RFCs 3849 and 6303)
zone "8.b.d.0.1.0.0.2.ip6.arpa" { type master; file "/etc/namedb/master/empty.db"; };

// Domain Names for Documentation and Testing (BCP 32)
zone "test" { type master; file "/etc/namedb/master/empty.db"; };
zone "example" { type master; file "/etc/namedb/master/empty.db"; };
zone "invalid" { type master; file "/etc/namedb/master/empty.db"; };
zone "example.com" { type master; file "/etc/namedb/master/empty.db"; };
zone "example.net" { type master; file "/etc/namedb/master/empty.db"; };
zone "example.org" { type master; file "/etc/namedb/master/empty.db"; };

// Router Benchmark Testing (RFCs 2544 and 5735)
zone "18.198.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };
zone "19.198.in-addr.arpa" { type master; file "/etc/namedb/master/empty.db"; };

// IANA Reserved - Old Class E Space (RFC 5735)
zone "240.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "241.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "242.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "243.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "244.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "245.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "246.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "247.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "248.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "249.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "250.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "251.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "252.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "253.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "254.in-addr.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };

// IPv6 Unassigned Addresses (RFC 4291)
zone "1.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "3.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "4.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "5.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "6.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "7.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "8.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "9.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "a.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "b.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "c.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "d.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "e.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "0.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "1.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "2.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "3.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "4.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "5.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "6.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "7.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "8.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "9.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "a.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "b.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "0.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "1.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "2.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "3.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "4.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "5.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "6.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "7.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };

// IPv6 ULA (RFCs 4193 and 6303)
zone "c.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "d.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };

// IPv6 Link Local (RFCs 4291 and 6303)
zone "8.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "9.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "a.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "b.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };

// IPv6 Deprecated Site-Local Addresses (RFCs 3879 and 6303)
zone "c.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "d.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "e.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };
zone "f.e.f.ip6.arpa"	{ type master; file "/etc/namedb/master/empty.db"; };

// IP6.INT is Deprecated (RFC 4159)
zone "ip6.int"		{ type master; file "/etc/namedb/master/empty.db"; };

zone "arda.homeunix.net" {
        type master;
        file "/etc/namedb/master/arda.homeunix.net.db";
};

// dynamicically updated subdomain of arda.homeunix.net
zone "endor.arda.homeunix.net" {
        type master;
        file "/etc/namedb/dynamic/endor.arda.homeunix.net.db";
        update-policy { grant mimas-dhcp subdomain endor.arda.homeunix.net. A DHCID TXT; };
};

zone "arda.homelinux.net" {
        type master;
        file "/etc/namedb/master/arda.homelinux.net.db";
};

zone "10.168.192.in-addr.arpa" {
        type master;
        file "/etc/namedb/master/10.168.192.in-addr.arpa.db";
};

// dynamically updated classless reverse zone
zone "32-47.10.168.192.in-addr.arpa" {
        type master;
        file "/etc/namedb/dynamic/32-47.10.168.192.in-addr.arpa.db";
        update-policy { grant mimas-dhcp subdomain 32-47.10.168.192.in-addr.arpa. DHCID PTR; };
};

// rblsmptd uses this zone to block IPs from China
zone "chinablock.hosts" {
        type master;
        file "/etc/namedb/master/chinablock.hosts.db";
};

};

view "ultimate-chaos" chaos {

	recursion no;

	zone "." {
		type hint;
		file "/dev/null";
	};

	zone "bind" {
		type master;
		file "/etc/namedb/master/bind.db";
	};
};

Some things to note concerning my named.conf file include the following points.

  • I use an include statement to inline my TSIG keys which are kept in a separate file, named.key. The reason for this is that the TSIG keys are only of value if nobody can gain access to them. The named.key file has more restrictive permissions than the named.conf file.
  • I have one access control list (ACL) defined; ‘internal-net’. I use this ACL to restrict who can query my name server. In my case, I allow queries only from machines on my home network.
  • The controls clause determines from where rndc can be used to control BIND. I have BIND accepting rndc commands from the loopback address only.
  • I use a logging clause to define three log channels. One channel essentially replaces logging to syslog. I thought having BIND send logs to a separate file would make it more convenient for me to find important log messages. Defining a log channel explicitly also provides a lot of control over what gets logged. For example, setting the severity level to dynamic allows me to determine how much debugging information I want to log by sending trace and notrace commands to rndc. The second channel is for logging the queries BIND handles. Queries are logged only if you turn query logging on using rndc. My DNS server is not very busy so I can afford to leave query logging on all the time. On a heavily loaded DNS server, you probably want to turn query logging on only when troubleshooting a problem. A busy name server can produce piles of query logs in a very short timespan. the third logging channel records dynamic updates. I found this very handy when configuring updates in ISC DHCP and, like query logging, since the rate of dynamic updates on my home network is low, I prefer to keep the logging on all the time.
  • I have notify set to no in the options section. Once I’ve set up a second DNS server, I’ll override this setting for the particular zones that can change from time to time.
  • The allow-transfer option in the options section sets BIND’s default behaviour to refuse all zone transfers. Like the notify option, I’ll override this setting for the zones that should be transferred to a second DNS server once I’ve set one up. In the meantime, this option ensures that my DNS server won’t be handing out zone transfers to just any old computer that asks for one.
  • The forwarders option tells BIND to not use iterative queries itself for information it doesn’t already know about but to forward a recursive query to the name servers specified instead. In my case, I have my server pointing to my ISP’s name servers. This allows me to make use of the caches on these name servers, which are almost certainly more extensive than those on my own name server. It should be noted that my setup will work perfectly fine without using the forwarders option. Whether you should use forwarders depends on many things including your network topology, the type of internet connection available, and the volume and types of queries you will be generating.
  • I’ve set up my BIND server to use views. One common use of views is to allow your name server to answer queries from your internal network differently than those from the internet at large, a so-called split horizon DNS server. In my case, I’m using views to have more control over how version information is served by BIND through the named.bind zone.
  • The arda.homelinux.net zone references a virtual domain used exclusively with my mail server; no real hosts are part of this domain. This entry is what allows me to route mail for the arda.homelinux.net domain. Every virtual domain used by my mail server needs to have a similar zone entry in the named.conf file.
  • The update-policy option in the arda.homeunix and 32-47.10.168.192.in-addr.arpa zones indicate that they can be updated by ISC DHCP. BIND also offers the allow-update option for dynamic DHCP updates. Both options can use a TSIG key to restrict who can perform updates but update-policy allows more control over what kinds of updates ISC DHCP can perform on a zone.
  • The odd looking reverse zone,  32-47.10.168.192.in-addr.arpa is there to deal with the fact that I’ve separated my DHCP range into it’s own zone files. The scheme I’ve followed roughly corresponds to what you would do for classless in-addr.arpa delegation. I’ve used it for a different purpose, though, and I have more to say about it here.
  • The bind zone is different from the rest. It’s presence allows me to control the version information reported by BIND. The ‘version’ option will also do this but setting up this zone provides for hiding version information from some clients using access control lists. It also allows for logging of such requests, something that isn’t possible when using the version option. BIND complaines if there is no hint zone in this view but it still seems to work. You can retrieve the information in the bind zone with these queries:
        dig version.bind txt chaos
      dig authors.bind txt chaos

Here is my rndc.conf file.

key "rndc-key" {
	algorithm hmac-md5;
	secret "<rndc-key key goes here>";
};

options {
	default-key "rndc-key";
	default-server 127.0.0.1;
	default-port 953;
};

And here is my named.key file.

key "rndc-key" {
	algorithm hmac-md5;
	secret "<rndc-key key goes here>";
};

key "mimas-dhcp" {
        algorithm hmac-md5;
        secret "<mimas-dhcp key goes here>";
};

My /etc/resolv.conf file looks like this.

search	arda.homeunix.net endor.arda.homeunix.net
nameserver	192.168.42.11

Zone Files

Zone files are located in the chroot jail in directories under /var/named/etc/namedb. BIND keeps zone files in three separate directories; master, slave and dynamic. Mimas has zone files in the master and dynamic directories but none in the slave directory. The Running BIND Chrooted section shows a listing of all the directories and files in the jail.

There are two *.jnl files in the dynamic directory. They are produced when ISC DHCP dynamically updates my zones.

Here are what my zone files look like.

/var/named/etc/namedb/master/

Zone File Contents
arda.homeunix.net.db
$ORIGIN .
$TTL 86400      ; 1 day
arda.homeunix.net       IN SOA  mimas.arda.homeunix.net. postmaster.arda.homeunix.net. (
                                20131220   ; serial
                                21600      ; refresh (6 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                21600      ; minimum (6 hours)
                                )
                        NS      mimas.arda.homeunix.net.
                        MX      10 phoebe.arda.homeunix.net.
$ORIGIN arda.homeunix.net.
pelori                  A       192.168.10.1
doriath                 A       192.168.10.2
mimas                   A       192.168.10.11
phoebe                  A       192.168.10.12
tethys                  A       192.168.10.13
rhea			A	192.168.10.14
atlas			A	192.168.10.15
Media-Centre-Mac-mini	A	192.168.10.24
mail			CNAME	phoebe
www			CNAME	rhea
arda.homelinux.net.db
$ORIGIN .
$TTL 86400      ; 1 day
arda.homelinux.net      IN SOA  mimas.arda.homeunix.net. postmaster.arda.homeunix.net. (
                                20130420   ; serial
                                21600      ; refresh (6 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                        NS      mimas.arda.homeunix.net.
                        MX      10 phoebe.arda.homeunix.net.
10.168.192.in-addr.arpa.db
$ORIGIN .
$TTL 86400      ; 1 day
10.168.192.in-addr.arpa IN SOA  mimas.arda.homeunix.net. postmaster.arda.homeunix.net. (
                                20140125   ; serial
                                21600      ; refresh (6 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                21600      ; minimum (6 hours)
                                )
                        NS      mimas.arda.homeunix.net.
$ORIGIN 10.168.192.in-addr.arpa.
; static IP addresses
1                       PTR     pelori.arda.homeunix.net.
2                       PTR     doriath.arda.homeunix.net.
11                      PTR     mimas.arda.homeunix.net.
12                      PTR     phoebe.arda.homeunix.net.
13                      PTR     tethys.arda.homeunix.net.
14                      PTR     rhea.arda.homeunix.net.
15                      PTR     atlas.arda.homeunix.net.
24			PTR	Media-Centre-Mac-mini.arda.homeunix.net.
; dynamic IP addresses
$GENERATE 32-47	$	CNAME	$.10.168.192.32-47
localhost-forward.db
; $FreeBSD: release/8.4.0/etc/namedb/master/localhost-forward.db 170914 2007-06-18 05:58:23Z dougb $

$TTL 3h
localhost. SOA localhost. nobody.localhost. 42 1d 12h 1w 3h
	; Serial, Refresh, Retry, Expire, Neg. cache TTL

	NS	localhost.

	A	127.0.0.1
	AAAA	::1
localhost-reverse.db
; $FreeBSD: release/8.4.0/etc/namedb/master/localhost-reverse.db 170914 2007-06-18 05:58:23Z dougb $

$TTL 3h
@ SOA localhost. nobody.localhost. 42 1d 12h 1w 3h
	; Serial, Refresh, Retry, Expire, Neg. cache TTL

	NS	localhost.

1.0.0	PTR	localhost.

1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 PTR localhost.
empty.db
; $FreeBSD: release/8.4.0/etc/namedb/master/empty.db 170914 2007-06-18 05:58:23Z dougb $

$TTL 3h
@ SOA @ nobody.localhost. 42 1d 12h 1w 3h
	; Serial, Refresh, Retry, Expire, Neg. cache TTL

@	NS	@

; Silence a BIND warning
@	A	127.0.0.1
bind.db
$TTL 1w
$ORIGIN bind.
@       CHAOS SOA mimas.arda.homeunix.net. postmaster.arda.homeunix.net. (
                                        1       ; Serial
                                        6h      ; Refresh after 6 hours
                                        1h      ; Retry after 1 hour
                                        1w      ; Expire after 1 week
                                        1d )    ; Negative caching TTL of 1 day

                        CHAOS   NS      localhost.

version.bind.           CHAOS   TXT     "BIND 9"
authors.bind.           CHAOS   TXT     "Are at home at the ISC."
chinablock.hosts.db
$TTL 86400
@       86400   IN      SOA     mimas.arda.homeunix.net. postmaster.arda.homeunix.net.  2013122301      5000    7200
        604800  86400
@               IN      NS      mimas.arda.homeunix.net.
*.1.0.1         IN      TXT     "Your source IP address has been rejected"      ;china
*.1.0.1         IN      A       127.0.0.2       ;china
*.2.0.1         IN      TXT     "Your source IP address has been rejected"      ;china
*.2.0.1         IN      A       127.0.0.2       ;china
...
*.252.255.223           IN      TXT     "Your source IP address has been rejected"      ;china
*.252.255.223           IN      A       127.0.0.2       ;china
*.253.255.223           IN      TXT     "Your source IP address has been rejected"      ;china
*.253.255.223           IN      A       127.0.0.2       ;china
;

The two localhost-*.db and the empty.db zone files were auto-generated when I installed BIND. The purpose of the empty.db zone file is to prevent unnecessary DNS queries from leaking out of my network and hitting the root name servers. The default named.conf file installed by BIND includes over 150 zones that point to the empty.db zone file. You’ll find more detailed explanations for the existence of the empty.db zone and the address ranges that use it in RFC5735 and RFC6303.

The two localhost-*.db zone files take care of DNS lookups to localhost, forward and reverse. Often the forward lookup is included in another zone file; in my case it would be arda.homeunix.net.db. BIND breaks it out by default, however, and gives it its own zone file. Usually name lookups for localhost are taken care of by a computer’s hosts file, at least in the Unix and Linux world, but it’s not a bad idea to have these zones present in DNS. They prevent DNS lookups for localhost or 127.0.0.1 from being sent to the root name servers which save the root servers some work and improves the performance of the applications initiating the lookups. RFC1912 goes into more detail about why you want to have DNS entries for localhost and your network and broadcast addresses.

The arda.homelinux.net.zone file contains no A records. Its sole purpose is to identify the mail server, via the MX record, that mail addressed to the arda.homelinux.net domain should be sent to.

My 10.168.192.in-addr.arpa zone uses the $GENERATE directive to create a number of CNAME resource records covering a specific range of IP addresses. These records are part of the in-addr.arpa delegation that I’ve set up to separate out my DHCP range into its own zone files.

The chinablock.hosts.db zone is different in purpose from my other zone files. It lists all known network blocks used by China. I use this zone file in conjunction with rblsmtpd on my mail server to reject email coming from that country. Before implementing this zone, all the email I received from China was spam. Most of it was caught by the various anti-spam measures I had in place but it was putting a lot of load on my mail server. I would also be subjected to regular dictionary attacks against my email authentication system. Eventually I said enough is enough and put the chinablock zone in place. Since then, I still see a China based mail server trying to spam me from time to time but using rblsmtpd with the chinablock zone allows my mail server to drop the connection a lot sooner while doing a lot less work than if, say, Spamassassin had to figure out if the incoming mail is spam or not. It’s a rather draconian measure but it’s an example of what you can do when you run your own mail server.

/var/named/etc/namedb/dynamic/

Zone File Contents
endor.arda.homeunix.net.db
$ORIGIN .
$TTL 86400	; 1 day
endor.arda.homeunix.net	IN SOA	mimas.arda.homeunix.net. postmaster.arda.homeunix.net. (
				20140116   ; serial
				21600      ; refresh (6 hours)
				3600       ; retry (1 hour)
				604800     ; expire (1 week)
				21600      ; minimum (6 hours)
				)
			NS	mimas.arda.homeunix.net.
			MX	10 phoebe.arda.homeunix.net.
$ORIGIN endor.arda.homeunix.net.
$TTL 14400	; 4 hours
MacBook-Pro		A	192.168.10.32
			TXT	"31780e98964637e85eaa17e06fa95e6966"
32-47.10.168.192.in-addr.arpa.db
$ORIGIN .
$TTL 86400	; 1 day
32-47.10.168.192.in-addr.arpa IN SOA mimas.arda.homeunix.net. postmaster.arda.homeunix.net. (
				20140135   ; serial
				21600      ; refresh (6 hours)
				3600       ; retry (1 hour)
				604800     ; expire (1 week)
				21600      ; minimum (6 hours)
				)
			NS	mimas.arda.homeunix.net.
$ORIGIN 10.168.192.32-47.10.168.192.in-addr.arpa.
$TTL 14400	; 4 hours
32			PTR	MacBook-Pro.endor.arda.homeunix.net.
36			PTR	WIN7-ASTJEAN.faceless.corporation.com.

As the name implies, all the zones in the namedb/dynamic directory are intended to be updated dynamically in response to a DHCP server handing out leases to clients. I used to have dynamic updates mixed up with static DNS records in my main arda.homeunix.net domain. I decided to tidy things up by separating DHCP associated records into their own subdomain. This led me to create the endor.arda.homeunix.net and 32-47.10.168.192.in-addr.arpa zones. It complicates my DNS configuration but it has a couple of significant benefits. My zone files are a lot cleaner now. There are no more dynamic records stuck in the midst of my static records in arda.homeunix.net.db or 10.168.192.in-addr.arpa.db. I can also restrict dynamic update permissions only to those zones that really need them.

The drawback is that I had to set up  classless in-addr.arpa delegation as described in RFC2317 to separate out the dynamically updated address range into the 32-47.10.168.192.in-addr.arpa zone. Even though I’ve set things up following the RFC, I’m not really delegating anything, Mimas is still authoritative for the dynamic zones so I don’t need to put NS records for any other name servers in my 10.168.19.in-addr.arpa zone.

Actually, I didn’t really have to do this at all. I had to do it only because I’m using a single /26 address range for my home network. I could have avoided the classless delegation by using two full class C subnets, one for static addresses and one for dynamic addresses. Alternatively, I could have simply ignored separating dynamic records from static records in my reverse zone and avoided the whole issue. Neither option would have let me learn how to set up classless delegation, however.

Notice that MacBook-Pro has A, TXT and PTR records while WIN7-ASTJEAN has only a PTR record. The difference has to do with how I’ve configured BIND and ISC DHCP to handle dynamic DNS updates. The Dynamic DNS Updates section of this documents goes into detail about what’s going on here and why I’ve set things up the way I did.

/var/named/etc/namedb/

Zone File Contents
named.root
;
; $FreeBSD: release/8.4.0/etc/namedb/named.root 245160 2011-07-22 21:45:12Z dougb $
;

;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  "
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC 
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:    Jan 3, 2013
;       related version of root zone:   2013010300
;
; formerly NS.INTERNIC.NET
;
.                        3600000  IN  NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:BA3E::2:30
;
; 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     199.7.91.13
D.ROOT-SERVERS.NET.	 3600000      AAAA  2001:500:2D::D
;
; 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
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2F::F
;
; 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
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::803F:235
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7FE::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:C27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7FD::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:3::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:DC3::35
; End of File

Finally we come to named.root, my root hints zone. The named.root file was auto-generated when installing BIND. Unlike every other zone file, BIND mixes this one up with its configuration files instead of putting it into one of the zone file directories described earlier. I can’t think of a reason why BIND does this but it does. The stock zone file provides instructions on how to download fresh copies but this command will provide the same information.

dig @a.root-servers.net . ns > named.root

Whether you download the file or execute the above command, it’s a good idea to refresh named.root periodically to ensure the list of root name servers is up to date. Root name servers don’t change very often so updating this file more than twice a year is probably overkill. Frequent updates also put undo load on the root name servers; they have enough to do as it is.

Manually Updating Zone Files

There are times when I’ve needed to manually update a zone file. Thanks to rndc, it’s a pretty simple process even when working with dynamically updated zones.

  1. Use rndc to freeze the zone. Or freeze all dynamically updated zones if you’re going to be modifying more than one.
  2. Edit the zone files as necessary. Make sure to increment the serial number of any file edited.
  3. Use rndc to thaw the zones.
  4. Use rndc to reload the modified zones.

If you need to edit zone files that are not subject to dynamic updates, then you don’t even need to freeze and thaw the zones. Edit the zone files remembering to increment their serial number and issue a reload command from rndc, simple as that.

Running BIND Chrooted

I run BIND with reduced privileges and in a chroot jail. There’s really nothing to doing this on FreeBSD as the BIND port does everything for you the first time you start the named process. The directory FreeBSD uses for its jail is /var/named. Here is what my jail looks like.

drwxr-xr-x  5 root  wheel      512 Sep 26 22:47 /var/named/
dr-xr-xr-x  8 root  wheel      512 Feb 16 23:20 /var/named/dev/
crw-rw-rw-  1 root  wheel     0x1e Feb 17 21:11 /var/named/dev/null
crw-rw-rw-  1 root  wheel      0xa Feb 16 17:36 /var/named/dev/random
drwxr-xr-x  3 root  wheel      512 Feb 16 22:36 /var/named/etc/
-r--r--r--  1 root  wheel     3477 Feb 16 10:43 /var/named/etc/localtime
drwxr-xr-x  6 root  wheel      512 Feb 16 21:51 /var/named/etc/namedb/
drwxr-xr-x  2 bind  wheel      512 Feb 16 23:56 /var/named/etc/namedb/dynamic/
-rw-r--r--  1 bind  wheel      477 Feb 16 23:56 /var/named/etc/namedb/dynamic/32-47.42.168.192.in-addr.arpa.db
-rw-r--r--  1 bind  wheel     1203 Feb 16 23:51 /var/named/etc/namedb/dynamic/32-47.42.168.192.in-addr.arpa.db.jnl
-rw-r--r--  1 bind  wheel      475 Feb 16 23:46 /var/named/etc/namedb/dynamic/endor.arda.homeunix.net.db
-rw-r--r--  1 bind  wheel      893 Feb 16 23:32 /var/named/etc/namedb/dynamic/endor.arda.homeunix.net.db.jnl
drwxr-xr-x  2 root  wheel      512 Feb 16 22:20 /var/named/etc/namedb/master/
-rw-r--r--  1 root  wheel     1163 Feb 16 22:17 /var/named/etc/namedb/master/42.168.192.in-addr.arpa.db
-rw-r--r--  1 root  wheel      676 Feb 16 22:18 /var/named/etc/namedb/master/arda.homelinux.net.db
-rw-r--r--  1 root  wheel     1127 Feb 16 22:19 /var/named/etc/namedb/master/arda.homeunix.net.db
-rw-r--r--  1 root  wheel      613 Feb 17 19:57 /var/named/etc/namedb/master/bind.db
-rw-r--r--  1 root  wheel  3643582 Feb 16 22:16 /var/named/etc/namedb/master/chinablock.hosts.db
-rw-r--r--  1 root  wheel      239 Sep 27 06:34 /var/named/etc/namedb/master/empty.db
-rw-r--r--  1 root  wheel      261 Sep 27 06:34 /var/named/etc/namedb/master/localhost-forward.db
-rw-r--r--  1 root  wheel      329 Sep 27 06:34 /var/named/etc/namedb/master/localhost-reverse.db
-rw-r--r--  1 root  wheel    19746 Feb 16 23:15 /var/named/etc/namedb/named.conf
-r--r-----  1 bind  wheel      211 Feb 16 21:50 /var/named/etc/namedb/named.key
-rw-r--r--  1 root  wheel     3137 Sep 27 06:34 /var/named/etc/namedb/named.root
-r--r-----  1 root  wheel      182 Feb 16 21:51 /var/named/etc/namedb/rndc.conf
drwxr-xr-x  2 bind  wheel      512 Sep 26 22:47 /var/named/etc/namedb/slave/
drwxr-xr-x  2 bind  wheel      512 Feb 16 23:34 /var/named/etc/namedb/working/
-rw-r--r--  1 root  wheel     6088 Sep 27 06:34 /var/named/etc/protocols
-rw-r--r--  1 root  wheel    86669 Sep 27 06:34 /var/named/etc/services
drwxr-xr-x  6 root  wheel      512 Sep 26 22:47 /var/named/var/
drwxr-xr-x  2 bind  wheel      512 Sep 26 22:47 /var/named/var/dump/
drwxr-xr-x  2 bind  wheel      512 Feb 16 22:44 /var/named/var/log/
-rw-r--r--  1 bind  wheel    49188 Feb 17 21:15 /var/named/var/log/named.log
-rw-r--r--  1 bind  wheel  1412521 Feb 17 21:22 /var/named/var/log/query.log
-rw-r--r--  1 bind  wheel     2261 Feb 16 23:51 /var/named/var/log/update.log
drwxr-xr-x  3 bind  wheel      512 Feb 16 23:01 /var/named/var/run/
srw-rw-rw-  1 root  wheel        0 Feb 16 23:01 /var/named/var/run/log
drwxr-xr-x  2 bind  wheel      512 Feb 16 23:34 /var/named/var/run/named/
-rw-r--r--  1 bind  wheel        5 Feb 16 23:34 /var/named/var/run/named/pid
-rw-------  1 bind  wheel      102 Feb 16 23:20 /var/named/var/run/named/session.key
drwxr-xr-x  2 bind  wheel      512 Sep 26 22:47 /var/named/var/stats/

Notice that only files that BIND has to write to are owned by the user bind. The exception is named.key which is owned by bind so that this user can read it but still can’t write to it.

Startup Scripts

To run BIND on system boot, put this line into /etc/rc.conf.

named_enable="YES"

If you really want BIND’s chroot jail to reside in a different directory, you can add this line to /etc/rc.conf as well.

named_chrootdir="/your/chosen/path"

If you decide to do this, remember to copy the directory structure found in /var/named to your preferred chroot otherwise as all that wonderful automation I talked about won’t work.

Did I mention that FreeBSD also configures BIND to run with reduced privileges as the user bind? There is no need for you to create the required user or set extra arguments for named yourself. Not bad, huh?

DHCP

When I built ISC DHCP on Mimas, I had the option to include Paranoia configure parameters, which I took. Doing so allows me to run ISC DHCP chrooted with reduced privileges. I strongly suggest you use this option! The FreeBSD port I used to install ISC DHCP added these two configure parameters to the build when I chose the Paranoia option. If you’re compiling the ISC DHCP tarball from scratch, make sure you include them too.

--enable-paranoia --enable-early-chroot

The functionality provided by these parameters used to be provided by a third party patch but is now incorporated into the DHCP codebase. You can still find the standalone DHCP Paranoia patch at the link listed in the Software Home Sites section of this document but I include it only for historical interest. You don’t need it with current versions of ISC DHCP.

Configuration Files

Here is my DHCP configuration file.

/usr/local/etc/dhcpd.conf

# dhcpd.conf

# option definitions common to all supported networks...
option domain-name "arda.homeunix.net";
option domain-name-servers 192.168.10.11;

default-lease-time 14400;
max-lease-time 86400;

# Use this to enble / disable dynamic dns updates globally.
ddns-update-style interim;
ddns-ttl 14400;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

subnet 192.168.10.0 netmask 255.255.255.192 {

  range 192.168.10.32 192.168.10.47;

  # let clients modify their own records
  allow client-updates;

  # options
  option subnet-mask 255.255.255.192;
  option broadcast-address 192.168.10.63;
  option routers 192.168.10.1;
  option domain-name "endor.arda.homeunix.net";
  option domain-search "endor.arda.homeunix.net", "arda.homeunix.net";

  # dynamic DNS updates
  ddns-domainname "endor.arda.homeunix.net.";
  ddns-rev-domainname "32-47.10.168.192.in-addr.arpa.";

  key "mimas-dhcp" {
    algorithm hmac-md5;
    secret "<mimas-dhcp key>";
  };

  zone endor.arda.homeunix.net. {
    primary 192.168.10.11;
    key mimas-dhcp;
  }

  zone 32-47.10.168.192.in-addr.arpa. {
    primary 192.168.10.11;
    key mimas-dhcp;
  }
}

# host declarations are global in scope

# always give my media centre the same address
host Media-Centre-Mac-mini {
  hardware ethernet 00:24:36:a9:fd:5c;
  fixed-address 192.168.10.24;
}

The dhcpd.conf file supplies all the information that will be given to DHCP clients and also controls dynamic updates with DNS servers. There are several points to note with this file.

  • I’m using a CIDR network. This only seemed reasonable given the small number of machines I have running. The size of the network (64 IP addresses starting with 192.168.10.0) is stipulated by the subnet and netmask line. Make sure the subnet-mask and broadcast-address lines match otherwise your network is going to get very confused. You can calculate all the network parameters you need to set up a CIDR network from my IP Addressing for CIDR Networks page.
  • The ddns-* parameters control dynamic updates between ISC DHCP and BIND. Make sure you use the correct value for ddns-update-style. I used to use ‘ad-hoc’ for this value but that update style is now deprecated and I needed to change the value to ‘interim’. The correct value has been interim for quite a while now. There is nothing so permanent as a temporary measure.
  • I added the allow client-updates parameter to my dhcpd.conf file. This lets DHCP clients attempt to update DNS directly. I say attempt because I’m using a TSIG key to restrict who can update DNS. I explain why I’ve set things up this way in the Dynamic DNS Updates section below.
  • The mimas-dhcp TSIG key referred to in the configuration file is the same key that appears in the rndc.key file on Mimas.
  • I give a fixed address to the Mac Mini I use as a media centre. There’s no particular reason it needs a fixed address. I just decided I wanted to set one up to see what they looked like.

Dynamic DNS Updates

When setting up dynamic DNS updates in ISC DHCP I found the documentation a little on the vague side. With that in mind, I thought I’d explain how dynamic updates are working on my network and why I set things up the way I have.

As I explained in my description of BIND, I set up two DNS zones specifically for dynamic updates, endor.arda.homeunix.net and 32-47.168.192.in-addr.arpa. This allows me to separate dynamically updated resource records from all my static addresses. Besides keeping my zone files tidy, this allows me to use more restrictive permissions on my static zones. The dynamic zones have to be owned by the user bind, for example, while static zones are owned by root.

To further control who is able to update my dynamic zones, I’m using a TSIG key. Only signed update requests will by honoured by BIND. All other requests will be ignored. In practice, this means BIND is only going to accept update requests coming from ISC DHCP.

But hold on. I’m using the ‘allow client-updates’ directive in my DHCP configuration. Isn’t this telling ISC DHCP to allow DHCP clients to update DNS directly if they so choose? Yes it does, but my use of TSIG signed updates means BIND will reject all update requests coming directly from DHCP clients. What gives?

It turns out that even when you use allow client-updates, ISC DHCP still updates the PTR record in BIND itself leaving the DHCP client to update its own A record. Not only that, but ISC DHCP keeps the client’s native domain in the PTR record it sends to BIND. That’s why I see this PTR record in the relevant zone file when I connect my work laptop to my network.

36			PTR	WIN7-ASTJEAN.faceless.corporation.com.

And not something like this.

36			PTR	WIN7-ASTJEAN.endor.arda.homeunix.net.

There is no A record for WIN7-ASTJEAN because BIND is rejecting any updates sent directly by my laptop. After all, I haven’t told my laptop about the TSIG key I’m using.

There are two other options for the client-updates directive, ignore and deny. As far as I can tell, they result in identical behaviour. In both cases, A, TXT and PTR records are created in the relevant zone files by ISC DHCP. The A and PTR records replace the DHCP client’s native domain name with the dynamic domain I’ve specified in my DHCP configuration file, endor,arda.homeunix.net. Keep in mind that this behaviour describes a Windows client. Other operating systems, Linux for example, might behave differently.

Turns out I prefer having DHCP clients keep their native domains when updating BIND. In my home network, it really doesn’t make much difference which way I go. If I’m not aware of all the computer’s connecting to my network, then I have bigger problems than what domain names they have in BIND. On a large network, though, where you can’t know ahead of time all the computers that will be connecting, I can see pros and cons for both options. Do you need to have A records for all DHCP clients? Is it more important to easily identify guest computers in which case having a computer’s native domain in its PTR record might make more sense. Which way you go really comes down to what you need to do.

Running ISC DHCP Chrooted

Like BIND, I run ISC DHCP with reduced privileges and in a chroot jail. Once again, using the FreeBSD port to install software came to my rescue and the jail was automatically created with all required files already in place. The port placed the jail in /var/dhcpd.

Here is a listing of the various directories and files that are found in the jail. The /var/dhcpd/dev directory contains numerous device files. More than I wanted to list here. I’m sure ISC DHCP doesn’t need them all, in my old installation only dev/null and dev/random were present in the jail and I wasn’t sure it needed even those two devices. Since the FreeBSD port populated this directory for me though, I’m not going to argue.

dr-xr-xr-x  6 root  wheel  512 Jan  3 17:46 /var/dhcpd/dev/
dr-xr-xr-x  6 root  wheel  512 Jan  3 17:46 /var/dhcpd/dev/...
drwxr-xr-x  3 root  wheel  512 Jan  3 17:46 /var/dhcpd/etc/
drwxr-xr-x  2 dhcpd  dhcpd   512 Dec 25 21:55 /var/dhcpd/etc/_
-rw-r--r--  1 dhcpd  dhcpd    46 Dec 25 15:11 /var/dhcpd/etc/host.conf
-rw-r--r--  1 dhcpd  dhcpd   176 Dec 25 10:09 /var/dhcpd/etc/hosts
-r--r--r--  1 dhcpd  dhcpd  3477 Dec 25 10:08 /var/dhcpd/etc/localtime
-rw-r--r--  1 dhcpd  dhcpd    74 Dec 25 11:32 /var/dhcpd/etc/resolv.conf
drwxr-xr-x  3 root  wheel  512 Dec 25 21:55 /var/dhcpd/usr/
drwxr-xr-x  3 root  wheel  512 Dec 25 21:55 /var/dhcpd/usr/local/
drwxr-xr-x  2 dhcpd  dhcpd  512 Jan  3 17:46 /var/dhcpd/usr/local/etc
-r--r-----  1 dhcpd  dhcpd  1649 Jan  3 17:29 /var/dhcpd/usr/local/etc/dhcpd.conf
drwxr-xr-x  4 root  dhcpd  512 Dec 25 21:55 /var/dhcpd/var/
drwxr-xr-x  3 root  dhcpd  512 Dec 25 21:55 /var/dhcpd/var/db/
drwxr-xr-x  2 dhcpd  dhcpd  512 Jan 25 20:10 /var/dhcpd/var/db/dhcpd/
-rw-r--r--  1 dhcpd  dhcpd  2208 Jan 25 20:41 /var/dhcpd/var/db/dhcpd/dhcpd.leases
-rw-r--r--  1 dhcpd  dhcpd  2692 Jan 25 20:10 /var/dhcpd/var/db/dhcpd/dhcpd.leases~
drwxr-xr-x  3 root  dhcpd  512 Dec 25 22:08 /var/dhcpd/var/run/
drwxr-xr-x  2 dhcpd  dhcpd  512 Dec 25 21:55 /var/dhcpd/var/run/dhcpd/
-rw-r--r--  1 dhcpd  dhcpd  6 Jan  3 17:46 /var/dhcpd/var/run/dhcpd/dhcpd.pid
srw-rw-rw-  1 root   dhcpd    0 Dec 25 22:08 /var/dhcpd/var/run/log

You’ll notice that there is a copy of ISC DHCP’s configuration file within the jail, in /var/dhcpd/usr/local/etc to be precise. That file is copied from /usr/local/etc every time ISC DHCP starts up. Here is a listing of the file outside the jail. Note that it is owned by root:wheel.

-r--r-----  1 root  wheel  1649 Jan  3 17:29 /usr/local/etc/dhcpd.conf

If ISC DHCP is compromised and an attacker is able to modify the copy of dhcpd.conf found inside the jail, it will simply be overwritten the next time ISC DHCP is started.

Another feature to note is the UNIX domain socket /var/dhcpd/var/run/log. This is present to allow ISC DHCP to send messages to syslog from within the jail. To make this work, I needed to add this line to my rc.conf file.

/etc/rc.conf

syslogd_flags="-l /var/dhcpd/var/run/log -s"

Startup Scripts

I added a number of lines to my rc.conf file to control how ISC DHCP starts. Most of these lines are related to running ISC DHCP in a chroot jail.

/etc/rc.conf

dhcpd_enable="YES"
dhcpd_flags="-q"
dhcpd_conf="/usr/local/etc/dhcpd.conf"
dhcpd_ifaces="em0"
dhcpd_chuser_enable="YES"
dhcpd_withuser=dhcpd
dhcpd_withgroup=dhcpd
dhcpd_chroot_enable="YES"
dhcpd_devfs_enable="YES"
dhcpd_rootdir="/var/dhcpd"

Most of the startup directives are self-explanatory. The -q flag suppresses a copyright notice during startup . Also note that the configuration file pointed to by dhcpd_conf is the one outside the chroot jail. ISC DHCP needs to know where it is so it can copy it into the jail at startup.

And with that, you’re good to go. ISC DHCP should be ready to hand out leases and dynamically update BIND.

Software Home Sites

BIND
DHCP
http://www.isc.org/
dhcp-3.0+paranoia.patch http://www.episec.com/people/edelkind/patches/

Further Reading

Bind9.net – An excellent source of DNS and DHCP information http://www.bind9.net/
DNS Group Webstart Page – Lots of links to DNS information http://www.the-paynes.com/DNS/
DNS Setup and Troubleshooting – Covers BIND version 8 http://www.troubleshooters.com/linux/dns.htm
Building and Running BIND 9 http://www.unixwiz.net/techtips/bind9-chroot.html
Secure BIND Template http://www.cymru.com/Documents/secure-bind-template.html
Descriptions of classless in-addr.arpa delegation http://www.indelible.org/ink/classless/
http://cr.yp.to/djbdns/dot-arpa.html
Dissenting opinions regarding RFC 2317 http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/avoid-rfc-2317-delegation.html