On Linux host servers, libvirt uses a separate instance of dnsmasq for each virtual network. So if you want full name and reverse lookup for KVM guests on the default 192.168.122.0 network, you can configure this particular dnsmasq instance using virsh.
The ability to customize the libvirt instances are limited, however, so if you need full dnsmasq capabilities or you need this DNS resolution to span multiple networks then you may want to allow these instances to go upstream to a global service instance of dnsmasq.
virsh for specific virtual network instance
Take a look at the dnsmasq instance used for the ‘default’ virtual network. Notice how the binding is specific to the 192.168.122.1 network.
$ virsh net-list --all Name State Autostart Persistent ---------------------------------------------------------- default active yes yes $ ps -ef | grep dnsmasq | grep default libvirt+ 2624 1 0 Oct16 ? 00:00:05 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf $ lsof -p 2624 | grep IPv4 | grep LISTEN dnsmasq 2624 libvirt-dnsmasq 7u IPv4 17534 0t0 TCP 192.168.122.1:domain (LISTEN)
If we wanted to add full DNS resolution to a host named ‘esxi1.lab.home’ with a static IP of 192.168.122.133, then we would first use virsh net-edit on the default network.
virsh net-edit default
And add the following content right before the <ip> element:
<dns> <host ip='192.168.122.133'> <hostname>esxi1.home.lab</hostname> </host> </dns>
Then restart the default virtual network.
virsh net-destroy default && virsh net-start default
And test both a name and reverse lookup.
$ nslookup esxi1.home.lab 192.168.122.1 Server: 192.168.122.1 Address: 192.168.122.1#53 Name: esxi1.home.lab Address: 192.168.122.133 $ nslookup 192.168.122.133 192.168.122.1 Server: 192.168.122.1 Address: 192.168.122.1#53 133.122.168.192.in-addr.arpa name = esxi1.home.lab.
Although the configuration files for the libvirt instances is kept in the “/var/lib/libvirt/dnsmasq” directory, changes you make to these files will be overwritten, so modifying them directly is not an option – instead you need to use virsh.
Host service instance of dnsmasq
The libvirt specific instances of dnsmasq use the DNS server the host machine has defined as upstream. In other words, if the libvirt host machine’s “/etc/resolv.conf” points at Google’s DNS servers, that is where it will go for unrecognized names.
We can use this hook and have the libvirt host’s “/etc/resolv.conf” point to 127.0.0.1, and now all the libvirt specific dnsmasq instances will defer their upstream requests to our custom host instance of dnsmasq.
This exposes the full feature set of dnsmasq including wildcards and domains. Installing dnsmasq on the host is as simple as using apt-get.
sudo apt-get install dnsmasq -y
Add the following lines to “/etc/dnsmasq.conf”, which will limit the binding to the local interface (lo) so it does not interfere with the libvirt bindings on other interfaces.
listen-address=127.0.0.1 interface=lo # if you wanted additional bindings, append another 'interface' or 'listen-address' line # I have seen interface throw 'unknown interface' errors # if so, try listen-address instead #interface=br0 #listen-address=<myNIC_IP> bind-interfaces server=<yourUpstreamDNSIPAddress> log-queries # does not go upstream to resolve addresses ending in 'home.lab' local=/home.lab/
And restart the dnsmasq service
sudo systemctl restart dnsmasq sudo systemctl status dnsmasq
Although you could add custom hostname mappings directly to dnsmasq.conf, dnsmasq also reads “/etc/hosts” as part of its lookup logic, so this is a nice way to easily add entries. Go ahead and add the following entries to “/etc/hosts”.
192.168.122.133 esxi1.home.lab
Now edit “/etc/systemd/resolved.conf” (the newer replacement for what used to be “/etc/resolv.conf”) so it points at this dnsmasq instance for resolution.
# change 'DNS' to 127.0.0.1 sudo vi /etc/systemd/resolved.conf # restart systemd resolv and then check status sudo systemctl restart systemd-resolved # global DNS should now be '127.0.0.1' pointing to local dnsmasq resolvectl dns
Validate by doing a name and reverse lookup on this local dnsmasq instance.
$ nslookup esxi1.home.lab 127.0.0.1 Server: 127.0.0.1 Address: 127.0.0.1#53 Name: esxi1.home.lab Address: 192.168.122.133 $ nslookup 192.168.122.133 127.0.0.1 Server: 127.0.0.1 Address: 127.0.0.1#53 133.122.168.192.in-addr.arpa name = esxi1.home.lab.
Validate upstream of virtual network specific instances
If you want to prove to yourself that the virtual network specific instances will use the host service instance for upstream, then do a ‘virsh net-edit default’ and remove the <dns> section and restart the default network.
virsh net-destroy default && virsh net-start default
Then do a lookup on the 192.168.122 specific instance, and notice it still resolves. This is because it is going to the dnsmasq host instance.
nslookup esxi1.home.lab 192.168.122.1
And if you tail “/var/log/syslog”, you will see the query come in.
Oct 21 23:50:44 myhost dnsmasq[8446]: query[A] esxi1.home.lab from 127.0.0.1 Oct 21 23:50:44 myhost dnsmasq[8446]: /etc/hosts esxi1.home.lab is 192.168.122.133
REFERENCES
https://www.cyberciti.biz/faq/linux-kvm-libvirt-dnsmasq-dhcp-static-ip-address-configuration-for-guest-os/ (set static IP for virsh)
https://serverfault.com/questions/101292/libvirt-change-dhcp-setup-without-restarting
https://www.redhat.com/archives/libvirt-users/2015-February/msg00089.html (example <dns> section)
https://wiki.libvirt.org/page/Networking#virsh_net-update (only safe changes to dnsmaq are through virsh net-update)
https://serverfault.com/questions/840163/custom-dnsmasq-or-custom-options-with-libvrt (advanced dnsmasq options not available with libvirt)
https://serverfault.com/questions/727998/dnsmasq-on-virbr0-libvirt-and-network-manager (new dnsmasq instance for each virtual interface bridge)
https://serverfault.com/questions/101982/get-list-of-dhcp-clients-with-kvmlibvirt (domifaddr and net-dhcp-leases in newer releases of virsh)
http://www.think-foundry.com/build-cloud-foundry-vsphere-bosh/ (vmware and cloudfoundry with vlan)
https://wiki.libvirt.org/page/Networking#virsh_net-update (list of items that can be updated with virsh net-update)
https://qiita.com/bmj0114/items/9c24d863bcab1a634503 (dnsmasq wildcards and forwarding to upstream)
https://www.redhat.com/archives/libvirt-users/2014-April/msg00028.html (use bind-interfaces for host system instance so it does not conflict with instances from libvirt)
https://wiki.archlinux.org/index.php/dnsmasq (dnsmasq upstream, custom domain, expand-hosts, test)
https://serverfault.com/questions/799200/bind-dnsmasq-dns-to-just-localhost-127-0-0-1 (bind just to localhost to avoid conflict)
https://docs.openstack.org/ocata/networking-guide/misc-libvirt.html (default iptables rules that libvirt creates for default network)
https://textik.com/ (ascii art creator for image)
NOTES
Example of using dns-txt, dns-srv, dns-host records [1].
<domain name="example.com"/> <dns> <txt name="example" value="example value" /> <srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10'/> <host ip='192.168.122.2'> <hostname>myhost</hostname> <hostname>myhostalias</hostname> </host> </dns>
direct mapping put into /etc/dnsmasq.conf
local=/home.lab/ address=/esxi1.home.lab/192.168.122.133
if dnsmasq systemd service was started and stopped too frequently, you have to unmask
sudo systemctl unmask dnsmasq.service && sudo systemctl enable dnsmasq.service