Simple DNS For Private LAN

Giorgos Keramidas keramida at ceid.upatras.gr
Wed Jun 28 14:44:10 UTC 2006


On 2006-06-23 14:26, Drew Tomlinson <drew at mykitchentable.net> wrote:
>> If you use NAT, then I can guide you through setting up a local
>> ``master zone'' that is only visible inside your home network, and a
>> ``slave zone'' that pulls stuff from ZoneEdit for the
>> ``mykitchentable.net'' domain.  I already have a similar setup at
>> home, to let my internal systems (workstation, laptop) see each other
>> with internal names and still use my ISP's name servers for
>> everything else.
>>
>> If you don't use NAT, things are going to be much easier, since you
>> only have to set up the names at ZoneEdit and pull the master zone
>> from there.
>
> Thank you for your reply.

You're welcome of course :-)

> I use NAT for my servers that are visible from the outside so I set
> ZoneEdit to return the same address for all servers at
> mykitchentable.net which is currently 67.137.238.101.

Excellent!  This is exactly what I was hoping the setup would be.

> Thus www.mykitchentable.net, drew.mykitchentable.net,
> mykitchentable.net, and whatever else. all return 67.137.238.101.
> Based up this, it seems that I should leave ZoneEdit alone and set up
> a local "master zone" visible only to my private LAN as you describe
> above.  Being a slave and pulling from ZoneEdit wouldn't have any
> benefit as the public address won't equal the private address.

Quite right.

> So assuming I understand correctly, yes, please guide me in setting up
> a local master zone.

Assuming that your local home network uses addresses in the
192.168.0.0/16 range, you have to set up a local name server which will
recognize and reply for the following zones:

    "drew."		# "*.drew" are local home network names
    192.168.0.*		# reverse IP address -> name for home hosts
    127.0.0.*           # localhost zone (optional)

Optionally, you can set up a 'slave' zone for the `mykitchentable.net'
hostnames, but this is not obligatory.

To set up the local nameserver for the local zones mentioned above, you
will need to modify (or create) at least the following files:

    /etc/namedb/named.conf
    /etc/namedb/master/drew
    /etc/namedb/master/drew.rev
    /etc/namedb/master/localhost.rev
    /etc/namedb/master/localhost-v6.rev
    /etc/rc.conf

After you finish setting up all these files, you should be able to:

    * Resolve hostnames of the form foo.drew to IP addresses of your
      internal home network.

    * Resolve IP addresses of your internal home network to hostnames of
      the form foo.drew.

    * Resolve `localhost' to your 127.0.0.1 address (and its IPv6
      equivalent).

    * Check your new named setup and see that it works as expected

    * Troubleshoot your setup, i.e. tweak the logging level of named and
      find out what it logs through syslog

1. Setting up named.conf
************************

The `named.conf' file is the one BIND reads to find out which `zones' to
load (a `zone' is BIND terminology for what you may have heard being
called a `domain').

The FreeBSD source tree contains a sample `named.conf' file at
`/usr/src/etc/namedb/named.conf', which normally gets installed as
`/etc/namedb/named.conf' on your system.  This file is not used, until
you decide to enable the `named' daemon though.

The sample file installed as `/etc/namedb/named.conf' includes several
commented parts that you can use as examples for writing your own
`named.conf' file.

After you have finished writing your own `named.conf' file it should
contain:

    * An `options' section, with global options that apply to the way
      your `named' service works.

    * Optionally, a `logging' section, with the configuration options
      that define what is logged, where it is logged, etc.

    * A `root' zone entry, which points to the root DNS servers.  An up
      to date list is distributed with the FreeBSD source tree, and can
      be found at `/usr/src/etc/namedb/named.root'.

    * Optionally, a `localhost' zone entry (for resolving 127.0.0.1 to a
      hostname of your choise).

    * Optionally, a `localhost-v6' zone entry (for resolving the IPv6
      equivalent of 127.0.0.1 to a hostname of your choise).

    * A zone entry for your internal, home network.

1.1. Global `options' for `named.conf'
======================================

The `options' section of your `named.conf' file defines stuff that tunes
global parameters of the `named' service.  After removing the stuff that
is commented out or an example, the `options' section of the default
`named.conf' file looks like this:

    options {
            directory       "/etc/namedb";
            pid-file        "/var/run/named/pid";
            dump-file       "/var/dump/named_dump.db";
            statistics-file "/var/stats/named.stats";
            listen-on       { 127.0.0.1; };
    };

Most of these defaults should work just fine for a standalone `named'
server, but you will have to tweak a bit the `listen-on' option to make
it work in an internal, home network.  The default list of addresses
that your `named' server will listen on includes only 127.0.0.1 and this
will make it inaccessible to all the machines of your internal network
(i.e. all machines that have an 192.168.0.0/24 address).

