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_resigninc(dns_zone_t *zone) {
	const char *me = "zone_resigninc";
	dns_db_t *db = NULL;
	dns_dbversion_t *version = NULL;
	dns_diff_t _sig_diff;
	dns__zonediff_t zonediff;
	dns_fixedname_t fixed;
	dns_name_t *name;
	dns_rdataset_t rdataset;
	dns_rdatatype_t covers;
	dst_key_t *zone_keys[DNS_MAXZONEKEYS];
	bool check_ksk, keyset_kskonly = false;
	isc_result_t result;
	isc_stdtime_t now, inception, soaexpire, expire, stop;
	uint32_t jitter, sigvalidityinterval;
	unsigned int i;
	unsigned int nkeys = 0;
	unsigned int resign;

	ENTER;

	dns_rdataset_init(&rdataset);
	dns_diff_init(zone->mctx, &_sig_diff);
	zonediff_init(&zonediff, &_sig_diff);

	/*
	 * Zone is frozen or automatic resigning is disabled.
	 * Pause for 5 minutes.
	 */
	if (zone->update_disabled ||
	    DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_NORESIGN))
	{
		result = ISC_R_FAILURE;
		goto failure;
	}

	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	dns_db_attach(zone->db, &db);
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);

	result = dns_db_newversion(db, &version);
	if (result != ISC_R_SUCCESS) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "zone_resigninc: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) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "zone_resigninc:dns__zone_findkeys -> %s",
			     dns_result_totext(result));
		goto failure;
	}

	sigvalidityinterval = zone->sigvalidityinterval;
	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;
	}
	stop = now + 5;

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

	name = dns_fixedname_initname(&fixed);
	result = dns_db_getsigningtime(db, &rdataset, name);
	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "zone_resigninc:dns_db_getsigningtime -> %s",
			     dns_result_totext(result));
	}

	i = 0;
	while (result == ISC_R_SUCCESS) {
		resign = rdataset.resign - zone->sigresigninginterval;
		covers = rdataset.covers;
		dns_rdataset_disassociate(&rdataset);

		/*
		 * Stop if we hit the SOA as that means we have walked the
		 * entire zone.  The SOA record should always be the most
		 * recent signature.
		 */
		/* XXXMPA increase number of RRsets signed pre call */
		if (covers == dns_rdatatype_soa || i++ > zone->signatures ||
		    resign > stop)
			break;

		result = del_sigs(zone, db, version, name, covers, &zonediff,
				  zone_keys, nkeys, now, true);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "zone_resigninc:del_sigs -> %s",
				     dns_result_totext(result));
			break;
		}

		result = add_sigs(db, version, name, covers, zonediff.diff,
				  zone_keys, nkeys, zone->mctx, inception,
				  expire, check_ksk, keyset_kskonly);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "zone_resigninc:add_sigs -> %s",
				     dns_result_totext(result));
			break;
		}
		result	= dns_db_getsigningtime(db, &rdataset, name);
		if (nkeys == 0 && result == ISC_R_NOTFOUND) {
			result = ISC_R_SUCCESS;
			break;
		}
		if (result != ISC_R_SUCCESS)
			dns_zone_log(zone, ISC_LOG_ERROR,
			     "zone_resigninc:dns_db_getsigningtime -> %s",
				     dns_result_totext(result));
	}

	if (result != ISC_R_NOMORE && result != ISC_R_SUCCESS)
		goto failure;

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

	/*
	 * Did we change anything in the zone?
	 */
	if (ISC_LIST_EMPTY(zonediff.diff->tuples)) {
		/*
		 * Commit the changes if any key has been marked as offline.
		 */
		if (zonediff.offline)
			dns_db_closeversion(db, &version, true);
		goto failure;
	}

	/* Increment SOA serial if we have made changes */
	result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
				   zone->updatemethod);
	if (result != ISC_R_SUCCESS) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "zone_resigninc:update_soa_serial -> %s",
			     dns_result_totext(result));
		goto failure;
	}

	/*
	 * 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) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "zone_resigninc:add_sigs -> %s",
			     dns_result_totext(result));
		goto failure;
	}

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

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

 failure:
	dns_diff_clear(&_sig_diff);
	for (i = 0; i < nkeys; i++)
		dst_key_free(&zone_keys[i]);
	if (version != NULL) {
		dns_db_closeversion(db, &version, false);
		dns_db_detach(&db);
	} else if (db != NULL)
		dns_db_detach(&db);
	if (result == ISC_R_SUCCESS) {
		set_resigntime(zone);
		LOCK_ZONE(zone);
		zone_needdump(zone, DNS_DUMP_DELAY);
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
		UNLOCK_ZONE(zone);
	} else {
		/*
		 * Something failed.  Retry in 5 minutes.
		 */
		isc_interval_t ival;
		isc_interval_set(&ival, 300, 0);
		isc_time_nowplusinterval(&zone->resigntime, &ival);
	}

	INSIST(version == NULL);
}

Project: bind9
File: zone.c

dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl) {

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	if (zone->update_acl != NULL)
		dns_acl_detach(&zone->update_acl);
	dns_acl_attach(acl, &zone->update_acl);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

zone_loaddone(void *arg, isc_result_t result) {
	static char me[] = "zone_loaddone";
	dns_load_t *load = arg;
	dns_zone_t *zone;
	isc_result_t tresult;
	dns_zone_t *secure = NULL;

	REQUIRE(DNS_LOAD_VALID(load));
	zone = load->zone;

	ENTER;

	tresult = dns_db_endload(load->db, &load->callbacks);
	if (tresult != ISC_R_SUCCESS &&
	    (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
		result = tresult;

	/*
	 * Lock hierarchy: zmgr, zone, raw.
	 */
 again:
	LOCK_ZONE(zone);
	INSIST(zone != zone->raw);
	if (inline_secure(zone))
		LOCK_ZONE(zone->raw);
	else if (inline_raw(zone)) {
		secure = zone->secure;
		TRYLOCK_ZONE(result, secure);
		if (result != ISC_R_SUCCESS) {
			UNLOCK_ZONE(zone);
			secure = NULL;
			isc_thread_yield();
			goto again;
		}
	}
	(void)zone_postload(zone, load->db, load->loadtime, result);
	zonemgr_putio(&zone->readio);
	DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADING);
	zone_idetach(&load->callbacks.zone);
	/*
	 * Leave the zone frozen if the reload fails.
	 */
	if ((result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) &&
	     DNS_ZONE_FLAG(zone, DNS_ZONEFLG_THAW))
		zone->update_disabled = false;
	DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_THAW);
	if (inline_secure(zone))
		UNLOCK_ZONE(zone->raw);
	else if (secure != NULL)
		UNLOCK_ZONE(secure);
	UNLOCK_ZONE(zone);

	load->magic = 0;
	dns_db_detach(&load->db);
	if (load->zone->lctx != NULL)
		dns_loadctx_detach(&load->zone->lctx);
	dns_zone_idetach(&load->zone);
	isc_mem_putanddetach(&load->mctx, load, sizeof(*load));
}

Project: bind9
File: zone.c

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

Project: bind9
File: zone.c

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

	return (zone->journalsize);
}

Project: bind9
File: zone.c

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

	LOCK_ZONE(zone);
	if (zone->prev_view != NULL)
		dns_view_weakdetach(&zone->prev_view);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
	dns_notify_t *notify;
	isc_result_t result;
	dns_message_t *message = NULL;
	isc_netaddr_t dstip;
	dns_tsigkey_t *key = NULL;
	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
	isc_sockaddr_t src;
	unsigned int options, timeout;
	bool have_notifysource = false;
	bool have_notifydscp = false;
	isc_dscp_t dscp = -1;

	notify = event->ev_arg;
	REQUIRE(DNS_NOTIFY_VALID(notify));

	UNUSED(task);

	LOCK_ZONE(notify->zone);

	notify->event = NULL;

	if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0) {
		result = ISC_R_CANCELED;
		goto cleanup;
	}

	if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 ||
	    DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING) ||
	    notify->zone->view->requestmgr == NULL ||
	    notify->zone->db == NULL) {
		result = ISC_R_CANCELED;
		goto cleanup;
	}

	/*
	 * The raw IPv4 address should also exist.  Don't send to the
	 * mapped form.
	 */
	if (isc_sockaddr_pf(&notify->dst) == PF_INET6 &&
	    IN6_IS_ADDR_V4MAPPED(&notify->dst.type.sin6.sin6_addr)) {
		isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
		notify_log(notify->zone, ISC_LOG_DEBUG(3),
			   "notify: ignoring IPv6 mapped IPV4 address: %s",
			   addrbuf);
		result = ISC_R_CANCELED;
		goto cleanup;
	}

	result = notify_createmessage(notify->zone, notify->flags, &message);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
	if (notify->key != NULL) {
		/* Transfer ownership of key */
		key = notify->key;
		notify->key = NULL;
	} else {
		isc_netaddr_fromsockaddr(&dstip, &notify->dst);
		result = dns_view_getpeertsig(notify->zone->view, &dstip, &key);
		if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
			notify_log(notify->zone, ISC_LOG_ERROR,
				   "NOTIFY to %s not sent. "
				   "Peer TSIG key lookup failure.", addrbuf);
			goto cleanup_message;
		}
	}

	/* XXX: should we log the tsig key too? */
	notify_log(notify->zone, ISC_LOG_DEBUG(3), "sending notify to %s",
		   addrbuf);
	options = 0;
	if (notify->zone->view->peers != NULL) {
		dns_peer_t *peer = NULL;
		bool usetcp = false;
		result = dns_peerlist_peerbyaddr(notify->zone->view->peers,
						 &dstip, &peer);
		if (result == ISC_R_SUCCESS) {
			result = dns_peer_getnotifysource(peer, &src);
			if (result == ISC_R_SUCCESS)
				have_notifysource = true;
			dns_peer_getnotifydscp(peer, &dscp);
			if (dscp != -1)
				have_notifydscp = true;
			result = dns_peer_getforcetcp(peer, &usetcp);
			if (result == ISC_R_SUCCESS && usetcp)
				options |= DNS_FETCHOPT_TCP;
		}
	}
	switch (isc_sockaddr_pf(&notify->dst)) {
	case PF_INET:
		if (!have_notifysource)
			src = notify->zone->notifysrc4;
		if (!have_notifydscp)
			dscp = notify->zone->notifysrc4dscp;
		break;
	case PF_INET6:
		if (!have_notifysource)
			src = notify->zone->notifysrc6;
		if (!have_notifydscp)
			dscp = notify->zone->notifysrc6dscp;
		break;
	default:
		result = ISC_R_NOTIMPLEMENTED;
		goto cleanup_key;
	}
	timeout = 15;
	if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_DIALNOTIFY))
		timeout = 30;
	result = dns_request_createvia(notify->zone->view->requestmgr,
				       message, &src, &notify->dst, dscp,
				       options, key, timeout * 3, timeout,
				       0, notify->zone->task, notify_done,
				       notify, &notify->request);
	if (result == ISC_R_SUCCESS) {
		if (isc_sockaddr_pf(&notify->dst) == AF_INET) {
			inc_stats(notify->zone,
				  dns_zonestatscounter_notifyoutv4);
		} else {
			inc_stats(notify->zone,
				  dns_zonestatscounter_notifyoutv6);
		}
	}

 cleanup_key:
	if (key != NULL)
		dns_tsigkey_detach(&key);
 cleanup_message:
	dns_message_destroy(&message);
 cleanup:
	UNLOCK_ZONE(notify->zone);
	isc_event_free(&event);
	if (result != ISC_R_SUCCESS)
		notify_destroy(notify, false);
}

Project: bind9
File: zone.c

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

	return (zmgr->transfersperns);
}

Project: bind9
File: zone.c

fail_secure(dns_zone_t *zone, dns_name_t *keyname) {
	isc_result_t result;
	dns_keytable_t *sr = NULL;

	result = dns_view_getsecroots(zone->view, &sr);
	if (result == ISC_R_SUCCESS) {
		dns_keytable_marksecure(sr, keyname);
		dns_keytable_detach(&sr);
	}
}

Project: bind9
File: zone.c

dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
			   isc_sockaddr_t *local)
{
	unsigned int i;
	isc_rwlocktype_t locktype;
	isc_result_t result;

	char master[ISC_SOCKADDR_FORMATSIZE];
	char source[ISC_SOCKADDR_FORMATSIZE];

	isc_sockaddr_format(remote, master, sizeof(master));
	isc_sockaddr_format(local, source, sizeof(source));

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	locktype = isc_rwlocktype_read;
	RWLOCK(&zmgr->urlock, locktype);
	for (i = 0; i < UNREACH_CHACHE_SIZE; i++) {
		if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) &&
		    isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) {
			if (zmgr->unreachable[i].expire == 0)
				break;
			result = isc_rwlock_tryupgrade(&zmgr->urlock);
			if (result == ISC_R_SUCCESS) {
				locktype = isc_rwlocktype_write;
				zmgr->unreachable[i].expire = 0;
				isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
					      DNS_LOGMODULE_ZONE, ISC_LOG_INFO,
					      "master %s (source %s) deleted "
					      "from unreachable cache",
					      master, source);
			}
			break;
		}
	}
	RWUNLOCK(&zmgr->urlock, locktype);
}

Project: bind9
File: zone.c

dns_zone_setmaxrefreshtime(dns_zone_t *zone, uint32_t val) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(val > 0);

	zone->maxrefresh = val;
}

Project: bind9
File: zone.c

dns_zone_setupdatedisabled(dns_zone_t *zone, bool state) {
	REQUIRE(DNS_ZONE_VALID(zone));
	zone->update_disabled = state;
}

Project: bind9
File: zone.c

inc_stats(dns_zone_t *zone, isc_statscounter_t counter) {
	if (zone->stats != NULL)
		isc_stats_increment(zone->stats, counter);
}

Project: bind9
File: zone.c

dns_zone_getxfrsource4dscp(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->xfrsource4dscp);
}

Project: bind9
File: zone.c

zone_detachdb(dns_zone_t *zone) {
	REQUIRE(zone->db != NULL);

	dns_db_detach(&zone->db);
}

Project: bind9
File: zone.c

dns_zone_setstring(dns_zone_t *zone, char **field, const char *value) {
	char *copy;

	if (value != NULL) {
		copy = isc_mem_strdup(zone->mctx, value);
		if (copy == NULL)
			return (ISC_R_NOMEMORY);
	} else {
		copy = NULL;
	}

	if (*field != NULL)
		isc_mem_free(zone->mctx, *field);

	*field = copy;
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zone_setnodes(dns_zone_t *zone, uint32_t nodes) {
	REQUIRE(DNS_ZONE_VALID(zone));

	if (nodes == 0)
		nodes = 1;
	zone->nodes = nodes;
}

Project: bind9
File: zone.c

dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) {
	char namebuf[1024];

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(type != dns_zone_none);

	/*
	 * Test and set.
	 */
	LOCK_ZONE(zone);
	REQUIRE(zone->type == dns_zone_none || zone->type == type);
	zone->type = type;

	if (zone->strnamerd != NULL)
		isc_mem_free(zone->mctx, zone->strnamerd);

	zone_namerd_tostr(zone, namebuf, sizeof namebuf);
	zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
	dns_nsec3chain_t *nsec3chain, *current;
	dns_dbversion_t *version = NULL;
	bool nseconly = false, nsec3ok = false;
	isc_result_t result;
	isc_time_t now;
	unsigned int options = 0;
	char saltbuf[255*2+1];
	char flags[sizeof("INITIAL|REMOVE|CREATE|NONSEC|OPTOUT")];
	dns_db_t *db = NULL;

	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_SUCCESS;
		goto cleanup;
	}

	/*
	 * If this zone is not NSEC3-capable, attempting to remove any NSEC3
	 * chain from it is pointless as it would not be possible for the
	 * latter to exist in the first place.
	 */
	dns_db_currentversion(db, &version);
	result = dns_nsec_nseconly(db, version, &nseconly);
	nsec3ok = (result == ISC_R_SUCCESS && !nseconly);
	dns_db_closeversion(db, &version, false);
	if (!nsec3ok && (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) == 0) {
		result = ISC_R_SUCCESS;
		goto cleanup;
	}

	/*
	 * Allocate and initialize structure preserving state of
	 * adding/removing records belonging to this NSEC3 chain between
	 * separate zone_nsec3chain() calls.
	 */
	nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain);
	if (nsec3chain == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}

	nsec3chain->magic = 0;
	nsec3chain->done = false;
	nsec3chain->db = NULL;
	nsec3chain->dbiterator = NULL;
	nsec3chain->nsec3param.common.rdclass = nsec3param->common.rdclass;
	nsec3chain->nsec3param.common.rdtype = nsec3param->common.rdtype;
	nsec3chain->nsec3param.hash = nsec3param->hash;
	nsec3chain->nsec3param.iterations = nsec3param->iterations;
	nsec3chain->nsec3param.flags = nsec3param->flags;
	nsec3chain->nsec3param.salt_length = nsec3param->salt_length;
	memmove(nsec3chain->salt, nsec3param->salt, nsec3param->salt_length);
	nsec3chain->nsec3param.salt = nsec3chain->salt;
	nsec3chain->seen_nsec = false;
	nsec3chain->delete_nsec = false;
	nsec3chain->save_delete_nsec = false;

	/*
	 * Log NSEC3 parameters defined by supplied NSEC3PARAM RDATA.
	 */
	if (nsec3param->flags == 0) {
		strlcpy(flags, "NONE", sizeof(flags));
	} else {
		flags[0] = '\0';
		if ((nsec3param->flags & DNS_NSEC3FLAG_REMOVE) != 0) {
			strlcat(flags, "REMOVE", sizeof(flags));
		}
		if ((nsec3param->flags & DNS_NSEC3FLAG_INITIAL) != 0) {
			if (flags[0] == '\0') {
				strlcpy(flags, "INITIAL", sizeof(flags));
			} else {
				strlcat(flags, "|INITIAL", sizeof(flags));
			}
		}
		if ((nsec3param->flags & DNS_NSEC3FLAG_CREATE) != 0) {
			if (flags[0] == '\0') {
				strlcpy(flags, "CREATE", sizeof(flags));
			} else {
				strlcat(flags, "|CREATE", sizeof(flags));
			}
		}
		if ((nsec3param->flags & DNS_NSEC3FLAG_NONSEC) != 0) {
			if (flags[0] == '\0') {
				strlcpy(flags, "NONSEC", sizeof(flags));
			} else {
				strlcat(flags, "|NONSEC", sizeof(flags));
			}
		}
		if ((nsec3param->flags & DNS_NSEC3FLAG_OPTOUT) != 0) {
			if (flags[0] == '\0') {
				strlcpy(flags, "OPTOUT", sizeof(flags));
			} else {
				strlcat(flags, "|OPTOUT", sizeof(flags));
			}
		}
	}
	result = dns_nsec3param_salttotext(nsec3param, saltbuf,
					   sizeof(saltbuf));
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
	dnssec_log(zone, ISC_LOG_INFO, "zone_addnsec3chain(%u,%s,%u,%s)",
		   nsec3param->hash, flags, nsec3param->iterations, saltbuf);

	/*
	 * If the NSEC3 chain defined by the supplied NSEC3PARAM RDATA is
	 * currently being processed, interrupt its processing to avoid
	 * simultaneously adding and removing records for the same NSEC3 chain.
	 */
	for (current = ISC_LIST_HEAD(zone->nsec3chain);
	     current != NULL;
	     current = ISC_LIST_NEXT(current, link))
	{
		if ((current->db == db) &&
		    (current->nsec3param.hash == nsec3param->hash) &&
		    (current->nsec3param.iterations ==
		     nsec3param->iterations) &&
		    (current->nsec3param.salt_length ==
		     nsec3param->salt_length) &&
		    memcmp(current->nsec3param.salt, nsec3param->salt,
			   nsec3param->salt_length) == 0)
		{
			current->done = true;
		}
	}

	/*
	 * Attach zone database to the structure initialized above and create
	 * an iterator for it with appropriate options in order to avoid
	 * creating NSEC3 records for NSEC3 records.
	 */
	dns_db_attach(db, &nsec3chain->db);
	if ((nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0) {
		options = DNS_DB_NONSEC3;
	}
	result = dns_db_createiterator(nsec3chain->db, options,
				       &nsec3chain->dbiterator);
	if (result == ISC_R_SUCCESS) {
		result = dns_dbiterator_first(nsec3chain->dbiterator);
	}
	if (result == ISC_R_SUCCESS) {
		/*
		 * Database iterator initialization succeeded.  We are now
		 * ready to kick off adding/removing records belonging to this
		 * NSEC3 chain.  Append the structure initialized above to the
		 * "nsec3chain" list for the zone and set the appropriate zone
		 * timer so that zone_nsec3chain() is called as soon as
		 * possible.
		 */
		dns_dbiterator_pause(nsec3chain->dbiterator);
		ISC_LIST_INITANDAPPEND(zone->nsec3chain,
				       nsec3chain, link);
		nsec3chain = NULL;
		if (isc_time_isepoch(&zone->nsec3chaintime)) {
			TIME_NOW(&now);
			zone->nsec3chaintime = now;
			if (zone->task != NULL) {
				zone_settimer(zone, &now);
			}
		}
	}

	if (nsec3chain != NULL) {
		if (nsec3chain->db != NULL) {
			dns_db_detach(&nsec3chain->db);
		}
		if (nsec3chain->dbiterator != NULL) {
			dns_dbiterator_destroy(&nsec3chain->dbiterator);
		}
		isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
	}

 cleanup:
	if (db != NULL) {
		dns_db_detach(&db);
	}
	return (result);
}

Project: bind9
File: zone.c

dns_zone_nameonly(dns_zone_t *zone, char *buf, size_t length) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(buf != NULL);
	zone_name_tostr(zone, buf, length);
}

Project: bind9
File: zone.c

keydone(isc_task_t *task, isc_event_t *event) {
	const char *me = "keydone";
	bool commit = false;
	isc_result_t result;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_dbversion_t *oldver = NULL, *newver = NULL;
	dns_zone_t *zone;
	dns_db_t *db = NULL;
	dns_dbnode_t *node = NULL;
	dns_rdataset_t rdataset;
	dns_diff_t diff;
	struct keydone *kd = (struct keydone *)event;
	dns_update_log_t log = { update_log_cb, NULL };
	bool clear_pending = false;

	UNUSED(task);

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

	ENTER;

	dns_rdataset_init(&rdataset);
	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) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "keydone:dns_db_newversion -> %s",
			   dns_result_totext(result));
		goto failure;
	}

	result = dns_db_getoriginnode(db, &node);
	if (result != ISC_R_SUCCESS) {
		goto failure;
	}

	result = dns_db_findrdataset(db, node, newver, zone->privatetype,
				     dns_rdatatype_none, 0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto failure;
	}
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto failure;
	}

	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset))
	{
		bool found = false;

		dns_rdataset_current(&rdataset, &rdata);

		if (kd->all) {
			if (rdata.length == 5 && rdata.data[0] != 0 &&
			       rdata.data[3] == 0 && rdata.data[4] == 1)
			{
				found = true;
			} else if (rdata.data[0] == 0 &&
				   (rdata.data[2] & PENDINGFLAGS) != 0)
			{
				found = true;
				clear_pending = true;
			}
		} else if (rdata.length == 5 &&
			   memcmp(rdata.data, kd->data, 5) == 0)
		{
			found = true;
		}

		if (found) {
			CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_DEL,
					    &zone->origin, rdataset.ttl,
					    &rdata));
		}
		dns_rdata_reset(&rdata);
	}

	if (!ISC_LIST_EMPTY(diff.tuples)) {
		/* Write changes to journal file. */
		CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
					zone->updatemethod));

		result = dns_update_signatures(&log, zone, db,
					       oldver, newver, &diff,
					       zone->sigvalidityinterval);
		if (!clear_pending) {
			CHECK(result);
		}

		CHECK(zone_journal(zone, &diff, NULL, "keydone"));
		commit = true;

		LOCK_ZONE(zone);
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
		zone_needdump(zone, 30);
		UNLOCK_ZONE(zone);
	}

 failure:
	if (dns_rdataset_isassociated(&rdataset)) {
		dns_rdataset_disassociate(&rdataset);
	}
	if (db != NULL) {
		if (node != NULL) {
			dns_db_detachnode(db, &node);
		}
		if (oldver != NULL) {
			dns_db_closeversion(db, &oldver, false);
		}
		if (newver != NULL) {
			dns_db_closeversion(db, &newver, commit);
		}
		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

zone_journal(dns_zone_t *zone, dns_diff_t *diff, uint32_t *sourceserial,
	     const char *caller)
{
	const char me[] = "zone_journal";
	const char *journalfile;
	isc_result_t result = ISC_R_SUCCESS;
	dns_journal_t *journal = NULL;
	unsigned int mode = DNS_JOURNAL_CREATE|DNS_JOURNAL_WRITE;

	ENTER;
	journalfile = dns_zone_getjournal(zone);
	if (journalfile != NULL) {
		result = dns_journal_open(zone->mctx, journalfile, mode,
					  &journal);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "%s:dns_journal_open -> %s",
				     caller, dns_result_totext(result));
			return (result);
		}

		if (sourceserial != NULL)
			dns_journal_set_sourceserial(journal, *sourceserial);

		result = dns_journal_write_transaction(journal, diff);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "%s:dns_journal_write_transaction -> %s",
				     caller, dns_result_totext(result));
		}
		dns_journal_destroy(&journal);
	}

	return (result);
}

Project: bind9
File: zone.c

