summaryrefslogtreecommitdiffstats
path: root/lib/dns/zone.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/zone.c')
-rw-r--r--lib/dns/zone.c211
1 files changed, 161 insertions, 50 deletions
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 423b005..c21b1f0 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.483.36.6 2009/03/26 22:57:07 marka Exp $ */
+/* $Id: zone.c,v 1.483.36.17 2009/12/21 04:32:42 marka Exp $ */
/*! \file */
@@ -200,7 +200,6 @@ struct dns_zone {
isc_time_t keywarntime;
isc_time_t signingtime;
isc_time_t nsec3chaintime;
- isc_uint32_t serial;
isc_uint32_t refresh;
isc_uint32_t retry;
isc_uint32_t expire;
@@ -351,11 +350,15 @@ struct dns_zone {
#define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U
#define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U
#define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U
+#define DNS_ZONEFLG_REFRESHING 0x04000000U /*%< Refreshing keydata */
+#define DNS_ZONEFLG_THAW 0x08000000U
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
/* Flags for zone_load() */
#define DNS_ZONELOADFLAG_NOSTAT 0x00000001U /* Do not stat() master files */
+#define DNS_ZONELOADFLAG_THAW 0x00000002U /* Thaw the zone on successful
+ load. */
#define UNREACH_CHACHE_SIZE 10U
#define UNREACH_HOLD_TIME 600 /* 10 minutes */
@@ -718,7 +721,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
isc_time_settoepoch(&zone->keywarntime);
isc_time_settoepoch(&zone->signingtime);
isc_time_settoepoch(&zone->nsec3chaintime);
- zone->serial = 0;
zone->refresh = DNS_ZONE_DEFAULTREFRESH;
zone->retry = DNS_ZONE_DEFAULTRETRY;
zone->expire = 0;
@@ -967,16 +969,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);
}
@@ -1314,7 +1335,9 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
INSIST(zone->type != dns_zone_none);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) {
- result = ISC_R_SUCCESS;
+ if ((flags & DNS_ZONELOADFLAG_THAW) != 0)
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW);
+ result = DNS_R_CONTINUE;
goto cleanup;
}
@@ -1448,6 +1471,8 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
if (result == DNS_R_CONTINUE) {
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADING);
+ if ((flags & DNS_ZONELOADFLAG_THAW) != 0)
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW);
goto cleanup;
}
@@ -1470,6 +1495,30 @@ dns_zone_loadnew(dns_zone_t *zone) {
return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
}
+isc_result_t
+dns_zone_loadandthaw(dns_zone_t *zone) {
+ isc_result_t result;
+
+ result = zone_load(zone, DNS_ZONELOADFLAG_THAW);
+ switch (result) {
+ case DNS_R_CONTINUE:
+ /* Deferred thaw. */
+ break;
+ case ISC_R_SUCCESS:
+ case DNS_R_UPTODATE:
+ case DNS_R_SEENINCLUDE:
+ zone->update_disabled = ISC_FALSE;
+ break;
+ case DNS_R_NOMASTERFILE:
+ zone->update_disabled = ISC_FALSE;
+ break;
+ default:
+ /* Error, remain in disabled state. */
+ break;
+ }
+ return (result);
+}
+
static unsigned int
get_master_options(dns_zone_t *zone) {
unsigned int options;
@@ -2148,7 +2197,8 @@ resume_signingwithkey(dns_zone_t *zone) {
}
result = zone_signwithkey(zone, rdata.data[0],
- (rdata.data[1] << 8) | rdata.data[2], ISC_TF(rdata.data[3]));
+ (rdata.data[1] << 8) | rdata.data[2],
+ ISC_TF(rdata.data[3]));
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"zone_signwithkey failed: %s",
@@ -2291,7 +2341,6 @@ static void
set_resigntime(dns_zone_t *zone) {
dns_rdataset_t rdataset;
dns_fixedname_t fixed;
- char namebuf[DNS_NAME_FORMATSIZE];
unsigned int resign;
isc_result_t result;
isc_uint32_t nanosecs;
@@ -2305,7 +2354,6 @@ set_resigntime(dns_zone_t *zone) {
return;
}
resign = rdataset.resign;
- dns_name_format(dns_fixedname_name(&fixed), namebuf, sizeof(namebuf));
dns_rdataset_disassociate(&rdataset);
isc_random_get(&nanosecs);
nanosecs %= 1000000000;
@@ -2409,7 +2457,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);
@@ -2463,8 +2511,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
options = DNS_JOURNALOPT_RESIGN;
else
options = 0;
- result = dns_journal_rollforward(zone->mctx, db, options,
- zone->journal);
+ result = dns_journal_rollforward2(zone->mctx, db, options,
+ zone->sigresigninginterval,
+ zone->journal);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND &&
result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL &&
result != ISC_R_RANGE) {
@@ -2544,14 +2593,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: "
@@ -2560,10 +2613,10 @@ 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 has gone backwards");
- else if (serial == zone->serial && !hasinclude)
+ else if (serial == oldserial && !hasinclude)
dns_zone_log(zone, ISC_LOG_ERROR,
"zone serial unchanged. "
"zone may fail to transfer "
@@ -2580,7 +2633,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,
@@ -2664,8 +2716,7 @@ 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_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s", serial,
dns_db_issecure(db) ? " (signed)" : "");
return (result);
@@ -2683,7 +2734,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
if (zone->task != NULL)
zone_settimer(zone, &now);
result = ISC_R_SUCCESS;
- }
+ } else if (zone->type == dns_zone_master)
+ dns_zone_log(zone, ISC_LOG_ERROR, "not loaded due to errors.");
return (result);
}
@@ -4374,7 +4426,8 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
seen_done = ISC_TRUE;
else
CHECK(update_one_rr(signing->db, version, diff,
- DNS_DIFFOP_DEL, name, rdataset.ttl, &rdata));
+ DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata));
dns_rdata_reset(&rdata);
}
if (result == ISC_R_NOMORE)
@@ -5458,6 +5511,7 @@ zone_sign(dns_zone_t *zone) {
dst_key_t *zone_keys[MAXZONEKEYS];
isc_int32_t signatures;
isc_boolean_t check_ksk, is_ksk;
+ isc_boolean_t commit = ISC_FALSE;
isc_boolean_t delegation;
isc_boolean_t finishedakey = ISC_FALSE;
isc_boolean_t secureupdated = ISC_FALSE;
@@ -5745,6 +5799,7 @@ zone_sign(dns_zone_t *zone) {
goto failure;
}
}
+
if (finishedakey) {
/*
* We have changed the RRset above so we need to update
@@ -5770,6 +5825,15 @@ zone_sign(dns_zone_t *zone) {
goto failure;
}
}
+
+ /*
+ * Have we changed anything?
+ */
+ if (ISC_LIST_HEAD(sig_diff.tuples) == NULL)
+ goto pauseall;
+
+ commit = ISC_TRUE;
+
result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
&sig_diff, zone_keys, nkeys, now);
if (result != ISC_R_SUCCESS) {
@@ -5801,6 +5865,9 @@ zone_sign(dns_zone_t *zone) {
goto failure;
}
+ /*
+ * Write changes to journal file.
+ */
journalfile = dns_zone_getjournal(zone);
if (journalfile != NULL) {
dns_journal_t *journal = NULL;
@@ -5823,7 +5890,7 @@ zone_sign(dns_zone_t *zone) {
}
}
-
+ pauseall:
/*
* Pause all iterators so that dns_db_closeversion() can succeed.
*/
@@ -5840,7 +5907,7 @@ zone_sign(dns_zone_t *zone) {
/*
* Everything has succeeded. Commit the changes.
*/
- dns_db_closeversion(db, &version, ISC_TRUE);
+ dns_db_closeversion(db, &version, commit);
/*
* Everything succeeded so we can clean these up now.
@@ -5856,9 +5923,11 @@ zone_sign(dns_zone_t *zone) {
set_resigntime(zone);
- LOCK_ZONE(zone);
- zone_needdump(zone, DNS_DUMP_DELAY);
- UNLOCK_ZONE(zone);
+ if (commit) {
+ LOCK_ZONE(zone);
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ UNLOCK_ZONE(zone);
+ }
failure:
/*
@@ -6498,6 +6567,7 @@ notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) {
isc_sockaddr_t any;
isc_boolean_t isself;
isc_netaddr_t dstaddr;
+ isc_result_t result;
if (zone->view == NULL || zone->isself == NULL)
return (ISC_FALSE);
@@ -6523,7 +6593,9 @@ notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) {
src = *dst;
isc_netaddr_fromsockaddr(&dstaddr, dst);
- (void)dns_view_getpeertsig(zone->view, &dstaddr, &key);
+ result = dns_view_getpeertsig(zone->view, &dstaddr, &key);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
+ return (ISC_FALSE);
isself = (zone->isself)(zone->view, key, &src, dst, zone->rdclass,
zone->isselfarg);
if (key != NULL)
@@ -6725,9 +6797,14 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
goto cleanup;
isc_netaddr_fromsockaddr(&dstip, &notify->dst);
- (void)dns_view_getpeertsig(notify->zone->view, &dstip, &key);
-
isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
+ result = dns_view_getpeertsig(notify->zone->view, &dstip, &key);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+ notify_log(notify->zone, ISC_LOG_ERROR, "NOTIFY to %s not "
+ "sent. Peer TSIG key lookup failure.", addrbuf);
+ goto cleanup_message;
+ }
+
notify_log(notify->zone, ISC_LOG_DEBUG(3), "sending notify to %s",
addrbuf);
if (notify->zone->view->peers != NULL) {
@@ -6774,6 +6851,7 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
cleanup_key:
if (key != NULL)
dns_tsigkey_detach(&key);
+ cleanup_message:
dns_message_destroy(&message);
cleanup:
UNLOCK_ZONE(notify->zone);
@@ -7386,7 +7464,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;
@@ -7609,12 +7687,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,
@@ -7638,7 +7721,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)
@@ -7671,7 +7754,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;
@@ -7965,10 +8048,19 @@ soa_query(isc_task_t *task, isc_event_t *event) {
dns_name_format(keyname, namebuf, sizeof(namebuf));
dns_zone_log(zone, ISC_LOG_ERROR,
"unable to find key: %s", namebuf);
+ goto skip_master;
+ }
+ }
+ if (key == NULL) {
+ result = dns_view_getpeertsig(zone->view, &masterip, &key);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+ char addrbuf[ISC_NETADDR_FORMATSIZE];
+ isc_netaddr_format(&masterip, addrbuf, sizeof(addrbuf));
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "unable to find TSIG key for %s", addrbuf);
+ goto skip_master;
}
}
- if (key == NULL)
- (void)dns_view_getpeertsig(zone->view, &masterip, &key);
have_xfrsource = ISC_FALSE;
reqnsid = zone->view->requestnsid;
@@ -8789,13 +8881,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",
@@ -9473,7 +9573,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");
@@ -9488,11 +9588,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]",
@@ -9685,7 +9789,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,
@@ -9723,7 +9826,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);
}
/*
@@ -9873,6 +9976,13 @@ zone_loaddone(void *arg, isc_result_t result) {
(void)zone_postload(load->zone, load->db, load->loadtime, result);
zonemgr_putio(&load->zone->readio);
DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_LOADING);
+ /*
+ * Leave the zone frozen if the reload fails.
+ */
+ if ((result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) &&
+ DNS_ZONE_FLAG(load->zone, DNS_ZONEFLG_THAW))
+ zone->update_disabled = ISC_FALSE;
+ DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_THAW);
UNLOCK_ZONE(load->zone);
load->magic = 0;
@@ -11508,7 +11618,8 @@ zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid,
cleanup:
if (signing != NULL) {
- dns_db_detach(&signing->db);
+ if (signing->db != NULL)
+ dns_db_detach(&signing->db);
if (signing->dbiterator != NULL)
dns_dbiterator_destroy(&signing->dbiterator);
isc_mem_put(zone->mctx, signing, sizeof *signing);
OpenPOWER on IntegriCloud