To let all machines of your internal network query the `named' server
running on your FreeBSD system, you have to add the internal IP address
of the FreeBSD system to that list too, i.e.:

            listen-on       { 127.0.0.1; 192.168.0.2; };

    --------------------------------------------------------------------
    IMPORTANT NOTE: Be carerul not to miss the ';' semicolon after the
    second IP address.  If you do, then the bogus `listen-on' option
    will cause your `named' service to fail starting (but see section 4
    below, ``Troubleshooting named problems'', to see how you can track
    this sort of problem and fix it.
    --------------------------------------------------------------------

There are various other options that you can set in this section.

The most important is probably the `forwarders' list.  This can be used
to let your `named' process ask upstream DNS servers, like the ones your
ISP is probably already using, instead of going all the way to a root NS
for resolving host names and IP addresses.  This is quite often a good
idea, as it allows your local `named' process to take advantage of the
cache your ISP's DNS servers already have, speeding up DNS queries a
fair bit.

A typical `forwarders' section looks a lot like the `listen-on' list you
have already seen above, but this time it lists the IP addresses of the
remote servers instead of your own:

            forwarders       { 150.140.141.181; 150.140.141.182; };

This would let your `named' service ask the upstream DNS servers at
150.140.141.181 and 150.140.141.182 for hostnames it cannot resolve
locally.

1.2. Setting up a `logging' section
===================================

See section 4 further down for information about setting up a `logging'
section, and how you can read the log messages your `named' service will
write.

1.3. A `root zone' entry
========================

A `root zone' is a list of IP addresses for the DNS servers that are
called `root name servers'.  If you are not using forwaders, your
`named' service will have to query these root name servers for
information about the toplevel DNS domains (i.e. "com", "net", "edu",
"gr", "de", "fr", etc.)

An example root zone entry is part of `/usr/src/etc/namedb/named.conf'.
You can typically keep this unchanged:

    zone "." {
            type hint;
            file "named.root";
    };

This entry points `named' at the file `named.root' at the directory that
is defined as the default directory in your `options' section.  Since
the default directory is set to `/etc/namedb', this entry refers to the
file `/etc/namedb/named.root'.

Normally, you shouldn't have to edit this entry in `named.conf' or the
`named.root' file.  Only change these two if you are *VERY* sure about
what you are doing.

1.4. The `localhost' and `localhost-v6' local zones
===================================================

The default `named.conf' file that is distributed with FreeBSD includes
two zone entries that allow client-systems that ask your DNS server to
resolve the IP addresses of `localhost' for both IP and IPv6.  These
addresses are listed in the usual ``reverse-logic'' order that is used
for IP address -> hostname zones in `named.conf':

    zone "0.0.127.IN-ADDR.ARPA" {
            type master;
            file "master/localhost.rev";
    };

    // RFC 3152
    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"
    {
            type master;
            file "master/localhost-v6.rev";
    };

These two zone entries depend on two files in `/etc/namedb/master' to
work properly.  To make things easier for you, FreeBSD provides a shell
script that can auto-generate these files for you, guessing the proper
hostname and domain information from the current hostname of the system
(as reported by running the hostname(1) utility).  All you normally have
to do is to keep the entries shown above in your `named.conf' file and
then run the `make-localhost' script in `/etc/namedb':

    # cd /etc/namedb
    # sh make-localhost

Two new files should appear in `/etc/namedb/master' now:

    # cd /etc/namedb/master
    # ls -ld localhost*
    -rw-r--r--  1 root  wheel  - 431 Jun 26 07:56 localhost-v6.rev
    -rw-r--r--  1 root  wheel  - 431 Jun 26 07:56 localhost.rev

This should be all it takes.  You can manually check the contents of
these files and make changes to them, but it is probably a good idea to
keep them unchanged for now.  At least, until you know what the contents
of a ``zone file'' look like and what each part means, you should avoid
making manual changes to these files.

1.5. Zone entries for your internal, home network
=================================================

Now comes the interesting part.  You should also add to your
`named.conf' file a ``zone entry'' for your internal, home network.

This is not so difficult, but there are a few details that you should
get right and they are spread across at least three files:

    * The `named.conf' file, which contains the zone entries for mapping
      hostnames to addresses and for mapping addresses to hostnames.

    * A file under `/etc/namedb/master' that contains the actual
      information for mapping hostnames -> IP addresses.

    * A file under `/etc/namedb/master' that contains the actual
      information for mapping IP addresses -> hostnames.

1.5.1. Adding forward and reverse zone entries in `named.conf'
--------------------------------------------------------------

