Saturday, 3 November 2007

DHCP and Dynamic DNS on Ubuntu Server

The cunning plan

I have broadband Internet at home and to connect to the outside world I use a Wi-Fi ADSL router. This router also acts as a DHCP and DNS server. The DHCP function is what allows any machine I connect to my home network to dynamically obtain an IP address. The DNS function is what resolves names into IP addresses, for example, the DNS will tell you that www.blogger.com is really called blogger.l.google.com and its address is 72.14.221.191. This is all well and good: when I switch on one of my computers and let it connect to the network, it will get its IP address from the router, which will also tell it to use the same router for names service queries. The router itself knows to delegate requests to my ISP's DNS so the new computer on the network has full access to the Internet. If I connect a second computer on the network, the same happens and both can have access to the Internet at the same time. Great! However, they don't know anything about each other. If I connect the two machines called nuuk and helsinki to my network, the DNS server is unable to tell either what the address of the other one is. This is because the DNS in the router is fairly basic and doesn't know to update its database when a new machine gets allocated an address by the DHCP service. Basically, we'd want a DHCP server that can communicate with the DNS server and tell it oy, I've got a new machine on the network, here's its name and the address I just allocated to it when a new machine comes online.

So what's a geek to do? Set up his own DHCP and DNS server obviously! And make them talk together. Luckily, I have an old workstation that I haven't used for many years and that I was planning to throw away: it's a bit dated but it should be exactly what I need for this. Then my recent experience with Ubuntu suggests that the recently released Ubuntu 7.10 Gutsy Gibbon Server Edition might be exactly what I need for the job. So let's get started.

The hardware

I said I had this dated workstation lying around. It's an 8 year old piece of kit that was originally built to run Red Hat Linux. It wasn't very good at it at the time because Linux was not quite ready for the desktop at the time but it was a wicked piece of kit at the time:

CPU
Dual 666 MHz Pentium III (Coppermine)
Memory
256 Mb
Storage
10 Gb SCSI hard disk: I got a SCSI controller rather than the cheaper IDE because I wanted to connect my SCSI negative scanner to it

There's plenty of horsepower for what we want to do, more than enough storage and the memory should be fine if the operating system we install on it is lightweight enough. This is where the Server Edition of Ubuntu comes into play: it's meant for server hardware and doesn't have the nice but memory hungry desktop front-end, it's all command line driven. No glitz, just useful stuff. This means that even the latest version of Ubuntu Server should be able to run comfortably within 256 Mb and there should be no need to fall back on an older version of the operating system.

Preparation

Before we start, there is a bit of planning to do. As the new server will be the authority in terms of assigning IP addresses on the network, it needs to have its own address fixed. We also need to decide on a range of addresses to allocate through DHCP. As the router is currently using the address 192.168.1.254, it makes sense to leave it as it is. Here is the network configuration I am aiming for:

ADSL router
192.168.1.254
New DHCP and DNS server
192.168.1.253 and I'll call it szczecin
DHCP address range
From 192.168.1.100 to 192.168.1.200
Domain name
home: no need to have an official domain name and in fact it's probably better if it's not something that could be a valid Internet domain

One thing I did before installing anything and that you may want to do as well is boot the new server with the desktop Ubuntu Live CD just to check that all the hardware is supported. The server edition is not a live CD so it doesn't give you the opportunity to check that before going ahead.

Installing Ubuntu

Let's plug everything together first: a monitor, a keyboard, no need for a mouse as it's all command line, power and VGA cables. And we might as well connect it to the network immediately so we'll need a network cable as well.

Start the machine, put the CD in the drive and follow the instructions. As usual with Ubuntu, it's quite easy. There are only a few things to be careful about:

  • When it asks how to partition the disk, choose the automatic option using the whole disk.
  • When it gets to network setup, cancel the DHCP client setup and configure the network manually. Give it the IP address chosen above and a name. When it asks for a DNS server, put its own address.
  • Don't forget to select DNS in the list of additional services you want to install. I would suggest you also install the SSH server to that you can connect to the machine remotely.

