Commit message: Update keyfetch_done compute_tag check

If in keyfetch_done the compute_tag fails (because for example the
algorithm is not supported), don't crash, but instead ignore the
key.
CVE: CVE-2018-5745
CWE: CWE-327
Vulnerability description: "managed-keys" is a feature which allows a BIND resolver to automatically maintain the keys used by trust anchors which operators configure for use in DNSSEC validation. Due to an error in the managed-keys feature it is possible for a BIND server which uses managed-keys to exit due to an assertion failure if, during key rollover, a trust anchor's keys are replaced with keys which use an unsupported algorithm. Versions affected: BIND 9.9.0 -> 9.10.8-P1, 9.11.0 -> 9.11.5-P1, 9.12.0 -> 9.12.3-P1, and versions 9.9.3-S1 -> 9.11.5-S3 of BIND 9 Supported Preview Edition. Versions 9.13.0 -> 9.13.6 of the 9.13 development branch are also affected. Versions prior to BIND 9.9.0 have not been evaluated for vulnerability to CVE-2018-5745.

Project: bind9
File: zone.c

zone_sign(dns_zone_t *zone) {
	const char *me = "zone_sign";
	dns_db_t *db = NULL;
	dns_dbnode_t *node = NULL;
	dns_dbversion_t *version = NULL;
	dns_diff_t _sig_diff;
	dns_diff_t post_diff;
	dns__zonediff_t zonediff;
	dns_fixedname_t fixed;
	dns_fixedname_t nextfixed;
	dns_name_t *name, *nextname;
	dns_rdataset_t rdataset;
	dns_signing_t *signing, *nextsigning;
	dns_signinglist_t cleanup;
	dst_key_t *zone_keys[DNS_MAXZONEKEYS];
	int32_t signatures;
	bool check_ksk, keyset_kskonly, is_ksk;
	bool with_ksk, with_zsk;
	bool commit = false;
	bool is_bottom_of_zone;
	bool build_nsec = false;
	bool build_nsec3 = false;
	bool first;
	isc_result_t result;
	isc_stdtime_t now, inception, soaexpire, expire;
	uint32_t jitter, sigvalidityinterval, expiryinterval;
	unsigned int i, j;
	unsigned int nkeys = 0;
	uint32_t nodes;

	ENTER;

	dns_rdataset_init(&rdataset);
	name = dns_fixedname_initname(&fixed);
	nextname = dns_fixedname_initname(&nextfixed);
	dns_diff_init(zone->mctx, &_sig_diff);
	dns_diff_init(zone->mctx, &post_diff);
	zonediff_init(&zonediff, &_sig_diff);
	ISC_LIST_INIT(cleanup);

	/*
	 * Updates are disabled.  Pause for 1 minute.
	 */
	if (zone->update_disabled) {
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	if (zone->db != NULL) {
		dns_db_attach(zone->db, &db);
	}
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
	if (db == NULL) {
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	result = dns_db_newversion(db, &version);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_sign:dns_db_newversion -> %s",
			   dns_result_totext(result));
		goto cleanup;
	}

	isc_stdtime_get(&now);

	result = dns__zone_findkeys(zone, db, version, now, zone->mctx,
				    DNS_MAXZONEKEYS, zone_keys, &nkeys);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_sign:dns__zone_findkeys -> %s",
			   dns_result_totext(result));
		goto cleanup;
	}

	sigvalidityinterval = dns_zone_getsigvalidityinterval(zone);
	inception = now - 3600;	/* Allow for clock skew. */
	soaexpire = now + sigvalidityinterval;
	expiryinterval = dns_zone_getsigresigninginterval(zone);
	if (expiryinterval > sigvalidityinterval) {
		expiryinterval = sigvalidityinterval;
	} else {
		expiryinterval = sigvalidityinterval - expiryinterval;
	}

	/*
	 * Spread out signatures over time if they happen to be
	 * clumped.  We don't do this for each add_sigs() call as
	 * we still want some clustering to occur.
	 */
	if (sigvalidityinterval >= 3600U) {
		if (sigvalidityinterval > 7200U) {
			jitter = isc_random_uniform(expiryinterval);
		} else {
			jitter = isc_random_uniform(1200);
		}
		expire = soaexpire - jitter - 1;
	} else {
		expire = soaexpire - 1;
	}

	/*
	 * We keep pulling nodes off each iterator in turn until
	 * we have no more nodes to pull off or we reach the limits
	 * for this quantum.
	 */
	nodes = zone->nodes;
	signatures = zone->signatures;
	signing = ISC_LIST_HEAD(zone->signing);
	first = true;

	check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
	keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY);

	/* Determine which type of chain to build */
	CHECK(dns_private_chains(db, version, zone->privatetype,
				 &build_nsec, &build_nsec3));

	/* If neither chain is found, default to NSEC */
	if (!build_nsec && !build_nsec3) {
		build_nsec = true;
	}

	while (signing != NULL && nodes-- > 0 && signatures > 0) {
		bool has_alg = false;
		nextsigning = ISC_LIST_NEXT(signing, link);

		ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
		if (signing->done || signing->db != zone->db) {
			/*
			 * The zone has been reloaded.	We will have
			 * created new signings as part of the reload
			 * process so we can destroy this one.
			 */
			ISC_LIST_UNLINK(zone->signing, signing, link);
			ISC_LIST_APPEND(cleanup, signing, link);
			ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
			goto next_signing;
		}
		ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);

		if (signing->db != db) {
			goto next_signing;
		}

		is_bottom_of_zone = false;

		if (first && signing->deleteit) {
			/*
			 * Remove the key we are deleting from consideration.
			 */
			for (i = 0, j = 0; i < nkeys; i++) {
				/*
				 * Find the key we want to remove.
				 */
				if (ALG(zone_keys[i]) == signing->algorithm &&
				    dst_key_id(zone_keys[i]) == signing->keyid)
				{
					if (KSK(zone_keys[i]))
						dst_key_free(&zone_keys[i]);
					continue;
				}
				zone_keys[j] = zone_keys[i];
				j++;
			}
			for (i = j; i < nkeys; i++) {
				zone_keys[i] = NULL;
			}
			nkeys = j;
		}

		dns_dbiterator_current(signing->dbiterator, &node, name);

		if (signing->deleteit) {
			dns_dbiterator_pause(signing->dbiterator);
			CHECK(del_sig(db, version, name, node, nkeys,
				      signing->algorithm, signing->keyid,
				      &has_alg, zonediff.diff));
		}

		/*
		 * On the first pass we need to check if the current node
		 * has not been obscured.
		 */
		if (first) {
			dns_fixedname_t ffound;
			dns_name_t *found;
			found = dns_fixedname_initname(&ffound);
			result = dns_db_find(db, name, version,
					     dns_rdatatype_soa,
					     DNS_DBFIND_NOWILD, 0, NULL, found,
					     NULL, NULL);
			if ((result == DNS_R_DELEGATION ||
			     result == DNS_R_DNAME) &&
			    !dns_name_equal(name, found))
			{
				/*
				 * Remember the obscuring name so that
				 * we skip all obscured names.
				 */
				dns_name_copy(found, name, NULL);
				is_bottom_of_zone = true;
				goto next_node;
			}
		}

		/*
		 * Process one node.
		 */
		with_ksk = false;
		with_zsk = false;
		dns_dbiterator_pause(signing->dbiterator);

		CHECK(check_if_bottom_of_zone(db, node, version,
					      &is_bottom_of_zone));

		for (i = 0; !has_alg && i < nkeys; i++) {
			bool both = false;

			/*
			 * Find the keys we want to sign with.
			 */
			if (!dst_key_isprivate(zone_keys[i])) {
				continue;
			}
			/*
			 * Should be redundant.
			 */
			if (dst_key_inactive(zone_keys[i])) {
				continue;
			}

			/*
			 * When adding look for the specific key.
			 */
			if (!signing->deleteit &&
			    (dst_key_alg(zone_keys[i]) != signing->algorithm ||
			     dst_key_id(zone_keys[i]) != signing->keyid))
			{
				continue;
			}

			/*
			 * When deleting make sure we are properly signed
			 * with the algorithm that was being removed.
			 */
			if (signing->deleteit &&
			    ALG(zone_keys[i]) != signing->algorithm)
			{
				continue;
			}

			/*
			 * Do we do KSK processing?
			 */
			if (check_ksk && !REVOKE(zone_keys[i])) {
				bool have_ksk, have_nonksk;
				if (KSK(zone_keys[i])) {
					have_ksk = true;
					have_nonksk = false;
				} else {
					have_ksk = false;
					have_nonksk = true;
				}
				for (j = 0; j < nkeys; j++) {
					if (j == i ||
					    (ALG(zone_keys[i]) !=
					     ALG(zone_keys[j])))
					{
						continue;
					}
					if (!dst_key_isprivate(zone_keys[j])) {
						continue;
					}
					/*
					 * Should be redundant.
					 */
					if (dst_key_inactive(zone_keys[j])) {
						continue;
					}
					if (REVOKE(zone_keys[j])) {
						continue;
					}
					if (KSK(zone_keys[j])) {
						have_ksk = true;
					} else {
						have_nonksk = true;
					}
					both = have_ksk && have_nonksk;
					if (both) {
						break;
					}
				}
			}
			if (both || REVOKE(zone_keys[i])) {
				is_ksk = KSK(zone_keys[i]);
			} else {
				is_ksk = false;
			}

			/*
			 * If deleting signatures, we need to ensure that
			 * the RRset is still signed at least once by a
			 * KSK and a ZSK.
			 */
			if (signing->deleteit && !is_ksk && with_zsk) {
				continue;
			}

			if (signing->deleteit && is_ksk && with_ksk) {
				continue;
			}

			CHECK(sign_a_node(db, name, node, version, build_nsec3,
					  build_nsec, zone_keys[i], inception,
					  expire, zone->minimum, is_ksk,
					  (both && keyset_kskonly),
					  is_bottom_of_zone, zonediff.diff,
					  &signatures, zone->mctx));
			/*
			 * If we are adding we are done.  Look for other keys
			 * of the same algorithm if deleting.
			 */
			if (!signing->deleteit) {
				break;
			}
			if (!is_ksk) {
				with_zsk = true;
			}
			if (KSK(zone_keys[i])) {
				with_ksk = true;
			}
		}

		/*
		 * Go onto next node.
		 */
 next_node:
		first = false;
		dns_db_detachnode(db, &node);
		do {
			result = dns_dbiterator_next(signing->dbiterator);
			if (result == ISC_R_NOMORE) {
				ISC_LIST_UNLINK(zone->signing, signing, link);
				ISC_LIST_APPEND(cleanup, signing, link);
				dns_dbiterator_pause(signing->dbiterator);
				if (nkeys != 0 && build_nsec) {
					/*
					 * We have finished regenerating the
					 * zone with a zone signing key.
					 * The NSEC chain is now complete and
					 * there is a full set of signatures
					 * for the zone.  We can now clear the
					 * OPT bit from the NSEC record.
					 */
					result = updatesecure(db, version,
							      &zone->origin,
							      zone->minimum,
							      false,
							      &post_diff);
					if (result != ISC_R_SUCCESS) {
						dnssec_log(zone, ISC_LOG_ERROR,
						   "updatesecure -> %s",
						    dns_result_totext(result));
						goto cleanup;
					}
				}
				result = updatesignwithkey(zone, signing,
							   version,
							   build_nsec3,
							   zone->minimum,
							   &post_diff);
				if (result != ISC_R_SUCCESS) {
					dnssec_log(zone, ISC_LOG_ERROR,
						   "updatesignwithkey -> %s",
						   dns_result_totext(result));
					goto cleanup;
				}
				build_nsec = false;
				goto next_signing;
			} else if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_sign:"
					   "dns_dbiterator_next -> %s",
					   dns_result_totext(result));
				goto cleanup;
			} else if (is_bottom_of_zone) {
				dns_dbiterator_current(signing->dbiterator,
						       &node, nextname);
				dns_db_detachnode(db, &node);
				if (!dns_name_issubdomain(nextname, name)) {
					break;
				}
			} else {
				break;
			}
		} while (1);
		continue;

 next_signing:
		dns_dbiterator_pause(signing->dbiterator);
		signing = nextsigning;
		first = true;
	}

	if (ISC_LIST_HEAD(post_diff.tuples) != NULL) {
		result = dns__zone_updatesigs(&post_diff, db, version,
					      zone_keys, nkeys, zone,
					      inception, expire, 0, now,
					      check_ksk, keyset_kskonly,
					      &zonediff);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "zone_sign:dns__zone_updatesigs -> %s",
				   dns_result_totext(result));
			goto cleanup;
		}
	}

	/*
	 * Have we changed anything?
	 */
	if (ISC_LIST_EMPTY(zonediff.diff->tuples)) {
		if (zonediff.offline) {
			commit = true;
		}
		result = ISC_R_SUCCESS;
		goto pauseall;
	}

	commit = true;

	result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
			  &zonediff, zone_keys, nkeys, now, false);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR, "zone_sign:del_sigs -> %s",
			   dns_result_totext(result));
		goto cleanup;
	}

	result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
				   zone->updatemethod);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_sign:update_soa_serial -> %s",
			   dns_result_totext(result));
		goto cleanup;
	}

	/*
	 * Generate maximum life time signatures so that the above loop
	 * termination is sensible.
	 */
	result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa,
			  zonediff.diff, zone_keys, nkeys, zone->mctx,
			  inception, soaexpire, check_ksk, keyset_kskonly);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR, "zone_sign:add_sigs -> %s",
			   dns_result_totext(result));
		goto cleanup;
	}

	/*
	 * Write changes to journal file.
	 */
	CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_sign"));

 pauseall:
	/*
	 * Pause all iterators so that dns_db_closeversion() can succeed.
	 */
	for (signing = ISC_LIST_HEAD(zone->signing);
	     signing != NULL;
	     signing = ISC_LIST_NEXT(signing, link))
	{
		dns_dbiterator_pause(signing->dbiterator);
	}

	for (signing = ISC_LIST_HEAD(cleanup);
	     signing != NULL;
	     signing = ISC_LIST_NEXT(signing, link))
	{
		dns_dbiterator_pause(signing->dbiterator);
	}

	/*
	 * Everything has succeeded. Commit the changes.
	 */
	dns_db_closeversion(db, &version, commit);

	/*
	 * Everything succeeded so we can clean these up now.
	 */
	signing = ISC_LIST_HEAD(cleanup);
	while (signing != NULL) {
		ISC_LIST_UNLINK(cleanup, signing, link);
		dns_db_detach(&signing->db);
		dns_dbiterator_destroy(&signing->dbiterator);
		isc_mem_put(zone->mctx, signing, sizeof *signing);
		signing = ISC_LIST_HEAD(cleanup);
	}

	set_resigntime(zone);

	if (commit) {
		LOCK_ZONE(zone);
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
		zone_needdump(zone, DNS_DUMP_DELAY);
		UNLOCK_ZONE(zone);
	}

 failure:
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR, "zone_sign: failed: %s",
			   dns_result_totext(result));
	}

 cleanup:
	/*
	 * Pause all dbiterators.
	 */
	for (signing = ISC_LIST_HEAD(zone->signing);
	     signing != NULL;
	     signing = ISC_LIST_NEXT(signing, link))
	{
		dns_dbiterator_pause(signing->dbiterator);
	}

	/*
	 * Rollback the cleanup list.
	 */
	signing = ISC_LIST_HEAD(cleanup);
	while (signing != NULL) {
		ISC_LIST_UNLINK(cleanup, signing, link);
		ISC_LIST_PREPEND(zone->signing, signing, link);
		dns_dbiterator_first(signing->dbiterator);
		dns_dbiterator_pause(signing->dbiterator);
		signing = ISC_LIST_HEAD(cleanup);
	}

	dns_diff_clear(&_sig_diff);

	for (i = 0; i < nkeys; i++) {
		dst_key_free(&zone_keys[i]);
	}

	if (node != NULL) {
		dns_db_detachnode(db, &node);
	}

	if (version != NULL) {
		dns_db_closeversion(db, &version, false);
		dns_db_detach(&db);
	} else if (db != NULL) {
		dns_db_detach(&db);
	}

	if (ISC_LIST_HEAD(zone->signing) != NULL) {
		isc_interval_t interval;
		if (zone->update_disabled || result != ISC_R_SUCCESS) {
			isc_interval_set(&interval, 60, 0);	  /* 1 minute */
		} else {
			isc_interval_set(&interval, 0, 10000000); /* 10 ms */
		}
		isc_time_nowplusinterval(&zone->signingtime, &interval);
	} else {
		isc_time_settoepoch(&zone->signingtime);
	}

	INSIST(version == NULL);
}

