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