The changes that should be done to `named.conf' are related to the
following two types of hostname <=> address translations:

    * hostname of the form `*.drew' => internal home-network address

    * internal home network address => hostname of the form `*.drew'

For these two DNS query types, you will need two zone entries in
`named.conf' and two `zone files' in `/etc/namedb/master'.  The entries
in `named.conf' can be similar to:

    zone "drew." {
        type master;
        file "master/drew";
    };

    zone "0.168.192.in-addr.arpa." {
        type master;
        file "master/drew.rev";
    };

The important points to watch out for while writing these entries are:

    * The zone name is quoted with double-quote characters

    * The zone entries refer to files of the form "master/foo", where
      file `foo' maps to `/etc/namedb/master/foo'

    * There are two zone entries for the same set of systems, one to map
      hostnames of the form "*.drew" to IP addresses (the "drew." zone
      entry), and one to map IP addresses in the IP range 192.168.0.* to
      hostnames (the "0.168.192.in-addr.arpa." zone entry).

    * The IP range 192.168.0.* is spelled _backwards_ in the zone entry
      that maps it to a file and it has an "in-addr.arpa." suffix.

The two zone entries are commonly referred to as the `forward' and the
`reverse' zone:

    1. The `forward' zone is the one that maps hostnames to IP
       addresses.

    2. The `reverse' zone is the one that maps addresses of the form
       "0.0.168.192.in-addr.arpa.", "1.0.168.192.in-addr.arpa.",
       "2.0.168.192.in-addr.arpa.", "3.0.168.192.in-addr.arpa.",
       ... "255.0.168.192.in-addr.arpa." to a hostname.

You have to manually create the zone files for each one of these zones.
It's not too difficult, since you already have at least two sample zone
files to read as examples:

    /etc/namedb/master/localhost.rev
    /etc/namedb/master/localhost-v6.rev

By looking at these two files and reading the next paragraphs, you
should be able to create your own zone files too :-)

1.5.2. Creating a forward lookup zone
-------------------------------------

A ``forward lookup zone'' is an entry in `named.conf' that points the
local nameserver to a hostname -> address map.  The smallest zone entry
you will typically find in `named.conf' files looks like this:

    zone "drew." {
        type master;
        file "master/drew";
    };

After adding this zone entry in your `named.conf' you should also create
a file in `/etc/namedb/master' called `drew'.  This is the file that
will contain the `records' that map hostnames of the form "*.drew" to IP
addresses.  Semicolon characters `;' can be used to add comments to
these files.  The semicolon and everything else up to the next newline
character are ignored.

A small zone file can look like this:

    $TTL    3600
    
    @       IN      SOA     bsd.drew. hostmaster.bsd.drew.  (
                                    2006051501      ; Serial
                                    3600            ; Refresh
                                    900             ; Retry
                                    3600000         ; Expire
                                    3600 )          ; Minimum
    
                    IN      NS      bsd.drew.
    
                    IN      MX      5 bsd.drew.
                    IN      MX      10 linux.drew.
    
    localhost       IN      A       127.0.0.1
    
    bsd             IN      A       192.168.0.1
    linux           IN      A       192.168.0.2
    laptop          IN      A       192.168.0.3