Project: bind9
File: zone.c

set_key_expiry_warning(dns_zone_t *zone, isc_stdtime_t when, isc_stdtime_t now)
{
	unsigned int delta;
	char timebuf[80];

	zone->key_expiry = when;
	if (when <= now) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "DNSKEY RRSIG(s) have expired");
		isc_time_settoepoch(&zone->keywarntime);
	} else if (when < now + 7 * 24 * 3600) {
		isc_time_t t;
		isc_time_set(&t, when, 0);
		isc_time_formattimestamp(&t, timebuf, 80);
		dns_zone_log(zone, ISC_LOG_WARNING,
			     "DNSKEY RRSIG(s) will expire within 7 days: %s",
			     timebuf);
		delta = when - now;
		delta--;		/* loop prevention */
		delta /= 24 * 3600;	/* to whole days */
		delta *= 24 * 3600;	/* to seconds */
		isc_time_set(&zone->keywarntime, when - delta, 0);
	}  else {
		isc_time_set(&zone->keywarntime, when - 7 * 24 * 3600, 0);
		isc_time_formattimestamp(&zone->keywarntime, timebuf, 80);
		dns_zone_log(zone, ISC_LOG_NOTICE,
			     "setting keywarntime to %s", timebuf);
	}
}

Project: bind9
File: zone.c

zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
	isc_time_t now;
	bool again = false;
	unsigned int soacount;
	unsigned int nscount;
	uint32_t serial, refresh, retry, expire, minimum;
	isc_result_t xfrresult = result;
	bool free_needed;
	dns_zone_t *secure = NULL;

	REQUIRE(DNS_ZONE_VALID(zone));

	dns_zone_log(zone, ISC_LOG_DEBUG(1),
		     "zone transfer finished: %s", dns_result_totext(result));

	/*
	 * Obtaining a lock on the zone->secure (see zone_send_secureserial)
	 * could result in a deadlock due to a LOR so we will spin if we
	 * can't obtain the both locks.
	 */
 again:
	LOCK_ZONE(zone);
	if (inline_raw(zone)) {
		secure = zone->secure;
		INSIST(secure != zone);
		TRYLOCK_ZONE(result, secure);
		if (result != ISC_R_SUCCESS) {
			UNLOCK_ZONE(zone);
			secure = NULL;
			isc_thread_yield();
			goto again;
		}
	}

	INSIST((zone->flags & DNS_ZONEFLG_REFRESH) != 0);
	DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
	DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR);

	TIME_NOW(&now);
	switch (xfrresult) {
	case ISC_R_SUCCESS:
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
		/* FALLTHROUGH */
	case DNS_R_UPTODATE:
		DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FORCEXFER);
		/*
		 * Has the zone expired underneath us?
		 */
		ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
		if (zone->db == NULL) {
			ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
			goto same_master;
		}

		/*
		 * Update the zone structure's data from the actual
		 * SOA received.
		 */
		nscount = 0;
		soacount = 0;
		INSIST(zone->db != NULL);
		result = zone_get_from_db(zone, zone->db, &nscount,
					  &soacount, &serial, &refresh,
					  &retry, &expire, &minimum, NULL);
		ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
		if (result == ISC_R_SUCCESS) {
			if (soacount != 1)
				dns_zone_log(zone, ISC_LOG_ERROR,
					     "transferred zone "
					     "has %d SOA record%s", soacount,
					     (soacount != 0) ? "s" : "");
			if (nscount == 0) {
				dns_zone_log(zone, ISC_LOG_ERROR,
					     "transferred zone "
					     "has no NS records");
				if (DNS_ZONE_FLAG(zone,
						  DNS_ZONEFLG_HAVETIMERS)) {
					zone->refresh = DNS_ZONE_DEFAULTREFRESH;
					zone->retry = DNS_ZONE_DEFAULTRETRY;
				}
				DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
				zone_unload(zone);
				goto next_master;
			}
			zone->refresh = RANGE(refresh, zone->minrefresh,
					      zone->maxrefresh);
			zone->retry = RANGE(retry, zone->minretry,
					    zone->maxretry);
			zone->expire = RANGE(expire,
					     zone->refresh + zone->retry,
					     DNS_MAX_EXPIRE);
			zone->minimum = minimum;
			DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
		}

		/*
		 * Set our next update/expire times.
		 */
		if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) {
			DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH);
			zone->refreshtime = now;
			DNS_ZONE_TIME_ADD(&now, zone->expire,
					  &zone->expiretime);
		} else {
			DNS_ZONE_JITTER_ADD(&now, zone->refresh,
					    &zone->refreshtime);
			DNS_ZONE_TIME_ADD(&now, zone->expire,
					  &zone->expiretime);
		}
		if (result == ISC_R_SUCCESS && xfrresult == ISC_R_SUCCESS) {
			char buf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")];
			if (zone->tsigkey != NULL) {
				char namebuf[DNS_NAME_FORMATSIZE];
				dns_name_format(&zone->tsigkey->name, namebuf,
						sizeof(namebuf));
				snprintf(buf, sizeof(buf), ": TSIG '%s'",
					 namebuf);
			} else
				buf[0] = '\0';
			dns_zone_log(zone, ISC_LOG_INFO,
				     "transferred serial %u%s",
				     serial, buf);
			if (inline_raw(zone))
				zone_send_secureserial(zone, serial);
		}

		/*
		 * This is not necessary if we just performed a AXFR
		 * however it is necessary for an IXFR / UPTODATE and
		 * won't hurt with an AXFR.
		 */
		if (zone->masterfile != NULL || zone->journal != NULL) {
			unsigned int delay = DNS_DUMP_DELAY;

			result = ISC_R_FAILURE;
			if (zone->journal != NULL)
				result = isc_file_settime(zone->journal, &now);
			if (result != ISC_R_SUCCESS &&
			    zone->masterfile != NULL)
				result = isc_file_settime(zone->masterfile,
							  &now);

			if ((DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NODELAY) != 0) ||
			    result == ISC_R_FILENOTFOUND)
				delay = 0;

			if ((result == ISC_R_SUCCESS ||
			    result == ISC_R_FILENOTFOUND) &&
			    zone->masterfile != NULL)
				zone_needdump(zone, delay);
			else if (result != ISC_R_SUCCESS)
				dns_zone_log(zone, ISC_LOG_ERROR,
					     "transfer: could not set file "
					     "modification time of '%s': %s",
					     zone->masterfile,
					     dns_result_totext(result));
		}
		DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NODELAY);
		inc_stats(zone, dns_zonestatscounter_xfrsuccess);
		break;

	case DNS_R_BADIXFR:
		/* Force retry with AXFR. */
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLAG_NOIXFR);
		goto same_master;

	case DNS_R_TOOMANYRECORDS:
	case DNS_R_VERIFYFAILURE:
		DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
		inc_stats(zone, dns_zonestatscounter_xfrfail);
		break;

	default:
	next_master:
		/*
		 * 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;
			if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) &&
			    !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 = true;
			} else
				DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
		} else {
			DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH);
			again = true;
		}
		inc_stats(zone, dns_zonestatscounter_xfrfail);
		break;
	}
	zone_settimer(zone, &now);

	/*
	 * If creating the transfer object failed, zone->xfr is NULL.
	 * Otherwise, we are called as the done callback of a zone
	 * transfer object that just entered its shutting-down
	 * state.  Since we are no longer responsible for shutting
	 * it down, we can detach our reference.
	 */
	if (zone->xfr != NULL)
		dns_xfrin_detach(&zone->xfr);

	if (zone->tsigkey != NULL)
		dns_tsigkey_detach(&zone->tsigkey);

	/*
	 * Handle any deferred journal compaction.
	 */
	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDCOMPACT)) {
		dns_db_t *db = NULL;
		if (dns_zone_getdb(zone, &db) == ISC_R_SUCCESS) {
			zone_journal_compact(zone, db, zone->compact_serial);
			dns_db_detach(&db);
			DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT);
		}
	}

	if (secure != NULL)
		UNLOCK_ZONE(secure);
	/*
	 * This transfer finishing freed up a transfer quota slot.
	 * Let any other zones waiting for quota have it.
	 */
	if (zone->zmgr != NULL &&
	    zone->statelist == &zone->zmgr->xfrin_in_progress) {
		UNLOCK_ZONE(zone);
		RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
		ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink);
		zone->statelist = NULL;
		zmgr_resume_xfrs(zone->zmgr, false);
		RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
		LOCK_ZONE(zone);
	}

	/*
	 * Retry with a different server if necessary.
	 */
	if (again && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
		queue_soa_query(zone);

	INSIST(zone->irefs > 0);
	zone->irefs--;
	free_needed = exit_check(zone);
	UNLOCK_ZONE(zone);
	if (free_needed)
		zone_free(zone);
}

Project: bind9
File: zone.c

dns_zone_gettype(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->type);
}

Project: bind9
File: zone.c

dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify,
		       uint32_t count)
{
	return (dns_zone_setalsonotifydscpkeys(zone, notify, NULL, NULL,
					       count));
}

Project: bind9
File: zone.c

was_dumping(dns_zone_t *zone) {
	bool dumping;

	REQUIRE(LOCKED_ZONE(zone));

	dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING);
	DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
	if (!dumping) {
		DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
		isc_time_settoepoch(&zone->dumptime);
	}
	return (dumping);
}

Project: bind9
File: zone.c

dns_zone_setrequestixfr(dns_zone_t *zone, bool flag) {
	REQUIRE(DNS_ZONE_VALID(zone));
	zone->requestixfr = flag;
}

Project: bind9
File: zone.c

notify_log(dns_zone_t *zone, int level, const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	dns_zone_logv(zone, DNS_LOGCATEGORY_NOTIFY, level, NULL, fmt, ap);
	va_end(ap);
}

Project: bind9
File: zone.c

dns_zone_getexpiretime(dns_zone_t *zone, isc_time_t *expiretime) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(expiretime != NULL);

	LOCK_ZONE(zone);
	*expiretime = zone->expiretime;
	UNLOCK_ZONE(zone);
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zone_getqueryacl(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->query_acl);
}