create_keydata(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
	       dns_diff_t *diff, dns_keytable_t *keytable,
	       dns_keynode_t **keynodep, bool *changed)
{
	const char me[] = "create_keydata";
	isc_result_t result = ISC_R_SUCCESS;
	isc_buffer_t keyb, dstb;
	unsigned char key_buf[4096], dst_buf[DST_KEY_MAXSIZE];
	dns_rdata_keydata_t keydata;
	dns_rdata_dnskey_t dnskey;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_keynode_t *keynode;
	isc_stdtime_t now;
	isc_region_t r;
	dst_key_t *key;

	REQUIRE(keynodep != NULL);
	keynode = *keynodep;

	ENTER;
	isc_stdtime_get(&now);

	/* Loop in case there's more than one key. */
	while (result == ISC_R_SUCCESS) {
		dns_keynode_t *nextnode = NULL;

		key = dns_keynode_key(keynode);
		if (key == NULL)
			goto skip;

		isc_buffer_init(&dstb, dst_buf, sizeof(dst_buf));
		CHECK(dst_key_todns(key, &dstb));

		/* Convert DST key to DNSKEY. */
		dns_rdata_reset(&rdata);
		isc_buffer_usedregion(&dstb, &r);
		dns_rdata_fromregion(&rdata, dst_key_class(key),
				     dns_rdatatype_dnskey, &r);

		/* DSTKEY to KEYDATA. */
		CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL));
		CHECK(dns_keydata_fromdnskey(&keydata, &dnskey, now, 0, 0,
					     NULL));

		/* KEYDATA to rdata. */
		dns_rdata_reset(&rdata);
		isc_buffer_init(&keyb, key_buf, sizeof(key_buf));
		CHECK(dns_rdata_fromstruct(&rdata,
					   zone->rdclass, dns_rdatatype_keydata,
					   &keydata, &keyb));

		/* Add rdata to zone. */
		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD,
				    dst_key_name(key), 0, &rdata));
		*changed = true;

		/* Refresh new keys from the zone apex as soon as possible. */
		set_refreshkeytimer(zone, &keydata, now, true);

 skip:
		result = dns_keytable_nextkeynode(keytable, keynode, &nextnode);
		if (result != ISC_R_NOTFOUND) {
			dns_keytable_detachkeynode(keytable, &keynode);
			keynode = nextnode;
		}
	}

	if (keynode != NULL)
		dns_keytable_detachkeynode(keytable, &keynode);
	*keynodep = NULL;

	return (ISC_R_SUCCESS);

  failure:
	return (result);
}

Project: bind9
File: zone.c

exit_check(dns_zone_t *zone) {
	REQUIRE(LOCKED_ZONE(zone));

	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) && zone->irefs == 0) {
		/*
		 * DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0.
		 */
		INSIST(isc_refcount_current(&zone->erefs) == 0);
		return (true);
	}
	return (false);
}

Project: bind9
File: zone.c

dns_zone_getadded(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->added);
}

Project: bind9
File: zone.c

dns_zone_keydone(dns_zone_t *zone, const char *keystr) {
	isc_result_t result = ISC_R_SUCCESS;
	isc_event_t *e;
	isc_buffer_t b;
	dns_zone_t *dummy = NULL;
	struct keydone *kd;

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);

	e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_KEYDONE, keydone,
			       zone, sizeof(struct keydone));
	if (e == NULL) {
		result = ISC_R_NOMEMORY;
		goto failure;
	}

	kd = (struct keydone *) e;
	if (strcasecmp(keystr, "all") == 0) {
		kd->all = true;
	} else {
		isc_textregion_t r;
		const char *algstr;
		dns_keytag_t keyid;
		dns_secalg_t alg;
		size_t n;

		kd->all = false;

		n = sscanf(keystr, "%hu/", &keyid);
		if (n == 0U) {
			CHECK(ISC_R_FAILURE);
		}

		algstr = strchr(keystr, '/');
		if (algstr != NULL) {
			algstr++;
		} else {
			CHECK(ISC_R_FAILURE);
		}

		n = sscanf(algstr, "%hhu", &alg);
		if (n == 0U) {
			DE_CONST(algstr, r.base);
			r.length = strlen(algstr);
			CHECK(dns_secalg_fromtext(&alg, &r));
		}

		/* construct a private-type rdata */
		isc_buffer_init(&b, kd->data, sizeof(kd->data));
		isc_buffer_putuint8(&b, alg);
		isc_buffer_putuint8(&b, (keyid & 0xff00) >> 8);
		isc_buffer_putuint8(&b, (keyid & 0xff));
		isc_buffer_putuint8(&b, 0);
		isc_buffer_putuint8(&b, 1);
	}

	zone_iattach(zone, &dummy);
	isc_task_send(zone->task, &e);

 failure:
	if (e != NULL) {
		isc_event_free(&e);
	}
	UNLOCK_ZONE(zone);
	return (result);
}

Project: bind9
File: zone.c

zonemgr_getio(dns_zonemgr_t *zmgr, bool high,
	      isc_task_t *task, isc_taskaction_t action, void *arg,
	      dns_io_t **iop)
{
	dns_io_t *io;
	bool queue;

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));
	REQUIRE(iop != NULL && *iop == NULL);

	io = isc_mem_get(zmgr->mctx, sizeof(*io));
	if (io == NULL)
		return (ISC_R_NOMEMORY);

	io->event = isc_event_allocate(zmgr->mctx, task, DNS_EVENT_IOREADY,
				       action, arg, sizeof(*io->event));
	if (io->event == NULL) {
		isc_mem_put(zmgr->mctx, io, sizeof(*io));
		return (ISC_R_NOMEMORY);
	}

	io->zmgr = zmgr;
	io->high = high;
	io->task = NULL;
	isc_task_attach(task, &io->task);
	ISC_LINK_INIT(io, link);
	io->magic = IO_MAGIC;

	LOCK(&zmgr->iolock);
	zmgr->ioactive++;
	queue = (zmgr->ioactive > zmgr->iolimit);
	if (queue) {
		if (io->high)
			ISC_LIST_APPEND(zmgr->high, io, link);
		else
			ISC_LIST_APPEND(zmgr->low, io, link);
	}
	UNLOCK(&zmgr->iolock);
	*iop = io;

	if (!queue)
		isc_task_send(io->task, &io->event);
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

zonemgr_putio(dns_io_t **iop) {
	dns_io_t *io;
	dns_io_t *next;
	dns_zonemgr_t *zmgr;

	REQUIRE(iop != NULL);
	io = *iop;
	REQUIRE(DNS_IO_VALID(io));

	*iop = NULL;

	INSIST(!ISC_LINK_LINKED(io, link));
	INSIST(io->event == NULL);

	zmgr = io->zmgr;
	isc_task_detach(&io->task);
	io->magic = 0;
	isc_mem_put(zmgr->mctx, io, sizeof(*io));

	LOCK(&zmgr->iolock);
	INSIST(zmgr->ioactive > 0);
	zmgr->ioactive--;
	next = HEAD(zmgr->high);
	if (next == NULL)
		next = HEAD(zmgr->low);
	if (next != NULL) {
		if (next->high)
			ISC_LIST_UNLINK(zmgr->high, next, link);
		else
			ISC_LIST_UNLINK(zmgr->low, next, link);
		INSIST(next->event != NULL);
	}
	UNLOCK(&zmgr->iolock);
	if (next != NULL)
		isc_task_send(next->task, &next->event);
}

Project: bind9
File: zone.c

dns_zone_setforwardacl(dns_zone_t *zone, dns_acl_t *acl) {

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	if (zone->forward_acl != NULL)
		dns_acl_detach(&zone->forward_acl);
	dns_acl_attach(acl, &zone->forward_acl);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

zone_freedbargs(dns_zone_t *zone) {
	unsigned int i;

	/* Free the old database argument list. */
	if (zone->db_argv != NULL) {
		for (i = 0; i < zone->db_argc; i++)
			isc_mem_free(zone->mctx, zone->db_argv[i]);
		isc_mem_put(zone->mctx, zone->db_argv,
			    zone->db_argc * sizeof(*zone->db_argv));
	}
	zone->db_argc = 0;
	zone->db_argv = NULL;
}

Project: bind9
File: zone.c

dns_zone_load(dns_zone_t *zone, bool newonly) {
	return (zone_load(zone, newonly ? DNS_ZONELOADFLAG_NOSTAT : 0, false));
}

Project: bind9
File: zone.c

dns_zone_setjournalsize(dns_zone_t *zone, int32_t size) {
	REQUIRE(DNS_ZONE_VALID(zone));

	zone->journalsize = size;
}

Project: bind9
File: zone.c

add_chains(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
	   dns_diff_t *diff)
{
	dns_name_t *origin;
	bool build_nsec3;
	isc_result_t result;

	origin = dns_db_origin(db);
	CHECK(dns_private_chains(db, ver, zone->privatetype, NULL,
				 &build_nsec3));
	if (build_nsec3)
		CHECK(dns_nsec3_addnsec3sx(db, ver, origin, zone->minimum,
					   false, zone->privatetype, diff));
	CHECK(updatesecure(db, ver, origin, zone->minimum, true, diff));

 failure:
	return (result);
}

Project: bind9
File: zone.c

zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
	dns_dbversion_t *ver;
	isc_result_t result;
	unsigned int soacount = 0;
	unsigned int nscount = 0;

	/*
	 * 'zone' and 'zone->db' locked by caller.
	 */
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(LOCKED_ZONE(zone));
	if (inline_raw(zone))
		REQUIRE(LOCKED_ZONE(zone->secure));

	result = zone_get_from_db(zone, db, &nscount, &soacount,
				  NULL, NULL, NULL, NULL, NULL, NULL);
	if (result == ISC_R_SUCCESS) {
		if (soacount != 1) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "has %d SOA records", soacount);
			result = DNS_R_BADZONE;
		}
		if (nscount == 0 && zone->type != dns_zone_key) {
			dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records");
			result = DNS_R_BADZONE;
		}
		if (result != ISC_R_SUCCESS)
			return (result);
	} else {
		dns_zone_log(zone, ISC_LOG_ERROR,
			    "retrieving SOA and NS records failed: %s",
			    dns_result_totext(result));
		return (result);
	}

	result = check_nsec3param(zone, db);
	if (result != ISC_R_SUCCESS)
		return (result);

	ver = NULL;
	dns_db_currentversion(db, &ver);

	/*
	 * The initial version of a slave zone is always dumped;
	 * subsequent versions may be journaled instead if this
	 * is enabled in the configuration.
	 */
	if (zone->db != NULL && zone->journal != NULL &&
	    DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) &&
	    !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER))
	{
		uint32_t serial, oldserial;

		dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs");

		result = dns_db_getsoaserial(db, ver, &serial);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "ixfr-from-differences: unable to get "
				     "new serial");
			goto fail;
		}

		/*
		 * This is checked in zone_postload() for master zones.
		 */
		result = zone_get_from_db(zone, zone->db, NULL, &soacount,
					  &oldserial, NULL, NULL, NULL, NULL,
					  NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		RUNTIME_CHECK(soacount > 0U);
		if ((zone->type == dns_zone_slave ||
		     (zone->type == dns_zone_redirect &&
		      zone->masters != NULL))
		    && !isc_serial_gt(serial, oldserial)) {
			uint32_t serialmin, serialmax;
			serialmin = (oldserial + 1) & 0xffffffffU;
			serialmax = (oldserial + 0x7fffffffU) & 0xffffffffU;
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "ixfr-from-differences: failed: "
				     "new serial (%u) out of range [%u - %u]",
				     serial, serialmin, serialmax);
			result = ISC_R_RANGE;
			goto fail;
		}

		result = dns_db_diff(zone->mctx, db, ver, zone->db, NULL,
				     zone->journal);
		if (result != ISC_R_SUCCESS) {
			char strbuf[ISC_STRERRORSIZE];
			strerror_r(errno, strbuf, sizeof(strbuf));
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "ixfr-from-differences: failed: "
				     "%s", strbuf);
			goto fallback;
		}
		if (dump)
			zone_needdump(zone, DNS_DUMP_DELAY);
		else
			zone_journal_compact(zone, zone->db, serial);
		if (zone->type == dns_zone_master && inline_raw(zone))
			zone_send_secureserial(zone, serial);
	} else {
 fallback:
		if (dump && zone->masterfile != NULL) {
			/*
			 * If DNS_ZONEFLG_FORCEXFER was set we don't want
			 * to keep the old masterfile.
			 */
			if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) &&
			    remove(zone->masterfile) < 0 && errno != ENOENT) {
				char strbuf[ISC_STRERRORSIZE];
				strerror_r(errno, strbuf, sizeof(strbuf));
				isc_log_write(dns_lctx,
					      DNS_LOGCATEGORY_GENERAL,
					      DNS_LOGMODULE_ZONE,
					      ISC_LOG_WARNING,
					      "unable to remove masterfile "
					      "'%s': '%s'",
					      zone->masterfile, strbuf);
			}
			if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) == 0)
				DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NODELAY);
			else
				zone_needdump(zone, 0);
		}
		if (dump && zone->journal != NULL) {
			/*
			 * The in-memory database just changed, and
			 * because 'dump' is set, it didn't change by
			 * being loaded from disk.  Also, we have not
			 * journaled diffs for this change.
			 * Therefore, the on-disk journal is missing
			 * the deltas for this change.	Since it can
			 * no longer be used to bring the zone
			 * up-to-date, it is useless and should be
			 * removed.
			 */
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
				      DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
				      "removing journal file");
			if (remove(zone->journal) < 0 && errno != ENOENT) {
				char strbuf[ISC_STRERRORSIZE];
				strerror_r(errno, strbuf, sizeof(strbuf));
				isc_log_write(dns_lctx,
					      DNS_LOGCATEGORY_GENERAL,
					      DNS_LOGMODULE_ZONE,
					      ISC_LOG_WARNING,
					      "unable to remove journal "
					      "'%s': '%s'",
					      zone->journal, strbuf);
			}
		}

		if (inline_raw(zone))
			zone_send_securedb(zone, db);
	}

	dns_db_closeversion(db, &ver, false);

	dns_zone_log(zone, ISC_LOG_DEBUG(3), "replacing zone database");

	if (zone->db != NULL)
		zone_detachdb(zone);
	zone_attachdb(zone, db);
	dns_db_settask(zone->db, zone->task);
	DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
	return (ISC_R_SUCCESS);

 fail:
	dns_db_closeversion(db, &ver, false);
	return (result);
}

Project: bind9
File: zone.c

dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) {

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, value);
}

Project: bind9
File: zone.c

dns_zone_getnotifysrc6dscp(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->notifysrc6dscp);
}

Project: bind9
File: zone.c

refresh_time(dns_keyfetch_t *kfetch, bool retry) {
	isc_result_t result;
	uint32_t t;
	dns_rdataset_t *rdset;
	dns_rdata_t sigrr = DNS_RDATA_INIT;
	dns_rdata_sig_t sig;
	isc_stdtime_t now;

	isc_stdtime_get(&now);

	if (dns_rdataset_isassociated(&kfetch->dnskeysigset))
		rdset = &kfetch->dnskeysigset;
	else
		return (now + dns_zone_mkey_hour);

	result = dns_rdataset_first(rdset);
	if (result != ISC_R_SUCCESS)
		return (now + dns_zone_mkey_hour);

	dns_rdataset_current(rdset, &sigrr);
	result = dns_rdata_tostruct(&sigrr, &sig, NULL);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);

	if (!retry) {
		t = sig.originalttl / 2;

		if (isc_serial_gt(sig.timeexpire, now)) {
			uint32_t exp = (sig.timeexpire - now) / 2;
			if (t > exp)
				t = exp;
		}

		if (t > (15 * dns_zone_mkey_day))
			t = (15 * dns_zone_mkey_day);

		if (t < dns_zone_mkey_hour)
			t = dns_zone_mkey_hour;
	} else {
		t = sig.originalttl / 10;

		if (isc_serial_gt(sig.timeexpire, now)) {
			uint32_t exp = (sig.timeexpire - now) / 10;
			if (t > exp)
				t = exp;
		}

		if (t > dns_zone_mkey_day)
			t = dns_zone_mkey_day;

		if (t < dns_zone_mkey_hour)
			t = dns_zone_mkey_hour;
	}

	return (now + t);
}

Project: bind9
File: zone.c

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

	LOCK_ZONE(zone);
	zone_unload(zone);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) {
	REQUIRE(DNS_ZONE_VALID(zone));

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

Project: bind9
File: zone.c

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

	return (zone->maxxfrout);
}

Project: bind9
File: zone.c

dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
	isc_result_t result;
	int ntasks = num_zones / ZONES_PER_TASK;
	int nmctx = num_zones / ZONES_PER_MCTX;
	isc_taskpool_t *pool = NULL;
	isc_pool_t *mctxpool = NULL;

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	/*
	 * For anything fewer than 1000 zones we use 10 tasks in
	 * the task pools.  More than that, and we'll scale at one
	 * task per 100 zones.  Similarly, for anything smaller than
	 * 2000 zones we use 2 memory contexts, then scale at 1:1000.
	 */
	if (ntasks < 10)
		ntasks = 10;
	if (nmctx < 2)
		nmctx = 2;

	/* Create or resize the zone task pools. */
	if (zmgr->zonetasks == NULL)
		result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx,
					     ntasks, 2, &pool);
	else
		result = isc_taskpool_expand(&zmgr->zonetasks, ntasks, &pool);

	if (result == ISC_R_SUCCESS)
		zmgr->zonetasks = pool;

	pool = NULL;
	if (zmgr->loadtasks == NULL)
		result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx,
					     ntasks, 2, &pool);
	else
		result = isc_taskpool_expand(&zmgr->loadtasks, ntasks, &pool);

	if (result == ISC_R_SUCCESS)
		zmgr->loadtasks = pool;

	/*
	 * We always set all tasks in the zone-load task pool to
	 * privileged.  This prevents other tasks in the system from
	 * running while the server task manager is in privileged
	 * mode.
	 *
	 * NOTE: If we start using task privileges for any other
	 * part of the system than zone tasks, then this will need to be
	 * revisted.  In that case we'd want to turn on privileges for
	 * zone tasks only when we were loading, and turn them off the
	 * rest of the time.  For now, however, it's okay to just
	 * set it and forget it.
	 */
	isc_taskpool_setprivilege(zmgr->loadtasks, true);

	/* Create or resize the zone memory context pool. */
	if (zmgr->mctxpool == NULL)
		result = isc_pool_create(zmgr->mctx, nmctx, mctxfree,
					 mctxinit, NULL, &mctxpool);
	else
		result = isc_pool_expand(&zmgr->mctxpool, nmctx, &mctxpool);

	if (result == ISC_R_SUCCESS)
		zmgr->mctxpool = mctxpool;

	return (result);
}

Project: bind9
File: zone.c

dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) {
	char namebuf[1024];

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(rdclass != dns_rdataclass_none);

	/*
	 * Test and set.
	 */
	LOCK_ZONE(zone);
	INSIST(zone != zone->raw);
	REQUIRE(zone->rdclass == dns_rdataclass_none ||
		zone->rdclass == rdclass);
	zone->rdclass = rdclass;

	if (zone->strnamerd != NULL)
		isc_mem_free(zone->mctx, zone->strnamerd);
	if (zone->strrdclass != NULL)
		isc_mem_free(zone->mctx, zone->strrdclass);

	zone_namerd_tostr(zone, namebuf, sizeof namebuf);
	zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
	zone_rdclass_tostr(zone, namebuf, sizeof namebuf);
	zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf);

	if (inline_secure(zone))
		dns_zone_setclass(zone->raw, rdclass);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_notify(dns_zone_t *zone) {
	isc_time_t now;

	REQUIRE(DNS_ZONE_VALID(zone));

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

	TIME_NOW(&now);
	zone_settimer(zone, &now);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_settask(dns_zone_t *zone, isc_task_t *task) {
	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	if (zone->task != NULL)
		isc_task_detach(&zone->task);
	isc_task_attach(task, &zone->task);
	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	if (zone->db != NULL)
		dns_db_settask(zone->db, zone->task);
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zonemgr_detach(dns_zonemgr_t **zmgrp) {
	dns_zonemgr_t *zmgr;
	bool free_now = false;

	REQUIRE(zmgrp != NULL);
	zmgr = *zmgrp;
	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	zmgr->refs--;
	if (zmgr->refs == 0)
		free_now = true;
	RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);

	if (free_now)
		zonemgr_free(zmgr);
	*zmgrp = NULL;
}

Project: bind9
File: zone.c

mctxinit(void **target, void *arg) {
	isc_result_t result;
	isc_mem_t *mctx = NULL;

	UNUSED(arg);

	REQUIRE(target != NULL && *target == NULL);

	result = isc_mem_create(0, 0, &mctx);
	if (result != ISC_R_SUCCESS)
		return (result);
	isc_mem_setname(mctx, "zonemgr-pool", NULL);

	*target = mctx;
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
		dns_rdatatype_t type, dst_key_t *key)
{
	isc_result_t result;
	dns_rdataset_t rdataset;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdata_rrsig_t rrsig;

	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig,
				     type, 0, &rdataset, NULL);
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		return (false);
	}
	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset)) {
		dns_rdataset_current(&rdataset, &rdata);
		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
		INSIST(result == ISC_R_SUCCESS);
		if (rrsig.algorithm == dst_key_alg(key) &&
		    rrsig.keyid == dst_key_id(key)) {
			dns_rdataset_disassociate(&rdataset);
			return (true);
		}
		dns_rdata_reset(&rdata);
	}
	dns_rdataset_disassociate(&rdataset);
	return (false);
}

Project: bind9
File: zone.c

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

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

	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) {
	if ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0)
		return;

	zone->sourceserial = header->sourceserial;
	zone->sourceserialset = true;
}

Project: bind9
File: zone.c

zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel,
	      const char *fmt, ...)
{
	int level = ISC_LOG_DEBUG(debuglevel);
	va_list ap;

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

Project: bind9
File: zone.c

zone_unchanged(dns_db_t *db1, dns_db_t *db2, isc_mem_t *mctx) {
	isc_result_t result;
	bool answer = false;
	dns_diff_t diff;

	dns_diff_init(mctx, &diff);
	result = dns_db_diffx(&diff, db1, NULL, db2, NULL, NULL);
	if (result == ISC_R_SUCCESS && ISC_LIST_EMPTY(diff.tuples))
		answer = true;
	dns_diff_clear(&diff);
	return (answer);
}

Project: bind9
File: zone.c

zone_rekey(dns_zone_t *zone) {
	isc_result_t result;
	dns_db_t *db = NULL;
	dns_dbnode_t *node = NULL;
	dns_dbversion_t *ver = NULL;
	dns_rdataset_t cdsset, soaset, soasigs, keyset, keysigs, cdnskeyset;
	dns_dnsseckeylist_t dnskeys, keys, rmkeys;
	dns_dnsseckey_t *key = NULL;
	dns_diff_t diff, _sig_diff;
	dns__zonediff_t zonediff;
	bool commit = false, newactive = false;
	bool newalg = false;
	bool fullsign;
	dns_ttl_t ttl = 3600;
	const char *dir = NULL;
	isc_mem_t *mctx = NULL;
	isc_stdtime_t now;
	isc_time_t timenow;
	isc_interval_t ival;
	char timebuf[80];

	REQUIRE(DNS_ZONE_VALID(zone));

	ISC_LIST_INIT(dnskeys);
	ISC_LIST_INIT(keys);
	ISC_LIST_INIT(rmkeys);
	dns_rdataset_init(&soaset);
	dns_rdataset_init(&soasigs);
	dns_rdataset_init(&keyset);
	dns_rdataset_init(&keysigs);
	dns_rdataset_init(&cdsset);
	dns_rdataset_init(&cdnskeyset);
	dir = dns_zone_getkeydirectory(zone);
	mctx = zone->mctx;
	dns_diff_init(mctx, &diff);
	dns_diff_init(mctx, &_sig_diff);
	zonediff_init(&zonediff, &_sig_diff);

	CHECK(dns_zone_getdb(zone, &db));
	CHECK(dns_db_newversion(db, &ver));
	CHECK(dns_db_getoriginnode(db, &node));

	TIME_NOW(&timenow);
	now = isc_time_seconds(&timenow);

	dnssec_log(zone, ISC_LOG_INFO, "reconfiguring zone keys");

	/* Get the SOA record's TTL */
	CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_soa,
				  dns_rdatatype_none, 0, &soaset, &soasigs));
	ttl = soaset.ttl;
	dns_rdataset_disassociate(&soaset);

	/* Get the DNSKEY rdataset */
	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey,
				     dns_rdatatype_none, 0, &keyset, &keysigs);
	if (result == ISC_R_SUCCESS) {
		ttl = keyset.ttl;
		CHECK(dns_dnssec_keylistfromrdataset(&zone->origin, dir,
						     mctx, &keyset,
						     &keysigs, &soasigs,
						     false, false,
						     &dnskeys));
	} else if (result != ISC_R_NOTFOUND) {
		goto failure;
	}


	/* Get the CDS rdataset */
	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_cds,
				     dns_rdatatype_none, 0, &cdsset, NULL);
	if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdsset))
		dns_rdataset_disassociate(&cdsset);

	/* Get the CDNSKEY rdataset */
	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_cdnskey,
				     dns_rdatatype_none, 0, &cdnskeyset, NULL);
	if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdnskeyset))
	{
		dns_rdataset_disassociate(&cdnskeyset);
	}

	/*
	 * True when called from "rndc sign".  Indicates the zone should be
	 * fully signed now.
	 */
	fullsign = DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_FULLSIGN);

	result = dns_dnssec_findmatchingkeys(&zone->origin, dir, now, mctx,
					     &keys);
	if (result == ISC_R_SUCCESS) {
		bool check_ksk;
		check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);

		result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys,
					       &zone->origin, ttl, &diff,
					       !check_ksk, mctx,
					       dnssec_report);
		/*
		 * Keys couldn't be updated for some reason;
		 * try again later.
		 */
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "zone_rekey:couldn't update zone keys: %s",
				   isc_result_totext(result));
			goto failure;
		}

		/*
		 * Update CDS / CDNSKEY records.
		 */
		result = dns_dnssec_syncupdate(&dnskeys, &rmkeys, &cdsset,
					       &cdnskeyset, now, ttl,
					       &diff, mctx);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "zone_rekey:couldn't update CDS/CDNSKEY: %s",
				   isc_result_totext(result));
			goto failure;
		}

		/*
		 * See if any pre-existing keys have newly become active;
		 * also, see if any new key is for a new algorithm, as in that
		 * event, we need to sign the zone fully.  (If there's a new
		 * key, but it's for an already-existing algorithm, then
		 * the zone signing can be handled incrementally.)
		 */
		for (key = ISC_LIST_HEAD(dnskeys);
		     key != NULL;
		     key = ISC_LIST_NEXT(key, link))
		{
			if (!key->first_sign) {
				continue;
			}

			newactive = true;

			if (!dns_rdataset_isassociated(&keysigs)) {
				newalg = true;
				break;
			}

			if (signed_with_alg(&keysigs, dst_key_alg(key->key))) {
				/*
				 * This isn't a new algorithm; clear
				 * first_sign so we won't sign the
				 * whole zone with this key later
				 */
				key->first_sign = false;
			} else {
				newalg = true;
				break;
			}
		}

		if ((newactive || fullsign || !ISC_LIST_EMPTY(diff.tuples)) &&
		    dnskey_sane(zone, db, ver, &diff))
		{
			CHECK(dns_diff_apply(&diff, db, ver));
			CHECK(clean_nsec3param(zone, db, ver, &diff));
			CHECK(add_signing_records(db, zone->privatetype,
						  ver, &diff,
						  (newalg || fullsign)));
			CHECK(update_soa_serial(db, ver, &diff, mctx,
						zone->updatemethod));
			CHECK(add_chains(zone, db, ver, &diff));
			CHECK(sign_apex(zone, db, ver, now, &diff, &zonediff));
			CHECK(zone_journal(zone, zonediff.diff, NULL,
					   "zone_rekey"));
			commit = true;
		}
	}

	dns_db_closeversion(db, &ver, true);

	if (commit) {
		dns_difftuple_t *tuple;

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

		zone_needdump(zone, DNS_DUMP_DELAY);

		zone_settimer(zone, &timenow);

		/* Remove any signatures from removed keys.  */
		if (!ISC_LIST_EMPTY(rmkeys)) {
			for (key = ISC_LIST_HEAD(rmkeys);
			     key != NULL;
			     key = ISC_LIST_NEXT(key, link))
			{
				result = zone_signwithkey(zone,
							  dst_key_alg(key->key),
							  dst_key_id(key->key),
							  true);
				if (result != ISC_R_SUCCESS) {
					dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_signwithkey failed: %s",
					   dns_result_totext(result));
				}
			}
		}

		if (fullsign) {
			/*
			 * "rndc sign" was called, so we now sign the zone
			 * with all active keys, whether they're new or not.
			 */
			for (key = ISC_LIST_HEAD(dnskeys);
			     key != NULL;
			     key = ISC_LIST_NEXT(key, link))
			{
				if (!key->force_sign && !key->hint_sign) {
					continue;
				}

				result = zone_signwithkey(zone,
							  dst_key_alg(key->key),
							  dst_key_id(key->key),
							  false);
				if (result != ISC_R_SUCCESS) {
					dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_signwithkey failed: %s",
					   dns_result_totext(result));
				}
			}
		} else if (newalg) {
			/*
			 * We haven't been told to sign fully, but a new
			 * algorithm was added to the DNSKEY.  We sign
			 * the full zone, but only with newly active
			 * keys.
			 */
			for (key = ISC_LIST_HEAD(dnskeys);
			     key != NULL;
			     key = ISC_LIST_NEXT(key, link))
			{
				if (!key->first_sign) {
					continue;
				}

				result = zone_signwithkey(zone,
							  dst_key_alg(key->key),
							  dst_key_id(key->key),
							  false);
				if (result != ISC_R_SUCCESS) {
					dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_signwithkey failed: %s",
					   dns_result_totext(result));
				}
			}
		}

		/*
		 * Clear fullsign flag, if it was set, so we don't do
		 * another full signing next time
		 */
		zone->keyopts &= ~DNS_ZONEKEY_FULLSIGN;

		/*
		 * Cause the zone to add/delete NSEC3 chains for the
		 * deferred NSEC3PARAM changes.
		 */
		for (tuple = ISC_LIST_HEAD(zonediff.diff->tuples);
		     tuple != NULL;
		     tuple = ISC_LIST_NEXT(tuple, link))
		{
			unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
			dns_rdata_t rdata = DNS_RDATA_INIT;
			dns_rdata_nsec3param_t nsec3param;

			if (tuple->rdata.type != zone->privatetype ||
			    tuple->op != DNS_DIFFOP_ADD)
			{
				continue;
			}

			if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
							buf, sizeof(buf)))
			{
				continue;
			}

			result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			if (nsec3param.flags == 0) {
				continue;
			}

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

		/*
		 * Activate any NSEC3 chain updates that may have
		 * been scheduled before this rekey.
		 */
		if (fullsign || newalg) {
			resume_addnsec3chain(zone);
		}

		/*
		 * Schedule the next resigning event
		 */
		set_resigntime(zone);
		UNLOCK_ZONE(zone);
	}

	isc_time_settoepoch(&zone->refreshkeytime);

	/*
	 * If we're doing key maintenance, set the key refresh timer to
	 * the next scheduled key event or to 'dnssec-loadkeys-interval'
	 * seconds in the future, whichever is sooner.
	 */
	if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) {
		isc_time_t timethen;
		isc_stdtime_t then;

		LOCK_ZONE(zone);
		DNS_ZONE_TIME_ADD(&timenow, zone->refreshkeyinterval,
				  &timethen);
		zone->refreshkeytime = timethen;
		UNLOCK_ZONE(zone);

		for (key = ISC_LIST_HEAD(dnskeys);
		     key != NULL;
		     key = ISC_LIST_NEXT(key, link))
		{
			then = now;
			result = next_keyevent(key->key, &then);
			if (result != ISC_R_SUCCESS) {
				continue;
			}

			DNS_ZONE_TIME_ADD(&timenow, then - now, &timethen);
			LOCK_ZONE(zone);
			if (isc_time_compare(&timethen,
					     &zone->refreshkeytime) < 0)
			{
				zone->refreshkeytime = timethen;
			}
			UNLOCK_ZONE(zone);
		}

		zone_settimer(zone, &timenow);

		isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
		dnssec_log(zone, ISC_LOG_INFO, "next key event: %s", timebuf);
	}

	result = ISC_R_SUCCESS;

 failure:
	if (result != ISC_R_SUCCESS) {
		/*
		 * Something went wrong; try again in ten minutes or
		 * after a key refresh interval, whichever is shorter.
		 */
		isc_interval_set(&ival,
				 ISC_MIN(zone->refreshkeyinterval, 600), 0);
		isc_time_nowplusinterval(&zone->refreshkeytime, &ival);
	}

	dns_diff_clear(&diff);
	dns_diff_clear(&_sig_diff);

	clear_keylist(&dnskeys, mctx);
	clear_keylist(&keys, mctx);
	clear_keylist(&rmkeys, mctx);

	if (ver != NULL) {
		dns_db_closeversion(db, &ver, false);
	}
	if (dns_rdataset_isassociated(&cdsset)) {
		dns_rdataset_disassociate(&cdsset);
	}
	if (dns_rdataset_isassociated(&keyset)) {
		dns_rdataset_disassociate(&keyset);
	}
	if (dns_rdataset_isassociated(&keysigs)) {
		dns_rdataset_disassociate(&keysigs);
	}
	if (dns_rdataset_isassociated(&soasigs)) {
		dns_rdataset_disassociate(&soasigs);
	}
	if (dns_rdataset_isassociated(&cdnskeyset)) {
		dns_rdataset_disassociate(&cdnskeyset);
	}
	if (node != NULL) {
		dns_db_detachnode(db, &node);
	}
	if (db != NULL) {
		dns_db_detach(&db);
	}

	INSIST(ver == NULL);
}

Project: bind9
File: zone.c

restore_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
		   nsec3paramlist_t *nsec3list)
{
	isc_result_t result;
	dns_diff_t diff;
	dns_rdata_t rdata;
	nsec3param_t *nsec3p = NULL;
	nsec3param_t *next;

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

	dns_diff_init(zone->mctx, &diff);

	/*
	 * Loop through the list of private-type records, set the INITIAL
	 * and CREATE flags, and the add the record to the apex of the tree
	 * in db.
	 */
	for (nsec3p = ISC_LIST_HEAD(*nsec3list);
	     nsec3p != NULL;
	     nsec3p = next)
	{
		next = ISC_LIST_NEXT(nsec3p, link);
		dns_rdata_init(&rdata);
		nsec3p->data[2] = DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_INITIAL;
		rdata.length = nsec3p->length;
		rdata.data = nsec3p->data;
		rdata.type = zone->privatetype;
		rdata.rdclass = zone->rdclass;
		result = update_one_rr(db, version, &diff, DNS_DIFFOP_ADD,
				       &zone->origin, 0, &rdata);
		if (result != ISC_R_SUCCESS) {
			break;
		}
	}

	dns_diff_clear(&diff);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_getaltxfrsource4(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (&zone->altxfrsource4);
}

Project: bind9
File: zone.c

dns_zone_getautomatic(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->automatic);
}

Project: bind9
File: zone.c

deletematchingnsec3(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
		    dns_name_t *name, const dns_rdata_nsec3param_t *param,
		    dns_diff_t *diff)
{
	dns_rdataset_t rdataset;
	dns_rdata_nsec3_t nsec3;
	isc_result_t result;

	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3,
				     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(dns_rdata_tostruct(&rdata, &nsec3, NULL));
		if (nsec3.hash != param->hash ||
		    nsec3.iterations != param->iterations ||
		    nsec3.salt_length != param->salt_length ||
		    memcmp(nsec3.salt, param->salt, nsec3.salt_length))
			continue;
		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_clearupdateacl(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

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

Project: bind9
File: zone.c

dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type) {
	REQUIRE(DNS_ZONE_VALID(zone));
	zone->privatetype = type;
}

Project: bind9
File: zone.c

dns_zone_setjournal(dns_zone_t *zone, const char *myjournal) {
	isc_result_t result = ISC_R_SUCCESS;

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	result = dns_zone_setstring(zone, &zone->journal, myjournal);
	UNLOCK_ZONE(zone);

	return (result);
}

Project: bind9
File: zone.c

dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory) {
	isc_result_t result = ISC_R_SUCCESS;

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	result = dns_zone_setstring(zone, &zone->keydirectory, directory);
	UNLOCK_ZONE(zone);

	return (result);
}

Project: bind9
File: zone.c

dns_zone_setdbtype(dns_zone_t *zone,
		   unsigned int dbargc, const char * const *dbargv)
{
	isc_result_t result = ISC_R_SUCCESS;
	char **argv = NULL;
	unsigned int i;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(dbargc >= 1);
	REQUIRE(dbargv != NULL);

	LOCK_ZONE(zone);

	/* Set up a new database argument list. */
	argv = isc_mem_get(zone->mctx, dbargc * sizeof(*argv));
	if (argv == NULL) {
		goto nomem;
	}
	for (i = 0; i < dbargc; i++) {
		argv[i] = NULL;
	}
	for (i = 0; i < dbargc; i++) {
		argv[i] = isc_mem_strdup(zone->mctx, dbargv[i]);
		if (argv[i] == NULL)
			goto nomem;
	}

	/* Free the old list. */
	zone_freedbargs(zone);

	zone->db_argc = dbargc;
	zone->db_argv = argv;
	result = ISC_R_SUCCESS;
	goto unlock;

 nomem:
	if (argv != NULL) {
		for (i = 0; i < dbargc; i++) {
			if (argv[i] != NULL) {
				isc_mem_free(zone->mctx, argv[i]);
			}
		}
		isc_mem_put(zone->mctx, argv, dbargc * sizeof(*argv));
	}
	result = ISC_R_NOMEMORY;

 unlock:
	UNLOCK_ZONE(zone);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_getnotifyacl(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->notify_acl);
}

Project: bind9
File: zone.c

load_secroots(dns_zone_t *zone, dns_name_t *name, dns_rdataset_t *rdataset) {
	isc_result_t result;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdata_keydata_t keydata;
	dns_rdata_dnskey_t dnskey;
	isc_mem_t *mctx = zone->mctx;
	int trusted = 0, revoked = 0, pending = 0;
	isc_stdtime_t now;
	dns_keytable_t *sr = NULL;

	isc_stdtime_get(&now);

	result = dns_view_getsecroots(zone->view, &sr);
	if (result == ISC_R_SUCCESS) {
		dns_keytable_delete(sr, name);
		dns_keytable_detach(&sr);
	}

	/* Now insert all the accepted trust anchors from this keydata set. */
	for (result = dns_rdataset_first(rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(rdataset))
	{
		dns_rdata_reset(&rdata);
		dns_rdataset_current(rdataset, &rdata);

		/* Convert rdata to keydata. */
		result = dns_rdata_tostruct(&rdata, &keydata, NULL);
		if (result == ISC_R_UNEXPECTEDEND) {
			continue;
		}
		RUNTIME_CHECK(result == ISC_R_SUCCESS);

		/* Set the key refresh timer to force a fast refresh. */
		set_refreshkeytimer(zone, &keydata, now, true);

		/* If the removal timer is nonzero, this key was revoked. */
		if (keydata.removehd != 0) {
			revoked++;
			continue;
		}

		/*
		 * If the add timer is still pending, this key is not
		 * trusted yet.
		 */
		if (now < keydata.addhd) {
			pending++;
			continue;
		}

		/* Convert keydata to dnskey. */
		dns_keydata_todnskey(&keydata, &dnskey, NULL);

		/* Add to keytables. */
		trusted++;
		trust_key(zone, name, &dnskey, (keydata.addhd == 0), mctx);
	}

	if (trusted == 0 && pending != 0) {
		char namebuf[DNS_NAME_FORMATSIZE];
		dns_name_format(name, namebuf, sizeof namebuf);
		dnssec_log(zone, ISC_LOG_ERROR,
			   "No valid trust anchors for '%s'!", namebuf);
		dnssec_log(zone, ISC_LOG_ERROR,
			   "%d key(s) revoked, %d still pending",
			     revoked, pending);
		dnssec_log(zone, ISC_LOG_ERROR,
			   "All queries to '%s' will fail", namebuf);
		fail_secure(zone, name);
	}
}

Project: bind9
File: zone.c

dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first) {
	REQUIRE(DNS_ZONEMGR_VALID(zmgr));
	REQUIRE(first != NULL && *first == NULL);

	*first = ISC_LIST_HEAD(zmgr->zones);
	if (*first == NULL)
		return (ISC_R_NOMORE);
	else
		return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zone_getxfracl(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->xfr_acl);
}

Project: bind9
File: zone.c

compute_tag(dns_name_t *name, dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx,
	    dns_keytag_t *tag)
{
	isc_result_t result;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	unsigned char data[4096];
	isc_buffer_t buffer;
	dst_key_t *dstkey = NULL;

	isc_buffer_init(&buffer, data, sizeof(data));
	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
			     dns_rdatatype_dnskey, dnskey, &buffer);

	result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &dstkey);
	if (result == ISC_R_SUCCESS) {
		*tag = dst_key_id(dstkey);
		dst_key_free(&dstkey);
	}

	return (result);
}

Project: bind9
File: zone.c

updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing,
		  dns_dbversion_t *version, bool build_nsec3,
		  dns_ttl_t minimum, dns_diff_t *diff)
{
	isc_result_t result;
	dns_dbnode_t *node = NULL;
	dns_rdataset_t rdataset;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	unsigned char data[5];
	bool seen_done = false;
	bool have_rr = false;

	dns_rdataset_init(&rdataset);
	result = dns_db_getoriginnode(signing->db, &node);
	if (result != ISC_R_SUCCESS)
		goto failure;

	result = dns_db_findrdataset(signing->db, node, version,
				     zone->privatetype, dns_rdatatype_none,
				     0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		result = ISC_R_SUCCESS;
		goto failure;
	}
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto failure;
	}
	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset)) {
		dns_rdataset_current(&rdataset, &rdata);
		/*
		 * If we don't match the algorithm or keyid skip the record.
		 */
		if (rdata.length != 5 ||
		    rdata.data[0] != signing->algorithm ||
		    rdata.data[1] != ((signing->keyid >> 8) & 0xff) ||
		    rdata.data[2] != (signing->keyid & 0xff)) {
			have_rr = true;
			dns_rdata_reset(&rdata);
			continue;
		}
		/*
		 * We have a match.  If we were signing (!signing->deleteit)
		 * and we already have a record indicating that we have
		 * finished signing (rdata.data[4] != 0) then keep it.
		 * Otherwise it needs to be deleted as we have removed all
		 * the signatures (signing->deleteit), so any record indicating
		 * completion is now out of date, or we have finished signing
		 * with the new record so we no longer need to remember that
		 * we need to sign the zone with the matching key across a
		 * nameserver re-start.
		 */
		if (!signing->deleteit && rdata.data[4] != 0) {
			seen_done = true;
			have_rr = true;
		} else
			CHECK(update_one_rr(signing->db, version, diff,
					    DNS_DIFFOP_DEL, &zone->origin,
					    rdataset.ttl, &rdata));
		dns_rdata_reset(&rdata);
	}
	if (result == ISC_R_NOMORE)
		result = ISC_R_SUCCESS;
	if (!signing->deleteit && !seen_done) {
		/*
		 * If we were signing then we need to indicate that we have
		 * finished signing the zone with this key.  If it is already
		 * there we don't need to add it a second time.
		 */
		data[0] = signing->algorithm;
		data[1] = (signing->keyid >> 8) & 0xff;
		data[2] = signing->keyid & 0xff;
		data[3] = 0;
		data[4] = 1;
		rdata.length = sizeof(data);
		rdata.data = data;
		rdata.type = zone->privatetype;
		rdata.rdclass = dns_db_class(signing->db);
		CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD,
				    &zone->origin, rdataset.ttl, &rdata));
	} else if (!have_rr) {
		dns_name_t *origin = dns_db_origin(signing->db);
		/*
		 * Rebuild the NSEC/NSEC3 record for the origin as we no
		 * longer have any private records.
		 */
		if (build_nsec3)
			CHECK(dns_nsec3_addnsec3s(signing->db, version, origin,
						  minimum, false, diff));
		CHECK(updatesecure(signing->db, version, origin, minimum,
				   true, diff));
	}

 failure:
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	if (node != NULL)
		dns_db_detachnode(signing->db, &node);
	return (result);
}

Project: bind9
File: zone.c

zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount,
		 unsigned int *soacount, uint32_t *serial,
		 uint32_t *refresh, uint32_t *retry,
		 uint32_t *expire, uint32_t *minimum,
		 unsigned int *errors)
{
	isc_result_t result;
	isc_result_t answer = ISC_R_SUCCESS;
	dns_dbversion_t *version = NULL;
	dns_dbnode_t *node;

	REQUIRE(db != NULL);
	REQUIRE(zone != NULL);

	dns_db_currentversion(db, &version);

	if (nscount != NULL)
		*nscount = 0;
	if (soacount != NULL)
		*soacount = 0;
	if (serial != NULL)
		*serial = 0;
	if (refresh != NULL)
		*refresh = 0;
	if (retry != NULL)
		*retry = 0;
	if (expire != NULL)
		*expire = 0;
	if (errors != NULL)
		*errors = 0;

	node = NULL;
	result = dns_db_findnode(db, &zone->origin, false, &node);
	if (result != ISC_R_SUCCESS) {
		answer = result;
		goto closeversion;
	}

	if (nscount != NULL || errors != NULL) {
		result = zone_count_ns_rr(zone, db, node, version,
					  nscount, errors, true);
		if (result != ISC_R_SUCCESS)
			answer = result;
	}

	if (soacount != NULL || serial != NULL || refresh != NULL
	    || retry != NULL || expire != NULL || minimum != NULL) {
		result = zone_load_soa_rr(db, node, version, soacount,
					  serial, refresh, retry, expire,
					  minimum);
		if (result != ISC_R_SUCCESS)
			answer = result;
	}

	dns_db_detachnode(db, &node);
 closeversion:
	dns_db_closeversion(db, &version, false);

	return (answer);
}

Project: bind9
File: zone.c

del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
	dns_dbnode_t *node, unsigned int nkeys, dns_secalg_t algorithm,
	uint16_t keyid, bool *has_algp, dns_diff_t *diff)
{
	dns_rdata_rrsig_t rrsig;
	dns_rdataset_t rdataset;
	dns_rdatasetiter_t *iterator = NULL;
	isc_result_t result;
	bool alg_missed = false;
	bool alg_found = false;

	char namebuf[DNS_NAME_FORMATSIZE];
	dns_name_format(name, namebuf, sizeof(namebuf));

	result = dns_db_allrdatasets(db, node, version, 0, &iterator);
	if (result != ISC_R_SUCCESS) {
		if (result == ISC_R_NOTFOUND)
			result = ISC_R_SUCCESS;
		return (result);
	}

	dns_rdataset_init(&rdataset);
	for (result = dns_rdatasetiter_first(iterator);
	     result == ISC_R_SUCCESS;
	     result = dns_rdatasetiter_next(iterator)) {
		bool has_alg = false;
		dns_rdatasetiter_current(iterator, &rdataset);
		if (nkeys == 0 && rdataset.type == dns_rdatatype_nsec) {
			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, version, diff,
						    DNS_DIFFOP_DEL, name,
						    rdataset.ttl, &rdata));
			}
			if (result != ISC_R_NOMORE)
				goto failure;
			dns_rdataset_disassociate(&rdataset);
			continue;
		}
		if (rdataset.type != dns_rdatatype_rrsig) {
			dns_rdataset_disassociate(&rdataset);
			continue;
		}
		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(dns_rdata_tostruct(&rdata, &rrsig, NULL));
			if (nkeys != 0 &&
			    (rrsig.algorithm != algorithm ||
			     rrsig.keyid != keyid))
			{
				if (rrsig.algorithm == algorithm) {
					has_alg = true;
				}
				continue;
			}
			CHECK(update_one_rr(db, version, diff,
					    DNS_DIFFOP_DELRESIGN, name,
					    rdataset.ttl, &rdata));
		}
		dns_rdataset_disassociate(&rdataset);
		if (result != ISC_R_NOMORE)
			break;

		/*
		 * After deleting, if there's still a signature for
		 * 'algorithm', set alg_found; if not, set alg_missed.
		 */
		if (has_alg) {
			alg_found = true;
		} else {
			alg_missed = true;
		}
	}
	if (result == ISC_R_NOMORE)
		result = ISC_R_SUCCESS;

	/*
	 * Set `has_algp` if the algorithm was found in every RRset:
	 * i.e., found in at least one, and not missing from any.
	 */
	*has_algp = (alg_found && !alg_missed);
 failure:
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	dns_rdatasetiter_destroy(&iterator);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_setmaxrecords(dns_zone_t *zone, uint32_t val) {
	REQUIRE(DNS_ZONE_VALID(zone));

	zone->maxrecords = val;
}

Project: bind9
File: zone.c

dns_zone_getaltxfrsource6(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (&zone->altxfrsource6);
}

Project: bind9
File: zone.c

dns_zone_setstatistics(dns_zone_t *zone, bool on) {
	/*
	 * This function is obsoleted.
	 */
	UNUSED(zone);
	UNUSED(on);
	return (ISC_R_NOTIMPLEMENTED);
}

Project: bind9
File: zone.c

dns_zone_maintenance(dns_zone_t *zone) {
	const char me[] = "dns_zone_maintenance";
	isc_time_t now;

	REQUIRE(DNS_ZONE_VALID(zone));
	ENTER;

	LOCK_ZONE(zone);
	TIME_NOW(&now);
	zone_settimer(zone, &now);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

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

	return (zone->rdclass);
}

Project: bind9
File: zone.c

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

	return (zone->idleout);
}

Project: bind9
File: zone.c

forward_callback(isc_task_t *task, isc_event_t *event) {
	const char me[] = "forward_callback";
	dns_requestevent_t *revent = (dns_requestevent_t *)event;
	dns_message_t *msg = NULL;
	char master[ISC_SOCKADDR_FORMATSIZE];
	isc_result_t result;
	dns_forward_t *forward;
	dns_zone_t *zone;

	UNUSED(task);

	forward = revent->ev_arg;
	INSIST(DNS_FORWARD_VALID(forward));
	zone = forward->zone;
	INSIST(DNS_ZONE_VALID(zone));

	ENTER;

	isc_sockaddr_format(&forward->addr, master, sizeof(master));

	if (revent->result != ISC_R_SUCCESS) {
		dns_zone_log(zone, ISC_LOG_INFO,
			     "could not forward dynamic update to %s: %s",
			     master, dns_result_totext(revent->result));
		goto next_master;
	}

	result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg);
	if (result != ISC_R_SUCCESS)
		goto next_master;

	result = dns_request_getresponse(revent->request, msg,
					 DNS_MESSAGEPARSE_PRESERVEORDER |
					 DNS_MESSAGEPARSE_CLONEBUFFER);
	if (result != ISC_R_SUCCESS)
		goto next_master;

	switch (msg->rcode) {
	/*
	 * Pass these rcodes back to client.
	 */
	case dns_rcode_noerror:
	case dns_rcode_yxdomain:
	case dns_rcode_yxrrset:
	case dns_rcode_nxrrset:
	case dns_rcode_refused:
	case dns_rcode_nxdomain: {
		char rcode[128];
		isc_buffer_t rb;

		isc_buffer_init(&rb, rcode, sizeof(rcode));
		(void)dns_rcode_totext(msg->rcode, &rb);
		dns_zone_log(zone, ISC_LOG_INFO,
			     "forwarded dynamic update: "
			     "master %s returned: %.*s",
			     master, (int)rb.used, rcode);
		break;
	}

	/* These should not occur if the masters/zone are valid. */
	case dns_rcode_notzone:
	case dns_rcode_notauth: {
		char rcode[128];
		isc_buffer_t rb;

		isc_buffer_init(&rb, rcode, sizeof(rcode));
		(void)dns_rcode_totext(msg->rcode, &rb);
		dns_zone_log(zone, ISC_LOG_WARNING,
			     "forwarding dynamic update: "
			     "unexpected response: master %s returned: %.*s",
			     master, (int)rb.used, rcode);
		goto next_master;
	}

	/* Try another server for these rcodes. */
	case dns_rcode_formerr:
	case dns_rcode_servfail:
	case dns_rcode_notimp:
	case dns_rcode_badvers:
	default:
		goto next_master;
	}

	/* call callback */
	(forward->callback)(forward->callback_arg, ISC_R_SUCCESS, msg);
	msg = NULL;
	dns_request_destroy(&forward->request);
	forward_destroy(forward);
	isc_event_free(&event);
	return;

 next_master:
	if (msg != NULL)
		dns_message_destroy(&msg);
	isc_event_free(&event);
	forward->which++;
	dns_request_destroy(&forward->request);
	result = sendtomaster(forward);
	if (result != ISC_R_SUCCESS) {
		/* call callback */
		dns_zone_log(zone, ISC_LOG_DEBUG(3),
			     "exhausted dynamic update forwarder list");
		(forward->callback)(forward->callback_arg, result, NULL);
		forward_destroy(forward);
	}
}

Project: bind9
File: zone.c

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

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

	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zone_setxfracl(dns_zone_t *zone, dns_acl_t *acl) {

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	if (zone->xfr_acl != NULL)
		dns_acl_detach(&zone->xfr_acl);
	dns_acl_attach(acl, &zone->xfr_acl);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_getxfrsource6(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (&zone->xfrsource6);
}

Project: bind9
File: zone.c

dns_zone_setminretrytime(dns_zone_t *zone, uint32_t val) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(val > 0);

	zone->minretry = val;
}

Project: bind9
File: zone.c

inline_raw(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	if (zone->secure != NULL)
		return (true);
	return (false);
}

Project: bind9
File: zone.c

dns_zone_flush(dns_zone_t *zone) {
	isc_result_t result = ISC_R_SUCCESS;
	bool dumping;

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FLUSH);
	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
	    zone->masterfile != NULL) {
		result = ISC_R_ALREADYRUNNING;
		dumping = was_dumping(zone);
	} else
		dumping = true;
	UNLOCK_ZONE(zone);
	if (!dumping)
		result = zone_dump(zone, true);	/* Unknown task. */
	return (result);
}