The format of the ``zone files'' is described online too and in the
documentation of BIND[1], but I'll try to explain some of the more
tricky details.

    * The ``$TTL'' line sets the default time-to-live for the records
      that follow.  Setting the TTL to 3600 seconds, like above, means
      that other name-servers that query your own name-server will ask
      after 3600 seconds for a new copy of the records.

    * The '@' special record-name refers to the name of this zone, as it
      was defined in the `named.conf' file.

      In the case of the `/etc/namedb/master/drew' zone file, this is
      equal to "drew." -- as this the name of the zone recorded in
      `named.conf'.

    * The SOA record is a bit strange.  It defines far too many things
      in one record, but you can read more about each field at [bind9]

    * The MX records are optional.  You only need them if you plan to
      set up a local mail server that handles all outgoing email for
      your internal, home network.

    * Whenever a host name ends in a dot character `.', the currently
      defined name of the zone is _not_ appended to the host name.
      Adding the final dot means that you know what you are doing and
      that you refer to the host by its fully qualified name.

    * The most interesting records are the 'A' ones.  They define host
      names for systems in the "drew." zone.  The full name of the zone
      is not repeated as part of each line.  It is, rather, implied by
      the defined name of this zone (in `named.conf' as usual).

Whenever you make changes to this zone file, make ABSOLUTELY SURE that
you also update the `Serial' field in your SOA record.  Otherwise, other
name-servers will ignore yours and your own name server will not
necessarily reload the information of the zone file.

1.5.3. Creating a reverse lookup zone
-------------------------------------

A reverse lookup zone is very similar to a forward lookup zone.  The
most important difference from the standpoint of someone writing the
`named.conf' entry for this zone and the one writing the actual
`records' in the `/etc/namedb/master/foo.rev' file is that this zone
maps IP addresses to hostnames (reverse DNS lookup).

Typically, the reverse zones look like this in `named.conf':

    zone "0.168.192.in-addr.arpa." {
        type master;
        file "master/drew.rev";
    };

After adding this zone entry in your `named.conf' you should also create
a file in `/etc/namedb/master' called `drew.rev'.  This is the file that
will contain the `records' that map IP addresses like "192.160.0.*" to
hostnames.  Semicolon characters `;' can be used to add comments to
these files.  The semicolon and everything else up to the next newline
character are ignored.

A small zone file can look like this:

    $TTL    3600

    @       IN      SOA     bsd.drew. hostmaster.bsd.drew.  (
                                    2006051501      ; Serial
                                    3600            ; Refresh
                                    900             ; Retry
                                    3600000         ; Expire
                                    3600 )          ; Minimum

                    IN      NS      bsd.drew.

                    IN      MX      5 bsd.drew.
                    IN      MX      10 linux.drew.

    1               IN      PTR     bsd.drew.
    2               IN      PTR     linux.drew.
    3               IN      PTR     laptop.drew.

Note that this is *very* similar to the forward zone, except for a tiny
detail.  It contains `PTR' records instead of `A' (address) records.
The `PTR' records map numeric addresses to hostnames with the following
easy scheme:

    * The leftmost column of the `PTR' line is a number from 1 to 254.

    * This number (let's call it "NUM") is prepended to the `zone name'
      from `named.conf'.

    * The address "NUM.0.168.192.in-addr.arpa." resolves to the host
      name listed after the `PTR' text.

For example this line:

    1               IN      PTR     bsd.drew.

when it is present in the zone file for `0.168.192.in-addr.arpa.' maps
the address `1.0.168.192.in-addr.arpa.' to the hostname `bsd.drew.'.

Note the trailing dot in the last-column hostnames, to prevent named
from adding the current zone name as a suffix to the hostname.

Similarly, you can map 2.0.168.192.in-addr.arpa. to "linux.drew."
(as shown above), 3.0.168.192.in-addr.arpa. to "laptop.drew." etc.

Just keep in mind, that when you need to add a hostname for the IP
address `192.168.0.X', you can strip the trailing `.X' number, reverse
the parts of the IP address, append `.in-addr.arpa' and then you end up
with:

    0.168.192.in-addr.arpa.

This is the zone that you have to add a record for `X' and DNS will care
care of doing the mapping for lookups from `192.168.0.X' to
`X.0.168.192.in-addr.arpa.' for you.

2. Setting up your zone files in /etc/namedb/master
***************************************************

If you have read and understood everything so far, then you are ready to
set up zone files in your `/etc/namedb/master'.

Copy the sample zone files from above, modify them at will and save them
under `/etc/namedb/master' using the names configured at the "file"
options of the zone entries in `named.conf'.

Make sure that you do NOT confuse the `zone name', which is listed right
after the `zone' keyword in `named.conf':

    ==> zone "drew." {

and the `zone file name', which is listed as the argument of the `file'
option in the zone entry:

        zone "drew." {
            type master;
==>         file "master/drew";
        };

These are two separate things.

3. Enabling named in /etc/rc.conf
*********************************

With a fairly recent and up to date `/etc/rc.d/*' collection of startup
files, all you have to do to enable the named daemon is to add a simple
line in `/etc/rc.conf':

    named_enable='YES'

Then, you can start the `named' daemon by running as `root':

    kobe# /etc/rc.d/named start

If all goes well, you should be able to see the running daemon by using
ps(1), pgrep(1) or any other tool you find convenient.  The following
bash(1) command shows `named' running here:

    kobe# ps xau | { read head; echo "$head"; grep 'named '; }
    USER      PID %CPU %MEM   VSZ   RSS  TT  STAT STARTED      TIME COMMAND
    bind    12168  0.0  0.3  6124  3444  ??  Ss    1:06AM   0:00.05 /usr/sbin/named -t /var/named -u bind
    kobe#

If this didn't work, then read the following stuff about named logging
setup and try to find out what `named' writes to syslog.  This should
help you find out what went wrong.

4. Troubleshooting named problems
*********************************

Whenever you have any sort of problem with the `named' daemon, you
should first check /var/log/messages for any interesting information,
and then you may find it useful to tweak the logging level and output of
`named'.

The BIND nameserver that is included with FreeBSD supports an extremely
customizable logging mechanism.  Some may argue that logging is *too*
configurable, and thus ends up being confusing, but let's put this aside
for now :)

Logging is configured by modifying the `named.conf' file, and adding a
`logging' section.  There are several predefined `categories' of log
messages and some predefined `channels' where these messages can be sent
to be logged.  These are described in the official BIND
documentation[*], so I won't repeat them all here.

An example of how a `logging' section can be added to `named.conf' is
probably much easier to understand than reading through all the BIND
documentation for logging tips.  Here is what I use for the logging
section of the caching named daemon I run at home:

    logging {
        category default         { default_syslog; default_debug; };
        category security        { default_syslog; default_debug; };
        category xfer-in         { default_syslog; default_debug; };
        category xfer-out        { default_syslog; default_debug; };
        category notify          { default_syslog; default_debug; };
        category update          { default_syslog; default_debug; };
        category update-security { default_syslog; default_debug; };
        category lame-servers    { default_syslog; default_debug; };
    };

* NOTE: Watch out for missing semicolon `;' characters.  Forgetting to
  add one after the last entry in a { ... } block of named.conf or
  missing the trailing ';' character _after_ a block is one of the most
  common bugs in configuration files that fail to load.  This can be
  very annoying, especially if you have to spend several hours before
  you notice that there is just a tiny missing character that you can
  add to fix everything!

To use this logging section, you can simply copy it into your existing
`named.conf' file, right after the global `options' section and then
restart `named':

    kobe# /etc/rc.d/named restart
    Stopping named.
    Starting named.

If all has gone well, and you have no syntax errors in the logging
section you just added, something like the following should appear in
your `/var/log/messages' file:

    kobe# tail -3f /var/log/messages
    Jun 24 00:06:34 kobe named[12168]: starting BIND 9.3.2 -t /var/named -u bind
    Jun 24 00:06:34 kobe named[12168]: command channel listening on 127.0.0.1#953
    Jun 24 00:06:34 kobe named[12168]: running

Now just stand back and wait for any other messages from `named' that
point towards a configuration error or other problem.

5. Making the local nameserver the default
******************************************

Now you are ready to make your local nameserver the default server to be
contacted for DNS queries.  This is done by updating the
`/etc/resolv.conf' file to include something like this:

    $ cat /etc/resolv.conf 
    search drew.
    nameserver 127.0.0.1
    $

Now all DNS-using applications should use 127.0.0.1 for their queries.
Similarly, for other machines of the 192.168.0.X network, you should
configure a `resolv.conf' file like this:

    $ cat /etc/resolv.conf
    search drew.
    nameserver 192.168.0.1
    $

6. Checking your new BIND setup
*******************************

If your name server has started without problems, then you are ready to
test it.  You can use host(1), dig(1) and nslookup(1) for this.  You
should test that at least the following work correctly:

    * Lookup of hostname -> address

    * Lookup of address -> name

These are easy to do, if you keep in mind that your `name server' is now
127.0.0.1 (on the name server itself), or 192.168.0.1 (if you are using
"bsd.drew." as your DNS server):

1. Testing that 127.0.0.1 resolves correctly to `localhost.drew.'

    bsd# host 127.0.0.1 127.0.0.1
    1.0.0.127.in-addr.arpa domain name pointer localhost.drew.

2. Testing that `localhost.drew.' resolves correctly to `127.0.0.1'

    bsd# host localhost.drew.
    localhost.drew has address 127.0.0.1

3. Testing that `*.drew' resolve correctly:

    bsd# bash
    bash$ for hname in bsd linux laptop; do host "$hname"; done
    bsd.drew has address 192.168.0.1
    linux.drew has address 192.168.0.2
    laptop.drew has address 192.168.0.3

Useful BIND Resources
*********************

[1] Internet Systems Consortium, Inc. ``BIND 9 Administrator Reference Manual''.
    2000-2005.  http://www.isc.org/sw/bind/ , http://www.isc.org/sw/bind/arm93/ ,
    http://www.isc.org/sw/bind/arm93/Bv9ARM.ch06.html#id2564557


More information about the freebsd-questions mailing list