How I do static IPs and names for my NAT'd libvirt-based VMs
One of the things that I use Linux libvirt for is a collection of virtual machines that I only NAT onto the network, instead of giving them their own distinct public IPs. When I first set this up, I didn't do anything special to give these NAT VMs consistent IPs or any names at all, which made it a bit annoying when I wanted to SSH in to one (most of them are Fedora VMs, so I can actually do that). Eventually I went through the effort to set up fixed, static IPs for these and give them names that I could use, which has turned out to be much more convenient.
Giving fixed IPs to libvirt VMs that are on a NAT'd virtual network takes a little bit of work. First off, you have to edit the XML of your network, following the example in Addressing (and the discussion of 'host' in the dhcp section). This will look like this:
<ip ....> <dhcp> <range ... /> <host mac="NN:NN:NN:NN:NN" ip="<fixed IP 1>" name="<your-host>" /> <host mac="NN:NN:NN:NN:NN" ip="<fixed IP x21>" name="<your-host2>" /> </dhcp>
The <ip>, <dhcp>, and <range> bits will already be present; you need to add the <host> bits. If you're using virt-manager, you'll need to go into its preferences and enable XML editing (and then I think possibly quit and restart). I got my host MAC addresses by booting each machine and copying them down, but now that I look, virt-manager will also show you the MAC for each VM's interface(s).
One gotcha I found is that editing the XML won't take effect until you stop and then restart that libvirt network interface (including as part of rebooting your host system). For me, taking my NAT interface down sometimes causes my iptables and ip rules to get a bit scrambled, which makes things a bit annoying and does make me not update things as much as I could.
(Behind the scenes, libvirt generates a dnsmasq configuration and runs it to provide both DHCP and DNS. Presumably it doesn't regenerate the configuration and restart dnsmasq until the network is brought down and then back up again.)
Many examples will show names for your hosts that end in .default. What this does is make the dnsmasq that libvirt will wind up running for this network replace the .default with your default domain, so your NAT'd VMs are <name>.example.org or whatever to themselves and each other. If you give your VMs names ending in something else, for example .local, then that will be their full name (eg 'fedora37.local'). However, all of this is only for the VMs, not necessarily for your host machine.
On my desktops, I use Unbound for local DNS resolution. Fortunately Unbound has a quite straightforward setup for adding local records; in Fedora I created an /etc/unbound/local.d/my-libvirt.conf file and then create a series of pairs of records:
local-data: "fedora37.local. IN A 192....." local-data-ptr: "192..... fedora37.local"
These Unbound names don't have to exactly match either the host names in the libvirt network XML or the actual libvirt names of your virtual machines, but generally the closer that all three of them are to each other, the less annoyed at yourself you'll be.
(Take it from me, as I've learned this the hard way. Even as small a thing as the VM being called 'fedora-37' and the DNS name being 'fedora37' can be a little rough spot.)
PS: On balance, I don't want to connect my desktop's regular DNS resolution to the libvirt dnsmasq in any way. The libvirt dnsmasq has a magically generated configuration and behavior that's hard to predict; my desktop Unbound configuration is fully understandable and under my control.