Project: bind9
File: zone.c

dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg,
		       dns_updatecallback_t callback, void *callback_arg)
{
	dns_forward_t *forward;
	isc_result_t result;
	isc_region_t *mr;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(msg != NULL);
	REQUIRE(callback != NULL);

	forward = isc_mem_get(zone->mctx, sizeof(*forward));
	if (forward == NULL)
		return (ISC_R_NOMEMORY);

	forward->request = NULL;
	forward->zone = NULL;
	forward->msgbuf = NULL;
	forward->which = 0;
	forward->mctx = 0;
	forward->callback = callback;
	forward->callback_arg = callback_arg;
	ISC_LINK_INIT(forward, link);
	forward->magic = FORWARD_MAGIC;
	forward->options = DNS_REQUESTOPT_TCP;
	/*
	 * If we have a SIG(0) signed message we need to preserve the
	 * query id as that is included in the SIG(0) computation.
	 */
	if (msg->sig0 != NULL)
		forward->options |= DNS_REQUESTOPT_FIXEDID;

	mr = dns_message_getrawmessage(msg);
	if (mr == NULL) {
		result = ISC_R_UNEXPECTEDEND;
		goto cleanup;
	}

	result = isc_buffer_allocate(zone->mctx, &forward->msgbuf, mr->length);
	if (result != ISC_R_SUCCESS)
		goto cleanup;
	result = isc_buffer_copyregion(forward->msgbuf, mr);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	isc_mem_attach(zone->mctx, &forward->mctx);
	dns_zone_iattach(zone, &forward->zone);
	result = sendtomaster(forward);

 cleanup:
	if (result != ISC_R_SUCCESS) {
		forward_destroy(forward);
	}
	return (result);
}

Project: bind9
File: zone.c

zonemgr_cancelio(dns_io_t *io) {
	bool send_event = false;

	REQUIRE(DNS_IO_VALID(io));

	/*
	 * If we are queued to be run then dequeue.
	 */
	LOCK(&io->zmgr->iolock);
	if (ISC_LINK_LINKED(io, link)) {
		if (io->high)
			ISC_LIST_UNLINK(io->zmgr->high, io, link);
		else
			ISC_LIST_UNLINK(io->zmgr->low, io, link);

		send_event = true;
		INSIST(io->event != NULL);
	}
	UNLOCK(&io->zmgr->iolock);
	if (send_event) {
		io->event->ev_attributes |= ISC_EVENTATTR_CANCELED;
		isc_task_send(io->task, &io->event);
	}
}

Project: bind9
File: zone.c

dns_zone_getrequeststats(dns_zone_t *zone) {
	/*
	 * We don't lock zone for efficiency reason.  This is not catastrophic
	 * because requeststats must always be valid when requeststats_on is
	 * true.
	 * Some counters may be incremented while requeststats_on is becoming
	 * false, or some cannot be incremented just after the statistics are
	 * installed, but it shouldn't matter much in practice.
	 */
	if (zone->requeststats_on)
		return (zone->requeststats);
	else
		return (NULL);
}

Project: bind9
File: zone.c

dns_zone_getmctx(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->mctx);
}

Project: bind9
File: zone.c

zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node,
		 dns_dbversion_t *version, unsigned int *nscount,
		 unsigned int *errors, bool logit)
{
	isc_result_t result;
	unsigned int count = 0;
	unsigned int ecount = 0;
	dns_rdataset_t rdataset;
	dns_rdata_t rdata;
	dns_rdata_ns_t ns;

	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns,
				     dns_rdatatype_none, 0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto success;
	}
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto invalidate_rdataset;
	}

	result = dns_rdataset_first(&rdataset);
	while (result == ISC_R_SUCCESS) {
		if (errors != NULL && zone->rdclass == dns_rdataclass_in &&
		    (zone->type == dns_zone_master ||
		     zone->type == dns_zone_slave ||
		     zone->type == dns_zone_mirror))
		{
			dns_rdata_init(&rdata);
			dns_rdataset_current(&rdataset, &rdata);
			result = dns_rdata_tostruct(&rdata, &ns, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			if (dns_name_issubdomain(&ns.name, &zone->origin) &&
			    !zone_check_ns(zone, db, version, &ns.name, logit))
				ecount++;
		}
		count++;
		result = dns_rdataset_next(&rdataset);
	}
	dns_rdataset_disassociate(&rdataset);

 success:
	if (nscount != NULL)
		*nscount = count;
	if (errors != NULL)
		*errors = ecount;

	result = ISC_R_SUCCESS;

 invalidate_rdataset:
	dns_rdataset_invalidate(&rdataset);

	return (result);
}

Project: bind9
File: zone.c

dns_zone_getforwardacl(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->forward_acl);
}

Project: bind9
File: zone.c

delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
	    dns_name_t *name, dns_diff_t *diff)
{
	dns_rdataset_t rdataset;
	isc_result_t result;

	dns_rdataset_init(&rdataset);

	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
				     0, 0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND)
		return (ISC_R_SUCCESS);
	if (result != ISC_R_SUCCESS)
		return (result);
	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset)) {
		dns_rdata_t rdata = DNS_RDATA_INIT;

		dns_rdataset_current(&rdataset, &rdata);
		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name,
				    rdataset.ttl, &rdata));
	}
	if (result == ISC_R_NOMORE)
		result = ISC_R_SUCCESS;
 failure:
	dns_rdataset_disassociate(&rdataset);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_getaltxfrsource6dscp(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->altxfrsource6dscp);
}

Project: bind9
File: zone.c

dns_zone_getserialupdatemethod(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return(zone->updatemethod);
}

Project: bind9
File: zone.c

dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version,
		     dst_key_t *zone_keys[], unsigned int nkeys,
		     dns_zone_t *zone, isc_stdtime_t inception,
		     isc_stdtime_t expire, isc_stdtime_t keyexpire,
		     isc_stdtime_t now, bool check_ksk,
		     bool keyset_kskonly, dns__zonediff_t *zonediff)
{
	dns_difftuple_t *tuple;
	isc_result_t result;

	while ((tuple = ISC_LIST_HEAD(diff->tuples)) != NULL) {
		isc_stdtime_t exp = expire;

		if (keyexpire != 0 &&
		    (tuple->rdata.type == dns_rdatatype_dnskey ||
		     tuple->rdata.type == dns_rdatatype_cdnskey ||
		     tuple->rdata.type == dns_rdatatype_cds))
		{
			exp = keyexpire;
		}

		result = del_sigs(zone, db, version, &tuple->name,
				  tuple->rdata.type, zonediff,
				  zone_keys, nkeys, now, false);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "dns__zone_updatesigs:del_sigs -> %s",
				     dns_result_totext(result));
			return (result);
		}
		result = add_sigs(db, version, &tuple->name,
				  tuple->rdata.type, zonediff->diff,
				  zone_keys, nkeys, zone->mctx, inception,
				  exp, check_ksk, keyset_kskonly);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "dns__zone_updatesigs:add_sigs -> %s",
				     dns_result_totext(result));
			return (result);
		}

		/*
		 * Signature changes for all RRs with name tuple->name and type
		 * tuple->rdata.type were appended to zonediff->diff.  Now we
		 * remove all the "raw" changes with the same name and type
		 * from diff (so that they are not processed by this loop
		 * again) and append them to zonediff so that they get applied.
		 */
		move_matching_tuples(tuple, diff, zonediff->diff);
	}
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) {
	dns_zone_t *p;

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
	for (p = ISC_LIST_HEAD(zmgr->zones);
	     p != NULL;
	     p = ISC_LIST_NEXT(p, link))
	{
		dns_zone_maintenance(p);
	}
	RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);

	/*
	 * Recent configuration changes may have increased the
	 * amount of available transfers quota.  Make sure any
	 * transfers currently blocked on quota get started if
	 * possible.
	 */
	RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	zmgr_resume_xfrs(zmgr, true);
	RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

clear_addresskeylist(isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp,
		     dns_name_t ***keynamesp, unsigned int *countp,
		     isc_mem_t *mctx)
{
	unsigned int count;
	isc_sockaddr_t *addrs;
	isc_dscp_t *dscps;
	dns_name_t **keynames;

	REQUIRE(countp != NULL && addrsp != NULL && dscpsp != NULL &&
		keynamesp != NULL);

	count = *countp;
	*countp = 0;
	addrs = *addrsp;
	*addrsp = NULL;
	dscps = *dscpsp;
	*dscpsp = NULL;
	keynames = *keynamesp;
	*keynamesp = NULL;

	if (addrs != NULL)
		isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t));

	if (dscps != NULL)
		isc_mem_put(mctx, dscps, count * sizeof(isc_dscp_t));

	if (keynames != NULL) {
		unsigned int i;
		for (i = 0; i < count; i++) {
			if (keynames[i] != NULL) {
				dns_name_free(keynames[i], mctx);
				isc_mem_put(mctx, keynames[i],
					    sizeof(dns_name_t));
				keynames[i] = NULL;
			}
		}
		isc_mem_put(mctx, keynames, count * sizeof(dns_name_t *));
	}
}

Project: bind9
File: zone.c

next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname,
	    dns_name_t *newname, bool bottom)
{
	isc_result_t result;
	dns_dbiterator_t *dbit = NULL;
	dns_rdatasetiter_t *rdsit = NULL;
	dns_dbnode_t *node = NULL;

	CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
	CHECK(dns_dbiterator_seek(dbit, oldname));
	do {
		result = dns_dbiterator_next(dbit);
		if (result == ISC_R_NOMORE)
			CHECK(dns_dbiterator_first(dbit));
		CHECK(dns_dbiterator_current(dbit, &node, newname));
		if (bottom && dns_name_issubdomain(newname, oldname) &&
		    !dns_name_equal(newname, oldname)) {
			dns_db_detachnode(db, &node);
			continue;
		}
		/*
		 * Is this node empty?
		 */
		CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsit));
		result = dns_rdatasetiter_first(rdsit);
		dns_db_detachnode(db, &node);
		dns_rdatasetiter_destroy(&rdsit);
		if (result != ISC_R_NOMORE)
			break;
	} while (1);
 failure:
	if (node != NULL)
		dns_db_detachnode(db, &node);
	if (dbit != NULL)
		dns_dbiterator_destroy(&dbit);
	return (result);
}

Project: bind9
File: zone.c

revocable(dns_keyfetch_t *kfetch, dns_rdata_keydata_t *keydata) {
	isc_result_t result;
	dns_name_t *keyname;
	isc_mem_t *mctx;
	dns_rdata_t sigrr = DNS_RDATA_INIT;
	dns_rdata_t rr = DNS_RDATA_INIT;
	dns_rdata_rrsig_t sig;
	dns_rdata_dnskey_t dnskey;
	dst_key_t *dstkey = NULL;
	unsigned char key_buf[4096];
	isc_buffer_t keyb;
	bool answer = false;

	REQUIRE(kfetch != NULL && keydata != NULL);
	REQUIRE(dns_rdataset_isassociated(&kfetch->dnskeysigset));

	keyname = dns_fixedname_name(&kfetch->name);
	mctx = kfetch->zone->view->mctx;

	/* Generate a key from keydata */
	isc_buffer_init(&keyb, key_buf, sizeof(key_buf));
	dns_keydata_todnskey(keydata, &dnskey, NULL);
	dns_rdata_fromstruct(&rr, keydata->common.rdclass,
			     dns_rdatatype_dnskey, &dnskey, &keyb);
	result = dns_dnssec_keyfromrdata(keyname, &rr, mctx, &dstkey);
	if (result != ISC_R_SUCCESS) {
		return (false);
	}

	/* See if that key generated any of the signatures */
	for (result = dns_rdataset_first(&kfetch->dnskeysigset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&kfetch->dnskeysigset))
	{
		dns_fixedname_t fixed;
		dns_fixedname_init(&fixed);

		dns_rdata_reset(&sigrr);
		dns_rdataset_current(&kfetch->dnskeysigset, &sigrr);
		result = dns_rdata_tostruct(&sigrr, &sig, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);

		if (dst_key_alg(dstkey) == sig.algorithm &&
		    dst_key_rid(dstkey) == sig.keyid)
		{
			result = dns_dnssec_verify(keyname,
						   &kfetch->dnskeyset,
						   dstkey, false, 0, mctx,
						   &sigrr,
						   dns_fixedname_name(&fixed));

			dnssec_log(kfetch->zone, ISC_LOG_DEBUG(3),
				   "Confirm revoked DNSKEY is self-signed: %s",
				   dns_result_totext(result));

			if (result == ISC_R_SUCCESS) {
				answer = true;
				break;
			}
		}
	}

	dst_key_free(&dstkey);
	return (answer);
}

Project: bind9
File: zone.c

dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	zone->xfrsource6 = *xfrsource;
	UNLOCK_ZONE(zone);

	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zone_getkeydirectory(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->keydirectory);
}

Project: bind9
File: zone.c

dns_zone_idetach(dns_zone_t **zonep) {
	dns_zone_t *zone;
	bool free_needed;

	REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
	zone = *zonep;
	*zonep = NULL;

	LOCK_ZONE(zone);
	INSIST(zone->irefs > 0);
	zone->irefs--;
	free_needed = exit_check(zone);
	UNLOCK_ZONE(zone);
	if (free_needed)
		zone_free(zone);
}

Project: bind9
File: zone.c

