A Simple Dynamic DNS for Home Networks

This article explains how to provide a simple dynamic DNS for home networks, so that all Linux machines in the network can be addressed by name instead of by their IP addresses.

It's similar to http://smorgasbord.gavagai.nl/2011/08/homemade-dynamic-dns-service/ except that it works only for home networks without the need for external domain name.

Typical setup addressed by this article

A home network of computers, connected by one wired/wireless home router (perhaps also acting as a modem for Internet access), which also acts as DHCP server for all computers in the network.

What you will need:

Overview of what we will do

The Server

  1. Get a working dnsmasq package for the server.

  2. Preferably use a fixed (internal) IP address of the server, in the same subnet as the rest of the home network.

  3. Using either configuration file or command line parameter (config file is preferred), tell dnsmasq to:
  4. Create a few init script to start dnsmasq at boot time, using the correct config file (or parameters).

  5. Create a simple "server" to allow other machines to deposit or update a file into the server's /tmp/hosts. This can be anything; if you wish you can run a samba server (an overkill, but works); or run ssh/dropbear server, ftp server, web server with php/ruby/python/generic CGI, etc.

    For this article, however, I will just use busybox' version of netcat (nc) to do the job - it will listen to a specified port and execute a shell script when something connects to that port (=a poor man's inetd). The script reads a line that contains an action, password, hostname and IP address. If the password matches, the script will create/update/delete a hostfile entry in /tmp/hosts depending on the action.

  6. Dnsmasq doesn't automatically reload the files in the /tmp/hosts if they change. You have to send SIGHUP to dnsmasq to tell it to re-load its configuration files including re-reading /tmp/hosts. But that's not a problem, we can either setup a inotify watch on the directory and sends SIGHUP to dnsmasq when it changes; or you can immediately send SIGHUP from the script that nc executes after it updates /tmp/hosts (this is what I do).

The Client

All that the clients (ie the other computers) need to do is to watch for changes in its IP address (and hostname too, but hostname rarely changes so I don't even bother here); usually because it gets a new lease, but may be for other reasons too. As soon as it detects that the IP address has changed, contact the server to tell it of its new address.

For this article - matching the simple server - to do the update is very simple as well: just use nc again to contact the server's nc to push the details. In fact, if bash is your shell, you don't even need nc here - you can send the command just by echo-ing to bash's virtual /dev/tcp/host/port.

To detect the IP address change, the easiest to use "ip monitor" command, available from iproute2 package (unfortunately busybox' ip command has not yet supported the "monitor" sub-command). But this package isn't included in Fatdog64 or Puppy, so instead I've adapted a simple C client (ipmon.c) that uses netlink to detect the changes and output the new IP address to stdout. It should be straightforward to change the script to use ip monitor instead, if you wish.

The Modem/Router

To glue all these together, we need to instruct the DHCP server on the home router to hand out our dnsmasq server as the DNS IP address, instead of the original modem/router/ISP DNS IP address (that's the reason why the dnsmasq server IP address should be fixed). This can usually be done through the modem/router's configuration page.

If this is not possible, then we'll just have to modify the dhcp script which updates /etc/resolv.conf on the client machines to use our dnsmasq server IP address instead of using one obtained from DHCP server.

If this is still too difficult, then one can use inotify to watch /etc/resolv.conf and as soon as the file is changed (by DHCP client presumably), override it again with our dnsmasq server address.

As a precaution, ensure that you put two nameserver entries in /etc/resolv.conf - the first one (which will have priority) is the dnsmasq server; and the second one is a upstream DNS server (your modem's, your ISP's, Google's, OpenDNS's, etc) which will be used if the first nameserver can't be contacted.

This ensures that your network can still access the Internet even when your dnsmasq server is down for whatever reason.

Download

The tarball contains dnsmasq configuration and scripts for server setup, scripts for client setup, ipmon.c, statically-compiled ipmon for x86-64 (Fatdog64) and ARMv6 (FatdogArm).

Get it here.

Note: If you choose not to use nc as the update mechanism, you can uncomment watch_hostdir in the server's init script so that changes to /tmp/hosts are automatically applied (this requires busybox' inotifyd).

Comparison with other methods

  1. mDNS (multicast DNS/nss-mdns/Bonjour/Avahi)

    Works, and works better than the method outlined here, but it requires a special DNS resolver (nss-mdns) and a daemon to respond to the mdns requests. The typical daemons are Bonjour and Avahi; both of these have larger scope and just doing DNS resolution (they also do for service advertisement and discovery). All machines must run one of these to participate.

    With the method of the article, a machine which doesn't run the "client" setup can still participate - it can still contacts other machines by normal DNS resolution (this is especially true if the modem/router can be configured to hand out dnsmasq server IP address during DHCP negotiation); although it itself isn't contactable.

  2. http://smorgasbord.gavagai.nl/2011/08/homemade-dynamic-dns-service/

    The idea is the same (in fact, the above site is where I get the inspiration from), only the implementation is different. The above site uses sheerdns as the DNS server (instead of dnsmasq), and uses Apache/Python/PHP for the 'client' setup to update the name server.

    Sheerdns is an authoritative server, not a caching nameserver; so to run it you need a fully-qualified domain over which you have been delegated as its authority. It's good if the scope is the Internet (you can use it just like a proper dynamic DNS service like no-ip.org, dyndns.org, etc).

    The idea of contacting an URL managed with a wildcard CNAME is clever (contacting the URL http://kitten.reg-a-record.tld/reg.php will create a DNS entry for "kitten" with the caller's IP address - no form filling is necessary), but it requires a heavier infrastructure (at least a web server with CGI). The benefit is, since it uses HTTP, it works with all sorts of clients, not only desktops (it also works smartphones, etc).

Concluding remarks and notes

You can achieve the same thing with even less work if you disable your router's DHCP server altogether, and instead run dnsmasq as both your DHCP (and caching DNS) server.

Dnsmasq can provide DNS resolution to hostnames it receives through DHCP requests - so as soon as a machine in the network is started and it asks for an IP address (and declare its preferred hostname); dnsmasq will allocate the IP address for that machine and automagically map that hostname to this IP address for later DNS resolution requests. No other server/clients are necessary: dnsmasq is your server and your DHCP client is your client.

Security Notes

This, by its very mechanism, is not secure. The hostname is provided by the 'client' machine, the IP address is also provided by the 'client' machine, it is easy for a client machine to create multiple entries and spoof names of other client machines to point them to itself.

Use this only in a closed network where the participating machines are not hostile.