Setting up DNS in Small Subnets

If you try to run an authoritative DNS server for a small network, such as a /26 (which contains only 2(32-26)=64 addresses), you'll run into a big problem: there's no easy way to specify which of the 256 addresses in your Class C network belong to you and which belong to someone else. This is because BIND, the software that handles your DNS, can only handle addresses that end on a byte boundary. Getting things to work correctly in this situation involves choosing among a variety of messy solutions.

If you're planning to run a name server, you absolutely need the book DNS and BIND by Paul Albitz and Cricket Liu. It's the bible for people who administer name servers. This article is just a refresher course. See also linuxsetup26.html for details about setting up BIND.

Please do not use the IP addresses or hostnames shown on this page in your own configuration. You must substitute your own IP addresses and hostnames or it will not work.

Overview of DNS and BIND

First, let's review how DNS works. We'll assume you're using BIND 9, but the procedure for configuring BIND 8 is almost identical. We'll also assume you want your server to be the authoritative server for the domain. This means that all the other servers will get their DNS records about your domain from you. Obviously if these records are wrong, no one will be able to find you. On the other hand, if you're just running a local caching server that is not known to the entire Internet, and someone else handles your DNS, it doesn't much matter.

The main file for BIND is /etc/named.conf. This file is basically a list of "zones" and "zone files". Here's a complete named.conf for a simple network with domain and one block of addresses:
  zone "." {
          type hint;
          file "db.cache";
  };
  zone "0.0.127.in-addr.arpa" {
	  type master;
	  file "db.127.0.0";
	  allow-update { none; };
  };
  zone "weinerschnitzel.org" {
	  type master;
	  file "db.mittlenkampf";
	  allow-update { any; };
	  allow-transfer { any; };
	  allow-query { "any"; };
	  notify yes;
  };
  zone "111.111.11.in-addr.arpa" {
	  type master;
	  file "db.11.111.111";
	  allow-update { any; };
	  allow-transfer { any; };
	  allow-query { "any"; };
  };
In this example, we have a subnet mask of 255.255.255.192 (which is a /26 because the first 26 bits in the mask are 1's). The network's name is therefore 11.111.111.192/26. Our host names have addresses between 11.111.111.193 and 11.111.111.254. The last IP number, 11.111.111.255, can't be used because it's the broadcast address. So there are actually only 62 usable addresses.

There is a forward zone called "weinerschnitzel.org" and a reverse zone called "111.111.11.in-addr.arpa". These zone names aren't arbitrary. You have to obtain the in-addr.arpa zones from your ISP, who gave you a block of IP addresses back when you gave them all that nice money to get you online, and you need to purchase the domains for the forward zones (such as weinerschnitzel.org) from a domain name vendor (who has the rest of your money). The software (BIND) has to match the zone name exactly in order to do lookups. It can't do anything fancy, like checking subnet masks. All BIND can do is concatenate parts of an address with each other. This is what causes the problem with small networks.

The forward lookups for the domain weinerschnitzel.org use the file /var/named/db.weinerschnitzel. This file consists of a header
Note: Please do not use these hostnames or IP numbers in your own configuration.
  $TTL 21600
@   IN  SOA   malaria.weinerschnitzel.org.  hostmaster.weinerschnitzel.org. (
                      00000005        ; Serial Number (not a date)
                      21600   ; Refresh every 6 hours
                      3600    ; Retry every hour
                      1728000 ; Expire every 20 days
                      21600 ) ; Minimum 6 hours
        IN    NS      malaria.mittlenkampf.org.
        IN    MX      10 engram.mittlenkampf.org.
        IN    A       11.111.111.236
;
followed by a list of "A" and "CNAME" records
  entropy         IN      A       11.111.111.236
  diphtheria      IN      A       11.111.111.237
  www             IN      CNAME   diphtheria
  nimrod          IN      A       11.111.111.238
  hotrod          IN      A       11.111.111.239
  goldenrod       IN      A       11.111.111.240
Notice that the authoritative server does not need to be part of the domain that it serves information about. In fact, usually it's on a different domain because that makes it easier to connect to it when it stops working.

The header tells BIND the following information:

  1. The SOA or Start of Authority record means that the authoritative name server for this domain is malaria.weinerschnitzel.org. It also contains various timeout parameters to help it decide how long it should wait before giving out information to other servers.
  2. When you update the master zone file, you should increment the serial number. (This particular file is up to '5'). This will cause BIND to send messages to all the other servers to tell them that new authoritative information is available. They will then request a zone transfer from your server.
  3. The MX or mail records mean that engram.weinerschnitzel.org is the server that handles email for the domain.
  4. The NS or nameserver records point to other servers that also happen to be handling name resolution for the same domain.
  5. The A or address record tells BIND to substitute the IP address on the right for the hostname on the left. Once BIND gets an IP address, it stops looking and returns the information to the requester. The A record in the header means that weinerschnitzel.org itself is also a hostname, and that it's the same as the computer called entropy.weinerschnitzel.org.
  6. The CNAME or alias record tells BIND that the name (in this case "www.weinerschnitzel.org") is an alias for a different hostname (diphtheria.weinerschnitzel.org). When it matches a CNAME, BIND then starts over and looks up this new hostname.

Note that all the FQDNs end with a period. This is essential.

BIND handles this file by simply scanning for the hostname on the left and then substituting the IP address on the right. This means, for example, that a server can have as many names as you want, by mapping different names to the same IP address. This is great for confusing your users.

Mail Server Records

If a MX record points to a mail server, you need to make sure that the name is listed in the mail server's /etc/mail/local-host-names file, otherwise you'll get errors like
  MX list for weinerschnitzel.org. points back to entropy.brqimeister.org
  DSN: Local configuration error
when you try to send mail. This is not a DNS problem as it might appear, but is caused by sendmail being unaware that the computer it's running on has more than one name. (In this case, the computer is also on two different domains. Why? Don't ask.)

