Print warning when falling back to increment soa serial method

When using the `unixtime` or `date` method to update the SOA serial,
`named` and `dnssec-signzone` would silently fallback to `increment`
method to prevent the new serial number to be smaller than the old
serial number (using the serial number arithmetics).  Add a warning
message when such fallback happens.
This commit is contained in:
Ondřej Surý 2020-12-10 10:31:31 +01:00 committed by Ondřej Surý
parent 3e4f5319ef
commit ef685bab5c
6 changed files with 95 additions and 54 deletions

View file

@ -1352,7 +1352,8 @@ setsoaserial(uint32_t serial, dns_updatemethod_t method) {
dns_dbnode_t *node = NULL;
dns_rdataset_t rdataset;
dns_rdata_t rdata = DNS_RDATA_INIT;
uint32_t old_serial, new_serial;
uint32_t old_serial, new_serial = 0;
dns_updatemethod_t used = dns_updatemethod_none;
result = dns_db_getoriginnode(gdb, &node);
if (result != ISC_R_SUCCESS) {
@ -1376,16 +1377,20 @@ setsoaserial(uint32_t serial, dns_updatemethod_t method) {
if (method == dns_updatemethod_date ||
method == dns_updatemethod_unixtime) {
new_serial = dns_update_soaserial(old_serial, method);
new_serial = dns_update_soaserial(old_serial, method, &used);
} else if (serial != 0 || method == dns_updatemethod_none) {
/* Set SOA serial to the value provided. */
new_serial = serial;
used = method;
} else {
/* Increment SOA serial using RFC 1982 arithmetic */
new_serial = (old_serial + 1) & 0xFFFFFFFF;
if (new_serial == 0) {
new_serial = 1;
}
new_serial = dns_update_soaserial(old_serial, method, &used);
}
if (method != used) {
fprintf(stderr,
"%s: warning: Serial number would not advance, "
"using increment method instead\n",
program);
}
/* If the new serial is not likely to cause a zone transfer

View file

@ -38,15 +38,23 @@ ISC_LANG_BEGINDECLS
***/
uint32_t
dns_update_soaserial(uint32_t serial, dns_updatemethod_t method);
dns_update_soaserial(uint32_t serial, dns_updatemethod_t method,
dns_updatemethod_t *used);
/*%<
* Return the next serial number after 'serial', depending on the
* update method 'method':
*
*\li * dns_updatemethod_increment increments the serial number by one
*\li * dns_updatemethod_date sets the serial number to YYYYMMDD00
*\li * dns_updatemethod_unixtime sets the serial number to the current
* time (seconds since UNIX epoch) if possible, or increments by one
* if not.
* time (seconds since UNIX epoch)
*\li * dns_updatemethod_none just returns the given serial
*
* NOTE: The dns_updatemethod_increment will be used if dns_updatemethod_date or
* dns_updatemethod_unixtime is used and the new serial number would be lower
* than current serial number.
*
* Sets *used to the method that was used.
*/
isc_result_t

View file

@ -88,7 +88,7 @@ increment_test(void **state) {
UNUSED(state);
serial = dns_update_soaserial(old, dns_updatemethod_increment);
serial = dns_update_soaserial(old, dns_updatemethod_increment, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, 51);
@ -102,7 +102,7 @@ increment_past_zero_test(void **state) {
UNUSED(state);
serial = dns_update_soaserial(old, dns_updatemethod_increment);
serial = dns_update_soaserial(old, dns_updatemethod_increment, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, 1u);
@ -119,7 +119,7 @@ past_to_unix_test(void **state) {
set_mystdtime(2011, 6, 22);
old = mystdtime - 1;
serial = dns_update_soaserial(old, dns_updatemethod_unixtime);
serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, mystdtime);
@ -136,7 +136,7 @@ now_to_unix_test(void **state) {
set_mystdtime(2011, 6, 22);
old = mystdtime;
serial = dns_update_soaserial(old, dns_updatemethod_unixtime);
serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, old + 1);
@ -153,7 +153,7 @@ future_to_unix_test(void **state) {
set_mystdtime(2011, 6, 22);
old = mystdtime + 1;
serial = dns_update_soaserial(old, dns_updatemethod_unixtime);
serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, old + 1);
@ -171,7 +171,7 @@ undefined_plus1_to_unix_test(void **state) {
old = mystdtime ^ 0x80000000u;
old += 1;
serial = dns_update_soaserial(old, dns_updatemethod_unixtime);
serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, mystdtime);
@ -189,7 +189,7 @@ undefined_minus1_to_unix_test(void **state) {
old = mystdtime ^ 0x80000000u;
old -= 1;
serial = dns_update_soaserial(old, dns_updatemethod_unixtime);
serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, old + 1);
@ -206,7 +206,7 @@ undefined_to_unix_test(void **state) {
set_mystdtime(2011, 6, 22);
old = mystdtime ^ 0x80000000u;
serial = dns_update_soaserial(old, dns_updatemethod_unixtime);
serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, old + 1);
@ -223,7 +223,7 @@ unixtime_zero_test(void **state) {
mystdtime = 0;
old = 0xfffffff0;
serial = dns_update_soaserial(old, dns_updatemethod_unixtime);
serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, old + 1);
@ -237,10 +237,10 @@ past_to_date_test(void **state) {
UNUSED(state);
set_mystdtime(2014, 3, 31);
old = dns_update_soaserial(0, dns_updatemethod_date);
old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
set_mystdtime(2014, 4, 1);
serial = dns_update_soaserial(old, dns_updatemethod_date);
serial = dns_update_soaserial(old, dns_updatemethod_date, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
@ -256,9 +256,9 @@ now_to_date_test(void **state) {
UNUSED(state);
set_mystdtime(2014, 4, 1);
old = dns_update_soaserial(0, dns_updatemethod_date);
old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
serial = dns_update_soaserial(old, dns_updatemethod_date);
serial = dns_update_soaserial(old, dns_updatemethod_date, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, 2014040101);
@ -273,10 +273,10 @@ future_to_date_test(void **state) {
UNUSED(state);
set_mystdtime(2014, 4, 1);
old = dns_update_soaserial(0, dns_updatemethod_date);
old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
set_mystdtime(2014, 3, 31);
serial = dns_update_soaserial(old, dns_updatemethod_date);
serial = dns_update_soaserial(old, dns_updatemethod_date, NULL);
assert_true(isc_serial_lt(old, serial));
assert_int_not_equal(serial, 0);
assert_int_equal(serial, 2014040101);

View file

@ -2204,35 +2204,55 @@ epoch_to_yyyymmdd(time_t when) {
tm->tm_mday);
}
uint32_t
dns_update_soaserial(uint32_t serial, dns_updatemethod_t method) {
static uint32_t
dns__update_soaserial(uint32_t serial, dns_updatemethod_t method) {
isc_stdtime_t now;
uint32_t new_serial;
switch (method) {
case dns_updatemethod_none:
return (serial);
case dns_updatemethod_unixtime:
isc_stdtime_get(&now);
if (now != 0 && isc_serial_gt(now, serial)) {
return (now);
}
break;
return (now);
case dns_updatemethod_date:
isc_stdtime_get(&now);
new_serial = epoch_to_yyyymmdd((time_t)now) * 100;
if (new_serial != 0 && isc_serial_gt(new_serial, serial)) {
return (new_serial);
return (epoch_to_yyyymmdd((time_t)now) * 100);
case dns_updatemethod_increment:
/* RFC1982 */
serial = (serial + 1) & 0xFFFFFFFF;
if (serial == 0) {
return (1);
}
return (serial);
default:
INSIST(0);
ISC_UNREACHABLE();
}
}
uint32_t
dns_update_soaserial(uint32_t serial, dns_updatemethod_t method,
dns_updatemethod_t *used) {
uint32_t new_serial = dns__update_soaserial(serial, method);
switch (method) {
case dns_updatemethod_none:
case dns_updatemethod_increment:
break;
case dns_updatemethod_unixtime:
case dns_updatemethod_date:
if (!(new_serial != 0 && isc_serial_gt(new_serial, serial))) {
method = dns_updatemethod_increment;
new_serial = dns__update_soaserial(serial, method);
}
break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
/* RFC1982 */
serial = (serial + 1) & 0xFFFFFFFF;
if (serial == 0) {
serial = 1;
if (used != NULL) {
*used = method;
}
return (serial);
return (new_serial);
}

View file

@ -4346,12 +4346,14 @@ update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
}
static isc_result_t
update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
isc_mem_t *mctx, dns_updatemethod_t method) {
update_soa_serial(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
dns_diff_t *diff, isc_mem_t *mctx,
dns_updatemethod_t method) {
dns_difftuple_t *deltuple = NULL;
dns_difftuple_t *addtuple = NULL;
uint32_t serial;
isc_result_t result;
dns_updatemethod_t used = dns_updatemethod_none;
INSIST(method != dns_updatemethod_none);
@ -4360,7 +4362,12 @@ update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
addtuple->op = DNS_DIFFOP_ADD;
serial = dns_soa_getserial(&addtuple->rdata);
serial = dns_update_soaserial(serial, method);
serial = dns_update_soaserial(serial, method, &used);
if (method != used) {
dns_zone_log(zone, ISC_LOG_WARNING,
"update_soa_serial:new serial would be lower than "
"old serial, using increment method instead");
}
dns_soa_setserial(serial, &addtuple->rdata);
CHECK(do_one_tuple(&deltuple, db, ver, diff));
CHECK(do_one_tuple(&addtuple, db, ver, diff));
@ -4617,7 +4624,7 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
result = arg.result;
if (changed) {
/* Write changes to journal file. */
CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
CHECK(update_soa_serial(zone, db, ver, &diff, zone->mctx,
zone->updatemethod));
CHECK(zone_journal(zone, &diff, NULL, "sync_keyzone"));
@ -7164,7 +7171,7 @@ zone_resigninc(dns_zone_t *zone) {
}
/* Increment SOA serial if we have made changes */
result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
result = update_soa_serial(zone, db, version, zonediff.diff, zone->mctx,
zone->updatemethod);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
@ -8872,7 +8879,7 @@ skip_removals:
goto failure;
}
result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
result = update_soa_serial(zone, db, version, zonediff.diff, zone->mctx,
zone->updatemethod);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
@ -9615,7 +9622,7 @@ zone_sign(dns_zone_t *zone) {
goto cleanup;
}
result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
result = update_soa_serial(zone, db, version, zonediff.diff, zone->mctx,
zone->updatemethod);
if (result != ISC_R_SUCCESS) {
dnssec_log(zone, ISC_LOG_ERROR,
@ -10624,7 +10631,7 @@ anchors_done:
done:
if (!ISC_LIST_EMPTY(diff.tuples)) {
/* Write changes to journal file. */
CHECK(update_soa_serial(kfetch->db, ver, &diff, mctx,
CHECK(update_soa_serial(zone, kfetch->db, ver, &diff, mctx,
zone->updatemethod));
CHECK(zone_journal(zone, &diff, NULL, "keyfetch_done"));
commit = true;
@ -10855,7 +10862,7 @@ zone_refreshkeys(dns_zone_t *zone) {
}
}
if (!ISC_LIST_EMPTY(diff.tuples)) {
CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
CHECK(update_soa_serial(zone, db, ver, &diff, zone->mctx,
zone->updatemethod));
CHECK(zone_journal(zone, &diff, NULL, "zone_refreshkeys"));
commit = true;
@ -16013,7 +16020,8 @@ nextevent:
CHECK(do_one_tuple(&soatuple, zone->rss_db,
zone->rss_newver, &zone->rss_diff));
} else {
CHECK(update_soa_serial(zone->rss_db, zone->rss_newver,
CHECK(update_soa_serial(zone, zone->rss_db,
zone->rss_newver,
&zone->rss_diff, zone->mctx,
zone->updatemethod));
}
@ -19910,7 +19918,7 @@ zone_rekey(dns_zone_t *zone) {
CHECK(clean_nsec3param(zone, db, ver, &diff));
CHECK(add_signing_records(db, zone->privatetype, ver,
&diff, (newalg || fullsign)));
CHECK(update_soa_serial(db, ver, &diff, mctx,
CHECK(update_soa_serial(zone, db, ver, &diff, mctx,
zone->updatemethod));
CHECK(add_chains(zone, db, ver, &diff));
CHECK(sign_apex(zone, db, ver, now, &diff, &zonediff));
@ -20719,7 +20727,7 @@ keydone(isc_task_t *task, isc_event_t *event) {
if (!ISC_LIST_EMPTY(diff.tuples)) {
/* Write changes to journal file. */
CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
CHECK(update_soa_serial(zone, db, newver, &diff, zone->mctx,
zone->updatemethod));
result = dns_update_signatures(&log, zone, db, oldver, newver,
@ -21004,7 +21012,7 @@ rss_post(dns_zone_t *zone, isc_event_t *event) {
* records.
*/
if (!ISC_LIST_EMPTY(diff.tuples)) {
CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
CHECK(update_soa_serial(zone, db, newver, &diff, zone->mctx,
zone->updatemethod));
result = dns_update_signatures(&log, zone, db, oldver, newver,
&diff,

View file

@ -1486,7 +1486,7 @@ update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
addtuple->op = DNS_DIFFOP_ADD;
serial = dns_soa_getserial(&addtuple->rdata);
serial = dns_update_soaserial(serial, method);
serial = dns_update_soaserial(serial, method, NULL);
dns_soa_setserial(serial, &addtuple->rdata);
CHECK(do_one_tuple(&deltuple, db, ver, diff));
CHECK(do_one_tuple(&addtuple, db, ver, diff));