Introduction
Zone transfers (AXFR for full transfers, IXFR for incremental) replicate DNS zone data from master to slave servers. When zone transfers fail, slaves have outdated zone data, causing inconsistent DNS responses across your infrastructure. This leads to some users seeing old IP addresses while others see current ones. Zone transfer issues require access to both master and slave server configurations.
Symptoms
- Slave DNS servers return outdated records
- Zone updates not reflected on all servers
- AXFR/IXFR errors in DNS server logs
dig axfrreturns "Transfer failed" or timeout- SOA serial mismatch between master and slaves
- DNS queries return different results from different servers
- Log messages: "received notify for zone" but no transfer follows
- "refused" or "not authorized" errors on zone transfer attempts
Common Causes
- Master server not configured to allow transfers to slave IPs
- Slave server not configured to request transfers from correct master
- Firewall blocking TCP port 53 (zone transfers use TCP)
- ACL mismatch on master's allow-transfer statement
- TSIG key mismatch between master and slave
- SOA serial not incremented after zone changes
- Master not sending NOTIFY, or slave not receiving it
- Zone not loaded on master (configuration error)
Step-by-Step Fix
- 1.Verify the master zone is loaded and responding.
```bash # Check master server has the zone loaded # On master server:
# BIND: rndc status rndc zonestatus example.com
# Check zone is in running state dig @master-ip example.com SOA
# Verify zone content dig @master-ip example.com AXFR
# Or from remote: dig @ns1.example.com example.com SOA +short # Should return SOA record with current serial ```
- 1.Test zone transfer from slave's perspective.
```bash # Attempt zone transfer from master dig @master-ip example.com AXFR
# This should return the full zone # If you get "Transfer failed" or timeout, transfer is blocked
# Test with specific slave IP as source # (If your IP isn't allowed, simulate from allowed IP) dig @master-ip example.com AXFR
# Check for specific error responses dig @master-ip example.com AXFR +yaml # Look for: status: REFUSED, status: SERVFAIL, etc. ```
- 1.Check SOA serial matches between master and slave.
```bash # Get serial from master master_serial=$(dig @master-ip example.com SOA +short | awk '{print $3}') echo "Master serial: $master_serial"
# Get serial from slave slave_serial=$(dig @slave-ip example.com SOA +short | awk '{print $3}') echo "Slave serial: $slave_serial"
# Compare if [ "$master_serial" = "$slave_serial" ]; then echo "OK: Serials match" else echo "ERROR: Serial mismatch" echo "Master is ahead by $((master_serial - slave_serial))" fi
# Check all slaves for slave in slave1.example.com slave2.example.com; do serial=$(dig @$slave example.com SOA +short | awk '{print $3}') echo "$slave: serial $serial" done ```
- 1.Verify TCP connectivity for zone transfers.
```bash # Zone transfers use TCP, not UDP # Test TCP connectivity to master
nc -vz master-ip 53
# Or with telnet telnet master-ip 53
# If TCP fails but UDP works, firewall is blocking TCP # Test UDP (should work) dig @master-ip example.com SOA
# Test TCP specifically dig @master-ip example.com SOA +tcp
# If +tcp fails, check firewall rules ```
- 1.Check master's allow-transfer configuration.
```bash # On master BIND server, check named.conf # Look for allow-transfer statements
# Zone-level configuration: zone "example.com" { type master; file "zones/example.com.zone"; allow-transfer { 192.0.2.10; 192.0.2.11; }; also-notify { 192.0.2.10; 192.0.2.11; }; };
# Or server-level in options: options { allow-transfer { none; }; # Default deny };
# Check current configuration: named-checkconf | grep allow-transfer
# View effective settings: rndc zonestatus example.com | grep -i transfer ```
- 1.Check slave's master configuration.
```bash # On slave BIND server, check named.conf zone "example.com" { type slave; file "slaves/example.com.zone"; masters { 192.0.2.1; }; };
# Verify masters IP is correct # Check slave can reach master ping master-ip dig @master-ip example.com SOA
# Force transfer from slave rndc retransfer example.com
# Check slave logs journalctl -u named | grep -i transfer # or tail -f /var/log/named/named.log | grep -i transfer ```
- 1.Diagnose TSIG key issues (if using signed transfers).
```bash # TSIG provides authentication for zone transfers
# Check TSIG key exists on both master and slave # On master: tsig-keygen -a hmac-sha256 transfer-key # Add to named.conf: key "transfer-key" { algorithm hmac-sha256; secret "BASE64SECRET"; };
# On master's zone config: allow-transfer { key "transfer-key"; };
# On slave's server config: server master-ip { keys { transfer-key; }; };
# Test with TSIG dig @master-ip example.com AXFR -k /etc/transfer.key
# Common issues: # - Key mismatch (different secrets) # - Algorithm mismatch # - Key not loaded (restart needed) # - Time skew (TSIG uses timestamps) ```
- 1.Check NOTIFY configuration.
```bash # NOTIFY tells slaves to check for updates
# On master: zone "example.com" { type master; notify yes; # or explicit also-notify { 192.0.2.10; 192.0.2.11; }; };
# On slave: zone "example.com" { type slave; allow-notify { 192.0.2.1; }; # Master IP };
# Send manual notify from master rndc notify example.com
# Check if slave receives notify # On slave, watch logs: journalctl -u named -f | grep notify
# Look for: "received notify for zone 'example.com'" ```
- 1.Manually trigger zone transfer for testing.
```bash # On slave, force full zone transfer rndc retransfer example.com
# Or refresh (incremental if supported) rndc refresh example.com
# On master, force notify to all slaves rndc notify example.com
# Check transfer status rndc zonestatus example.com
# Watch logs during transfer # Master: should show "transfer of 'example.com' started" # Slave: should show "transfer of 'example.com' from master completed" ```
- 1.Fix common configuration errors.
```bash # Master configuration (BIND example): zone "example.com" IN { type master; file "example.com.zone"; allow-transfer { 192.0.2.10; # slave1 192.0.2.11; # slave2 key "transfer-key"; # if using TSIG }; notify yes; also-notify { 192.0.2.10; 192.0.2.11; }; };
# Slave configuration: zone "example.com" IN { type slave; file "slaves/example.com.zone"; masters { 192.0.2.1; }; allow-notify { 192.0.2.1; }; };
# After changes: # Check config syntax named-checkconf
# Reload configuration rndc reload
# Reload specific zone rndc reload example.com
# Verify zone is loaded rndc zonestatus example.com ```
Verification
After fixing zone transfer issues:
```bash # 1. Verify serials match on all servers echo "=== Serial Check ===" for server in master-ip slave1-ip slave2-ip; do serial=$(dig @$server example.com SOA +short | awk '{print $3}') echo "$server: $serial" done
# 2. Test zone transfer works echo -e "\n=== Zone Transfer Test ===" dig @master-ip example.com AXFR | tail -5
# 3. Verify specific records match echo -e "\n=== Record Comparison ===" record="www.example.com" for server in master-ip slave1-ip slave2-ip; do echo -n "$server: " dig @$server $record A +short done
# 4. Check logs for transfer success echo -e "\n=== Recent Transfer Logs ===" journalctl -u named --since "10 minutes ago" | grep -i transfer
# 5. Test NOTIFY flow echo -e "\n=== NOTIFY Test ===" # On master: rndc notify example.com # Watch slave logs for notify receipt
# 6. Verify all zone data echo -e "\n=== Zone Data Size ===" dig @master-ip example.com AXFR 2>/dev/null | wc -l dig @slave-ip example.com AXFR 2>/dev/null | wc -l # Should be equal ```
Zone Transfer Debugging Checklist
```bash # Master server checks: [ ] Zone loaded (rndc zonestatus) [ ] SOA serial current [ ] allow-transfer includes slave IPs [ ] notify enabled [ ] also-notify configured [ ] TCP port 53 open [ ] TSIG key correct (if used)
# Slave server checks: [ ] Zone configured as slave [ ] masters IP correct [ ] allow-notify includes master IP [ ] Can reach master on TCP 53 [ ] Write permission on slave zone file [ ] TSIG key matches master
# Network checks: [ ] TCP 53 not blocked by firewall [ ] Both servers can ping each other [ ] No NAT issues affecting source IP ```
Security Note
Zone transfers expose your entire zone data. Always: - Restrict allow-transfer to known slave IPs - Use TSIG for authentication - Never allow-transfer { any; }; in production - Consider ACLs on both master and firewall