Reverse DNS lookups

The "reverse", or in-addr.arpa zone file is similar to the forward zone file. The main difference is that the IP addresses are on the left and the hostnames are on the right. BIND uses in-addr.arpa style addresses when it does reverse lookups. To make things easier for BIND, all the in-addr.arpa addresses are written with their bytes in reverse order. The bits within each byte are unchanged, however. Thus, if your IP address is 11.111.111.196, BIND will look for 196 in the 111.111.11.in-addr.arpa zonefile when it needs your hostname.
  193               IN      PTR     host193.weinerschnitzel.org.
  194               IN      PTR     mail.weinerschnitzel.org.
  195               IN      PTR     weinerschnitzel.org.
  196               IN      PTR     entropy.brqimeister.org.
The hostnames in an in-addr.arpa zone file are "pointer" or PTR records and must end with a period. BIND scans down the left column until it matches the last byte of the IP address, then substitutes the "pointee" or hostname for the address.

Normally, you already own your own domain name, having fought over it with some other company that happens to have the same initials as yours, or however you acquired it. If you're going to run an authoritative server, you need to get control of your addresses as well. These addresses are owned by your ISP, and this can't really be changed, because DNS lookups are always hierarchical. There's no way for other servers to find your server other than through the domain above yours, which means they must go through your ISP. But they are often happy to delegate the responsibility for your DNS to you, because this means they won't have to handle any more pesky requests from you to change your DNS.

Here's the procedure:

  1. Set up your name server on a local computer. It's obviously critical to make sure the forward and reverse lookup tables are in sync. Put your server's name in your /etc/resolv.conf file and test it for a couple days. Make sure the computer running BIND has a big battery-powered UPS. If this server goes down for a long enough time, it will take a long time for your information to propagate through the Internet again when it finally comes back up.

    An important tip: shut down the named daemon before editing your zone files, otherwise BIND will get mightily pissed and start sending you obscure error messages like this:
      journal rollforward failed: journal out of sync with zone 
    This error refers to the .jnl file in /var/named. If it's out of sync, the zone file won't load. To fix it, get rid of the .jnl file.

    Another tip is to check the zone files from time to time. BIND often mangles the zone files, adding hostnames that it gets from weird places like your DHCP server, and sorts them in a seemingly random order. This is highly undesirable, because it means your Windows users are editing your DNS table every time they boot up their computer. You will end up with multiple hostnames resolving to the same IP and your zone files will eventually become unmaintainable. To prevent dynamic updates, add the following to each zone entry in /etc/named.conf:
      allow-update { none; };
    (or omit it altogether, since the default is not to accept any dynamic DNS updates).

  2. Once your name server is set up and is resolving both forward and reverse hostname lookups correctly, contact your ISP and ask them to delegate the DNS for your IP addresses to you. It's necessary to state clearly what you want: you would like to become authoritative for your domain and run your own name server. ISPs often don't read customers' emails carefully. They may see the word "DNS" and immediately snap back a message saying something like, "Our fee for handling your DNS will be $50 per domain".

    Another problem is that they may delegate your DNS to you, and then forget that they already have another authoritative server somewhere that is still handing out addresses (which are now incorrect). This can create quite a mess.

    You have to ask the ISP nicely, because they sometimes can get uncooperative if they think you're being arrogant or if you seem not to be knowledgeable enough about computers. And there are some ISPs that have saved money by outsourcing all their technical staff and replacing them with people who don't know anything. If they ask you whether you'd like fries with that, that would be a clue.

  3. Finally, once you get your DNS delegation, go back to the domain name vendor's website and click on "Manage your Domain". Enter the FQDN of your new DNS server.

