A DNS zone transfer isn’t just copying records; it’s a synchronized dance where a secondary nameserver asks the primary for the entire song sheet, and the primary obliges, sending over every note and rest.
Let’s see this in action. Imagine we have a zone example.com managed by a primary server at 192.168.1.100. We want our secondary server, at 192.168.1.101, to hold a copy.
On the primary server (192.168.1.100), our CoreDNS configuration (Corefile) might look like this:
.:53 {
errors
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
cache 30
loop
reload
bind
# This is the key for zone transfers
transfer {
# Specify the zone and the IP of the secondary
from example.com 192.168.1.101
}
# The actual zone data for example.com
file db.example.com
}
On the secondary server (192.168.1.101), the Corefile would be:
.:53 {
errors
ready
prometheus :9153
cache 30
loop
reload
bind
# This is the key for zone transfers
transfer {
# Specify the zone and the IP of the primary
to example.com 192.168.1.100
}
# This tells CoreDNS where to get the zone data from
auto 192.168.1.100:53
}
The transfer plugin on the primary tells it to allow zone transfers (AXFR or IXFR) for example.com to 192.168.1.101. The transfer plugin on the secondary tells it to request zone transfers for example.com from 192.168.1.100. The auto directive on the secondary then tells CoreDNS to dynamically load the zone data it receives.
The fundamental problem zone transfers solve is redundancy and load balancing for DNS. Without them, if your primary nameserver goes down, your domain becomes unreachable. Zone transfers create authoritative copies of your DNS records on multiple machines. The secondary server periodically polls the primary for changes. If the primary is unavailable, the secondary continues to serve its existing copy of the zone, ensuring continued resolution. For high-traffic zones, having multiple secondaries also distributes the query load, preventing a single server from becoming a bottleneck.
Internally, when the secondary initiates a transfer, it sends a DNS query for the SOA record of the zone. The primary, seeing this query comes from an IP it’s configured to allow transfers from (via the transfer from directive), responds with the current zone serial number. The secondary compares this to its own copy. If the serial is higher, it requests a full zone transfer (AXFR). If it’s only slightly higher, it might request an incremental zone transfer (IXFR), which sends only the changes since the last transfer. The transfer plugin on the secondary then parses the received zone data and updates its internal representation. The auto plugin on the secondary is crucial; it dynamically creates a zone configuration based on the data received from the primary, rather than requiring a static file or db directive in the Corefile.
The most surprising part is how the serial number dictates everything. It’s not just a version number; it’s the single source of truth for synchronization. Any change to a DNS record on the primary must increment the SOA serial number. If you forget to increment it, the secondary will never know there’s new data, even if you restart the primary. This strict adherence to serial numbers is what prevents data divergence and ensures the integrity of the DNS data across servers.
The next concept you’ll grapple with is ensuring these transfers are secure, often involving TSIG keys to authenticate the primary and secondary.