Reset the serial number of a DNS zone
Tested on |
Debian (Lenny) |
Ubuntu (Lucid, Maverick) |
Objective
To reset the serial number of a DNS zone
Scenario
Suppose that the zone example.com
has two nameservers: ns0.example.com
(198.51.100.1) which is the master and ns1.example.com
(203.0.113.1) which is a slave.
You follow the convention of encoding the date in the DNS serial number, but have made a mistake: instead of 2011012400 you have set it to 2111012400. You want to correct this error without disrupting the normal operation of the zone (and in particular, without causing ns1
to lose synchronisation with ns0
).
Background
Serial numbers are used by slave nameservers to determine when a zone transfer is necessary. Higher values are considered to be more recent than lower values. If the master has a more recent copy of the zone than the slave then the slave requests a transfer.
For this scheme to work the serial number of each zone must increase monotonically. However, serial numbers do not follow the normal rules of integer arithmetic. Instead they use 32-bit sequence space arithmetic:
- All calculations are performed modulo 232.
- The only values that can be added to a serial number are non-negative integers less than 231.
- If there is a value ∆x such that x+∆x=y then x<y and y>x.
Changing a serial number directly from 2111012400 to 2011012400 is not allowed because it would require either a subtraction, or an addition outside of the permitted range. However it is possible to achieve the same outcome by performing two separate additions.
Method
Overview
The following procedure allows any desired serial number to be reached:
- Calculate the total distance by which the serial number must advance to reach the desired value.
- Divide this distance into steps that are no larger than the permitted maximum.
- Add each step to the serial number of the master zone file, stopping after each one until all of the slave nameservers have resynchronised.
Steps 1 and 2 can be performed using the DNS serial number calculator provided in the tools section of this website.
Calculate the total distance by which the serial number must advance
Serial numbers wrap around modulo 232 (equal to 4294967296). To calculate the total distance you should therefore:
- Subtract the current serial number from the required serial number.
- Add 232 if the result would otherwise be negative.
For the scenario considered here this would be (2011012400 − 2111012400) + 4294967296 = 4194967296.
Divide the total distance into steps
The maximum distance by which the serial number can advance in one step is 231−1 (equal to 2147483647). It is desirable that the number of steps be minimised in order to avoid unnecessary work. This can be achieved as follows:
- If the remaining distance is greater than 231−1 then advance by 231−1.
- Otherwise, advance by the remaining distance.
- Repeat until the remaining distance is zero.
It is usually possible to reach the desired serial number in two steps. For the scenario considered here, those steps would be:
- 2111012400 + 2147483647 = 4258496047
- 4258496047 + 2047483649 = 2011012400
There are only two situations that require three steps:
- Decrementing the serial number by one. This is unlikely to be worth doing.
- Performing a forward sweep through the entire sequence space, then returning the serial number to its original value. You might want to do this if the serial number on the master was correct, but one of the slaves had a higher value.
Add each step to the serial number of the master zone file
Each time the serial number is changed you must reload the zone into the master nameserver, then wait for it to propagate to all of the slaves.
You can check whether a zone change has propagated to a particular slave by requesting the SOA record for the zone:
dig @203.0.113.1 -t SOA example.com
The format of the answer is slightly different from the format used in a zone file, but it contains the same information (including the serial number) in the same order:
;; ANSWER SECTION: example.com. 86400 IN SOA example.com. hostmaster.example.com. 2011012400 86400 900 1209600 3600
If you make a second change to the serial number when one of the slave nameservers has not registered the first one then instead of taking two steps forward the value will appear to have taken one step back. The zone will not then be transferred and the slave will lose synchronisation with the master. If this happens then you will need to repeat the entire process from the beginning.
Alternatives
Purge each slave of zone data
An alternative method is to:
- stop the slave nameserver,
- delete its backup copy of the zone content (assuming that it has one and you can find it), then
- restart the slave.
It should then fetch a fresh copy of the zone, regardless of serial number. The details of this method will vary according to the nameserver software you are using. In the case of BIND 9, the location of the zone file is specified in the zone declaration:
zone "example.com" { type slave; masters { 198.51.100.1; }; file "/var/lib/bind/db.example.com"; };
Deleting this file while the nameserver is stopped should have the desired effect, for example:
service stop bind9 rm /var/lib/bind/db.example.com service start bind9
As above you can check which version of the zone has been loaded by inspecting the SOA record. Depending on your configuration, it may be necessary to purge some or all of the slaves simultaneously in order to prevent them from fetching the unwanted copy of the zone from each other.
Methods to avoid
Set the serial number to zero
Some nameserver software will perform a zone transfer if the serial number on the master is set to zero, regardless of the serial number on the slave. This behaviour was never RFC-compliant, and is no longer supported by BIND.
Tags: dns