HOWTO Setup a DNS Server with BIND

From Gentoo Linux Wiki

Jump to: navigation, search
This article is part of the HOWTO series.
Installation Kernel & Hardware Networks Portage Software System X Server Gaming Non-x86 Emulators Misc



Contents

[edit] Introduction

BIND (Berkeley Internet Name Daemon) is an open reference implementation of the Domain Name System (DNS) protocol and provides a redistributable implementation of the major components of the Domain Name System.

  • a name server (named)
  • a resolver library
  • troubleshooting tools like nslookup and dig

The BIND DNS Server is used on the vast majority of name serving machines on the Internet, providing a robust and stable architecture on top of which an organization's naming architecture can be built. The resolver library included in the BIND distribution provides the standard APIs for translation between domain names and Internet addresses and is intended to be linked with applications requiring name service.

[edit] My Bind Installation

My personal Bind installation has over 15000 zones and peaks at roughly 500 queries/sec across two servers. This How-To includes many organizational tips for running a large system without administration of it becoming unwieldly. I'll point those out along the way so home users with three or four domains can skip the extra steps. However most of the large system configs are geared towards easier troubleshooting and administration and I encourage all users to use the ISP tweaks I've included. After all most large systems started out as small systems.

[edit] Firewall Config

Bind listens on port 53 UDP and TCP. TCP is normally only used during zone transfers so it would appear that you could filter it if you have no slaves. However If the response to a query is greater than 1024 bytes, the server sends a partial response, and client and server will try to redo the transaction with TCP.

Responses that big do not happen often, but they happen. And people do quite often block 53/tcp without their world coming to an end. But this is where one usually inserts the story about the Great DNS Meltdown when more root servers were added. This made queries for the root list greater than 1024 and the whole DNS system started to break down from people violating the DNS spec (RFC1035) and blocking TCP.

[edit] Installing Bind

This document is based on a fresh install of 2005.0 built on July 13 on a Dell 4700. 3.0Ghz P4 w/HT, gentoo-sources 2.6.12-r4 SMP kernel, glibc built with the NPTL flag, and Bind 9.2.5-r4. Older or newer installs should not differ too greatly from this install.

Bind is in Portage and has a number of USE variables to add functionality. We're going to eliminate most of them for the purpose of this doc to keep things simple. Once I'm happy that this doc can actually lead someone through a simple setup, I may go back and add in other functionality.


[edit] Choosing your USE flags

For most users I'd recommend removing IPv6 support and any database support. This doc probably won't delve into using a database backend. Linux 2.6 users with NPTL that anticipate a high number of queries will defintely want to enable threads as Bind is highly threaded.

Code: /etc/portage/package.use
net-dns/bind -ipv6 -ldap -mysql -bind-mysql -postgres -odbc threads

[edit] Dependencies

On my fresh install there were no extra dependencies required over the default install using the above USE variables.

azul ~ # emerge -upv bind

These are the packages that I would merge, in order:

Calculating dependencies ...done!
[ebuild  N    ] net-dns/bind-9.2.5-r4  +berkdb -bind-mysql -dlz -doc -idn
-ipv6 -ldap -mysql -odbc -postgres (-selinux) +ssl +threads 4,398 kB


Bind as configured above builds in under five minutes on my test system. Your mileage may vary.

[edit] Configuring kernel

It's possible that you may need to change your kernel configuration. "Different security models" is optional, but if you have enabled it, you must also enable the default Linux capabilities:

Linux Kernel Configuration: Kernel Configuration
Security options  --->
    [X] Enable different security models
        <*>   Default Linux Capabilities

[edit] Configuring Bind

Gentoo alternates between naming files and directories "named" or "bind" which makes everything confusing. Also, most other OSs use "named" for everything rather than "bind". I've forgotten exactly what I did to straighten things out, but the commands below should allow you to assume everything is in a named/something or called named.whatever. I'll need to do a fresh install to verify sometime soon.

I prefer to break customer domains into include files by company. We have a small number of customers with 500+ domains per customer. It's a bit easier to find domains in the config this way and to track changes. I also include the logging config and any acls this way as well. You can put them all into one file if you like.