Project: bind9
File: zone.c

dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns) {
	REQUIRE(DNS_ZONE_VALID(zone));
	zone->checkns = checkns;
}

Project: bind9
File: zone.c

dns_zone_setxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp) {
	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	zone->xfrsource4dscp = dscp;
	UNLOCK_ZONE(zone);

	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

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

	return (zmgr->transfersin);
}

Project: bind9
File: zone.c

dns_zone_setidleout(dns_zone_t *zone, uint32_t idleout) {
	REQUIRE(DNS_ZONE_VALID(zone));

	zone->idleout = idleout;
}

Project: bind9
File: zone.c

dns__zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
		   isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys,
		   dst_key_t **keys, unsigned int *nkeys)
{
	isc_result_t result;
	dns_dbnode_t *node = NULL;
	const char *directory = dns_zone_getkeydirectory(zone);

	CHECK(dns_db_findnode(db, dns_db_origin(db), false, &node));
	memset(keys, 0, sizeof(*keys) * maxkeys);
	result = dns_dnssec_findzonekeys(db, ver, node, dns_db_origin(db),
					 directory, now, mctx, maxkeys, keys,
					 nkeys);
	if (result == ISC_R_NOTFOUND)
		result = ISC_R_SUCCESS;
 failure:
	if (node != NULL)
		dns_db_detachnode(db, &node);
	return (result);
}

Project: bind9
File: zone.c

zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) {
	isc_result_t result = ISC_R_FAILURE;
	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->type != dns_zone_redirect && zone->type != dns_zone_key) {
		if (dns_name_dynamic(&zone->origin))
			result = dns_name_totext(&zone->origin, true, &buffer);
		if (result != ISC_R_SUCCESS &&
		    isc_buffer_availablelength(&buffer) >= (sizeof("<UNKNOWN>") - 1))
			isc_buffer_putstr(&buffer, "<UNKNOWN>");

		if (isc_buffer_availablelength(&buffer) > 0)
			isc_buffer_putstr(&buffer, "/");
		(void)dns_rdataclass_totext(zone->rdclass, &buffer);
	}

	if (zone->view != NULL && strcmp(zone->view->name, "_bind") != 0 &&
	    strcmp(zone->view->name, "_default") != 0 &&
	    strlen(zone->view->name) < isc_buffer_availablelength(&buffer)) {
		isc_buffer_putstr(&buffer, "/");
		isc_buffer_putstr(&buffer, zone->view->name);
	}
	if (inline_secure(zone) && 9U < isc_buffer_availablelength(&buffer))
		isc_buffer_putstr(&buffer, " (signed)");
	if (inline_raw(zone) && 11U < isc_buffer_availablelength(&buffer))
		isc_buffer_putstr(&buffer, " (unsigned)");

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

Project: bind9
File: zone.c

zone_attachdb(dns_zone_t *zone, dns_db_t *db) {
	REQUIRE(zone->db == NULL && db != NULL);

	dns_db_attach(db, &zone->db);
}

Project: bind9
File: zone.c

mctxfree(void **target) {
	isc_mem_t *mctx = *(isc_mem_t **) target;
	isc_mem_detach(&mctx);
	*target = NULL;
}

Project: bind9
File: zone.c

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

	return (zmgr->serialqueryrate);
}

Project: bind9
File: zone.c

integrity_checks(dns_zone_t *zone, dns_db_t *db) {
	dns_dbiterator_t *dbiterator = NULL;
	dns_dbnode_t *node = NULL;
	dns_rdataset_t rdataset;
	dns_fixedname_t fixed;
	dns_fixedname_t fixedbottom;
	dns_rdata_mx_t mx;
	dns_rdata_ns_t ns;
	dns_rdata_in_srv_t srv;
	dns_rdata_t rdata;
	dns_name_t *name;
	dns_name_t *bottom;
	isc_result_t result;
	bool ok = true, have_spf, have_txt;

	name = dns_fixedname_initname(&fixed);
	bottom = dns_fixedname_initname(&fixedbottom);
	dns_rdataset_init(&rdataset);
	dns_rdata_init(&rdata);

	result = dns_db_createiterator(db, 0, &dbiterator);
	if (result != ISC_R_SUCCESS)
		return (true);

	result = dns_dbiterator_first(dbiterator);
	while (result == ISC_R_SUCCESS) {
		result = dns_dbiterator_current(dbiterator, &node, name);
		if (result != ISC_R_SUCCESS)
			goto cleanup;

		/*
		 * Is this name visible in the zone?
		 */
		if (!dns_name_issubdomain(name, &zone->origin) ||
		    (dns_name_countlabels(bottom) > 0 &&
		     dns_name_issubdomain(name, bottom)))
			goto next;

		/*
		 * Don't check the NS records at the origin.
		 */
		if (dns_name_equal(name, &zone->origin))
			goto checkfordname;

		result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ns,
					     0, 0, &rdataset, NULL);
		if (result != ISC_R_SUCCESS)
			goto checkfordname;
		/*
		 * Remember bottom of zone due to NS.
		 */
		dns_name_copy(name, bottom, NULL);

		result = dns_rdataset_first(&rdataset);
		while (result == ISC_R_SUCCESS) {
			dns_rdataset_current(&rdataset, &rdata);
			result = dns_rdata_tostruct(&rdata, &ns, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			if (!zone_check_glue(zone, db, &ns.name, name))
				ok = false;
			dns_rdata_reset(&rdata);
			result = dns_rdataset_next(&rdataset);
		}
		dns_rdataset_disassociate(&rdataset);
		goto next;

 checkfordname:
		result = dns_db_findrdataset(db, node, NULL,
					     dns_rdatatype_dname, 0, 0,
					     &rdataset, NULL);
		if (result == ISC_R_SUCCESS) {
			/*
			 * Remember bottom of zone due to DNAME.
			 */
			dns_name_copy(name, bottom, NULL);
			dns_rdataset_disassociate(&rdataset);
		}

		result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx,
					     0, 0, &rdataset, NULL);
		if (result != ISC_R_SUCCESS)
			goto checksrv;
		result = dns_rdataset_first(&rdataset);
		while (result == ISC_R_SUCCESS) {
			dns_rdataset_current(&rdataset, &rdata);
			result = dns_rdata_tostruct(&rdata, &mx, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			if (!zone_check_mx(zone, db, &mx.mx, name))
				ok = false;
			dns_rdata_reset(&rdata);
			result = dns_rdataset_next(&rdataset);
		}
		dns_rdataset_disassociate(&rdataset);

 checksrv:
		if (zone->rdclass != dns_rdataclass_in)
			goto next;
		result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_srv,
					     0, 0, &rdataset, NULL);
		if (result != ISC_R_SUCCESS)
			goto checkspf;
		result = dns_rdataset_first(&rdataset);
		while (result == ISC_R_SUCCESS) {
			dns_rdataset_current(&rdataset, &rdata);
			result = dns_rdata_tostruct(&rdata, &srv, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			if (!zone_check_srv(zone, db, &srv.target, name))
				ok = false;
			dns_rdata_reset(&rdata);
			result = dns_rdataset_next(&rdataset);
		}
		dns_rdataset_disassociate(&rdataset);

 checkspf:
		/*
		 * Check if there is a type SPF record without an
		 * SPF-formatted type TXT record also being present.
		 */
		if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSPF))
			goto next;
		if (zone->rdclass != dns_rdataclass_in)
			goto next;
		have_spf = have_txt = false;
		result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_spf,
					     0, 0, &rdataset, NULL);
		if (result == ISC_R_SUCCESS) {
			dns_rdataset_disassociate(&rdataset);
			have_spf = true;
		}
		result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_txt,
					     0, 0, &rdataset, NULL);
		if (result != ISC_R_SUCCESS)
			goto notxt;
		result = dns_rdataset_first(&rdataset);
		while (result == ISC_R_SUCCESS) {
			dns_rdataset_current(&rdataset, &rdata);
			have_txt = isspf(&rdata);
			dns_rdata_reset(&rdata);
			if (have_txt)
				break;
			result = dns_rdataset_next(&rdataset);
		}
		dns_rdataset_disassociate(&rdataset);

 notxt:
		if (have_spf && !have_txt) {
			char namebuf[DNS_NAME_FORMATSIZE];

			dns_name_format(name, namebuf, sizeof(namebuf));
			dns_zone_log(zone, ISC_LOG_WARNING, "'%s' found type "
				     "SPF record but no SPF TXT record found, "
				     "add matching type TXT record", namebuf);
		}

 next:
		dns_db_detachnode(db, &node);
		result = dns_dbiterator_next(dbiterator);
	}

 cleanup:
	if (node != NULL)
		dns_db_detachnode(db, &node);
	dns_dbiterator_destroy(&dbiterator);

	return (ok);
}

Project: bind9
File: zone.c

zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
	      dns_name_t *owner)
{
	isc_result_t result;
	char ownerbuf[DNS_NAME_FORMATSIZE];
	char namebuf[DNS_NAME_FORMATSIZE];
	char altbuf[DNS_NAME_FORMATSIZE];
	dns_fixedname_t fixed;
	dns_name_t *foundname;
	int level;

	/*
	 * "." means the services does not exist.
	 */
	if (dns_name_equal(name, dns_rootname))
		return (true);

	/*
	 * Outside of zone.
	 */
	if (!dns_name_issubdomain(name, &zone->origin)) {
		if (zone->checkmx != NULL)
			return ((zone->checkmx)(zone, name, owner));
		return (true);
	}

	if (zone->type == dns_zone_master)
		level = ISC_LOG_ERROR;
	else
		level = ISC_LOG_WARNING;

	foundname = dns_fixedname_initname(&fixed);

	result = dns_db_find(db, name, NULL, dns_rdatatype_a,
			     0, 0, NULL, foundname, NULL, NULL);
	if (result == ISC_R_SUCCESS)
		return (true);

	if (result == DNS_R_NXRRSET) {
		result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
				     0, 0, NULL, foundname, NULL, NULL);
		if (result == ISC_R_SUCCESS)
			return (true);
	}

	dns_name_format(owner, ownerbuf, sizeof ownerbuf);
	dns_name_format(name, namebuf, sizeof namebuf);
	if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
	    result == DNS_R_EMPTYNAME) {
		if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
			level = ISC_LOG_WARNING;
		dns_zone_log(zone, level,
			     "%s/MX '%s' has no address records (A or AAAA)",
			     ownerbuf, namebuf);
		return ((level == ISC_LOG_WARNING) ? true : false);
	}

	if (result == DNS_R_CNAME) {
		if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) ||
		    DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME))
			level = ISC_LOG_WARNING;
		if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME))
			dns_zone_log(zone, level,
				     "%s/MX '%s' is a CNAME (illegal)",
				     ownerbuf, namebuf);
		return ((level == ISC_LOG_WARNING) ? true : false);
	}

	if (result == DNS_R_DNAME) {
		if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) ||
		    DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME))
			level = ISC_LOG_WARNING;
		if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) {
			dns_name_format(foundname, altbuf, sizeof altbuf);
			dns_zone_log(zone, level, "%s/MX '%s' is below a DNAME"
				     " '%s' (illegal)", ownerbuf, namebuf,
				     altbuf);
		}
		return ((level == ISC_LOG_WARNING) ? true : false);
	}

	if (zone->checkmx != NULL && result == DNS_R_DELEGATION)
		return ((zone->checkmx)(zone, name, owner));

	return (true);
}

Project: bind9
File: zone.c

dns_zone_verifydb(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver) {
	dns_dbversion_t *version = NULL;
	dns_keytable_t *secroots = NULL;
	isc_result_t result;
	dns_name_t *origin;

	const char me[] = "dns_zone_verifydb";
	ENTER;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(db != NULL);

	if (dns_zone_gettype(zone) != dns_zone_mirror) {
		return (ISC_R_SUCCESS);
	}

	if (ver == NULL) {
		dns_db_currentversion(db, &version);
	} else {
		version = ver;
	}

	if (zone->view != NULL) {
		result = dns_view_getsecroots(zone->view, &secroots);
		if (result != ISC_R_SUCCESS) {
			goto done;
		}
	}

	origin = dns_db_origin(db);
	result = dns_zoneverify_dnssec(zone, db, version, origin, secroots,
				       zone->mctx, true, false);

 done:
	if (secroots != NULL) {
		dns_keytable_detach(&secroots);
	}

	if (ver == NULL) {
		dns_db_closeversion(db, &version, false);
	}

	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR, "zone verification failed: %s",
			   isc_result_totext(result));
		result = DNS_R_VERIFYFAILURE;
	}

	return (result);
}

Project: bind9
File: zone.c

dumptostream(dns_zone_t *zone, FILE *fd, const dns_master_style_t *style,
	     dns_masterformat_t format, const uint32_t rawversion)
{
	isc_result_t result;
	dns_dbversion_t *version = NULL;
	dns_db_t *db = NULL;
	dns_masterrawheader_t rawdata;

	REQUIRE(DNS_ZONE_VALID(zone));

	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)
		return (DNS_R_NOTLOADED);

	dns_db_currentversion(db, &version);
	dns_master_initrawheader(&rawdata);
	if (rawversion == 0)
		rawdata.flags |= DNS_MASTERRAW_COMPAT;
	else if (inline_secure(zone))
		get_raw_serial(zone->raw, &rawdata);
	else if (zone->sourceserialset) {
		rawdata.flags = DNS_MASTERRAW_SOURCESERIALSET;
		rawdata.sourceserial = zone->sourceserial;
	}
	result = dns_master_dumptostream(zone->mctx, db, version, style,
					 format, &rawdata, fd);
	dns_db_closeversion(db, &version, false);
	dns_db_detach(&db);
	return (result);
}

Project: bind9
File: zone.c

fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
		 bool active, dns_rdatatype_t privatetype,
		 dns_diff_t *diff)
{
	dns_dbnode_t *node = NULL;
	dns_name_t *name = dns_db_origin(db);
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdataset_t rdataset;
	dns_rdata_nsec3param_t nsec3param;
	isc_result_t result;
	isc_buffer_t buffer;
	unsigned char parambuf[DNS_NSEC3PARAM_BUFFERSIZE];
	dns_ttl_t ttl = 0;
	bool nseconly = false, nsec3ok = false;

	dns_rdataset_init(&rdataset);

	result = dns_db_getoriginnode(db, &node);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
				     0, 0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND)
		goto try_private;
	if (result != ISC_R_SUCCESS)
		goto failure;

	/*
	 * Preserve the existing ttl.
	 */
	ttl = rdataset.ttl;

	/*
	 * Delete all NSEC3PARAM records which match that in nsec3chain.
	 */
	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset)) {

		dns_rdataset_current(&rdataset, &rdata);
		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));

		if (nsec3param.hash != chain->nsec3param.hash ||
		    (active && nsec3param.flags != 0) ||
		    nsec3param.iterations != chain->nsec3param.iterations ||
		    nsec3param.salt_length != chain->nsec3param.salt_length ||
		    memcmp(nsec3param.salt, chain->nsec3param.salt,
			   nsec3param.salt_length)) {
			dns_rdata_reset(&rdata);
			continue;
		}

		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
				    name, rdataset.ttl, &rdata));
		dns_rdata_reset(&rdata);
	}
	if (result != ISC_R_NOMORE)
		goto failure;

	dns_rdataset_disassociate(&rdataset);

 try_private:

	if (active)
		goto add;

	result = dns_nsec_nseconly(db, ver, &nseconly);
	nsec3ok = (result == ISC_R_SUCCESS && !nseconly);

	/*
	 * Delete all private records which match that in nsec3chain.
	 */
	result = dns_db_findrdataset(db, node, ver, privatetype,
				     0, 0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND)
		goto add;
	if (result != ISC_R_SUCCESS)
		goto failure;

	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset)) {
		dns_rdata_t private = DNS_RDATA_INIT;
		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];

		dns_rdataset_current(&rdataset, &private);
		if (!dns_nsec3param_fromprivate(&private, &rdata,
						buf, sizeof(buf)))
			continue;
		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));

		if ((!nsec3ok &&
		     (nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0) ||
		    nsec3param.hash != chain->nsec3param.hash ||
		    nsec3param.iterations != chain->nsec3param.iterations ||
		    nsec3param.salt_length != chain->nsec3param.salt_length ||
		    memcmp(nsec3param.salt, chain->nsec3param.salt,
			   nsec3param.salt_length)) {
			dns_rdata_reset(&rdata);
			continue;
		}

		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
				    name, rdataset.ttl, &private));
		dns_rdata_reset(&rdata);
	}
	if (result != ISC_R_NOMORE)
		goto failure;

  add:
	if ((chain->nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) {
		result = ISC_R_SUCCESS;
		goto failure;
	}

	/*
	 * Add a NSEC3PARAM record which matches that in nsec3chain but
	 * with all flags bits cleared.
	 *
	 * Note: we do not clear chain->nsec3param.flags as this change
	 * may be reversed.
	 */
	isc_buffer_init(&buffer, &parambuf, sizeof(parambuf));
	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db),
				   dns_rdatatype_nsec3param,
				   &chain->nsec3param, &buffer));
	rdata.data[1] = 0;	/* Clear flag bits. */
	CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, ttl, &rdata));

  failure:
	dns_db_detachnode(db, &node);
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
		     uint16_t keyid, bool deleteit)
{
	isc_result_t result;
	REQUIRE(DNS_ZONE_VALID(zone));

	dnssec_log(zone, ISC_LOG_NOTICE,
		   "dns_zone_signwithkey(algorithm=%u, keyid=%u)",
		   algorithm, keyid);
	LOCK_ZONE(zone);
	result = zone_signwithkey(zone, algorithm, keyid, deleteit);
	UNLOCK_ZONE(zone);

	return (result);
}

Project: bind9
File: zone.c

dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote,
			   isc_sockaddr_t *local, isc_time_t *now)
{
	uint32_t seconds = isc_time_seconds(now);
	uint32_t last = seconds;
	unsigned int i, slot = UNREACH_CHACHE_SIZE, oldest = 0;

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	RWLOCK(&zmgr->urlock, isc_rwlocktype_write);
	for (i = 0; i < UNREACH_CHACHE_SIZE; i++) {
		/* Existing entry? */
		if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) &&
		    isc_sockaddr_equal(&zmgr->unreachable[i].local, local))
			break;
		/* Empty slot? */
		if (zmgr->unreachable[i].expire < seconds)
			slot = i;
		/* Least recently used slot? */
		if (zmgr->unreachable[i].last < last) {
			last = zmgr->unreachable[i].last;
			oldest = i;
		}
	}
	if (i < UNREACH_CHACHE_SIZE) {
		/*
		 * Found a existing entry.  Update the expire timer and
		 * last usage timestamps.
		 */
		zmgr->unreachable[i].expire = seconds + UNREACH_HOLD_TIME;
		zmgr->unreachable[i].last = seconds;
		if (zmgr->unreachable[i].expire < seconds)
			zmgr->unreachable[i].count = 1;
		else
			zmgr->unreachable[i].count++;
	} else if (slot != UNREACH_CHACHE_SIZE) {
		/*
		 * Found a empty slot. Add a new entry to the cache.
		 */
		zmgr->unreachable[slot].expire = seconds + UNREACH_HOLD_TIME;
		zmgr->unreachable[slot].last = seconds;
		zmgr->unreachable[slot].remote = *remote;
		zmgr->unreachable[slot].local = *local;
		zmgr->unreachable[slot].count = 1;
	} else {
		/*
		 * Replace the least recently used entry in the cache.
		 */
		zmgr->unreachable[oldest].expire = seconds + UNREACH_HOLD_TIME;
		zmgr->unreachable[oldest].last = seconds;
		zmgr->unreachable[oldest].remote = *remote;
		zmgr->unreachable[oldest].local = *local;
		zmgr->unreachable[oldest].count = 1;
	}
	RWUNLOCK(&zmgr->urlock, isc_rwlocktype_write);
}

Project: bind9
File: zone.c

dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
		       isc_sockaddr_t *to, dns_message_t *msg)
{
	unsigned int i;
	dns_rdata_soa_t soa;
	dns_rdataset_t *rdataset = NULL;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_result_t result;
	char fromtext[ISC_SOCKADDR_FORMATSIZE];
	int match = 0;
	isc_netaddr_t netaddr;
	uint32_t serial = 0;
	bool have_serial = false;
	dns_tsigkey_t *tsigkey;
	dns_name_t *tsig;

	REQUIRE(DNS_ZONE_VALID(zone));

	/*
	 * If type != T_SOA return DNS_R_NOTIMP.  We don't yet support
	 * ROLLOVER.
	 *
	 * SOA:	RFC1996
	 * Check that 'from' is a valid notify source, (zone->masters).
	 *	Return DNS_R_REFUSED if not.
	 *
	 * If the notify message contains a serial number check it
	 * against the zones serial and return if <= current serial
	 *
	 * If a refresh check is progress, if so just record the
	 * fact we received a NOTIFY and from where and return.
	 * We will perform a new refresh check when the current one
	 * completes. Return ISC_R_SUCCESS.
	 *
	 * Otherwise initiate a refresh check using 'from' as the
	 * first address to check.  Return ISC_R_SUCCESS.
	 */

	isc_sockaddr_format(from, fromtext, sizeof(fromtext));

	/*
	 * Notify messages are processed by the raw zone.
	 */
	LOCK_ZONE(zone);
	INSIST(zone != zone->raw);
	if (inline_secure(zone)) {
		result = dns_zone_notifyreceive(zone->raw, from, to, msg);
		UNLOCK_ZONE(zone);
		return (result);
	}
	/*
	 *  We only handle NOTIFY (SOA) at the present.
	 */
	if (isc_sockaddr_pf(from) == PF_INET)
		inc_stats(zone, dns_zonestatscounter_notifyinv4);
	else
		inc_stats(zone, dns_zonestatscounter_notifyinv6);
	if (msg->counts[DNS_SECTION_QUESTION] == 0 ||
	    dns_message_findname(msg, DNS_SECTION_QUESTION, &zone->origin,
				 dns_rdatatype_soa, dns_rdatatype_none,
				 NULL, NULL) != ISC_R_SUCCESS) {
		UNLOCK_ZONE(zone);
		if (msg->counts[DNS_SECTION_QUESTION] == 0) {
			dns_zone_log(zone, ISC_LOG_NOTICE,
				     "NOTIFY with no "
				     "question section from: %s", fromtext);
			return (DNS_R_FORMERR);
		}
		dns_zone_log(zone, ISC_LOG_NOTICE,
			     "NOTIFY zone does not match");
		return (DNS_R_NOTIMP);
	}

	/*
	 * If we are a master zone just succeed.
	 */
	if (zone->type == dns_zone_master) {
		UNLOCK_ZONE(zone);
		return (ISC_R_SUCCESS);
	}

	isc_netaddr_fromsockaddr(&netaddr, from);
	for (i = 0; i < zone->masterscnt; i++) {
		if (isc_sockaddr_eqaddr(from, &zone->masters[i]))
			break;
		if (zone->view->aclenv.match_mapped &&
		    IN6_IS_ADDR_V4MAPPED(&from->type.sin6.sin6_addr) &&
		    isc_sockaddr_pf(&zone->masters[i]) == AF_INET) {
			isc_netaddr_t na1, na2;
			isc_netaddr_fromv4mapped(&na1, &netaddr);
			isc_netaddr_fromsockaddr(&na2, &zone->masters[i]);
			if (isc_netaddr_equal(&na1, &na2))
				break;
		}
	}

	/*
	 * Accept notify requests from non masters if they are on
	 * 'zone->notify_acl'.
	 */
	tsigkey = dns_message_gettsigkey(msg);
	tsig = dns_tsigkey_identity(tsigkey);
	if (i >= zone->masterscnt && zone->notify_acl != NULL &&
	    (dns_acl_match(&netaddr, tsig, zone->notify_acl,
			   &zone->view->aclenv, &match,
			   NULL) == ISC_R_SUCCESS) &&
	    match > 0)
	{
		/* Accept notify. */
	} else if (i >= zone->masterscnt) {
		UNLOCK_ZONE(zone);
		dns_zone_log(zone, ISC_LOG_INFO,
			     "refused notify from non-master: %s", fromtext);
		inc_stats(zone, dns_zonestatscounter_notifyrej);
		return (DNS_R_REFUSED);
	}

	/*
	 * If the zone is loaded and there are answers check the serial
	 * to see if we need to do a refresh.  Do not worry about this
	 * check if we are a dialup zone as we use the notify request
	 * to trigger a refresh check.
	 */
	if (msg->counts[DNS_SECTION_ANSWER] > 0 &&
	    DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
	    !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH)) {
		result = dns_message_findname(msg, DNS_SECTION_ANSWER,
					      &zone->origin,
					      dns_rdatatype_soa,
					      dns_rdatatype_none, NULL,
					      &rdataset);
		if (result == ISC_R_SUCCESS)
			result = dns_rdataset_first(rdataset);
		if (result == ISC_R_SUCCESS) {
			uint32_t oldserial;
			unsigned int soacount;

			dns_rdataset_current(rdataset, &rdata);
			result = dns_rdata_tostruct(&rdata, &soa, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			serial = soa.serial;
			have_serial = true;
			/*
			 * The following should safely be performed without DB
			 * lock and succeed in this context.
			 */
			result = zone_get_from_db(zone, zone->db, NULL,
						  &soacount, &oldserial, NULL,
						  NULL, NULL, NULL, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
			RUNTIME_CHECK(soacount > 0U);
			if (isc_serial_le(serial, oldserial)) {
				dns_zone_log(zone,
					     ISC_LOG_INFO,
					     "notify from %s: "
					     "zone is up to date",
					     fromtext);
				UNLOCK_ZONE(zone);
				return (ISC_R_SUCCESS);
			}
		}
	}

	/*
	 * If we got this far and there was a refresh in progress just
	 * let it complete.  Record where we got the notify from so we
	 * can perform a refresh check when the current one completes
	 */
	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) {
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDREFRESH);
		zone->notifyfrom = *from;
		UNLOCK_ZONE(zone);
		if (have_serial)
			dns_zone_log(zone, ISC_LOG_INFO,
				     "notify from %s: serial %u: refresh in "
				     "progress, refresh check queued",
				      fromtext, serial);
		else
			dns_zone_log(zone, ISC_LOG_INFO,
				     "notify from %s: refresh in progress, "
				     "refresh check queued", fromtext);
		return (ISC_R_SUCCESS);
	}
	if (have_serial)
		dns_zone_log(zone, ISC_LOG_INFO, "notify from %s: serial %u",
			     fromtext, serial);
	else
		dns_zone_log(zone, ISC_LOG_INFO, "notify from %s: no serial",
			     fromtext);
	zone->notifyfrom = *from;
	UNLOCK_ZONE(zone);

	if (to != NULL) {
		dns_zonemgr_unreachabledel(zone->zmgr, from, to);
	}
	dns_zone_refresh(zone);
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
	isc_result_t result;
	dns_zone_t *zone;
	isc_time_t now;

	REQUIRE(zonep != NULL && *zonep == NULL);
	REQUIRE(mctx != NULL);

	TIME_NOW(&now);
	zone = isc_mem_get(mctx, sizeof(*zone));
	if (zone == NULL) {
		return (ISC_R_NOMEMORY);
	}

	zone->mctx = NULL;
	isc_mem_attach(mctx, &zone->mctx);

	isc_mutex_init(&zone->lock);

	result = ZONEDB_INITLOCK(&zone->dblock);
	if (result != ISC_R_SUCCESS) {
		goto free_mutex;
	}

	/* XXX MPA check that all elements are initialised */