dns_zone_clearnotifyacl(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	if (zone->notify_acl != NULL)
		dns_acl_detach(&zone->notify_acl);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_gettask(dns_zone_t *zone, isc_task_t **target) {
	REQUIRE(DNS_ZONE_VALID(zone));
	isc_task_attach(zone->task, target);
}

Project: bind9
File: zone.c

dns_zone_setadded(dns_zone_t *zone, bool added) {
	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	zone->added = added;
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

setserial(isc_task_t *task, isc_event_t *event) {
	uint32_t oldserial, desired;
	const char *me = "setserial";
	bool commit = false;
	isc_result_t result;
	dns_dbversion_t *oldver = NULL, *newver = NULL;
	dns_zone_t *zone;
	dns_db_t *db = NULL;
	dns_diff_t diff;
	struct ssevent *sse = (struct ssevent *)event;
	dns_update_log_t log = { update_log_cb, NULL };
	dns_difftuple_t *oldtuple = NULL, *newtuple = NULL;

	UNUSED(task);

	zone = event->ev_arg;
	INSIST(DNS_ZONE_VALID(zone));

	ENTER;

	if (zone->update_disabled)
		goto failure;

	desired = sse->serial;

	dns_diff_init(zone->mctx, &diff);

	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	if (zone->db != NULL)
		dns_db_attach(zone->db, &db);
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
	if (db == NULL)
		goto failure;

	dns_db_currentversion(db, &oldver);
	result = dns_db_newversion(db, &newver);
	if (result != ISC_R_SUCCESS) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "setserial:dns_db_newversion -> %s",
			     dns_result_totext(result));
		goto failure;
	}

	CHECK(dns_db_createsoatuple(db, oldver, diff.mctx,
				    DNS_DIFFOP_DEL, &oldtuple));
	CHECK(dns_difftuple_copy(oldtuple, &newtuple));
	newtuple->op = DNS_DIFFOP_ADD;

	oldserial = dns_soa_getserial(&oldtuple->rdata);
	if (desired == 0U)
		desired = 1;
	if (!isc_serial_gt(desired, oldserial)) {
		if (desired != oldserial)
			dns_zone_log(zone, ISC_LOG_INFO,
				     "setserial: desired serial (%u) "
				     "out of range (%u-%u)", desired,
				     oldserial + 1, (oldserial + 0x7fffffff));
		goto failure;
	}

	dns_soa_setserial(desired, &newtuple->rdata);
	CHECK(do_one_tuple(&oldtuple, db, newver, &diff));
	CHECK(do_one_tuple(&newtuple, db, newver, &diff));
	result = dns_update_signatures(&log, zone, db,
				       oldver, newver, &diff,
				       zone->sigvalidityinterval);
	if (result != ISC_R_NOTFOUND)
		CHECK(result);

	/* Write changes to journal file. */
	CHECK(zone_journal(zone, &diff, NULL, "setserial"));
	commit = true;

	LOCK_ZONE(zone);
	zone_needdump(zone, 30);
	UNLOCK_ZONE(zone);

 failure:
	if (oldtuple != NULL)
		dns_difftuple_free(&oldtuple);
	if (newtuple != NULL)
		dns_difftuple_free(&newtuple);
	if (oldver != NULL)
		dns_db_closeversion(db, &oldver, false);
	if (newver != NULL)
		dns_db_closeversion(db, &newver, commit);
	if (db != NULL)
		dns_db_detach(&db);
	dns_diff_clear(&diff);
	isc_event_free(&event);
	dns_zone_idetach(&zone);

	INSIST(oldver == NULL);
	INSIST(newver == NULL);
}

Project: bind9
File: zone.c

dns_zone_isforced(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));

	return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER));
}

Project: bind9
File: zone.c

dns_zone_getchecknames(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->check_names);
}

Project: bind9
File: zone.c

dns_zone_checknames(dns_zone_t *zone, const dns_name_t *name,
		    dns_rdata_t *rdata)
{
	bool ok = true;
	bool fail = false;
	char namebuf[DNS_NAME_FORMATSIZE];
	char namebuf2[DNS_NAME_FORMATSIZE];
	char typebuf[DNS_RDATATYPE_FORMATSIZE];
	int level = ISC_LOG_WARNING;
	dns_name_t bad;

	REQUIRE(DNS_ZONE_VALID(zone));

	if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES) &&
	    rdata->type != dns_rdatatype_nsec3)
		return (ISC_R_SUCCESS);

	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL) ||
	    rdata->type == dns_rdatatype_nsec3) {
		level = ISC_LOG_ERROR;
		fail = true;
	}

	ok = dns_rdata_checkowner(name, rdata->rdclass, rdata->type, true);
	if (!ok) {
		dns_name_format(name, namebuf, sizeof(namebuf));
		dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
		dns_zone_log(zone, level, "%s/%s: %s", namebuf, typebuf,
			     dns_result_totext(DNS_R_BADOWNERNAME));
		if (fail)
			return (DNS_R_BADOWNERNAME);
	}

	dns_name_init(&bad, NULL);
	ok = dns_rdata_checknames(rdata, name, &bad);
	if (!ok) {
		dns_name_format(name, namebuf, sizeof(namebuf));
		dns_name_format(&bad, namebuf2, sizeof(namebuf2));
		dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
		dns_zone_log(zone, level, "%s/%s: %s: %s ", namebuf, typebuf,
			     namebuf2, dns_result_totext(DNS_R_BADNAME));
		if (fail)
			return (DNS_R_BADNAME);
	}

	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length) {
	isc_buffer_t buffer;

	REQUIRE(buf != NULL);
	REQUIRE(length > 1U);

	/*
	 * Leave space for terminating '\0'.
	 */
	isc_buffer_init(&buffer, buf, (unsigned int)length - 1);
	(void)dns_rdataclass_totext(zone->rdclass, &buffer);

	buf[isc_buffer_usedlength(&buffer)] = '\0';
}

Project: bind9
File: zone.c

dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(zone->stats == NULL);

	LOCK_ZONE(zone);
	zone->stats = NULL;
	isc_stats_attach(stats, &zone->stats);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_setsigresigninginterval(dns_zone_t *zone, uint32_t interval) {
	isc_time_t now;

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	zone->sigresigninginterval = interval;
	set_resigntime(zone);
	if (zone->task != NULL) {
		TIME_NOW(&now);
		zone_settimer(zone, &now);
	}
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) {
	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	zone->notifysrc6 = *notifysrc;
	UNLOCK_ZONE(zone);

	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

get_edns_expire(dns_zone_t * zone, dns_message_t *message,
		uint32_t *expirep)
{
	isc_result_t result;
	uint32_t expire;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_buffer_t optbuf;
	uint16_t optcode;
	uint16_t optlen;

	REQUIRE(expirep != NULL);
	REQUIRE(message != NULL);

	if (message->opt == NULL)
		return;

	result = dns_rdataset_first(message->opt);
	if (result == ISC_R_SUCCESS) {
		dns_rdataset_current(message->opt, &rdata);
		isc_buffer_init(&optbuf, rdata.data, rdata.length);
		isc_buffer_add(&optbuf, rdata.length);
		while (isc_buffer_remaininglength(&optbuf) >= 4) {
			optcode = isc_buffer_getuint16(&optbuf);
			optlen = isc_buffer_getuint16(&optbuf);
			/*
			 * A EDNS EXPIRE response has a length of 4.
			 */
			if (optcode != DNS_OPT_EXPIRE || optlen != 4) {
				isc_buffer_forward(&optbuf, optlen);
				continue;
			}
			expire = isc_buffer_getuint32(&optbuf);
			dns_zone_log(zone, ISC_LOG_DEBUG(1),
				     "got EDNS EXPIRE of %u", expire);
			/*
			 * Trim *expirep?
			 */
			if (expire < *expirep)
				*expirep = expire;
			break;
		}
	}
}

Project: bind9
File: zone.c

dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr) {
	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	return (zmgr->notifyrate);
}

Project: bind9
File: zone.c