[edit] Creating Dirs and Symlinks

We're going to create some structure for the rest of config files. We're also going to symlink bind dirs to named dirs so that admins unfamilar with Gentoo can still find evertything. It's like that whole /etc/apache vs /etc/httpd problem people new to Gentoo have. This will also keep /var/bind/ from getting littered with files and make an etc-update mishaps less likely to lose all your configs.

ln -sf /etc/bind /etc/named
ln -sf /var/bind /var/named
mkdir /var/bind/conf
mkdir /var/named/reverse
mkdir /var/named/personal
mkdir /var/named/customer1
mkdir /var/named/customer2
chown -R named: /var/bind
mkdir /var/log/bind
ln -sf /var/log/bind /var/log/named
chown -R named: /var/log/bind

[edit] Fixing the Pid Files and RC Scripts

Note: This is an obsolete step for current ebuilds.

Ebuilds prior to net-dns/bind-9.2.5-r4 had an issue with the named.pid file. Following steps are recommended to fix it.

mkdir -p /var/run/named
chown named: /var/run/named

Then edit /etc/init.d/named and change all instances of /var/run/named.pid to /var/run/named/named.pid. I find this layout a bit cleaner than dropping named in /var/run/ and my named.conf below assumes you've done this.

[edit] named.conf

I really suggest using this config. Yes you can set Bind up without all the logging, splitting domains into their own file, but troubleshooting is vastly easier when you have done all the groundwork. You will need to change the IP's that are allowed to do recursion to your own IP's. The same will allow transfer and notify as well.


File: /etc/named/named.conf
options {
        directory "/var/named"; // sets root dir, use full path to escape
        statistics-file "/var/named/named.stats"; // stats are your friend
        dump-file "/var/named/named.dump";
        zone-statistics yes;
        allow-recursion { 127.0.0.1; 10.0.0.0/8; }; // allow recursive lookups
        allow-transfer { 10.11.12.1; 10.11.12.2; }; // allow transfers to these IP's
        notify yes; // notify the above IP's when a zone is updated
        also-notify { 10.110.0.11; 10.120.0.11; }; // notify these other servers when a zone is updated
        pid-file "/var/run/named/named.pid";
        transfer-format many-answers; // Generates more efficient zone transfers
        listen-on { any; };
};

// Include logging config file
include "/var/named/conf/logging.conf";

// Include to ACLs
include "/var/named/conf/acls.conf";

// Include customer zones
include "/var/named/conf/customer1.conf";
include "/var/named/conf/customer2.conf";


NOTE: The 'listen-on' option can have as many IP addresses as you want separated by ';' or the word 'any' which will make it listen on all IP's on port 53 by default (you can specify other ports as well). The default for this option is '127.0.0.1' which will not allow a DNS lookup to your server from any computer other than the one you are running BIND on.

[edit] Logging conf

Bind can be chatty in the log files and the sheer amount of data can sometimes make it hard to find interesting logs. Fortunately Bind allows you to separate your logs and rotate them automatically in its config. The following config splits each logging category into separate files, rotates them every 5MB, and keeps three rotations of each log. You can change the length of the log file rotations by changing the versions and size options in each channel. While this config seems quite large and ugly it'll never need to be touched and having log files separated like this can make many common troubleshooting procedures easier.