#ifdef DNS_ZONE_CHECKLOCK
	zone->locked = false;
#endif
	zone->db = NULL;
	zone->zmgr = NULL;
	ISC_LINK_INIT(zone, link);
	isc_refcount_init(&zone->erefs, 1);	/* Implicit attach. */
	zone->irefs = 0;
	dns_name_init(&zone->origin, NULL);
	zone->strnamerd = NULL;
	zone->strname = NULL;
	zone->strrdclass = NULL;
	zone->strviewname = NULL;
	zone->masterfile = NULL;
	ISC_LIST_INIT(zone->includes);
	ISC_LIST_INIT(zone->newincludes);
	zone->nincludes = 0;
	zone->masterformat = dns_masterformat_none;
	zone->masterstyle = NULL;
	zone->keydirectory = NULL;
	zone->journalsize = -1;
	zone->journal = NULL;
	zone->rdclass = dns_rdataclass_none;
	zone->type = dns_zone_none;
	zone->flags = 0;
	zone->options = 0;
	zone->keyopts = 0;
	zone->db_argc = 0;
	zone->db_argv = NULL;
	isc_time_settoepoch(&zone->expiretime);
	isc_time_settoepoch(&zone->refreshtime);
	isc_time_settoepoch(&zone->dumptime);
	isc_time_settoepoch(&zone->loadtime);
	zone->notifytime = now;
	isc_time_settoepoch(&zone->resigntime);
	isc_time_settoepoch(&zone->keywarntime);
	isc_time_settoepoch(&zone->signingtime);
	isc_time_settoepoch(&zone->nsec3chaintime);
	isc_time_settoepoch(&zone->refreshkeytime);
	zone->refreshkeyinterval = 0;
	zone->refreshkeycount = 0;
	zone->refresh = DNS_ZONE_DEFAULTREFRESH;
	zone->retry = DNS_ZONE_DEFAULTRETRY;
	zone->expire = 0;
	zone->minimum = 0;
	zone->maxrefresh = DNS_ZONE_MAXREFRESH;
	zone->minrefresh = DNS_ZONE_MINREFRESH;
	zone->maxretry = DNS_ZONE_MAXRETRY;
	zone->minretry = DNS_ZONE_MINRETRY;
	zone->masters = NULL;
	zone->masterdscps = NULL;
	zone->masterkeynames = NULL;
	zone->mastersok = NULL;
	zone->masterscnt = 0;
	zone->curmaster = 0;
	zone->maxttl = 0;
	zone->notify = NULL;
	zone->notifykeynames = NULL;
	zone->notifydscp = NULL;
	zone->notifytype = dns_notifytype_yes;
	zone->notifycnt = 0;
	zone->task = NULL;
	zone->loadtask = NULL;
	zone->update_acl = NULL;
	zone->forward_acl = NULL;
	zone->notify_acl = NULL;
	zone->query_acl = NULL;
	zone->queryon_acl = NULL;
	zone->xfr_acl = NULL;
	zone->update_disabled = false;
	zone->zero_no_soa_ttl = true;
	zone->check_names = dns_severity_ignore;
	zone->request = NULL;
	zone->lctx = NULL;
	zone->readio = NULL;
	zone->dctx = NULL;
	zone->writeio = NULL;
	zone->timer = NULL;
	zone->idlein = DNS_DEFAULT_IDLEIN;
	zone->idleout = DNS_DEFAULT_IDLEOUT;
	zone->log_key_expired_timer = 0;
	ISC_LIST_INIT(zone->notifies);
	isc_sockaddr_any(&zone->notifysrc4);
	isc_sockaddr_any6(&zone->notifysrc6);
	isc_sockaddr_any(&zone->xfrsource4);
	isc_sockaddr_any6(&zone->xfrsource6);
	isc_sockaddr_any(&zone->altxfrsource4);
	isc_sockaddr_any6(&zone->altxfrsource6);
	zone->notifysrc4dscp = -1;
	zone->notifysrc6dscp = -1;
	zone->xfrsource4dscp = -1;
	zone->xfrsource6dscp = -1;
	zone->altxfrsource4dscp = -1;
	zone->altxfrsource6dscp = -1;
	zone->xfr = NULL;
	zone->tsigkey = NULL;
	zone->maxxfrin = MAX_XFER_TIME;
	zone->maxxfrout = MAX_XFER_TIME;
	zone->ssutable = NULL;
	zone->sigvalidityinterval = 30 * 24 * 3600;
	zone->keyvalidityinterval = 0;
	zone->sigresigninginterval = 7 * 24 * 3600;
	zone->view = NULL;
	zone->prev_view = NULL;
	zone->checkmx = NULL;
	zone->checksrv = NULL;
	zone->checkns = NULL;
	ISC_LINK_INIT(zone, statelink);
	zone->statelist = NULL;
	zone->stats = NULL;
	zone->requeststats_on = false;
	zone->statlevel = dns_zonestat_none;
	zone->requeststats = NULL;
	zone->rcvquerystats = NULL;
	zone->notifydelay = 5;
	zone->isself = NULL;
	zone->isselfarg = NULL;
	ISC_LIST_INIT(zone->signing);
	ISC_LIST_INIT(zone->nsec3chain);
	ISC_LIST_INIT(zone->setnsec3param_queue);
	zone->signatures = 10;
	zone->nodes = 100;
	zone->privatetype = (dns_rdatatype_t)0xffffU;
	zone->added = false;
	zone->automatic = false;
	zone->rpzs = NULL;
	zone->rpz_num = DNS_RPZ_INVALID_NUM;

	zone->catzs = NULL;
	zone->parentcatz = NULL;

	ISC_LIST_INIT(zone->forwards);
	zone->raw = NULL;
	zone->secure = NULL;
	zone->sourceserial = 0;
	zone->sourceserialset = false;
	zone->requestixfr = true;
	zone->requestexpire = true;
	ISC_LIST_INIT(zone->rss_events);
	zone->rss_db = NULL;
	zone->rss_raw = NULL;
	zone->rss_newver = NULL;
	zone->rss_oldver = NULL;
	zone->rss_event = NULL;
	zone->rss_state = NULL;
	zone->updatemethod = dns_updatemethod_increment;
	zone->maxrecords = 0U;

	zone->magic = ZONE_MAGIC;

	zone->gluecachestats = NULL;
	result = isc_stats_create(mctx, &zone->gluecachestats,
				  dns_gluecachestatscounter_max);
	if (result != ISC_R_SUCCESS) {
		goto free_erefs;
	}

	/* Must be after magic is set. */
	result = dns_zone_setdbtype(zone, dbargc_default, dbargv_default);
	if (result != ISC_R_SUCCESS) {
		goto free_stats;
	}

	ISC_EVENT_INIT(&zone->ctlevent, sizeof(zone->ctlevent), 0, NULL,
		       DNS_EVENT_ZONECONTROL, zone_shutdown, zone, zone,
		       NULL, NULL);
	*zonep = zone;
	return (ISC_R_SUCCESS);

 free_stats:
	if (zone->gluecachestats != NULL)
		isc_stats_detach(&zone->gluecachestats);

 free_erefs:
	INSIST(isc_refcount_decrement(&zone->erefs) > 0);
	isc_refcount_destroy(&zone->erefs);

	ZONEDB_DESTROYLOCK(&zone->dblock);

 free_mutex:
	isc_mutex_destroy(&zone->lock);

	isc_mem_putanddetach(&zone->mctx, zone, sizeof(*zone));
	return (result);
}

Project: bind9
File: zone.c

find_next_matching_tuple(dns_difftuple_t *cur) {
	dns_difftuple_t *next = cur;

	while ((next = ISC_LIST_NEXT(next, link)) != NULL) {
		if (cur->rdata.type == next->rdata.type &&
		    dns_name_equal(&cur->name, &next->name))
		{
			return (next);
		}
	}

	return (NULL);
}

Project: bind9
File: zone.c

dns_zone_dialup(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

	zone_debuglog(zone, "dns_zone_dialup", 3,
		      "notify = %d, refresh = %d",
		      DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY),
		      DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH));

	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY))
		dns_zone_notify(zone);
	if (zone->type != dns_zone_master && zone->masters != NULL &&
	    DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH))
		dns_zone_refresh(zone);
}

Project: bind9
File: zone.c

zone_journal_compact(dns_zone_t *zone, dns_db_t *db, uint32_t serial) {
	isc_result_t result;
	int32_t journalsize;
	dns_dbversion_t *ver = NULL;
	uint64_t dbsize;

	INSIST(LOCKED_ZONE(zone));
	if (inline_raw(zone))
		INSIST(LOCKED_ZONE(zone->secure));

	journalsize = zone->journalsize;
	if (journalsize == -1) {
		journalsize = DNS_JOURNAL_SIZE_MAX;
		dns_db_currentversion(db, &ver);
		result = dns_db_getsize(db, ver, NULL, &dbsize);
		dns_db_closeversion(db, &ver, false);
		if (result != ISC_R_SUCCESS) {
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "zone_journal_compact: "
				     "could not get zone size: %s",
				     isc_result_totext(result));
		} else if (dbsize < DNS_JOURNAL_SIZE_MAX / 2) {
			journalsize = (int32_t)dbsize * 2;
		}
	}
	zone_debuglog(zone, "zone_journal_compact", 1,
		      "target journal size %d", journalsize);
	result = dns_journal_compact(zone->mctx, zone->journal,
				     serial, journalsize);
	switch (result) {
	case ISC_R_SUCCESS:
	case ISC_R_NOSPACE:
	case ISC_R_NOTFOUND:
		dns_zone_log(zone, ISC_LOG_DEBUG(3),
			     "dns_journal_compact: %s",
			     dns_result_totext(result));
		break;
	default:
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "dns_journal_compact failed: %s",
			     dns_result_totext(result));
		break;
	}
}

Project: bind9
File: zone.c

delete_keydata(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
	       dns_name_t *name, dns_rdataset_t *rdataset)
{
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_result_t result, uresult;

	for (result = dns_rdataset_first(rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(rdataset)) {
		dns_rdata_reset(&rdata);
		dns_rdataset_current(rdataset, &rdata);
		uresult = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
					name, 0, &rdata);
		if (uresult != ISC_R_SUCCESS)
			return (uresult);
	}
	if (result == ISC_R_NOMORE)
		result = ISC_R_SUCCESS;
	return (result);
}

Project: bind9
File: zone.c

soa_query(isc_task_t *task, isc_event_t *event) {
	const char me[] = "soa_query";
	isc_result_t result = ISC_R_FAILURE;
	dns_message_t *message = NULL;
	dns_zone_t *zone = event->ev_arg;
	dns_zone_t *dummy = NULL;
	isc_netaddr_t masterip;
	dns_tsigkey_t *key = NULL;
	uint32_t options;
	bool cancel = true;
	int timeout;
	bool have_xfrsource, have_xfrdscp, reqnsid, reqexpire;
	uint16_t udpsize = SEND_BUFFER_SIZE;
	isc_dscp_t dscp = -1;

	REQUIRE(DNS_ZONE_VALID(zone));

	UNUSED(task);

	ENTER;

	LOCK_ZONE(zone);
	if (((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) ||
	    DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) ||
	    zone->view->requestmgr == NULL) {
		if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
			cancel = false;
		goto cleanup;
	}

 again:
	result = create_query(zone, dns_rdatatype_soa, &message);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	INSIST(zone->masterscnt > 0);
	INSIST(zone->curmaster < zone->masterscnt);

	zone->masteraddr = zone->masters[zone->curmaster];

	isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
	/*
	 * First, look for a tsig key in the master statement, then
	 * try for a server key.
	 */
	if ((zone->masterkeynames != NULL) &&
	    (zone->masterkeynames[zone->curmaster] != NULL)) {
		dns_view_t *view = dns_zone_getview(zone);
		dns_name_t *keyname = zone->masterkeynames[zone->curmaster];
		result = dns_view_gettsig(view, keyname, &key);
		if (result != ISC_R_SUCCESS) {
			char namebuf[DNS_NAME_FORMATSIZE];
			dns_name_format(keyname, namebuf, sizeof(namebuf));
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "unable to find key: %s", namebuf);
			goto skip_master;
		}
	}
	if (key == NULL) {
		result = dns_view_getpeertsig(zone->view, &masterip, &key);
		if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
			char addrbuf[ISC_NETADDR_FORMATSIZE];
			isc_netaddr_format(&masterip, addrbuf, sizeof(addrbuf));
			dns_zone_log(zone, ISC_LOG_ERROR,
				     "unable to find TSIG key for %s", addrbuf);
			goto skip_master;
		}
	}

	options = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEVC) ?
		  DNS_REQUESTOPT_TCP : 0;
	have_xfrsource = have_xfrdscp = false;
	reqnsid = zone->view->requestnsid;
	reqexpire = zone->requestexpire;
	if (zone->view->peers != NULL) {
		dns_peer_t *peer = NULL;
		bool edns, usetcp;
		result = dns_peerlist_peerbyaddr(zone->view->peers,
						 &masterip, &peer);
		if (result == ISC_R_SUCCESS) {
			result = dns_peer_getsupportedns(peer, &edns);
			if (result == ISC_R_SUCCESS && !edns)
				DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
			result = dns_peer_gettransfersource(peer,
							    &zone->sourceaddr);
			if (result == ISC_R_SUCCESS)
				have_xfrsource = true;
			(void)dns_peer_gettransferdscp(peer, &dscp);
			if (dscp != -1)
				have_xfrdscp = true;
			if (zone->view->resolver != NULL)
				udpsize =
				  dns_resolver_getudpsize(zone->view->resolver);
			(void)dns_peer_getudpsize(peer, &udpsize);
			(void)dns_peer_getrequestnsid(peer, &reqnsid);
			(void)dns_peer_getrequestexpire(peer, &reqexpire);
			result = dns_peer_getforcetcp(peer, &usetcp);
			if (result == ISC_R_SUCCESS && usetcp)
				options |= DNS_REQUESTOPT_TCP;
		}
	}

	switch (isc_sockaddr_pf(&zone->masteraddr)) {
	case PF_INET:
		if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) {
			if (isc_sockaddr_equal(&zone->altxfrsource4,
					       &zone->xfrsource4))
				goto skip_master;
			zone->sourceaddr = zone->altxfrsource4;
			if (!have_xfrdscp)
				dscp = zone->altxfrsource4dscp;
		} else if (!have_xfrsource) {
			zone->sourceaddr = zone->xfrsource4;
			if (!have_xfrdscp)
				dscp = zone->xfrsource4dscp;
		}
		break;
	case PF_INET6:
		if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) {
			if (isc_sockaddr_equal(&zone->altxfrsource6,
					       &zone->xfrsource6))
				goto skip_master;
			zone->sourceaddr = zone->altxfrsource6;
			if (!have_xfrdscp)
				dscp = zone->altxfrsource6dscp;
		} else if (!have_xfrsource) {
			zone->sourceaddr = zone->xfrsource6;
			if (!have_xfrdscp)
				dscp = zone->xfrsource6dscp;
		}
		break;
	default:
		result = ISC_R_NOTIMPLEMENTED;
		goto cleanup;
	}

	if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
		result = add_opt(message, udpsize, reqnsid, reqexpire);
		if (result != ISC_R_SUCCESS)
			zone_debuglog(zone, me, 1,
				      "unable to add opt record: %s",
				      dns_result_totext(result));
	}

	zone_iattach(zone, &dummy);
	timeout = 15;
	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH))
		timeout = 30;
	result = dns_request_createvia(zone->view->requestmgr, message,
				       &zone->sourceaddr, &zone->masteraddr,
				       dscp, options, key, timeout * 3,
				       timeout, 0, zone->task,
				       refresh_callback, zone, &zone->request);
	if (result != ISC_R_SUCCESS) {
		zone_idetach(&dummy);
		zone_debuglog(zone, me, 1,
			      "dns_request_createvia4() failed: %s",
			      dns_result_totext(result));
		goto skip_master;
	} else {
		if (isc_sockaddr_pf(&zone->masteraddr) == PF_INET)
			inc_stats(zone, dns_zonestatscounter_soaoutv4);
		else
			inc_stats(zone, dns_zonestatscounter_soaoutv6);
	}
	cancel = false;

 cleanup:
	if (key != NULL)
		dns_tsigkey_detach(&key);
	if (result != ISC_R_SUCCESS)
		DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
	if (message != NULL)
		dns_message_destroy(&message);
	if (cancel)
		cancel_refresh(zone);
	isc_event_free(&event);
	UNLOCK_ZONE(zone);
	dns_zone_idetach(&zone);
	return;

 skip_master:
	if (key != NULL)
		dns_tsigkey_detach(&key);
	dns_message_destroy(&message);
	/*
	 * Skip to next failed / untried master.
	 */
	do {
		zone->curmaster++;
	} while (zone->curmaster < zone->masterscnt &&
		 zone->mastersok[zone->curmaster]);
	if (zone->curmaster < zone->masterscnt)
		goto again;
	zone->curmaster = 0;
	goto cleanup;
}

Project: bind9
File: zone.c

dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(catzs != NULL);

	LOCK_ZONE(zone);
	INSIST(zone->catzs == NULL || zone->catzs == catzs);
	dns_catz_catzs_set_view(catzs, zone->view);
	if (zone->catzs == NULL)
		dns_catz_catzs_attach(catzs, &zone->catzs);
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

move_matching_tuples(dns_difftuple_t *cur, dns_diff_t *src, dns_diff_t *dst) {
	do {
		dns_difftuple_t *next = find_next_matching_tuple(cur);
		ISC_LIST_UNLINK(src->tuples, cur, link);
		dns_diff_appendminimal(dst, &cur);
		cur = next;
	} while (cur != NULL);
}

Project: bind9
File: zone.c

add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
		    dns_dbversion_t *ver, dns_diff_t *diff,
		    bool sign_all)
{
	dns_difftuple_t *tuple, *newtuple = NULL;
	dns_rdata_dnskey_t dnskey;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	bool flag;
	isc_region_t r;
	isc_result_t result = ISC_R_SUCCESS;
	uint16_t keyid;
	unsigned char buf[5];
	dns_name_t *name = dns_db_origin(db);

	for (tuple = ISC_LIST_HEAD(diff->tuples);
	     tuple != NULL;
	     tuple = ISC_LIST_NEXT(tuple, link)) {
		if (tuple->rdata.type != dns_rdatatype_dnskey)
			continue;

		result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		if ((dnskey.flags &
		     (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
			 != DNS_KEYOWNER_ZONE)
			continue;

		dns_rdata_toregion(&tuple->rdata, &r);

		keyid = dst_region_computeid(&r);

		buf[0] = dnskey.algorithm;
		buf[1] = (keyid & 0xff00) >> 8;
		buf[2] = (keyid & 0xff);
		buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
		buf[4] = 0;
		rdata.data = buf;
		rdata.length = sizeof(buf);
		rdata.type = privatetype;
		rdata.rdclass = tuple->rdata.rdclass;

		if (sign_all || tuple->op == DNS_DIFFOP_DEL) {
			CHECK(rr_exists(db, ver, name, &rdata, &flag));
			if (flag)
				continue;
			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
						   name, 0, &rdata, &newtuple));
			CHECK(do_one_tuple(&newtuple, db, ver, diff));
			INSIST(newtuple == NULL);
		}

		/*
		 * Remove any record which says this operation has already
		 * completed.
		 */
		buf[4] = 1;
		CHECK(rr_exists(db, ver, name, &rdata, &flag));
		if (flag) {
			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
						   name, 0, &rdata, &newtuple));
			CHECK(do_one_tuple(&newtuple, db, ver, diff));
			INSIST(newtuple == NULL);
		}
	}
 failure:
	return (result);
}

Project: bind9
File: zone.c

zone_asyncload(isc_task_t *task, isc_event_t *event) {
	dns_asyncload_t *asl = event->ev_arg;
	dns_zone_t *zone = asl->zone;
	isc_result_t result;

	UNUSED(task);

	REQUIRE(DNS_ZONE_VALID(zone));

	isc_event_free(&event);

	LOCK_ZONE(zone);
	result = zone_load(zone, asl->flags, true);
	if (result != DNS_R_CONTINUE) {
		DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING);
	}
	UNLOCK_ZONE(zone);

	/* Inform the zone table we've finished loading */
	if (asl->loaded != NULL)
		(asl->loaded)(asl->loaded_arg, zone, task);

	isc_mem_put(zone->mctx, asl, sizeof (*asl));
	dns_zone_idetach(&zone);
}

Project: bind9
File: zone.c

sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
	  isc_stdtime_t now, dns_diff_t *diff, dns__zonediff_t *zonediff)
{
	isc_result_t result;
	isc_stdtime_t inception, soaexpire, keyexpire;
	bool check_ksk, keyset_kskonly;
	dst_key_t *zone_keys[DNS_MAXZONEKEYS];
	unsigned int nkeys = 0, i;
	dns_difftuple_t *tuple;

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

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

	keyexpire = dns_zone_getkeyvalidityinterval(zone);
	if (keyexpire == 0) {
		keyexpire = soaexpire - 1;
	} else {
		keyexpire += now;
	}

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

	/*
	 * See if dns__zone_updatesigs() will update DNSKEY signature and if
	 * not cause them to sign so that newly activated keys are used.
	 */
	for (tuple = ISC_LIST_HEAD(diff->tuples);
	     tuple != NULL;
	     tuple = ISC_LIST_NEXT(tuple, link))
	{
		if (tuple->rdata.type == dns_rdatatype_dnskey &&
		    dns_name_equal(&tuple->name, &zone->origin))
		{
			break;
		}
	}

	if (tuple == NULL) {
		result = del_sigs(zone, db, ver, &zone->origin,
				  dns_rdatatype_dnskey, zonediff,
				  zone_keys, nkeys, now, false);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "sign_apex:del_sigs -> %s",
				   dns_result_totext(result));
			goto failure;
		}
		result = add_sigs(db, ver, &zone->origin, dns_rdatatype_dnskey,
				  zonediff->diff, zone_keys, nkeys, zone->mctx,
				  inception, keyexpire, check_ksk,
				  keyset_kskonly);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "sign_apex:add_sigs -> %s",
				   dns_result_totext(result));
			goto failure;
		}
	}

	result = dns__zone_updatesigs(diff, db, ver, zone_keys, nkeys, zone,
				      inception, soaexpire, keyexpire, now,
				      check_ksk, keyset_kskonly, zonediff);

	if (result != ISC_R_SUCCESS) {
		dnssec_log(zone, ISC_LOG_ERROR,
			   "sign_apex:dns__zone_updatesigs -> %s",
			   dns_result_totext(result));
		goto failure;
	}

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

Project: bind9
File: zone.c

dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(raw != NULL && *raw == NULL);

	LOCK(&zone->lock);
	INSIST(zone != zone->raw);
	if (zone->raw != NULL)
		dns_zone_attach(zone->raw, raw);
	UNLOCK(&zone->lock);
}

Project: bind9
File: zone.c

dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
	bool free_now = false;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(DNS_ZONEMGR_VALID(zmgr));
	REQUIRE(zone->zmgr == zmgr);

	RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	LOCK_ZONE(zone);

	ISC_LIST_UNLINK(zmgr->zones, zone, link);
	zone->zmgr = NULL;
	zmgr->refs--;
	if (zmgr->refs == 0)
		free_now = true;

	UNLOCK_ZONE(zone);
	RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);

	if (free_now)
		zonemgr_free(zmgr);
	ENSURE(zone->zmgr == NULL);
}

Project: bind9
File: zone.c

dns_zone_setchecksrv(dns_zone_t *zone, dns_checksrvfunc_t checksrv) {
	REQUIRE(DNS_ZONE_VALID(zone));
	zone->checksrv = checksrv;
}

Project: bind9
File: zone.c

dns_zone_getrefreshkeytime(dns_zone_t *zone, isc_time_t *refreshkeytime) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(refreshkeytime != NULL);

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

Project: bind9
File: zone.c

dns_zone_setalsonotifydscpkeys(dns_zone_t *zone, const isc_sockaddr_t *notify,
			       const isc_dscp_t *dscps, dns_name_t **keynames,
			       uint32_t count)
{
	isc_result_t result;
	isc_sockaddr_t *newaddrs = NULL;
	isc_dscp_t *newdscps = NULL;
	dns_name_t **newnames = NULL;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(count == 0 || notify != NULL);
	if (keynames != NULL)
		REQUIRE(count != 0);

	LOCK_ZONE(zone);

	if (count == zone->notifycnt &&
	    same_addrs(zone->notify, notify, count) &&
	    same_keynames(zone->notifykeynames, keynames, count))
		goto unlock;

	clear_addresskeylist(&zone->notify, &zone->notifydscp,
			     &zone->notifykeynames, &zone->notifycnt,
			     zone->mctx);

	if (count == 0)
		goto unlock;

	/*
	 * Set up the notify and notifykey lists
	 */
	result = set_addrkeylist(count, notify, &newaddrs, dscps, &newdscps,
				 keynames, &newnames, zone->mctx);
	if (result != ISC_R_SUCCESS)
		goto unlock;

	/*
	 * Everything is ok so attach to the zone.
	 */
	zone->notify = newaddrs;
	zone->notifydscp = newdscps;
	zone->notifykeynames = newnames;
	zone->notifycnt = count;
 unlock:
	UNLOCK_ZONE(zone);
	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

resume_addnsec3chain(dns_zone_t *zone) {
	dns_dbnode_t *node = NULL;
	dns_dbversion_t *version = NULL;
	dns_rdataset_t rdataset;
	isc_result_t result;
	dns_rdata_nsec3param_t nsec3param;
	bool nseconly = false, nsec3ok = false;
	dns_db_t *db = NULL;

	INSIST(LOCKED_ZONE(zone));

	if (zone->privatetype == 0)
		return;

	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 cleanup;
	}

	result = dns_db_findnode(db, &zone->origin, false, &node);
	if (result != ISC_R_SUCCESS) {
		goto cleanup;
	}

	dns_db_currentversion(db, &version);

	/*
	 * In order to create NSEC3 chains we need the DNSKEY RRset at zone
	 * apex to exist and contain no keys using NSEC-only algorithms.
	 */
	result = dns_nsec_nseconly(db, version, &nseconly);
	nsec3ok = (result == ISC_R_SUCCESS && !nseconly);

	/*
	 * Get the RRset containing all private-type records at the zone apex.
	 */
	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(db, node, version,
				     zone->privatetype, dns_rdatatype_none,
				     0, &rdataset, NULL);
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto cleanup;
	}

	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset))
	{
		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
		dns_rdata_t rdata = DNS_RDATA_INIT;
		dns_rdata_t private = DNS_RDATA_INIT;

		dns_rdataset_current(&rdataset, &private);
		/*
		 * Try extracting NSEC3PARAM RDATA from this private-type
		 * record.  Failure means this private-type record does not
		 * represent an NSEC3PARAM record, so skip it.
		 */
		if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
						sizeof(buf)))
		{
			continue;
		}
		result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		if (((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) ||
		    ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 && nsec3ok))
		{
			/*
			 * Pass the NSEC3PARAM RDATA contained in this
			 * private-type record to zone_addnsec3chain() so that
			 * it can kick off adding or removing NSEC3 records.
			 */
			result = zone_addnsec3chain(zone, &nsec3param);
			if (result != ISC_R_SUCCESS) {
				dnssec_log(zone, ISC_LOG_ERROR,
					   "zone_addnsec3chain failed: %s",
					   dns_result_totext(result));
			}
		}
	}
	dns_rdataset_disassociate(&rdataset);

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