At the end of the installation, the machine pops the CD out and asks you to confirm a restart. No nice funky Ubuntu logo when it restarts, it's all text and you are faced with a command line login prompt. If you want to keep working from the console you can, or you can just connect from any other machine connected to the same network using SSH, provided you installed the SSH server obviously. So let's login to our new server.

Configuring a simple static DNS

The first step is to configure a simple static DNS service that is able to resolve names for the router and the new server. Ubuntu 7.10 comes with BIND 9.4.1 as a DNS server and I have used O'Reilly's DNS and BIND book as my reference. The copy I have is the 3rd edition rather than the 5th but it is more than adequate for my purpose.

The very first task is to make sure we have the necessary basics in /etc/hosts:

127.0.0.1       localhost
192.168.1.253   szczecin.home szczecin
192.168.1.254   gateway.home  gateway

Then we need to reproduce that in the BIND configuration. The first task is to find where the BIND configuration files are. On Ubuntu, you will find them in /etc/bind with a modular default set of files:

$ ls /etc/bind
db.0
db.127
db.255
db.empty
db.local
db.root
named.conf
named.conf.local
named.conf.options
rndc.key
zones.rfc1918

The main file, named.conf is constructed in such a way that for most simple installations, you should only have to change named.conf.local, which is exactly what we are going to do. But first, we need to create our database files. Let's start with the forward lookup, which we will name db.home

