dnsmasq
Installation
SKILL.md
Identity
- Unit:
dnsmasq.service - Config:
/etc/dnsmasq.conf,/etc/dnsmasq.d/(drop-in directory) - Logs:
journalctl -u dnsmasq,/var/log/dnsmasq.log(iflog-facilityset) - Leases:
/var/lib/misc/dnsmasq.leases - Distro install:
apt install dnsmasq/dnf install dnsmasq
Key Operations
| Operation | Command |
|---|---|
| Status | systemctl status dnsmasq |
| Reload (re-reads config, leases) | sudo systemctl reload dnsmasq |
| Restart | sudo systemctl restart dnsmasq |
| Test config syntax | dnsmasq --test |
| Test config with explicit file | dnsmasq --test -C /etc/dnsmasq.conf |
| View active config (compiled) | dnsmasq --test --conf-file=/etc/dnsmasq.conf 2>&1 |
| Check listening ports | ss -ulnp | grep dnsmasq; ss -tlnp | grep dnsmasq |
| Query DNS via dnsmasq | dig @127.0.0.1 example.com |
| Check DNSSEC validation | dig @127.0.0.1 example.com +dnssec |
| List DHCP leases | cat /var/lib/misc/dnsmasq.leases |
| Signal re-read of hosts/leases | sudo kill -HUP $(pidof dnsmasq) |
| Add static DHCP host | Add dhcp-host=MAC,IP,hostname to config, then reload |
| Block domain (sinkhole) | Add address=/badsite.com/ to config, then reload |
| Watch live DNS queries | journalctl -u dnsmasq -f (requires log-queries in config) |
Expected Ports
- 53/udp and 53/tcp — DNS (both protocols required; TCP for large responses and DNSSEC)
- 67/udp — DHCP server (only when DHCP is enabled)
- Verify:
ss -ulnp | grep ':53\|:67' - Firewall (DNS only):
sudo ufw allow 53orsudo firewall-cmd --add-service=dns --permanent - Firewall (DHCP):
sudo ufw allow 67/udporsudo firewall-cmd --add-service=dhcp --permanent
Health Checks
systemctl is-active dnsmasq→activednsmasq --test 2>&1→ containssyntax check OKdig @127.0.0.1 google.com +short→ returns one or more IP addresses (notSERVFAIL)ss -ulnp | grep ':53'→ dnsmasq listed on port 53
Common Failures
| Symptom | Likely cause | Check/Fix |
|---|---|---|
failed to create listening socket for port 53: Address already in use |
systemd-resolved stub listener is on 53 | ss -ulnp | grep :53 — disable resolved stub: DNSStubListener=no in /etc/systemd/resolved.conf, then systemctl restart systemd-resolved |
| DHCP not handing out addresses | No interface= or listen-address= set |
Add interface=eth0 (or the LAN interface name) to config and reload |
DNS queries return SERVFAIL |
Upstream servers unreachable or no server= set |
Check /etc/resolv.conf; add server=8.8.8.8 explicitly; verify connectivity with dig @8.8.8.8 google.com |
/etc/hosts entries not served via DNS |
no-hosts option is set |
Remove no-hosts from config, or use addn-hosts= to add a separate hosts file |
NetworkManager overwrites /etc/resolv.conf |
NM manages DNS and resets resolv.conf on reconnect | Set dns=none in /etc/NetworkManager/NetworkManager.conf under [main], or configure NM to use dnsmasq as a plugin |
| Clients get IP but no DNS via DHCP | dhcp-option=6 not set (option 6 = DNS server) |
Add dhcp-option=6,<dnsmasq-ip> to config and reload |
| Log shows queries but responses are slow | Upstream resolver latency or no-cache scenario | Check cache-size (default 150); increase to 1000; verify upstream latency with dig @<upstream> |
| DNSSEC validation failures for legitimate domains | Clock skew or upstream doesn't support DNSSEC | Check timedatectl; temporarily disable with dnssec=no to confirm; fix NTP sync |
Pain Points
- systemd-resolved conflict on Ubuntu/Debian: On modern Ubuntu,
systemd-resolvedbinds 127.0.0.53:53 by default AND sets/etc/resolv.confto point there. You must disable its stub listener (DNSStubListener=no) and point/etc/resolv.confat127.0.0.1(dnsmasq) before dnsmasq can start. Alternatively, run dnsmasq on the physical interface address only (not127.0.0.1) and leave the stub in place, at the cost of some complexity. interface=is mandatory for DHCP: dnsmasq silently ignores DHCP requests on interfaces not explicitly listed. If DHCP appears to start but hands out nothing, a missinginterface=line is the most likely cause.conf-dirfor modular config: Drop-in files in/etc/dnsmasq.d/are only included whenconf-dir=/etc/dnsmasq.d/,*.confappears indnsmasq.conf. Without this, the directory is ignored. Debian-packaged dnsmasq typically includes this already; manual installs may not.- NetworkManager integration: NM has a built-in dnsmasq plugin (
dns=dnsmasqinNetworkManager.conf) that runs its own dnsmasq instance per-connection. This conflicts with a standalone dnsmasq. Pick one approach — do not run both. - DNSSEC validation gotchas: Enabling
dnssecrequires correct system time (within a few minutes) and an upstream resolver that passes DNSSEC records. Validating behind a corporate proxy that intercepts DNS will break. Usednssec-check-unsignedcarefully — it flags unsigned zones asBOGUS, which breaks many CDNs and older domains. bind-interfacesvs default any-interface behavior: By default dnsmasq listens on all interfaces but filters by theinterface=list. Withbind-interfacesit actually binds only to the listed interfaces — necessary in multi-homed hosts to avoid port conflicts with other DNS services on other interfaces.
References
See references/ for:
dnsmasq.conf.annotated— complete config with every directive explaineddocs.md— official documentation and community links
Related skills