Support optional port attribute for <forwarder> element in network XML
Problem Statement
The <forwarder> element in libvirt's network XML currently only supports the addr and domain attributes. This forces DNS forwarding to always target port 53 on the upstream server, which creates significant limitations for modern DNS setups where services intentionally run on non-standard ports.[1]
Use Cases
Many DNS services deliberately avoid port 53 to prevent conflicts:
- Tor's DNSPort: Tor's DNS resolver typically runs on ports like 9053 to avoid conflicting with system DNS[2]
- Pi-hole on custom ports: Users running Pi-hole alongside libvirt experience port 53 conflicts[3]
- DNS-over-HTTPS proxies: Tools like dnscrypt-proxy often use alternative ports
- Containerized DNS services: Multiple DNS resolvers on the same host need different ports
- Development/testing: Running multiple DNS services with different configurations
Current Workarounds
Users currently resort to complex workarounds:
- NAT/iptables rules: Redirecting port 53 to the target port with firewall rules[4]
-
Disabling libvirt DNS: Using
<dns enable="no"/>which breaks VM DNS resolution entirely[4] - Chained forwarding: Running intermediate dnsmasq instances
- Port conflicts: Forcing services onto port 53, causing system-wide conflicts[5][3]
These workarounds are neither declarative nor maintainable.
Proposed Solution
Add an optional port attribute to the <forwarder> element:
<network>
<name>default</name>
<dns>
<!-- Forward all DNS queries to Tor's DNSPort -->
<forwarder addr="127.0.0.1" port="9053"/>
<!-- Domain-specific forwarding with custom port -->
<forwarder domain="onion" addr="127.0.0.1" port="9053"/>
</dns>
<!-- ... rest of network config ... -->
</network>
Technical Basis
dnsmasq already supports this functionality via the --server option with port specification:[6]
--server=/domain/ip-address#port
--server=127.0.0.1#9053
The implementation would simply map the XML port attribute to dnsmasq's existing syntax when generating the dnsmasq configuration.
Implementation Details
- The
portattribute would be optional (default: 53) - Backward compatibility is maintained (no breaking changes)
- Minimal change to XML schema and dnsmasq command-line generation
- Works with both IPv4 and IPv6 addresses
Impact
This feature would:
- Enable clean Tor integration with libvirt networks (my use case: nixtornet)
- Eliminate complex iptables workarounds
- Support modern DNS service architectures
- Maintain full backward compatibility
Community Evidence
This limitation affects real users across multiple platforms:
- Stack Overflow 2022: Users asking how to change libvirt's DNS port due to conflicts[4]
- Reddit 2021: Pi-hole + libvirt port 53 conflicts requiring workarounds[3]
- Unraid 2017: Unable to run secondary DNS services due to port binding[5]
- Multiple blog posts: DNS resolution challenges in libvirt requiring external solutions[7][8]
Related Work
Similar enhancement requests (like Issue #285 for hostfwd support) show that libvirt accepts features when the underlying technology (dnsmasq/QEMU) already supports them. This follows the same pattern.[9]
Additional Context
I'm developing a NixOS module for Tor-integrated libvirt networks and hit this limitation immediately (https://codeberg.org/malik/nixtornet/issues/3). Currently forced to use iptables NAT rules to redirect DNS traffic from port 53 to Tor's DNSPort on 9053, which defeats the purpose of declarative networking configuration.