home.           IN SOA  szczecin.home. admin.email.address. (
                                1          ; serial
                                10800      ; refresh (3 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
home.           IN NS   szczecin.home.

localhost.home. IN A    127.0.0.1

szczecin.home.  IN A    192.168.1.253
gateway.home.   IN A    192.168.1.254

The first entry specifies the Start Of Authority, identifying that our server is the best source of information for this zone. The admin.email.address. bit can be any admin email address you want to advertise, with the @ sign replaced by a dot. It doesn't have to be a valid address if you don't want it to be. The second entry identifies this machine as the name server for this zone. If you had multiple servers, you'd need one line per server. The following lines reflect what we have in /etc/hosts.

After that, we can work on the reverse lookup file, which will be named db.192.168.1:

1.168.192.in-addr.arpa.     IN SOA  szczecin.home. admin.email.address. (
                                1          ; serial
                                10800      ; refresh (3 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
1.168.192.in-addr.arpa.     IN NS   szczecin.home.

253.1.168.192.in-addr.arpa. IN PTR  szczecin.home.
254.1.168.192.in-addr.arpa. IN PTR  gateway.home.

This file just defines the opposite mapping. The first two entries follow the same format that in the other file. Note how the IP addresses are back to front. The last two entries use the PTR record type rather than the A record type. We now need to declare those two database files in the BIND configuration. To do this, we just add the following to the end of the named.conf.local file:

zone "home" in {
        type master;
        file "/etc/bind/db.home";
};

zone "1.168.192.in-addr.arpa" in {
        type master;
        file "/etc/bind/db.192.168.1";
};

Note the semi-colons all over the place in the file, BIND doesn't like it if you forget them. We just need to restart the DNS for it to pick up the configuration:

$ sudo /etc/init.d/bind9 restart

If it doesn't start properly, the best way to identify what's wrong is to go have a look at the system log files. On Ubuntu, the DNS messages will be in /var/log/daemon.log. One last thing to do before we test our setup is to update the local resolver configuration by modifying /etc/resolv.conf. Remove all lines that start nameserver so that the local resolver automatically sends requests to the local BIND instance irrespective of the IP address of the machine. We should end up with a file that contains a single line:

domain home

And we can now use nslookup to verify that it's all working:

$ nslookup szczecin
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   szczecin.home
Address: 192.168.1.253

$ nslookup szczecin.home
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   szczecin.home
Address: 192.168.1.253

$ nslookup gateway
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   gateway.home
Address: 192.168.1.254

$ nslookup localhost
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   localhost.home
Address: 127.0.0.1

Installing the DHCP server

My reference for installing the DHCP server was an excellent article aimed at the Debian distribution by Adam Trickett. As Ubuntu is based on Debian, I didn't have much to change. In its default state, an Ubuntu installation doesn't include a DHCP server so we need to add it:

$ sudo apt-get install dhcp3-server

This will install the ISC DHCP server. It will ask you to insert the Ubuntu CD in the drive so just do so. It will then attempt to start the new DHCP server and fail saying that the configuration is incorrect, which is to be expected. Configuration files for this server can be found in /etc/dhcp3 and the one we are interested in is dhcpd.conf. Move the default version out of the way by renaming it and we will start anew with an empty file. Here is what I have on my system, based on Adam's article. I highlighted the lines that tell the DHCP server to update the DNS and what key file to use.

# Basic stuff to name the server and switch on updating
server-identifier       192.168.1.253;
ddns-updates            on;
ddns-update-style       interim;
ddns-domainname         "home.";
ddns-rev-domainname     "in-addr.arpa.";
# Ignore Windows FQDN updates
ignore                  client-updates;

# Include the key so that DHCP can authenticate itself to BIND9
include                 "/etc/bind/rndc.key";

# This is the communication zone
zone home. {
        primary 127.0.0.1;
        key rndc-key;
}

# Normal DHCP stuff
option domain-name              "home.";
option domain-name-servers      192.168.1.253;
option ip-forwarding            off;

default-lease-time              600;
max-lease-time                  7200;

# Tell the server it is authoritative on that subnet (essential)
authoritative;

subnet 192.168.1.0 netmask 255.255.255.0 {
        range                           192.168.1.100 192.168.1.200;
        option broadcast-address        192.168.1.255;
        option routers                  192.168.1.254;
        allow                           unknown-clients;

        zone 1.168.192.in-addr.arpa. {
                primary 192.168.1.253;
                key "rndc-key";
        }

        zone localdomain. {
                primary 192.168.1.253;
                key "rndc-key";
        }
}

Now that we've done that, we need to modify the DNS configuration so that it can accept the changes. But first, a quick note on the /etc/bind/rndc.key file. This file is automatically created when you install DNS on Ubuntu and should be fine for your installation. It is a key file that authenticates the DHCP server to the DNS server so that only the DHCP server is allowed to send updates. You don't want random people to be able to update your DNS database. Having said that, we need to modify the DNS configuration to accept the updates so back to /etc/bind. And while we are at it, let's have a look at this key file.

key "rndc-key" {
        algorithm hmac-md5;
        secret "some base 64 encoded secret key";
};

Note the name of the key on the first line, it may vary from one distribution to another so make a note of it. Then we need to add the control information to the DNS configuration. Rather than update named.conf, I decided to add the relevant code to the end of named.conf.options: it feels like the right place to put it but I suspect it doesn't really matter. So add this to the end of the file:

// allow localhost to perform updates
controls {
        inet 127.0.0.1 allow { localhost; } keys { "rndc-key"; };
};

Then we need to modify the zone definitions in the named.conf.local file. Here is what it looks like with changes highlighted:

zone "home" in {
        type master;
        file "/etc/bind/db.home";
        allow-update { key "rndc-key"; };
        notify yes;
};

zone "1.168.192.in-addr.arpa" in {
        type master;
        file "/etc/bind/db.192.168.1";
        allow-update { key "rndc-key"; };
        notify yes;
};

include "/etc/bind/rndc.key";

We're nearly there. The changes we just made mean two things: the DNS server needs to be able to update the content of the /etc/bind directory and the DHCP server needs to be able to read the key file /etc/bind/rndc.key. By default on Ubuntu, this won't work as the permissions around those files are fairly stringent. So let's change them. As the BIND configuration directory belongs to root:bind, we just need to give write access to the group for BIND to be able to write to it. To give the DHCP server access to the key file, the right thing to do would be to add the dhcpd user to the bind group but we can also make the file readable to everybody. Yes this is less secure but will be fine for a home installation.

$ sudo chmod g+w /etc/bind

$ sudo chmod +r /etc/bind/rndc.key

Now we just need to start DHCP and restart DNS.

$ sudo /etc/init.d/dhcp3-server start

$ sudo /etc/init.d/bind9 restart

Error messages will be in the same place as before if the services don't start properly. If all starts as exected, it's now time to go to the administration interface of the router and disable DHCP. We should not need it anymore.

Booting the clients

The proof of the pudding is in the eating and the proof of installing a server is in starting a number of clients to use the service. The first machine I tried with was my Ubuntu laptop called nuuk. To see what happens, tail the log file. You should see something like the following appear:

Nov  3 15:14:02 szczecin dhcpd: DHCPDISCOVER from 00:12:f0:1e:f4:79 via eth0
Nov  3 15:14:03 szczecin dhcpd: DHCPOFFER on 192.168.1.102 to 00:12:f0:1e:f4:79
(nuuk) via eth0
Nov  3 15:14:03 szczecin named[4771]: client 127.0.0.1#32773: updating zone
'home/IN': adding an RR at 'nuuk.home' A
Nov  3 15:14:03 szczecin named[4771]: client 127.0.0.1#32773: updating zone
'home/IN': adding an RR at 'nuuk.home' TXT
Nov  3 15:14:03 szczecin dhcpd: Added new forward map from nuuk.home. to
192.168.1.102
Nov  3 15:14:03 szczecin named[4771]: client 192.168.1.253#32773: updating zone
'1.168.192.in-addr.arpa/IN': deleting rrset at '102.1.168.192.in-addr.arpa' PTR
Nov  3 15:14:03 szczecin named[4771]: client 192.168.1.253#32773: updating zone
'1.168.192.in-addr.arpa/IN': adding an RR at '102.1.168.192.in-addr.arpa' PTR
Nov  3 15:14:03 szczecin dhcpd: added reverse map from 102.1.168.192.in-addr.arpa.
to nuuk.home.
Nov  3 15:14:03 szczecin dhcpd: Wrote 4 leases to leases file.
Nov  3 15:14:03 szczecin dhcpd: DHCPREQUEST for 192.168.1.102 (192.168.1.253) from
00:12:f0:1e:f4:79 (nuuk) via eth0
Nov  3 15:14:03 szczecin dhcpd: DHCPACK on 192.168.1.102 to 00:12:f0:1e:f4:79 (nuuk)
via eth0

If you don't see the message about updating the forward and reverse maps, it may be that your client machine is not configured to send its name to the DHCP server. For this to work on Ubuntu, you should have the following line in /etc/dhcp3/dhclient.conf:

send host-name "<hostname>";

Next on the list is my Apple PowerMac G5 called helsinki. A simple restart and it works like a charm: I can ping hesinki from nuuk or szczecin and the other way round, all machines can access the Internet, great! While we're talking about computer names, if you don't know how to change the machine's name under OS-X, here's how.

The next test is with my work's Windows XP laptop. All goes well: the Windows box gets an IP address and I can ping it from the other machines. However, I can't ping from the Windows box to the other ones unless I use the fully qualified domain name: that is I can ping nuuk.home but not nuuk. It looks like Windows ignores the domain information sent by DHCP. This is not a major problem as everything else works fine. I vaguely remember something about network settings on Windows that you have to change but. I'll have a look see if I can remember where it was when I can.

The final test is to start my Solaris Express laptop called mariehamn. It gets its IP address fine but doesn't seem to send its name to the server. So it can't be pinged. Everything else works though: it can ping all of the other machines, get to the Internet, etc. I suspect I need to find the equivalent of the /etc/dhcp3/dhclient.conf file on Solaris and change it so that it sends its name. It's probably hidden somewhere in the Network Auto-Magic configuration.

Conclusion

That was a bit convoluted but the excellent resources that are the O'Reilly DNS and BIND book and Adam's article made it significantly easier. Real system administrators would say that was a doodle and made way too easy by Ubuntu. I've learnt useful stuff on the way and I now have a good use for this old workstation. Speaking of which, it hasn't really been breaking a sweat so far: it's been close to 100% idle all the time, it has 114Mb RAM free out of 256 and the hard disk has seen virtually no activity. In other words, my 8 year old box is over spec'ed for this and I could get it to do a lot more server tasks. Should I mention that the server version of some other recent operating systems that shall remain nameless would not even start on such a machine? No, I'll leave that debate for another day.

For those who are wondering what scheme I use to name my computers, it all comes from a previous job and all machines are named after cities of the world, with a Scandinavian and Baltic theme so far: Helsinki, Szczecin, Nuuk and Mariehamn.

Post a Comment