If your network is a full Class C (meaning you have 256 addresses), you're finished. Otherwise, your journey through DNS hell is just beginning. You're not afraid? You will be!

Small Sites

As I mentioned above, BIND doesn't do anything fancy with the bits in your IP address. DNS has no concept of subnets or "Classless Interdomain Routing" (CIDR), in which the division between the network address and host number can be at any point in your IP address, not just on a byte boundary as it was in the good old days.

To handle this, you need the cooperation of your ISP. You'll incur the wrath of the entire Internet if you start serving out addresses that are outside your address space. Each ISP has a different way of handling the situation of small address blocks. You need to do things their way.

One way is described in RFC 2317, "Classless IN-ADDR.ARPA Delegation". It uses a clever trick to send to your server only the addresses that belong to you.

To implement RFC 2317 routing, your ISP sets up a special IN-ADDR.ARPA file that consists entirely of a header plus "alias" or CNAME records like this:
192-255.111.111.11.in-addr.arpa  IN  NS    malaria.weinerschnitzel.org.
193.111.111.11.in-addr.arpa  IN  CNAME 193.192-255.111.111.11.in-addr.arpa.
194.111.111.11.in-addr.arpa  IN  CNAME 194.192-255.111.111.11.in-addr.arpa.
195.111.111.11.in-addr.arpa  IN  CNAME 195.192-255.111.111.11.in-addr.arpa.
BIND will see this mess when it tries to do a reverse lookup. If it matches host 194, for example, it discovers that the address is nothing more than an alias for host 194 at a weird-looking domain called 192-255.111.111.11.in-addr.arpa. Since this is not a bona fide domain, BIND starts looking for a name server that handles this new domain. It doesn't have to look far--we have conveniently provided its location in the NS record at the top. This request will wind up at the 192-255.111.111.11.in-addr.arpa name server (in this case, malaria) run by the customer that runs the (192-255) subnet. Because it's a bogus name, this particular domain name is actually meaningless to the Internet. We could have called it "Fritz", and it would still probably work, as long as your named.conf had a zone named "fritz". But following convention is important, if only to make life easier for your successor.

Even though 192-255.111.111.11.in-addr.arpa is not a legitimate IN-ADDR.ARPA domain name, most recent versions of BIND will still do the right thing and look up the zone at the name server specified in the NS record. In this way, the ISP can send some of the reverse lookups to you, and the rest to its other customers who use other parts of the same Class C network.

At your local server, you would simply add a new zone in your /etc/named.conf file like this:
  zone "192-255.111.111.11.in-addr.arpa" {
	type master;
	file "db.11.111.111.192-255";
	allow-update { none; };
	allow-transfer { any; };
	allow-query { "any"; };
 };
The file /var/named/db.11.111.111.192-255 would be identical to a normal zone file (as described above), except for the fact that the zone name is different. (Unlike zone names, the filenames are arbitrary. We could also have named this file "Fritz" if we wanted to. But calling everything "Fritz" creates problems of its own.)

Caveats

There is no guarantee that your ISP will agree to handle things this way. Some ISPs use a different naming convention that involves setting up a zone with too many numbers, like this:
  zone "192.111.111.11.in-addr.arpa"
In this scheme, just as in the previous scheme, your zone files are unchanged. When you do reverse lookups, you get weird-looking results:
  $ host 11.111.111.236
236.111.111.11.IN-ADDR.ARPA is a nickname for 236.192.111.111.11.IN-ADDR.ARPA
236.192.111.111.11.IN-ADDR.ARPA domain name pointer entropy.weinerschnitzel.org
Notice that there are five numbers in the IP address, which means it's not a valid IN-ADDR.ARPA address. It may be ugly, but somehow it resolves correctly, and that's all that counts.

It's necessary to ask the ISP what their policy is for handling the small network situation. Most of them will probably use some variation of this method; or they may refuse to delegate to small networks altogether. But they should at least be aware of the issue, and shouldn't let you set up a server that answers to the whole Class C. If your ISP acts like they don't know what you're talking about when you ask them, it may be time to find a new one.


Back