2704. [bug] Serial of dynamic and stub zones could be inconsistent

with their SOA serial.  [RT #19387]
This commit is contained in:
Evan Hunt 2009-10-05 19:39:20 +00:00
parent 3c52c4e44c
commit 3ff75c89eb
5 changed files with 91 additions and 40 deletions

View file

@ -1,3 +1,6 @@
2704. [bug] Serial of dynamic and stub zones could be inconsistent
with their SOA serial. [RT #19387]
2703. [func] Introduce an OpenSSL "engine" argument with -E
for all binaries which can take benefit of
crypto hardware. [RT #20230]

View file

@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: statschannel.c,v 1.22 2009/02/17 03:40:28 marka Exp $ */
/* $Id: statschannel.c,v 1.23 2009/10/05 19:39:20 each Exp $ */
/*! \file */
@ -678,9 +678,11 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
xmlTextWriterWriteString(writer, ISC_XMLCHAR buf);
xmlTextWriterEndElement(writer);
serial = dns_zone_getserial(zone);
xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial");
xmlTextWriterWriteFormatString(writer, "%u", serial);
if (dns_zone_getserial2(zone, &serial) == ISC_R_SUCCESS)
xmlTextWriterWriteFormatString(writer, "%u", serial);
else
xmlTextWriterWriteString(writer, ISC_XMLCHAR "-");
xmlTextWriterEndElement(writer);
zonestats = dns_zone_getrequeststats(zone);
@ -729,7 +731,7 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "bind"));
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
ISC_XMLCHAR "2.1"));
ISC_XMLCHAR "2.2"));
/* Set common fields for statistics dump */
dumparg.type = statsformat_xml;

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.h,v 1.166 2009/07/02 07:39:03 marka Exp $ */
/* $Id: zone.h,v 1.167 2009/10/05 19:39:20 each Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
@ -150,13 +150,24 @@ dns_zone_getclass(dns_zone_t *zone);
*\li 'zone' to be a valid zone.
*/
isc_result_t
dns_zone_getserial2(dns_zone_t *zone, isc_uint32_t *serialp);
isc_uint32_t
dns_zone_getserial(dns_zone_t *zone);
/*%<
* Returns the current serial number of the zone.
* Returns the current serial number of the zone. On success, the SOA
* serial of the zone will be copied into '*serialp'.
* dns_zone_getserial() cannot catch failure cases and is deprecated by
* dns_zone_getserial2().
*
* Requires:
*\li 'zone' to be a valid zone.
*\li 'serialp' to be non NULL
*
* Returns:
*\li #ISC_R_SUCCESS
*\li #DNS_R_NOTLOADED zone DB is not loaded
*/
void

View file

