Now that we have a working knowledge of the Domain Name System architecture, it's time to move from theory to practice and set up our first domain name server.
This is the overall layout of the network in which our name servers will be placed. It is a very simple network, made up of:
All of our systems will belong to the "kernel-panic.it" zone and our first DNS server will be the primary master name server for that zone; it will reside in the DMZ and answer internal queries for Internet and DMZ servers' names.
Bind configuration takes place in named.conf(5), which is, by default, located in /var/named/etc/. You can, however, specify an alternate path using the -c flag of the named(8) command.
The configuration syntax is rather simple: it is a series of statements enclosed in curly braces and terminated with a semi-colon. Statements contain a variable number of semi-colon terminated clauses, in keyword/value form. Supported comment styles are:
The "options" statement defines global options to be used by Bind. The "directory" clause specifies the directory against which subsequent relative paths should be resolved. The default values are retained for unspecified clauses. E.g.:
options { # Bind runs chrooted to "/var/named/", hence "/" actually is "/var/named/" directory "/"; };
The "zone" statements tell Bind what zones it is authoritative for; for each zone, the "type" clause specifies whether the server is a master or a slave for it and the "file" clause specifies the path to the corresponding zone data file. E.g.:
zone "kernel-panic.it" { type master; file "master/db.kernel-panic.it"; };
The names of the zone data files are free-form, but it's highly recommended to follow a reasonable naming convention to make maintenance easier. For instance, zone data files are often called db.domain.
In order to allow for reverse name resolution, we also need to create zone data files for each network:
zone "240.16.172.in-addr.arpa" { type master; file "master/db.172.16.240"; }; zone "250.16.172.in-addr.arpa" { type master; file "master/db.172.16.250"; }; zone "3.2.1.in-addr.arpa" { type master; file "master/db.1.2.3"; };
The name server will also need to map the loopback address to a name. Therefore, we will have to create specific zone data files for the "localhost" zone and the 127.0.0.0/8 network:
zone "localhost" { type master; file "master/db.localhost"; }; zone "127.in-addr.arpa" { type master; file "master/db.127"; };
[RFC1912] also recommends that the "255.in-addr.arpa" and "0.in-addr.arpa" zones always be present in nameserver configurations to either provide nameservice for "special" addresses, or to help eliminate accidental queries for broadcast or local address to be sent off to the root nameservers
:
zone "255.in-addr.arpa" { type master; file "master/db.255"; }; zone "0.in-addr.arpa" { type master; file "master/db.0"; };
Finally, if the name server must be able to resolve Internet names, we have to give it the list of the root name servers, which is specified using a hint zone.
zone "." { type hint; file "master/root.hint"; };
You can find a copy of the root.hint file in the /var/named/etc directory.
Zone data files contain information about the zones the server is authoritative for, and, according to our configuration, they will be placed in the /var/named/master/ directory.
Usually, the first line of a zone data file sets the default TTL for the zone, i.e. how long other DNS servers and applications are allowed to cache the record.
$TTL 3h
A zone data file may contain multiple $TTL statements: each applies to all subsequent records (that don't have an explicit TTL) until a new $TTL statement is found. You may want to tweak this value to find a good trade-off between bandwidth usage and data freshness.
The next entry in a zone data file is the SOA record, which indicates that the name server is authoritative for that zone.
@ IN SOA dns1.kernel-panic.it. danix.kernel-panic.it. ( 2007020601 ; serial 3h ; refresh after 3 hours 1h ; retry after 1 hour 1w ; expire after 1 week 1h ) ; negative caching TTL of 1 hour
Let's examine it in detail. The "@" symbol represents the zone the server is authoritative for; well, to be more precise, it represents the origin of the data in the zone data file, which, by default, is the same as the zone's domain name. The origin is appended to all names in the zone data file that don't end with a trailing dot and can be modified with the $ORIGIN statement.
IN is the class of the record (Internet). SOA is the record type (Start Of Authority). "dns1.kernel-panic.it." is the name of the primary master name server for this zone and "danix.kernel-panic.it." is the mail address of the zone administrator, with the "@" replaced with a dot (therefore, the actual address would be "danix@kernel-panic.it").
Now we come to the numbers enclosed within brackets (brackets simply allow the record to span across multiple lines) (note that comments, in zone data files, start with a semicolon and finish at the end of the line). The serial number is a progressive number that must be increased whenever zone data is updated or slave name servers won't notice that data has changed (according to [RFC1912], the recommended format for the serial number is "YYYYMMDDnn", where "nn" is the revision number). The refresh value sets how often slave name servers should check that their zone data is up to date. If the master is unreachable, the retry and expire values tell slaves at what interval to attempt to connect again and after how long to stop giving out data about the zone. The last value is the time to live for negative responses from the name servers authoritative for the zone.
Next, every zone data file has one or more NS records, specifying the name servers authoritative for the zone.
kernel-panic.it. IN NS dns1.kernel-panic.it. kernel-panic.it. IN NS dns2.kernel-panic.it.
The first field of a resource record is its name and must start on the first column; if omitted, it defaults to the previous one. Therefore, the above NS records can be shortened as:
IN NS dns1.kernel-panic.it. IN NS dns2.kernel-panic.it.
The MX record allows you to specify the host that will manage mail for the domain name; this record has an extra parameter, a 16-bit integer indicating the mail exchanger's priority (the lower the number, the higher the priority).
IN MX 0 mail.kernel-panic.it. IN MX 10 mail.provider.com.
The next record, "A", is specific to forward-mapping zone data files, since it associates domain names with their IP address.
mail IN A 172.16.240.150 proxy IN A 172.16.240.151 www1 IN A 172.16.240.152 www2 IN A 172.16.240.153 dns1 IN A 172.16.240.154 dns2 IN A 172.16.240.155 mickey IN A 172.16.0.200 IN A 172.16.240.200 minnie IN A 172.16.0.201 IN A 172.16.240.201 router IN A 172.16.250.1 IN A 1.2.3.4 [...]
The CNAME record maps an alias to its canonical name; in other words, it defines a domain name pointing to another node of the domain name space.
antivirus IN CNAME mail cache IN CNAME proxy
Ok, we're done with forward-mapping; let's have a look at the reverse-mapping zone data files. The beginning is exactly the same: you set the default TTL and insert the SOA and NS records that we've seen before. Next come the PTR records, which map addresses to host names; well, to be more precise, they map names in the in-addr.arpa domain to names in the kernel-panic.it domain. Again, the origin is automatically appended to all domain names that don't end with a trailing dot, allowing you to specify only the last octet(s) of the IP addresses.
$TTL 3h @ IN SOA dns1.kernel-panic.it. danix.kernel-panic.it. ( 2007020601 ; serial 3h ; refresh after 3 hours 1h ; retry after 1 hour 1w ; expire after 1 week 1h ) ; negative caching TTL of 1 hour IN NS dns1.kernel-panic.it. IN NS dns2.kernel-panic.it. 100 IN PTR donald.kernel-panic.it. 101 IN PTR daisy.kernel-panic.it. 102 IN PTR fw-ext.kernel-panic.it. 150 IN PTR mail.kernel-panic.it. 151 IN PTR proxy.kernel-panic.it. 152 IN PTR www1.kernel-panic.it. 153 IN PTR www2.kernel-panic.it. 154 IN PTR dns1.kernel-panic.it. 155 IN PTR dns2.kernel-panic.it. 200 IN PTR mickey.kernel-panic.it. 201 IN PTR minnie.kernel-panic.it. 202 IN PTR fw-int.kernel-panic.it.
To recap, here are the complete zone data files.
Running Bind is as simple as typing "named". The first time, you may want to run it with the -g flag, which runs the server in the foreground and forces all logging to stderr.
# named -g 10-Nov-2013 18:17:44.897 starting BIND 9.4.2-P2 -g 10-Nov-2013 18:17:44.907 loading configuration from '/etc/named.conf' 10-Nov-2013 18:17:44.910 listening on IPv6 interfaces, port 53 Binding privsep [...] 10-Nov-2013 18:17:45.494 running
You will probably be warned that the name server couldn't find the file /etc/rndc.key: don't worry about this yet, we will discuss rndc(8) in a moment. In case named(8) complains about syntax errors, you can use the named-checkconf(8) and named-checkzone(8) commands to check the syntax of the Bind configuration file and the zone data files respectively.
If everything looks alright, you can test your fresh new name server with nslookup(1) or dig(1).
$ nslookup mail.kernel-panic.it 127.0.0.1 Server: 127.0.0.1 Address: 127.0.0.1#53 Name: mail.kernel-panic.it Address: 172.16.240.150 $
To start Bind on system boot, simply add the following line to the /etc/rc.conf.local(8) file:
named_flags=""
The rndc(8) utility allows you to communicate with the name server and send it authenticated commands over a TCP connection. It reads its configuration from the rndc.conf(5) file (by default in /var/named/etc/), which has a syntax similar to named.conf(5). The following is a sample configuration file to connect to the server at localhost:
options { default-server localhost; default-port 953; default-key "rndc-key"; }; server localhost { key "rndc-key"; }; key "rndc-key" { algorithm hmac-md5; secret "jIpKqniOSfP7Nr5GTTyDkw=="; };
To make the name server accept rndc(8) connections, just add the following lines to your named.conf(5) file (adjusting the allow list as needed):
key "rndc-key" { algorithm hmac-md5; secret "jIpKqniOSfP7Nr5GTTyDkw=="; }; controls { inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; }; };
If you like things simple, you can generate the rndc(8) configuration file automatically, by using the rndc-confgen(8) utility. A typical usage for rndc(8) is to force Bind to reload its configuration file and zones:
# rndc -c /var/named/etc/rndc.conf reload server reload successful
Now that your primary master name server runs fine, you may want to set up a slave name server to allow for redundancy and load sharing. Bind configuration is quite similar:
options { directory "/"; }; zone "kernel-panic.it" { type slave; masters { 172.16.240.154; }; file "slave/bak.kernel-panic.it"; }; zone "240.16.172.in-addr.arpa" { type slave; masters { 172.16.240.154; }; file "slave/bak.172.16.240"; }; zone "250.16.172.in-addr.arpa" { type slave; masters { 172.16.240.154; }; file "slave/bak.172.16.250"; }; zone "3.2.1.in-addr.arpa" { type slave; masters { 172.16.240.154; }; file "slave/bak.1.2.3"; }; # Loopback address zone "localhost" { type master; file "master/db.localhost"; }; zone "127.in-addr.arpa" { type master; file "master/db.127"; }; # Special zones zone "255.in-addr.arpa" { type master; file "master/db.255"; }; zone "0.in-addr.arpa" { type master; file "master/db.0"; }; # Root zone zone "." { type hint; file "master/db.cache"; };
For all the zones the slave name server is authoritative for (except for the loopback address and the "special" zones) type is now slave. We also had to add the masters clause to tell Bind the address of the primary master name server(s). The file specified in a slave zone is where Bind will store data transferred from the master; this allows Bind to have a local copy of the data in case the master name server is unreachable at startup.