pdnsd: Local caching DNS

tung's picture

I love watching Firefox forever display "Looking up www.example.com...". I love it when it says it can't find a server, even when I can ping individual IPs just fine.

No, actually, I hate it.

Why doesn't my machine just remember which IP matches which domain name, even if the router or my ISP craps out? Well, looks like somebody else was thinking like I was, because that's exactly what pdnsd does: it looks up domain names, and remembers their matching IP addresses.

So here's how I set it up for myself.

I use Arch Linux, so I just followed the instructions here.

It works by sitting on your local machine, and instead of your OS asking the name servers what domain name means what IP address, it asks pdnsd. pdnsd will get back to you right away if it knows the answer. If it doesn't, it asks the usual grapevine, and caches the lookup. Result? Much faster lookups, and no more DNS problems with the router or ISP.

I tweaked mine a bit from that wiki article. I use NetworkManager, which overwrites a file needed to make pdnsd work: /etc/resolv.conf. That file tells your computer where to look up names. NetworkManager wants to make it whatever network you're connected to, which messes up my config, which is to use pdnsd which then looks up the network I'm connected to. What to do?

After I set up pdnsd, I wanted to make NetworkManager still work for me. First, NetworkManager needs to stop crapping all over /etc/resolv.conf. Putting this script in /etc/NetworkManager/dispatcher.d/screwyoudude did the trick:

#!/bin/bash
#
# Override /etc/resolv.conf and tell
# NetworkManagerDispatcher to go pluck itself.
#
# scripts in the /etc/NetworkManager/dispatcher.d/ directory
# are called alphabetically and are passed two parameters:
# $1 is the interface name, and $2 is “up” or “down” as the
# case may be.
 
# Here, no matter what interface or state, override the
# created resolver config with my config.
 
cp -f /etc/resolv.conf.mine /etc/resolv.conf

I swiped that from a forum post I'm not willing to look up right now. Meanwhile, /etc/resolv.conf.mine has this:

# Tung's super special thing for pdnsd - the local DNS caching program!
#
# Used by /etc/NetworkManager/dispatcher.d/screwyoudude, because
# NetworkManager is totally incompetent.  This stuff is copied
# right to /etc/resolv.conf.
 
nameserver 127.0.0.1

Now NetworkManager will put what I want in /etc/resolv.conf, instead of what it wants.

EDIT: Don't forget to start NetworkManagerDispatcher as a daemon! NetworkManager 0.7 runs these automatically now.

But now how would I adapt to other networks? NetworkManager comes with a nice tool called nm-tool which, amongst other things, spits out these lines:

  IP Settings:
    IP Address:      10.1.1.7
    Subnet Mask:     255.0.0.0
    Broadcast:       10.255.255.255
    Gateway:         10.1.1.1
    Primary DNS:     10.1.1.1
    Secondary DNS:   0.0.0.0

See those last lines with "DNS" in them? Used in conjunction with pdnsd-ctl to change pdnsd's settings dynamically, I knocked up this (living in /etc/NetworkManager/dispatcher.d/pdnsd-auto-dns):

#!/bin/bash
#
# Tung: Set the DNS IPs that pdnsd will use.  Since pdnsd is a proxy DNS
# service/cacher, it needs real DNS servers for unseen names, which this
# script will set at run-time.
#
# $1 is the device name (e.g. eth0), $2 is either 'up' or 'down'.
 
if [ "$2" = "up" ]; then
    dnsips=`nm-tool | awk '/DNS/ && !/0\.0\.0\.0/ { printf $3 "," }'`
    if [ -n "$dnsips" ]; then
        # DNS IPs found that weren't 0.0.0.0
        dnsips=`echo $dnsips | head -c -1`
        pdnsd-ctl server blurg up $dnsips
    fi
fi

All it does is run nm-tool, look for those "DNS" lines, and set pdnsd's config to use those for domain name lookups whenever NetworkManager connects to a new network. I have a "blurg" config group in my pdnsd config file, but it could be called anything.

I also enable the OpenDNS servers, with name server IPs 208.67.222.222 and 208.67.220.220. It's fine to cache lookups locally, but unknown names and crappy domain name servers will still cause problems, so I enabled the group in the pdnsd config file. I've also heard 4.2.2.1 and 4.2.2.2 work as alternative name servers, but I haven't heard much anything about them, so I'm not sure I want to use them just yet.

So now pdnsd will save my domain name to IP address lookups, save the cached results between sessions, and will "know" when I change networks. Huzzah!