July 30, 2010

Weekend Project: Cache Local DNS Queries

 

There are few additions to your network that will make as immediate of a performance boost as setting up a caching DNS server. Every computer on the local segment of your network makes hundreds -- if not thousands -- of DNS queries, and if you forward each one of them to a server on the other side of your WAN pipe, you are just throwing away bandwidth. Not only is caching DNS services simple to set up, you even have multiple options for doing so under Linux.

As always, picking the best approach starts with looking at your local network configuration. If you only have one box to worry about, you can install a caching DNS server on that box that intercepts all queries before they even reach the network adapter. If you have multiple machines, you can install the DNS server at the gateway, and share one cache between all of the machines, further speeding up name resolution.  Furthermore, if the gateway machine is also a dynamic host configuration protocol (DHCP) server, the client-side setup is even easier. Finally, if you have hostnames for your local-area servers and desktops, you should go ahead and set up the caching DNS server to answer for them, too, rather than trying to maintain /etc/hosts files -- after all, as long as you're saving time, you'd might as well save your own in addition to your DNS clients'....

The most popular caching DNS choice for small-to-medium deployments is dnsmasq, which is both a lightweight DNS server and a lightweight DHCP server. It is GPL-licensed and is a standard package in modern Linux distributions. If your distro doesn't provide it, though, you can download and install the source without too much trouble; there are no major external package dependencies.

A less-well-known but equally valid option is pdnsd (which seems to stand for either "proxy DNS" or "permanent DNS" depending on where you look). Pdnsd has the advantage of writing its cache of query results to disk, so that they can be saved from one session to another. On the other hand, pdnsd does not incorporate DHCP functionality, so serving an entire network will require another software package.

The Lone Resolver

Although it is usually referred to as a network service, if you only have a single Linux box, you can set up dnsmasq to run as the "server" even though the "client" sending requests is the same machine. Without dnsmasq running, a Linux machine looks in the file /etc/resolv.conf for an ordered list of DNS servers to query. Statically-configured machines might add servers to this file manually; DHCP client machines have the file automatically updated whenever they get a new lease from their DHCP server.

When you've installed dnsmasq, open the file /etc/dnsmasq.conf as root. There are several dozen configuration options -- all of them well-documented -- but it only takes a few to get set up for normal use.  Near the top, uncomment out the listen-address= directive and add the localhost address 127.0.0.1: listen-address=127.0.0.1. This tells dnsmasq to listen for DNS queries that originate on the local machine.

If you maintain a static resolv.conf, simply open it in an editor and add nameserver 127.0.0.1 to the top. The locally-running copy of dnsmasq will now receive all DNS queries first, and cache the results.

Alternatively, if your computer is a DHCP client -- and if you are installing dnsmasq on it, you presumably do not have access to the DHCP server -- you will need to alter a different file instead. Open your DHCP configuration file -- typically /etc/dhcp3/dhclient.conf.  Then either uncomment or (if it is not present) add the line prepend domain-name-servers 127.0.0.1;. Be sure to include the closing semicolon.

This tells the DHCP client to add 127.0.0.1 to the head of the line whenever the DHCP server sends over the list of DNS servers. The supplied servers may be ISP-provided or at-large public DNS servers, but whatever they are, the local dnsmasq server will get the queries first, enabling the cache.

Whichever configuration you use, start dnsmasq with /etc/rc.d/dnsmasq start. You can use the "dig" command to send a DNS query from the command line; by running it twice in a row, you can see how much shorter the reported "query time" is for the second, cached, reply. In my test, dig www.linux.com took 132 ms uncached and dropped to 1 ms once cached. In addition to the speed gains, though, caching query results locally keeps your browser and other applications from timing out when one of the ISP's DNS servers is suddenly unreachable. There's no real way to test for that scenario, but most of us hope to avoid it anyway.

The LAN

Although you could run dnsmasq on every machine on your local network, running a single instance of it that answers and caches all machines' DNS queries is simpler, and results in fewer queries being forwarded upstream. First, set one machine up as the server. However, in addition to specifying 127.0.0.1 as the listen-address in /etc/dnsmasq.conf, you must also add a listen-address line for the server's local IP address, such as listen-address=192.168.1.101. If your server is a gateway machine with more than one network adapter, you should also be sure to bind dnsmasq only to the local interface, by uncommenting the "interface" line and specifying the adapter: interface=eth0.

You then configure the clients individually. For all non-DHCP clients, you can simply add the server machine's IP to /etc/resolv.conf, e.g., nameserver 192.168.1.101. If your DHCP clients use a separate DHCP server, you can likewise add prepend domain-name-servers 192.168.1.101; to their /etc/dhcp3/dhclient.conf files.

Things are even easier if you use dnsmasq as both the DNS and the DHCP server, though. To enable the DHCP functionality, open /etc/dnsmasq.conf and uncomment the "dhcp-range=" line. This line takes two required and one optional argument. The required arguments are the start and end addresses of the DHCP leases for the server to hand out; if so desired you can optionally add a lease time as the third. For example, dhcp-range=192.168.0.100,192.168.0.200,23h.

It can also help to uncomment the "expand-hosts" and "domain=" lines; doing so appends whatever domain you specify after domain= to the names of local network hosts -- ".local" for example, is unambiguous. If you have some statically-configured hosts (say, servers) and some DHCP clients (say, laptops), dnsmasq.conf gives you several options to set static hostnames -- by IP address, by hardware MAC address, by the hostname the host reports for itself. In this sort of mixed environment, using expand-hosts to tack .local onto hostnames can help prevent accidents like having DNS queries about a local machine forwarded upstream and out to a public DNS server that will not know what to do with them.

Using pdnsd

The above instructions used dnsmasq as the example, but you could also perform most of the same steps (except for the integrated DHCP server, of course) using the disk-caching pdnsd. On the client side, the configuration details are the same: you add the DNS server's IP address to /etc/resolv.conf or the appropriate "prepend" line to /etc/dhcp3/dhclient.conf.

Configuring the server is no more difficult; it just uses a slightly different syntax. In /etc/pdnsd.conf, you would specify the IP address to listen on for DNS queries with server_ip=192.168.1.101, or the interface to listen on with interface=eth0. You do need to tell pdnsd where to find the upstream DNS servers to forward recursive queries to; the simplest way is with a file=/etc/resolv.conf line, although you can also specify the other DNS servers individually. Finally, you can either use the default location for the cache file, /var/cache/pdnsd, or specify a different location with cache_dir=/some/directory/path/of/your/choosing.

Getting Fancy

Once you start playing around with dnsmasq and/or pdnsd, you may think of a few uses for these services beyond what we have covered here. The most obvious, perhaps, is configuring either for IPv6 addresses.  Both support it; the relevant example lines just weren't shown with IPv6 dummy addresses for clarity.

But there is actually more; dnsmasq, for example, has special support for virtual private networks (VPNs), by which you can have dnsmasq direct queries for certain domains (like the company's) to a particular server, rather than forwarding them out to the Internet at large. You can also set up dnsmasq to enable a local-network-only mail service using a local MX record. There is plenty more where that comes from, but let's face it -- most of us want to set-and-forget DNS service, so we can spend more of our browsing time actually reading the sites that interest us, and more of our free time thinking up really good hostnames for all of those LAN clients....

Click Here!