zone_nsec3chain(dns_zone_t *zone) {
	const char *me = "zone_nsec3chain";
	dns_db_t *db = NULL;
	dns_dbnode_t *node = NULL;
	dns_dbversion_t *version = NULL;
	dns_diff_t _sig_diff;
	dns_diff_t nsec_diff;
	dns_diff_t nsec3_diff;
	dns_diff_t param_diff;
	dns__zonediff_t zonediff;
	dns_fixedname_t fixed;
	dns_fixedname_t nextfixed;
	dns_name_t *name, *nextname;
	dns_rdataset_t rdataset;
	dns_nsec3chain_t *nsec3chain = NULL, *nextnsec3chain;
	dns_nsec3chainlist_t cleanup;
	dst_key_t *zone_keys[DNS_MAXZONEKEYS];
	int32_t signatures;
	bool check_ksk, keyset_kskonly;
	bool delegation;
	bool first;
	isc_result_t result;
	isc_stdtime_t now, inception, soaexpire, expire;
	uint32_t jitter, sigvalidityinterval;
	unsigned int i;
	unsigned int nkeys = 0;
	uint32_t nodes;
	bool unsecure = false;
	bool seen_soa, seen_ns, seen_dname, seen_ds;
	bool seen_nsec, seen_nsec3, seen_rr;
	dns_rdatasetiter_t *iterator = NULL;
	bool buildnsecchain;
	bool updatensec = false;
	dns_rdatatype_t privatetype = zone->privatetype;

	ENTER;

	dns_rdataset_init(&rdataset);
	name = dns_fixedname_initname(&fixed);
	nextname = dns_fixedname_initname(&nextfixed);
	dns_diff_init(zone->mctx, &param_diff);
	dns_diff_init(zone->mctx, &nsec3_diff);
	dns_diff_init(zone->mctx, &nsec_diff);
	dns_diff_init(zone->mctx, &_sig_diff);
	zonediff_init(&zonediff, &_sig_diff);
	ISC_LIST_INIT(cleanup);

	/*
	 * Updates are disabled.  Pause for 5 minutes.
	 */
	if (zone->update_disabled) {
		result = ISC_R_FAILURE;
		goto failure;
	}

	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	/*
	 * This function is called when zone timer fires, after the latter gets
	 * set by zone_addnsec3chain().  If the action triggering the call to
	 * zone_addnsec3chain() is closely followed by a zone deletion request,
	 * it might turn out that the timer thread will not be woken up until
	 * after the zone is deleted by rmzone(), which calls dns_db_detach()
	 * for zone->db, causing the latter to become NULL.  Return immediately
	 * if that happens.
	 */
	if (zone->db != NULL) {
		dns_db_attach(zone->db, &db);
	}
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
	if (db == NULL) {
		return;
	}

	result = dns_db_newversion(db, &version);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:dns_db_newversion -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	isc_stdtime_get(&now);

	result = dns__zone_findkeys(zone, db, version, now, zone->mctx,
				    DNS_MAXZONEKEYS, zone_keys, &nkeys);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:dns__zone_findkeys -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	sigvalidityinterval = dns_zone_getsigvalidityinterval(zone);
	inception = now - 3600;	/* Allow for clock skew. */
	soaexpire = now + sigvalidityinterval;

	/*
	 * Spread out signatures over time if they happen to be
	 * clumped.  We don't do this for each add_sigs() call as
	 * we still want some clustering to occur.
	 */
	if (sigvalidityinterval >= 3600U) {
		if (sigvalidityinterval > 7200U) {
			jitter = isc_random_uniform(3600);
		} else {
			jitter = isc_random_uniform(1200);
		}
		expire = soaexpire - jitter - 1;
	} else {
		expire = soaexpire - 1;
	}

	check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
	keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY);

	/*
	 * We keep pulling nodes off each iterator in turn until
	 * we have no more nodes to pull off or we reach the limits
	 * for this quantum.
	 */
	nodes = zone->nodes;
	signatures = zone->signatures;
	LOCK_ZONE(zone);
	nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
	UNLOCK_ZONE(zone);
	first = true;

	if (nsec3chain != NULL) {
		nsec3chain->save_delete_nsec = nsec3chain->delete_nsec;
	}
	/*
	 * Generate new NSEC3 chains first.
	 *
	 * The following while loop iterates over nodes in the zone database,
	 * updating the NSEC3 chain by calling dns_nsec3_addnsec3() for each of
	 * them.  Once all nodes are processed, the "delete_nsec" field is
	 * consulted to check whether we are supposed to remove NSEC records
	 * from the zone database; if so, the database iterator is reset to
	 * point to the first node and the loop traverses all of them again,
	 * this time removing NSEC records.  If we hit a node which is obscured
	 * by a delegation or a DNAME, nodes are skipped over until we find one
	 * that is not obscured by the same obscuring name and then normal
	 * processing is resumed.
	 *
	 * The above is repeated until all requested NSEC3 chain changes are
	 * applied or when we reach the limits for this quantum, whichever
	 * happens first.
	 *
	 * Note that the "signatures" variable is only used here to limit the
	 * amount of work performed.  Actual DNSSEC signatures are only
	 * generated by dns__zone_updatesigs() calls later in this function.
	 */
	while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) {
		LOCK_ZONE(zone);
		nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link);

		ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
		if (nsec3chain->done || nsec3chain->db != zone->db) {
			ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link);
			ISC_LIST_APPEND(cleanup, nsec3chain, link);
		}
		ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
		UNLOCK_ZONE(zone);
		if (ISC_LIST_TAIL(cleanup) == nsec3chain)
			goto next_addchain;

		/*
		 * Possible future db.
		 */
		if (nsec3chain->db != db) {
			goto next_addchain;
		}

		if (NSEC3REMOVE(nsec3chain->nsec3param.flags))
			goto next_addchain;

		dns_dbiterator_current(nsec3chain->dbiterator, &node, name);

		if (nsec3chain->delete_nsec) {
			delegation = false;
			dns_dbiterator_pause(nsec3chain->dbiterator);
			CHECK(delete_nsec(db, version, node, name, &nsec_diff));
			goto next_addnode;
		}
		/*
		 * On the first pass we need to check if the current node
		 * has not been obscured.
		 */
		delegation = false;
		unsecure = false;
		if (first) {
			dns_fixedname_t ffound;
			dns_name_t *found;
			found = dns_fixedname_initname(&ffound);
			result = dns_db_find(db, name, version,
					     dns_rdatatype_soa,
					     DNS_DBFIND_NOWILD, 0, NULL, found,
					     NULL, NULL);
			if ((result == DNS_R_DELEGATION ||
			    result == DNS_R_DNAME) &&
			    !dns_name_equal(name, found)) {
				/*
				 * Remember the obscuring name so that
				 * we skip all obscured names.
				 */
				dns_name_copy(found, name, NULL);
				delegation = true;
				goto next_addnode;
			}
		}

		/*
		 * Check to see if this is a bottom of zone node.
		 */
		result = dns_db_allrdatasets(db, node, version, 0, &iterator);
		if (result == ISC_R_NOTFOUND) {
			/* Empty node? */
			goto next_addnode;
		}
		if (result != ISC_R_SUCCESS) {
			goto failure;
		}

		seen_soa = seen_ns = seen_dname = seen_ds = seen_nsec = false;
		for (result = dns_rdatasetiter_first(iterator);
		     result == ISC_R_SUCCESS;
		     result = dns_rdatasetiter_next(iterator))
		{
			dns_rdatasetiter_current(iterator, &rdataset);
			INSIST(rdataset.type != dns_rdatatype_nsec3);
			if (rdataset.type == dns_rdatatype_soa) {
				seen_soa = true;
			} else if (rdataset.type == dns_rdatatype_ns) {
				seen_ns = true;
			} else if (rdataset.type == dns_rdatatype_dname) {
				seen_dname = true;
			} else if (rdataset.type == dns_rdatatype_ds) {
				seen_ds = true;
			} else if (rdataset.type == dns_rdatatype_nsec) {
				seen_nsec = true;
			}
			dns_rdataset_disassociate(&rdataset);
		}
		dns_rdatasetiter_destroy(&iterator);
		/*
		 * Is there a NSEC chain than needs to be cleaned up?
		 */
		if (seen_nsec) {
			nsec3chain->seen_nsec = true;
		}
		if (seen_ns && !seen_soa && !seen_ds) {
			unsecure = true;
		}
		if ((seen_ns && !seen_soa) || seen_dname) {
			delegation = true;
		}

		/*
		 * Process one node.
		 */
		dns_dbiterator_pause(nsec3chain->dbiterator);
		result = dns_nsec3_addnsec3(db, version, name,
					    &nsec3chain->nsec3param,
					    zone->minimum, unsecure,
					    &nsec3_diff);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
				   "dns_nsec3_addnsec3 -> %s",
				   dns_result_totext(result));
			goto failure;
		}

		/*
		 * Treat each call to dns_nsec3_addnsec3() as if it's cost is
		 * two signatures.  Additionally there will, in general, be
		 * two signature generated below.
		 *
		 * If we are only changing the optout flag the cost is half
		 * that of the cost of generating a completely new chain.
		 */
		signatures -= 4;

		/*
		 * Go onto next node.
		 */
 next_addnode:
		first = false;
		dns_db_detachnode(db, &node);
		do {
			result = dns_dbiterator_next(nsec3chain->dbiterator);

			if (result == ISC_R_NOMORE && nsec3chain->delete_nsec) {
				dns_dbiterator_pause(nsec3chain->dbiterator);
				CHECK(fixup_nsec3param(db, version, nsec3chain,
						       false, privatetype,
						       &param_diff));
				LOCK_ZONE(zone);
				ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
						link);
				UNLOCK_ZONE(zone);
				ISC_LIST_APPEND(cleanup, nsec3chain, link);
				goto next_addchain;
			}
			if (result == ISC_R_NOMORE) {
				dns_dbiterator_pause(nsec3chain->dbiterator);
				if (nsec3chain->seen_nsec) {
					CHECK(fixup_nsec3param(db, version,
							       nsec3chain,
							       true,
							       privatetype,
							       &param_diff));
					nsec3chain->delete_nsec = true;
					goto same_addchain;
				}
				CHECK(fixup_nsec3param(db, version, nsec3chain,
						       false, privatetype,
						       &param_diff));
				LOCK_ZONE(zone);
				ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
						link);
				UNLOCK_ZONE(zone);
				ISC_LIST_APPEND(cleanup, nsec3chain, link);
				goto next_addchain;
			} else if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_nsec3chain:"
					   "dns_dbiterator_next -> %s",
					   dns_result_totext(result));
				goto failure;
			} else if (delegation) {
				dns_dbiterator_current(nsec3chain->dbiterator,
						       &node, nextname);
				dns_db_detachnode(db, &node);
				if (!dns_name_issubdomain(nextname, name))
					break;
			} else {
				break;
			}
		} while (1);
		continue;

 same_addchain:
		CHECK(dns_dbiterator_first(nsec3chain->dbiterator));
		first = true;
		continue;

 next_addchain:
		dns_dbiterator_pause(nsec3chain->dbiterator);
		nsec3chain = nextnsec3chain;
		first = true;
		if (nsec3chain != NULL) {
			nsec3chain->save_delete_nsec = nsec3chain->delete_nsec;
		}
	}

	if (nsec3chain != NULL) {
		goto skip_removals;
	}

	/*
	 * Process removals.
	 *
	 * This is a counterpart of the above while loop which takes care of
	 * removing an NSEC3 chain.  It starts with determining whether the
	 * zone needs to switch from NSEC3 to NSEC; if so, it first builds an
	 * NSEC chain by iterating over all nodes in the zone database and only
	 * then goes on to remove NSEC3 records be iterating over all nodes
	 * again and calling deletematchingnsec3() for each of them; otherwise,
	 * it starts removing NSEC3 records immediately.  Rules for processing
	 * obscured nodes and interrupting work are the same as for the while
	 * loop above.
	 */
	LOCK_ZONE(zone);
	nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
	UNLOCK_ZONE(zone);
	first = true;
	buildnsecchain = false;
	while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) {
		LOCK_ZONE(zone);
		nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link);
		UNLOCK_ZONE(zone);

		if (nsec3chain->db != db) {
			goto next_removechain;
		}

		if (!NSEC3REMOVE(nsec3chain->nsec3param.flags)) {
			goto next_removechain;
		}

		/*
		 * Work out if we need to build a NSEC chain as a consequence
		 * of removing this NSEC3 chain.
		 */
		if (first && !updatensec &&
		    (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0)
		{
			result = need_nsec_chain(db, version,
						 &nsec3chain->nsec3param,
						 &buildnsecchain);
			if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_nsec3chain:"
					   "need_nsec_chain -> %s",
					   dns_result_totext(result));
				goto failure;
			}
		}

		if (first) {
			dnssec_log(zone, ISC_LOG_DEBUG(3),
				   "zone_nsec3chain:buildnsecchain = %u\n",
				   buildnsecchain);
		}

		dns_dbiterator_current(nsec3chain->dbiterator, &node, name);
		delegation = false;

		if (!buildnsecchain) {
			/*
			 * Delete the NSEC3PARAM record matching this chain.
			 */
			if (first) {
				result = fixup_nsec3param(db, version,
							  nsec3chain,
							  true, privatetype,
							  &param_diff);
				if (result != ISC_R_SUCCESS) {
					dnssec_log(zone, ISC_LOG_ERROR,
						   "zone_nsec3chain:"
						   "fixup_nsec3param -> %s",
						   dns_result_totext(result));
					goto failure;
				}
			}

			/*
			 * Delete the NSEC3 records.
			 */
			result = deletematchingnsec3(db, version, node, name,
						     &nsec3chain->nsec3param,
						     &nsec3_diff);
			if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_nsec3chain:"
					   "deletematchingnsec3 -> %s",
					   dns_result_totext(result));
				goto failure;
			}
			goto next_removenode;
		}

		if (first) {
			dns_fixedname_t ffound;
			dns_name_t *found;
			found = dns_fixedname_initname(&ffound);
			result = dns_db_find(db, name, version,
					     dns_rdatatype_soa,
					     DNS_DBFIND_NOWILD, 0, NULL, found,
					     NULL, NULL);
			if ((result == DNS_R_DELEGATION ||
			     result == DNS_R_DNAME) &&
			    !dns_name_equal(name, found))
			{
				/*
				 * Remember the obscuring name so that
				 * we skip all obscured names.
				 */
				dns_name_copy(found, name, NULL);
				delegation = true;
				goto next_removenode;
			}
		}

		/*
		 * Check to see if this is a bottom of zone node.
		 */
		result = dns_db_allrdatasets(db, node, version, 0, &iterator);
		if (result == ISC_R_NOTFOUND) {
			/* Empty node? */
			goto next_removenode;
		}
		if (result != ISC_R_SUCCESS) {
			goto failure;
		}

		seen_soa = seen_ns = seen_dname = seen_nsec3 =
			   seen_nsec = seen_rr = false;
		for (result = dns_rdatasetiter_first(iterator);
		     result == ISC_R_SUCCESS;
		     result = dns_rdatasetiter_next(iterator))
		{
			dns_rdatasetiter_current(iterator, &rdataset);
			if (rdataset.type == dns_rdatatype_soa) {
				seen_soa = true;
			} else if (rdataset.type == dns_rdatatype_ns) {
				seen_ns = true;
			} else if (rdataset.type == dns_rdatatype_dname) {
				seen_dname = true;
			} else if (rdataset.type == dns_rdatatype_nsec) {
				seen_nsec = true;
			} else if (rdataset.type == dns_rdatatype_nsec3) {
				seen_nsec3 = true;
			} else if (rdataset.type != dns_rdatatype_rrsig) {
				seen_rr = true;
			}
			dns_rdataset_disassociate(&rdataset);
		}
		dns_rdatasetiter_destroy(&iterator);

		if (!seen_rr || seen_nsec3 || seen_nsec) {
			goto next_removenode;
		}
		if ((seen_ns && !seen_soa) || seen_dname) {
			delegation = true;
		}

		/*
		 * Add a NSEC record except at the origin.
		 */
		if (!dns_name_equal(name, dns_db_origin(db))) {
			dns_dbiterator_pause(nsec3chain->dbiterator);
			CHECK(add_nsec(db, version, name, node, zone->minimum,
				       delegation, &nsec_diff));
			signatures--;
		}

 next_removenode:
		first = false;
		dns_db_detachnode(db, &node);
		do {
			result = dns_dbiterator_next(nsec3chain->dbiterator);
			if (result == ISC_R_NOMORE && buildnsecchain) {
				/*
				 * The NSEC chain should now be built.
				 * We can now remove the NSEC3 chain.
				 */
				updatensec = true;
				goto same_removechain;
			}
			if (result == ISC_R_NOMORE) {
				LOCK_ZONE(zone);
				ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
						link);
				UNLOCK_ZONE(zone);
				ISC_LIST_APPEND(cleanup, nsec3chain, link);
				dns_dbiterator_pause(nsec3chain->dbiterator);
				result = fixup_nsec3param(db, version,
							  nsec3chain, false,
							  privatetype,
							  &param_diff);
				if (result != ISC_R_SUCCESS) {
					dnssec_log(zone, ISC_LOG_ERROR,
						   "zone_nsec3chain:"
						   "fixup_nsec3param -> %s",
						   dns_result_totext(result));
					goto failure;
				}
				goto next_removechain;
			} else if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_nsec3chain:"
					   "dns_dbiterator_next -> %s",
					   dns_result_totext(result));
				goto failure;
			} else if (delegation) {
				dns_dbiterator_current(nsec3chain->dbiterator,
						       &node, nextname);
				dns_db_detachnode(db, &node);
				if (!dns_name_issubdomain(nextname, name)) {
					break;
				}
			} else {
				break;
			}
		} while (1);
		continue;

 same_removechain:
		CHECK(dns_dbiterator_first(nsec3chain->dbiterator));
		buildnsecchain = false;
		first = true;
		continue;

 next_removechain:
		dns_dbiterator_pause(nsec3chain->dbiterator);
		nsec3chain = nextnsec3chain;
		first = true;
	}

 skip_removals:
	/*
	 * We may need to update the NSEC/NSEC3 records for the zone apex.
	 */
	if (!ISC_LIST_EMPTY(param_diff.tuples)) {
		bool rebuild_nsec = false,
			      rebuild_nsec3 = false;
		result = dns_db_getoriginnode(db, &node);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		result = dns_db_allrdatasets(db, node, version, 0, &iterator);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "zone_nsec3chain:dns_db_allrdatasets -> %s",
				   dns_result_totext(result));
			goto failure;
		}
		for (result = dns_rdatasetiter_first(iterator);
		     result == ISC_R_SUCCESS;
		     result = dns_rdatasetiter_next(iterator))
		{
			dns_rdatasetiter_current(iterator, &rdataset);
			if (rdataset.type == dns_rdatatype_nsec) {
				rebuild_nsec = true;
			} else if (rdataset.type == dns_rdatatype_nsec3param) {
				rebuild_nsec3 = true;
			}
			dns_rdataset_disassociate(&rdataset);
		}
		dns_rdatasetiter_destroy(&iterator);
		dns_db_detachnode(db, &node);

		if (rebuild_nsec) {
			if (nsec3chain != NULL) {
				dns_dbiterator_pause(nsec3chain->dbiterator);
			}

			result = updatesecure(db, version, &zone->origin,
					      zone->minimum, true,
					      &nsec_diff);
			if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_nsec3chain:updatesecure -> %s",
					   dns_result_totext(result));
				goto failure;
			}
		}

		if (rebuild_nsec3) {
			if (nsec3chain != NULL) {
				dns_dbiterator_pause(nsec3chain->dbiterator);
			}

			result = dns_nsec3_addnsec3s(db, version,
						     dns_db_origin(db),
						     zone->minimum, false,
						     &nsec3_diff);
			if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_nsec3chain:"
					   "dns_nsec3_addnsec3s -> %s",
					   dns_result_totext(result));
				goto failure;
			}
		}
	}

	/*
	 * Add / update signatures for the NSEC3 records.
	 */
	if (nsec3chain != NULL) {
		dns_dbiterator_pause(nsec3chain->dbiterator);
	}
	result = dns__zone_updatesigs(&nsec3_diff, db, version, zone_keys,
				      nkeys, zone, inception, expire, 0, now,
				      check_ksk, keyset_kskonly, &zonediff);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:dns__zone_updatesigs -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	/*
	 * We have changed the NSEC3PARAM or private RRsets
	 * above so we need to update the signatures.
	 */
	result = dns__zone_updatesigs(&param_diff, db, version, zone_keys,
				      nkeys, zone, inception, expire, 0, now,
				      check_ksk, keyset_kskonly, &zonediff);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:dns__zone_updatesigs -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	if (updatensec) {
		result = updatesecure(db, version, &zone->origin,
				      zone->minimum, false, &nsec_diff);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "zone_nsec3chain:updatesecure -> %s",
				   dns_result_totext(result));
			goto failure;
		}
	}

	result = dns__zone_updatesigs(&nsec_diff, db, version, zone_keys,
				      nkeys, zone, inception, expire, 0, now,
				      check_ksk, keyset_kskonly, &zonediff);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:dns__zone_updatesigs -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	/*
	 * If we made no effective changes to the zone then we can just
	 * cleanup otherwise we need to increment the serial.
	 */
	if (ISC_LIST_EMPTY(zonediff.diff->tuples)) {
		/*
		 * No need to call dns_db_closeversion() here as it is
		 * called with commit = true below.
		 */
		goto done;
	}

	result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
			  &zonediff, zone_keys, nkeys, now, false);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:del_sigs -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
				   zone->updatemethod);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:update_soa_serial -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa,
			  zonediff.diff, zone_keys, nkeys, zone->mctx,
			  inception, soaexpire, check_ksk, keyset_kskonly);
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "zone_nsec3chain:add_sigs -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	/* Write changes to journal file. */
	CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_nsec3chain"));

	LOCK_ZONE(zone);
	zone_needdump(zone, DNS_DUMP_DELAY);
	DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
	UNLOCK_ZONE(zone);

 done:
	/*
	 * Pause all iterators so that dns_db_closeversion() can succeed.
	 */
	LOCK_ZONE(zone);
	for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
	     nsec3chain != NULL;
	     nsec3chain = ISC_LIST_NEXT(nsec3chain, link))
	{
		dns_dbiterator_pause(nsec3chain->dbiterator);
	}
	UNLOCK_ZONE(zone);

	/*
	 * Everything has succeeded. Commit the changes.
	 * Unconditionally commit as zonediff.offline not checked above.
	 */
	dns_db_closeversion(db, &version, true);

	/*
	 * Everything succeeded so we can clean these up now.
	 */
	nsec3chain = ISC_LIST_HEAD(cleanup);
	while (nsec3chain != NULL) {
		ISC_LIST_UNLINK(cleanup, nsec3chain, link);
		dns_db_detach(&nsec3chain->db);
		dns_dbiterator_destroy(&nsec3chain->dbiterator);
		isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
		nsec3chain = ISC_LIST_HEAD(cleanup);
	}

	set_resigntime(zone);

 failure:
	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain: %s",
			   dns_result_totext(result));
	}

	/*
	 * On error roll back the current nsec3chain.
	 */
	if (result != ISC_R_SUCCESS && nsec3chain != NULL) {
		if (nsec3chain->done) {
			dns_db_detach(&nsec3chain->db);
			dns_dbiterator_destroy(&nsec3chain->dbiterator);
			isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
		} else {
			result = dns_dbiterator_first(nsec3chain->dbiterator);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			dns_dbiterator_pause(nsec3chain->dbiterator);
			nsec3chain->delete_nsec = nsec3chain->save_delete_nsec;
		}
	}

	/*
	 * Rollback the cleanup list.
	 */
	nsec3chain = ISC_LIST_TAIL(cleanup);
	while (nsec3chain != NULL) {
		ISC_LIST_UNLINK(cleanup, nsec3chain, link);
		if (nsec3chain->done) {
			dns_db_detach(&nsec3chain->db);
			dns_dbiterator_destroy(&nsec3chain->dbiterator);
			isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
		} else {
			LOCK_ZONE(zone);
			ISC_LIST_PREPEND(zone->nsec3chain, nsec3chain, link);
			UNLOCK_ZONE(zone);
			result = dns_dbiterator_first(nsec3chain->dbiterator);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			dns_dbiterator_pause(nsec3chain->dbiterator);
			nsec3chain->delete_nsec = nsec3chain->save_delete_nsec;
		}
		nsec3chain = ISC_LIST_TAIL(cleanup);
	}

	LOCK_ZONE(zone);
	for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
	     nsec3chain != NULL;
	     nsec3chain = ISC_LIST_NEXT(nsec3chain, link))
	{
		dns_dbiterator_pause(nsec3chain->dbiterator);
	}
	UNLOCK_ZONE(zone);

	dns_diff_clear(&param_diff);
	dns_diff_clear(&nsec3_diff);
	dns_diff_clear(&nsec_diff);
	dns_diff_clear(&_sig_diff);

	if (iterator != NULL) {
		dns_rdatasetiter_destroy(&iterator);
	}

	for (i = 0; i < nkeys; i++) {
		dst_key_free(&zone_keys[i]);
	}

	if (node != NULL) {
		dns_db_detachnode(db, &node);
	}
	if (version != NULL) {
		dns_db_closeversion(db, &version, false);
		dns_db_detach(&db);
	} else if (db != NULL) {
		dns_db_detach(&db);
	}

	LOCK_ZONE(zone);
	if (ISC_LIST_HEAD(zone->nsec3chain) != NULL) {
		isc_interval_t interval;
		if (zone->update_disabled || result != ISC_R_SUCCESS) {
			isc_interval_set(&interval, 60, 0);	  /* 1 minute */
		} else {
			isc_interval_set(&interval, 0, 10000000); /* 10 ms */
		}
		isc_time_nowplusinterval(&zone->nsec3chaintime, &interval);
	} else {
		isc_time_settoepoch(&zone->nsec3chaintime);
	}
	UNLOCK_ZONE(zone);

	INSIST(version == NULL);
}