Note: The directory specified in each channel statement (in this example: /var/log/named) must exist and be writable by the named user
File: /var/named/conf/logging.conf
logging {

  channel default_file { file "/var/log/named/default.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel general_file { file "/var/log/named/general.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel database_file { file "/var/log/named/database.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel security_file { file "/var/log/named/security.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel config_file { file "/var/log/named/config.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel resolver_file { file "/var/log/named/resolver.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel xfer-in_file { file "/var/log/named/xfer-in.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel xfer-out_file { file "/var/log/named/xfer-out.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel notify_file { file "/var/log/named/notify.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel client_file { file "/var/log/named/client.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel unmatched_file { file "/var/log/named/unmatched.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel queries_file { file "/var/log/named/queries.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel network_file { file "/var/log/named/network.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel update_file { file "/var/log/named/update.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel dispatch_file { file "/var/log/named/dispatch.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel dnssec_file { file "/var/log/named/dnssec.log" versions 3 size 5m; severity dynamic; print-time yes; };
  channel lame-servers_file { file "/var/log/named/lame-servers.log" versions 3 size 5m; severity dynamic; print-time yes; };

  category default { default_file; };
  category general { general_file; };
  category database { database_file; };
  category security { security_file; };
  category config { config_file; };
  category resolver { resolver_file; };
  category xfer-in { xfer-in_file; };
  category xfer-out { xfer-out_file; };
  category notify { notify_file; };
  category client { client_file; };
  category unmatched { unmatched_file; };
  category queries { queries_file; };
  category network { network_file; };
  category update { update_file; };
  category dispatch { dispatch_file; };
  category dnssec { dnssec_file; };
  category lame-servers { lame-servers_file; };

};

[edit] ACL conf

The ACL section defines Access Control Lists that Bind uses to group a set of networks by name. In this example, the networks 10.*.*.*, 192.168.1.*, and 127.0.0.1 have been grouped together under the name 'our-networks'. This name can then be used to refer to the entire group when assigning permissions. (See: HOWTO_Setup_a_DNS_Server_with_BIND#Adding an ACL to a Zone)

File: /var/named/conf/acls.conf
acl "our-networks" {
        10.0.0.0/8;
        192.168.1.0/24;
        127.0.0.1;
};

[edit] Zone File conf

There are many examples of how to add a zone file to the config. Zone statements can be placed directly in named.conf, or they can be included from an external file using the include statement. In this example we will include one of the two zone statements listed below. Zone configurations can be made in two different formats. Let's call them single-line and multi-line.

This is how a configuration in multi-line format appears:

File: multi-line.conf
zone "badapple.net" IN {
      type master;
      file "personal/badapple.net";
};
zone "chilug.org" IN {
      type master;
      file "personal/chilug.org";
};


And this is the same config with a single zone on each line:

File: single-line.conf
zone "badapple.net" IN { type master; file "personal/badapple.net"; };
zone "chilug.org" IN { type master; file "personal/chilug.org"; };


You may prefer the single line format for administrative tasks. It's easier to run sort, grep, sed, and other tools against the config file to make mass changes. Any script you write to generate a new slave or master config will be easier and simpler to write. However, it appears that the multi-line config is easier to read in documentation, so we're going to use it through out this How-To for clarity.

Each refers to zone file using the file line to include a map of domain names and their matching IP addresses. Zone files are covered in more detail below.

Note: The examples above use relative paths for each zone file. The directory root is specified by the directory statement in the options section of named.conf. Any directory listed without a leading slash will have the root directory added to the beginning of the path. In this case, personal/chilug.org is treated by Bind as /var/named/personal/chilug.org.

[edit] Adding a Slave Zone

File: multi-line.conf
zone "badapple.net" IN {
    type slave;
    file "personal/badapple.net";
    masters { 10.11.12.1; };
};

zone "chilug.org" IN {
    type slave;
    file "personal/chilug.org";
    masters { 10.11.12.1; };
};

Note: There is a bit of confusion on where these files go. multi-line.conf would be the include you had in /etc/bind/named.conf. In this case you would add the line include "/var/named/conf/multi-line.conf".

[edit] Adding an ACL to a Zone

We can use the Access Control Lists to specify permissions for each zone.

 allow-query { our-networks; };

Adding this line to the zone defined below tells Bind that any of the networks specified in the 'our-networks' group has permission to request the name of any IP address in the 10.113.1.* network.

File: /var/named/conf/zone-with-acl.conf
zone "1.113.10.in-addr.arpa" IN {
    type master;
    file "reverse/10.113.1.0";
    allow-query { our-networks; };
};

[edit] Zone Files

[edit] Picking Your Zone File

There are a number of example of zone files on the Internet, each with their own little quirks. I would recommend using a layout that appeals to you. However it is in your best interest to use the same format for all your domains. This will make changes easier and you can script out wholesale changes using sed or other tools if your IP's need to change quickly or other problems. There is nothing worse than trying to edit 1000 domains by hand each with a different format.

[edit] Example of a Zone File for a Domain

File: Sample of Zone File
$TTL 600
; domain1.com
@       IN      SOA     laxlxns01.dnsserver.com. hostmaster.dnsserver.com. (
                        2005062601      ; serial
                        12h             ; refresh
                        1h              ; retry
                        2w              ; expire
                        1h              ; minimum
                        )

        IN      NS      laxlxns01.dnsserver.com.
        IN      NS      laxlxns02.dnsserver.com.
        IN      MX      10      mail.domain1.com.
@                       IN      A       10.10.10.34

; host records
localhost               IN      A       127.0.0.1
mail                    IN      A       10.20.20.45
*                       IN      A       10.10.10.34

[edit] Domain Zone File Explained

[edit] About serial numbers

Don't forget to update the serial number each time you change a zone file. The new serial number must be anything larger than the previous one. Most systems simply use the date of the change plus two digits as a serial number. For example, a zone file that has been changed for the second time on the third of January 2004 would have
2004010302
as a serial number. But the serial number can be any number with the maximum value of 9999999999 as long as the new serial number is larger than the previous serial number. If you don't increment your serial number, your DNS slave servers will not accept the changes and keep the old version of the zone file.

Sometimes you'll need to reset your serial number. This is easy to do if you control all your name servers. Change the master server, stop the slave servers, delete the old zone, start the slave servers. However if you do not have access to your slave servers you can set the serial number to 0 on the master server. Once the slave picks up the change you'll be able to use any number as the next serial number. This is usually done when an admin sets the serial to 3005103001 and wants to reset the serial back to 2005103001 or something similar.

[edit] About IP Addresses

When specifying a given IP range using the format 8.113.10.in-addr.arpa., the bytes are given in reverse order. In effect the IP range is 10.113.8.0/24. For a 16-bit netmask, it would be 113.10.in-addr.arpa., equivalent to 10.113.0.0/16.

[edit] Example of a Zone for Reverse DNS

File: reverse
$TTL    600
8.113.10.in-addr.arpa.   IN      SOA     laxlxns01.dnsserver.com.    hostmaster.dnsserver.com. (
                        2005062601      ; serial
                        12h             ; refresh
                        1h              ; retry
                        2w              ; expire
                        1h              ; default_ttl
                        )

8.113.10.in-addr.arpa.  IN      NS      laxlxns01.dnsserver.com.
                        IN      NS      laxlxns02.dnsserver.com.

;
; DB VLAN

21      IN      PTR     laxlxdb01.domain1.com.
22      IN      PTR     laxlxdb02.domain1.com.

31      IN      PTR     laxlxdb01.domain2.com.
32      IN      PTR     laxlxdb02.domain2.com.

[edit] Helper Scripts

File: dns-generateslave.sh
#!/bin/bash
# Quick little bash script to create a slave conf based on the current master conf.

echo ""
echo "Current directories are:"
echo "customer1, customer2, customer3"
echo ""
read -p "Enter the directory you wish to create a slave config for:  "

for i in `awk '{print $2}' /var/named/conf/$REPLY.conf | sed 's/\"//g'`
        do echo "zone \""$i"\" IN { type slave; file \""$REPLY/$i"\"; masters { 38.118.147.251; }; };" >> $REPLY-slave.conf
        done
File: dns-newdomains.sh
#!/bin/bash
#  Quick little bash script to create a new master conf by listing the domains in a dir

echo "Current directories are:"
echo "customer1, customer2, customer3"
echo ""
read -p "Enter the directory you wish to create a config for:  "

for i in `ls /var/named/$REPLY`
        do echo "zone \""$i"\" IN { type master; file \""$REPLY/$i"\"; };" >> $REPLY.conf
        done

[edit] Default zone

If you are a hosting provider and want to have default zone (if some domain has your NS server as primary, but you haven't added zone for this domain yet) for newly-added domains AND your server is not designed to execute recursive queries, you can use this section:

File: Sample of Default Zone File
zone "." IN {
	type master;
	file "path_to_default_zone_file";
};

After this, any domain, that cannot be found in your configuration will be passed over "path_to_default_zone_file" ruleset.

[edit] Further Information

Personal tools
In other languages