@ -731,6 +731,7 @@ dns_zone_getprivatetype
dns_zone_getqueryacl
dns_zone_getrequeststats
dns_zone_getserial
dns_zone_getserial2
dns_zone_getsigresigninginterval
dns_zone_getsigvalidityinterval
dns_zone_getssutable

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.507 2009/09/22 08:38:14 fdupont Exp $ */
/* $Id: zone.c,v 1.508 2009/10/05 19:39:20 each Exp $ */
/*! \file */
@ -207,7 +207,6 @@ struct dns_zone {
isc_time_t nsec3chaintime;
isc_time_t refreshkeytime; /* Used by key zones */
isc_uint32_t refreshkeycount;
isc_uint32_t serial;
isc_uint32_t refresh;
isc_uint32_t retry;
isc_uint32_t expire;
@ -748,7 +747,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
isc_time_settoepoch(&zone->nsec3chaintime);
isc_time_settoepoch(&zone->refreshkeytime);
zone->refreshkeycount = 0;
zone->serial = 0;
zone->refresh = DNS_ZONE_DEFAULTREFRESH;
zone->retry = DNS_ZONE_DEFAULTRETRY;
zone->expire = 0;
@ -997,16 +995,35 @@ dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) {
UNLOCK_ZONE(zone);
}
isc_uint32_t
dns_zone_getserial(dns_zone_t *zone) {
isc_uint32_t serial;
isc_result_t
dns_zone_getserial2(dns_zone_t *zone, isc_uint32_t *serialp) {
isc_result_t result;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(serialp != NULL);
LOCK_ZONE(zone);
serial = zone->serial;
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->db != NULL) {
result = zone_get_from_db(zone, zone->db, NULL, NULL, serialp,
NULL, NULL, NULL, NULL, NULL);
} else
result = DNS_R_NOTLOADED;
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
UNLOCK_ZONE(zone);
return (result);
}
isc_uint32_t
dns_zone_getserial(dns_zone_t *zone) {
isc_result_t result;
isc_uint32_t serial;
result = dns_zone_getserial2(zone, &serial);
if (result != ISC_R_SUCCESS)
serial = 0; /* XXX: not really correct, but no other choice */
return (serial);
}
@ -3086,7 +3103,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
unsigned int soacount = 0;
unsigned int nscount = 0;
unsigned int errors = 0;
isc_uint32_t serial, refresh, retry, expire, minimum;
isc_uint32_t serial, oldserial, refresh, retry, expire, minimum;
isc_time_t now;
isc_boolean_t needdump = ISC_FALSE;
isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE);
@ -3238,14 +3255,18 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
* This is checked in zone_replacedb() for slave zones
* as they don't reload from disk.
*/
result = zone_get_from_db(zone, zone->db, NULL, NULL,
&oldserial, NULL, NULL, NULL,
NULL, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) &&
!isc_serial_gt(serial, zone->serial)) {
!isc_serial_gt(serial, oldserial)) {
isc_uint32_t serialmin, serialmax;
INSIST(zone->type == dns_zone_master);
serialmin = (zone->serial + 1) & 0xffffffffU;
serialmax = (zone->serial + 0x7fffffffU) &
serialmin = (oldserial + 1) & 0xffffffffU;
serialmax = (oldserial + 0x7fffffffU) &
0xffffffffU;
dns_zone_log(zone, ISC_LOG_ERROR,
"ixfr-from-differences: "
@ -3254,11 +3275,11 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
serialmax);
result = DNS_R_BADZONE;
goto cleanup;
} else if (!isc_serial_ge(serial, zone->serial))
} else if (!isc_serial_ge(serial, oldserial))
dns_zone_log(zone, ISC_LOG_ERROR,
"zone serial (%u/%u) has gone "
"backwards", serial, zone->serial);
else if (serial == zone->serial && !hasinclude)
"backwards", serial, oldserial);
else if (serial == oldserial && !hasinclude)
dns_zone_log(zone, ISC_LOG_ERROR,
"zone serial (%u) unchanged. "
"zone may fail to transfer "
@ -3275,7 +3296,6 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
"3 * refresh.");
}
zone->serial = serial;
zone->refresh = RANGE(refresh,
zone->minrefresh, zone->maxrefresh);
zone->retry = RANGE(retry,
@ -3311,7 +3331,6 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
break;
case dns_zone_key:
zone->serial = serial;
result = sync_keyzone(zone, db);
if (result != ISC_R_SUCCESS)
goto cleanup;
@ -3374,9 +3393,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
}
if (! dns_db_ispersistent(db))
dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s",
zone->serial,
dns_db_issecure(db) ? " (signed)" : "");
dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s", serial,
dns_db_issecure(db) ? " (DNSSEC signed)" : "");
return (result);
@ -8766,7 +8784,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_soa_t soa;
isc_result_t result;
isc_uint32_t serial;
isc_uint32_t serial, oldserial;
unsigned int j;
zone = revent->ev_arg;
@ -8989,12 +9007,17 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
RUNTIME_CHECK(result == ISC_R_SUCCESS);
serial = soa.serial;
zone_debuglog(zone, me, 1, "serial: new %u, old %u",
serial, zone->serial);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
result = dns_zone_getserial2(zone, &oldserial);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
zone_debuglog(zone, me, 1, "serial: new %u, old %u",
serial, oldserial);
} else
zone_debuglog(zone, me, 1, "serial: new %u, old not loaded",
serial);
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) ||
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) ||
isc_serial_gt(serial, zone->serial)) {
isc_serial_gt(serial, oldserial)) {
if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr,
&zone->sourceaddr, &now)) {
dns_zone_log(zone, ISC_LOG_INFO,
@ -9018,7 +9041,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
}
if (msg != NULL)
dns_message_destroy(&msg);
} else if (isc_serial_eq(soa.serial, zone->serial)) {
} else if (isc_serial_eq(soa.serial, oldserial)) {
if (zone->masterfile != NULL) {
result = ISC_R_FAILURE;
if (zone->journal != NULL)
@ -9051,7 +9074,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MULTIMASTER))
dns_zone_log(zone, ISC_LOG_INFO, "serial number (%u) "
"received from master %s < ours (%u)",
soa.serial, master, zone->serial);
soa.serial, master, oldserial);
else
zone_debuglog(zone, me, 1, "ahead");
zone->mastersok[zone->curmaster] = ISC_TRUE;
@ -10186,13 +10209,21 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
if (result == ISC_R_SUCCESS)
result = dns_rdataset_first(rdataset);
if (result == ISC_R_SUCCESS) {
isc_uint32_t serial = 0;
isc_uint32_t serial = 0, oldserial;
dns_rdataset_current(rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &soa, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
serial = soa.serial;
if (isc_serial_le(serial, zone->serial)) {
/*
* The following should safely be performed without DB
* lock and succeed in this context.
*/
result = zone_get_from_db(zone, zone->db, NULL, NULL,
&oldserial, NULL, NULL, NULL,
NULL, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (isc_serial_le(serial, oldserial)) {
dns_zone_log(zone, ISC_LOG_INFO,
"notify from %s: "
"zone is up to date",
@ -10870,7 +10901,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
if (zone->db != NULL && zone->journal != NULL &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) &&
!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) {
isc_uint32_t serial;
isc_uint32_t serial, oldserial;
dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs");
@ -10885,11 +10916,15 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
/*
* This is checked in zone_postload() for master zones.
*/
result = zone_get_from_db(zone, zone->db, NULL, NULL,
&oldserial, NULL, NULL, NULL, NULL,
NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (zone->type == dns_zone_slave &&
!isc_serial_gt(serial, zone->serial)) {
!isc_serial_gt(serial, oldserial)) {
isc_uint32_t serialmin, serialmax;
serialmin = (zone->serial + 1) & 0xffffffffU;
serialmax = (zone->serial + 0x7fffffffU) & 0xffffffffU;
serialmin = (oldserial + 1) & 0xffffffffU;
serialmax = (oldserial + 0x7fffffffU) & 0xffffffffU;
dns_zone_log(zone, ISC_LOG_ERROR,
"ixfr-from-differences: failed: "
"new serial (%u) out of range [%u - %u]",
@ -11082,7 +11117,6 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
zone_unload(zone);
goto next_master;
}
zone->serial = serial;
zone->refresh = RANGE(refresh, zone->minrefresh,
zone->maxrefresh);
zone->retry = RANGE(retry, zone->minretry,
@ -11120,7 +11154,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
buf[0] = '\0';
dns_zone_log(zone, ISC_LOG_INFO,
"transferred serial %u%s",
zone->serial, buf);
serial, buf);
}
/*