Home | History | Annotate | Line # | Download | only in ns
update.c revision 1.4.2.2
      1 /*	$NetBSD: update.c,v 1.4.2.2 2019/06/10 22:04:49 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 #include <config.h>
     15 
     16 #include <stdbool.h>
     17 #include <inttypes.h>
     18 
     19 #include <isc/netaddr.h>
     20 #include <isc/print.h>
     21 #include <isc/serial.h>
     22 #include <isc/stats.h>
     23 #include <isc/string.h>
     24 #include <isc/taskpool.h>
     25 #include <isc/util.h>
     26 
     27 #include <dns/db.h>
     28 #include <dns/dbiterator.h>
     29 #include <dns/diff.h>
     30 #include <dns/dnssec.h>
     31 #include <dns/events.h>
     32 #include <dns/fixedname.h>
     33 #include <dns/journal.h>
     34 #include <dns/keyvalues.h>
     35 #include <dns/message.h>
     36 #include <dns/nsec.h>
     37 #include <dns/nsec3.h>
     38 #include <dns/private.h>
     39 #include <dns/rdataclass.h>
     40 #include <dns/rdataset.h>
     41 #include <dns/rdatasetiter.h>
     42 #include <dns/rdatastruct.h>
     43 #include <dns/rdatatype.h>
     44 #include <dns/soa.h>
     45 #include <dns/ssu.h>
     46 #include <dns/tsig.h>
     47 #include <dns/update.h>
     48 #include <dns/view.h>
     49 #include <dns/zone.h>
     50 #include <dns/zt.h>
     51 
     52 #include <ns/client.h>
     53 #include <ns/interfacemgr.h>
     54 #include <ns/log.h>
     55 #include <ns/server.h>
     56 #include <ns/stats.h>
     57 #include <ns/update.h>
     58 
     59 /*! \file
     60  * \brief
     61  * This module implements dynamic update as in RFC2136.
     62  */
     63 
     64 /*
     65  *  XXX TODO:
     66  * - document strict minimality
     67  */
     68 
     69 /**************************************************************************/
     70 
     71 /*%
     72  * Log level for tracing dynamic update protocol requests.
     73  */
     74 #define LOGLEVEL_PROTOCOL	ISC_LOG_INFO
     75 
     76 /*%
     77  * Log level for low-level debug tracing.
     78  */
     79 #define LOGLEVEL_DEBUG		ISC_LOG_DEBUG(8)
     80 
     81 /*%
     82  * Check an operation for failure.  These macros all assume that
     83  * the function using them has a 'result' variable and a 'failure'
     84  * label.
     85  */
     86 #define CHECK(op) \
     87 	do { result = (op); \
     88 		if (result != ISC_R_SUCCESS) goto failure; \
     89 	} while (0)
     90 
     91 /*%
     92  * Fail unconditionally with result 'code', which must not
     93  * be ISC_R_SUCCESS.  The reason for failure presumably has
     94  * been logged already.
     95  *
     96  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
     97  * from complaining about "end-of-loop code not reached".
     98  */
     99 
    100 #define FAIL(code) \
    101 	do {							\
    102 		result = (code);				\
    103 		if (result != ISC_R_SUCCESS) goto failure;	\
    104 	} while (0)
    105 
    106 /*%
    107  * Fail unconditionally and log as a client error.
    108  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
    109  * from complaining about "end-of-loop code not reached".
    110  */
    111 #define FAILC(code, msg) \
    112 	do {							\
    113 		const char *_what = "failed";			\
    114 		result = (code);				\
    115 		switch (result) {				\
    116 		case DNS_R_NXDOMAIN:				\
    117 		case DNS_R_YXDOMAIN:				\
    118 		case DNS_R_YXRRSET:				\
    119 		case DNS_R_NXRRSET:				\
    120 			_what = "unsuccessful";			\
    121 		}						\
    122 		update_log(client, zone, LOGLEVEL_PROTOCOL,	\
    123 			   "update %s: %s (%s)", _what,		\
    124 			   msg, isc_result_totext(result));	\
    125 		if (result != ISC_R_SUCCESS) goto failure;	\
    126 	} while (0)
    127 #define PREREQFAILC(code, msg) \
    128 	do {							\
    129 		inc_stats(client, zone, ns_statscounter_updatebadprereq); \
    130 		FAILC(code, msg);				\
    131 	} while (0)
    132 
    133 #define FAILN(code, name, msg) \
    134 	do {								\
    135 		const char *_what = "failed";				\
    136 		result = (code);					\
    137 		switch (result) {					\
    138 		case DNS_R_NXDOMAIN:					\
    139 		case DNS_R_YXDOMAIN:					\
    140 		case DNS_R_YXRRSET:					\
    141 		case DNS_R_NXRRSET:					\
    142 			_what = "unsuccessful";				\
    143 		}							\
    144 		if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) {	\
    145 			char _nbuf[DNS_NAME_FORMATSIZE];		\
    146 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
    147 			update_log(client, zone, LOGLEVEL_PROTOCOL,	\
    148 				   "update %s: %s: %s (%s)", _what, _nbuf, \
    149 				   msg, isc_result_totext(result));	\
    150 		}							\
    151 		if (result != ISC_R_SUCCESS) goto failure;		\
    152 	} while (0)
    153 #define PREREQFAILN(code, name, msg) \
    154 	do {								\
    155 		inc_stats(client, zone, ns_statscounter_updatebadprereq); \
    156 		FAILN(code, name, msg);					\
    157 	} while (0)
    158 
    159 #define FAILNT(code, name, type, msg) \
    160 	do {								\
    161 		const char *_what = "failed";				\
    162 		result = (code);					\
    163 		switch (result) {					\
    164 		case DNS_R_NXDOMAIN:					\
    165 		case DNS_R_YXDOMAIN:					\
    166 		case DNS_R_YXRRSET:					\
    167 		case DNS_R_NXRRSET:					\
    168 			_what = "unsuccessful";				\
    169 		}							\
    170 		if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) {	\
    171 			char _nbuf[DNS_NAME_FORMATSIZE];		\
    172 			char _tbuf[DNS_RDATATYPE_FORMATSIZE];		\
    173 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
    174 			dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
    175 			update_log(client, zone, LOGLEVEL_PROTOCOL,	\
    176 				   "update %s: %s/%s: %s (%s)",		\
    177 				   _what, _nbuf, _tbuf, msg,		\
    178 				   isc_result_totext(result));		\
    179 		}							\
    180 		if (result != ISC_R_SUCCESS) goto failure;		\
    181 	} while (0)
    182 #define PREREQFAILNT(code, name, type, msg)				\
    183 	do {								\
    184 		inc_stats(client, zone, ns_statscounter_updatebadprereq); \
    185 		FAILNT(code, name, type, msg);				\
    186 	} while (0)
    187 
    188 /*%
    189  * Fail unconditionally and log as a server error.
    190  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
    191  * from complaining about "end-of-loop code not reached".
    192  */
    193 #define FAILS(code, msg) \
    194 	do {							\
    195 		result = (code);				\
    196 		update_log(client, zone, LOGLEVEL_PROTOCOL,	\
    197 			   "error: %s: %s",			\
    198 			   msg, isc_result_totext(result));	\
    199 		if (result != ISC_R_SUCCESS) goto failure;	\
    200 	} while (0)
    201 
    202 /*
    203  * Return TRUE if NS_CLIENTATTR_TCP is set in the attributes other FALSE.
    204  */
    205 #define TCPCLIENT(client) (((client)->attributes & NS_CLIENTATTR_TCP) != 0)
    206 
    207 /**************************************************************************/
    208 
    209 typedef struct rr rr_t;
    210 
    211 struct rr {
    212 	/* dns_name_t name; */
    213 	uint32_t		ttl;
    214 	dns_rdata_t		rdata;
    215 };
    216 
    217 typedef struct update_event update_event_t;
    218 
    219 struct update_event {
    220 	ISC_EVENT_COMMON(update_event_t);
    221 	dns_zone_t		*zone;
    222 	isc_result_t		result;
    223 	dns_message_t		*answer;
    224 };
    225 
    226 /*%
    227  * Prepare an RR for the addition of the new RR 'ctx->update_rr',
    228  * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting
    229  * the RRs if it is replaced by the new RR or has a conflicting TTL.
    230  * The necessary changes are appended to ctx->del_diff and ctx->add_diff;
    231  * we need to do all deletions before any additions so that we don't run
    232  * into transient states with conflicting TTLs.
    233  */
    234 
    235 typedef struct {
    236 	dns_db_t *db;
    237 	dns_dbversion_t *ver;
    238 	dns_diff_t *diff;
    239 	dns_name_t *name;
    240 	dns_name_t *oldname;
    241 	dns_rdata_t *update_rr;
    242 	dns_ttl_t update_rr_ttl;
    243 	bool ignore_add;
    244 	dns_diff_t del_diff;
    245 	dns_diff_t add_diff;
    246 } add_rr_prepare_ctx_t;
    247 
    248 /**************************************************************************/
    249 /*
    250  * Forward declarations.
    251  */
    252 
    253 static void update_action(isc_task_t *task, isc_event_t *event);
    254 static void updatedone_action(isc_task_t *task, isc_event_t *event);
    255 static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone);
    256 static void forward_done(isc_task_t *task, isc_event_t *event);
    257 static isc_result_t add_rr_prepare_action(void *data, rr_t *rr);
    258 
    259 /**************************************************************************/
    260 
    261 static void
    262 update_log(ns_client_t *client, dns_zone_t *zone,
    263 	   int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
    264 
    265 static void
    266 update_log(ns_client_t *client, dns_zone_t *zone,
    267 	   int level, const char *fmt, ...)
    268 {
    269 	va_list ap;
    270 	char message[4096];
    271 	char namebuf[DNS_NAME_FORMATSIZE];
    272 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
    273 
    274 	if (client == NULL) {
    275 		return;
    276 	}
    277 
    278 	if (isc_log_wouldlog(ns_lctx, level) == false) {
    279 		return;
    280 	}
    281 
    282 	va_start(ap, fmt);
    283 	vsnprintf(message, sizeof(message), fmt, ap);
    284 	va_end(ap);
    285 
    286 	if (zone != NULL) {
    287 		dns_name_format(dns_zone_getorigin(zone), namebuf,
    288 				sizeof(namebuf));
    289 		dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
    290 				      sizeof(classbuf));
    291 
    292 		ns_client_log(client, NS_LOGCATEGORY_UPDATE,
    293 			      NS_LOGMODULE_UPDATE,
    294 			      level, "updating zone '%s/%s': %s",
    295 			      namebuf, classbuf, message);
    296 	} else {
    297 		ns_client_log(client, NS_LOGCATEGORY_UPDATE,
    298 			      NS_LOGMODULE_UPDATE,
    299 			      level, "%s", message);
    300 	}
    301 
    302 }
    303 
    304 static void
    305 update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) {
    306 	update_log(arg, zone, level, "%s", message);
    307 }
    308 
    309 /*%
    310  * Increment updated-related statistics counters.
    311  */
    312 static inline void
    313 inc_stats(ns_client_t *client, dns_zone_t *zone, isc_statscounter_t counter) {
    314 	ns_stats_increment(client->sctx->nsstats, counter);
    315 
    316 	if (zone != NULL) {
    317 		isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
    318 		if (zonestats != NULL)
    319 			isc_stats_increment(zonestats, counter);
    320 	}
    321 }
    322 
    323 /*%
    324  * Check if we could have queried for the contents of this zone or
    325  * if the zone is potentially updateable.
    326  * If the zone can potentially be updated and the check failed then
    327  * log a error otherwise we log a informational message.
    328  */
    329 static isc_result_t
    330 checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename,
    331 	      dns_acl_t *updateacl, dns_ssutable_t *ssutable)
    332 {
    333 	char namebuf[DNS_NAME_FORMATSIZE];
    334 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
    335 	int level;
    336 	isc_result_t result;
    337 
    338 	result = ns_client_checkaclsilent(client, NULL, queryacl, true);
    339 	if (result != ISC_R_SUCCESS) {
    340 		dns_name_format(zonename, namebuf, sizeof(namebuf));
    341 		dns_rdataclass_format(client->view->rdclass, classbuf,
    342 				      sizeof(classbuf));
    343 
    344 		level = (updateacl == NULL && ssutable == NULL) ?
    345 				ISC_LOG_INFO : ISC_LOG_ERROR;
    346 
    347 		ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
    348 			      NS_LOGMODULE_UPDATE, level,
    349 			      "update '%s/%s' denied due to allow-query",
    350 			      namebuf, classbuf);
    351 	} else if (updateacl == NULL && ssutable == NULL) {
    352 		dns_name_format(zonename, namebuf, sizeof(namebuf));
    353 		dns_rdataclass_format(client->view->rdclass, classbuf,
    354 				      sizeof(classbuf));
    355 
    356 		result = DNS_R_REFUSED;
    357 		ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
    358 			      NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
    359 			      "update '%s/%s' denied", namebuf, classbuf);
    360 	}
    361 	return (result);
    362 }
    363 
    364 /*%
    365  * Override the default acl logging when checking whether a client
    366  * can update the zone or whether we can forward the request to the
    367  * master based on IP address.
    368  *
    369  * 'message' contains the type of operation that is being attempted.
    370  * 'slave' indicates if this is a slave zone.  If 'acl' is NULL then
    371  * log at debug=3.
    372  * If the zone has no access controls configured ('acl' == NULL &&
    373  * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise
    374  * at error.
    375  *
    376  * If the request was signed log that we received it.
    377  */
    378 static isc_result_t
    379 checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message,
    380 	       dns_name_t *zonename, bool slave,
    381 	       bool has_ssutable)
    382 {
    383 	char namebuf[DNS_NAME_FORMATSIZE];
    384 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
    385 	int level = ISC_LOG_ERROR;
    386 	const char *msg = "denied";
    387 	isc_result_t result;
    388 
    389 	if (slave && acl == NULL) {
    390 		result = DNS_R_NOTIMP;
    391 		level = ISC_LOG_DEBUG(3);
    392 		msg = "disabled";
    393 	} else {
    394 		result = ns_client_checkaclsilent(client, NULL, acl, false);
    395 		if (result == ISC_R_SUCCESS) {
    396 			level = ISC_LOG_DEBUG(3);
    397 			msg = "approved";
    398 		} else if (acl == NULL && !has_ssutable) {
    399 			level = ISC_LOG_INFO;
    400 		}
    401 	}
    402 
    403 	if (client->signer != NULL) {
    404 		dns_name_format(client->signer, namebuf, sizeof(namebuf));
    405 		ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
    406 			      NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
    407 			      "signer \"%s\" %s", namebuf, msg);
    408 	}
    409 
    410 	dns_name_format(zonename, namebuf, sizeof(namebuf));
    411 	dns_rdataclass_format(client->view->rdclass, classbuf,
    412 			      sizeof(classbuf));
    413 
    414 	ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
    415 		      NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s",
    416 		      message, namebuf, classbuf, msg);
    417 	return (result);
    418 }
    419 
    420 /*%
    421  * Update a single RR in version 'ver' of 'db' and log the
    422  * update in 'diff'.
    423  *
    424  * Ensures:
    425  * \li	'*tuple' == NULL.  Either the tuple is freed, or its
    426  *	ownership has been transferred to the diff.
    427  */
    428 static isc_result_t
    429 do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
    430 	     dns_diff_t *diff)
    431 {
    432 	dns_diff_t temp_diff;
    433 	isc_result_t result;
    434 
    435 	/*
    436 	 * Create a singleton diff.
    437 	 */
    438 	dns_diff_init(diff->mctx, &temp_diff);
    439 	ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
    440 
    441 	/*
    442 	 * Apply it to the database.
    443 	 */
    444 	result = dns_diff_apply(&temp_diff, db, ver);
    445 	ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
    446 	if (result != ISC_R_SUCCESS) {
    447 		dns_difftuple_free(tuple);
    448 		return (result);
    449 	}
    450 
    451 	/*
    452 	 * Merge it into the current pending journal entry.
    453 	 */
    454 	dns_diff_appendminimal(diff, tuple);
    455 
    456 	/*
    457 	 * Do not clear temp_diff.
    458 	 */
    459 	return (ISC_R_SUCCESS);
    460 }
    461 
    462 /*%
    463  * Perform the updates in 'updates' in version 'ver' of 'db' and log the
    464  * update in 'diff'.
    465  *
    466  * Ensures:
    467  * \li	'updates' is empty.
    468  */
    469 static isc_result_t
    470 do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver,
    471 	dns_diff_t *diff)
    472 {
    473 	isc_result_t result;
    474 	while (! ISC_LIST_EMPTY(updates->tuples)) {
    475 		dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples);
    476 		ISC_LIST_UNLINK(updates->tuples, t, link);
    477 		CHECK(do_one_tuple(&t, db, ver, diff));
    478 	}
    479 	return (ISC_R_SUCCESS);
    480 
    481  failure:
    482 	dns_diff_clear(diff);
    483 	return (result);
    484 }
    485 
    486 static isc_result_t
    487 update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
    488 	      dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
    489 	      dns_rdata_t *rdata)
    490 {
    491 	dns_difftuple_t *tuple = NULL;
    492 	isc_result_t result;
    493 	result = dns_difftuple_create(diff->mctx, op,
    494 				      name, ttl, rdata, &tuple);
    495 	if (result != ISC_R_SUCCESS)
    496 		return (result);
    497 	return (do_one_tuple(&tuple, db, ver, diff));
    498 }
    499 
    500 /**************************************************************************/
    501 /*
    502  * Callback-style iteration over rdatasets and rdatas.
    503  *
    504  * foreach_rrset() can be used to iterate over the RRsets
    505  * of a name and call a callback function with each
    506  * one.  Similarly, foreach_rr() can be used to iterate
    507  * over the individual RRs at name, optionally restricted
    508  * to RRs of a given type.
    509  *
    510  * The callback functions are called "actions" and take
    511  * two arguments: a void pointer for passing arbitrary
    512  * context information, and a pointer to the current RRset
    513  * or RR.  By convention, their names end in "_action".
    514  */
    515 
    516 /*
    517  * XXXRTH  We might want to make this public somewhere in libdns.
    518  */
    519 
    520 /*%
    521  * Function type for foreach_rrset() iterator actions.
    522  */
    523 typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
    524 
    525 /*%
    526  * Function type for foreach_rr() iterator actions.
    527  */
    528 typedef isc_result_t rr_func(void *data, rr_t *rr);
    529 
    530 /*%
    531  * Internal context struct for foreach_node_rr().
    532  */
    533 typedef struct {
    534 	rr_func *	rr_action;
    535 	void *		rr_action_data;
    536 } foreach_node_rr_ctx_t;
    537 
    538 /*%
    539  * Internal helper function for foreach_node_rr().
    540  */
    541 static isc_result_t
    542 foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
    543 	isc_result_t result;
    544 	foreach_node_rr_ctx_t *ctx = data;
    545 	for (result = dns_rdataset_first(rdataset);
    546 	     result == ISC_R_SUCCESS;
    547 	     result = dns_rdataset_next(rdataset))
    548 	{
    549 		rr_t rr = { 0, DNS_RDATA_INIT };
    550 
    551 		dns_rdataset_current(rdataset, &rr.rdata);
    552 		rr.ttl = rdataset->ttl;
    553 		result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
    554 		if (result != ISC_R_SUCCESS)
    555 			return (result);
    556 	}
    557 	if (result != ISC_R_NOMORE)
    558 		return (result);
    559 	return (ISC_R_SUCCESS);
    560 }
    561 
    562 /*%
    563  * For each rdataset of 'name' in 'ver' of 'db', call 'action'
    564  * with the rdataset and 'action_data' as arguments.  If the name
    565  * does not exist, do nothing.
    566  *
    567  * If 'action' returns an error, abort iteration and return the error.
    568  */
    569 static isc_result_t
    570 foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
    571 	      rrset_func *action, void *action_data)
    572 {
    573 	isc_result_t result;
    574 	dns_dbnode_t *node;
    575 	dns_rdatasetiter_t *iter;
    576 	dns_clientinfomethods_t cm;
    577 	dns_clientinfo_t ci;
    578 	dns_dbversion_t *oldver = NULL;
    579 
    580 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
    581 
    582 	/*
    583 	 * Only set the clientinfo 'versionp' if the new version is
    584 	 * different from the current version
    585 	 */
    586 	dns_db_currentversion(db, &oldver);
    587 	dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
    588 	dns_db_closeversion(db, &oldver, false);
    589 
    590 	node = NULL;
    591 	result = dns_db_findnodeext(db, name, false, &cm, &ci, &node);
    592 	if (result == ISC_R_NOTFOUND)
    593 		return (ISC_R_SUCCESS);
    594 	if (result != ISC_R_SUCCESS)
    595 		return (result);
    596 
    597 	iter = NULL;
    598 	result = dns_db_allrdatasets(db, node, ver,
    599 				     (isc_stdtime_t) 0, &iter);
    600 	if (result != ISC_R_SUCCESS)
    601 		goto cleanup_node;
    602 
    603 	for (result = dns_rdatasetiter_first(iter);
    604 	     result == ISC_R_SUCCESS;
    605 	     result = dns_rdatasetiter_next(iter))
    606 	{
    607 		dns_rdataset_t rdataset;
    608 
    609 		dns_rdataset_init(&rdataset);
    610 		dns_rdatasetiter_current(iter, &rdataset);
    611 
    612 		result = (*action)(action_data, &rdataset);
    613 
    614 		dns_rdataset_disassociate(&rdataset);
    615 		if (result != ISC_R_SUCCESS)
    616 			goto cleanup_iterator;
    617 	}
    618 	if (result == ISC_R_NOMORE)
    619 		result = ISC_R_SUCCESS;
    620 
    621  cleanup_iterator:
    622 	dns_rdatasetiter_destroy(&iter);
    623 
    624  cleanup_node:
    625 	dns_db_detachnode(db, &node);
    626 
    627 	return (result);
    628 }
    629 
    630 /*%
    631  * For each RR of 'name' in 'ver' of 'db', call 'action'
    632  * with the RR and 'action_data' as arguments.  If the name
    633  * does not exist, do nothing.
    634  *
    635  * If 'action' returns an error, abort iteration
    636  * and return the error.
    637  */
    638 static isc_result_t
    639 foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
    640 		rr_func *rr_action, void *rr_action_data)
    641 {
    642 	foreach_node_rr_ctx_t ctx;
    643 	ctx.rr_action = rr_action;
    644 	ctx.rr_action_data = rr_action_data;
    645 	return (foreach_rrset(db, ver, name,
    646 			      foreach_node_rr_action, &ctx));
    647 }
    648 
    649 
    650 /*%
    651  * For each of the RRs specified by 'db', 'ver', 'name', 'type',
    652  * (which can be dns_rdatatype_any to match any type), and 'covers', call
    653  * 'action' with the RR and 'action_data' as arguments. If the name
    654  * does not exist, or if no RRset of the given type exists at the name,
    655  * do nothing.
    656  *
    657  * If 'action' returns an error, abort iteration and return the error.
    658  */
    659 static isc_result_t
    660 foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
    661 	   dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
    662 	   void *rr_action_data)
    663 {
    664 
    665 	isc_result_t result;
    666 	dns_dbnode_t *node;
    667 	dns_rdataset_t rdataset;
    668 	dns_clientinfomethods_t cm;
    669 	dns_clientinfo_t ci;
    670 	dns_dbversion_t *oldver = NULL;
    671 	dns_fixedname_t fixed;
    672 
    673 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
    674 
    675 	/*
    676 	 * Only set the clientinfo 'versionp' if the new version is
    677 	 * different from the current version
    678 	 */
    679 	dns_db_currentversion(db, &oldver);
    680 	dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
    681 	dns_db_closeversion(db, &oldver, false);
    682 
    683 	if (type == dns_rdatatype_any)
    684 		return (foreach_node_rr(db, ver, name,
    685 					rr_action, rr_action_data));
    686 
    687 	node = NULL;
    688 	if (type == dns_rdatatype_nsec3 ||
    689 	    (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
    690 		result = dns_db_findnsec3node(db, name, false, &node);
    691 	else
    692 		result = dns_db_findnodeext(db, name, false,
    693 					    &cm, &ci, &node);
    694 	if (result == ISC_R_NOTFOUND)
    695 		return (ISC_R_SUCCESS);
    696 	if (result != ISC_R_SUCCESS)
    697 		return (result);
    698 
    699 	dns_rdataset_init(&rdataset);
    700 	result = dns_db_findrdataset(db, node, ver, type, covers,
    701 				     (isc_stdtime_t) 0, &rdataset, NULL);
    702 	if (result == ISC_R_NOTFOUND) {
    703 		result = ISC_R_SUCCESS;
    704 		goto cleanup_node;
    705 	}
    706 	if (result != ISC_R_SUCCESS)
    707 		goto cleanup_node;
    708 
    709 	if (rr_action == add_rr_prepare_action) {
    710 		add_rr_prepare_ctx_t *ctx = rr_action_data;
    711 
    712 		ctx->oldname = dns_fixedname_initname(&fixed);
    713 		dns_name_copy(name, ctx->oldname, NULL);
    714 		dns_rdataset_getownercase(&rdataset, ctx->oldname);
    715 	}
    716 
    717 	for (result = dns_rdataset_first(&rdataset);
    718 	     result == ISC_R_SUCCESS;
    719 	     result = dns_rdataset_next(&rdataset))
    720 	{
    721 		rr_t rr = { 0, DNS_RDATA_INIT };
    722 		dns_rdataset_current(&rdataset, &rr.rdata);
    723 		rr.ttl = rdataset.ttl;
    724 		result = (*rr_action)(rr_action_data, &rr);
    725 		if (result != ISC_R_SUCCESS)
    726 			goto cleanup_rdataset;
    727 	}
    728 	if (result != ISC_R_NOMORE)
    729 		goto cleanup_rdataset;
    730 	result = ISC_R_SUCCESS;
    731 
    732  cleanup_rdataset:
    733 	dns_rdataset_disassociate(&rdataset);
    734  cleanup_node:
    735 	dns_db_detachnode(db, &node);
    736 
    737 	return (result);
    738 }
    739 
    740 /**************************************************************************/
    741 /*
    742  * Various tests on the database contents (for prerequisites, etc).
    743  */
    744 
    745 /*%
    746  * Function type for predicate functions that compare a database RR 'db_rr'
    747  * against an update RR 'update_rr'.
    748  */
    749 typedef bool rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
    750 
    751 /*%
    752  * Helper function for rrset_exists().
    753  */
    754 static isc_result_t
    755 rrset_exists_action(void *data, rr_t *rr) {
    756 	UNUSED(data);
    757 	UNUSED(rr);
    758 	return (ISC_R_EXISTS);
    759 }
    760 
    761 /*%
    762  * Utility macro for RR existence checking functions.
    763  *
    764  * If the variable 'result' has the value ISC_R_EXISTS or
    765  * ISC_R_SUCCESS, set *exists to true or false,
    766  * respectively, and return success.
    767  *
    768  * If 'result' has any other value, there was a failure.
    769  * Return the failure result code and do not set *exists.
    770  *
    771  * This would be more readable as "do { if ... } while(0)",
    772  * but that form generates tons of warnings on Solaris 2.6.
    773  */
    774 #define RETURN_EXISTENCE_FLAG				\
    775 	return ((result == ISC_R_EXISTS) ?		\
    776 		(*exists = true, ISC_R_SUCCESS) :	\
    777 		((result == ISC_R_SUCCESS) ?		\
    778 		 (*exists = false, ISC_R_SUCCESS) :	\
    779 		 result))
    780 
    781 /*%
    782  * Set '*exists' to true iff an rrset of the given type exists,
    783  * to false otherwise.
    784  */
    785 static isc_result_t
    786 rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
    787 	     dns_rdatatype_t type, dns_rdatatype_t covers,
    788 	     bool *exists)
    789 {
    790 	isc_result_t result;
    791 	result = foreach_rr(db, ver, name, type, covers,
    792 			    rrset_exists_action, NULL);
    793 	RETURN_EXISTENCE_FLAG;
    794 }
    795 
    796 /*%
    797  * Helper function for cname_incompatible_rrset_exists.
    798  */
    799 static isc_result_t
    800 cname_compatibility_action(void *data, dns_rdataset_t *rrset) {
    801 	UNUSED(data);
    802 	if (rrset->type != dns_rdatatype_cname &&
    803 	    ! dns_rdatatype_atcname(rrset->type))
    804 	{
    805 		return (ISC_R_EXISTS);
    806 	}
    807 	return (ISC_R_SUCCESS);
    808 }
    809 
    810 /*%
    811  * Check whether there is an rrset incompatible with adding a CNAME RR,
    812  * i.e., anything but another CNAME (which can be replaced) or a
    813  * DNSSEC RR (which can coexist).
    814  *
    815  * If such an incompatible rrset exists, set '*exists' to true.
    816  * Otherwise, set it to false.
    817  */
    818 static isc_result_t
    819 cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
    820 				dns_name_t *name, bool *exists) {
    821 	isc_result_t result;
    822 	result = foreach_rrset(db, ver, name,
    823 			       cname_compatibility_action, NULL);
    824 	RETURN_EXISTENCE_FLAG;
    825 }
    826 
    827 /*%
    828  * Helper function for rr_count().
    829  */
    830 static isc_result_t
    831 count_rr_action(void *data, rr_t *rr) {
    832 	int *countp = data;
    833 	UNUSED(rr);
    834 	(*countp)++;
    835 	return (ISC_R_SUCCESS);
    836 }
    837 
    838 /*%
    839  * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'.
    840  */
    841 static isc_result_t
    842 rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
    843 	 dns_rdatatype_t type, dns_rdatatype_t covers, int *countp)
    844 {
    845 	*countp = 0;
    846 	return (foreach_rr(db, ver, name, type, covers,
    847 			   count_rr_action, countp));
    848 }
    849 
    850 /*%
    851  * Context struct and helper function for name_exists().
    852  */
    853 
    854 static isc_result_t
    855 name_exists_action(void *data, dns_rdataset_t *rrset) {
    856 	UNUSED(data);
    857 	UNUSED(rrset);
    858 	return (ISC_R_EXISTS);
    859 }
    860 
    861 /*%
    862  * Set '*exists' to true iff the given name exists, to false otherwise.
    863  */
    864 static isc_result_t
    865 name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
    866 	    bool *exists)
    867 {
    868 	isc_result_t result;
    869 	result = foreach_rrset(db, ver, name,
    870 			       name_exists_action, NULL);
    871 	RETURN_EXISTENCE_FLAG;
    872 }
    873 
    874 /*
    875  *	'ssu_check_t' is used to pass the arguments to
    876  *	dns_ssutable_checkrules() to the callback function
    877  *	ssu_checkrule().
    878  */
    879 typedef struct {
    880 	/* The ownername of the record to be updated. */
    881 	dns_name_t *name;
    882 
    883 	/* The signature's name if the request was signed. */
    884 	dns_name_t *signer;
    885 
    886 	/* The address of the client. */
    887 	isc_netaddr_t *addr;
    888 
    889 	/* The ACL environment */
    890 	dns_aclenv_t *aclenv;
    891 
    892 	/* Whether the request was sent via TCP. */
    893 	bool tcp;
    894 
    895 	/* The ssu table to check against. */
    896 	dns_ssutable_t *table;
    897 
    898 	/* the key used for TKEY requests */
    899 	dst_key_t *key;
    900 } ssu_check_t;
    901 
    902 static isc_result_t
    903 ssu_checkrule(void *data, dns_rdataset_t *rrset) {
    904 	ssu_check_t *ssuinfo = data;
    905 	bool result;
    906 
    907 	/*
    908 	 * If we're deleting all records, it's ok to delete RRSIG and NSEC even
    909 	 * if we're normally not allowed to.
    910 	 */
    911 	if (rrset->type == dns_rdatatype_rrsig ||
    912 	    rrset->type == dns_rdatatype_nsec)
    913 		return (ISC_R_SUCCESS);
    914 	result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
    915 					 ssuinfo->name, ssuinfo->addr,
    916 					 ssuinfo->tcp, ssuinfo->aclenv,
    917 					 rrset->type, ssuinfo->key);
    918 	return (result == true ? ISC_R_SUCCESS : ISC_R_FAILURE);
    919 }
    920 
    921 static bool
    922 ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
    923 	     dns_ssutable_t *ssutable, dns_name_t *signer,
    924 	     isc_netaddr_t *addr, dns_aclenv_t *aclenv, bool tcp,
    925 	     dst_key_t *key)
    926 {
    927 	isc_result_t result;
    928 	ssu_check_t ssuinfo;
    929 
    930 	ssuinfo.name = name;
    931 	ssuinfo.table = ssutable;
    932 	ssuinfo.signer = signer;
    933 	ssuinfo.addr = addr;
    934 	ssuinfo.aclenv = aclenv;
    935 	ssuinfo.tcp = tcp;
    936 	ssuinfo.key = key;
    937 	result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
    938 	return (result == ISC_R_SUCCESS);
    939 }
    940 
    941 /**************************************************************************/
    942 /*
    943  * Checking of "RRset exists (value dependent)" prerequisites.
    944  *
    945  * In the RFC2136 section 3.2.5, this is the pseudocode involving
    946  * a variable called "temp", a mapping of <name, type> tuples to rrsets.
    947  *
    948  * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
    949  * where each tuple has op==DNS_DIFFOP_EXISTS.
    950  */
    951 
    952 
    953 /*%
    954  * Append a tuple asserting the existence of the RR with
    955  * 'name' and 'rdata' to 'diff'.
    956  */
    957 static isc_result_t
    958 temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) {
    959 	isc_result_t result;
    960 	dns_difftuple_t *tuple = NULL;
    961 
    962 	REQUIRE(DNS_DIFF_VALID(diff));
    963 	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS,
    964 				   name, 0, rdata, &tuple));
    965 	ISC_LIST_APPEND(diff->tuples, tuple, link);
    966  failure:
    967 	return (result);
    968 }
    969 
    970 /*%
    971  * Compare two rdatasets represented as sorted lists of tuples.
    972  * All list elements must have the same owner name and type.
    973  * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset)
    974  * if not.
    975  */
    976 static isc_result_t
    977 temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) {
    978 	for (;;) {
    979 		if (a == NULL || b == NULL)
    980 			break;
    981 		INSIST(a->op == DNS_DIFFOP_EXISTS &&
    982 		       b->op == DNS_DIFFOP_EXISTS);
    983 		INSIST(a->rdata.type == b->rdata.type);
    984 		INSIST(dns_name_equal(&a->name, &b->name));
    985 		if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0)
    986 			return (DNS_R_NXRRSET);
    987 		a = ISC_LIST_NEXT(a, link);
    988 		b = ISC_LIST_NEXT(b, link);
    989 	}
    990 	if (a != NULL || b != NULL)
    991 		return (DNS_R_NXRRSET);
    992 	return (ISC_R_SUCCESS);
    993 }
    994 
    995 /*%
    996  * A comparison function defining the sorting order for the entries
    997  * in the "temp" data structure.  The major sort key is the owner name,
    998  * followed by the type and rdata.
    999  */
   1000 static int
   1001 temp_order(const void *av, const void *bv) {
   1002 	dns_difftuple_t const * const *ap = av;
   1003 	dns_difftuple_t const * const *bp = bv;
   1004 	dns_difftuple_t const *a = *ap;
   1005 	dns_difftuple_t const *b = *bp;
   1006 	int r;
   1007 	r = dns_name_compare(&a->name, &b->name);
   1008 	if (r != 0)
   1009 		return (r);
   1010 	r = (b->rdata.type - a->rdata.type);
   1011 	if (r != 0)
   1012 		return (r);
   1013 	r = dns_rdata_casecompare(&a->rdata, &b->rdata);
   1014 	return (r);
   1015 }
   1016 
   1017 /*%
   1018  * Check the "RRset exists (value dependent)" prerequisite information
   1019  * in 'temp' against the contents of the database 'db'.
   1020  *
   1021  * Return ISC_R_SUCCESS if the prerequisites are satisfied,
   1022  * rcode(dns_rcode_nxrrset) if not.
   1023  *
   1024  * 'temp' must be pre-sorted.
   1025  */
   1026 
   1027 static isc_result_t
   1028 temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
   1029 	   dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep)
   1030 {
   1031 	isc_result_t result;
   1032 	dns_name_t *name;
   1033 	dns_dbnode_t *node;
   1034 	dns_difftuple_t *t;
   1035 	dns_diff_t trash;
   1036 
   1037 	dns_diff_init(mctx, &trash);
   1038 
   1039 	/*
   1040 	 * For each name and type in the prerequisites,
   1041 	 * construct a sorted rdata list of the corresponding
   1042 	 * database contents, and compare the lists.
   1043 	 */
   1044 	t = ISC_LIST_HEAD(temp->tuples);
   1045 	while (t != NULL) {
   1046 		name = &t->name;
   1047 		(void)dns_name_copy(name, tmpname, NULL);
   1048 		*typep = t->rdata.type;
   1049 
   1050 		/* A new unique name begins here. */
   1051 		node = NULL;
   1052 		result = dns_db_findnode(db, name, false, &node);
   1053 		if (result == ISC_R_NOTFOUND) {
   1054 			dns_diff_clear(&trash);
   1055 			return (DNS_R_NXRRSET);
   1056 		}
   1057 		if (result != ISC_R_SUCCESS) {
   1058 			dns_diff_clear(&trash);
   1059 			return (result);
   1060 		}
   1061 
   1062 		/* A new unique type begins here. */
   1063 		while (t != NULL && dns_name_equal(&t->name, name)) {
   1064 			dns_rdatatype_t type, covers;
   1065 			dns_rdataset_t rdataset;
   1066 			dns_diff_t d_rrs; /* Database RRs with
   1067 						this name and type */
   1068 			dns_diff_t u_rrs; /* Update RRs with
   1069 						this name and type */
   1070 
   1071 			*typep = type = t->rdata.type;
   1072 			if (type == dns_rdatatype_rrsig ||
   1073 			    type == dns_rdatatype_sig)
   1074 				covers = dns_rdata_covers(&t->rdata);
   1075 			else if (type == dns_rdatatype_any) {
   1076 				dns_db_detachnode(db, &node);
   1077 				dns_diff_clear(&trash);
   1078 				return (DNS_R_NXRRSET);
   1079 			} else
   1080 				covers = 0;
   1081 
   1082 			/*
   1083 			 * Collect all database RRs for this name and type
   1084 			 * onto d_rrs and sort them.
   1085 			 */
   1086 			dns_rdataset_init(&rdataset);
   1087 			result = dns_db_findrdataset(db, node, ver, type,
   1088 						     covers, (isc_stdtime_t) 0,
   1089 						     &rdataset, NULL);
   1090 			if (result != ISC_R_SUCCESS) {
   1091 				dns_db_detachnode(db, &node);
   1092 				dns_diff_clear(&trash);
   1093 				return (DNS_R_NXRRSET);
   1094 			}
   1095 
   1096 			dns_diff_init(mctx, &d_rrs);
   1097 			dns_diff_init(mctx, &u_rrs);
   1098 
   1099 			for (result = dns_rdataset_first(&rdataset);
   1100 			     result == ISC_R_SUCCESS;
   1101 			     result = dns_rdataset_next(&rdataset))
   1102 			{
   1103 				dns_rdata_t rdata = DNS_RDATA_INIT;
   1104 				dns_rdataset_current(&rdataset, &rdata);
   1105 				result = temp_append(&d_rrs, name, &rdata);
   1106 				if (result != ISC_R_SUCCESS)
   1107 					goto failure;
   1108 			}
   1109 			if (result != ISC_R_NOMORE)
   1110 				goto failure;
   1111 			result = dns_diff_sort(&d_rrs, temp_order);
   1112 			if (result != ISC_R_SUCCESS)
   1113 				goto failure;
   1114 
   1115 			/*
   1116 			 * Collect all update RRs for this name and type
   1117 			 * onto u_rrs.  No need to sort them here -
   1118 			 * they are already sorted.
   1119 			 */
   1120 			while (t != NULL &&
   1121 			       dns_name_equal(&t->name, name) &&
   1122 			       t->rdata.type == type)
   1123 			{
   1124 				dns_difftuple_t *next =
   1125 					ISC_LIST_NEXT(t, link);
   1126 				ISC_LIST_UNLINK(temp->tuples, t, link);
   1127 				ISC_LIST_APPEND(u_rrs.tuples, t, link);
   1128 				t = next;
   1129 			}
   1130 
   1131 			/* Compare the two sorted lists. */
   1132 			result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples),
   1133 						  ISC_LIST_HEAD(d_rrs.tuples));
   1134 			if (result != ISC_R_SUCCESS)
   1135 				goto failure;
   1136 
   1137 			/*
   1138 			 * We are done with the tuples, but we can't free
   1139 			 * them yet because "name" still points into one
   1140 			 * of them.  Move them on a temporary list.
   1141 			 */
   1142 			ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link);
   1143 			ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link);
   1144 			dns_rdataset_disassociate(&rdataset);
   1145 
   1146 			continue;
   1147 
   1148 		    failure:
   1149 			dns_diff_clear(&d_rrs);
   1150 			dns_diff_clear(&u_rrs);
   1151 			dns_diff_clear(&trash);
   1152 			dns_rdataset_disassociate(&rdataset);
   1153 			dns_db_detachnode(db, &node);
   1154 			return (result);
   1155 		}
   1156 
   1157 		dns_db_detachnode(db, &node);
   1158 	}
   1159 
   1160 	dns_diff_clear(&trash);
   1161 	return (ISC_R_SUCCESS);
   1162 }
   1163 
   1164 /**************************************************************************/
   1165 /*
   1166  * Conditional deletion of RRs.
   1167  */
   1168 
   1169 /*%
   1170  * Context structure for delete_if().
   1171  */
   1172 
   1173 typedef struct {
   1174 	rr_predicate *predicate;
   1175 	dns_db_t *db;
   1176 	dns_dbversion_t *ver;
   1177 	dns_diff_t *diff;
   1178 	dns_name_t *name;
   1179 	dns_rdata_t *update_rr;
   1180 } conditional_delete_ctx_t;
   1181 
   1182 /*%
   1183  * Predicate functions for delete_if().
   1184  */
   1185 
   1186 /*%
   1187  * Return true iff 'db_rr' is neither a SOA nor an NS RR nor
   1188  * an RRSIG nor an NSEC3PARAM nor a NSEC.
   1189  */
   1190 static bool
   1191 type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
   1192 	UNUSED(update_rr);
   1193 	return ((db_rr->type != dns_rdatatype_soa &&
   1194 		 db_rr->type != dns_rdatatype_ns &&
   1195 		 db_rr->type != dns_rdatatype_nsec3param &&
   1196 		 db_rr->type != dns_rdatatype_rrsig &&
   1197 		 db_rr->type != dns_rdatatype_nsec) ?
   1198 		true : false);
   1199 }
   1200 
   1201 /*%
   1202  * Return true iff 'db_rr' is neither a RRSIG nor a NSEC.
   1203  */
   1204 static bool
   1205 type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
   1206 	UNUSED(update_rr);
   1207 	return ((db_rr->type != dns_rdatatype_rrsig &&
   1208 		 db_rr->type != dns_rdatatype_nsec) ?
   1209 		true : false);
   1210 }
   1211 
   1212 /*%
   1213  * Return true always.
   1214  */
   1215 static bool
   1216 true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
   1217 	UNUSED(update_rr);
   1218 	UNUSED(db_rr);
   1219 	return (true);
   1220 }
   1221 
   1222 /*%
   1223  * Return true iff the two RRs have identical rdata.
   1224  */
   1225 static bool
   1226 rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
   1227 	/*
   1228 	 * XXXRTH  This is not a problem, but we should consider creating
   1229 	 *         dns_rdata_equal() (that used dns_name_equal()), since it
   1230 	 *         would be faster.  Not a priority.
   1231 	 */
   1232 	return (dns_rdata_casecompare(update_rr, db_rr) == 0 ?
   1233 		true : false);
   1234 }
   1235 
   1236 /*%
   1237  * Return true iff 'update_rr' should replace 'db_rr' according
   1238  * to the special RFC2136 rules for CNAME, SOA, and WKS records.
   1239  *
   1240  * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
   1241  * make little sense, so we replace those, too.
   1242  *
   1243  * Additionally replace RRSIG that have been generated by the same key
   1244  * for the same type.  This simplifies refreshing a offline KSK by not
   1245  * requiring that the old RRSIG be deleted.  It also simplifies key
   1246  * rollover by only requiring that the new RRSIG be added.
   1247  */
   1248 static bool
   1249 replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
   1250 	dns_rdata_rrsig_t updatesig, dbsig;
   1251 	isc_result_t result;
   1252 
   1253 	if (db_rr->type != update_rr->type)
   1254 		return (false);
   1255 	if (db_rr->type == dns_rdatatype_cname)
   1256 		return (true);
   1257 	if (db_rr->type == dns_rdatatype_dname)
   1258 		return (true);
   1259 	if (db_rr->type == dns_rdatatype_soa)
   1260 		return (true);
   1261 	if (db_rr->type == dns_rdatatype_nsec)
   1262 		return (true);
   1263 	if (db_rr->type == dns_rdatatype_rrsig) {
   1264 		/*
   1265 		 * Replace existing RRSIG with the same keyid,
   1266 		 * covered and algorithm.
   1267 		 */
   1268 		result = dns_rdata_tostruct(db_rr, &dbsig, NULL);
   1269 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1270 		result = dns_rdata_tostruct(update_rr, &updatesig, NULL);
   1271 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1272 		if (dbsig.keyid == updatesig.keyid &&
   1273 		    dbsig.covered == updatesig.covered &&
   1274 		    dbsig.algorithm == updatesig.algorithm)
   1275 			return (true);
   1276 	}
   1277 	if (db_rr->type == dns_rdatatype_wks) {
   1278 		/*
   1279 		 * Compare the address and protocol fields only.  These
   1280 		 * form the first five bytes of the RR data.  Do a
   1281 		 * raw binary comparison; unpacking the WKS RRs using
   1282 		 * dns_rdata_tostruct() might be cleaner in some ways.
   1283 		 */
   1284 		INSIST(db_rr->length >= 5 && update_rr->length >= 5);
   1285 		return (memcmp(db_rr->data, update_rr->data, 5) == 0 ?
   1286 			true : false);
   1287 	}
   1288 
   1289 	if (db_rr->type == dns_rdatatype_nsec3param) {
   1290 		if (db_rr->length != update_rr->length)
   1291 			return (false);
   1292 		INSIST(db_rr->length >= 4 && update_rr->length >= 4);
   1293 		/*
   1294 		 * Replace NSEC3PARAM records that only differ by the
   1295 		 * flags field.
   1296 		 */
   1297 		if (db_rr->data[0] == update_rr->data[0] &&
   1298 		    memcmp(db_rr->data+2, update_rr->data+2,
   1299 			   update_rr->length - 2) == 0)
   1300 			return (true);
   1301 	}
   1302 	return (false);
   1303 }
   1304 
   1305 /*%
   1306  * Internal helper function for delete_if().
   1307  */
   1308 static isc_result_t
   1309 delete_if_action(void *data, rr_t *rr) {
   1310 	conditional_delete_ctx_t *ctx = data;
   1311 	if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
   1312 		isc_result_t result;
   1313 		result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
   1314 				       DNS_DIFFOP_DEL, ctx->name,
   1315 				       rr->ttl, &rr->rdata);
   1316 		return (result);
   1317 	} else {
   1318 		return (ISC_R_SUCCESS);
   1319 	}
   1320 }
   1321 
   1322 /*%
   1323  * Conditionally delete RRs.  Apply 'predicate' to the RRs
   1324  * specified by 'db', 'ver', 'name', and 'type' (which can
   1325  * be dns_rdatatype_any to match any type).  Delete those
   1326  * RRs for which the predicate returns true, and log the
   1327  * deletions in 'diff'.
   1328  */
   1329 static isc_result_t
   1330 delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
   1331 	  dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
   1332 	  dns_rdata_t *update_rr, dns_diff_t *diff)
   1333 {
   1334 	conditional_delete_ctx_t ctx;
   1335 	ctx.predicate = predicate;
   1336 	ctx.db = db;
   1337 	ctx.ver = ver;
   1338 	ctx.diff = diff;
   1339 	ctx.name = name;
   1340 	ctx.update_rr = update_rr;
   1341 	return (foreach_rr(db, ver, name, type, covers,
   1342 			   delete_if_action, &ctx));
   1343 }
   1344 
   1345 /**************************************************************************/
   1346 
   1347 static isc_result_t
   1348 add_rr_prepare_action(void *data, rr_t *rr) {
   1349 	isc_result_t result = ISC_R_SUCCESS;
   1350 	add_rr_prepare_ctx_t *ctx = data;
   1351 	dns_difftuple_t *tuple = NULL;
   1352 	bool equal, case_equal, ttl_equal;
   1353 
   1354 	/*
   1355 	 * Are the new and old cases equal?
   1356 	 */
   1357 	case_equal = dns_name_caseequal(ctx->name, ctx->oldname);
   1358 
   1359 	/*
   1360 	 * Are the ttl's equal?
   1361 	 */
   1362 	ttl_equal = rr->ttl == ctx->update_rr_ttl;
   1363 
   1364 	/*
   1365 	 * If the update RR is a "duplicate" of a existing RR,
   1366 	 * the update should be silently ignored.
   1367 	 */
   1368 	equal = (dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0);
   1369 	if (equal && case_equal && ttl_equal) {
   1370 		ctx->ignore_add = true;
   1371 		return (ISC_R_SUCCESS);
   1372 	}
   1373 
   1374 	/*
   1375 	 * If this RR is "equal" to the update RR, it should
   1376 	 * be deleted before the update RR is added.
   1377 	 */
   1378 	if (replaces_p(ctx->update_rr, &rr->rdata)) {
   1379 		CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
   1380 					   ctx->oldname, rr->ttl, &rr->rdata,
   1381 					   &tuple));
   1382 		dns_diff_append(&ctx->del_diff, &tuple);
   1383 		return (ISC_R_SUCCESS);
   1384 	}
   1385 
   1386 	/*
   1387 	 * If this RR differs in TTL or case from the update RR,
   1388 	 * its TTL and case must be adjusted.
   1389 	 */
   1390 	if (!ttl_equal || !case_equal) {
   1391 		CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
   1392 					   ctx->oldname, rr->ttl, &rr->rdata,
   1393 					   &tuple));
   1394 		dns_diff_append(&ctx->del_diff, &tuple);
   1395 		if (!equal) {
   1396 			CHECK(dns_difftuple_create(ctx->add_diff.mctx,
   1397 						   DNS_DIFFOP_ADD, ctx->name,
   1398 						   ctx->update_rr_ttl,
   1399 						   &rr->rdata, &tuple));
   1400 			dns_diff_append(&ctx->add_diff, &tuple);
   1401 		}
   1402 	}
   1403  failure:
   1404 	return (result);
   1405 }
   1406 
   1407 /**************************************************************************/
   1408 /*
   1409  * Miscellaneous subroutines.
   1410  */
   1411 
   1412 /*%
   1413  * Extract a single update RR from 'section' of dynamic update message
   1414  * 'msg', with consistency checking.
   1415  *
   1416  * Stores the owner name, rdata, and TTL of the update RR at 'name',
   1417  * 'rdata', and 'ttl', respectively.
   1418  */
   1419 static void
   1420 get_current_rr(dns_message_t *msg, dns_section_t section,
   1421 	       dns_rdataclass_t zoneclass, dns_name_t **name,
   1422 	       dns_rdata_t *rdata, dns_rdatatype_t *covers,
   1423 	       dns_ttl_t *ttl, dns_rdataclass_t *update_class)
   1424 {
   1425 	dns_rdataset_t *rdataset;
   1426 	isc_result_t result;
   1427 	dns_message_currentname(msg, section, name);
   1428 	rdataset = ISC_LIST_HEAD((*name)->list);
   1429 	INSIST(rdataset != NULL);
   1430 	INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
   1431 	*covers = rdataset->covers;
   1432 	*ttl = rdataset->ttl;
   1433 	result = dns_rdataset_first(rdataset);
   1434 	INSIST(result == ISC_R_SUCCESS);
   1435 	dns_rdataset_current(rdataset, rdata);
   1436 	INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
   1437 	*update_class = rdata->rdclass;
   1438 	rdata->rdclass = zoneclass;
   1439 }
   1440 
   1441 /*%
   1442  * Increment the SOA serial number of database 'db', version 'ver'.
   1443  * Replace the SOA record in the database, and log the
   1444  * change in 'diff'.
   1445  */
   1446 
   1447 	/*
   1448 	 * XXXRTH  Failures in this routine will be worth logging, when
   1449 	 *         we have a logging system.  Failure to find the zonename
   1450 	 *	   or the SOA rdataset warrant at least an UNEXPECTED_ERROR().
   1451 	 */
   1452 
   1453 static isc_result_t
   1454 update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
   1455 		  isc_mem_t *mctx, dns_updatemethod_t method)
   1456 {
   1457 	dns_difftuple_t *deltuple = NULL;
   1458 	dns_difftuple_t *addtuple = NULL;
   1459 	uint32_t serial;
   1460 	isc_result_t result;
   1461 
   1462 	CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
   1463 	CHECK(dns_difftuple_copy(deltuple, &addtuple));
   1464 	addtuple->op = DNS_DIFFOP_ADD;
   1465 
   1466 	serial = dns_soa_getserial(&addtuple->rdata);
   1467 	serial = dns_update_soaserial(serial, method);
   1468 	dns_soa_setserial(serial, &addtuple->rdata);
   1469 	CHECK(do_one_tuple(&deltuple, db, ver, diff));
   1470 	CHECK(do_one_tuple(&addtuple, db, ver, diff));
   1471 	result = ISC_R_SUCCESS;
   1472 
   1473  failure:
   1474 	if (addtuple != NULL)
   1475 		dns_difftuple_free(&addtuple);
   1476 	if (deltuple != NULL)
   1477 		dns_difftuple_free(&deltuple);
   1478 	return (result);
   1479 }
   1480 
   1481 /*%
   1482  * Check that the new SOA record at 'update_rdata' does not
   1483  * illegally cause the SOA serial number to decrease or stay
   1484  * unchanged relative to the existing SOA in 'db'.
   1485  *
   1486  * Sets '*ok' to true if the update is legal, false if not.
   1487  *
   1488  * William King points out that RFC2136 is inconsistent about
   1489  * the case where the serial number stays unchanged:
   1490  *
   1491  *   section 3.4.2.2 requires a server to ignore a SOA update request
   1492  *   if the serial number on the update SOA is less_than_or_equal to
   1493  *   the zone SOA serial.
   1494  *
   1495  *   section 3.6 requires a server to ignore a SOA update request if
   1496  *   the serial is less_than the zone SOA serial.
   1497  *
   1498  * Paul says 3.4.2.2 is correct.
   1499  *
   1500  */
   1501 static isc_result_t
   1502 check_soa_increment(dns_db_t *db, dns_dbversion_t *ver,
   1503 		    dns_rdata_t *update_rdata, bool *ok)
   1504 {
   1505 	uint32_t db_serial;
   1506 	uint32_t update_serial;
   1507 	isc_result_t result;
   1508 
   1509 	update_serial = dns_soa_getserial(update_rdata);
   1510 
   1511 	result = dns_db_getsoaserial(db, ver, &db_serial);
   1512 	if (result != ISC_R_SUCCESS)
   1513 		return (result);
   1514 
   1515 	if (DNS_SERIAL_GE(db_serial, update_serial)) {
   1516 		*ok = false;
   1517 	} else {
   1518 		*ok = true;
   1519 	}
   1520 
   1521 	return (ISC_R_SUCCESS);
   1522 
   1523 }
   1524 
   1525 /**************************************************************************/
   1526 /*%
   1527  * The actual update code in all its glory.  We try to follow
   1528  * the RFC2136 pseudocode as closely as possible.
   1529  */
   1530 
   1531 static isc_result_t
   1532 send_update_event(ns_client_t *client, dns_zone_t *zone) {
   1533 	isc_result_t result = ISC_R_SUCCESS;
   1534 	update_event_t *event = NULL;
   1535 	isc_task_t *zonetask = NULL;
   1536 	ns_client_t *evclient;
   1537 
   1538 	event = (update_event_t *)
   1539 		isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
   1540 				   update_action, NULL, sizeof(*event));
   1541 	if (event == NULL)
   1542 		FAIL(ISC_R_NOMEMORY);
   1543 	event->zone = zone;
   1544 	event->result = ISC_R_SUCCESS;
   1545 
   1546 	evclient = NULL;
   1547 	ns_client_attach(client, &evclient);
   1548 	INSIST(client->nupdates == 0);
   1549 	client->nupdates++;
   1550 	event->ev_arg = evclient;
   1551 
   1552 	dns_zone_gettask(zone, &zonetask);
   1553 	isc_task_send(zonetask, ISC_EVENT_PTR(&event));
   1554 
   1555  failure:
   1556 	if (event != NULL)
   1557 		isc_event_free(ISC_EVENT_PTR(&event));
   1558 	return (result);
   1559 }
   1560 
   1561 static void
   1562 respond(ns_client_t *client, isc_result_t result) {
   1563 	isc_result_t msg_result;
   1564 
   1565 	msg_result = dns_message_reply(client->message, true);
   1566 	if (msg_result != ISC_R_SUCCESS)
   1567 		goto msg_failure;
   1568 	client->message->rcode = dns_result_torcode(result);
   1569 
   1570 	ns_client_send(client);
   1571 	return;
   1572 
   1573  msg_failure:
   1574 	isc_log_write(ns_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
   1575 		      ISC_LOG_ERROR,
   1576 		      "could not create update response message: %s",
   1577 		      isc_result_totext(msg_result));
   1578 	ns_client_next(client, msg_result);
   1579 }
   1580 
   1581 void
   1582 ns_update_start(ns_client_t *client, isc_result_t sigresult) {
   1583 	dns_message_t *request = client->message;
   1584 	isc_result_t result;
   1585 	dns_name_t *zonename;
   1586 	dns_rdataset_t *zone_rdataset;
   1587 	dns_zone_t *zone = NULL, *raw = NULL;
   1588 
   1589 	/*
   1590 	 * Interpret the zone section.
   1591 	 */
   1592 	result = dns_message_firstname(request, DNS_SECTION_ZONE);
   1593 	if (result != ISC_R_SUCCESS)
   1594 		FAILC(DNS_R_FORMERR, "update zone section empty");
   1595 
   1596 	/*
   1597 	 * The zone section must contain exactly one "question", and
   1598 	 * it must be of type SOA.
   1599 	 */
   1600 	zonename = NULL;
   1601 	dns_message_currentname(request, DNS_SECTION_ZONE, &zonename);
   1602 	zone_rdataset = ISC_LIST_HEAD(zonename->list);
   1603 	if (zone_rdataset->type != dns_rdatatype_soa)
   1604 		FAILC(DNS_R_FORMERR,
   1605 		      "update zone section contains non-SOA");
   1606 	if (ISC_LIST_NEXT(zone_rdataset, link) != NULL)
   1607 		FAILC(DNS_R_FORMERR,
   1608 		      "update zone section contains multiple RRs");
   1609 
   1610 	/* The zone section must have exactly one name. */
   1611 	result = dns_message_nextname(request, DNS_SECTION_ZONE);
   1612 	if (result != ISC_R_NOMORE)
   1613 		FAILC(DNS_R_FORMERR,
   1614 		      "update zone section contains multiple RRs");
   1615 
   1616 	result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
   1617 			     &zone);
   1618 	if (result != ISC_R_SUCCESS)
   1619 		FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
   1620 
   1621 	/*
   1622 	 * If there is a raw (unsigned) zone associated with this
   1623 	 * zone then it processes the UPDATE request.
   1624 	 */
   1625 	dns_zone_getraw(zone, &raw);
   1626 	if (raw != NULL) {
   1627 		dns_zone_detach(&zone);
   1628 		dns_zone_attach(raw, &zone);
   1629 		dns_zone_detach(&raw);
   1630 	}
   1631 
   1632 	switch(dns_zone_gettype(zone)) {
   1633 	case dns_zone_master:
   1634 	case dns_zone_dlz:
   1635 		/*
   1636 		 * We can now fail due to a bad signature as we now know
   1637 		 * that we are the master.
   1638 		 */
   1639 		if (sigresult != ISC_R_SUCCESS)
   1640 			FAIL(sigresult);
   1641 		CHECK(send_update_event(client, zone));
   1642 		break;
   1643 	case dns_zone_slave:
   1644 	case dns_zone_mirror:
   1645 		CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
   1646 				     "update forwarding", zonename, true,
   1647 				     false));
   1648 		CHECK(send_forward_event(client, zone));
   1649 		break;
   1650 	default:
   1651 		FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
   1652 	}
   1653 	return;
   1654 
   1655  failure:
   1656 	if (result == DNS_R_REFUSED) {
   1657 		INSIST(dns_zone_gettype(zone) == dns_zone_slave ||
   1658 		       dns_zone_gettype(zone) == dns_zone_mirror);
   1659 		inc_stats(client, zone, ns_statscounter_updaterej);
   1660 	}
   1661 	/*
   1662 	 * We failed without having sent an update event to the zone.
   1663 	 * We are still in the client task context, so we can
   1664 	 * simply give an error response without switching tasks.
   1665 	 */
   1666 	respond(client, result);
   1667 	if (zone != NULL)
   1668 		dns_zone_detach(&zone);
   1669 }
   1670 
   1671 /*%
   1672  * DS records are not allowed to exist without corresponding NS records,
   1673  * RFC 3658, 2.2 Protocol Change,
   1674  * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
   1675  */
   1676 
   1677 static isc_result_t
   1678 remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) {
   1679 	isc_result_t result;
   1680 	bool ns_exists;
   1681 	dns_difftuple_t *tupple;
   1682 	dns_diff_t temp_diff;
   1683 
   1684 	dns_diff_init(diff->mctx, &temp_diff);
   1685 
   1686 	for (tupple = ISC_LIST_HEAD(diff->tuples);
   1687 	     tupple != NULL;
   1688 	     tupple = ISC_LIST_NEXT(tupple, link)) {
   1689 		if (!((tupple->op == DNS_DIFFOP_DEL &&
   1690 		       tupple->rdata.type == dns_rdatatype_ns) ||
   1691 		      (tupple->op == DNS_DIFFOP_ADD &&
   1692 		       tupple->rdata.type == dns_rdatatype_ds)))
   1693 			continue;
   1694 		CHECK(rrset_exists(db, newver, &tupple->name,
   1695 				   dns_rdatatype_ns, 0, &ns_exists));
   1696 		if (ns_exists &&
   1697 		    !dns_name_equal(&tupple->name, dns_db_origin(db)))
   1698 			continue;
   1699 		CHECK(delete_if(true_p, db, newver, &tupple->name,
   1700 				dns_rdatatype_ds, 0, NULL, &temp_diff));
   1701 	}
   1702 	result = ISC_R_SUCCESS;
   1703 
   1704  failure:
   1705 	for (tupple = ISC_LIST_HEAD(temp_diff.tuples);
   1706 	     tupple != NULL;
   1707 	     tupple = ISC_LIST_HEAD(temp_diff.tuples)) {
   1708 		ISC_LIST_UNLINK(temp_diff.tuples, tupple, link);
   1709 		dns_diff_appendminimal(diff, &tupple);
   1710 	}
   1711 	return (result);
   1712 }
   1713 
   1714 /*
   1715  * This implements the post load integrity checks for mx records.
   1716  */
   1717 static isc_result_t
   1718 check_mx(ns_client_t *client, dns_zone_t *zone,
   1719 	 dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff)
   1720 {
   1721 	char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
   1722 	char ownerbuf[DNS_NAME_FORMATSIZE];
   1723 	char namebuf[DNS_NAME_FORMATSIZE];
   1724 	char altbuf[DNS_NAME_FORMATSIZE];
   1725 	dns_difftuple_t *t;
   1726 	dns_fixedname_t fixed;
   1727 	dns_name_t *foundname;
   1728 	dns_rdata_mx_t mx;
   1729 	dns_rdata_t rdata;
   1730 	bool ok = true;
   1731 	bool isaddress;
   1732 	isc_result_t result;
   1733 	struct in6_addr addr6;
   1734 	struct in_addr addr;
   1735 	dns_zoneopt_t options;
   1736 
   1737 	foundname = dns_fixedname_initname(&fixed);
   1738 	dns_rdata_init(&rdata);
   1739 	options = dns_zone_getoptions(zone);
   1740 
   1741 	for (t = ISC_LIST_HEAD(diff->tuples);
   1742 	     t != NULL;
   1743 	     t = ISC_LIST_NEXT(t, link)) {
   1744 		if (t->op != DNS_DIFFOP_ADD ||
   1745 		    t->rdata.type != dns_rdatatype_mx)
   1746 			continue;
   1747 
   1748 		result = dns_rdata_tostruct(&t->rdata, &mx, NULL);
   1749 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1750 		/*
   1751 		 * Check if we will error out if we attempt to reload the
   1752 		 * zone.
   1753 		 */
   1754 		dns_name_format(&mx.mx, namebuf, sizeof(namebuf));
   1755 		dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf));
   1756 		isaddress = false;
   1757 		if ((options & DNS_ZONEOPT_CHECKMX) != 0 &&
   1758 		    strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) {
   1759 			if (tmp[strlen(tmp) - 1] == '.')
   1760 				tmp[strlen(tmp) - 1] = '\0';
   1761 			if (inet_pton(AF_INET, tmp, &addr) == 1 ||
   1762 			    inet_pton(AF_INET6, tmp, &addr6) == 1)
   1763 				isaddress = true;
   1764 		}
   1765 
   1766 		if (isaddress && (options & DNS_ZONEOPT_CHECKMXFAIL) != 0) {
   1767 			update_log(client, zone, ISC_LOG_ERROR,
   1768 				   "%s/MX: '%s': %s",
   1769 				   ownerbuf, namebuf,
   1770 				   dns_result_totext(DNS_R_MXISADDRESS));
   1771 			ok = false;
   1772 		} else if (isaddress) {
   1773 			update_log(client, zone, ISC_LOG_WARNING,
   1774 				   "%s/MX: warning: '%s': %s",
   1775 				   ownerbuf, namebuf,
   1776 				   dns_result_totext(DNS_R_MXISADDRESS));
   1777 		}
   1778 
   1779 		/*
   1780 		 * Check zone integrity checks.
   1781 		 */
   1782 		if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0)
   1783 			continue;
   1784 		result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a,
   1785 				     0, 0, NULL, foundname, NULL, NULL);
   1786 		if (result == ISC_R_SUCCESS)
   1787 			continue;
   1788 
   1789 		if (result == DNS_R_NXRRSET) {
   1790 			result = dns_db_find(db, &mx.mx, newver,
   1791 					     dns_rdatatype_aaaa,
   1792 					     0, 0, NULL, foundname,
   1793 					     NULL, NULL);
   1794 			if (result == ISC_R_SUCCESS)
   1795 				continue;
   1796 		}
   1797 
   1798 		if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
   1799 			update_log(client, zone, ISC_LOG_ERROR,
   1800 				   "%s/MX '%s' has no address records "
   1801 				   "(A or AAAA)", ownerbuf, namebuf);
   1802 			ok = false;
   1803 		} else if (result == DNS_R_CNAME) {
   1804 			update_log(client, zone, ISC_LOG_ERROR,
   1805 				   "%s/MX '%s' is a CNAME (illegal)",
   1806 				   ownerbuf, namebuf);
   1807 			ok = false;
   1808 		} else if (result == DNS_R_DNAME) {
   1809 			dns_name_format(foundname, altbuf, sizeof altbuf);
   1810 			update_log(client, zone, ISC_LOG_ERROR,
   1811 				   "%s/MX '%s' is below a DNAME '%s' (illegal)",
   1812 				   ownerbuf, namebuf, altbuf);
   1813 			ok = false;
   1814 		}
   1815 	}
   1816 	return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
   1817 }
   1818 
   1819 static isc_result_t
   1820 rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
   1821 	  const dns_rdata_t *rdata, bool *flag)
   1822 {
   1823 	dns_rdataset_t rdataset;
   1824 	dns_dbnode_t *node = NULL;
   1825 	isc_result_t result;
   1826 
   1827 	dns_rdataset_init(&rdataset);
   1828 	if (rdata->type == dns_rdatatype_nsec3)
   1829 		CHECK(dns_db_findnsec3node(db, name, false, &node));
   1830 	else
   1831 		CHECK(dns_db_findnode(db, name, false, &node));
   1832 	result = dns_db_findrdataset(db, node, ver, rdata->type, 0,
   1833 				     (isc_stdtime_t) 0, &rdataset, NULL);
   1834 	if (result == ISC_R_NOTFOUND) {
   1835 		*flag = false;
   1836 		result = ISC_R_SUCCESS;
   1837 		goto failure;
   1838 	}
   1839 
   1840 	for (result = dns_rdataset_first(&rdataset);
   1841 	     result == ISC_R_SUCCESS;
   1842 	     result = dns_rdataset_next(&rdataset)) {
   1843 		dns_rdata_t myrdata = DNS_RDATA_INIT;
   1844 		dns_rdataset_current(&rdataset, &myrdata);
   1845 		if (!dns_rdata_casecompare(&myrdata, rdata))
   1846 			break;
   1847 	}
   1848 	dns_rdataset_disassociate(&rdataset);
   1849 	if (result == ISC_R_SUCCESS) {
   1850 		*flag = true;
   1851 	} else if (result == ISC_R_NOMORE) {
   1852 		*flag = false;
   1853 		result = ISC_R_SUCCESS;
   1854 	}
   1855 
   1856  failure:
   1857 	if (node != NULL)
   1858 		dns_db_detachnode(db, &node);
   1859 	return (result);
   1860 }
   1861 
   1862 static isc_result_t
   1863 get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype,
   1864 	       unsigned int *iterationsp)
   1865 {
   1866 	dns_dbnode_t *node = NULL;
   1867 	dns_rdata_nsec3param_t nsec3param;
   1868 	dns_rdataset_t rdataset;
   1869 	isc_result_t result;
   1870 	unsigned int iterations = 0;
   1871 
   1872 	dns_rdataset_init(&rdataset);
   1873 
   1874 	result = dns_db_getoriginnode(db, &node);
   1875 	if (result != ISC_R_SUCCESS)
   1876 		return (result);
   1877 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
   1878 				     0, (isc_stdtime_t) 0, &rdataset, NULL);
   1879 	if (result == ISC_R_NOTFOUND)
   1880 		goto try_private;
   1881 	if (result != ISC_R_SUCCESS)
   1882 		goto failure;
   1883 
   1884 	for (result = dns_rdataset_first(&rdataset);
   1885 	     result == ISC_R_SUCCESS;
   1886 	     result = dns_rdataset_next(&rdataset)) {
   1887 		dns_rdata_t rdata = DNS_RDATA_INIT;
   1888 		dns_rdataset_current(&rdataset, &rdata);
   1889 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
   1890 		if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
   1891 			continue;
   1892 		if (nsec3param.iterations > iterations)
   1893 			iterations = nsec3param.iterations;
   1894 	}
   1895 	if (result != ISC_R_NOMORE)
   1896 		goto failure;
   1897 
   1898 	dns_rdataset_disassociate(&rdataset);
   1899 
   1900  try_private:
   1901 	if (privatetype == 0)
   1902 		goto success;
   1903 
   1904 	result = dns_db_findrdataset(db, node, ver, privatetype,
   1905 				     0, (isc_stdtime_t) 0, &rdataset, NULL);
   1906 	if (result == ISC_R_NOTFOUND)
   1907 		goto success;
   1908 	if (result != ISC_R_SUCCESS)
   1909 		goto failure;
   1910 
   1911 	for (result = dns_rdataset_first(&rdataset);
   1912 	     result == ISC_R_SUCCESS;
   1913 	     result = dns_rdataset_next(&rdataset)) {
   1914 		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
   1915 		dns_rdata_t private = DNS_RDATA_INIT;
   1916 		dns_rdata_t rdata = DNS_RDATA_INIT;
   1917 
   1918 		dns_rdataset_current(&rdataset, &rdata);
   1919 		if (!dns_nsec3param_fromprivate(&private, &rdata,
   1920 						buf, sizeof(buf)))
   1921 			continue;
   1922 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
   1923 		if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
   1924 			continue;
   1925 		if (nsec3param.iterations > iterations)
   1926 			iterations = nsec3param.iterations;
   1927 	}
   1928 	if (result != ISC_R_NOMORE)
   1929 		goto failure;
   1930 
   1931  success:
   1932 	*iterationsp = iterations;
   1933 	result = ISC_R_SUCCESS;
   1934 
   1935  failure:
   1936 	if (node != NULL)
   1937 		dns_db_detachnode(db, &node);
   1938 	if (dns_rdataset_isassociated(&rdataset))
   1939 		dns_rdataset_disassociate(&rdataset);
   1940 	return (result);
   1941 }
   1942 
   1943 /*
   1944  * Prevent the zone entering a inconsistent state where
   1945  * NSEC only DNSKEYs are present with NSEC3 chains.
   1946  */
   1947 static isc_result_t
   1948 check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
   1949 	     dns_dbversion_t *ver, dns_diff_t *diff)
   1950 {
   1951 	dns_difftuple_t *tuple;
   1952 	bool nseconly = false, nsec3 = false;
   1953 	isc_result_t result;
   1954 	unsigned int iterations = 0, max;
   1955 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
   1956 
   1957 	/* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */
   1958 	for (tuple = ISC_LIST_HEAD(diff->tuples);
   1959 	     tuple != NULL;
   1960 	     tuple = ISC_LIST_NEXT(tuple, link)) {
   1961 		if (tuple->op != DNS_DIFFOP_ADD)
   1962 			continue;
   1963 
   1964 		if (tuple->rdata.type == dns_rdatatype_dnskey) {
   1965 			uint8_t alg;
   1966 			alg = tuple->rdata.data[3];
   1967 			if (alg == DST_ALG_RSASHA1) {
   1968 				nseconly = true;
   1969 				break;
   1970 			}
   1971 		} else if (tuple->rdata.type == dns_rdatatype_nsec3param) {
   1972 			nsec3 = true;
   1973 			break;
   1974 		}
   1975 	}
   1976 
   1977 	/* Check existing DB for NSEC-only DNSKEY */
   1978 	if (!nseconly) {
   1979 		result = dns_nsec_nseconly(db, ver, &nseconly);
   1980 
   1981 		/*
   1982 		 * An NSEC3PARAM update can proceed without a DNSKEY (it
   1983 		 * will trigger a delayed change), so we can ignore
   1984 		 * ISC_R_NOTFOUND here.
   1985 		 */
   1986 		if (result == ISC_R_NOTFOUND)
   1987 			result = ISC_R_SUCCESS;
   1988 
   1989 		CHECK(result);
   1990 	}
   1991 
   1992 	/* Check existing DB for NSEC3 */
   1993 	if (!nsec3)
   1994 		CHECK(dns_nsec3_activex(db, ver, false,
   1995 					privatetype, &nsec3));
   1996 
   1997 	/* Refuse to allow NSEC3 with NSEC-only keys */
   1998 	if (nseconly && nsec3) {
   1999 		update_log(client, zone, ISC_LOG_ERROR,
   2000 			   "NSEC only DNSKEYs and NSEC3 chains not allowed");
   2001 		result = DNS_R_REFUSED;
   2002 		goto failure;
   2003 	}
   2004 
   2005 	/* Verify NSEC3 params */
   2006 	CHECK(get_iterations(db, ver, privatetype, &iterations));
   2007 	CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
   2008 	if (max != 0 && iterations > max) {
   2009 		update_log(client, zone, ISC_LOG_ERROR,
   2010 			   "too many NSEC3 iterations (%u) for "
   2011 			   "weakest DNSKEY (%u)", iterations, max);
   2012 		result = DNS_R_REFUSED;
   2013 		goto failure;
   2014 	}
   2015 
   2016  failure:
   2017 	return (result);
   2018 }
   2019 
   2020 /*
   2021  * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
   2022  */
   2023 static isc_result_t
   2024 add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
   2025 		       dns_dbversion_t *ver, dns_diff_t *diff)
   2026 {
   2027 	isc_result_t result = ISC_R_SUCCESS;
   2028 	dns_difftuple_t *tuple, *newtuple = NULL, *next;
   2029 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2030 	unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1];
   2031 	dns_diff_t temp_diff;
   2032 	dns_diffop_t op;
   2033 	bool flag;
   2034 	dns_name_t *name = dns_zone_getorigin(zone);
   2035 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
   2036 	uint32_t ttl = 0;
   2037 	bool ttl_good = false;
   2038 
   2039 	update_log(client, zone, ISC_LOG_DEBUG(3),
   2040 		    "checking for NSEC3PARAM changes");
   2041 
   2042 	dns_diff_init(diff->mctx, &temp_diff);
   2043 
   2044 	/*
   2045 	 * Extract NSEC3PARAM tuples from list.
   2046 	 */
   2047 	for (tuple = ISC_LIST_HEAD(diff->tuples);
   2048 	     tuple != NULL;
   2049 	     tuple = next) {
   2050 
   2051 		next = ISC_LIST_NEXT(tuple, link);
   2052 
   2053 		if (tuple->rdata.type != dns_rdatatype_nsec3param ||
   2054 		    !dns_name_equal(name, &tuple->name))
   2055 			continue;
   2056 		ISC_LIST_UNLINK(diff->tuples, tuple, link);
   2057 		ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
   2058 	}
   2059 
   2060 	/*
   2061 	 * Extract TTL changes pairs, we don't need to convert these to
   2062 	 * delayed changes.
   2063 	 */
   2064 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
   2065 	     tuple != NULL; tuple = next) {
   2066 		if (tuple->op == DNS_DIFFOP_ADD) {
   2067 			if (!ttl_good) {
   2068 				/*
   2069 				 * Any adds here will contain the final
   2070 				 * NSEC3PARAM RRset TTL.
   2071 				 */
   2072 				ttl = tuple->ttl;
   2073 				ttl_good = true;
   2074 			}
   2075 			/*
   2076 			 * Walk the temp_diff list looking for the
   2077 			 * corresponding delete.
   2078 			 */
   2079 			next = ISC_LIST_HEAD(temp_diff.tuples);
   2080 			while (next != NULL) {
   2081 				unsigned char *next_data = next->rdata.data;
   2082 				unsigned char *tuple_data = tuple->rdata.data;
   2083 				if (next->op == DNS_DIFFOP_DEL &&
   2084 				    next->rdata.length == tuple->rdata.length &&
   2085 				    !memcmp(next_data, tuple_data,
   2086 					    next->rdata.length)) {
   2087 					ISC_LIST_UNLINK(temp_diff.tuples, next,
   2088 							link);
   2089 					ISC_LIST_APPEND(diff->tuples, next,
   2090 							link);
   2091 					break;
   2092 				}
   2093 				next = ISC_LIST_NEXT(next, link);
   2094 			}
   2095 			/*
   2096 			 * If we have not found a pair move onto the next
   2097 			 * tuple.
   2098 			 */
   2099 			if (next == NULL) {
   2100 				next = ISC_LIST_NEXT(tuple, link);
   2101 				continue;
   2102 			}
   2103 			/*
   2104 			 * Find the next tuple to be processed before
   2105 			 * unlinking then complete moving the pair to 'diff'.
   2106 			 */
   2107 			next = ISC_LIST_NEXT(tuple, link);
   2108 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
   2109 			ISC_LIST_APPEND(diff->tuples, tuple, link);
   2110 		} else
   2111 			next = ISC_LIST_NEXT(tuple, link);
   2112 	}
   2113 
   2114 	/*
   2115 	 * Preserve any ongoing changes from a BIND 9.6.x upgrade.
   2116 	 *
   2117 	 * Any NSEC3PARAM records with flags other than OPTOUT named
   2118 	 * in managing and should not be touched so revert such changes
   2119 	 * taking into account any TTL change of the NSEC3PARAM RRset.
   2120 	 */
   2121 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
   2122 	     tuple != NULL; tuple = next) {
   2123 		next = ISC_LIST_NEXT(tuple, link);
   2124 		if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
   2125 			/*
   2126 			 * If we havn't had any adds then the tuple->ttl must
   2127 			 * be the original ttl and should be used for any
   2128 			 * future changes.
   2129 			 */
   2130 			if (!ttl_good) {
   2131 				ttl = tuple->ttl;
   2132 				ttl_good = true;
   2133 			}
   2134 			op = (tuple->op == DNS_DIFFOP_DEL) ?
   2135 			     DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
   2136 			CHECK(dns_difftuple_create(diff->mctx, op, name,
   2137 						   ttl, &tuple->rdata,
   2138 						   &newtuple));
   2139 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2140 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
   2141 			dns_diff_appendminimal(diff, &tuple);
   2142 		}
   2143 	}
   2144 
   2145 	/*
   2146 	 * We now have just the actual changes to the NSEC3PARAM RRset.
   2147 	 * Convert the adds to delayed adds and the deletions into delayed
   2148 	 * deletions.
   2149 	 */
   2150 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
   2151 	     tuple != NULL; tuple = next) {
   2152 		/*
   2153 		 * If we havn't had any adds then the tuple->ttl must be the
   2154 		 * original ttl and should be used for any future changes.
   2155 		 */
   2156 		if (!ttl_good) {
   2157 			ttl = tuple->ttl;
   2158 			ttl_good = true;
   2159 		}
   2160 		if (tuple->op == DNS_DIFFOP_ADD) {
   2161 			bool nseconly = false;
   2162 
   2163 			/*
   2164 			 * Look for any deletes which match this ADD ignoring
   2165 			 * flags.  We don't need to explictly remove them as
   2166 			 * they will be removed a side effect of processing
   2167 			 * the add.
   2168 			 */
   2169 			next = ISC_LIST_HEAD(temp_diff.tuples);
   2170 			while (next != NULL) {
   2171 				unsigned char *next_data = next->rdata.data;
   2172 				unsigned char *tuple_data = tuple->rdata.data;
   2173 				if (next->op != DNS_DIFFOP_DEL ||
   2174 				    next->rdata.length != tuple->rdata.length ||
   2175 				    next_data[0] != tuple_data[0] ||
   2176 				    next_data[2] != tuple_data[2] ||
   2177 				    next_data[3] != tuple_data[3] ||
   2178 				    memcmp(next_data + 4, tuple_data + 4,
   2179 					   tuple->rdata.length - 4)) {
   2180 					next = ISC_LIST_NEXT(next, link);
   2181 					continue;
   2182 				}
   2183 				ISC_LIST_UNLINK(temp_diff.tuples, next, link);
   2184 				ISC_LIST_APPEND(diff->tuples, next, link);
   2185 				next = ISC_LIST_HEAD(temp_diff.tuples);
   2186 			}
   2187 
   2188 			/*
   2189 			 * Create a private-type record to signal that
   2190 			 * we want a delayed NSEC3 chain add/delete
   2191 			 */
   2192 			dns_nsec3param_toprivate(&tuple->rdata, &rdata,
   2193 						 privatetype, buf, sizeof(buf));
   2194 			buf[2] |= DNS_NSEC3FLAG_CREATE;
   2195 
   2196 			/*
   2197 			 * If the zone is not currently capable of
   2198 			 * supporting an NSEC3 chain, then we set the
   2199 			 * INITIAL flag to indicate that these parameters
   2200 			 * are to be used later.
   2201 			 */
   2202 			result = dns_nsec_nseconly(db, ver, &nseconly);
   2203 			if (result == ISC_R_NOTFOUND || nseconly)
   2204 				buf[2] |= DNS_NSEC3FLAG_INITIAL;
   2205 
   2206 			/*
   2207 			 * See if this CREATE request already exists.
   2208 			 */
   2209 			CHECK(rr_exists(db, ver, name, &rdata, &flag));
   2210 
   2211 			if (!flag) {
   2212 				CHECK(dns_difftuple_create(diff->mctx,
   2213 							   DNS_DIFFOP_ADD,
   2214 							   name, 0, &rdata,
   2215 							   &newtuple));
   2216 				CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2217 			}
   2218 
   2219 			/*
   2220 			 * Remove any existing CREATE request to add an
   2221 			 * otherwise indentical chain with a reversed
   2222 			 * OPTOUT state.
   2223 			 */
   2224 			buf[2] ^= DNS_NSEC3FLAG_OPTOUT;
   2225 			CHECK(rr_exists(db, ver, name, &rdata, &flag));
   2226 
   2227 			if (flag) {
   2228 				CHECK(dns_difftuple_create(diff->mctx,
   2229 							   DNS_DIFFOP_DEL,
   2230 							   name, 0, &rdata,
   2231 							   &newtuple));
   2232 				CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2233 			}
   2234 
   2235 			/*
   2236 			 * Find the next tuple to be processed and remove the
   2237 			 * temporary add record.
   2238 			 */
   2239 			next = ISC_LIST_NEXT(tuple, link);
   2240 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
   2241 						   name, ttl, &tuple->rdata,
   2242 						   &newtuple));
   2243 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2244 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
   2245 			dns_diff_appendminimal(diff, &tuple);
   2246 			dns_rdata_reset(&rdata);
   2247 		} else
   2248 			next = ISC_LIST_NEXT(tuple, link);
   2249 	}
   2250 
   2251 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
   2252 	     tuple != NULL; tuple = next) {
   2253 
   2254 		INSIST(ttl_good);
   2255 
   2256 		next = ISC_LIST_NEXT(tuple, link);
   2257 		/*
   2258 		 * See if we already have a REMOVE request in progress.
   2259 		 */
   2260 		dns_nsec3param_toprivate(&tuple->rdata, &rdata, privatetype,
   2261 					 buf, sizeof(buf));
   2262 
   2263 		buf[2] |= DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
   2264 
   2265 		CHECK(rr_exists(db, ver, name, &rdata, &flag));
   2266 		if (!flag) {
   2267 			buf[2] &= ~DNS_NSEC3FLAG_NONSEC;
   2268 			CHECK(rr_exists(db, ver, name, &rdata, &flag));
   2269 		}
   2270 
   2271 		if (!flag) {
   2272 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
   2273 						   name, 0, &rdata, &newtuple));
   2274 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2275 		}
   2276 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
   2277 					   ttl, &tuple->rdata, &newtuple));
   2278 		CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2279 		ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
   2280 		dns_diff_appendminimal(diff, &tuple);
   2281 		dns_rdata_reset(&rdata);
   2282 	}
   2283 
   2284 	result = ISC_R_SUCCESS;
   2285  failure:
   2286 	dns_diff_clear(&temp_diff);
   2287 	return (result);
   2288 }
   2289 
   2290 static isc_result_t
   2291 rollback_private(dns_db_t *db, dns_rdatatype_t privatetype,
   2292 		 dns_dbversion_t *ver, dns_diff_t *diff)
   2293 {
   2294 	dns_diff_t temp_diff;
   2295 	dns_diffop_t op;
   2296 	dns_difftuple_t *tuple, *newtuple = NULL, *next;
   2297 	dns_name_t *name = dns_db_origin(db);
   2298 	isc_mem_t *mctx = diff->mctx;
   2299 	isc_result_t result;
   2300 
   2301 	if (privatetype == 0)
   2302 		return (ISC_R_SUCCESS);
   2303 
   2304 	dns_diff_init(mctx, &temp_diff);
   2305 
   2306 	/*
   2307 	 * Extract the changes to be rolled back.
   2308 	 */
   2309 	for (tuple = ISC_LIST_HEAD(diff->tuples);
   2310 	     tuple != NULL; tuple = next) {
   2311 
   2312 		next = ISC_LIST_NEXT(tuple, link);
   2313 
   2314 		if (tuple->rdata.type != privatetype ||
   2315 		    !dns_name_equal(name, &tuple->name))
   2316 			continue;
   2317 
   2318 		/*
   2319 		 * Allow records which indicate that a zone has been
   2320 		 * signed with a DNSKEY to be removed.
   2321 		 */
   2322 		if (tuple->op == DNS_DIFFOP_DEL &&
   2323 		    tuple->rdata.length == 5 &&
   2324 		    tuple->rdata.data[0] != 0 &&
   2325 		    tuple->rdata.data[4] != 0)
   2326 			continue;
   2327 
   2328 		ISC_LIST_UNLINK(diff->tuples, tuple, link);
   2329 		ISC_LIST_PREPEND(temp_diff.tuples, tuple, link);
   2330 	}
   2331 
   2332 	/*
   2333 	 * Rollback the changes.
   2334 	 */
   2335 	while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) {
   2336 		op = (tuple->op == DNS_DIFFOP_DEL) ?
   2337 		      DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
   2338 		CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl,
   2339 					   &tuple->rdata, &newtuple));
   2340 		CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff));
   2341 	}
   2342 	result = ISC_R_SUCCESS;
   2343 
   2344  failure:
   2345 	dns_diff_clear(&temp_diff);
   2346 	return (result);
   2347 }
   2348 
   2349 /*
   2350  * Add records to cause the delayed signing of the zone by added DNSKEY
   2351  * to remove the RRSIG records generated by a deleted DNSKEY.
   2352  */
   2353 static isc_result_t
   2354 add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
   2355 		    dns_dbversion_t *ver, dns_diff_t *diff)
   2356 {
   2357 	dns_difftuple_t *tuple, *newtuple = NULL, *next;
   2358 	dns_rdata_dnskey_t dnskey;
   2359 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2360 	bool flag;
   2361 	isc_region_t r;
   2362 	isc_result_t result = ISC_R_SUCCESS;
   2363 	uint16_t keyid;
   2364 	unsigned char buf[5];
   2365 	dns_name_t *name = dns_db_origin(db);
   2366 	dns_diff_t temp_diff;
   2367 
   2368 	dns_diff_init(diff->mctx, &temp_diff);
   2369 
   2370 	/*
   2371 	 * Extract the DNSKEY tuples from the list.
   2372 	 */
   2373 	for (tuple = ISC_LIST_HEAD(diff->tuples);
   2374 	     tuple != NULL; tuple = next) {
   2375 
   2376 		next = ISC_LIST_NEXT(tuple, link);
   2377 
   2378 		if (tuple->rdata.type != dns_rdatatype_dnskey)
   2379 			continue;
   2380 
   2381 		ISC_LIST_UNLINK(diff->tuples, tuple, link);
   2382 		ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
   2383 	}
   2384 
   2385 	/*
   2386 	 * Extract TTL changes pairs, we don't need signing records for these.
   2387 	 */
   2388 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
   2389 	     tuple != NULL; tuple = next) {
   2390 		if (tuple->op == DNS_DIFFOP_ADD) {
   2391 			/*
   2392 			 * Walk the temp_diff list looking for the
   2393 			 * corresponding delete.
   2394 			 */
   2395 			next = ISC_LIST_HEAD(temp_diff.tuples);
   2396 			while (next != NULL) {
   2397 				unsigned char *next_data = next->rdata.data;
   2398 				unsigned char *tuple_data = tuple->rdata.data;
   2399 				if (next->op == DNS_DIFFOP_DEL &&
   2400 				    dns_name_equal(&tuple->name, &next->name) &&
   2401 				    next->rdata.length == tuple->rdata.length &&
   2402 				    !memcmp(next_data, tuple_data,
   2403 					    next->rdata.length)) {
   2404 					ISC_LIST_UNLINK(temp_diff.tuples, next,
   2405 							link);
   2406 					ISC_LIST_APPEND(diff->tuples, next,
   2407 							link);
   2408 					break;
   2409 				}
   2410 				next = ISC_LIST_NEXT(next, link);
   2411 			}
   2412 			/*
   2413 			 * If we have not found a pair move onto the next
   2414 			 * tuple.
   2415 			 */
   2416 			if (next == NULL) {
   2417 				next = ISC_LIST_NEXT(tuple, link);
   2418 				continue;
   2419 			}
   2420 			/*
   2421 			 * Find the next tuple to be processed before
   2422 			 * unlinking then complete moving the pair to 'diff'.
   2423 			 */
   2424 			next = ISC_LIST_NEXT(tuple, link);
   2425 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
   2426 			ISC_LIST_APPEND(diff->tuples, tuple, link);
   2427 		} else
   2428 			next = ISC_LIST_NEXT(tuple, link);
   2429 	}
   2430 
   2431 	/*
   2432 	 * Process the remaining DNSKEY entries.
   2433 	 */
   2434 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
   2435 	     tuple != NULL;
   2436 	     tuple = ISC_LIST_HEAD(temp_diff.tuples)) {
   2437 
   2438 		ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
   2439 		ISC_LIST_APPEND(diff->tuples, tuple, link);
   2440 
   2441 		result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
   2442 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2443 		if ((dnskey.flags &
   2444 		     (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
   2445 			 != DNS_KEYOWNER_ZONE)
   2446 			continue;
   2447 
   2448 		dns_rdata_toregion(&tuple->rdata, &r);
   2449 
   2450 		keyid = dst_region_computeid(&r);
   2451 
   2452 		buf[0] = dnskey.algorithm;
   2453 		buf[1] = (keyid & 0xff00) >> 8;
   2454 		buf[2] = (keyid & 0xff);
   2455 		buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
   2456 		buf[4] = 0;
   2457 		rdata.data = buf;
   2458 		rdata.length = sizeof(buf);
   2459 		rdata.type = privatetype;
   2460 		rdata.rdclass = tuple->rdata.rdclass;
   2461 
   2462 		CHECK(rr_exists(db, ver, name, &rdata, &flag));
   2463 		if (flag)
   2464 			continue;
   2465 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
   2466 					   name, 0, &rdata, &newtuple));
   2467 		CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2468 		INSIST(newtuple == NULL);
   2469 		/*
   2470 		 * Remove any record which says this operation has already
   2471 		 * completed.
   2472 		 */
   2473 		buf[4] = 1;
   2474 		CHECK(rr_exists(db, ver, name, &rdata, &flag));
   2475 		if (flag) {
   2476 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
   2477 						   name, 0, &rdata, &newtuple));
   2478 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
   2479 			INSIST(newtuple == NULL);
   2480 		}
   2481 	}
   2482 
   2483  failure:
   2484 	dns_diff_clear(&temp_diff);
   2485 	return (result);
   2486 }
   2487 
   2488 static bool
   2489 isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) {
   2490 	isc_result_t result;
   2491 	bool build_nsec, build_nsec3;
   2492 
   2493 	if (dns_db_issecure(db))
   2494 		return (true);
   2495 
   2496 	result = dns_private_chains(db, ver, privatetype,
   2497 				    &build_nsec, &build_nsec3);
   2498 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2499 	return (build_nsec || build_nsec3);
   2500 }
   2501 
   2502 static void
   2503 update_action(isc_task_t *task, isc_event_t *event) {
   2504 	update_event_t *uev = (update_event_t *) event;
   2505 	dns_zone_t *zone = uev->zone;
   2506 	ns_client_t *client = (ns_client_t *)event->ev_arg;
   2507 	isc_result_t result;
   2508 	dns_db_t *db = NULL;
   2509 	dns_dbversion_t *oldver = NULL;
   2510 	dns_dbversion_t *ver = NULL;
   2511 	dns_diff_t diff;	/* Pending updates. */
   2512 	dns_diff_t temp;	/* Pending RR existence assertions. */
   2513 	bool soa_serial_changed = false;
   2514 	isc_mem_t *mctx = client->mctx;
   2515 	dns_rdatatype_t covers;
   2516 	dns_message_t *request = client->message;
   2517 	dns_rdataclass_t zoneclass;
   2518 	dns_name_t *zonename;
   2519 	dns_ssutable_t *ssutable = NULL;
   2520 	dns_fixedname_t tmpnamefixed;
   2521 	dns_name_t *tmpname = NULL;
   2522 	dns_zoneopt_t options;
   2523 	dns_difftuple_t *tuple;
   2524 	dns_rdata_dnskey_t dnskey;
   2525 	bool had_dnskey;
   2526 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
   2527 	dns_ttl_t maxttl = 0;
   2528 	uint32_t maxrecords;
   2529 	uint64_t records;
   2530 	dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr);
   2531 
   2532 	INSIST(event->ev_type == DNS_EVENT_UPDATE);
   2533 
   2534 	dns_diff_init(mctx, &diff);
   2535 	dns_diff_init(mctx, &temp);
   2536 
   2537 	CHECK(dns_zone_getdb(zone, &db));
   2538 	zonename = dns_db_origin(db);
   2539 	zoneclass = dns_db_class(db);
   2540 	dns_zone_getssutable(zone, &ssutable);
   2541 
   2542 	/*
   2543 	 * Update message processing can leak record existance information
   2544 	 * so check that we are allowed to query this zone.  Additionally
   2545 	 * if we would refuse all updates for this zone we bail out here.
   2546 	 */
   2547 	CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename,
   2548 			    dns_zone_getupdateacl(zone), ssutable));
   2549 
   2550 	/*
   2551 	 * Get old and new versions now that queryacl has been checked.
   2552 	 */
   2553 	dns_db_currentversion(db, &oldver);
   2554 	CHECK(dns_db_newversion(db, &ver));
   2555 
   2556 	/*
   2557 	 * Check prerequisites.
   2558 	 */
   2559 
   2560 	for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
   2561 	     result == ISC_R_SUCCESS;
   2562 	     result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
   2563 	{
   2564 		dns_name_t *name = NULL;
   2565 		dns_rdata_t rdata = DNS_RDATA_INIT;
   2566 		dns_ttl_t ttl;
   2567 		dns_rdataclass_t update_class;
   2568 		bool flag;
   2569 
   2570 		get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
   2571 			       &name, &rdata, &covers, &ttl, &update_class);
   2572 
   2573 		if (ttl != 0)
   2574 			PREREQFAILC(DNS_R_FORMERR,
   2575 				    "prerequisite TTL is not zero");
   2576 
   2577 		if (! dns_name_issubdomain(name, zonename))
   2578 			PREREQFAILN(DNS_R_NOTZONE, name,
   2579 				    "prerequisite name is out of zone");
   2580 
   2581 		if (update_class == dns_rdataclass_any) {
   2582 			if (rdata.length != 0)
   2583 				PREREQFAILC(DNS_R_FORMERR,
   2584 				      "class ANY prerequisite "
   2585 				      "RDATA is not empty");
   2586 			if (rdata.type == dns_rdatatype_any) {
   2587 				CHECK(name_exists(db, ver, name, &flag));
   2588 				if (! flag) {
   2589 					PREREQFAILN(DNS_R_NXDOMAIN, name,
   2590 						    "'name in use' "
   2591 						    "prerequisite not "
   2592 						    "satisfied");
   2593 				}
   2594 			} else {
   2595 				CHECK(rrset_exists(db, ver, name,
   2596 						   rdata.type, covers, &flag));
   2597 				if (! flag) {
   2598 					/* RRset does not exist. */
   2599 					PREREQFAILNT(DNS_R_NXRRSET,
   2600 						     name, rdata.type,
   2601 					"'rrset exists (value independent)' "
   2602 					"prerequisite not satisfied");
   2603 				}
   2604 			}
   2605 		} else if (update_class == dns_rdataclass_none) {
   2606 			if (rdata.length != 0)
   2607 				PREREQFAILC(DNS_R_FORMERR,
   2608 					    "class NONE prerequisite "
   2609 					    "RDATA is not empty");
   2610 			if (rdata.type == dns_rdatatype_any) {
   2611 				CHECK(name_exists(db, ver, name, &flag));
   2612 				if (flag) {
   2613 					PREREQFAILN(DNS_R_YXDOMAIN, name,
   2614 						    "'name not in use' "
   2615 						    "prerequisite not "
   2616 						    "satisfied");
   2617 				}
   2618 			} else {
   2619 				CHECK(rrset_exists(db, ver, name,
   2620 						   rdata.type, covers, &flag));
   2621 				if (flag) {
   2622 					/* RRset exists. */
   2623 					PREREQFAILNT(DNS_R_YXRRSET, name,
   2624 						     rdata.type,
   2625 						     "'rrset does not exist' "
   2626 						     "prerequisite not "
   2627 						     "satisfied");
   2628 				}
   2629 			}
   2630 		} else if (update_class == zoneclass) {
   2631 			/* "temp<rr.name, rr.type> += rr;" */
   2632 			result = temp_append(&temp, name, &rdata);
   2633 			if (result != ISC_R_SUCCESS) {
   2634 				UNEXPECTED_ERROR(__FILE__, __LINE__,
   2635 					 "temp entry creation failed: %s",
   2636 						 dns_result_totext(result));
   2637 				FAIL(ISC_R_UNEXPECTED);
   2638 			}
   2639 		} else {
   2640 			PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite");
   2641 		}
   2642 	}
   2643 	if (result != ISC_R_NOMORE)
   2644 		FAIL(result);
   2645 
   2646 	/*
   2647 	 * Perform the final check of the "rrset exists (value dependent)"
   2648 	 * prerequisites.
   2649 	 */
   2650 	if (ISC_LIST_HEAD(temp.tuples) != NULL) {
   2651 		dns_rdatatype_t type;
   2652 
   2653 		/*
   2654 		 * Sort the prerequisite records by owner name,
   2655 		 * type, and rdata.
   2656 		 */
   2657 		result = dns_diff_sort(&temp, temp_order);
   2658 		if (result != ISC_R_SUCCESS)
   2659 			FAILC(result, "'RRset exists (value dependent)' "
   2660 			      "prerequisite not satisfied");
   2661 
   2662 		tmpname = dns_fixedname_initname(&tmpnamefixed);
   2663 		result = temp_check(mctx, &temp, db, ver, tmpname, &type);
   2664 		if (result != ISC_R_SUCCESS)
   2665 			FAILNT(result, tmpname, type,
   2666 			       "'RRset exists (value dependent)' "
   2667 			       "prerequisite not satisfied");
   2668 	}
   2669 
   2670 	update_log(client, zone, LOGLEVEL_DEBUG,
   2671 		   "prerequisites are OK");
   2672 
   2673 	/*
   2674 	 * Check Requestor's Permissions.  It seems a bit silly to do this
   2675 	 * only after prerequisite testing, but that is what RFC2136 says.
   2676 	 */
   2677 	if (ssutable == NULL)
   2678 		CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
   2679 				     "update", zonename, false, false));
   2680 	else if (client->signer == NULL && !TCPCLIENT(client))
   2681 		CHECK(checkupdateacl(client, NULL, "update", zonename,
   2682 				     false, true));
   2683 
   2684 	if (dns_zone_getupdatedisabled(zone))
   2685 		FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
   2686 				     "because the zone is frozen.  Use "
   2687 				     "'rndc thaw' to re-enable updates.");
   2688 
   2689 	/*
   2690 	 * Perform the Update Section Prescan.
   2691 	 */
   2692 
   2693 	for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
   2694 	     result == ISC_R_SUCCESS;
   2695 	     result = dns_message_nextname(request, DNS_SECTION_UPDATE))
   2696 	{
   2697 		dns_name_t *name = NULL;
   2698 		dns_rdata_t rdata = DNS_RDATA_INIT;
   2699 		dns_ttl_t ttl;
   2700 		dns_rdataclass_t update_class;
   2701 		get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
   2702 			       &name, &rdata, &covers, &ttl, &update_class);
   2703 
   2704 		if (! dns_name_issubdomain(name, zonename))
   2705 			FAILC(DNS_R_NOTZONE,
   2706 			      "update RR is outside zone");
   2707 		if (update_class == zoneclass) {
   2708 			/*
   2709 			 * Check for meta-RRs.  The RFC2136 pseudocode says
   2710 			 * check for ANY|AXFR|MAILA|MAILB, but the text adds
   2711 			 * "or any other QUERY metatype"
   2712 			 */
   2713 			if (dns_rdatatype_ismeta(rdata.type)) {
   2714 				FAILC(DNS_R_FORMERR,
   2715 				      "meta-RR in update");
   2716 			}
   2717 			result = dns_zone_checknames(zone, name, &rdata);
   2718 			if (result != ISC_R_SUCCESS)
   2719 				FAIL(DNS_R_REFUSED);
   2720 		} else if (update_class == dns_rdataclass_any) {
   2721 			if (ttl != 0 || rdata.length != 0 ||
   2722 			    (dns_rdatatype_ismeta(rdata.type) &&
   2723 			     rdata.type != dns_rdatatype_any))
   2724 				FAILC(DNS_R_FORMERR,
   2725 				      "meta-RR in update");
   2726 		} else if (update_class == dns_rdataclass_none) {
   2727 			if (ttl != 0 ||
   2728 			    dns_rdatatype_ismeta(rdata.type))
   2729 				FAILC(DNS_R_FORMERR,
   2730 				      "meta-RR in update");
   2731 		} else {
   2732 			update_log(client, zone, ISC_LOG_WARNING,
   2733 				   "update RR has incorrect class %d",
   2734 				   update_class);
   2735 			FAIL(DNS_R_FORMERR);
   2736 		}
   2737 
   2738 		/*
   2739 		 * draft-ietf-dnsind-simple-secure-update-01 says
   2740 		 * "Unlike traditional dynamic update, the client
   2741 		 * is forbidden from updating NSEC records."
   2742 		 */
   2743 		if (rdata.type == dns_rdatatype_nsec3) {
   2744 			FAILC(DNS_R_REFUSED,
   2745 			      "explicit NSEC3 updates are not allowed "
   2746 			      "in secure zones");
   2747 		} else if (rdata.type == dns_rdatatype_nsec) {
   2748 			FAILC(DNS_R_REFUSED,
   2749 			      "explicit NSEC updates are not allowed "
   2750 			      "in secure zones");
   2751 		} else if (rdata.type == dns_rdatatype_rrsig &&
   2752 			   !dns_name_equal(name, zonename)) {
   2753 			FAILC(DNS_R_REFUSED,
   2754 			      "explicit RRSIG updates are currently "
   2755 			      "not supported in secure zones except "
   2756 			      "at the apex");
   2757 		}
   2758 
   2759 		if (ssutable != NULL) {
   2760 			isc_netaddr_t netaddr;
   2761 			dst_key_t *tsigkey = NULL;
   2762 			isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   2763 
   2764 			if (client->message->tsigkey != NULL)
   2765 				tsigkey = client->message->tsigkey->key;
   2766 
   2767 			if (rdata.type != dns_rdatatype_any) {
   2768 				if (!dns_ssutable_checkrules
   2769 				(ssutable, client->signer, name, &netaddr,
   2770 				 TCPCLIENT(client),
   2771 				 env, rdata.type, tsigkey))
   2772 				{
   2773 					FAILC(DNS_R_REFUSED,
   2774 					      "rejected by secure update");
   2775 				}
   2776 			} else {
   2777 				if (!ssu_checkall(db, ver, name, ssutable,
   2778 						  client->signer,
   2779 						  &netaddr, env,
   2780 						  TCPCLIENT(client),
   2781 						  tsigkey))
   2782 				{
   2783 					FAILC(DNS_R_REFUSED,
   2784 					      "rejected by secure update");
   2785 				}
   2786 			}
   2787 		}
   2788 	}
   2789 	if (result != ISC_R_NOMORE)
   2790 		FAIL(result);
   2791 
   2792 	update_log(client, zone, LOGLEVEL_DEBUG,
   2793 		   "update section prescan OK");
   2794 
   2795 	/*
   2796 	 * Process the Update Section.
   2797 	 */
   2798 
   2799 	options = dns_zone_getoptions(zone);
   2800 	for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
   2801 	     result == ISC_R_SUCCESS;
   2802 	     result = dns_message_nextname(request, DNS_SECTION_UPDATE))
   2803 	{
   2804 		dns_name_t *name = NULL;
   2805 		dns_rdata_t rdata = DNS_RDATA_INIT;
   2806 		dns_ttl_t ttl;
   2807 		dns_rdataclass_t update_class;
   2808 		bool flag;
   2809 
   2810 		get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
   2811 			       &name, &rdata, &covers, &ttl, &update_class);
   2812 
   2813 		if (update_class == zoneclass) {
   2814 
   2815 			/*
   2816 			 * RFC1123 doesn't allow MF and MD in master zones.
   2817 			 */
   2818 			if (rdata.type == dns_rdatatype_md ||
   2819 			    rdata.type == dns_rdatatype_mf) {
   2820 				char typebuf[DNS_RDATATYPE_FORMATSIZE];
   2821 
   2822 				dns_rdatatype_format(rdata.type, typebuf,
   2823 						     sizeof(typebuf));
   2824 				update_log(client, zone, LOGLEVEL_PROTOCOL,
   2825 					   "attempt to add %s ignored",
   2826 					   typebuf);
   2827 				continue;
   2828 			}
   2829 			if ((rdata.type == dns_rdatatype_ns ||
   2830 			     rdata.type == dns_rdatatype_dname) &&
   2831 			    dns_name_iswildcard(name)) {
   2832 				char typebuf[DNS_RDATATYPE_FORMATSIZE];
   2833 
   2834 				dns_rdatatype_format(rdata.type, typebuf,
   2835 						     sizeof(typebuf));
   2836 				update_log(client, zone,
   2837 					   LOGLEVEL_PROTOCOL,
   2838 					   "attempt to add wildcard %s record "
   2839 					   "ignored", typebuf);
   2840 				continue;
   2841 			}
   2842 			if (rdata.type == dns_rdatatype_cname) {
   2843 				CHECK(cname_incompatible_rrset_exists(db, ver,
   2844 								      name,
   2845 								      &flag));
   2846 				if (flag) {
   2847 					update_log(client, zone,
   2848 						   LOGLEVEL_PROTOCOL,
   2849 						   "attempt to add CNAME "
   2850 						   "alongside non-CNAME "
   2851 						   "ignored");
   2852 					continue;
   2853 				}
   2854 			} else {
   2855 				CHECK(rrset_exists(db, ver, name,
   2856 						   dns_rdatatype_cname, 0,
   2857 						   &flag));
   2858 				if (flag &&
   2859 				    ! dns_rdatatype_atcname(rdata.type))
   2860 				{
   2861 					update_log(client, zone,
   2862 						   LOGLEVEL_PROTOCOL,
   2863 						   "attempt to add non-CNAME "
   2864 						   "alongside CNAME ignored");
   2865 					continue;
   2866 				}
   2867 			}
   2868 			if (rdata.type == dns_rdatatype_soa) {
   2869 				bool ok;
   2870 				CHECK(rrset_exists(db, ver, name,
   2871 						   dns_rdatatype_soa, 0,
   2872 						   &flag));
   2873 				if (! flag) {
   2874 					update_log(client, zone,
   2875 						   LOGLEVEL_PROTOCOL,
   2876 						   "attempt to create 2nd "
   2877 						   "SOA ignored");
   2878 					continue;
   2879 				}
   2880 				CHECK(check_soa_increment(db, ver, &rdata,
   2881 							  &ok));
   2882 				if (! ok) {
   2883 					update_log(client, zone,
   2884 						   LOGLEVEL_PROTOCOL,
   2885 						   "SOA update failed to "
   2886 						   "increment serial, "
   2887 						   "ignoring it");
   2888 					continue;
   2889 				}
   2890 				soa_serial_changed = true;
   2891 			}
   2892 
   2893 			if (rdata.type == privatetype) {
   2894 				update_log(client, zone, LOGLEVEL_PROTOCOL,
   2895 					   "attempt to add a private type "
   2896 					   "(%u) record rejected internal "
   2897 					   "use only", privatetype);
   2898 				continue;
   2899 			}
   2900 
   2901 			if (rdata.type == dns_rdatatype_nsec3param) {
   2902 				/*
   2903 				 * Ignore attempts to add NSEC3PARAM records
   2904 				 * with any flags other than OPTOUT.
   2905 				 */
   2906 				if ((rdata.data[1] &
   2907 				     ~DNS_NSEC3FLAG_OPTOUT) != 0)
   2908 				{
   2909 					update_log(client, zone,
   2910 						   LOGLEVEL_PROTOCOL,
   2911 						   "attempt to add NSEC3PARAM "
   2912 						   "record with non OPTOUT "
   2913 						   "flag");
   2914 					continue;
   2915 				}
   2916 			}
   2917 
   2918 			if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
   2919 			    dns_name_internalwildcard(name)) {
   2920 				char namestr[DNS_NAME_FORMATSIZE];
   2921 				dns_name_format(name, namestr,
   2922 						sizeof(namestr));
   2923 				update_log(client, zone, LOGLEVEL_PROTOCOL,
   2924 					   "warning: ownername '%s' contains "
   2925 					   "a non-terminal wildcard", namestr);
   2926 			}
   2927 
   2928 			if ((options & DNS_ZONEOPT_CHECKTTL) != 0) {
   2929 				maxttl = dns_zone_getmaxttl(zone);
   2930 				if (ttl > maxttl) {
   2931 					ttl = maxttl;
   2932 					update_log(client, zone,
   2933 						   LOGLEVEL_PROTOCOL,
   2934 						   "reducing TTL to the "
   2935 						   "configured max-zone-ttl %d",
   2936 						   maxttl);
   2937 				}
   2938 			}
   2939 
   2940 			if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) {
   2941 				char namestr[DNS_NAME_FORMATSIZE];
   2942 				char typestr[DNS_RDATATYPE_FORMATSIZE];
   2943 				char rdstr[2048];
   2944 				isc_buffer_t buf;
   2945 				int len = 0;
   2946 				const char *truncated = "";
   2947 
   2948 				dns_name_format(name, namestr, sizeof(namestr));
   2949 				dns_rdatatype_format(rdata.type, typestr,
   2950 						     sizeof(typestr));
   2951 				isc_buffer_init(&buf, rdstr, sizeof(rdstr));
   2952 				result = dns_rdata_totext(&rdata, NULL, &buf);
   2953 				if (result == ISC_R_NOSPACE) {
   2954 					len = (int)isc_buffer_usedlength(&buf);
   2955 					truncated = " [TRUNCATED]";
   2956 				} else if (result != ISC_R_SUCCESS) {
   2957 					snprintf(rdstr, sizeof(rdstr), "[dns_"
   2958 						 "rdata_totext failed: %s]",
   2959 						 dns_result_totext(result));
   2960 					len = strlen(rdstr);
   2961 				} else
   2962 					len = (int)isc_buffer_usedlength(&buf);
   2963 				update_log(client, zone, LOGLEVEL_PROTOCOL,
   2964 					   "adding an RR at '%s' %s %.*s%s",
   2965 					   namestr, typestr, len, rdstr,
   2966 					   truncated);
   2967 			}
   2968 
   2969 			/* Prepare the affected RRset for the addition. */
   2970 			{
   2971 				add_rr_prepare_ctx_t ctx;
   2972 				ctx.db = db;
   2973 				ctx.ver = ver;
   2974 				ctx.diff = &diff;
   2975 				ctx.name = name;
   2976 				ctx.oldname = name;
   2977 				ctx.update_rr = &rdata;
   2978 				ctx.update_rr_ttl = ttl;
   2979 				ctx.ignore_add = false;
   2980 				dns_diff_init(mctx, &ctx.del_diff);
   2981 				dns_diff_init(mctx, &ctx.add_diff);
   2982 				CHECK(foreach_rr(db, ver, name, rdata.type,
   2983 						 covers, add_rr_prepare_action,
   2984 						 &ctx));
   2985 
   2986 				if (ctx.ignore_add) {
   2987 					dns_diff_clear(&ctx.del_diff);
   2988 					dns_diff_clear(&ctx.add_diff);
   2989 				} else {
   2990 					result = do_diff(&ctx.del_diff, db, ver,
   2991 							 &diff);
   2992 					if (result == ISC_R_SUCCESS) {
   2993 						result = do_diff(&ctx.add_diff,
   2994 								 db, ver,
   2995 								 &diff);
   2996 					}
   2997 					if (result != ISC_R_SUCCESS) {
   2998 						dns_diff_clear(&ctx.del_diff);
   2999 						dns_diff_clear(&ctx.add_diff);
   3000 						goto failure;
   3001 					}
   3002 					CHECK(update_one_rr(db, ver, &diff,
   3003 							    DNS_DIFFOP_ADD,
   3004 							    name, ttl, &rdata));
   3005 				}
   3006 			}
   3007 		} else if (update_class == dns_rdataclass_any) {
   3008 			if (rdata.type == dns_rdatatype_any) {
   3009 				if (isc_log_wouldlog(ns_lctx,
   3010 						     LOGLEVEL_PROTOCOL))
   3011 				{
   3012 					char namestr[DNS_NAME_FORMATSIZE];
   3013 					dns_name_format(name, namestr,
   3014 							sizeof(namestr));
   3015 					update_log(client, zone,
   3016 						   LOGLEVEL_PROTOCOL,
   3017 						   "delete all rrsets from "
   3018 						   "name '%s'", namestr);
   3019 				}
   3020 				if (dns_name_equal(name, zonename)) {
   3021 					CHECK(delete_if(type_not_soa_nor_ns_p,
   3022 							db, ver, name,
   3023 							dns_rdatatype_any, 0,
   3024 							&rdata, &diff));
   3025 				} else {
   3026 					CHECK(delete_if(type_not_dnssec,
   3027 							db, ver, name,
   3028 							dns_rdatatype_any, 0,
   3029 							&rdata, &diff));
   3030 				}
   3031 			} else if (dns_name_equal(name, zonename) &&
   3032 				   (rdata.type == dns_rdatatype_soa ||
   3033 				    rdata.type == dns_rdatatype_ns)) {
   3034 				update_log(client, zone, LOGLEVEL_PROTOCOL,
   3035 					   "attempt to delete all SOA "
   3036 					   "or NS records ignored");
   3037 				continue;
   3038 			} else {
   3039 				if (isc_log_wouldlog(ns_lctx,
   3040 						     LOGLEVEL_PROTOCOL))
   3041 				{
   3042 					char namestr[DNS_NAME_FORMATSIZE];
   3043 					char typestr[DNS_RDATATYPE_FORMATSIZE];
   3044 					dns_name_format(name, namestr,
   3045 							sizeof(namestr));
   3046 					dns_rdatatype_format(rdata.type,
   3047 							     typestr,
   3048 							     sizeof(typestr));
   3049 					update_log(client, zone,
   3050 						   LOGLEVEL_PROTOCOL,
   3051 						   "deleting rrset at '%s' %s",
   3052 						   namestr, typestr);
   3053 				}
   3054 				CHECK(delete_if(true_p, db, ver, name,
   3055 						rdata.type, covers, &rdata,
   3056 						&diff));
   3057 			}
   3058 		} else if (update_class == dns_rdataclass_none) {
   3059 			char namestr[DNS_NAME_FORMATSIZE];
   3060 			char typestr[DNS_RDATATYPE_FORMATSIZE];
   3061 
   3062 			/*
   3063 			 * The (name == zonename) condition appears in
   3064 			 * RFC2136 3.4.2.4 but is missing from the pseudocode.
   3065 			 */
   3066 			if (dns_name_equal(name, zonename)) {
   3067 				if (rdata.type == dns_rdatatype_soa) {
   3068 					update_log(client, zone,
   3069 						   LOGLEVEL_PROTOCOL,
   3070 						   "attempt to delete SOA "
   3071 						   "ignored");
   3072 					continue;
   3073 				}
   3074 				if (rdata.type == dns_rdatatype_ns) {
   3075 					int count;
   3076 					CHECK(rr_count(db, ver, name,
   3077 						       dns_rdatatype_ns,
   3078 						       0, &count));
   3079 					if (count == 1) {
   3080 						update_log(client, zone,
   3081 							   LOGLEVEL_PROTOCOL,
   3082 							   "attempt to "
   3083 							   "delete last "
   3084 							   "NS ignored");
   3085 						continue;
   3086 					}
   3087 				}
   3088 			}
   3089 			dns_name_format(name, namestr, sizeof(namestr));
   3090 			dns_rdatatype_format(rdata.type, typestr,
   3091 					     sizeof(typestr));
   3092 			update_log(client, zone, LOGLEVEL_PROTOCOL,
   3093 				   "deleting an RR at %s %s", namestr, typestr);
   3094 			CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type,
   3095 					covers, &rdata, &diff));
   3096 		}
   3097 	}
   3098 	if (result != ISC_R_NOMORE)
   3099 		FAIL(result);
   3100 
   3101 	/*
   3102 	 * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
   3103 	 * If they don't then back out all changes to DNSKEY/NSEC3PARAM
   3104 	 * records.
   3105 	 */
   3106 	if (! ISC_LIST_EMPTY(diff.tuples))
   3107 		CHECK(check_dnssec(client, zone, db, ver, &diff));
   3108 
   3109 	if (! ISC_LIST_EMPTY(diff.tuples)) {
   3110 		unsigned int errors = 0;
   3111 		CHECK(dns_zone_nscheck(zone, db, ver, &errors));
   3112 		if (errors != 0) {
   3113 			update_log(client, zone, LOGLEVEL_PROTOCOL,
   3114 				   "update rejected: post update name server "
   3115 				   "sanity check failed");
   3116 			result = DNS_R_REFUSED;
   3117 			goto failure;
   3118 		}
   3119 	}
   3120 	if (! ISC_LIST_EMPTY(diff.tuples)) {
   3121 		result = dns_zone_cdscheck(zone, db, ver);
   3122 		if (result == DNS_R_BADCDS || result == DNS_R_BADCDNSKEY) {
   3123 			update_log(client, zone, LOGLEVEL_PROTOCOL,
   3124 				   "update rejected: bad %s RRset",
   3125 				   result == DNS_R_BADCDS ? "CDS" : "CDNSKEY");
   3126 			result = DNS_R_REFUSED;
   3127 			goto failure;
   3128 		}
   3129 		if (result != ISC_R_SUCCESS)
   3130 			goto failure;
   3131 
   3132 	}
   3133 
   3134 	/*
   3135 	 * If any changes were made, increment the SOA serial number,
   3136 	 * update RRSIGs and NSECs (if zone is secure), and write the update
   3137 	 * to the journal.
   3138 	 */
   3139 	if (! ISC_LIST_EMPTY(diff.tuples)) {
   3140 		char *journalfile;
   3141 		dns_journal_t *journal;
   3142 		bool has_dnskey;
   3143 
   3144 		/*
   3145 		 * Increment the SOA serial, but only if it was not
   3146 		 * changed as a result of an update operation.
   3147 		 */
   3148 		if (! soa_serial_changed) {
   3149 			CHECK(update_soa_serial(db, ver, &diff, mctx,
   3150 				       dns_zone_getserialupdatemethod(zone)));
   3151 		}
   3152 
   3153 		CHECK(check_mx(client, zone, db, ver, &diff));
   3154 
   3155 		CHECK(remove_orphaned_ds(db, ver, &diff));
   3156 
   3157 		CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
   3158 				   0, &has_dnskey));
   3159 
   3160 #define ALLOW_SECURE_TO_INSECURE(zone) \
   3161 	((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0)
   3162 
   3163 		CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
   3164 				   0, &had_dnskey));
   3165 		if (!ALLOW_SECURE_TO_INSECURE(zone)) {
   3166 			if (had_dnskey && !has_dnskey) {
   3167 				update_log(client, zone, LOGLEVEL_PROTOCOL,
   3168 					   "update rejected: all DNSKEY "
   3169 					   "records removed and "
   3170 					   "'dnssec-secure-to-insecure' "
   3171 					   "not set");
   3172 				result = DNS_R_REFUSED;
   3173 				goto failure;
   3174 			}
   3175 		}
   3176 
   3177 		CHECK(rollback_private(db, privatetype, ver, &diff));
   3178 
   3179 		CHECK(add_signing_records(db, privatetype, ver, &diff));
   3180 
   3181 		CHECK(add_nsec3param_records(client, zone, db, ver, &diff));
   3182 
   3183 		if (had_dnskey && !has_dnskey) {
   3184 			/*
   3185 			 * We are transitioning from secure to insecure.
   3186 			 * Cause all NSEC3 chains to be deleted.  When the
   3187 			 * the last signature for the DNSKEY records are
   3188 			 * remove any NSEC chain present will also be removed.
   3189 			 */
   3190 			 CHECK(dns_nsec3param_deletechains(db, ver, zone,
   3191 							   true, &diff));
   3192 		} else if (has_dnskey && isdnssec(db, ver, privatetype)) {
   3193 			uint32_t interval;
   3194 			dns_update_log_t log;
   3195 
   3196 			interval = dns_zone_getsigvalidityinterval(zone);
   3197 			log.func = update_log_cb;
   3198 			log.arg = client;
   3199 			result = dns_update_signatures(&log, zone, db, oldver,
   3200 						       ver, &diff, interval);
   3201 
   3202 			if (result != ISC_R_SUCCESS) {
   3203 				update_log(client, zone,
   3204 					   ISC_LOG_ERROR,
   3205 					   "RRSIG/NSEC/NSEC3 update failed: %s",
   3206 					   isc_result_totext(result));
   3207 				goto failure;
   3208 			}
   3209 		}
   3210 
   3211 		maxrecords = dns_zone_getmaxrecords(zone);
   3212 		if (maxrecords != 0U) {
   3213 			result = dns_db_getsize(db, ver, &records, NULL);
   3214 			if (result == ISC_R_SUCCESS && records > maxrecords) {
   3215 				update_log(client, zone, ISC_LOG_ERROR,
   3216 					   "records in zone (%"
   3217 					   PRIu64
   3218 					   ") exceeds max-records (%u)",
   3219 					   records, maxrecords);
   3220 				result = DNS_R_TOOMANYRECORDS;
   3221 				goto failure;
   3222 			}
   3223 		}
   3224 
   3225 		journalfile = dns_zone_getjournal(zone);
   3226 		if (journalfile != NULL) {
   3227 			update_log(client, zone, LOGLEVEL_DEBUG,
   3228 				   "writing journal %s", journalfile);
   3229 
   3230 			journal = NULL;
   3231 			result = dns_journal_open(mctx, journalfile,
   3232 						  DNS_JOURNAL_CREATE, &journal);
   3233 			if (result != ISC_R_SUCCESS)
   3234 				FAILS(result, "journal open failed");
   3235 
   3236 			result = dns_journal_write_transaction(journal, &diff);
   3237 			if (result != ISC_R_SUCCESS) {
   3238 				dns_journal_destroy(&journal);
   3239 				FAILS(result, "journal write failed");
   3240 			}
   3241 
   3242 			dns_journal_destroy(&journal);
   3243 		}
   3244 
   3245 		/*
   3246 		 * XXXRTH  Just a note that this committing code will have
   3247 		 *	   to change to handle databases that need two-phase
   3248 		 *	   commit, but this isn't a priority.
   3249 		 */
   3250 		update_log(client, zone, LOGLEVEL_DEBUG,
   3251 			   "committing update transaction");
   3252 
   3253 		dns_db_closeversion(db, &ver, true);
   3254 
   3255 		/*
   3256 		 * Mark the zone as dirty so that it will be written to disk.
   3257 		 */
   3258 		dns_zone_markdirty(zone);
   3259 
   3260 		/*
   3261 		 * Notify slaves of the change we just made.
   3262 		 */
   3263 		dns_zone_notify(zone);
   3264 
   3265 		/*
   3266 		 * Cause the zone to be signed with the key that we
   3267 		 * have just added or have the corresponding signatures
   3268 		 * deleted.
   3269 		 *
   3270 		 * Note: we are already committed to this course of action.
   3271 		 */
   3272 		for (tuple = ISC_LIST_HEAD(diff.tuples);
   3273 		     tuple != NULL;
   3274 		     tuple = ISC_LIST_NEXT(tuple, link)) {
   3275 			isc_region_t r;
   3276 			dns_secalg_t algorithm;
   3277 			uint16_t keyid;
   3278 
   3279 			if (tuple->rdata.type != dns_rdatatype_dnskey)
   3280 				continue;
   3281 
   3282 			dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
   3283 			if ((dnskey.flags &
   3284 			     (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
   3285 				 != DNS_KEYOWNER_ZONE)
   3286 				continue;
   3287 
   3288 			dns_rdata_toregion(&tuple->rdata, &r);
   3289 			algorithm = dnskey.algorithm;
   3290 			keyid = dst_region_computeid(&r);
   3291 
   3292 			result = dns_zone_signwithkey(zone, algorithm, keyid,
   3293 					(tuple->op == DNS_DIFFOP_DEL));
   3294 			if (result != ISC_R_SUCCESS) {
   3295 				update_log(client, zone, ISC_LOG_ERROR,
   3296 					   "dns_zone_signwithkey failed: %s",
   3297 					   dns_result_totext(result));
   3298 			}
   3299 		}
   3300 
   3301 		/*
   3302 		 * Cause the zone to add/delete NSEC3 chains for the
   3303 		 * deferred NSEC3PARAM changes.
   3304 		 *
   3305 		 * Note: we are already committed to this course of action.
   3306 		 */
   3307 		for (tuple = ISC_LIST_HEAD(diff.tuples);
   3308 		     tuple != NULL;
   3309 		     tuple = ISC_LIST_NEXT(tuple, link)) {
   3310 			unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
   3311 			dns_rdata_t rdata = DNS_RDATA_INIT;
   3312 			dns_rdata_nsec3param_t nsec3param;
   3313 
   3314 			if (tuple->rdata.type != privatetype ||
   3315 			    tuple->op != DNS_DIFFOP_ADD)
   3316 				continue;
   3317 
   3318 			if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
   3319 						   buf, sizeof(buf)))
   3320 				continue;
   3321 			dns_rdata_tostruct(&rdata, &nsec3param, NULL);
   3322 			if (nsec3param.flags == 0)
   3323 				continue;
   3324 
   3325 			result = dns_zone_addnsec3chain(zone, &nsec3param);
   3326 			if (result != ISC_R_SUCCESS) {
   3327 				update_log(client, zone, ISC_LOG_ERROR,
   3328 					   "dns_zone_addnsec3chain failed: %s",
   3329 					   dns_result_totext(result));
   3330 			}
   3331 		}
   3332 	} else {
   3333 		update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
   3334 		dns_db_closeversion(db, &ver, true);
   3335 	}
   3336 	result = ISC_R_SUCCESS;
   3337 	goto common;
   3338 
   3339  failure:
   3340 	/*
   3341 	 * The reason for failure should have been logged at this point.
   3342 	 */
   3343 	if (ver != NULL) {
   3344 		update_log(client, zone, LOGLEVEL_DEBUG,
   3345 			   "rolling back");
   3346 		dns_db_closeversion(db, &ver, false);
   3347 	}
   3348 
   3349  common:
   3350 	dns_diff_clear(&temp);
   3351 	dns_diff_clear(&diff);
   3352 
   3353 	if (oldver != NULL)
   3354 		dns_db_closeversion(db, &oldver, false);
   3355 
   3356 	if (db != NULL)
   3357 		dns_db_detach(&db);
   3358 
   3359 	if (ssutable != NULL)
   3360 		dns_ssutable_detach(&ssutable);
   3361 
   3362 	isc_task_detach(&task);
   3363 	uev->result = result;
   3364 	if (zone != NULL)
   3365 		INSIST(uev->zone == zone); /* we use this later */
   3366 	uev->ev_type = DNS_EVENT_UPDATEDONE;
   3367 	uev->ev_action = updatedone_action;
   3368 	isc_task_send(client->task, &event);
   3369 
   3370 	INSIST(ver == NULL);
   3371 	INSIST(event == NULL);
   3372 }
   3373 
   3374 static void
   3375 updatedone_action(isc_task_t *task, isc_event_t *event) {
   3376 	update_event_t *uev = (update_event_t *) event;
   3377 	ns_client_t *client = (ns_client_t *) event->ev_arg;
   3378 
   3379 	UNUSED(task);
   3380 
   3381 	INSIST(event->ev_type == DNS_EVENT_UPDATEDONE);
   3382 	INSIST(task == client->task);
   3383 
   3384 	INSIST(client->nupdates > 0);
   3385 	switch (uev->result) {
   3386 	case ISC_R_SUCCESS:
   3387 		inc_stats(client, uev->zone, ns_statscounter_updatedone);
   3388 		break;
   3389 	case DNS_R_REFUSED:
   3390 		inc_stats(client, uev->zone, ns_statscounter_updaterej);
   3391 		break;
   3392 	default:
   3393 		inc_stats(client, uev->zone, ns_statscounter_updatefail);
   3394 		break;
   3395 	}
   3396 	if (uev->zone != NULL)
   3397 		dns_zone_detach(&uev->zone);
   3398 	client->nupdates--;
   3399 	respond(client, uev->result);
   3400 	isc_event_free(&event);
   3401 	ns_client_detach(&client);
   3402 }
   3403 
   3404 /*%
   3405  * Update forwarding support.
   3406  */
   3407 
   3408 static void
   3409 forward_fail(isc_task_t *task, isc_event_t *event) {
   3410 	ns_client_t *client = (ns_client_t *)event->ev_arg;
   3411 
   3412 	UNUSED(task);
   3413 
   3414 	INSIST(client->nupdates > 0);
   3415 	client->nupdates--;
   3416 	respond(client, DNS_R_SERVFAIL);
   3417 	isc_event_free(&event);
   3418 	ns_client_detach(&client);
   3419 }
   3420 
   3421 
   3422 static void
   3423 forward_callback(void *arg, isc_result_t result, dns_message_t *answer) {
   3424 	update_event_t *uev = arg;
   3425 	ns_client_t *client = uev->ev_arg;
   3426 	dns_zone_t *zone = uev->zone;
   3427 
   3428 	if (result != ISC_R_SUCCESS) {
   3429 		INSIST(answer == NULL);
   3430 		uev->ev_type = DNS_EVENT_UPDATEDONE;
   3431 		uev->ev_action = forward_fail;
   3432 		inc_stats(client, zone, ns_statscounter_updatefwdfail);
   3433 	} else {
   3434 		uev->ev_type = DNS_EVENT_UPDATEDONE;
   3435 		uev->ev_action = forward_done;
   3436 		uev->answer = answer;
   3437 		inc_stats(client, zone, ns_statscounter_updaterespfwd);
   3438 	}
   3439 	isc_task_send(client->task, ISC_EVENT_PTR(&uev));
   3440 	dns_zone_detach(&zone);
   3441 }
   3442 
   3443 static void
   3444 forward_done(isc_task_t *task, isc_event_t *event) {
   3445 	update_event_t *uev = (update_event_t *) event;
   3446 	ns_client_t *client = (ns_client_t *)event->ev_arg;
   3447 
   3448 	UNUSED(task);
   3449 
   3450 	INSIST(client->nupdates > 0);
   3451 	client->nupdates--;
   3452 	ns_client_sendraw(client, uev->answer);
   3453 	dns_message_destroy(&uev->answer);
   3454 	isc_event_free(&event);
   3455 	ns_client_detach(&client);
   3456 }
   3457 
   3458 static void
   3459 forward_action(isc_task_t *task, isc_event_t *event) {
   3460 	update_event_t *uev = (update_event_t *) event;
   3461 	dns_zone_t *zone = uev->zone;
   3462 	ns_client_t *client = (ns_client_t *)event->ev_arg;
   3463 	isc_result_t result;
   3464 
   3465 	result = dns_zone_forwardupdate(zone, client->message,
   3466 					forward_callback, event);
   3467 	if (result != ISC_R_SUCCESS) {
   3468 		uev->ev_type = DNS_EVENT_UPDATEDONE;
   3469 		uev->ev_action = forward_fail;
   3470 		isc_task_send(client->task, &event);
   3471 		inc_stats(client, zone, ns_statscounter_updatefwdfail);
   3472 		dns_zone_detach(&zone);
   3473 	} else
   3474 		inc_stats(client, zone, ns_statscounter_updatereqfwd);
   3475 	isc_task_detach(&task);
   3476 }
   3477 
   3478 static isc_result_t
   3479 send_forward_event(ns_client_t *client, dns_zone_t *zone) {
   3480 	char namebuf[DNS_NAME_FORMATSIZE];
   3481 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   3482 	isc_result_t result = ISC_R_SUCCESS;
   3483 	update_event_t *event = NULL;
   3484 	isc_task_t *zonetask = NULL;
   3485 	ns_client_t *evclient;
   3486 
   3487 	/*
   3488 	 * This may take some time so replace this client.
   3489 	 */
   3490 	if (!client->mortal && (client->attributes & NS_CLIENTATTR_TCP) == 0)
   3491 		CHECK(ns_client_replace(client));
   3492 
   3493 	event = (update_event_t *)
   3494 		isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
   3495 				   forward_action, NULL, sizeof(*event));
   3496 	if (event == NULL)
   3497 		FAIL(ISC_R_NOMEMORY);
   3498 	event->zone = zone;
   3499 	event->result = ISC_R_SUCCESS;
   3500 
   3501 	evclient = NULL;
   3502 	ns_client_attach(client, &evclient);
   3503 	INSIST(client->nupdates == 0);
   3504 	client->nupdates++;
   3505 	event->ev_arg = evclient;
   3506 
   3507 	dns_name_format(dns_zone_getorigin(zone), namebuf,
   3508 			sizeof(namebuf));
   3509 	dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
   3510 			      sizeof(classbuf));
   3511 
   3512 	ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
   3513 		      LOGLEVEL_PROTOCOL, "forwarding update for zone '%s/%s'",
   3514 		      namebuf, classbuf);
   3515 
   3516 	dns_zone_gettask(zone, &zonetask);
   3517 	isc_task_send(zonetask, ISC_EVENT_PTR(&event));
   3518 
   3519  failure:
   3520 	if (event != NULL)
   3521 		isc_event_free(ISC_EVENT_PTR(&event));
   3522 	return (result);
   3523 }
   3524