Project: bind9
File: zone.c

forward_destroy(dns_forward_t *forward) {

	forward->magic = 0;
	if (forward->request != NULL)
		dns_request_destroy(&forward->request);
	if (forward->msgbuf != NULL)
		isc_buffer_free(&forward->msgbuf);
	if (forward->zone != NULL) {
		LOCK(&forward->zone->lock);
		if (ISC_LINK_LINKED(forward, link))
			ISC_LIST_UNLINK(forward->zone->forwards, forward, link);
		UNLOCK(&forward->zone->lock);
		dns_zone_idetach(&forward->zone);
	}
	isc_mem_putanddetach(&forward->mctx, forward, sizeof(*forward));
}

Project: bind9
File: zone.c

dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, uint32_t iolimit) {

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));
	REQUIRE(iolimit > 0);

	zmgr->iolimit = iolimit;
}

Project: bind9
File: zone.c

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

	bool free_now = false;
	dns_zone_t *raw = NULL;
	dns_zone_t *secure = NULL;
	if (isc_refcount_decrement(&zone->erefs) == 1) {
		isc_refcount_destroy(&zone->erefs);

		LOCK_ZONE(zone);
		INSIST(zone != zone->raw);
		/*
		 * We just detached the last external reference.
		 */
		if (zone->task != NULL) {
			/*
			 * This zone is being managed.	Post
			 * its control event and let it clean
			 * up synchronously in the context of
			 * its task.
			 */
			isc_event_t *ev = &zone->ctlevent;
			isc_task_send(zone->task, &ev);
		} else {
			/*
			 * This zone is not being managed; it has
			 * no task and can have no outstanding
			 * events.  Free it immediately.
			 */
			/*
			 * Unmanaged zones should not have non-null views;
			 * we have no way of detaching from the view here
			 * without causing deadlock because this code is called
			 * with the view already locked.
			 */
			INSIST(zone->view == NULL);
			free_now = true;
			raw = zone->raw;
			zone->raw = NULL;
			secure = zone->secure;
			zone->secure = NULL;
		}
		UNLOCK_ZONE(zone);
	}
	if (free_now) {
		if (raw != NULL) {
			dns_zone_detach(&raw);
		}
		if (secure != NULL) {
			dns_zone_idetach(&secure);
		}
		zone_free(zone);
	}
}

Project: bind9
File: zone.c

dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db) {
	isc_result_t result;
	if (zone->rpz_num == DNS_RPZ_INVALID_NUM)
		return;
	REQUIRE(zone->rpzs != NULL);
	zone->rpzs->zones[zone->rpz_num]->db_registered = true;
	result = dns_db_updatenotify_register(db,
					      dns_rpz_dbupdate_callback,
					      zone->rpzs->zones[zone->rpz_num]);
	REQUIRE(result == ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

sendtomaster(dns_forward_t *forward) {
	isc_result_t result;
	isc_sockaddr_t src;
	isc_dscp_t dscp = -1;

	LOCK_ZONE(forward->zone);

	if (DNS_ZONE_FLAG(forward->zone, DNS_ZONEFLG_EXITING)) {
		UNLOCK_ZONE(forward->zone);
		return (ISC_R_CANCELED);
	}

	if (forward->which >= forward->zone->masterscnt) {
		UNLOCK_ZONE(forward->zone);
		return (ISC_R_NOMORE);
	}

	forward->addr = forward->zone->masters[forward->which];
	/*
	 * Always use TCP regardless of whether the original update
	 * used TCP.
	 * XXX The timeout may but a bit small if we are far down a
	 * transfer graph and the master has to try several masters.
	 */
	switch (isc_sockaddr_pf(&forward->addr)) {
	case PF_INET:
		src = forward->zone->xfrsource4;
		dscp = forward->zone->xfrsource4dscp;
		break;
	case PF_INET6:
		src = forward->zone->xfrsource6;
		dscp = forward->zone->xfrsource6dscp;
		break;
	default:
		result = ISC_R_NOTIMPLEMENTED;
		goto unlock;
	}
	result = dns_request_createraw(forward->zone->view->requestmgr,
				       forward->msgbuf,
				       &src, &forward->addr, dscp,
				       forward->options, 15 /* XXX */,
				       0, 0, forward->zone->task,
				       forward_callback, forward,
				       &forward->request);
	if (result == ISC_R_SUCCESS) {
		if (!ISC_LINK_LINKED(forward, link))
			ISC_LIST_APPEND(forward->zone->forwards, forward, link);
	}

 unlock:
	UNLOCK_ZONE(forward->zone);
	return (result);
}

Project: bind9
File: zone.c

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

	zone->sigvalidityinterval = interval;
}

Project: bind9
File: zone.c

setmodtime(dns_zone_t *zone, isc_time_t *expiretime) {
	isc_result_t result;
	isc_time_t when;
	isc_interval_t i;

	isc_interval_set(&i, zone->expire, 0);
	result = isc_time_subtract(expiretime, &i, &when);
	if (result != ISC_R_SUCCESS)
		return;

	result = ISC_R_FAILURE;
	if (zone->journal != NULL)
		result = isc_file_settime(zone->journal, &when);
	if (result == ISC_R_SUCCESS &&
	    !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
	    !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP))
		result = isc_file_settime(zone->masterfile, &when);
	else if (result != ISC_R_SUCCESS)
		result = isc_file_settime(zone->masterfile, &when);

	/*
	 * Someone removed the file from underneath us!
	 */
	if (result == ISC_R_FILENOTFOUND) {
		zone_needdump(zone, DNS_DUMP_DELAY);
	} else if (result != ISC_R_SUCCESS)
		dns_zone_log(zone, ISC_LOG_ERROR, "refresh: could not set "
			     "file modification time of '%s': %s",
			     zone->masterfile, dns_result_totext(result));
}

Project: bind9
File: zone.c

add_soa(dns_zone_t *zone, dns_db_t *db) {
	isc_result_t result;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	unsigned char buf[DNS_SOA_BUFFERSIZE];
	dns_dbversion_t *ver = NULL;
	dns_diff_t diff;

	dns_zone_log(zone, ISC_LOG_DEBUG(1), "creating SOA");

	dns_diff_init(zone->mctx, &diff);
	result = dns_db_newversion(db, &ver);
	if (result != ISC_R_SUCCESS) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "add_soa:dns_db_newversion -> %s",
			     dns_result_totext(result));
		goto failure;
	}

	/* Build SOA record */
	result = dns_soa_buildrdata(&zone->origin, dns_rootname, zone->rdclass,
				    0, 0, 0, 0, 0, buf, &rdata);
	if (result != ISC_R_SUCCESS) {
		dns_zone_log(zone, ISC_LOG_ERROR,
			     "add_soa:dns_soa_buildrdata -> %s",
			     dns_result_totext(result));
		goto failure;
	}

	result = update_one_rr(db, ver, &diff, DNS_DIFFOP_ADD,
			       &zone->origin, 0, &rdata);

failure:
	dns_diff_clear(&diff);
	if (ver != NULL)
		dns_db_closeversion(db, &ver, (result == ISC_R_SUCCESS));

	INSIST(ver == NULL);

	return (result);
}

Project: bind9
File: zone.c

dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg) {
	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	zone->isself = isself;
	zone->isselfarg = arg;
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

trust_key(dns_zone_t *zone, dns_name_t *keyname,
	  dns_rdata_dnskey_t *dnskey, bool initial,
	  isc_mem_t *mctx)
{
	isc_result_t result;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	unsigned char data[4096];
	isc_buffer_t buffer;
	dns_keytable_t *sr = NULL;
	dst_key_t *dstkey = NULL;

	/* Convert dnskey to DST key. */
	isc_buffer_init(&buffer, data, sizeof(data));
	dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
			     dns_rdatatype_dnskey, dnskey, &buffer);

	result = dns_view_getsecroots(zone->view, &sr);
	if (result != ISC_R_SUCCESS)
		goto failure;

	CHECK(dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &dstkey));
	CHECK(dns_keytable_add(sr, true, initial, &dstkey));
	dns_keytable_detach(&sr);

  failure:
	if (dstkey != NULL)
		dst_key_free(&dstkey);
	if (sr != NULL)
		dns_keytable_detach(&sr);
	return;
}

Project: bind9
File: zone.c

offline(dns_db_t *db, dns_dbversion_t *ver, dns__zonediff_t *zonediff,
	dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
{
	isc_result_t result;

	if ((rdata->flags & DNS_RDATA_OFFLINE) != 0)
		return (ISC_R_SUCCESS);
	result = update_one_rr(db, ver, zonediff->diff, DNS_DIFFOP_DELRESIGN,
			       name, ttl, rdata);
	if (result != ISC_R_SUCCESS)
		return (result);
	rdata->flags |= DNS_RDATA_OFFLINE;
	result = update_one_rr(db, ver, zonediff->diff, DNS_DIFFOP_ADDRESIGN,
			       name, ttl, rdata);
	zonediff->offline = true;
	return (result);
}

Project: bind9
File: zone.c

zone_maintenance(dns_zone_t *zone) {
	const char me[] = "zone_maintenance";
	isc_time_t now;
	isc_result_t result;
	bool dumping, load_pending;

	REQUIRE(DNS_ZONE_VALID(zone));
	ENTER;

	/*
	 * Are we pending load/reload?
	 */
	LOCK_ZONE(zone);
	load_pending = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING);
	UNLOCK_ZONE(zone);

	if (load_pending) {
		return;
	}

	/*
	 * Configuring the view of this zone may have
	 * failed, for example because the config file
	 * had a syntax error.	In that case, the view
	 * adb or resolver will be NULL, and we had better not try
	 * to do further maintenance on it.
	 */
	if (zone->view == NULL || zone->view->adb == NULL)
		return;

	TIME_NOW(&now);

	/*
	 * Expire check.
	 */
	switch (zone->type) {
	case dns_zone_redirect:
		if (zone->masters == NULL)
			break;
		/* FALLTHROUGH */
	case dns_zone_slave:
	case dns_zone_mirror:
	case dns_zone_stub:
		LOCK_ZONE(zone);
		if (isc_time_compare(&now, &zone->expiretime) >= 0 &&
		    DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
			zone_expire(zone);
			zone->refreshtime = now;
		}
		UNLOCK_ZONE(zone);
		break;
	default:
		break;
	}

	/*
	 * Up to date check.
	 */
	switch (zone->type) {
	case dns_zone_redirect:
		if (zone->masters == NULL)
			break;
		/* FALLTHROUGH */
	case dns_zone_slave:
	case dns_zone_mirror:
	case dns_zone_stub:
		if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH) &&
		    isc_time_compare(&now, &zone->refreshtime) >= 0)
			dns_zone_refresh(zone);
		break;
	default:
		break;
	}

	/*
	 * Slaves send notifies before backing up to disk, masters after.
	 */
	if ((zone->type == dns_zone_slave || zone->type == dns_zone_mirror) &&
	    (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
	     DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY)) &&
	    isc_time_compare(&now, &zone->notifytime) >= 0)
		zone_notify(zone, &now);

	/*
	 * Do we need to consolidate the backing store?
	 */
	switch (zone->type) {
	case dns_zone_master:
	case dns_zone_slave:
	case dns_zone_mirror:
	case dns_zone_key:
	case dns_zone_redirect:
	case dns_zone_stub:
		LOCK_ZONE(zone);
		if (zone->masterfile != NULL &&
		    isc_time_compare(&now, &zone->dumptime) >= 0 &&
		    DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
		    DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP)) {
			dumping = was_dumping(zone);
		} else
			dumping = true;
		UNLOCK_ZONE(zone);
		if (!dumping) {
			result = zone_dump(zone, true); /* task locked */
			if (result != ISC_R_SUCCESS)
				dns_zone_log(zone, ISC_LOG_WARNING,
					     "dump failed: %s",
					     dns_result_totext(result));
		}
		break;
	default:
		break;
	}

	/*
	 * Master/redirect zones send notifies now, if needed
	 */
	switch (zone->type) {
	case dns_zone_master:
	case dns_zone_redirect:
		if ((DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
		     DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY))&&
		    isc_time_compare(&now, &zone->notifytime) >= 0)
			zone_notify(zone, &now);
	default:
		break;
	}

	/*
	 * Do we need to refresh keys?
	 */
	switch (zone->type) {
	case dns_zone_key:
		if (isc_time_compare(&now, &zone->refreshkeytime) >= 0) {
			if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
			    !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) {
				zone_refreshkeys(zone);
			}
		}
		break;
	case dns_zone_master:
		if (!isc_time_isepoch(&zone->refreshkeytime) &&
		    isc_time_compare(&now, &zone->refreshkeytime) >= 0 &&
		    zone->rss_event == NULL)
			zone_rekey(zone);
	default:
		break;
	}

	switch (zone->type) {
	case dns_zone_master:
	case dns_zone_redirect:
	case dns_zone_slave:
		/*
		 * Do we need to sign/resign some RRsets?
		 */
		if (zone->rss_event != NULL)
			break;
		if (!isc_time_isepoch(&zone->signingtime) &&
		    isc_time_compare(&now, &zone->signingtime) >= 0)
			zone_sign(zone);
		else if (!isc_time_isepoch(&zone->resigntime) &&
		    isc_time_compare(&now, &zone->resigntime) >= 0)
			zone_resigninc(zone);
		else if (!isc_time_isepoch(&zone->nsec3chaintime) &&
			isc_time_compare(&now, &zone->nsec3chaintime) >= 0)
			zone_nsec3chain(zone);
		/*
		 * Do we need to issue a key expiry warning?
		 */
		if (!isc_time_isepoch(&zone->keywarntime) &&
		    isc_time_compare(&now, &zone->keywarntime) >= 0)
			set_key_expiry_warning(zone, zone->key_expiry,
					       isc_time_seconds(&now));
		break;

	default:
		break;
	}
	zone_settimer(zone, &now);
}

Project: bind9
File: zone.c

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

	return (zone->idlein);
}

Project: bind9
File: zone.c

dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state) {
	dns_zone_t *zone;
	unsigned int count = 0;

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
	switch (state) {
	case DNS_ZONESTATE_XFERRUNNING:
		for (zone = ISC_LIST_HEAD(zmgr->xfrin_in_progress);
		     zone != NULL;
		     zone = ISC_LIST_NEXT(zone, statelink))
			count++;
		break;
	case DNS_ZONESTATE_XFERDEFERRED:
		for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin);
		     zone != NULL;
		     zone = ISC_LIST_NEXT(zone, statelink))
			count++;
		break;
	case DNS_ZONESTATE_SOAQUERY:
		for (zone = ISC_LIST_HEAD(zmgr->zones);
		     zone != NULL;
		     zone = ISC_LIST_NEXT(zone, link))
			if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH))
				count++;
		break;
	case DNS_ZONESTATE_ANY:
		for (zone = ISC_LIST_HEAD(zmgr->zones);
		     zone != NULL;
		     zone = ISC_LIST_NEXT(zone, link)) {
			dns_view_t *view = zone->view;
			if (view != NULL && strcmp(view->name, "_bind") == 0)
				continue;
			count++;
		}
		break;
	case DNS_ZONESTATE_AUTOMATIC:
		for (zone = ISC_LIST_HEAD(zmgr->zones);
		     zone != NULL;
		     zone = ISC_LIST_NEXT(zone, link)) {
			dns_view_t *view = zone->view;
			if (view != NULL && strcmp(view->name, "_bind") == 0)
				continue;
			if (zone->automatic)
				count++;
		}
		break;
	default:
		INSIST(0);
		ISC_UNREACHABLE();
	}

	RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);

	return (count);
}

Project: bind9
File: zone.c

create_query(dns_zone_t *zone, dns_rdatatype_t rdtype,
	     dns_message_t **messagep)
{
	dns_message_t *message = NULL;
	dns_name_t *qname = NULL;
	dns_rdataset_t *qrdataset = NULL;
	isc_result_t result;

	result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER,
				    &message);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	message->opcode = dns_opcode_query;
	message->rdclass = zone->rdclass;

	result = dns_message_gettempname(message, &qname);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	result = dns_message_gettemprdataset(message, &qrdataset);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	/*
	 * Make question.
	 */
	dns_name_init(qname, NULL);
	dns_name_clone(&zone->origin, qname);
	dns_rdataset_makequestion(qrdataset, zone->rdclass, rdtype);
	ISC_LIST_APPEND(qname->list, qrdataset, link);
	dns_message_addname(message, qname, DNS_SECTION_QUESTION);

	*messagep = message;
	return (ISC_R_SUCCESS);

 cleanup:
	if (qname != NULL)
		dns_message_puttempname(message, &qname);
	if (qrdataset != NULL)
		dns_message_puttemprdataset(message, &qrdataset);
	if (message != NULL)
		dns_message_destroy(&message);
	return (result);
}

Project: bind9
File: zone.c

zone_free(dns_zone_t *zone) {
	isc_mem_t *mctx = NULL;
	dns_signing_t *signing;
	dns_nsec3chain_t *nsec3chain;
	isc_event_t *setnsec3param_event;
	dns_include_t *include;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(isc_refcount_current(&zone->erefs) == 0);
	REQUIRE(zone->irefs == 0);
	REQUIRE(!LOCKED_ZONE(zone));
	REQUIRE(zone->timer == NULL);
	REQUIRE(zone->zmgr == NULL);

	/*
	 * Managed objects.  Order is important.
	 */
	if (zone->request != NULL) {
		dns_request_destroy(&zone->request); /* XXXMPA */
	}
	INSIST(zone->readio == NULL);
	INSIST(zone->statelist == NULL);
	INSIST(zone->writeio == NULL);

	if (zone->task != NULL) {
		isc_task_detach(&zone->task);
	}
	if (zone->loadtask != NULL) {
		isc_task_detach(&zone->loadtask);
	}
	if (zone->view != NULL) {
		dns_view_weakdetach(&zone->view);
	}
	if (zone->prev_view != NULL) {
		dns_view_weakdetach(&zone->prev_view);
	}

	/* Unmanaged objects */
	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);
		isc_event_free(&setnsec3param_event);
	}
	for (signing = ISC_LIST_HEAD(zone->signing);
	     signing != NULL;
	     signing = ISC_LIST_HEAD(zone->signing)) {
		ISC_LIST_UNLINK(zone->signing, signing, link);
		dns_db_detach(&signing->db);
		dns_dbiterator_destroy(&signing->dbiterator);
		isc_mem_put(zone->mctx, signing, sizeof *signing);
	}
	for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
	     nsec3chain != NULL;
	     nsec3chain = ISC_LIST_HEAD(zone->nsec3chain)) {
		ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link);
		dns_db_detach(&nsec3chain->db);
		dns_dbiterator_destroy(&nsec3chain->dbiterator);
		isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
	}
	for (include = ISC_LIST_HEAD(zone->includes);
	     include != NULL;
	     include = ISC_LIST_HEAD(zone->includes)) {
		ISC_LIST_UNLINK(zone->includes, include, link);
		isc_mem_free(zone->mctx, include->name);
		isc_mem_put(zone->mctx, include, sizeof *include);
	}
	for (include = ISC_LIST_HEAD(zone->newincludes);
	     include != NULL;
	     include = ISC_LIST_HEAD(zone->newincludes)) {
		ISC_LIST_UNLINK(zone->newincludes, include, link);
		isc_mem_free(zone->mctx, include->name);
		isc_mem_put(zone->mctx, include, sizeof *include);
	}
	if (zone->masterfile != NULL) {
		isc_mem_free(zone->mctx, zone->masterfile);
	}
	zone->masterfile = NULL;
	if (zone->keydirectory != NULL) {
		isc_mem_free(zone->mctx, zone->keydirectory);
	}
	zone->keydirectory = NULL;
	zone->journalsize = -1;
	if (zone->journal != NULL) {
		isc_mem_free(zone->mctx, zone->journal);
	}
	zone->journal = NULL;
	if (zone->stats != NULL) {
		isc_stats_detach(&zone->stats);
	}
	if (zone->requeststats != NULL) {
		isc_stats_detach(&zone->requeststats);
	}
	if (zone->rcvquerystats != NULL){
		dns_stats_detach(&zone->rcvquerystats);
	}
	if (zone->db != NULL) {
		zone_detachdb(zone);
	}
	if (zone->rpzs != NULL) {
		REQUIRE(zone->rpz_num < zone->rpzs->p.num_zones);
		dns_rpz_detach_rpzs(&zone->rpzs);
		zone->rpz_num = DNS_RPZ_INVALID_NUM;
	}
	if (zone->catzs != NULL) {
		dns_catz_catzs_detach(&zone->catzs);
	}
	zone_freedbargs(zone);
	RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL,
						  NULL, 0) == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_zone_setalsonotify(zone, NULL, 0) == ISC_R_SUCCESS);
	zone->check_names = dns_severity_ignore;
	if (zone->update_acl != NULL) {
		dns_acl_detach(&zone->update_acl);
	}
	if (zone->forward_acl != NULL) {
		dns_acl_detach(&zone->forward_acl);
	}
	if (zone->notify_acl != NULL) {
		dns_acl_detach(&zone->notify_acl);
	}
	if (zone->query_acl != NULL) {
		dns_acl_detach(&zone->query_acl);
	}
	if (zone->queryon_acl != NULL) {
		dns_acl_detach(&zone->queryon_acl);
	}
	if (zone->xfr_acl != NULL) {
		dns_acl_detach(&zone->xfr_acl);
	}
	if (dns_name_dynamic(&zone->origin)) {
		dns_name_free(&zone->origin, zone->mctx);
	}
	if (zone->strnamerd != NULL) {
		isc_mem_free(zone->mctx, zone->strnamerd);
	}
	if (zone->strname != NULL) {
		isc_mem_free(zone->mctx, zone->strname);
	}
	if (zone->strrdclass != NULL) {
		isc_mem_free(zone->mctx, zone->strrdclass);
	}
	if (zone->strviewname != NULL) {
		isc_mem_free(zone->mctx, zone->strviewname);
	}
	if (zone->ssutable != NULL) {
		dns_ssutable_detach(&zone->ssutable);
	}
	if (zone->gluecachestats != NULL) {
		isc_stats_detach(&zone->gluecachestats);
	}

	/* last stuff */
	ZONEDB_DESTROYLOCK(&zone->dblock);
	isc_mutex_destroy(&zone->lock);
	zone->magic = 0;
	mctx = zone->mctx;
	isc_mem_put(mctx, zone, sizeof(*zone));
	isc_mem_detach(&mctx);
}

Project: bind9
File: zone.c

queue_xfrin(dns_zone_t *zone) {
	const char me[] = "queue_xfrin";
	isc_result_t result;
	dns_zonemgr_t *zmgr = zone->zmgr;

	ENTER;

	INSIST(zone->statelist == NULL);

	RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	ISC_LIST_APPEND(zmgr->waiting_for_xfrin, zone, statelink);
	LOCK_ZONE(zone);
	zone->irefs++;
	UNLOCK_ZONE(zone);
	zone->statelist = &zmgr->waiting_for_xfrin;
	result = zmgr_start_xfrin_ifquota(zmgr, zone);
	RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);

	if (result == ISC_R_QUOTA) {
		dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO,
			      "zone transfer deferred due to quota");
	} else if (result != ISC_R_SUCCESS) {
		dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_ERROR,
			      "starting zone transfer: %s",
			      isc_result_totext(result));
	}
}

Project: bind9
File: zone.c

dns_zone_getprivatetype(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->privatetype);
}

Project: bind9
File: zone.c

zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
		 unsigned int *soacount,
		 uint32_t *serial, uint32_t *refresh,
		 uint32_t *retry, uint32_t *expire,
		 uint32_t *minimum)
{
	isc_result_t result;
	unsigned int count;
	dns_rdataset_t rdataset;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdata_soa_t soa;

	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa,
				     dns_rdatatype_none, 0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		if (soacount != NULL)
			*soacount = 0;
		if (serial != NULL)
			*serial = 0;
		if (refresh != NULL)
			*refresh = 0;
		if (retry != NULL)
			*retry = 0;
		if (expire != NULL)
			*expire = 0;
		if (minimum != NULL)
			*minimum = 0;
		result = ISC_R_SUCCESS;
		goto invalidate_rdataset;
	}
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto invalidate_rdataset;
	}

	count = 0;
	result = dns_rdataset_first(&rdataset);
	while (result == ISC_R_SUCCESS) {
		dns_rdata_init(&rdata);
		dns_rdataset_current(&rdataset, &rdata);
		count++;
		if (count == 1) {
			result = dns_rdata_tostruct(&rdata, &soa, NULL);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
		}

		result = dns_rdataset_next(&rdataset);
		dns_rdata_reset(&rdata);
	}
	dns_rdataset_disassociate(&rdataset);

	if (soacount != NULL)
		*soacount = count;

	if (count > 0) {
		if (serial != NULL)
			*serial = soa.serial;
		if (refresh != NULL)
			*refresh = soa.refresh;
		if (retry != NULL)
			*retry = soa.retry;
		if (expire != NULL)
			*expire = soa.expire;
		if (minimum != NULL)
			*minimum = soa.minimum;
	} else {
		if (soacount != NULL)
			*soacount = 0;
		if (serial != NULL)
			*serial = 0;
		if (refresh != NULL)
			*refresh = 0;
		if (retry != NULL)
			*retry = 0;
		if (expire != NULL)
			*expire = 0;
		if (minimum != NULL)
			*minimum = 0;
	}

	result = ISC_R_SUCCESS;

 invalidate_rdataset:
	dns_rdataset_invalidate(&rdataset);

	return (result);
}