Project: bind9
File: zone.c

dns_zone_attach(dns_zone_t *source, dns_zone_t **target) {
	REQUIRE(DNS_ZONE_VALID(source));
	REQUIRE(target != NULL && *target == NULL);
	isc_refcount_increment(&source->erefs);
	*target = source;
}

Project: bind9
File: zone.c

add_opt(dns_message_t *message, uint16_t udpsize, bool reqnsid,
	bool reqexpire)
{
	isc_result_t result;
	dns_rdataset_t *rdataset = NULL;
	dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
	int count = 0;

	/* Set EDNS options if applicable */
	if (reqnsid) {
		INSIST(count < DNS_EDNSOPTIONS);
		ednsopts[count].code = DNS_OPT_NSID;
		ednsopts[count].length = 0;
		ednsopts[count].value = NULL;
		count++;
	}
	if (reqexpire) {
		INSIST(count < DNS_EDNSOPTIONS);
		ednsopts[count].code = DNS_OPT_EXPIRE;
		ednsopts[count].length = 0;
		ednsopts[count].value = NULL;
		count++;
	}
	result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0,
				      ednsopts, count);
	if (result != ISC_R_SUCCESS)
		return (result);

	return (dns_message_setopt(message, rdataset));
}

Project: bind9
File: zone.c

zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length) {
	isc_buffer_t buffer;

	REQUIRE(buf != NULL);
	REQUIRE(length > 1U);


	/*
	 * Leave space for terminating '\0'.
	 */
	isc_buffer_init(&buffer, buf, (unsigned int)length - 1);

	if (zone->view == NULL) {
		isc_buffer_putstr(&buffer, "_none");
	} else if (strlen(zone->view->name)
		   < isc_buffer_availablelength(&buffer)) {
		isc_buffer_putstr(&buffer, zone->view->name);
	} else {
		isc_buffer_putstr(&buffer, "_toolong");
	}

	buf[isc_buffer_usedlength(&buffer)] = '\0';
}

Project: bind9
File: zone.c

save_nsec3param(dns_zone_t *zone, nsec3paramlist_t *nsec3list) {
	isc_result_t result;
	dns_dbnode_t *node = NULL;
	dns_rdataset_t rdataset, prdataset;
	dns_dbversion_t *version = NULL;
	nsec3param_t *nsec3param = NULL;
	nsec3param_t *nsec3p = NULL;
	nsec3param_t *next;
	dns_db_t *db = NULL;
	unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(nsec3list != NULL);
	REQUIRE(ISC_LIST_EMPTY(*nsec3list));

	dns_rdataset_init(&rdataset);
	dns_rdataset_init(&prdataset);

	dns_db_attach(zone->db, &db);
	CHECK(dns_db_getoriginnode(db, &node));

	dns_db_currentversion(db, &version);
	result = dns_db_findrdataset(db, node, version,
				     dns_rdatatype_nsec3param,
				     dns_rdatatype_none, 0, &rdataset, NULL);

	if (result != ISC_R_SUCCESS)
		goto getprivate;

	/*
	 * walk nsec3param rdataset making a list of parameters (note that
	 * multiple simultaneous nsec3 chains are annoyingly legal -- this
	 * is why we use an nsec3list, even tho we will usually only have
	 * one)
	 */
	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset))
	{
		dns_rdata_t rdata = DNS_RDATA_INIT;
		dns_rdata_t private = DNS_RDATA_INIT;

		dns_rdataset_current(&rdataset, &rdata);
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
			      DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
			      "looping through nsec3param data");
		nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t));
		if (nsec3param == NULL)
			CHECK(ISC_R_NOMEMORY);
		ISC_LINK_INIT(nsec3param, link);

		/*
		 * now transfer the data from the rdata to
		 * the nsec3param
		 */
		dns_nsec3param_toprivate(&rdata, &private,
					 zone->privatetype, nsec3param->data,
					 sizeof(nsec3param->data));
		nsec3param->length = private.length;
		ISC_LIST_APPEND(*nsec3list, nsec3param, link);
	}

 getprivate:
	result = dns_db_findrdataset(db, node, version, zone->privatetype,
				     dns_rdatatype_none, 0, &prdataset, NULL);
	if (result != ISC_R_SUCCESS)
		goto done;

	/*
	 * walk private type records, converting them to nsec3 parameters
	 * using dns_nsec3param_fromprivate(), do the right thing based on
	 * CREATE and REMOVE flags
	 */
	for (result = dns_rdataset_first(&prdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&prdataset))
	{
		dns_rdata_t rdata = DNS_RDATA_INIT;
		dns_rdata_t private = DNS_RDATA_INIT;

		dns_rdataset_current(&prdataset, &private);
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
			      DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
			      "looping through nsec3param private data");

		/*
		 * Do we have a valid private record?
		 */
		if (!dns_nsec3param_fromprivate(&private, &rdata,
						buf, sizeof(buf)))
			continue;

		/*
		 * Remove any NSEC3PARAM records scheduled to be removed.
		 */
		if (NSEC3REMOVE(rdata.data[1])) {
			/*
			 * Zero out the flags.
			 */
			rdata.data[1] = 0;

			for (nsec3p = ISC_LIST_HEAD(*nsec3list);
			     nsec3p != NULL;
			     nsec3p = next)
			{
				next = ISC_LIST_NEXT(nsec3p, link);

				if (nsec3p->length == rdata.length + 1 &&
				    memcmp(rdata.data, nsec3p->data + 1,
					   nsec3p->length - 1) == 0) {
					ISC_LIST_UNLINK(*nsec3list,
							nsec3p, link);
					isc_mem_put(zone->mctx, nsec3p,
						    sizeof(nsec3param_t));
				}
			}
			continue;
		}

		nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t));
		if (nsec3param == NULL)
			CHECK(ISC_R_NOMEMORY);
		ISC_LINK_INIT(nsec3param, link);

		/*
		 * Copy the remaining private records so the nsec/nsec3
		 * chain gets created.
		 */
		INSIST(private.length <= sizeof(nsec3param->data));
		memmove(nsec3param->data, private.data, private.length);
		nsec3param->length = private.length;
		ISC_LIST_APPEND(*nsec3list, nsec3param, link);
	}

 done:
	if (result == ISC_R_NOMORE || result == ISC_R_NOTFOUND)
		result = ISC_R_SUCCESS;

 failure:
	if (node != NULL)
		dns_db_detachnode(db, &node);
	if (version != NULL)
		dns_db_closeversion(db, &version, false);
	if (db != NULL)
		dns_db_detach(&db);
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	if (dns_rdataset_isassociated(&prdataset))
		dns_rdataset_disassociate(&prdataset);
	return (result);
}

