diff options
Diffstat (limited to 'lib/dns/zone.c')
-rw-r--r-- | lib/dns/zone.c | 211 |
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, ¬ify->dst); - (void)dns_view_getpeertsig(notify->zone->view, &dstip, &key); - isc_sockaddr_format(¬ify->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); |