What's Actually Happening
Dnsmasq DNS forwarder fails to resolve domain names. Clients receive SERVFAIL or no response to queries.
The Error You'll See
```bash $ dig @localhost google.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 12345 ```
No response:
;; connection timed out; no servers could be reachedLocal resolution fails:
```bash $ dig @localhost myhost.local
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN ```
Configuration error:
dnsmasq: bad option at line 10 of /etc/dnsmasq.confWhy This Happens
- 1.Upstream DNS unreachable - Cannot reach configured DNS servers
- 2.Configuration errors - Syntax errors in dnsmasq.conf
- 3.Port conflict - Another service using port 53
- 4.Hosts file issues - Malformed /etc/hosts entries
- 5.Permission issues - Cannot read configuration files
- 6.DNSSEC validation - Failing DNSSEC checks
- 7.Cache corruption - Corrupted DNS cache
Step 1: Check Dnsmasq Status
```bash # Check dnsmasq service: systemctl status dnsmasq
# Check process: ps aux | grep dnsmasq
# Check listening ports: netstat -tlnp | grep 53 ss -tlnp | grep 53
# Check UDP port: ss -ulnp | grep :53
# Check logs: journalctl -u dnsmasq -f
# Check configuration: dnsmasq --test
# Check version: dnsmasq -v
# Start dnsmasq: systemctl start dnsmasq
# Check config file: cat /etc/dnsmasq.conf
# Check additional configs: ls -la /etc/dnsmasq.d/
# Check hosts file: cat /etc/hosts ```
Step 2: Check Configuration
```bash # Test configuration syntax: dnsmasq --test
# Main configuration: cat /etc/dnsmasq.conf
# Common settings: # Listen on interfaces: listen-address=127.0.0.1,192.168.1.1
# Bind to interfaces: bind-interfaces
# Set port: port=53
# Upstream DNS: server=8.8.8.8 server=8.8.4.4
# Domain: domain=local
# DNS range: dhcp-range=192.168.1.50,192.168.1.150,12h
# Log queries: log-queries
# Check for included files: grep conf-dir /etc/dnsmasq.conf
# List included configs: ls -la /etc/dnsmasq.d/
# Check all configs: for f in /etc/dnsmasq.d/*; do echo "=== $f ===" cat $f done
# Common errors: # 1. Missing equals sign # 2. Invalid option name # 3. Wrong format for IP ranges ```
Step 3: Check Upstream DNS
```bash # Check configured upstream servers: grep "^server=" /etc/dnsmasq.conf
# Test upstream servers: ping 8.8.8.8 ping 8.8.4.4
# Test DNS resolution on upstream: dig @8.8.8.8 google.com
# Check port: nc -zuv 8.8.8.8 53
# If upstream unreachable: # Check firewall: iptables -L -n | grep 53
# Allow outbound DNS: iptables -I OUTPUT -p udp --dport 53 -j ACCEPT iptables -I OUTPUT -p tcp --dport 53 -j ACCEPT
# Add multiple upstream servers: server=8.8.8.8 server=8.8.4.4 server=1.1.1.1
# Use specific server for domain: server=/example.com/192.168.1.1
# Check for upstream errors: journalctl -u dnsmasq | grep -i "upstream|forward"
# Test forwarding: dig @localhost google.com +trace ```
Step 4: Check Local Resolution
```bash # Dnsmasq uses /etc/hosts for local names
# Check hosts file: cat /etc/hosts
# Format: # IP hostname alias 192.168.1.10 server1.local server1 192.168.1.11 server2.local server2
# Check for syntax errors: # - Missing IP address # - Missing hostname # - Invalid characters
# Add hosts file entry: echo "192.168.1.100 myhost.local" >> /etc/hosts
# Reload dnsmasq: systemctl reload dnsmasq
# Test local resolution: dig @localhost myhost.local
# Check hosts file permissions: ls -la /etc/hosts
# Additional hosts file: addn-hosts=/etc/hosts.dnsmasq
# Check address entries: grep "^address=" /etc/dnsmasq.conf
# Static address: address=/myhost.local/192.168.1.100 ```
Step 5: Check Port Binding
```bash # Check what's listening on port 53: ss -ulnp | grep :53 ss -tlnp | grep :53
# If another service using port 53: # Check systemd-resolved: systemctl status systemd-resolved
# Stop resolved if needed: systemctl stop systemd-resolved systemctl disable systemd-resolved
# Check for bind-utils: lsof -i :53
# Configure dnsmasq to bind: bind-interfaces listen-address=127.0.0.1
# Or listen on all: listen-address=0.0.0.0
# For specific interface: interface=eth0
# Check interface IP: ip addr show eth0
# Restart: systemctl restart dnsmasq
# Verify binding: ss -ulnp | grep dnsmasq ```
Step 6: Check DNSSEC Configuration
```bash # Check DNSSEC settings: grep -i dnssec /etc/dnsmasq.conf
# Disable DNSSEC (if issues): dnssec-off
# Or comment out DNSSEC options
# Check for DNSSEC errors: journalctl -u dnsmasq | grep -i dnssec
# DNSSEC trust anchor: dnssec-trust-anchor=...
# Test with DNSSEC disabled: # Stop dnsmasq systemctl stop dnsmasq
# Edit config, disable DNSSEC # Start dnsmasq systemctl start dnsmasq
# Test resolution: dig @localhost google.com
# If DNSSEC required: # Ensure trust anchors valid # Check for expired keys
# Forward DNSSEC: proxy-dnssec
# Check DNSSEC validation: dig @localhost google.com +dnssec ```
Step 7: Check Cache Settings
```bash # Check cache size: grep cache-size /etc/dnsmasq.conf
# Default cache size: cache-size=150
# Increase cache: cache-size=1000
# Clear cache: # Send SIGHUP to reload: kill -HUP $(cat /run/dnsmasq/dnsmasq.pid)
# Or restart: systemctl restart dnsmasq
# Check cache stats: dig @localhost example.com # Then: dig @localhost example.com # Second query should be cached
# Check cache in logs: # Enable logging: log-queries log-facility=/var/log/dnsmasq.log
# Monitor cache: watch "dig @localhost google.com +stats"
# No-negcache option: # Don't cache negative responses no-negcache
# Cache negative TTL: neg-ttl=60 ```
Step 8: Check DHCP Integration
```bash # If dnsmasq provides DHCP:
# Check DHCP range: grep dhcp-range /etc/dnsmasq.conf
# DHCP configuration: dhcp-range=192.168.1.50,192.168.1.150,12h
# Check DHCP leases: cat /var/lib/dnsmasq/dnsmasq.leases
# Or: cat /var/lib/misc/dnsmasq.leases
# DHCP option: dhcp-option=3,192.168.1.1 # Gateway dhcp-option=6,192.168.1.1 # DNS
# DNS from DHCP clients: # dnsmasq reads /etc/hosts for local names
# Enable DHCP: dhcp-authoritative
# Check for DHCP errors: journalctl -u dnsmasq | grep -i dhcp
# DHCP script: dhcp-script=/etc/dnsmasq.d/dhcp-script.sh
# Test DHCP: dhclient -v eth0 ```
Step 9: Debug Resolution Issues
```bash # Enable debug logging: log-queries log-dhcp
# In config: log-facility=/var/log/dnsmasq.log
# Restart: systemctl restart dnsmasq
# Watch logs: tail -f /var/log/dnsmasq.log
# Test specific query: dig @localhost google.com +short
# Test with debug: dnsmasq --no-daemon --log-queries
# Check response codes: dig @localhost google.com +stats
# Test TCP: dig @localhost google.com +tcp
# Force specific record: dig @localhost example.com A dig @localhost example.com MX dig @localhost example.com TXT
# Check for timeouts: dig @localhost google.com +time=10
# Use tcpdump: tcpdump -i any port 53 -n
# Check response time: dig @localhost google.com | grep "Query time" ```
Step 10: Dnsmasq Verification Script
```bash # Create verification script: cat << 'EOF' > /usr/local/bin/check-dnsmasq.sh #!/bin/bash
echo "=== Dnsmasq Service ===" systemctl status dnsmasq 2>/dev/null | head -5 || echo "Service not running"
echo "" echo "=== Process ===" ps aux | grep dnsmasq | grep -v grep || echo "No dnsmasq process"
echo "" echo "=== Listening Ports ===" ss -ulnp 2>/dev/null | grep :53 || netstat -ulnp | grep :53 || echo "Not listening on UDP 53" ss -tlnp 2>/dev/null | grep :53 || netstat -tlnp | grep :53 || echo "Not listening on TCP 53"
echo "" echo "=== Configuration Test ===" dnsmasq --test 2>&1 || echo "Configuration errors"
echo "" echo "=== Upstream Servers ===" grep "^server=" /etc/dnsmasq.conf 2>/dev/null || echo "No upstream servers configured"
echo "" echo "=== Listen Address ===" grep "^listen-address" /etc/dnsmasq.conf 2>/dev/null || echo "No listen address configured"
echo "" echo "=== Cache Size ===" grep "^cache-size" /etc/dnsmasq.conf 2>/dev/null || echo "Using default cache size"
echo "" echo "=== Hosts File ===" cat /etc/hosts 2>/dev/null | grep -v "^#" | grep -v "^$" | head -10
echo "" echo "=== Additional Configs ===" ls -la /etc/dnsmasq.d/ 2>/dev/null || echo "No additional config directory"
echo "" echo "=== Test Resolution ===" echo "Testing external DNS:" dig @localhost google.com +short 2>/dev/null | head -3 || echo "External resolution failed"
echo "" echo "Testing local DNS:" dig @localhost localhost +short 2>/dev/null || echo "Local resolution failed"
echo "" echo "=== Firewall ===" iptables -L -n 2>/dev/null | grep 53 || ufw status 2>/dev/null | grep 53 || echo "Check firewall manually"
echo "" echo "=== Recent Logs ===" journalctl -u dnsmasq --no-pager -n 10 2>/dev/null || tail /var/log/dnsmasq.log 2>/dev/null | tail -10 || echo "No logs"
echo "" echo "=== Recommendations ===" echo "1. Verify upstream DNS servers are reachable" echo "2. Check dnsmasq.conf syntax with dnsmasq --test" echo "3. Ensure port 53 is available (not used by systemd-resolved)" echo "4. Allow UDP/TCP port 53 in firewall" echo "5. Check /etc/hosts for local entries" echo "6. Disable DNSSEC if validation errors" echo "7. Increase cache size if needed" EOF
chmod +x /usr/local/bin/check-dnsmasq.sh
# Usage: /usr/local/bin/check-dnsmasq.sh ```
Dnsmasq DNS Resolution Checklist
| Check | Expected |
|---|---|
| Service running | dnsmasq process active |
| Port listening | UDP 53 accessible |
| Config valid | dnsmasq --test passes |
| Upstream reachable | Can query upstream DNS |
| Hosts file valid | No syntax errors |
| No port conflict | Port 53 not used by other |
| Firewall open | Port 53 allowed |
Verify the Fix
```bash # After fixing Dnsmasq DNS
# 1. Check service systemctl status dnsmasq // Active running
# 2. Test external dig @localhost google.com // Returns A record
# 3. Test local dig @localhost myhost.local // Returns local IP
# 4. Check config dnsmasq --test // No errors
# 5. Monitor logs journalctl -u dnsmasq -f // Queries logged
# 6. Test from client dig @dnsmasq-server google.com // Resolution works ```
Related Issues
- [Fix BIND DNS Resolution Failed](/articles/fix-bind-dns-resolution-failed)
- [Fix PowerDNS Query Failed](/articles/fix-powerdns-query-failed)
- [Fix Unbound DNS Not Responding](/articles/fix-unbound-dns-not-responding)