Project: bind9
File: zone.c

dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
	isc_result_t result;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	if (zmgr->zonetasks == NULL)
		return (ISC_R_FAILURE);

	RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	LOCK_ZONE(zone);
	REQUIRE(zone->task == NULL);
	REQUIRE(zone->timer == NULL);
	REQUIRE(zone->zmgr == NULL);

	isc_taskpool_gettask(zmgr->zonetasks, &zone->task);
	isc_taskpool_gettask(zmgr->loadtasks, &zone->loadtask);

	/*
	 * Set the task name.  The tag will arbitrarily point to one
	 * of the zones sharing the task (in practice, the one
	 * to be managed last).
	 */
	isc_task_setname(zone->task, "zone", zone);
	isc_task_setname(zone->loadtask, "loadzone", zone);

	result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive,
				  NULL, NULL,
				  zone->task, zone_timer, zone,
				  &zone->timer);

	if (result != ISC_R_SUCCESS)
		goto cleanup_tasks;

	/*
	 * The timer "holds" a iref.
	 */
	zone->irefs++;
	INSIST(zone->irefs != 0);

	ISC_LIST_APPEND(zmgr->zones, zone, link);
	zone->zmgr = zmgr;
	zmgr->refs++;

	goto unlock;

 cleanup_tasks:
	isc_task_detach(&zone->loadtask);
	isc_task_detach(&zone->task);

 unlock:
	UNLOCK_ZONE(zone);
	RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	return (result);
}

Project: bind9
File: zone.c

receive_secure_serial(isc_task_t *task, isc_event_t *event) {
	static char me[] = "receive_secure_serial";
	isc_result_t result = ISC_R_SUCCESS;
	dns_journal_t *rjournal = NULL;
	dns_journal_t *sjournal = NULL;
	uint32_t start, end;
	dns_zone_t *zone;
	dns_difftuple_t *tuple = NULL, *soatuple = NULL;
	dns_update_log_t log = { update_log_cb, NULL };
	uint32_t newserial = 0, desired = 0;
	isc_time_t timenow;

	UNUSED(task);

	zone = event->ev_arg;
	end = ((struct secure_event *)event)->serial;

	ENTER;

	LOCK_ZONE(zone);

	/*
	 * If we are already processing a receive secure serial event
	 * for the zone, just queue the new one and exit.
	 */
	if (zone->rss_event != NULL && zone->rss_event != event) {
		ISC_LIST_APPEND(zone->rss_events, event, ev_link);
		UNLOCK_ZONE(zone);
		return;
	}

 nextevent:
	if (zone->rss_event != NULL) {
		INSIST(zone->rss_event == event);
		UNLOCK_ZONE(zone);
	} else {
		zone->rss_event = event;
		dns_diff_init(zone->mctx, &zone->rss_diff);

		/*
		 * zone->db may be NULL, if the load from disk failed.
		 */
		result = ISC_R_SUCCESS;
		ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
		if (zone->db != NULL)
			dns_db_attach(zone->db, &zone->rss_db);
		else
			result = ISC_R_FAILURE;
		ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);

		if (result == ISC_R_SUCCESS && zone->raw != NULL)
			dns_zone_attach(zone->raw, &zone->rss_raw);
		else
			result = ISC_R_FAILURE;

		UNLOCK_ZONE(zone);

		CHECK(result);

		/*
		 * We first attempt to sync the raw zone to the secure zone
		 * by using the raw zone's journal, applying all the deltas
		 * from the latest source-serial of the secure zone up to
		 * the current serial number of the raw zone.
		 *
		 * If that fails, then we'll fall back to a direct comparison
		 * between raw and secure zones.
		 */
		CHECK(dns_journal_open(zone->rss_raw->mctx,
				       zone->rss_raw->journal,
				       DNS_JOURNAL_WRITE, &rjournal));

		result = dns_journal_open(zone->mctx, zone->journal,
					  DNS_JOURNAL_READ, &sjournal);
		if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
			goto failure;

		if (!dns_journal_get_sourceserial(rjournal, &start)) {
			start = dns_journal_first_serial(rjournal);
			dns_journal_set_sourceserial(rjournal, start);
		}
		if (sjournal != NULL) {
			uint32_t serial;
			/*
			 * We read the secure journal first, if that
			 * exists use its value provided it is greater
			 * that from the raw journal.
			 */
			if (dns_journal_get_sourceserial(sjournal, &serial)) {
				if (isc_serial_gt(serial, start))
					start = serial;
			}
			dns_journal_destroy(&sjournal);
		}

		dns_db_currentversion(zone->rss_db, &zone->rss_oldver);
		CHECK(dns_db_newversion(zone->rss_db, &zone->rss_newver));

		/*
		 * Try to apply diffs from the raw zone's journal to the secure
		 * zone.  If that fails, we recover by syncing up the databases
		 * directly.
		 */
		result = sync_secure_journal(zone, zone->rss_raw, rjournal,
					     start, end, &soatuple,
					     &zone->rss_diff);
		if (result == DNS_R_UNCHANGED)
			goto failure;
		else if (result != ISC_R_SUCCESS)
			CHECK(sync_secure_db(zone, zone->rss_raw, zone->rss_db,
					     zone->rss_oldver, &soatuple,
					     &zone->rss_diff));

		CHECK(dns_diff_apply(&zone->rss_diff, zone->rss_db,
				     zone->rss_newver));

		if (soatuple != NULL) {
			uint32_t oldserial;

			CHECK(dns_db_createsoatuple(zone->rss_db,
						    zone->rss_oldver,
						    zone->rss_diff.mctx,
						    DNS_DIFFOP_DEL, &tuple));
			oldserial = dns_soa_getserial(&tuple->rdata);
			newserial = desired =
				    dns_soa_getserial(&soatuple->rdata);
			if (!isc_serial_gt(newserial, oldserial)) {
				newserial = oldserial + 1;
				if (newserial == 0)
					newserial++;
				dns_soa_setserial(newserial, &soatuple->rdata);
			}
			CHECK(do_one_tuple(&tuple, zone->rss_db,
					   zone->rss_newver, &zone->rss_diff));
			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,
						&zone->rss_diff, zone->mctx,
						zone->updatemethod));

	}
	result = dns_update_signaturesinc(&log, zone, zone->rss_db,
					  zone->rss_oldver, zone->rss_newver,
					  &zone->rss_diff,
					  zone->sigvalidityinterval,
					  &zone->rss_state);
	if (result == DNS_R_CONTINUE) {
		if (rjournal != NULL)
			dns_journal_destroy(&rjournal);
		isc_task_send(task, &event);
		return;
	}
	/*
	 * If something went wrong while trying to update the secure zone and
	 * the latter was already signed before, do not apply raw zone deltas
	 * to it as that would break existing DNSSEC signatures.  However, if
	 * the secure zone was not yet signed (e.g. because no signing keys
	 * were created for it), commence applying raw zone deltas to it so
	 * that contents of the raw zone and the secure zone are kept in sync.
	 */
	if (result != ISC_R_SUCCESS && dns_db_issecure(zone->rss_db)) {
		goto failure;
	}

	if (rjournal == NULL)
		CHECK(dns_journal_open(zone->rss_raw->mctx,
				       zone->rss_raw->journal,
				       DNS_JOURNAL_WRITE, &rjournal));
	CHECK(zone_journal(zone, &zone->rss_diff, &end,
			   "receive_secure_serial"));

	dns_journal_set_sourceserial(rjournal, end);
	dns_journal_commit(rjournal);

	LOCK_ZONE(zone);
	DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);

	zone->sourceserial = end;
	zone->sourceserialset = true;
	zone_needdump(zone, DNS_DUMP_DELAY);

	TIME_NOW(&timenow);
	zone_settimer(zone, &timenow);
	UNLOCK_ZONE(zone);

	dns_db_closeversion(zone->rss_db, &zone->rss_oldver, false);
	dns_db_closeversion(zone->rss_db, &zone->rss_newver, true);

	if (newserial != 0) {
		dns_zone_log(zone, ISC_LOG_INFO, "serial %u (unsigned %u)",
			     newserial, desired);
	}

 failure:
	isc_event_free(&zone->rss_event);
	event = ISC_LIST_HEAD(zone->rss_events);

	if (zone->rss_raw != NULL)
		dns_zone_detach(&zone->rss_raw);
	if (result != ISC_R_SUCCESS)
		dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_serial: %s",
			     dns_result_totext(result));
	if (tuple != NULL)
		dns_difftuple_free(&tuple);
	if (soatuple != NULL)
		dns_difftuple_free(&soatuple);
	if (zone->rss_db != NULL) {
		if (zone->rss_oldver != NULL)
			dns_db_closeversion(zone->rss_db, &zone->rss_oldver,
					    false);
		if (zone->rss_newver != NULL)
			dns_db_closeversion(zone->rss_db, &zone->rss_newver,
					    false);
		dns_db_detach(&zone->rss_db);
	}
	INSIST(zone->rss_oldver == NULL);
	INSIST(zone->rss_newver == NULL);
	if (rjournal != NULL)
		dns_journal_destroy(&rjournal);
	dns_diff_clear(&zone->rss_diff);

	if (event != NULL) {
		LOCK_ZONE(zone);
		INSIST(zone->irefs > 1);
		zone->irefs--;
		ISC_LIST_UNLINK(zone->rss_events, event, ev_link);
		goto nextevent;
	}
	dns_zone_idetach(&zone);
}

Project: bind9
File: zone.c

dns_zone_refresh(dns_zone_t *zone) {
	isc_interval_t i;
	uint32_t oldflags;
	unsigned int j;
	isc_result_t result;

	REQUIRE(DNS_ZONE_VALID(zone));

	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
		return;

	/*
	 * Set DNS_ZONEFLG_REFRESH so that there is only one refresh operation
	 * in progress at a time.
	 */

	LOCK_ZONE(zone);
	oldflags = zone->flags;
	if (zone->masterscnt == 0) {
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOMASTERS);
		if ((oldflags & DNS_ZONEFLG_NOMASTERS) == 0)
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "cannot refresh: no masters");
		goto unlock;
	}
	DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH);
	DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS);
	DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
	if ((oldflags & (DNS_ZONEFLG_REFRESH|DNS_ZONEFLG_LOADING)) != 0)
		goto unlock;

	/*
	 * Set the next refresh time as if refresh check has failed.
	 * Setting this to the retry time will do that.  XXXMLG
	 * If we are successful it will be reset using zone->refresh.
	 */
	isc_interval_set(&i, zone->retry - isc_random_uniform(zone->retry / 4),
			 0);
	result = isc_time_nowplusinterval(&zone->refreshtime, &i);
	if (result != ISC_R_SUCCESS)
		dns_zone_log(zone, ISC_LOG_WARNING,
			     "isc_time_nowplusinterval() failed: %s",
			     dns_result_totext(result));

	/*
	 * When lacking user-specified timer values from the SOA,
	 * do exponential backoff of the retry time up to a
	 * maximum of six hours.
	 */
	if (! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HAVETIMERS))
		zone->retry = ISC_MIN(zone->retry * 2, 6 * 3600);

	zone->curmaster = 0;
	for (j = 0; j < zone->masterscnt; j++)
		zone->mastersok[j] = false;
	/* initiate soa query */
	queue_soa_query(zone);
 unlock:
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