Project: bind9
File: zone.c

addifmissing(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) {
	dns_db_t *db = ((struct addifmissing_arg *)arg)->db;
	dns_dbversion_t *ver = ((struct addifmissing_arg *)arg)->ver;
	dns_diff_t *diff = ((struct addifmissing_arg *)arg)->diff;
	dns_zone_t *zone = ((struct addifmissing_arg *)arg)->zone;
	bool *changed = ((struct addifmissing_arg *)arg)->changed;
	isc_result_t result;
	dns_keynode_t *dummy = NULL;

	if (((struct addifmissing_arg *)arg)->result != ISC_R_SUCCESS)
		return;

	if (dns_keynode_managed(keynode)) {
		dns_fixedname_t fname;
		dns_name_t *keyname;
		dst_key_t *key;

		key = dns_keynode_key(keynode);
		if (key == NULL)
			return;
		dns_fixedname_init(&fname);

		keyname = dst_key_name(key);
		result = dns_db_find(db, keyname, ver,
				     dns_rdatatype_keydata,
				     DNS_DBFIND_NOWILD, 0, NULL,
				     dns_fixedname_name(&fname),
				     NULL, NULL);
		if (result == ISC_R_SUCCESS)
			return;
		dns_keytable_attachkeynode(keytable, keynode, &dummy);
		result = create_keydata(zone, db, ver, diff, keytable,
					&dummy, changed);
		if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
			((struct addifmissing_arg *)arg)->result = result;
	}
};

Project: bind9
File: zone.c

need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver,
		const dns_rdata_nsec3param_t *param,
		bool *answer)
{
	dns_dbnode_t *node = NULL;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdata_nsec3param_t myparam;
	dns_rdataset_t rdataset;
	isc_result_t result;

	*answer = false;

	result = dns_db_getoriginnode(db, &node);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);

	dns_rdataset_init(&rdataset);

	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
				     0, 0, &rdataset, NULL);
	if (result == ISC_R_SUCCESS) {
		dns_rdataset_disassociate(&rdataset);
		dns_db_detachnode(db, &node);
		return (result);
	}
	if (result != ISC_R_NOTFOUND) {
		dns_db_detachnode(db, &node);
		return (result);
	}

	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
				     0, 0, &rdataset, NULL);
	if (result == ISC_R_NOTFOUND) {
		*answer = true;
		dns_db_detachnode(db, &node);
		return (ISC_R_SUCCESS);
	}
	if (result != ISC_R_SUCCESS) {
		dns_db_detachnode(db, &node);
		return (result);
	}

	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset)) {
		dns_rdataset_current(&rdataset, &rdata);
		CHECK(dns_rdata_tostruct(&rdata, &myparam, NULL));
		dns_rdata_reset(&rdata);
		/*
		 * Ignore any NSEC3PARAM removals.
		 */
		if (NSEC3REMOVE(myparam.flags))
			continue;
		/*
		 * Ignore the chain that we are in the process of deleting.
		 */
		if (myparam.hash == param->hash &&
		    myparam.iterations == param->iterations &&
		    myparam.salt_length == param->salt_length &&
		    !memcmp(myparam.salt, param->salt, myparam.salt_length))
			continue;
		/*
		 * Found an active NSEC3 chain.
		 */
		break;
	}
	if (result == ISC_R_NOMORE) {
		*answer = true;
		result = ISC_R_SUCCESS;
	}

 failure:
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	dns_db_detachnode(db, &node);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_logv(dns_zone_t *zone, isc_logcategory_t *category, int level,
	      const char *prefix, const char *fmt, va_list ap)
{
	char message[4096];
	const char *zstr;

	if (!isc_log_wouldlog(dns_lctx, level)) {
		return;
	}

	vsnprintf(message, sizeof(message), fmt, ap);

	switch (zone->type) {
	case dns_zone_key:
		zstr = "managed-keys-zone";
		break;
	case dns_zone_redirect:
		zstr = "redirect-zone";
		break;
	default:
		zstr = "zone ";
	}

	isc_log_write(dns_lctx, category, DNS_LOGMODULE_ZONE, level,
		      "%s%s%s%s: %s",
		      (prefix != NULL ? prefix : ""),
		      (prefix != NULL ? ": " : ""),
		      zstr, zone->strnamerd, message);
}

Project: bind9
File: zone.c

default_journal(dns_zone_t *zone) {
	isc_result_t result;
	char *journal;

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(LOCKED_ZONE(zone));

	if (zone->masterfile != NULL) {
		/* Calculate string length including '\0'. */
		int len = strlen(zone->masterfile) + sizeof(".jnl");
		journal = isc_mem_allocate(zone->mctx, len);
		if (journal == NULL)
			return (ISC_R_NOMEMORY);
		strlcpy(journal, zone->masterfile, len);
		strlcat(journal, ".jnl", len);
	} else {
		journal = NULL;
	}
	result = dns_zone_setstring(zone, &zone->journal, journal);
	if (journal != NULL)
		isc_mem_free(zone->mctx, journal);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_isdynamic(dns_zone_t *zone, bool ignore_freeze) {
	REQUIRE(DNS_ZONE_VALID(zone));

	if (zone->type == dns_zone_slave || zone->type == dns_zone_mirror ||
	    zone->type == dns_zone_stub || zone->type == dns_zone_key ||
	    (zone->type == dns_zone_redirect && zone->masters != NULL))
		return (true);

	/* Inline zones are always dynamic. */
	if (zone->type == dns_zone_master && zone->raw != NULL)
		return (true);

	/* If !ignore_freeze, we need check whether updates are disabled.  */
	if (zone->type == dns_zone_master &&
	    (!zone->update_disabled || ignore_freeze) &&
	    ((zone->ssutable != NULL) ||
	     (zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl))))
		return (true);

	return (false);

}

Project: bind9
File: zone.c

dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
		   isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
		   dns_zonemgr_t **zmgrp)
{
	dns_zonemgr_t *zmgr;
	isc_result_t result;

	zmgr = isc_mem_get(mctx, sizeof(*zmgr));
	if (zmgr == NULL)
		return (ISC_R_NOMEMORY);
	zmgr->mctx = NULL;
	zmgr->refs = 1;
	isc_mem_attach(mctx, &zmgr->mctx);
	zmgr->taskmgr = taskmgr;
	zmgr->timermgr = timermgr;
	zmgr->socketmgr = socketmgr;
	zmgr->zonetasks = NULL;
	zmgr->loadtasks = NULL;
	zmgr->mctxpool = NULL;
	zmgr->task = NULL;
	zmgr->notifyrl = NULL;
	zmgr->refreshrl = NULL;
	zmgr->startupnotifyrl = NULL;
	zmgr->startuprefreshrl = NULL;
	ISC_LIST_INIT(zmgr->zones);
	ISC_LIST_INIT(zmgr->waiting_for_xfrin);
	ISC_LIST_INIT(zmgr->xfrin_in_progress);
	memset(zmgr->unreachable, 0, sizeof(zmgr->unreachable));
	result = isc_rwlock_init(&zmgr->rwlock, 0, 0);
	if (result != ISC_R_SUCCESS)
		goto free_mem;

	zmgr->transfersin = 10;
	zmgr->transfersperns = 2;

	/* Unreachable lock. */
	result = isc_rwlock_init(&zmgr->urlock, 0, 0);
	if (result != ISC_R_SUCCESS)
		goto free_rwlock;

	/* Create a single task for queueing of SOA queries. */
	result = isc_task_create(taskmgr, 1, &zmgr->task);
	if (result != ISC_R_SUCCESS)
		goto free_urlock;

	isc_task_setname(zmgr->task, "zmgr", zmgr);
	result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
					&zmgr->notifyrl);
	if (result != ISC_R_SUCCESS)
		goto free_task;

	result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
					&zmgr->refreshrl);
	if (result != ISC_R_SUCCESS)
		goto free_notifyrl;

	result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
					&zmgr->startupnotifyrl);
	if (result != ISC_R_SUCCESS)
		goto free_refreshrl;

	result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
					&zmgr->startuprefreshrl);
	if (result != ISC_R_SUCCESS)
		goto free_startupnotifyrl;

	/* default to 20 refresh queries / notifies per second. */
	setrl(zmgr->notifyrl, &zmgr->notifyrate, 20);
	setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, 20);
	setrl(zmgr->refreshrl, &zmgr->serialqueryrate, 20);
	setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, 20);
	isc_ratelimiter_setpushpop(zmgr->startupnotifyrl, true);
	isc_ratelimiter_setpushpop(zmgr->startuprefreshrl, true);

	zmgr->iolimit = 1;
	zmgr->ioactive = 0;
	ISC_LIST_INIT(zmgr->high);
	ISC_LIST_INIT(zmgr->low);

	isc_mutex_init(&zmgr->iolock);

	zmgr->magic = ZONEMGR_MAGIC;

	*zmgrp = zmgr;
	return (ISC_R_SUCCESS);

#if 0
 free_iolock:
	isc_mutex_destroy(&zmgr->iolock);
#endif
 free_startupnotifyrl:
	isc_ratelimiter_detach(&zmgr->startupnotifyrl);
 free_refreshrl:
	isc_ratelimiter_detach(&zmgr->refreshrl);
 free_notifyrl:
	isc_ratelimiter_detach(&zmgr->notifyrl);
 free_task:
	isc_task_detach(&zmgr->task);
 free_urlock:
	isc_rwlock_destroy(&zmgr->urlock);
 free_rwlock:
	isc_rwlock_destroy(&zmgr->rwlock);
 free_mem:
	isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr));
	isc_mem_detach(&mctx);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_setfile(dns_zone_t *zone, const char *file,
		 dns_masterformat_t format,
		 const dns_master_style_t *style)
{
	isc_result_t result = ISC_R_SUCCESS;

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	result = dns_zone_setstring(zone, &zone->masterfile, file);
	if (result == ISC_R_SUCCESS) {
		zone->masterformat = format;
		if (format == dns_masterformat_text)
			zone->masterstyle = style;
		result = default_journal(zone);
	}
	UNLOCK_ZONE(zone);

	return (result);
}

Project: bind9
File: zone.c

dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
	isc_result_t result;
	dns_zone_t *secure = NULL;

	REQUIRE(DNS_ZONE_VALID(zone));
 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;
		}
	}
	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
	result = zone_replacedb(zone, db, dump);
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
	if (secure != NULL)
		UNLOCK_ZONE(secure);
	UNLOCK_ZONE(zone);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats) {

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	if (zone->requeststats_on && stats != NULL) {
		if (zone->rcvquerystats == NULL) {
			dns_stats_attach(stats, &zone->rcvquerystats);
			zone->requeststats_on = true;
		}
	}
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

maybe_send_secure(dns_zone_t *zone) {
	isc_result_t result;

	/*
	 * We've finished loading, or else failed to load, an inline-signing
	 * 'secure' zone.  We now need information about the status of the
	 * 'raw' zone.  If we failed to load, then we need it to send a
	 * copy of its database; if we succeeded, we need it to send its
	 * serial number so that we can sync with it.  If it has not yet
	 * loaded, we set a flag so that it will send the necessary
	 * information when it has finished loading.
	 */
	if (zone->raw->db != NULL) {
		if (zone->db != NULL) {
			uint32_t serial;
			unsigned int soacount;

			result = zone_get_from_db(zone->raw, zone->raw->db,
						  NULL, &soacount, &serial,
						  NULL, NULL, NULL, NULL, NULL);
			if (result == ISC_R_SUCCESS && soacount > 0U)
				zone_send_secureserial(zone->raw, serial);
		} else
			zone_send_securedb(zone->raw, zone->raw->db);

	} else
		DNS_ZONE_SETFLAG(zone->raw, DNS_ZONEFLG_SENDSECURE);
}

Project: bind9
File: zone.c

zone_dump(dns_zone_t *zone, bool compact) {
	const char me[] = "zone_dump";
	isc_result_t result;
	dns_dbversion_t *version = NULL;
	bool again;
	dns_db_t *db = NULL;
	char *masterfile = NULL;
	dns_masterformat_t masterformat = dns_masterformat_none;

/*
 * 'compact' MUST only be set if we are task locked.
 */

	REQUIRE(DNS_ZONE_VALID(zone));
	ENTER;

 redo:
	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	if (zone->db != NULL)
		dns_db_attach(zone->db, &db);
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
	LOCK_ZONE(zone);
	if (zone->masterfile != NULL) {
		masterfile = isc_mem_strdup(zone->mctx, zone->masterfile);
		masterformat = zone->masterformat;
	}
	UNLOCK_ZONE(zone);
	if (db == NULL) {
		result = DNS_R_NOTLOADED;
		goto fail;
	}
	if (masterfile == NULL) {
		result = DNS_R_NOMASTERFILE;
		goto fail;
	}

	if (compact && zone->type != dns_zone_stub) {
		dns_zone_t *dummy = NULL;
		LOCK_ZONE(zone);
		zone_iattach(zone, &dummy);
		result = zonemgr_getio(zone->zmgr, false, zone->task,
				       zone_gotwritehandle, zone,
				       &zone->writeio);
		if (result != ISC_R_SUCCESS)
			zone_idetach(&dummy);
		else
			result = DNS_R_CONTINUE;
		UNLOCK_ZONE(zone);
	} else {
		const dns_master_style_t *output_style;

		dns_masterrawheader_t rawdata;
		dns_db_currentversion(db, &version);
		dns_master_initrawheader(&rawdata);
		if (inline_secure(zone))
			get_raw_serial(zone->raw, &rawdata);
		if (zone->type == dns_zone_key)
			output_style = &dns_master_style_keyzone;
		else
			output_style = &dns_master_style_default;
		result = dns_master_dump(zone->mctx, db, version,
					 output_style, masterfile,
					 masterformat, &rawdata);
		dns_db_closeversion(db, &version, false);
	}
 fail:
	if (db != NULL)
		dns_db_detach(&db);
	if (masterfile != NULL)
		isc_mem_free(zone->mctx, masterfile);
	masterfile = NULL;

	if (result == DNS_R_CONTINUE)
		return (ISC_R_SUCCESS); /* XXXMPA */

	again = false;
	LOCK_ZONE(zone);
	DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DUMPING);
	if (result != ISC_R_SUCCESS) {
		/*
		 * Try again in a short while.
		 */
		zone_needdump(zone, DNS_DUMP_DELAY);
	} else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) &&
		   DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
		   DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
		DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
		isc_time_settoepoch(&zone->dumptime);
		again = true;
	} else
		DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FLUSH);
	UNLOCK_ZONE(zone);
	if (again)
		goto redo;

	return (result);
}

Project: bind9
File: zone.c

dns_zone_getxfrsource6dscp(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->xfrsource6dscp);
}

Project: bind9
File: zone.c

add_nsec(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
	 dns_dbnode_t *node, dns_ttl_t ttl, bool bottom,
	 dns_diff_t *diff)
{
	dns_fixedname_t fixed;
	dns_name_t *next;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_result_t result;
	unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE];

	next = dns_fixedname_initname(&fixed);

	CHECK(next_active(db, version, name, next, bottom));
	CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer,
				  &rdata));
	CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, ttl,
			    &rdata));
 failure:
	return (result);
}

Project: bind9
File: zone.c

dns_zone_next(dns_zone_t *zone, dns_zone_t **next) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(next != NULL && *next == NULL);

	*next = ISC_LIST_NEXT(zone, link);
	if (*next == NULL)
		return (ISC_R_NOMORE);
	else
		return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zone_setaltxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp) {
	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	zone->altxfrsource4dscp = dscp;
	UNLOCK_ZONE(zone);

	return (ISC_R_SUCCESS);
}

Project: bind9
File: zone.c

dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) {
	isc_result_t result;
	isc_mem_t *mctx = NULL;
	dns_zone_t *zone = NULL;
	void *item;

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));
	REQUIRE(zonep != NULL && *zonep == NULL);

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

	item = isc_pool_get(zmgr->mctxpool);
	if (item == NULL)
		return (ISC_R_FAILURE);

	isc_mem_attach((isc_mem_t *) item, &mctx);
	result = dns_zone_create(&zone, mctx);
	isc_mem_detach(&mctx);

	if (result == ISC_R_SUCCESS)
		*zonep = zone;

	return (result);
}

Project: bind9
File: zone.c

queue_soa_query(dns_zone_t *zone) {
	const char me[] = "queue_soa_query";
	isc_event_t *e;
	dns_zone_t *dummy = NULL;
	isc_result_t result;

	ENTER;
	/*
	 * Locked by caller
	 */
	REQUIRE(LOCKED_ZONE(zone));

	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
		cancel_refresh(zone);
		return;
	}

	e = isc_event_allocate(zone->mctx, NULL, DNS_EVENT_ZONE,
			       soa_query, zone, sizeof(isc_event_t));
	if (e == NULL) {
		cancel_refresh(zone);
		return;
	}

	/*
	 * Attach so that we won't clean up
	 * until the event is delivered.
	 */
	zone_iattach(zone, &dummy);

	e->ev_arg = zone;
	e->ev_sender = NULL;
	result = isc_ratelimiter_enqueue(zone->zmgr->refreshrl, zone->task, &e);
	if (result != ISC_R_SUCCESS) {
		zone_idetach(&dummy);
		isc_event_free(&e);
		cancel_refresh(zone);
	}
}

Project: bind9
File: zone.c

set_refreshkeytimer(dns_zone_t *zone, dns_rdata_keydata_t *key,
		    isc_stdtime_t now, bool force)
{
	const char me[] = "set_refreshkeytimer";
	isc_stdtime_t then;
	isc_time_t timenow, timethen;
	char timebuf[80];

	ENTER;
	then = key->refresh;
	if (force)
		then = now;
	if (key->addhd > now && key->addhd < then)
		then = key->addhd;
	if (key->removehd > now && key->removehd < then)
		then = key->removehd;

	TIME_NOW(&timenow);
	if (then > now)
		DNS_ZONE_TIME_ADD(&timenow, then - now, &timethen);
	else
		timethen = timenow;
	if (isc_time_compare(&zone->refreshkeytime, &timenow) < 0 ||
	    isc_time_compare(&timethen, &zone->refreshkeytime) < 0)
		zone->refreshkeytime = timethen;

	isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
	dns_zone_log(zone, ISC_LOG_DEBUG(1), "next key refresh: %s", timebuf);
	zone_settimer(zone, &timenow);
}

Project: bind9
File: zone.c

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

	return (zone->sigvalidityinterval);
}

Project: bind9
File: zone.c

notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) {
	dns_tsigkey_t *key = NULL;
	isc_sockaddr_t src;
	isc_sockaddr_t any;
	bool isself;
	isc_netaddr_t dstaddr;
	isc_result_t result;

	if (zone->view == NULL || zone->isself == NULL)
		return (false);

	switch (isc_sockaddr_pf(dst)) {
	case PF_INET:
		src = zone->notifysrc4;
		isc_sockaddr_any(&any);
		break;
	case PF_INET6:
		src = zone->notifysrc6;
		isc_sockaddr_any6(&any);
		break;
	default:
		return (false);
	}

	/*
	 * When sending from any the kernel will assign a source address
	 * that matches the destination address.
	 */
	if (isc_sockaddr_eqaddr(&any, &src))
		src = *dst;

	isc_netaddr_fromsockaddr(&dstaddr, dst);
	result = dns_view_getpeertsig(zone->view, &dstaddr, &key);
	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
		return (false);
	isself = (zone->isself)(zone->view, key, &src, dst, zone->rdclass,
				zone->isselfarg);
	if (key != NULL)
		dns_tsigkey_detach(&key);
	return (isself);
}

Project: bind9
File: zone.c

notify_createmessage(dns_zone_t *zone, unsigned int flags,
		     dns_message_t **messagep)
{
	dns_db_t *zonedb = NULL;
	dns_dbnode_t *node = NULL;
	dns_dbversion_t *version = NULL;
	dns_message_t *message = NULL;
	dns_rdataset_t rdataset;
	dns_rdata_t rdata = DNS_RDATA_INIT;

	dns_name_t *tempname = NULL;
	dns_rdata_t *temprdata = NULL;
	dns_rdatalist_t *temprdatalist = NULL;
	dns_rdataset_t *temprdataset = NULL;

	isc_result_t result;
	isc_region_t r;
	isc_buffer_t *b = NULL;

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

	result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER,
				    &message);
	if (result != ISC_R_SUCCESS)
		return (result);

	message->opcode = dns_opcode_notify;
	message->flags |= DNS_MESSAGEFLAG_AA;
	message->rdclass = zone->rdclass;

	result = dns_message_gettempname(message, &tempname);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	result = dns_message_gettemprdataset(message, &temprdataset);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	/*
	 * Make question.
	 */
	dns_name_init(tempname, NULL);
	dns_name_clone(&zone->origin, tempname);
	dns_rdataset_makequestion(temprdataset, zone->rdclass,
				  dns_rdatatype_soa);
	ISC_LIST_APPEND(tempname->list, temprdataset, link);
	dns_message_addname(message, tempname, DNS_SECTION_QUESTION);
	tempname = NULL;
	temprdataset = NULL;

	if ((flags & DNS_NOTIFY_NOSOA) != 0)
		goto done;

	result = dns_message_gettempname(message, &tempname);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;
	result = dns_message_gettemprdata(message, &temprdata);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;
	result = dns_message_gettemprdataset(message, &temprdataset);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;
	result = dns_message_gettemprdatalist(message, &temprdatalist);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;

	ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
	INSIST(zone->db != NULL); /* XXXJT: is this assumption correct? */
	dns_db_attach(zone->db, &zonedb);
	ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);

	dns_name_init(tempname, NULL);
	dns_name_clone(&zone->origin, tempname);
	dns_db_currentversion(zonedb, &version);
	result = dns_db_findnode(zonedb, tempname, false, &node);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;

	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(zonedb, node, version,
				     dns_rdatatype_soa,
				     dns_rdatatype_none, 0, &rdataset,
				     NULL);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;
	result = dns_rdataset_first(&rdataset);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;
	dns_rdataset_current(&rdataset, &rdata);
	dns_rdata_toregion(&rdata, &r);
	result = isc_buffer_allocate(zone->mctx, &b, r.length);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;
	isc_buffer_putmem(b, r.base, r.length);
	isc_buffer_usedregion(b, &r);
	dns_rdata_init(temprdata);
	dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r);
	dns_message_takebuffer(message, &b);
	result = dns_rdataset_next(&rdataset);
	dns_rdataset_disassociate(&rdataset);
	if (result != ISC_R_NOMORE)
		goto soa_cleanup;
	temprdatalist->rdclass = rdata.rdclass;
	temprdatalist->type = rdata.type;
	temprdatalist->ttl = rdataset.ttl;
	ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link);

	result = dns_rdatalist_tordataset(temprdatalist, temprdataset);
	if (result != ISC_R_SUCCESS)
		goto soa_cleanup;

	ISC_LIST_APPEND(tempname->list, temprdataset, link);
	dns_message_addname(message, tempname, DNS_SECTION_ANSWER);
	temprdatalist = NULL;
	temprdataset = NULL;
	temprdata = NULL;
	tempname = NULL;

 soa_cleanup:
	if (node != NULL)
		dns_db_detachnode(zonedb, &node);
	if (version != NULL)
		dns_db_closeversion(zonedb, &version, false);
	if (zonedb != NULL)
		dns_db_detach(&zonedb);
	if (tempname != NULL)
		dns_message_puttempname(message, &tempname);
	if (temprdata != NULL)
		dns_message_puttemprdata(message, &temprdata);
	if (temprdataset != NULL)
		dns_message_puttemprdataset(message, &temprdataset);
	if (temprdatalist != NULL)
		dns_message_puttemprdatalist(message, &temprdatalist);

 done:
	*messagep = message;
	return (ISC_R_SUCCESS);

 cleanup:
	if (tempname != NULL)
		dns_message_puttempname(message, &tempname);
	if (temprdataset != NULL)
		dns_message_puttemprdataset(message, &temprdataset);
	dns_message_destroy(&message);
	return (result);
}

Project: bind9
File: zone.c

dns_zone_get_parentcatz(const dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->parentcatz);
}

Project: bind9
File: zone.c

zone_touched(dns_zone_t *zone) {
	isc_result_t result;
	isc_time_t modtime;
	dns_include_t *include;

	REQUIRE(DNS_ZONE_VALID(zone));

	result = isc_file_getmodtime(zone->masterfile, &modtime);
	if (result != ISC_R_SUCCESS ||
	    isc_time_compare(&modtime, &zone->loadtime) > 0)
		return (true);

	for (include = ISC_LIST_HEAD(zone->includes);
	     include != NULL;
	     include = ISC_LIST_NEXT(include, link))
	{
		result = isc_file_getmodtime(include->name, &modtime);
		if (result != ISC_R_SUCCESS ||
		    isc_time_compare(&modtime, &include->filetime) > 0)
			return (true);
	}

	return (false);
}

Project: bind9
File: zone.c

dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters,
		    uint32_t count)
{
	isc_result_t result;

	result = dns_zone_setmasterswithkeys(zone, masters, NULL, count);
	return (result);
}

Project: bind9
File: zone.c

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

	return (zone->sigresigninginterval);
}

Project: bind9
File: zone.c

isspf(const dns_rdata_t *rdata) {
	char buf[1024];
	const unsigned char *data = rdata->data;
	unsigned int rdl = rdata->length, i = 0, tl, len;

	while (rdl > 0U) {
		len = tl = *data;
		++data;
		--rdl;
		INSIST(tl <= rdl);
		if (len > sizeof(buf) - i - 1)
			len = sizeof(buf) - i - 1;
		memmove(buf + i, data, len);
		i += len;
		data += tl;
		rdl -= tl;
	}

	if (i < 6U)
		return(false);

	buf[i] = 0;
	if (strncmp(buf, "v=spf1", 6) == 0 && (buf[6] == 0 || buf[6] == ' '))
		return (true);
	return (false);
}

Project: bind9
File: zone.c

