Skip to content

conditional name resolving with dnsmasq

For some reason I needed to install a lightweight DNS forwarder on my local machine. A host file would not be sufficient, I really needed some kind of local DNS machinery that allows for specific queries to be answered by certain DNS servers. But looking more closely, there were already two DNS servers running on that machine:
$ sudo netstat -lnpu | grep :53\ 
udp   127.0.0.53:53     0.0.0.0:*  3845/systemd-resolved
udp   192.168.122.1:53  0.0.0.0:*  3189/dnsmasq  
The first one is systemd-resolved, that mainly seems to care about which resolv.conf to use and provides only some basic configuration parameters, not sufficient to what's needed here.

The second one is from libvirtd, running on the default address of the virtual virbr0 interface. And indeed, some parameters could be adjusted and the following actually worked:
$ sudo virsh net-edit --network default
[...]
  <dns>
    <forwarder domain='example.com' addr='1.2.3.4'>
    <forwarder domain='foobar.net'  addr='2.2.2.2'/>
    <forwarder addr='5.5.5.5'/>
  </dns>

$ sudo virsh net-destroy --network default
$ sudo virsh net-start   --network default
This would forward queries for example.com to 1.2.3.4 and all queries not listed here to 5.5.5.5. That was kind of what was needed, but these rules needed to be updated from time to time and editing XML stanzas for DNS entries felt somewhat unnatural. Also, with that setup I would depend on libvirt to always be installed and in working condition. If, for some reason, the libvirt setups breaks and its dnsmasq instance doesn't come up, the system would have no DNS services. But since dnsmasq was installed anyway, let's just use that.

After disabling systemd-resolved, the DNS part of libvirt's dnsmasq instance needed to be disabled too:

  <dns enable='no'/>
With that, port 53 was free to use and a new dnsmasq instance could be spawned.
$ cat /etc/dnsmasq.d/local.conf
interface=lo
listen-address=127.0.0.1
log-queries
server=5.5.5.5

server=/example.com/1.2.3.4
server=/foobar.net/2.2.2.2
All unspecified queries will go to 5.5.5.5. We could also omit that and with the absence of a no-resolv directive, dnsmasq will forward all unspecified queries to a name server specified in /etc/resolv.conf. That way we can have distinct (private) name servers for certain domains, and a stable fallback for everything else. Neat :-)