diff options
Diffstat (limited to 'contrib/bind9/lib/dns/zone.c')
| -rw-r--r-- | contrib/bind9/lib/dns/zone.c | 245 |
1 files changed, 196 insertions, 49 deletions
diff --git a/contrib/bind9/lib/dns/zone.c b/contrib/bind9/lib/dns/zone.c index 29f99cb1d68a..a993877e91ae 100644 --- a/contrib/bind9/lib/dns/zone.c +++ b/contrib/bind9/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.333.2.23.2.55 2005/02/03 23:50:45 marka Exp $ */ +/* $Id: zone.c,v 1.333.2.23.2.59 2005/07/29 00:38:33 marka Exp $ */ #include <config.h> @@ -167,6 +167,7 @@ struct dns_zone { isc_sockaddr_t *masters; dns_name_t **masterkeynames; + isc_boolean_t *mastersok; unsigned int masterscnt; unsigned int curmaster; isc_sockaddr_t masteraddr; @@ -536,6 +537,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->minretry = DNS_ZONE_MINRETRY; zone->masters = NULL; zone->masterkeynames = NULL; + zone->mastersok = NULL; zone->masterscnt = 0; zone->curmaster = 0; zone->notify = NULL; @@ -590,7 +592,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { free_mutex: DESTROYLOCK(&zone->lock); - return (ISC_R_NOMEMORY); + isc_mem_putanddetach(&zone->mctx, zone, sizeof(*zone)); + return (result); } /* @@ -1250,6 +1253,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_uint32_t serial, 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); TIME_NOW(&now); @@ -1355,10 +1359,32 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, if (result != ISC_R_SUCCESS) goto cleanup; if (zone->db != NULL) { - if (!isc_serial_ge(serial, zone->serial)) { + /* + * This is checked in zone_replacedb() for slave zones + * as they don't reload from disk. + */ + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && + !isc_serial_gt(serial, zone->serial)) { + isc_uint32_t serialmin, serialmax; + + INSIST(zone->type == dns_zone_master); + + serialmin = (zone->serial + 1) & 0xffffffffU; + serialmax = (zone->serial + 0x7fffffffU) & + 0xffffffffU; + dns_zone_log(zone, ISC_LOG_ERROR, + "ixfr-from-differences: " + "new serial (%u) out of range " + "[%u - %u]", serial, serialmin, + serialmax); + result = DNS_R_BADZONE; + goto cleanup; + } else if (!isc_serial_ge(serial, zone->serial)) dns_zone_log(zone, ISC_LOG_ERROR, "zone serial has gone backwards"); - } + else if (serial == zone->serial && !hasinclude) + dns_zone_log(zone, ISC_LOG_ERROR, + "zone serial unchanged"); } zone->serial = serial; zone->refresh = RANGE(refresh, @@ -1943,6 +1969,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters, isc_sockaddr_t *new; isc_result_t result = ISC_R_SUCCESS; dns_name_t **newname; + isc_boolean_t *newok; unsigned int i; REQUIRE(DNS_ZONE_VALID(zone)); @@ -1972,10 +1999,15 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters, zone->masterscnt * sizeof(dns_name_t *)); zone->masterkeynames = NULL; } + if (zone->mastersok != NULL) { + isc_mem_put(zone->mctx, zone->mastersok, + zone->masterscnt * sizeof(isc_boolean_t)); + zone->mastersok = NULL; + } zone->masterscnt = 0; /* - * If count == 0, don't allocate any space for masters or keynames - * so internally, those pointers are NULL if count == 0 + * If count == 0, don't allocate any space for masters, mastersok or + * keynames so internally, those pointers are NULL if count == 0 */ if (count == 0) goto unlock; @@ -1983,27 +2015,35 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters, /* * masters must countain count elements! */ - new = isc_mem_get(zone->mctx, - count * sizeof(isc_sockaddr_t)); + new = isc_mem_get(zone->mctx, count * sizeof(*new)); if (new == NULL) { result = ISC_R_NOMEMORY; goto unlock; } memcpy(new, masters, count * sizeof(*new)); - zone->masters = new; - zone->masterscnt = count; - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS); + + /* + * Similarly for mastersok. + */ + newok = isc_mem_get(zone->mctx, count * sizeof(*newok)); + if (newok == NULL) { + result = ISC_R_NOMEMORY; + isc_mem_put(zone->mctx, new, count * sizeof(*new)); + goto unlock; + }; + for (i = 0; i < count; i++) + newok[i] = ISC_FALSE; /* * if keynames is non-NULL, it must contain count elements! */ + newname = NULL; if (keynames != NULL) { - newname = isc_mem_get(zone->mctx, - count * sizeof(dns_name_t *)); + newname = isc_mem_get(zone->mctx, count * sizeof(*newname)); if (newname == NULL) { result = ISC_R_NOMEMORY; - isc_mem_put(zone->mctx, zone->masters, - count * sizeof(*new)); + isc_mem_put(zone->mctx, new, count * sizeof(*new)); + isc_mem_put(zone->mctx, newok, count * sizeof(*newok)); goto unlock; } for (i = 0; i < count; i++) @@ -2024,16 +2064,27 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters, dns_name_free( newname[i], zone->mctx); - isc_mem_put(zone->mctx, zone->masters, + isc_mem_put(zone->mctx, new, count * sizeof(*new)); + isc_mem_put(zone->mctx, newok, + count * sizeof(*newok)); isc_mem_put(zone->mctx, newname, count * sizeof(*newname)); goto unlock; } } } - zone->masterkeynames = newname; } + + /* + * Everything is ok so attach to the zone. + */ + zone->masters = new; + zone->mastersok = newok; + zone->masterkeynames = newname; + zone->masterscnt = count; + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS); + unlock: UNLOCK_ZONE(zone); return (result); @@ -2222,6 +2273,7 @@ void dns_zone_refresh(dns_zone_t *zone) { isc_interval_t i; isc_uint32_t oldflags; + unsigned int j; REQUIRE(DNS_ZONE_VALID(zone)); @@ -2266,6 +2318,8 @@ dns_zone_refresh(dns_zone_t *zone) { zone->retry = ISC_MIN(zone->retry * 2, 6 * 3600); zone->curmaster = 0; + for (j = 0; j < zone->masterscnt; j++) + zone->mastersok[j] = ISC_FALSE; /* initiate soa query */ queue_soa_query(zone); unlock: @@ -3186,6 +3240,7 @@ stub_callback(isc_task_t *task, isc_event_t *event) { isc_time_t now; isc_boolean_t exiting = ISC_FALSE; isc_interval_t i; + unsigned int j; stub = revent->ev_arg; INSIST(DNS_STUB_VALID(stub)); @@ -3360,13 +3415,37 @@ stub_callback(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); LOCK_ZONE(zone); dns_request_destroy(&zone->request); - zone->curmaster++; + /* + * Skip to next failed / untried master. + */ + do { + zone->curmaster++; + } while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); if (exiting || zone->curmaster >= zone->masterscnt) { + isc_boolean_t done = ISC_TRUE; if (!exiting && DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { + /* + * Did we get a good answer from all the masters? + */ + for (j = 0; j < zone->masterscnt; j++) + if (zone->mastersok[j] == ISC_FALSE) { + done = ISC_FALSE; + break; + } + } else + done = ISC_TRUE; + if (!done) { zone->curmaster = 0; + /* + * Find the next failed master. + */ + while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]) + zone->curmaster++; DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); } else { DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); @@ -3420,6 +3499,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { dns_rdata_soa_t soa; isc_result_t result; isc_uint32_t serial; + unsigned int j; zone = revent->ev_arg; INSIST(DNS_ZONE_VALID(zone)); @@ -3668,6 +3748,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { } DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); + zone->mastersok[zone->curmaster] = ISC_TRUE; goto next_master; } else { if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MULTIMASTER)) @@ -3676,6 +3757,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { soa.serial, master, zone->serial); else zone_debuglog(zone, me, 1, "ahead"); + zone->mastersok[zone->curmaster] = ISC_TRUE; goto next_master; } if (msg != NULL) @@ -3688,13 +3770,37 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); LOCK_ZONE(zone); dns_request_destroy(&zone->request); - zone->curmaster++; + /* + * Skip to next failed / untried master. + */ + do { + zone->curmaster++; + } while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); if (zone->curmaster >= zone->masterscnt) { + isc_boolean_t done = ISC_TRUE; if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { + /* + * Did we get a good answer from all the masters? + */ + for (j = 0; j < zone->masterscnt; j++) + if (zone->mastersok[j] == ISC_FALSE) { + done = ISC_FALSE; + break; + } + } else + done = ISC_TRUE; + if (!done) { DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); zone->curmaster = 0; + /* + * Find the next failed master. + */ + while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]) + zone->curmaster++; goto requeue; } DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); @@ -4023,7 +4129,13 @@ soa_query(isc_task_t *task, isc_event_t *event) { skip_master: if (key != NULL) dns_tsigkey_detach(&key); - zone->curmaster++; + /* + * Skip to next failed / untried master. + */ + do { + zone->curmaster++; + } while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]); if (zone->curmaster < zone->masterscnt) goto again; zone->curmaster = 0; @@ -5275,40 +5387,58 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { * is enabled in the configuration. */ if (zone->db != NULL && zone->journal != NULL && - DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) { - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), - "generating diffs"); - result = dns_db_diff(zone->mctx, db, ver, - zone->db, NULL /* XXX */, + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { + isc_uint32_t serial; + + dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs"); + + result = dns_db_getsoaserial(db, ver, &serial); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "ixfr-from-differences: unable to get " + "new serial"); + goto fail; + } + + /* + * This is checked in zone_postload() for master zones. + */ + if (zone->type == dns_zone_slave && + !isc_serial_gt(serial, zone->serial)) { + isc_uint32_t serialmin, serialmax; + serialmin = (zone->serial + 1) & 0xffffffffU; + serialmax = (zone->serial + 0x7fffffffU) & 0xffffffffU; + dns_zone_log(zone, ISC_LOG_ERROR, + "ixfr-from-differences: failed: " + "new serial (%u) out of range [%u - %u]", + serial, serialmin, serialmax); + result = ISC_R_RANGE; + goto fail; + } + + result = dns_db_diff(zone->mctx, db, ver, zone->db, NULL, zone->journal); if (result != ISC_R_SUCCESS) goto fail; if (dump) zone_needdump(zone, DNS_DUMP_DELAY); else if (zone->journalsize != -1) { - isc_uint32_t serial; - - result = dns_db_getsoaserial(db, ver, &serial); - if (result == ISC_R_SUCCESS) { - result = dns_journal_compact(zone->mctx, - zone->journal, - serial, - zone->journalsize); - switch (result) { - case ISC_R_SUCCESS: - case ISC_R_NOSPACE: - case ISC_R_NOTFOUND: - dns_zone_log(zone, ISC_LOG_DEBUG(3), - "dns_journal_compact: %s", - dns_result_totext(result)); - break; - default: - dns_zone_log(zone, ISC_LOG_ERROR, + result = dns_journal_compact(zone->mctx, zone->journal, + serial, zone->journalsize); + switch (result) { + case ISC_R_SUCCESS: + case ISC_R_NOSPACE: + case ISC_R_NOTFOUND: + dns_zone_log(zone, ISC_LOG_DEBUG(3), + "dns_journal_compact: %s", + dns_result_totext(result)); + break; + default: + dns_zone_log(zone, ISC_LOG_ERROR, "dns_journal_compact failed: %s", - dns_result_totext(result)); - break; - } + dns_result_totext(result)); + break; } } } else { @@ -5503,7 +5633,14 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { default: next_master: - zone->curmaster++; + /* + * Skip to next failed / untried master. + */ + do { + zone->curmaster++; + } while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]); + /* FALLTHROUGH */ same_master: if (zone->curmaster >= zone->masterscnt) { zone->curmaster = 0; @@ -5511,6 +5648,9 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); + while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]) + zone->curmaster++; again = ISC_TRUE; } else DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); @@ -5697,7 +5837,11 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { "requesting AXFR of " "initial version from %s", mastertext); xfrtype = dns_rdatatype_axfr; - } else if (dns_zone_isforced(zone)) { + } else if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), "ixfr-from-differences " + "set, requesting AXFR from %s", mastertext); + xfrtype = dns_rdatatype_axfr; + } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { dns_zone_log(zone, ISC_LOG_DEBUG(1), "forced reload, requesting AXFR of " "initial version from %s", mastertext); @@ -6663,6 +6807,9 @@ void dns_zone_forcereload(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); + if (zone->type == dns_zone_master) + return; + LOCK_ZONE(zone); DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FORCEXFER); UNLOCK_ZONE(zone); |