zone_rrset_check_dup(dns_zone_t *zone, dns_name_t *owner,
		     dns_rdataset_t *rdataset)
{
	dns_rdataset_t tmprdataset;
	isc_result_t result;
	bool answer = true;
	bool format = true;
	int level = ISC_LOG_WARNING;
	char ownerbuf[DNS_NAME_FORMATSIZE];
	char typebuf[DNS_RDATATYPE_FORMATSIZE];
	unsigned int count1 = 0;

	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRRFAIL))
		level = ISC_LOG_ERROR;

	dns_rdataset_init(&tmprdataset);
	for (result = dns_rdataset_first(rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(rdataset)) {
		dns_rdata_t rdata1 = DNS_RDATA_INIT;
		unsigned int count2 = 0;

		count1++;
		dns_rdataset_current(rdataset, &rdata1);
		dns_rdataset_clone(rdataset, &tmprdataset);
		for (result = dns_rdataset_first(&tmprdataset);
		     result == ISC_R_SUCCESS;
		     result = dns_rdataset_next(&tmprdataset)) {
			dns_rdata_t rdata2 = DNS_RDATA_INIT;
			count2++;
			if (count1 >= count2)
				continue;
			dns_rdataset_current(&tmprdataset, &rdata2);
			if (dns_rdata_casecompare(&rdata1, &rdata2) == 0) {
				if (format) {
					dns_name_format(owner, ownerbuf,
							sizeof ownerbuf);
					dns_rdatatype_format(rdata1.type,
							     typebuf,
							     sizeof(typebuf));
					format = false;
				}
				dns_zone_log(zone, level, "%s/%s has "
					     "semantically identical records",
					     ownerbuf, typebuf);
				if (level == ISC_LOG_ERROR)
					answer = false;
				break;
			}
		}
		dns_rdataset_disassociate(&tmprdataset);
		if (!format)
			break;
	}
	return (answer);
}

Project: bind9
File: zone.c

resume_signingwithkey(dns_zone_t *zone) {
	dns_dbnode_t *node = NULL;
	dns_dbversion_t *version = NULL;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdataset_t rdataset;
	isc_result_t result;
	dns_db_t *db = NULL;

	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 cleanup;
	}

	result = dns_db_findnode(db, &zone->origin, false, &node);
	if (result != ISC_R_SUCCESS) {
		goto cleanup;
	}

	dns_db_currentversion(db, &version);
	dns_rdataset_init(&rdataset);
	result = dns_db_findrdataset(db, node, version,
				     zone->privatetype,
				     dns_rdatatype_none, 0,
				     &rdataset, NULL);
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto cleanup;
	}

	for (result = dns_rdataset_first(&rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(&rdataset))
	{
		dns_rdataset_current(&rdataset, &rdata);
		if (rdata.length != 5 ||
		    rdata.data[0] == 0 || rdata.data[4] != 0)
		{
			dns_rdata_reset(&rdata);
			continue;
		}

		result = zone_signwithkey(zone, rdata.data[0],
					  (rdata.data[1] << 8) | rdata.data[2],
					  rdata.data[3]);
		if (result != ISC_R_SUCCESS) {
			dnssec_log(zone, ISC_LOG_ERROR,
				   "zone_signwithkey failed: %s",
				   dns_result_totext(result));
		}
		dns_rdata_reset(&rdata);
	}
	dns_rdataset_disassociate(&rdataset);

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

Project: bind9
File: zone.c

dns_zone_getrequestixfr(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->requestixfr);
}

Project: bind9
File: zone.c

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

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(zone->zmgr != NULL);
	REQUIRE(zone->task != NULL);
	REQUIRE(zone->loadtask != NULL);
	REQUIRE(zone->raw == NULL);

	REQUIRE(DNS_ZONE_VALID(raw));
	REQUIRE(raw->zmgr == NULL);
	REQUIRE(raw->task == NULL);
	REQUIRE(raw->loadtask == NULL);
	REQUIRE(raw->secure == NULL);

	REQUIRE(zone != raw);

	/*
	 * Lock hierarchy: zmgr, zone, raw.
	 */
	zmgr = zone->zmgr;
	RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
	LOCK_ZONE(zone);
	LOCK_ZONE(raw);

	result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive,
				  NULL, NULL, zone->task, zone_timer, raw,
				  &raw->timer);
	if (result != ISC_R_SUCCESS)
		goto unlock;

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


	/* dns_zone_attach(raw, &zone->raw); */
	isc_refcount_increment(&raw->erefs);
	zone->raw = raw;

	/* dns_zone_iattach(zone,  &raw->secure); */
	zone_iattach(zone, &raw->secure);

	isc_task_attach(zone->task, &raw->task);
	isc_task_attach(zone->loadtask, &raw->loadtask);

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

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

Project: bind9
File: zone.c

same_addrs(isc_sockaddr_t const *oldlist, isc_sockaddr_t const *newlist,
	   uint32_t count)
{
	unsigned int i;

	for (i = 0; i < count; i++)
		if (!isc_sockaddr_equal(&oldlist[i], &newlist[i]))
			return (false);
	return (true);
}

Project: bind9
File: zone.c

process_adb_event(isc_task_t *task, isc_event_t *ev) {
	dns_notify_t *notify;
	isc_eventtype_t result;

	UNUSED(task);

	notify = ev->ev_arg;
	REQUIRE(DNS_NOTIFY_VALID(notify));
	INSIST(task == notify->zone->task);
	result = ev->ev_type;
	isc_event_free(&ev);
	if (result == DNS_EVENT_ADBMOREADDRESSES) {
		dns_adb_destroyfind(&notify->find);
		notify_find_address(notify);
		return;
	}
	if (result == DNS_EVENT_ADBNOMOREADDRESSES) {
		LOCK_ZONE(notify->zone);
		notify_send(notify);
		UNLOCK_ZONE(notify->zone);
	}
	notify_destroy(notify, false);
}

Project: bind9
File: zone.c

dns_zone_dumptostream(dns_zone_t *zone, FILE *fd, dns_masterformat_t format,
		      const dns_master_style_t *style,
		      const uint32_t rawversion)
{
	return (dumptostream(zone, fd, style, format, rawversion));
}

Project: bind9
File: zone.c

add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
	 dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys,
	 unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception,
	 isc_stdtime_t expire, bool check_ksk,
	 bool keyset_kskonly)
{
	isc_result_t result;
	dns_dbnode_t *node = NULL;
	dns_rdataset_t rdataset;
	dns_rdata_t sig_rdata = DNS_RDATA_INIT;
	unsigned char data[1024]; /* XXX */
	isc_buffer_t buffer;
	unsigned int i, j;

	dns_rdataset_init(&rdataset);
	isc_buffer_init(&buffer, data, sizeof(data));

	if (type == dns_rdatatype_nsec3)
		result = dns_db_findnsec3node(db, name, false, &node);
	else
		result = dns_db_findnode(db, name, false, &node);
	if (result == ISC_R_NOTFOUND)
		return (ISC_R_SUCCESS);
	if (result != ISC_R_SUCCESS)
		goto failure;
	result = dns_db_findrdataset(db, node, ver, type, 0,
				     (isc_stdtime_t) 0, &rdataset, NULL);
	dns_db_detachnode(db, &node);
	if (result == ISC_R_NOTFOUND) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		return (ISC_R_SUCCESS);
	}
	if (result != ISC_R_SUCCESS) {
		INSIST(!dns_rdataset_isassociated(&rdataset));
		goto failure;
	}

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

		if (!dst_key_isprivate(keys[i]))
			continue;
		if (dst_key_inactive(keys[i]))	/* Should be redundant. */
			continue;

		if (check_ksk && !REVOKE(keys[i])) {
			bool have_ksk, have_nonksk;
			if (KSK(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(keys[i]) != ALG(keys[j]))
					continue;
				if (!dst_key_isprivate(keys[j]))
					continue;
				if (dst_key_inactive(keys[j]))	/* SBR */
					continue;
				if (REVOKE(keys[j]))
					continue;
				if (KSK(keys[j]))
					have_ksk = true;
				else
					have_nonksk = true;
				both = have_ksk && have_nonksk;
				if (both)
					break;
			}
		}
		if (both) {
			/*
			 * CDS and CDNSKEY are signed with KSK (RFC 7344, 4.1).
			 */
			if (type == dns_rdatatype_dnskey ||
			    type == dns_rdatatype_cdnskey ||
			    type == dns_rdatatype_cds)
			{
				if (!KSK(keys[i]) && keyset_kskonly)
					continue;
			} else if (KSK(keys[i])) {
				continue;
			}
		} else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey) {
			continue;
		}

		/* Calculate the signature, creating a RRSIG RDATA. */
		isc_buffer_clear(&buffer);
		CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
				      &inception, &expire,
				      mctx, &buffer, &sig_rdata));
		/* Update the database and journal with the RRSIG. */
		/* XXX inefficient - will cause dataset merging */
		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN,
				    name, rdataset.ttl, &sig_rdata));
		dns_rdata_reset(&sig_rdata);
		isc_buffer_init(&buffer, data, sizeof(data));
	}

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

Project: bind9
File: zone.c

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

	return (zone->statlevel);
}

Project: bind9
File: zone.c

dns_zone_setmaxxfrin(dns_zone_t *zone, uint32_t maxxfrin) {
	REQUIRE(DNS_ZONE_VALID(zone));

	zone->maxxfrin = maxxfrin;
}

Project: bind9
File: zone.c

dns_zone_isloaded(const dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));

	return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED));
}

Project: bind9
File: zone.c

dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) {

	REQUIRE(DNS_ZONE_VALID(zone));

	LOCK_ZONE(zone);
	if (zone->requeststats_on && stats == NULL)
		zone->requeststats_on = false;
	else if (!zone->requeststats_on && stats != NULL) {
		if (zone->requeststats == NULL) {
			isc_stats_attach(stats, &zone->requeststats);
			zone->requeststats_on = true;
		}
	}
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_getnotifysrc4dscp(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (zone->notifysrc4dscp);
}

Project: bind9
File: zone.c

next_keyevent(dst_key_t *key, isc_stdtime_t *timep) {
	isc_result_t result;
	isc_stdtime_t now, then = 0, event;
	int i;

	now = *timep;

	for (i = 0; i <= DST_MAX_TIMES; i++) {
		result = dst_key_gettime(key, i, &event);
		if (result == ISC_R_SUCCESS && event > now &&
		    (then == 0 || event < then))
			then = event;
	}

	if (then != 0) {
		*timep = then;
		return (ISC_R_SUCCESS);
	}

	return (ISC_R_NOTFOUND);
}

Project: bind9
File: zone.c

zone_load(dns_zone_t *zone, unsigned int flags, bool locked) {
	isc_result_t result;
	isc_time_t now;
	isc_time_t loadtime;
	dns_db_t *db = NULL;
	bool rbt, hasraw;

	REQUIRE(DNS_ZONE_VALID(zone));

	if (!locked)
		LOCK_ZONE(zone);

	INSIST(zone != zone->raw);
	hasraw = inline_secure(zone);
	if (hasraw) {
		/*
		 * We are trying to load an inline-signed zone.  First call
		 * self recursively to try loading the raw version of the zone.
		 * Assuming the raw zone file is readable, there are two
		 * possibilities:
		 *
		 *  a) the raw zone was not yet loaded and thus it will be
		 *     loaded now, synchronously; if this succeeds, a
		 *     subsequent attempt to load the signed zone file will
		 *     take place and thus zone_postload() will be called
		 *     twice: first for the raw zone and then for the secure
		 *     zone; the latter call will take care of syncing the raw
		 *     version with the secure version,
		 *
		 *  b) the raw zone was already loaded and we are trying to
		 *     reload it, which will happen asynchronously; this means
		 *     zone_postload() will only be called for the raw zone
		 *     because "result" returned by the zone_load() call below
		 *     will not be ISC_R_SUCCESS but rather DNS_R_CONTINUE;
		 *     zone_postload() called for the raw zone will take care
		 *     of syncing the raw version with the secure version.
		 */
		result = zone_load(zone->raw, flags, false);
		if (result != ISC_R_SUCCESS) {
			if (!locked)
				UNLOCK_ZONE(zone);
			return(result);
		}
		LOCK_ZONE(zone->raw);
	}

	TIME_NOW(&now);

	INSIST(zone->type != dns_zone_none);

	if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) {
		if ((flags & DNS_ZONELOADFLAG_THAW) != 0)
			DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW);
		result = DNS_R_CONTINUE;
		goto cleanup;
	}

	INSIST(zone->db_argc >= 1);

	rbt = strcmp(zone->db_argv[0], "rbt") == 0 ||
	      strcmp(zone->db_argv[0], "rbt64") == 0;

	if (zone->db != NULL && zone->masterfile == NULL && rbt) {
		/*
		 * The zone has no master file configured.
		 */
		result = ISC_R_SUCCESS;
		goto cleanup;
	}

	if (zone->db != NULL && dns_zone_isdynamic(zone, false)) {
		/*
		 * This is a slave, stub, or dynamically updated
		 * zone being reloaded.  Do nothing - the database
		 * we already have is guaranteed to be up-to-date.
		 */
		if (zone->type == dns_zone_master && !hasraw)
			result = DNS_R_DYNAMIC;
		else
			result = ISC_R_SUCCESS;
		goto cleanup;
	}

	/*
	 * Store the current time before the zone is loaded, so that if the
	 * file changes between the time of the load and the time that
	 * zone->loadtime is set, then the file will still be reloaded
	 * the next time dns_zone_load is called.
	 */
	TIME_NOW(&loadtime);

	/*
	 * Don't do the load if the file that stores the zone is older
	 * than the last time the zone was loaded.  If the zone has not
	 * been loaded yet, zone->loadtime will be the epoch.
	 */
	if (zone->masterfile != NULL) {
		isc_time_t filetime;

		/*
		 * The file is already loaded.	If we are just doing a
		 * "rndc reconfig", we are done.
		 */
		if (!isc_time_isepoch(&zone->loadtime) &&
		    (flags & DNS_ZONELOADFLAG_NOSTAT) != 0) {
			result = ISC_R_SUCCESS;
			goto cleanup;
		}

		if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
		    !zone_touched(zone))
		{
			dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
				      ISC_LOG_DEBUG(1),
				      "skipping load: master file "
				      "older than last load");
			result = DNS_R_UPTODATE;
			goto cleanup;
		}

		/*
		 * If the file modification time is in the past
		 * set loadtime to that value.
		 */
		result = isc_file_getmodtime(zone->masterfile, &filetime);
		if (result == ISC_R_SUCCESS &&
		    isc_time_compare(&loadtime, &filetime) > 0)
			loadtime = filetime;
	}

	/*
	 * Built in zones (with the exception of empty zones) don't need
	 * to be reloaded.
	 */
	if (zone->type == dns_zone_master &&
	    strcmp(zone->db_argv[0], "_builtin") == 0 &&
	    (zone->db_argc < 2 || strcmp(zone->db_argv[1], "empty") != 0) &&
	    DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
		result = ISC_R_SUCCESS;
		goto cleanup;
	}

	/*
	 * Zones associated with a DLZ don't need to be loaded either,
	 * but we need to associate the database with the zone object.
	 */
	if (strcmp(zone->db_argv[0], "dlz") == 0) {
		dns_dlzdb_t *dlzdb;
		dns_dlzfindzone_t findzone;

		for (dlzdb = ISC_LIST_HEAD(zone->view->dlz_unsearched);
		     dlzdb != NULL;
		     dlzdb = ISC_LIST_NEXT(dlzdb, link))
		{
			INSIST(DNS_DLZ_VALID(dlzdb));
			if (strcmp(zone->db_argv[1], dlzdb->dlzname) == 0)
				break;
		}

		if (dlzdb == NULL) {
			dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
				      ISC_LOG_ERROR,
				      "DLZ %s does not exist or is set "
				      "to 'search yes;'", zone->db_argv[1]);
			result = ISC_R_NOTFOUND;
			goto cleanup;
		}

		ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
		/* ask SDLZ driver if the zone is supported */
		findzone = dlzdb->implementation->methods->findzone;
		result = (*findzone)(dlzdb->implementation->driverarg,
				     dlzdb->dbdata, dlzdb->mctx,
				     zone->view->rdclass, &zone->origin,
				     NULL, NULL, &db);
		if (result != ISC_R_NOTFOUND) {
			if (zone->db != NULL)
				zone_detachdb(zone);
			zone_attachdb(zone, db);
			dns_db_detach(&db);
			result = ISC_R_SUCCESS;
		}
		ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);

		if (result == ISC_R_SUCCESS) {
			if (dlzdb->configure_callback == NULL)
				goto cleanup;

			result = (*dlzdb->configure_callback)(zone->view,
							      dlzdb, zone);
			if (result != ISC_R_SUCCESS)
				dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
					      ISC_LOG_ERROR,
					      "DLZ configuration callback: %s",
					      isc_result_totext(result));
		}
		goto cleanup;
	}

	if ((zone->type == dns_zone_slave || zone->type == dns_zone_mirror ||
	     zone->type == dns_zone_stub ||
	     (zone->type == dns_zone_redirect && zone->masters != NULL)) &&
	    rbt) {
		if (zone->masterfile == NULL ||
		    !isc_file_exists(zone->masterfile)) {
			if (zone->masterfile != NULL) {
				dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
					      ISC_LOG_DEBUG(1),
					     "no master file");
			}
			zone->refreshtime = now;
			if (zone->task != NULL)
				zone_settimer(zone, &now);
			result = ISC_R_SUCCESS;
			goto cleanup;
		}
	}

	dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
		      ISC_LOG_DEBUG(1), "starting load");

	result = dns_db_create(zone->mctx, zone->db_argv[0],
			       &zone->origin, (zone->type == dns_zone_stub) ?
			       dns_dbtype_stub : dns_dbtype_zone,
			       zone->rdclass,
			       zone->db_argc - 1, zone->db_argv + 1,
			       &db);

	if (result != ISC_R_SUCCESS) {
		dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_ERROR,
			     "loading zone: creating database: %s",
			     isc_result_totext(result));
		goto cleanup;
	}
	dns_db_settask(db, zone->task);

	if (zone->type == dns_zone_master || zone->type == dns_zone_slave ||
	    zone->type == dns_zone_mirror)
	{
		result = dns_db_setgluecachestats(db, zone->gluecachestats);
		if (result == ISC_R_NOTIMPLEMENTED) {
			result = ISC_R_SUCCESS;
		}
		if (result != ISC_R_SUCCESS) {
			goto cleanup;
		}
	}

	if (! dns_db_ispersistent(db)) {
		if (zone->masterfile != NULL) {
			result = zone_startload(db, zone, loadtime);
		} else {
			result = DNS_R_NOMASTERFILE;
			if (zone->type == dns_zone_master ||
			    (zone->type == dns_zone_redirect &&
			     zone->masters == NULL)) {
				dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
					      ISC_LOG_ERROR,
					     "loading zone: "
					     "no master file configured");
				goto cleanup;
			}
			dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
				      ISC_LOG_INFO, "loading zone: "
				      "no master file configured: continuing");
		}
	}

	if (result == DNS_R_CONTINUE) {
		DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADING);
		if ((flags & DNS_ZONELOADFLAG_THAW) != 0)
			DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW);
		goto cleanup;
	}

	result = zone_postload(zone, db, loadtime, result);

 cleanup:
	if (hasraw)
		UNLOCK_ZONE(zone->raw);
	if (!locked)
		UNLOCK_ZONE(zone);
	if (db != NULL)
		dns_db_detach(&db);
	return (result);
}

Project: bind9
File: zone.c

zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
	dns_load_t *load;
	isc_result_t result;
	isc_result_t tresult;
	unsigned int options;

	dns_zone_rpz_enable_db(zone, db);
	dns_zone_catz_enable_db(zone, db);
	options = get_master_options(zone);
	if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
		options |= DNS_MASTER_MANYERRORS;

	if (zone->zmgr != NULL && zone->db != NULL && zone->loadtask != NULL) {
		load = isc_mem_get(zone->mctx, sizeof(*load));
		if (load == NULL)
			return (ISC_R_NOMEMORY);

		load->mctx = NULL;
		load->zone = NULL;
		load->db = NULL;
		load->loadtime = loadtime;
		load->magic = LOAD_MAGIC;

		isc_mem_attach(zone->mctx, &load->mctx);
		zone_iattach(zone, &load->zone);
		dns_db_attach(db, &load->db);
		dns_rdatacallbacks_init(&load->callbacks);
		load->callbacks.rawdata = zone_setrawdata;
		zone_iattach(zone, &load->callbacks.zone);
		result = dns_db_beginload(db, &load->callbacks);
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		result = zonemgr_getio(zone->zmgr, true, zone->loadtask,
				       zone_gotreadhandle, load,
				       &zone->readio);
		if (result != ISC_R_SUCCESS) {
			/*
			 * We can't report multiple errors so ignore
			 * the result of dns_db_endload().
			 */
			(void)dns_db_endload(load->db, &load->callbacks);
			goto cleanup;
		} else
			result = DNS_R_CONTINUE;
	} else {
		dns_rdatacallbacks_t callbacks;

		dns_rdatacallbacks_init(&callbacks);
		callbacks.rawdata = zone_setrawdata;
		zone_iattach(zone, &callbacks.zone);
		result = dns_db_beginload(db, &callbacks);
		if (result != ISC_R_SUCCESS) {
			zone_idetach(&callbacks.zone);
			return (result);
		}
		result = dns_master_loadfile(zone->masterfile,
					     &zone->origin, &zone->origin,
					     zone->rdclass, options, 0,
					     &callbacks,
					     zone_registerinclude,
					     zone, zone->mctx,
					     zone->masterformat,
					     zone->maxttl);
		tresult = dns_db_endload(db, &callbacks);
		if (result == ISC_R_SUCCESS)
			result = tresult;
		zone_idetach(&callbacks.zone);
	}

	return (result);

 cleanup:
	load->magic = 0;
	dns_db_detach(&load->db);
	zone_idetach(&load->zone);
	zone_idetach(&load->callbacks.zone);
	isc_mem_detach(&load->mctx);
	isc_mem_put(zone->mctx, load, sizeof(*load));
	return (result);
}

Project: bind9
File: zone.c

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

	return (zmgr->startupnotifyrate);
}

Project: bind9
File: zone.c

dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) {
	isc_result_t result;
	char namebuf[1024];

	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(origin != NULL);

	LOCK_ZONE(zone);
	INSIST(zone != zone->raw);
	if (dns_name_dynamic(&zone->origin)) {
		dns_name_free(&zone->origin, zone->mctx);
		dns_name_init(&zone->origin, NULL);
	}
	result = dns_name_dup(origin, zone->mctx, &zone->origin);

	if (zone->strnamerd != NULL)
		isc_mem_free(zone->mctx, zone->strnamerd);
	if (zone->strname != NULL)
		isc_mem_free(zone->mctx, zone->strname);

	zone_namerd_tostr(zone, namebuf, sizeof namebuf);
	zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
	zone_name_tostr(zone, namebuf, sizeof namebuf);
	zone->strname = isc_mem_strdup(zone->mctx, namebuf);

	if (result == ISC_R_SUCCESS && inline_secure(zone))
		result = dns_zone_setorigin(zone->raw, origin);
	UNLOCK_ZONE(zone);
	return (result);
}

Project: bind9
File: zone.c

zonemgr_free(dns_zonemgr_t *zmgr) {
	isc_mem_t *mctx;

	INSIST(zmgr->refs == 0);
	INSIST(ISC_LIST_EMPTY(zmgr->zones));

	zmgr->magic = 0;

	isc_mutex_destroy(&zmgr->iolock);
	isc_ratelimiter_detach(&zmgr->notifyrl);
	isc_ratelimiter_detach(&zmgr->refreshrl);
	isc_ratelimiter_detach(&zmgr->startupnotifyrl);
	isc_ratelimiter_detach(&zmgr->startuprefreshrl);

	isc_rwlock_destroy(&zmgr->urlock);
	isc_rwlock_destroy(&zmgr->rwlock);
	mctx = zmgr->mctx;
	isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr));
	isc_mem_detach(&mctx);
}

Project: bind9
File: zone.c

dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx) {
	REQUIRE(DNS_ZONE_VALID(zone));
	zone->checkmx = checkmx;
}

Project: bind9
File: zone.c

same_keynames(dns_name_t * const *oldlist, dns_name_t * const *newlist,
	      uint32_t count)
{
	unsigned int i;

	if (oldlist == NULL && newlist == NULL)
		return (true);
	if (oldlist == NULL || newlist == NULL)
		return (false);

	for (i = 0; i < count; i++) {
		if (oldlist[i] == NULL && newlist[i] == NULL)
			continue;
		if (oldlist[i] == NULL || newlist[i] == NULL ||
		    !dns_name_equal(oldlist[i], newlist[i]))
			return (false);
	}
	return (true);
}

Project: bind9
File: zone.c

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

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

Project: bind9
File: zone.c

dns_zone_setview_helper(dns_zone_t *zone, dns_view_t *view) {
	char namebuf[1024];

	if (zone->prev_view == NULL && zone->view != NULL) {
		dns_view_weakattach(zone->view, &zone->prev_view);
	}

	INSIST(zone != zone->raw);
	if (zone->view != NULL) {
		dns_view_weakdetach(&zone->view);
	}
	dns_view_weakattach(view, &zone->view);

	if (zone->strviewname != NULL) {
		isc_mem_free(zone->mctx, zone->strviewname);
	}
	if (zone->strnamerd != NULL) {
		isc_mem_free(zone->mctx, zone->strnamerd);
	}

	zone_namerd_tostr(zone, namebuf, sizeof namebuf);
	zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
	zone_viewname_tostr(zone, namebuf, sizeof namebuf);
	zone->strviewname = isc_mem_strdup(zone->mctx, namebuf);

	if (inline_secure(zone)) {
		dns_zone_setview(zone->raw, view);
	}
}

Project: bind9
File: zone.c

dns_zone_set_parentcatz(dns_zone_t *zone, dns_catz_zone_t *catz) {
	REQUIRE(DNS_ZONE_VALID(zone));
	REQUIRE(catz != NULL);
	LOCK_ZONE(zone);
	INSIST(zone->parentcatz == NULL || zone->parentcatz == catz);
	zone->parentcatz = catz;
	UNLOCK_ZONE(zone);
}

Project: bind9
File: zone.c

dns_zone_getxfrsource4(dns_zone_t *zone) {
	REQUIRE(DNS_ZONE_VALID(zone));
	return (&zone->xfrsource4);
}

Project: bind9
File: zone.c

dns_zone_getqueryonacl(dns_zone_t *zone) {

	REQUIRE(DNS_ZONE_VALID(zone));

	return (zone->queryon_acl);
}

Project: bind9
File: zone.c

dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) {

	REQUIRE(DNS_ZONEMGR_VALID(zmgr));

	setrl(zmgr->notifyrl, &zmgr->notifyrate, value);
}