Securing a DNS Server (207.3)

Revision: $Revision: 1037 $ ($Date: 2012-11-26 20:55:45 +0100 (Mon, 26 Nov 2012) $)

Resources and further reading: Albitz01, BINDfaq, DNShowto, Lindgreen01, Liu00, Nijssen99, Raftery01.

LPIC 2 objective 207.3 (2 points)

Candidates should be able to configure a DNS server to run as a non-root user and run in a chroot jail. This objective includes secure exchange of data between DNS servers.

Key Knowledge Areas:

  • BIND 9 configuration files
  • Configuring BIND to run in a chroot jail
  • Split configuration of BIND using the forwarders statement

The following is a partial list of used files, terms, and utilities:

  • /etc/named.conf
  • /etc/passwd
  • DNSSEC
  • dnssec-keygen

DNS Security Strategies

There are several strategies possible to make DNS more secure.

When a security bug is discovered in the BIND name server, it will in most cases be fixed within a few hours, resulting in a new BIND release. This means that some of the BIND versions that are a little older may have known (possibly security-related) bugs. Keep an eye on the BIND source site (http://www.isc.org/software/bind) periodically. Consider subscribing to a security announcement list of a Linux distribution. For instance, the Debian debian-security-announce list is fast way to learn about a new security bug. See http://lists.debian.org to subscribe.

Making information harder to get

There are ways to limit information that a normal user can query from a name server without influencing the normal name resolving. For instance, the version number can be hidden. Or access can be limited, e.g., zone transfers can be limited to a specific set of slave name servers. Both will be discussed next.

It is important to remember that hiding information is security through obscurity. That is, the easy way to get information is blocked, but there may be other ways to get the same information by trying several other ways. Security through obscurity makes it harder to get the information, but it does not make it impossible.

Hiding the version number

Since older BIND versions may have known security bugs, the BIND version number can be of great help to someone who wishes to compromise your system. The command

    dig @target chaos version.bind txt

will show the version of the BIND name server on host target.

The BIND version can be hidden by entering a version statement inside the options statement in named.conf. In the following example, the version will be set to the string hidden.

    options {
        // ...
          
        // hide bind version
        version "hidden";
    };        

The CERT article (Nijssen99) shows a way to limit access to the bind zone. This an alternative to replacing the BIND version.

Limiting access

There are several ways to limit access to the name server. First, an access control list must be defined. This is done with the acl statement.

    acl "trusted" {
        localhost;
        192.168.1.0/24;
    };

This acl defines an access control list with label trusted. This label is a name that can be used later, as will be shown.

Two types of connections between name servers and between name servers and resolvers are normal queries and zone transfers.

normal queries

When a host sends a query to a name server, it asks a name server for specific information.

The allow-query statement controls from which hosts queries are accepted.

zone transfers

A zone transfer happens when a name server sends all it knows about a zone to another name server or a resolver. Zone transfers are intended for slaves that need to get information from a master of the same zone.

Zone transfers are controlled by the allow-transfer statement.

The allow-query and allow-transfer statements can to be used inside a zone statement or inside an options statement. It can contain either an acl label (like trusted), or none, or one or more IP addresses or IP ranges.

Limiting zone transfers

Both dig and nslookup can initiate a zone transfer. By default, both master and slave servers can give out all zone information. With dig,

    dig @target example.org axfr

shows the complete information about example.org. With nslookup in interactive mode,

    ls -d example.org

shows the same information.

Strictly speaking, only a slave name server needs a zone transfer to get the full information about the zone from a master name server for the zone.

A setup where only these zone transfers are allowed, but all other zone transfers are prohibited, is described here. It consists of extras in the named.conf's of both the master and all the slaves for a particular zone.

On master name servers.  On a master name server for the example.org zone, the allow-transfer statement is used to limit zone transfers to a list of known slave servers.

    acl "my_slave_servers" {
        224.123.240.3;  // cat.example.org
    };

    // ...

    zone "example.org" IN {
        type master;
        // ....

        allow-transfer {
            my_slave_servers;
        };
    };

Now only the slaves (only cat here) can request a zone transfer from this master name server.

On slave name servers.  On a slave name server for the same zone, the complete zone should not be exposed at all. This too is implemented using an allow-transfer statement.

    zone "example.org" IN {
        type slave;
        // ....

        allow-transfer {
            none;
        };
    };

Now this slave will not accept zone transfer requests.

Note

Don't forget to do the same for the reverse zone.

Limiting queries

For security reasons, normal queries can also be limited to a set of clients. This limits access to a certain set of hosts.

    acl "myhosts" {
        224.123.240.0/24;
    };

    // ...

    zone "example.org" IN {
        // ...

        allow-queries {
            myhosts;
        };
    };

This limits queries to hosts with an IP address that starts with 224.123.240.

Controlling requests

Apart from hiding information by making it harder to get, one can control some automatic behavior of a name server that can turn out to be dangerous.

When a (malicious) name server receives a query it can respond with deliberately false data which infects the cache of the name server that sent the query. This is called spoofing. Although spoofing is not as easy as it may seem, it is wise to take precautions. Many possible spoofing methods have been made impossible in the software. In the BIND configuration steps can be taken to enhance spoofing security.

Limiting effects of an intrusion

Even if you're prepared to implement any DNS fix as soon as it appears, you may be too late - even by only a couple of hours: your system could be compromised anyway. You can prepare for this by minimizing the effects of possible compromises.

Running BIND with less privileges

By default, at least in some distributions, BIND runs as root. If BIND is compromised, the attacker may get root access. This can be prevented by running BIND under a different user and group.

It is tempting to use user nobody and group nogroup for this. However, with many services running as nobody and nogroup another security issue arises when these services are able to communicate in one way or another.

The suggested way is to create a special user, e.g. named, and a corresponding group (which could also be called named), and run the name server under this user/group combination.

To use the special user and group, specify the -u and -g options to named:

    named -u named -g named

On a Debian system, for instance, the start line in /etc/init.d/bind becomes

    start-stop-daemon ... --exec /usr/sbin/named -- -u named -g named

(for layout reasons some options have been replaced by dots). The extra -- tells the start-stop-daemon to stop eating options, so that the named program gets these.

On a Red Hat (or compatible) system, the bind file will probably be /etc/rc.d/init.d/dns. The corresponding line to start the name server will become something like

    daemon /sbin/named -u named -g named

Note

Make sure the name server has write access in the directory specified by the directory option in named.conf.

Running BIND in a chroot jail

Another way to prevent damage from a compromised name-server process is to put the process in a chroot jail. In such an environment, a specified directory (e.g., /var/cache/bind) will be the / (root) directory for this process. The process has no means of looking above this new root, i.e., it cannot see the rest of the filesystem anymore.

Preparing a chroot jail

Since BIND uses all sorts of files, these files must be copied to a directory structure below the new root that mimics the original directory structure. Article Lugo00 lists files to copy. Here is an abstract:

  • You will need the etc, dev, lib, sbin or usr/sbin, and var/run directories under the new root.

  • You'll probably need the /dev/null device under the new root:

        mknod -m 666 /var/cache/bind/dev/null c 1 3
    

    will create it.

  • You will need a passwd and a group file in the new /etc:

        cd /var/cache/bind/etc
        cp -p /etc/{passwd,group} .
    

    This copies the literal passwd and group files. An alternative is to create special passwd and group files, as will be shown in the section called “Combining special user and chroot”.

    You may also need to copy in some other stuff.

         cd /var/cache/bind/etc
         cp /etc/ld.so.cache .
         cp /etc/localtime .
    

  • The configuration must also be present under the new root. The chrooted named will need to find it when it receives a reload request. The configuration can be placed in /var/cache/bind/etc/bind.

    Note that each directory specified in the new named.conf - the ones specified with the directory option - is relative to the new root directory.

  • The new lib directory must contain at least all the shared libraries used by bind. For instance, on my system,

       ldd /usr/sbin/named
    

    yields

            libc.so.6 => /lib/libc.so.6 (0x40015000)
            /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
    

    When looking in (real) /lib, libc.so.6 is a symlink to libc-2.1.3.so and ld-linux.so.2 is a symlink to ld-2.1.3.so. Both the symlinks and the files they point to must be copied to the lib directory under the new root:

        cd /var/cache/bind/lib
        cp -pd /lib/{libc.so.6,libc-2.1.3.so,ld-linux.so.2,ld-2.1.3.so} .
    

  • Both the named and the named-xfer programs must be present under the new root. The rndc program may be of help too. On my system, they are in /usr/sbin:

        cp -p /usr/sbin/named{,-xfer} /var/cache/bind/usr/sbin
        cp -p /usr/sbin/rndc /var/cache/bind/usr/sbin
    

    On my system, it is in /usr/sbin and uses the same shared libraries as named.

Running BIND chrooted

To get the BIND name server in a chroot jail, simply add the -t and a directory name to the command line used to start the name server.

Note

It is also possible to use the chroot command to start the name server. This has exactly the same effect as using the -t option, so it is not covered here.

So, for example, in /etc/init.d/bind:

    start-stop-daemon ... --exec /usr/sbin/named -- -t /var/cache/bind

This will make /var/cache/bind the new root directory for the name server.

Or, in /etc/rc.d/init.d/dns:

    daemon ... /sbin/named -t /var/cache/bind

This makes /var/cache/bind the new root directory for the name server.

Remember that the double dash -- after named tells the start-stop-daemon to pass options after the double dash to named.

Important

The BIND name server activates the chroot immediately after all command lines are read. That is, before the configuration files are read.

Configuration for a chrooted BIND

The configuration files are read after the name server has chrooted to the specified directory. As a consequence, every configuration file (e.g. zone files and the named.conf file) must be present in a configuration directory (e.g., /etc/bind) under the chroot directory.

One of the things that must be reconfigured is logging. The normal logging to syslog will not work because of the chroot jail (cannot reach the Unix socket /dev/log and cannot recreate it). Here is an example logging statement from the named.conf file inside the chroot environment that can solve this problem:

    logging {
        channel some_log { 
            file "bind.log" versions 3; 
            severity info;
        };

        category default { some_log; };

        // ...
    };

This will write logging information to the file /var/cache/bind/var/cache/bind/bind.log, which was composed as follows:

/var/cache/bind (the first)

the chroot directory specified by the -t option when starting named

/var/cache/bind (the second)

the directory specified by the directory statement inside the options statement

bind.log

the name of the log file specified by the logging statement

Zone files, if any, are also placed inside the chroot environment. For instance, if named.conf contains a definition of a master zone like

    zone "example.com" IN {
        type master;
        file "/etc/bind/example.com.zone";
    };

the example.com.zone file will be in /var/cache/bin/etc/bind.

Combining special user and chroot

Using a combination of running the name server under a special user and group and a chroot environment will yield even better security. If the zone- and configuration files are unwritable by the special user and group the name server is running under, they cannot be compromised by a name server break in.

Note

Inspecting the source for BIND reveals the order in which things happen:

  • parsing of commandline options

  • chrooting

  • go in the background and write pid file

  • change to new user and group

This means that the directory where the pid file is written (e.g., /var/run) needs write permission for root, but the new caching directory needs write permission for the specified user and group.

The chroot environment creates the possibly of special /etc/passwd and /etc/group files, that are completely different from the ones in the real /etc. The special user and group used by the name server may not even exist in the real /etc/passwd. This is the way to create the special files

    cd /var/cache/bind/etc
    echo "named::22" > group
    echo "named:x:22:22:named:/var/cache/bind:/bin/false" > passwd

However, the named program needs to know the special uid/gid's at startup. So you must also do:

    echo "named::22" >> /etc/group
    echo "named:x:22:22:named:/var/cache/bind:/bin/false" >> /etc/passwd

Do not forget to add something like

    named:!:11222:0:99999:7:::

This must be added to both /etc/shadow files (one in the real /etc, and one relative to the chroot environment) if shadow passwords are active.

Securing name server connections

If a malicious name server manages to infect zone transfers, it can poison the zone information on a slave nameserver. Zone transfers can be limited to certain hosts by the allow-transfer statement in named.conf.

Queries can also be poisoned. Queries can also be limited to dedicated hosts or host groups using the allow-query statement.

Limiting access to certain hosts may solve the risk for poisoning if that hosts can be trusted. But how can you be sure of this? If a name server receives an answer, it simply cannot be sure that the name server that sent the answer really is the name server it claims to be.

Signing an answer by the name server that sends it may solve this. Now the name server that receives the answer can verify the signature. And, it knows whether or not the answer really originated on the name server that the sender claims to be.

According to the lpic2 objective you must be able to use BIND 9's dnssec-keygen. This helps you to configure secure transactions between name servers. This tool is not compatible with the DNSSEC tools shipped with BIND 9.2.x. and earlier.

Note

The dnssec-keygen command is part of the DNSSEC security extension for DNS (fully described in Albitz01).

DNSSEC was not really useful in BIND before version 9. It is fully implemented now which is described in the Albitz and Liu book.

DNSSEC was in development for several years, but since it is fully implemented in BIND 9 the use of it was minimal before. The 13 authoritive root servers are using DNSSEC since May 6th 2010.

Using the dnssec-keygen command

The dnssec-keygen generates public, private and shared keys for DNS, according to the manual page. The dnssec-keygen command can generate public and private keys to authenticate zone data and shared secret keys to be used for Request/Transaction signatures.

The required parameters for generating a key:

a algorithm (specify -a)

RSA | RSAMD5 | DH | DSA | RSASHA1 | HMAC-MD5

a key size (specify -b)

Depends on chosen algorithm:

RSAMD5: [512..4096]
RSASHA1: [512..4096]
DH: [128..4096]
DSA: [512..1024] and divisibly by 64
HMAC-MD5: [1..512]
a nametype (specify -n)

ZONE | HOST | ENTITY | USER | OTHER

Generated key files

The dnssec-keygen creates two files: Kname+algorithm+footprint.private and Kname+algorithm+footprint.key.

Suppose the command given is

    dnssec-keygen -a DSA -b 768 -n ZONE example.com.

Now two output files are created called Kkey.example.com.+157+12345.private and Kkey.example.com.+157+12345.key.

The file Kkey.example.com.+157+12345.private looks like

    Private-key-format: v1.2
    Algorithm: 157 (HMAC)
    Key: 5VBiSy...

The file Kkey.example.com.+157+12345.key has the following contents

    key.example.com. IN KEY 513 3 157 5VBiSy...

The generated keys (abbreviated in both cases) are identical in both files. That is because the key are generated using a HMAC algorithm.

Using the key

To use the generated key put a key statement in named.conf. This looks like

    key key.example.com. {
        algorithm "hmac-md5";
        secret "5VBiSy...";
    };

This requires, of course, that named.conf be unreadable for anyone but the name server. The key can also be put in a separate file that can be included with the include statement, so that the included file is the one that has limited readability.

Next, define the server that connects using the key. On server 224.123.400.2 define that host 224.123.400.1 can use this key:

    server 224.123.400.1 {
         keys key.example.com.;
    };

On name server 224.123.400.1 do the same for server 224.123.400.2.

Now transfers (for instance) can be limited to those zones that are signed by this key:

    zone "example.com" {
        type master;
        file "example.com.zone";
        allow-transfer { key key.example.com.; };
    };

Internal DNS

Suppose your division is located outside the firm's main building. The workgroup will have its own name servers. Internally, hosts will be members of the exworks (short for exampleworks) domain, that is, directly under the root (.) domain. IP addresses of all hosts begin with 192.168.72, so the reverse zone 72.168.192.in-addr.arpa will also be maintained.

The problem with this is that the root name servers don't know anything about the exworks and 72.168.192.in-addr.arpa zones. Nor should they: there should be no request concerning these internal zones to one of the root name servers. Since the DNS system was not designed for use behind a firewall, some tricks must be applied. A poor-man's solution is to try to limit any traffic from the internal name server to the root servers. But, using a split-level DNS setup is likely to be a much better solution. Two split-level DNS setups will be shown.

Limiting negotiations

BIND behind a dial-up connection can be a nuisance: every time a DNS wants to communicate with a root name server, an automatic dialer sets up a connection. You stop BIND from doing this by putting

        // prevent dialup access
        heartbeat-interval 0;
        dialup yes;

inside the options statement of the named.conf file.

This trick can also be used to limit communication from an internal zone like exworks. The exworks and 72.168.192.in-addr.arpa zones are implemented as conventional master zones as described earlier in this chapter.

The fundamental problem with this is that the real root servers still don't delegate the exworks (and corresponding reverse) domain. A better solution therefore is to put the internal zones together with the root name server definition into a separate DNS implementation. This requires at least two independent name servers, and they can be set up in two different ways, as will be described below.

Split DNS: stand-alone internal master

The first approach consists of a stand-alone name server (that is, master for the internal zones) and another name server on another host that can be used to resolve names from both the outside world and the internal zones.

The figure below presents the exworks domain that is used as an example.

The exworks network.

The two name servers in this example will be on different hosts. The first name server runs on privdns and will provide internal zone information. The other name server is on liongate, which will be a forwarding name server for both the internal zones and the outside world.

The host privdns (for private DNS) will contain the DNS for both the exworks and 72.168.192.in-addr.arpa zones. This name server will have the following characteristics:

  • it will be master for the root domain, but no DNS except itself will be able to access this information

  • it will be master for the the exworks and 72.168.192.in-addr.arpa domains. Only other name servers inside the building will be able to access this information

On the other hand, liongate will do the following:

  • do forwarding for the internal zones (this should be done first)

  • do forwarding for the outside world

Configuring the master on privdns

First, prepare a master file for the internal root zone For example:

    $TTL 25h
    .       IN  SOA privdns.exworks. postmaster.privdns.exworks. (
                2001121000    ; yyyymmhhee (ee == ser/day start 00)
                     28800
                      3600
                    604800
                     86400 )
            IN  NS privdns.exworks.
    privdns.exworks. IN  A  192.168.72.2

    ; glue records
    exworks.                 IN NS privdns.exworks.
    72.168.192.in-addr.arpa. IN NS privdns.exworks.

Note the glue records that delegate the exworks and 72.168.192.in-addr.arpa zones.

Next, add a zone statement in named.conf that points to the master file for the root zone:

    // ROOT MASTER zone for internal DNS server
    zone "." IN {
            type master;
            file "/etc/bind/internal.root.zone";
            allow-transfer { none; };
            allow-query    { none; };
    };

Using the type master tells the DNS that this really is a master server for the root zone. The root zone should not be known to any other name servers, therefore the allow-transfer and allow-query are set to none.

Note

The root zone definition type hint, as present in a default caching-only server, should be turned off (by not including it in the named.conf file.

Now, prepare zone files for the exworks and 72.168.192.in-addr.arpa zones, and add the corresponding zone entries in the named.conf file. The entry for exworks should look like this:

    zone "exworks" IN {
            type master;
            file "/etc/bind/exworks.zone";
            allow-transfer { none; };
            allow-query    { 192.168.72.1; }; // liongate
    };

The name server on liongate is the one providing names to the other hosts, so the IP address of liongate must be listed in the allow-query field.

The same must be done for the corresponding reverse zone.

Make sure the options statement contains

        recursion no;
        fetch-glue no;

These statements tell the name server it should not accept queries for zones other than the ones it knows about.

Hosts in the exworks zone should point their resolv.conf to liongate. That is, the file should contain the line:

    nameserver 192.168.72.1

where 192.168.72.1 is the IP address of liongate. On liongate itself, however,

    nameserver 127.0.0.1

is more efficient.

Note

The entries in resolv.conf on privdns should not point to the name server on privdns itself. If the host is to be used for purposes that require name resolving, it is better to point the entries to the name server on liongate.

Configuring DNS on liongate

The functionality of the DNS is twofold: first it should resolve names of the exworks zone (and corresponding reverse zone), secondly, it should resolve names from the outside world.

With the following forwarders statement queries to this name server are being forwarded to one on the listed IP addresses (remember that forwarders is part of the options statement):

        forwarders {
            192.168.72.2;   // privdns
            224.121.121.99; // ISP's DNS
        };

The name servers are tried in the order in which they are listed. Requests are forwarded to privdns first. If that one does not have the answer, the DNS of the ISP is contacted instead.

Note that the IP address of privdns should be mentioned first: we don't want requests for internal names be sent to the ISP.

Alternatively, the name server on liongate can be configured as slave for the exworks domain and corresponding reverse domain. Because this is a must in the setup where both name servers are on one host (which is described next), it is not discussed here.

Alternatives

There are two alternatives to this setup. Both require two separate name servers.

The first alternative is to use two nameserver statements in resolv.conf:

    nameserver 192.168.72.2
    nameserver 192.168.72.1

The first IP address points to privdns, the second to liongate. In this situation, privdns should also accept queries from 192.168.72.0/24 and the forwarders statement on liongate should not contain the 192.168.72.2 (the IP address of privdns). The downside of this is that there is no single name server entry-point.

The second alternative is to use a slave setup for the exworks (plus corresponding reverse) domain. This situation is required when two name servers are running on the same host. This will be elaborated below, so it will not be discussed here. For this to work, the forwarders statement on liongate should not contain the IP address of privdns.

Split DNS: two DNS servers on one machine

Suppose the same network exists as above, but with one important difference: host privdns is not available. This implies that the internal name server must now run on one of the other hosts, which also need access to the outside world.

In the situation described here, both name servers will be running on one host. At least one of these must run chrooted.

Two name servers on one host

In order to do this, the following settings must be made:

  • The internal name server.  There is a master name server that serves the exworks and corresponding reverse domains. It runs chrooted, under its own uid/gid, listening at a special port. It will not do any other resolver work. This name server will be referred to as the internal name server.

  • The visible name server.  The other name server does not run chrooted, but it does have its own uid/gid. It serves as a slave for the exworks and 72.168.192.in-addr.arpa domains. It also forwards other requests to the ISP. This name server will be referred to as the visible name server, since this is the name server that will be visible to other hosts.

The nameserver line in the resolv.conf file points to 127.0.0.1; other hosts in the exworks domain point their resolver to 192.168.72.1 (the IP address of liongate).

Configuring the internal name server

The name server is put into a chroot jail with own user and group ID's. The name server will chroot to /var/cache/bindInternal. It will run as user inamed with UID 5301 and as group with the same name and GID 5301.

This chrooted name server should be able to write to some directories. To allow this, these directories should be owned by the inamed UID and GID. The directories (inside the chroot jail) that need this are /var/run (because it needs to write named.pid) and /var/cache/bind (because it needs to write e.g. a logfile).

The configuration directory will be /var/cache/bindInternal/etc/bind, so that references from the named.conf file in that directory will be to /etc/bind. Files in that directory include the master file for the root zone and the zone files for both the exworks and 72.168.192.in-addr.arpa domains.

Here are the three master zone definitions:

    options {
        directory "/var/cache/bind";
        listen-on port 5353 { 127.0.0.1; };
        recursion no;
        fetch-glue no;
    };

    // NOT SHOWN HERE, described elsewhere:
    // - special chroot logging, see above
    // - zones "localhost", "127.in-addr.arpa", "0.in-addr.arpa" and
    //   "255.in-addr.arpa" as usual

    // ROOT MASTER for internal DNS server
    zone "." IN {
        type master;
        file "/etc/bind/internal.root.zone";
        allow-transfer { none; };
        allow-query    { none; };
    };
    // NO root zone, type hint definition!

    // EXWORKS ZONES
    zone "exworks" IN {
        type master;
        file "/etc/bind/exworks.zone";
        allow-transfer { 127.0.0.1; };
        allow-query    { 127.0.0.1; };
    };

    zone "72.168.192.in-addr.arpa" IN {
        type master;
        file "/etc/bind/exworks.rev";
        allow-transfer { 127.0.0.1; };
        allow-query    { 127.0.0.1; };
    };

The directory refers to a location inside the chrooted tree. The listen-on specifies that this name server should only listen on port 5353 on the internal address 127.0.0.1. The other two, recursion and fetch-glue, prevent resolving anything but the zones that were defined here.

The root zone is purely local, it is only for this name server. Therefore, the configuration does not allow queries and transfers.

The exworks and 72.168.192.in-addr.arpa zone definitions allow for internal zone transfers and queries, both specifically to the other name server running there (the visible one). No other transfers and queries are allowed for these zones.

Configuring the visible name server

This section will describe how to configure the visible name server (if in doubt read the section called “Two name servers on one host” again). Remember it does not run chrooted and listens on a normal port. Instead, it runs under its own UID/GID.

The visible name server should be able to answer queries about both the inside and the outside worlds.

Note

The visible name server on liongate could use forwarding to connect to the internal name server if the software allowed you to specify a port.

The named.conf for the visible name server, with common parts omitted, looks like this:

    // /etc/bind/named.conf
    // bind visible configuration on liongate

    options {
        directory "/var/cache/bindVisible";

        // point to the ISP's name server for outside world
        forwarders {
            224.121.121.99; // ISP's DNS
        };
    };

    // NOT SHOWN HERE, described elsewhere:
    // - logging as usual
    // - root zone type hint as usual
    // - zones "localhost", "127.in-addr.arpa", "0.in-addr.arpa" and
    //   "255.in-addr.arpa" as usual

    // point to port 5353 for these zones, be slave for both
    zone "exworks" IN {
         type slave;
         masters port 5353 { 127.0.0.1; };
         file "exworks.slave";
         allow-transfer { none; };
         allow-query    { 127.0.0.1; 192.168.72.0/24; };
    };

    zone "72.168.192.in-addr.arpa" IN {
         type slave;
         masters port 5353 { 127.0.0.1; };
         file "72.168.192.in-addr.arpa.slave";
         allow-transfer { none; };
         allow-query    { 127.0.0.1; 192.168.72.0/24; };
    };

This implements the following:

  • a name server that performs slave resolving for the exworks and 72.168.192.in-addr.arpa zones

  • forwarding to resolve names from the outside world

The directory specified by the directory statement must be writable by the running name server. That is, if the name server is running as user vnamed and group vnamed, the directory /var/cache/bindVisible must be owned by user vnamed and group vnamed. The slave files exworks.slave and 72.168.192.in-addr.arpa.slave will be put there.

Let's look at the slave zone definitions. Both refer to a master at port 5353 on the same host. Both definitions do not allow full zone transfers. The only zone transfers are from master (at port 5353) to slave (the configuration for the master allows this, see the section called “Configuring the master on privdns). Normal queries are allowed for the localhost (127.0.0.1, i.e., internal connections on liongate), as well as all hosts in the exworks zone (192.168.72.x).

On liongate the resolv.conf file will contain

    nameserver 127.0.0.1

that is, it points to the visible name server which listens on port 53. Other hosts in the exworks domain will have

    nameserver 192.168.72.1

(the IP address of liongate) in their resolv.conf.

Note

It is not possible to specify a portnumber in resolv.conf. The specified name server(s) will be contacted at port 53.

A problem

There is one problem with this scheme that results in extra maintenance. Normally, a master name server sends a notify to a slave name server when a zone definition changes. But there is no way to tell a name server that there are two name servers listening at the same IP addresses on different ports. In fact, the also-notify statement cannot contain port information.

There is a simple solution to this problem. After a master zone is changed, and the internal name server has reloaded the zone data, the visible name server has to be be restarted manually.

Copyright Snow B.V. The Netherlands