receive_secure_db(isc_task_t *task, isc_event_t *event) {
	isc_result_t result;
	dns_zone_t *zone;
	dns_db_t *rawdb, *db = NULL;
	dns_dbnode_t *rawnode = NULL, *node = NULL;
	dns_fixedname_t fname;
	dns_name_t *name;
	dns_dbiterator_t *dbiterator = NULL;
	dns_rdatasetiter_t *rdsit = NULL;
	dns_rdataset_t rdataset;
	dns_dbversion_t *version = NULL;
	isc_time_t loadtime;
	unsigned int oldserial = 0;
	bool have_oldserial = false;
	nsec3paramlist_t nsec3list;
	isc_event_t *setnsec3param_event;
	dns_zone_t *dummy;

	UNUSED(task);

	ISC_LIST_INIT(nsec3list);

	zone = event->ev_arg;
	rawdb = ((struct secure_event *)event)->db;
	isc_event_free(&event);

	name = dns_fixedname_initname(&fname);
	dns_rdataset_init(&rdataset);

	LOCK_ZONE(zone);
	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || !inline_secure(zone)) {
		result = ISC_R_SHUTTINGDOWN;
		goto failure;
	}

	TIME_NOW(&loadtime);
	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	if (zone->db != NULL) {
		result = dns_db_getsoaserial(zone->db, NULL, &oldserial);
		if (result == ISC_R_SUCCESS)
			have_oldserial = true;

		/*
		 * assemble nsec3parameters from the old zone, and set a flag
		 * if any are found
		 */
		result = save_nsec3param(zone, &nsec3list);
		if (result != ISC_R_SUCCESS) {
			ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
			goto failure;
		}
	}
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);

	result = dns_db_create(zone->mctx, zone->db_argv[0],
			       &zone->origin, dns_dbtype_zone, zone->rdclass,
			       zone->db_argc - 1, zone->db_argv + 1, &db);
	if (result != ISC_R_SUCCESS)
		goto failure;

	result = dns_db_setgluecachestats(db, zone->gluecachestats);
	if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
		goto failure;
	}

	result = dns_db_newversion(db, &version);
	if (result != ISC_R_SUCCESS)
		goto failure;

	result = dns_db_createiterator(rawdb, 0, &dbiterator);
	if (result != ISC_R_SUCCESS)
		goto failure;

	for (result = dns_dbiterator_first(dbiterator);
	     result == ISC_R_SUCCESS;
	     result = dns_dbiterator_next(dbiterator)) {
		result = dns_dbiterator_current(dbiterator, &rawnode, name);
		if (result != ISC_R_SUCCESS)
			continue;

		result = dns_db_findnode(db, name, true, &node);
		if (result != ISC_R_SUCCESS)
			goto failure;

		result = dns_db_allrdatasets(rawdb, rawnode, NULL, 0, &rdsit);
		if (result != ISC_R_SUCCESS)
			goto failure;

		for (result = dns_rdatasetiter_first(rdsit);
		     result == ISC_R_SUCCESS;
		     result = dns_rdatasetiter_next(rdsit)) {
			dns_rdatasetiter_current(rdsit, &rdataset);
			if (rdataset.type == dns_rdatatype_nsec ||
			    rdataset.type == dns_rdatatype_rrsig ||
			    rdataset.type == dns_rdatatype_nsec3 ||
			    rdataset.type == dns_rdatatype_dnskey ||
			    rdataset.type == dns_rdatatype_nsec3param) {
				dns_rdataset_disassociate(&rdataset);
				continue;
			}
			if (rdataset.type == dns_rdatatype_soa &&
			    have_oldserial) {
				result = checkandaddsoa(db, node, version,
							&rdataset, oldserial);
			} else
				result = dns_db_addrdataset(db, node, version,
							    0, &rdataset, 0,
							    NULL);
			if (result != ISC_R_SUCCESS)
				goto failure;

			dns_rdataset_disassociate(&rdataset);
		}
		dns_rdatasetiter_destroy(&rdsit);
		dns_db_detachnode(rawdb, &rawnode);
		dns_db_detachnode(db, &node);
	}

	/*
	 * Call restore_nsec3param() to create private-type records from
	 * the old nsec3 parameters and insert them into db
	 */
	if (!ISC_LIST_EMPTY(nsec3list)) {
		result = restore_nsec3param(zone, db, version, &nsec3list);
		if (result != ISC_R_SUCCESS) {
			goto failure;
		}
	}

	dns_db_closeversion(db, &version, true);

	/*
	 * Lock hierarchy: zmgr, zone, raw.
	 */
	INSIST(zone != zone->raw);
	LOCK_ZONE(zone->raw);
	DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
	result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS);
	zone_needdump(zone, 0); /* XXXMPA */
	UNLOCK_ZONE(zone->raw);

	/*
	 * Process any queued NSEC3PARAM change requests.
	 */
	while (!ISC_LIST_EMPTY(zone->setnsec3param_queue)) {
		setnsec3param_event = ISC_LIST_HEAD(zone->setnsec3param_queue);
		ISC_LIST_UNLINK(zone->setnsec3param_queue, setnsec3param_event,
				ev_link);
		dummy = NULL;
		zone_iattach(zone, &dummy);
		isc_task_send(zone->task, &setnsec3param_event);
	}

 failure:
	UNLOCK_ZONE(zone);
	if (result != ISC_R_SUCCESS)
		dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_db: %s",
			     dns_result_totext(result));

	while (!ISC_LIST_EMPTY(nsec3list)) {
		nsec3param_t *nsec3p;
		nsec3p = ISC_LIST_HEAD(nsec3list);
		ISC_LIST_UNLINK(nsec3list, nsec3p, link);
		isc_mem_put(zone->mctx, nsec3p, sizeof(nsec3param_t));
	}
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	if (db != NULL) {
		if (node != NULL)
			dns_db_detachnode(db, &node);
		if (version != NULL)
			dns_db_closeversion(db, &version, false);
		dns_db_detach(&db);
	}
	if (rawnode != NULL)
		dns_db_detachnode(rawdb, &rawnode);
	dns_db_detach(&rawdb);
	if (dbiterator != NULL)
		dns_dbiterator_destroy(&dbiterator);
	dns_zone_idetach(&zone);

	INSIST(version == NULL);
}

Project: bind9
File: zone.c

get_master_options(dns_zone_t *zone) {
	unsigned int options;

	options = DNS_MASTER_ZONE | DNS_MASTER_RESIGN;
	if (zone->type == dns_zone_slave || zone->type == dns_zone_mirror ||
	    (zone->type == dns_zone_redirect && zone->masters == NULL))
	{
		options |= DNS_MASTER_SLAVE;
	}
	if (zone->type == dns_zone_key) {
		options |= DNS_MASTER_KEY;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) {
		options |= DNS_MASTER_CHECKNS;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) {
		options |= DNS_MASTER_FATALNS;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES)) {
		options |= DNS_MASTER_CHECKNAMES;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) {
		options |= DNS_MASTER_CHECKNAMESFAIL;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX)) {
		options |= DNS_MASTER_CHECKMX;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) {
		options |= DNS_MASTER_CHECKMXFAIL;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD)) {
		options |= DNS_MASTER_CHECKWILDCARD;
	}
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKTTL)) {
		options |= DNS_MASTER_CHECKTTL;
	}

	return (options);
}

Project: bind9
File: zone.c

setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value) {
	isc_interval_t interval;
	uint32_t s, ns;
	uint32_t pertic;
	isc_result_t result;

	if (value == 0)
		value = 1;

	if (value == 1) {
		s = 1;
		ns = 0;
		pertic = 1;
	} else if (value <= 10) {
		s = 0;
		ns = 1000000000 / value;
		pertic = 1;
	} else {
		s = 0;
		ns = (1000000000 / value) * 10;
		pertic = 10;
	}

	isc_interval_set(&interval, s, ns);

	result = isc_ratelimiter_setinterval(rl, &interval);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
	isc_ratelimiter_setpertic(rl, pertic);

	*rate = value;
}

Project: bind9
File: zone.c

dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity) {
	REQUIRE(DNS_ZONE_VALID(zone));

	zone->check_names = severity;
}

Project: bind9
File: zone.c

dns_zone_setkeyvalidityinterval(dns_zone_t *zone, uint32_t interval) {
	REQUIRE(DNS_ZONE_VALID(zone));

	zone->keyvalidityinterval = interval;
}

Project: bind9
File: zone.c

dns_zone_setidlein(dns_zone_t *zone, uint32_t idlein) {
	REQUIRE(DNS_ZONE_VALID(zone));

	if (idlein == 0)
		idlein = DNS_DEFAULT_IDLEIN;
	zone->idlein = idlein;
}

Project: bind9
File: zone.c

dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value) {
	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	zmgr->transfersin = value;
}

Project: bind9
File: zone.c

clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) {
	dns_dnsseckey_t *key;
	while (!ISC_LIST_EMPTY(*list)) {
		key = ISC_LIST_HEAD(*list);
		ISC_LIST_UNLINK(*list, key, link);
		dns_dnsseckey_destroy(mctx, &key);
	}
}

Project: bind9
File: zone.c

dns_zone_log(dns_zone_t *zone, int level, const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	dns_zone_logv(zone, DNS_LOGCATEGORY_GENERAL, level, NULL, fmt, ap);
	va_end(ap);
}

Project: bind9
File: zone.c

dns_zone_getincludes(dns_zone_t *zone, char ***includesp) {
	dns_include_t *include;
	char **array = NULL;
	unsigned int n = 0;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(includesp != NULL && *includesp == NULL);

	LOCK_ZONE(zone);
	if (zone->nincludes == 0)
		goto done;

	array = isc_mem_allocate(zone->mctx, sizeof(char *) * zone->nincludes);
	if (array == NULL)
		goto done;
	for (include = ISC_LIST_HEAD(zone->includes);
	     include != NULL;
	     include = ISC_LIST_NEXT(include, link)) {
		INSIST(n < zone->nincludes);
		array[n++] = isc_mem_strdup(zone->mctx, include->name);
	}
	INSIST(n == zone->nincludes);
	*includesp = array;

 done:
	UNLOCK_ZONE(zone);
	return (n);
}

Project: bind9
File: zone.c

normalize_key(dns_rdata_t *rr, dns_rdata_t *target,
	      unsigned char *data, int size)
{
	dns_rdata_dnskey_t dnskey;
	dns_rdata_keydata_t keydata;
	isc_buffer_t buf;
	isc_result_t result;

	dns_rdata_reset(target);
	isc_buffer_init(&buf, data, size);

	switch (rr->type) {
	    case dns_rdatatype_dnskey:
		result = dns_rdata_tostruct(rr, &dnskey, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		dnskey.flags &= ~DNS_KEYFLAG_REVOKE;
		dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey,
				     &dnskey, &buf);
		break;
	    case dns_rdatatype_keydata:
		result = dns_rdata_tostruct(rr, &keydata, NULL);
		if (result == ISC_R_UNEXPECTEDEND)
			return (result);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		dns_keydata_todnskey(&keydata, &dnskey, NULL);
		dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey,
				     &dnskey, &buf);
		break;
	    default:
		INSIST(0);
		ISC_UNREACHABLE();
	}
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

clean_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
		 dns_diff_t *diff)
{
	isc_result_t result;
	dns_dbnode_t *node = NULL;
	dns_rdataset_t rdataset;

	dns_rdataset_init(&rdataset);
	CHECK(dns_db_getoriginnode(db, &node));

	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey,
				     dns_rdatatype_none, 0, &rdataset, NULL);
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	if (result != ISC_R_NOTFOUND)
		goto failure;

	result = dns_nsec3param_deletechains(db, ver, zone, true, diff);

 failure:
	if (node != NULL)
		dns_db_detachnode(db, &node);
	return (result);
}

Project: bind9
File: zone.c

dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) {

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	setrl(zmgr->refreshrl, &zmgr->serialqueryrate, value);
	/* XXXMPA seperate out once we have the code to support this. */
	setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, value);
}

Project: bind9
File: zone.c

zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
	dns_peer_t *peer = NULL;
	isc_netaddr_t masterip;
	uint32_t nxfrsin, nxfrsperns;
	dns_zone_t *x;
	uint32_t maxtransfersin, maxtransfersperns;
	isc_event_t *e;

	/*
	 * If we are exiting just pretend we got quota so the zone will
	 * be cleaned up in the zone's task context.
	 */
	LOCK_ZONE(zone);
	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
		UNLOCK_ZONE(zone);
		goto gotquota;
	}

	/*
	 * Find any configured information about the server we'd
	 * like to transfer this zone from.
	 */
	isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
	(void)dns_peerlist_peerbyaddr(zone->view->peers, &masterip, &peer);
	UNLOCK_ZONE(zone);

	/*
	 * Determine the total maximum number of simultaneous
	 * transfers allowed, and the maximum for this specific
	 * master.
	 */
	maxtransfersin = zmgr->transfersin;
	maxtransfersperns = zmgr->transfersperns;
	if (peer != NULL)
		(void)dns_peer_gettransfers(peer, &maxtransfersperns);

	/*
	 * Count the total number of transfers that are in progress,
	 * and the number of transfers in progress from this master.
	 * We linearly scan a list of all transfers; if this turns
	 * out to be too slow, we could hash on the master address.
	 */
	nxfrsin = nxfrsperns = 0;
	for (x = ISC_LIST_HEAD(zmgr->xfrin_in_progress);
	     x != NULL;
	     x = ISC_LIST_NEXT(x, statelink))
	{
		isc_netaddr_t xip;

		LOCK_ZONE(x);
		isc_netaddr_fromsockaddr(&xip, &x->masteraddr);
		UNLOCK_ZONE(x);

		nxfrsin++;
		if (isc_netaddr_equal(&xip, &masterip))
			nxfrsperns++;
	}

	/* Enforce quota. */
	if (nxfrsin >= maxtransfersin)
		return (ISC_R_QUOTA);

	if (nxfrsperns >= maxtransfersperns)
		return (ISC_R_QUOTA);

 gotquota:
	/*
	 * We have sufficient quota.  Move the zone to the "xfrin_in_progress"
	 * list and send it an event to let it start the actual transfer in the
	 * context of its own task.
	 */
	e = isc_event_allocate(zmgr->mctx, zmgr, DNS_EVENT_ZONESTARTXFRIN,
			       got_transfer_quota, zone, sizeof(isc_event_t));
	if (e == NULL)
		return (ISC_R_NOMEMORY);

	LOCK_ZONE(zone);
	INSIST(zone->statelist == &zmgr->waiting_for_xfrin);
	ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink);
	ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink);
	zone->statelist = &zmgr->xfrin_in_progress;
	isc_task_send(zone->task, &e);
	dns_zone_log(zone, ISC_LOG_INFO, "Transfer started.");
	UNLOCK_ZONE(zone);

	return (ISC_R_SUCCESS);
}