xref: /minix/external/bsd/bind/dist/lib/dns/update.c (revision bb9622b5)
1 /*	$NetBSD: update.c,v 1.4 2014/12/10 04:37:58 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id */
20 
21 #include <config.h>
22 
23 #include <isc/log.h>
24 #include <isc/netaddr.h>
25 #include <isc/print.h>
26 #include <isc/serial.h>
27 #include <isc/stats.h>
28 #include <isc/stdtime.h>
29 #include <isc/string.h>
30 #include <isc/taskpool.h>
31 #include <isc/util.h>
32 
33 #include <dns/db.h>
34 #include <dns/dbiterator.h>
35 #include <dns/diff.h>
36 #include <dns/dnssec.h>
37 #include <dns/events.h>
38 #include <dns/fixedname.h>
39 #include <dns/journal.h>
40 #include <dns/keyvalues.h>
41 #include <dns/log.h>
42 #include <dns/message.h>
43 #include <dns/nsec.h>
44 #include <dns/nsec3.h>
45 #include <dns/private.h>
46 #include <dns/rdataclass.h>
47 #include <dns/rdataset.h>
48 #include <dns/rdatasetiter.h>
49 #include <dns/rdatastruct.h>
50 #include <dns/rdatatype.h>
51 #include <dns/result.h>
52 #include <dns/soa.h>
53 #include <dns/ssu.h>
54 #include <dns/tsig.h>
55 #include <dns/update.h>
56 #include <dns/view.h>
57 #include <dns/zone.h>
58 #include <dns/zt.h>
59 
60 
61 /**************************************************************************/
62 
63 /*%
64  * Log level for tracing dynamic update protocol requests.
65  */
66 #define LOGLEVEL_PROTOCOL	ISC_LOG_INFO
67 
68 /*%
69  * Log level for low-level debug tracing.
70  */
71 #define LOGLEVEL_DEBUG		ISC_LOG_DEBUG(8)
72 
73 /*%
74  * Check an operation for failure.  These macros all assume that
75  * the function using them has a 'result' variable and a 'failure'
76  * label.
77  */
78 #define CHECK(op) \
79 	do { result = (op); \
80 		if (result != ISC_R_SUCCESS) goto failure; \
81 	} while (/*CONSTCOND*/0)
82 
83 /*%
84  * Fail unconditionally with result 'code', which must not
85  * be ISC_R_SUCCESS.  The reason for failure presumably has
86  * been logged already.
87  *
88  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
89  * from complaining about "end-of-loop code not reached".
90  */
91 
92 #define FAIL(code) \
93 	do {							\
94 		result = (code);				\
95 		if (result != ISC_R_SUCCESS) goto failure;	\
96 	} while (/*CONSTCOND*/0)
97 
98 /*%
99  * Fail unconditionally and log as a client error.
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 #define FAILC(code, msg) \
104 	do {							\
105 		const char *_what = "failed";			\
106 		result = (code);				\
107 		switch (result) {				\
108 		case DNS_R_NXDOMAIN:				\
109 		case DNS_R_YXDOMAIN:				\
110 		case DNS_R_YXRRSET:				\
111 		case DNS_R_NXRRSET:				\
112 			_what = "unsuccessful";			\
113 		}						\
114 		update_log(log, zone, LOGLEVEL_PROTOCOL,	\
115 			   "update %s: %s (%s)", _what,		\
116 			   msg, isc_result_totext(result));	\
117 		if (result != ISC_R_SUCCESS) goto failure;	\
118 	} while (/*CONSTCOND*/0)
119 
120 #define FAILN(code, name, msg) \
121 	do {								\
122 		const char *_what = "failed";				\
123 		result = (code);					\
124 		switch (result) {					\
125 		case DNS_R_NXDOMAIN:					\
126 		case DNS_R_YXDOMAIN:					\
127 		case DNS_R_YXRRSET:					\
128 		case DNS_R_NXRRSET:					\
129 			_what = "unsuccessful";				\
130 		}							\
131 		if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) {	\
132 			char _nbuf[DNS_NAME_FORMATSIZE];		\
133 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
134 			update_log(log, zone, LOGLEVEL_PROTOCOL,	\
135 				   "update %s: %s: %s (%s)", _what, _nbuf, \
136 				   msg, isc_result_totext(result));	\
137 		}							\
138 		if (result != ISC_R_SUCCESS) goto failure;		\
139 	} while (/*CONSTCOND*/0)
140 
141 #define FAILNT(code, name, type, msg) \
142 	do {								\
143 		const char *_what = "failed";				\
144 		result = (code);					\
145 		switch (result) {					\
146 		case DNS_R_NXDOMAIN:					\
147 		case DNS_R_YXDOMAIN:					\
148 		case DNS_R_YXRRSET:					\
149 		case DNS_R_NXRRSET:					\
150 			_what = "unsuccessful";				\
151 		}							\
152 		if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) {	\
153 			char _nbuf[DNS_NAME_FORMATSIZE];		\
154 			char _tbuf[DNS_RDATATYPE_FORMATSIZE];		\
155 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
156 			dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
157 			update_log(log, zone, LOGLEVEL_PROTOCOL,	\
158 				   "update %s: %s/%s: %s (%s)",		\
159 				   _what, _nbuf, _tbuf, msg,		\
160 				   isc_result_totext(result));		\
161 		}							\
162 		if (result != ISC_R_SUCCESS) goto failure;		\
163 	} while (/*CONSTCOND*/0)
164 
165 /*%
166  * Fail unconditionally and log as a server error.
167  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
168  * from complaining about "end-of-loop code not reached".
169  */
170 #define FAILS(code, msg) \
171 	do {							\
172 		result = (code);				\
173 		update_log(log, zone, LOGLEVEL_PROTOCOL,	\
174 			   "error: %s: %s",			\
175 			   msg, isc_result_totext(result));	\
176 		if (result != ISC_R_SUCCESS) goto failure;	\
177 	} while (/*CONSTCOND*/0)
178 
179 /**************************************************************************/
180 
181 typedef struct rr rr_t;
182 
183 struct rr {
184 	/* dns_name_t name; */
185 	isc_uint32_t		ttl;
186 	dns_rdata_t		rdata;
187 };
188 
189 typedef struct update_event update_event_t;
190 
191 /**************************************************************************/
192 
193 static void
194 update_log(dns_update_log_t *callback, dns_zone_t *zone,
195 	   int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
196 
197 static void
198 update_log(dns_update_log_t *callback, dns_zone_t *zone,
199 	   int level, const char *fmt, ...)
200 {
201 	va_list ap;
202 	char message[4096];
203 
204 	if (callback == NULL)
205 		return;
206 
207 	if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
208 		return;
209 
210 
211 	va_start(ap, fmt);
212 	vsnprintf(message, sizeof(message), fmt, ap);
213 	va_end(ap);
214 
215 	(callback->func)(callback->arg, zone, level, message);
216 }
217 
218 /*%
219  * Update a single RR in version 'ver' of 'db' and log the
220  * update in 'diff'.
221  *
222  * Ensures:
223  * \li	'*tuple' == NULL.  Either the tuple is freed, or its
224  *	ownership has been transferred to the diff.
225  */
226 static isc_result_t
227 do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
228 	     dns_diff_t *diff)
229 {
230 	dns_diff_t temp_diff;
231 	isc_result_t result;
232 
233 	/*
234 	 * Create a singleton diff.
235 	 */
236 	dns_diff_init(diff->mctx, &temp_diff);
237 	ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
238 
239 	/*
240 	 * Apply it to the database.
241 	 */
242 	result = dns_diff_apply(&temp_diff, db, ver);
243 	ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
244 	if (result != ISC_R_SUCCESS) {
245 		dns_difftuple_free(tuple);
246 		return (result);
247 	}
248 
249 	/*
250 	 * Merge it into the current pending journal entry.
251 	 */
252 	dns_diff_appendminimal(diff, tuple);
253 
254 	/*
255 	 * Do not clear temp_diff.
256 	 */
257 	return (ISC_R_SUCCESS);
258 }
259 
260 static isc_result_t
261 update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
262 	      dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
263 	      dns_rdata_t *rdata)
264 {
265 	dns_difftuple_t *tuple = NULL;
266 	isc_result_t result;
267 	result = dns_difftuple_create(diff->mctx, op,
268 				      name, ttl, rdata, &tuple);
269 	if (result != ISC_R_SUCCESS)
270 		return (result);
271 	return (do_one_tuple(&tuple, db, ver, diff));
272 }
273 
274 /**************************************************************************/
275 /*
276  * Callback-style iteration over rdatasets and rdatas.
277  *
278  * foreach_rrset() can be used to iterate over the RRsets
279  * of a name and call a callback function with each
280  * one.  Similarly, foreach_rr() can be used to iterate
281  * over the individual RRs at name, optionally restricted
282  * to RRs of a given type.
283  *
284  * The callback functions are called "actions" and take
285  * two arguments: a void pointer for passing arbitrary
286  * context information, and a pointer to the current RRset
287  * or RR.  By convention, their names end in "_action".
288  */
289 
290 /*
291  * XXXRTH  We might want to make this public somewhere in libdns.
292  */
293 
294 /*%
295  * Function type for foreach_rrset() iterator actions.
296  */
297 typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
298 
299 /*%
300  * Function type for foreach_rr() iterator actions.
301  */
302 typedef isc_result_t rr_func(void *data, rr_t *rr);
303 
304 /*%
305  * Internal context struct for foreach_node_rr().
306  */
307 typedef struct {
308 	rr_func *	rr_action;
309 	void *		rr_action_data;
310 } foreach_node_rr_ctx_t;
311 
312 /*%
313  * Internal helper function for foreach_node_rr().
314  */
315 static isc_result_t
316 foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
317 	isc_result_t result;
318 	foreach_node_rr_ctx_t *ctx = data;
319 	for (result = dns_rdataset_first(rdataset);
320 	     result == ISC_R_SUCCESS;
321 	     result = dns_rdataset_next(rdataset))
322 	{
323 		rr_t rr = { 0, DNS_RDATA_INIT };
324 
325 		dns_rdataset_current(rdataset, &rr.rdata);
326 		rr.ttl = rdataset->ttl;
327 		result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
328 		if (result != ISC_R_SUCCESS)
329 			return (result);
330 	}
331 	if (result != ISC_R_NOMORE)
332 		return (result);
333 	return (ISC_R_SUCCESS);
334 }
335 
336 /*%
337  * For each rdataset of 'name' in 'ver' of 'db', call 'action'
338  * with the rdataset and 'action_data' as arguments.  If the name
339  * does not exist, do nothing.
340  *
341  * If 'action' returns an error, abort iteration and return the error.
342  */
343 static isc_result_t
344 foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
345 	      rrset_func *action, void *action_data)
346 {
347 	isc_result_t result;
348 	dns_dbnode_t *node;
349 	dns_rdatasetiter_t *iter;
350 
351 	node = NULL;
352 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
353 	if (result == ISC_R_NOTFOUND)
354 		return (ISC_R_SUCCESS);
355 	if (result != ISC_R_SUCCESS)
356 		return (result);
357 
358 	iter = NULL;
359 	result = dns_db_allrdatasets(db, node, ver,
360 				     (isc_stdtime_t) 0, &iter);
361 	if (result != ISC_R_SUCCESS)
362 		goto cleanup_node;
363 
364 	for (result = dns_rdatasetiter_first(iter);
365 	     result == ISC_R_SUCCESS;
366 	     result = dns_rdatasetiter_next(iter))
367 	{
368 		dns_rdataset_t rdataset;
369 
370 		dns_rdataset_init(&rdataset);
371 		dns_rdatasetiter_current(iter, &rdataset);
372 
373 		result = (*action)(action_data, &rdataset);
374 
375 		dns_rdataset_disassociate(&rdataset);
376 		if (result != ISC_R_SUCCESS)
377 			goto cleanup_iterator;
378 	}
379 	if (result == ISC_R_NOMORE)
380 		result = ISC_R_SUCCESS;
381 
382  cleanup_iterator:
383 	dns_rdatasetiter_destroy(&iter);
384 
385  cleanup_node:
386 	dns_db_detachnode(db, &node);
387 
388 	return (result);
389 }
390 
391 /*%
392  * For each RR of 'name' in 'ver' of 'db', call 'action'
393  * with the RR and 'action_data' as arguments.  If the name
394  * does not exist, do nothing.
395  *
396  * If 'action' returns an error, abort iteration
397  * and return the error.
398  */
399 static isc_result_t
400 foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
401 		rr_func *rr_action, void *rr_action_data)
402 {
403 	foreach_node_rr_ctx_t ctx;
404 	ctx.rr_action = rr_action;
405 	ctx.rr_action_data = rr_action_data;
406 	return (foreach_rrset(db, ver, name,
407 			      foreach_node_rr_action, &ctx));
408 }
409 
410 
411 /*%
412  * For each of the RRs specified by 'db', 'ver', 'name', 'type',
413  * (which can be dns_rdatatype_any to match any type), and 'covers', call
414  * 'action' with the RR and 'action_data' as arguments. If the name
415  * does not exist, or if no RRset of the given type exists at the name,
416  * do nothing.
417  *
418  * If 'action' returns an error, abort iteration and return the error.
419  */
420 static isc_result_t
421 foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
422 	   dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
423 	   void *rr_action_data)
424 {
425 
426 	isc_result_t result;
427 	dns_dbnode_t *node;
428 	dns_rdataset_t rdataset;
429 
430 	if (type == dns_rdatatype_any)
431 		return (foreach_node_rr(db, ver, name,
432 					rr_action, rr_action_data));
433 
434 	node = NULL;
435 	if (type == dns_rdatatype_nsec3 ||
436 	    (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
437 		result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
438 	else
439 		result = dns_db_findnode(db, name, ISC_FALSE, &node);
440 	if (result == ISC_R_NOTFOUND)
441 		return (ISC_R_SUCCESS);
442 	if (result != ISC_R_SUCCESS)
443 		return (result);
444 
445 	dns_rdataset_init(&rdataset);
446 	result = dns_db_findrdataset(db, node, ver, type, covers,
447 				     (isc_stdtime_t) 0, &rdataset, NULL);
448 	if (result == ISC_R_NOTFOUND) {
449 		result = ISC_R_SUCCESS;
450 		goto cleanup_node;
451 	}
452 	if (result != ISC_R_SUCCESS)
453 		goto cleanup_node;
454 
455 	for (result = dns_rdataset_first(&rdataset);
456 	     result == ISC_R_SUCCESS;
457 	     result = dns_rdataset_next(&rdataset))
458 	{
459 		rr_t rr = { 0, DNS_RDATA_INIT };
460 		dns_rdataset_current(&rdataset, &rr.rdata);
461 		rr.ttl = rdataset.ttl;
462 		result = (*rr_action)(rr_action_data, &rr);
463 		if (result != ISC_R_SUCCESS)
464 			goto cleanup_rdataset;
465 	}
466 	if (result != ISC_R_NOMORE)
467 		goto cleanup_rdataset;
468 	result = ISC_R_SUCCESS;
469 
470  cleanup_rdataset:
471 	dns_rdataset_disassociate(&rdataset);
472  cleanup_node:
473 	dns_db_detachnode(db, &node);
474 
475 	return (result);
476 }
477 
478 /**************************************************************************/
479 /*
480  * Various tests on the database contents (for prerequisites, etc).
481  */
482 
483 /*%
484  * Function type for predicate functions that compare a database RR 'db_rr'
485  * against an update RR 'update_rr'.
486  */
487 typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
488 
489 /*%
490  * Helper function for rrset_exists().
491  */
492 static isc_result_t
493 rrset_exists_action(void *data, rr_t *rr) {
494 	UNUSED(data);
495 	UNUSED(rr);
496 	return (ISC_R_EXISTS);
497 }
498 
499 /*%
500  * Utility macro for RR existence checking functions.
501  *
502  * If the variable 'result' has the value ISC_R_EXISTS or
503  * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
504  * respectively, and return success.
505  *
506  * If 'result' has any other value, there was a failure.
507  * Return the failure result code and do not set *exists.
508  *
509  * This would be more readable as "do { if ... } while(0)",
510  * but that form generates tons of warnings on Solaris 2.6.
511  */
512 #define RETURN_EXISTENCE_FLAG				\
513 	return ((result == ISC_R_EXISTS) ?		\
514 		(*exists = ISC_TRUE, ISC_R_SUCCESS) :	\
515 		((result == ISC_R_SUCCESS) ?		\
516 		 (*exists = ISC_FALSE, ISC_R_SUCCESS) :	\
517 		 result))
518 
519 /*%
520  * Set '*exists' to true iff an rrset of the given type exists,
521  * to false otherwise.
522  */
523 static isc_result_t
524 rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
525 	     dns_rdatatype_t type, dns_rdatatype_t covers,
526 	     isc_boolean_t *exists)
527 {
528 	isc_result_t result;
529 	result = foreach_rr(db, ver, name, type, covers,
530 			    rrset_exists_action, NULL);
531 	RETURN_EXISTENCE_FLAG;
532 }
533 
534 /*%
535  * Set '*visible' to true if the RRset exists and is part of the
536  * visible zone.  Otherwise '*visible' is set to false unless a
537  * error occurs.
538  */
539 static isc_result_t
540 rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
541 	      dns_rdatatype_t type, isc_boolean_t *visible)
542 {
543 	isc_result_t result;
544 	dns_fixedname_t fixed;
545 
546 	dns_fixedname_init(&fixed);
547 	result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD,
548 			     (isc_stdtime_t) 0, NULL,
549 			     dns_fixedname_name(&fixed), NULL, NULL);
550 	switch (result) {
551 	case ISC_R_SUCCESS:
552 		*visible = ISC_TRUE;
553 		break;
554 	/*
555 	 * Glue, obscured, deleted or replaced records.
556 	 */
557 	case DNS_R_DELEGATION:
558 	case DNS_R_DNAME:
559 	case DNS_R_CNAME:
560 	case DNS_R_NXDOMAIN:
561 	case DNS_R_NXRRSET:
562 	case DNS_R_EMPTYNAME:
563 	case DNS_R_COVERINGNSEC:
564 		*visible = ISC_FALSE;
565 		result = ISC_R_SUCCESS;
566 		break;
567 	default:
568 		break;
569 	}
570 	return (result);
571 }
572 
573 /*%
574  * Context struct and helper function for name_exists().
575  */
576 
577 static isc_result_t
578 name_exists_action(void *data, dns_rdataset_t *rrset) {
579 	UNUSED(data);
580 	UNUSED(rrset);
581 	return (ISC_R_EXISTS);
582 }
583 
584 /*%
585  * Set '*exists' to true iff the given name exists, to false otherwise.
586  */
587 static isc_result_t
588 name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
589 	    isc_boolean_t *exists)
590 {
591 	isc_result_t result;
592 	result = foreach_rrset(db, ver, name,
593 			       name_exists_action, NULL);
594 	RETURN_EXISTENCE_FLAG;
595 }
596 
597 /**************************************************************************/
598 /*
599  * Checking of "RRset exists (value dependent)" prerequisites.
600  *
601  * In the RFC2136 section 3.2.5, this is the pseudocode involving
602  * a variable called "temp", a mapping of <name, type> tuples to rrsets.
603  *
604  * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
605  * where each tuple has op==DNS_DIFFOP_EXISTS.
606  */
607 
608 /*%
609  * A comparison function defining the sorting order for the entries
610  * in the "temp" data structure.  The major sort key is the owner name,
611  * followed by the type and rdata.
612  */
613 static int
614 temp_order(const void *av, const void *bv) {
615 	dns_difftuple_t const * const *ap = av;
616 	dns_difftuple_t const * const *bp = bv;
617 	dns_difftuple_t const *a = *ap;
618 	dns_difftuple_t const *b = *bp;
619 	int r;
620 	r = dns_name_compare(&a->name, &b->name);
621 	if (r != 0)
622 		return (r);
623 	r = (b->rdata.type - a->rdata.type);
624 	if (r != 0)
625 		return (r);
626 	r = dns_rdata_casecompare(&a->rdata, &b->rdata);
627 	return (r);
628 }
629 
630 /**************************************************************************/
631 /*
632  * Conditional deletion of RRs.
633  */
634 
635 /*%
636  * Context structure for delete_if().
637  */
638 
639 typedef struct {
640 	rr_predicate *predicate;
641 	dns_db_t *db;
642 	dns_dbversion_t *ver;
643 	dns_diff_t *diff;
644 	dns_name_t *name;
645 	dns_rdata_t *update_rr;
646 } conditional_delete_ctx_t;
647 
648 /*%
649  * Predicate functions for delete_if().
650  */
651 
652 /*%
653  * Return true always.
654  */
655 static isc_boolean_t
656 true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
657 	UNUSED(update_rr);
658 	UNUSED(db_rr);
659 	return (ISC_TRUE);
660 }
661 
662 /*%
663  * Return true if the record is a RRSIG.
664  */
665 static isc_boolean_t
666 rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
667 	UNUSED(update_rr);
668 	return ((db_rr->type == dns_rdatatype_rrsig) ?
669 		ISC_TRUE : ISC_FALSE);
670 }
671 
672 /*%
673  * Internal helper function for delete_if().
674  */
675 static isc_result_t
676 delete_if_action(void *data, rr_t *rr) {
677 	conditional_delete_ctx_t *ctx = data;
678 	if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
679 		isc_result_t result;
680 		result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
681 				       DNS_DIFFOP_DEL, ctx->name,
682 				       rr->ttl, &rr->rdata);
683 		return (result);
684 	} else {
685 		return (ISC_R_SUCCESS);
686 	}
687 }
688 
689 /*%
690  * Conditionally delete RRs.  Apply 'predicate' to the RRs
691  * specified by 'db', 'ver', 'name', and 'type' (which can
692  * be dns_rdatatype_any to match any type).  Delete those
693  * RRs for which the predicate returns true, and log the
694  * deletions in 'diff'.
695  */
696 static isc_result_t
697 delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
698 	  dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
699 	  dns_rdata_t *update_rr, dns_diff_t *diff)
700 {
701 	conditional_delete_ctx_t ctx;
702 	ctx.predicate = predicate;
703 	ctx.db = db;
704 	ctx.ver = ver;
705 	ctx.diff = diff;
706 	ctx.name = name;
707 	ctx.update_rr = update_rr;
708 	return (foreach_rr(db, ver, name, type, covers,
709 			   delete_if_action, &ctx));
710 }
711 
712 /**************************************************************************/
713 /*
714  * Incremental updating of NSECs and RRSIGs.
715  */
716 
717 /*%
718  * We abuse the dns_diff_t type to represent a set of domain names
719  * affected by the update.
720  */
721 static isc_result_t
722 namelist_append_name(dns_diff_t *list, dns_name_t *name) {
723 	isc_result_t result;
724 	dns_difftuple_t *tuple = NULL;
725 	static dns_rdata_t dummy_rdata = DNS_RDATA_INIT;
726 
727 	CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0,
728 				   &dummy_rdata, &tuple));
729 	dns_diff_append(list, &tuple);
730  failure:
731 	return (result);
732 }
733 
734 static isc_result_t
735 namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
736 {
737 	isc_result_t result;
738 	dns_fixedname_t fixedname;
739 	dns_name_t *child;
740 	dns_dbiterator_t *dbit = NULL;
741 
742 	dns_fixedname_init(&fixedname);
743 	child = dns_fixedname_name(&fixedname);
744 
745 	CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
746 
747 	for (result = dns_dbiterator_seek(dbit, name);
748 	     result == ISC_R_SUCCESS;
749 	     result = dns_dbiterator_next(dbit))
750 	{
751 		dns_dbnode_t *node = NULL;
752 		CHECK(dns_dbiterator_current(dbit, &node, child));
753 		dns_db_detachnode(db, &node);
754 		if (! dns_name_issubdomain(child, name))
755 			break;
756 		CHECK(namelist_append_name(affected, child));
757 	}
758 	if (result == ISC_R_NOMORE)
759 		result = ISC_R_SUCCESS;
760  failure:
761 	if (dbit != NULL)
762 		dns_dbiterator_destroy(&dbit);
763 	return (result);
764 }
765 
766 
767 
768 /*%
769  * Helper function for non_nsec_rrset_exists().
770  */
771 static isc_result_t
772 is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
773 	UNUSED(data);
774 	if (!(rrset->type == dns_rdatatype_nsec ||
775 	      rrset->type == dns_rdatatype_nsec3 ||
776 	      (rrset->type == dns_rdatatype_rrsig &&
777 	       (rrset->covers == dns_rdatatype_nsec ||
778 		rrset->covers == dns_rdatatype_nsec3))))
779 		return (ISC_R_EXISTS);
780 	return (ISC_R_SUCCESS);
781 }
782 
783 /*%
784  * Check whether there is an rrset other than a NSEC or RRSIG NSEC,
785  * i.e., anything that justifies the continued existence of a name
786  * after a secure update.
787  *
788  * If such an rrset exists, set '*exists' to ISC_TRUE.
789  * Otherwise, set it to ISC_FALSE.
790  */
791 static isc_result_t
792 non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
793 		     dns_name_t *name, isc_boolean_t *exists)
794 {
795 	isc_result_t result;
796 	result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
797 	RETURN_EXISTENCE_FLAG;
798 }
799 
800 /*%
801  * A comparison function for sorting dns_diff_t:s by name.
802  */
803 static int
804 name_order(const void *av, const void *bv) {
805 	dns_difftuple_t const * const *ap = av;
806 	dns_difftuple_t const * const *bp = bv;
807 	dns_difftuple_t const *a = *ap;
808 	dns_difftuple_t const *b = *bp;
809 	return (dns_name_compare(&a->name, &b->name));
810 }
811 
812 static isc_result_t
813 uniqify_name_list(dns_diff_t *list) {
814 	isc_result_t result;
815 	dns_difftuple_t *p, *q;
816 
817 	CHECK(dns_diff_sort(list, name_order));
818 
819 	p = ISC_LIST_HEAD(list->tuples);
820 	while (p != NULL) {
821 		do {
822 			q = ISC_LIST_NEXT(p, link);
823 			if (q == NULL || ! dns_name_equal(&p->name, &q->name))
824 				break;
825 			ISC_LIST_UNLINK(list->tuples, q, link);
826 			dns_difftuple_free(&q);
827 		} while (1);
828 		p = ISC_LIST_NEXT(p, link);
829 	}
830  failure:
831 	return (result);
832 }
833 
834 static isc_result_t
835 is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
836 	  isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure)
837 {
838 	isc_result_t result;
839 	dns_fixedname_t foundname;
840 	dns_fixedname_init(&foundname);
841 	result = dns_db_find(db, name, ver, dns_rdatatype_any,
842 			     DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
843 			     (isc_stdtime_t) 0, NULL,
844 			     dns_fixedname_name(&foundname),
845 			     NULL, NULL);
846 	if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
847 		*flag = ISC_TRUE;
848 		*cut = ISC_FALSE;
849 		if (unsecure != NULL)
850 			*unsecure = ISC_FALSE;
851 		return (ISC_R_SUCCESS);
852 	} else if (result == DNS_R_ZONECUT) {
853 		*flag = ISC_TRUE;
854 		*cut = ISC_TRUE;
855 		if (unsecure != NULL) {
856 			/*
857 			 * We are at the zonecut.  Check to see if there
858 			 * is a DS RRset.
859 			 */
860 			if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
861 					(isc_stdtime_t) 0, NULL,
862 					dns_fixedname_name(&foundname),
863 					NULL, NULL) == DNS_R_NXRRSET)
864 				*unsecure = ISC_TRUE;
865 			else
866 				*unsecure = ISC_FALSE;
867 		}
868 		return (ISC_R_SUCCESS);
869 	} else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
870 		   result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
871 		*flag = ISC_FALSE;
872 		*cut = ISC_FALSE;
873 		if (unsecure != NULL)
874 			*unsecure = ISC_FALSE;
875 		return (ISC_R_SUCCESS);
876 	} else {
877 		/*
878 		 * Silence compiler.
879 		 */
880 		*flag = ISC_FALSE;
881 		*cut = ISC_FALSE;
882 		if (unsecure != NULL)
883 			*unsecure = ISC_FALSE;
884 		return (result);
885 	}
886 }
887 
888 /*%
889  * Find the next/previous name that has a NSEC record.
890  * In other words, skip empty database nodes and names that
891  * have had their NSECs removed because they are obscured by
892  * a zone cut.
893  */
894 static isc_result_t
895 next_active(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
896 	    dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname,
897 	    isc_boolean_t forward)
898 {
899 	isc_result_t result;
900 	dns_dbiterator_t *dbit = NULL;
901 	isc_boolean_t has_nsec = ISC_FALSE;
902 	unsigned int wraps = 0;
903 	isc_boolean_t secure = dns_db_issecure(db);
904 
905 	CHECK(dns_db_createiterator(db, 0, &dbit));
906 
907 	CHECK(dns_dbiterator_seek(dbit, oldname));
908 	do {
909 		dns_dbnode_t *node = NULL;
910 
911 		if (forward)
912 			result = dns_dbiterator_next(dbit);
913 		else
914 			result = dns_dbiterator_prev(dbit);
915 		if (result == ISC_R_NOMORE) {
916 			/*
917 			 * Wrap around.
918 			 */
919 			if (forward)
920 				CHECK(dns_dbiterator_first(dbit));
921 			else
922 				CHECK(dns_dbiterator_last(dbit));
923 			wraps++;
924 			if (wraps == 2) {
925 				update_log(log, zone, ISC_LOG_ERROR,
926 					   "secure zone with no NSECs");
927 				result = DNS_R_BADZONE;
928 				goto failure;
929 			}
930 		}
931 		CHECK(dns_dbiterator_current(dbit, &node, newname));
932 		dns_db_detachnode(db, &node);
933 
934 		/*
935 		 * The iterator may hold the tree lock, and
936 		 * rrset_exists() calls dns_db_findnode() which
937 		 * may try to reacquire it.  To avoid deadlock
938 		 * we must pause the iterator first.
939 		 */
940 		CHECK(dns_dbiterator_pause(dbit));
941 		if (secure) {
942 			CHECK(rrset_exists(db, ver, newname,
943 					   dns_rdatatype_nsec, 0, &has_nsec));
944 		} else {
945 			dns_fixedname_t ffound;
946 			dns_name_t *found;
947 			dns_fixedname_init(&ffound);
948 			found = dns_fixedname_name(&ffound);
949 			result = dns_db_find(db, newname, ver,
950 					     dns_rdatatype_soa,
951 					     DNS_DBFIND_NOWILD, 0, NULL, found,
952 					     NULL, NULL);
953 			if (result == ISC_R_SUCCESS ||
954 			    result == DNS_R_EMPTYNAME ||
955 			    result == DNS_R_NXRRSET ||
956 			    result == DNS_R_CNAME ||
957 			    (result == DNS_R_DELEGATION &&
958 			     dns_name_equal(newname, found))) {
959 				has_nsec = ISC_TRUE;
960 				result = ISC_R_SUCCESS;
961 			} else if (result != DNS_R_NXDOMAIN)
962 				break;
963 		}
964 	} while (! has_nsec);
965  failure:
966 	if (dbit != NULL)
967 		dns_dbiterator_destroy(&dbit);
968 
969 	return (result);
970 }
971 
972 /*%
973  * Add a NSEC record for "name", recording the change in "diff".
974  * The existing NSEC is removed.
975  */
976 static isc_result_t
977 add_nsec(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
978 	 dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl,
979 	 dns_diff_t *diff)
980 {
981 	isc_result_t result;
982 	dns_dbnode_t *node = NULL;
983 	unsigned char buffer[DNS_NSEC_BUFFERSIZE];
984 	dns_rdata_t rdata = DNS_RDATA_INIT;
985 	dns_difftuple_t *tuple = NULL;
986 	dns_fixedname_t fixedname;
987 	dns_name_t *target;
988 
989 	dns_fixedname_init(&fixedname);
990 	target = dns_fixedname_name(&fixedname);
991 
992 	/*
993 	 * Find the successor name, aka NSEC target.
994 	 */
995 	CHECK(next_active(log, zone, db, ver, name, target, ISC_TRUE));
996 
997 	/*
998 	 * Create the NSEC RDATA.
999 	 */
1000 	CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1001 	dns_rdata_init(&rdata);
1002 	CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
1003 	dns_db_detachnode(db, &node);
1004 
1005 	/*
1006 	 * Delete the old NSEC and record the change.
1007 	 */
1008 	CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0,
1009 			NULL, diff));
1010 	/*
1011 	 * Add the new NSEC and record the change.
1012 	 */
1013 	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
1014 				   nsecttl, &rdata, &tuple));
1015 	CHECK(do_one_tuple(&tuple, db, ver, diff));
1016 	INSIST(tuple == NULL);
1017 
1018  failure:
1019 	if (node != NULL)
1020 		dns_db_detachnode(db, &node);
1021 	return (result);
1022 }
1023 
1024 /*%
1025  * Add a placeholder NSEC record for "name", recording the change in "diff".
1026  */
1027 static isc_result_t
1028 add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1029 		     dns_diff_t *diff)
1030 {
1031 	isc_result_t result;
1032 	dns_difftuple_t *tuple = NULL;
1033 	isc_region_t r;
1034 	unsigned char data[1] = { 0 }; /* The root domain, no bits. */
1035 	dns_rdata_t rdata = DNS_RDATA_INIT;
1036 
1037 	r.base = data;
1038 	r.length = sizeof(data);
1039 	dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
1040 	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
1041 				   &rdata, &tuple));
1042 	CHECK(do_one_tuple(&tuple, db, ver, diff));
1043  failure:
1044 	return (result);
1045 }
1046 
1047 static isc_result_t
1048 find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
1049 	       isc_mem_t *mctx, unsigned int maxkeys,
1050 	       dst_key_t **keys, unsigned int *nkeys)
1051 {
1052 	isc_result_t result;
1053 	dns_dbnode_t *node = NULL;
1054 	const char *directory = dns_zone_getkeydirectory(zone);
1055 	CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1056 	CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
1057 				       directory, mctx, maxkeys, keys, nkeys));
1058  failure:
1059 	if (node != NULL)
1060 		dns_db_detachnode(db, &node);
1061 	return (result);
1062 }
1063 
1064 /*%
1065  * Add RRSIG records for an RRset, recording the change in "diff".
1066  */
1067 static isc_result_t
1068 add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1069 	 dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type,
1070 	 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1071 	 isc_stdtime_t inception, isc_stdtime_t expire,
1072 	 isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
1073 {
1074 	isc_result_t result;
1075 	dns_dbnode_t *node = NULL;
1076 	dns_rdataset_t rdataset;
1077 	dns_rdata_t sig_rdata = DNS_RDATA_INIT;
1078 	isc_buffer_t buffer;
1079 	unsigned char data[1024]; /* XXX */
1080 	unsigned int i, j;
1081 	isc_boolean_t added_sig = ISC_FALSE;
1082 	isc_mem_t *mctx = diff->mctx;
1083 
1084 	dns_rdataset_init(&rdataset);
1085 	isc_buffer_init(&buffer, data, sizeof(data));
1086 
1087 	/* Get the rdataset to sign. */
1088 	if (type == dns_rdatatype_nsec3)
1089 		CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
1090 	else
1091 		CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1092 	CHECK(dns_db_findrdataset(db, node, ver, type, 0,
1093 				  (isc_stdtime_t) 0, &rdataset, NULL));
1094 	dns_db_detachnode(db, &node);
1095 
1096 #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
1097 #define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
1098 #define ALG(x) dst_key_alg(x)
1099 
1100 	/*
1101 	 * If we are honoring KSK flags then we need to check that we
1102 	 * have both KSK and non-KSK keys that are not revoked per
1103 	 * algorithm.
1104 	 */
1105 	for (i = 0; i < nkeys; i++) {
1106 		isc_boolean_t both = ISC_FALSE;
1107 
1108 		if (!dst_key_isprivate(keys[i]))
1109 			continue;
1110 
1111 		if (check_ksk && !REVOKE(keys[i])) {
1112 			isc_boolean_t have_ksk, have_nonksk;
1113 			if (KSK(keys[i])) {
1114 				have_ksk = ISC_TRUE;
1115 				have_nonksk = ISC_FALSE;
1116 			} else {
1117 				have_ksk = ISC_FALSE;
1118 				have_nonksk = ISC_TRUE;
1119 			}
1120 			for (j = 0; j < nkeys; j++) {
1121 				if (j == i || ALG(keys[i]) != ALG(keys[j]))
1122 					continue;
1123 				if (REVOKE(keys[j]))
1124 					continue;
1125 				if (KSK(keys[j]))
1126 					have_ksk = ISC_TRUE;
1127 				else
1128 					have_nonksk = ISC_TRUE;
1129 				both = have_ksk && have_nonksk;
1130 				if (both)
1131 					break;
1132 			}
1133 		}
1134 
1135 		if (both) {
1136 			if (type == dns_rdatatype_dnskey) {
1137 				if (!KSK(keys[i]) && keyset_kskonly)
1138 					continue;
1139 			} else if (KSK(keys[i]))
1140 				continue;
1141 		} else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey)
1142 			continue;
1143 
1144 		/* Calculate the signature, creating a RRSIG RDATA. */
1145 		CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
1146 				      &inception, &expire,
1147 				      mctx, &buffer, &sig_rdata));
1148 
1149 		/* Update the database and journal with the RRSIG. */
1150 		/* XXX inefficient - will cause dataset merging */
1151 		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, name,
1152 				    rdataset.ttl, &sig_rdata));
1153 		dns_rdata_reset(&sig_rdata);
1154 		isc_buffer_init(&buffer, data, sizeof(data));
1155 		added_sig = ISC_TRUE;
1156 	}
1157 	if (!added_sig) {
1158 		update_log(log, zone, ISC_LOG_ERROR,
1159 			   "found no active private keys, "
1160 			   "unable to generate any signatures");
1161 		result = ISC_R_NOTFOUND;
1162 	}
1163 
1164  failure:
1165 	if (dns_rdataset_isassociated(&rdataset))
1166 		dns_rdataset_disassociate(&rdataset);
1167 	if (node != NULL)
1168 		dns_db_detachnode(db, &node);
1169 	return (result);
1170 }
1171 
1172 /*
1173  * Delete expired RRsigs and any RRsigs we are about to re-sign.
1174  * See also zone.c:del_sigs().
1175  */
1176 static isc_result_t
1177 del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1178 	    dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys)
1179 {
1180 	isc_result_t result;
1181 	dns_dbnode_t *node = NULL;
1182 	dns_rdataset_t rdataset;
1183 	dns_rdata_t rdata = DNS_RDATA_INIT;
1184 	unsigned int i;
1185 	dns_rdata_rrsig_t rrsig;
1186 	isc_boolean_t found;
1187 
1188 	dns_rdataset_init(&rdataset);
1189 
1190 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
1191 	if (result == ISC_R_NOTFOUND)
1192 		return (ISC_R_SUCCESS);
1193 	if (result != ISC_R_SUCCESS)
1194 		goto failure;
1195 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
1196 				     dns_rdatatype_dnskey, (isc_stdtime_t) 0,
1197 				     &rdataset, NULL);
1198 	dns_db_detachnode(db, &node);
1199 
1200 	if (result == ISC_R_NOTFOUND)
1201 		return (ISC_R_SUCCESS);
1202 	if (result != ISC_R_SUCCESS)
1203 		goto failure;
1204 
1205 	for (result = dns_rdataset_first(&rdataset);
1206 	     result == ISC_R_SUCCESS;
1207 	     result = dns_rdataset_next(&rdataset)) {
1208 		dns_rdataset_current(&rdataset, &rdata);
1209 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
1210 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1211 		found = ISC_FALSE;
1212 		for (i = 0; i < nkeys; i++) {
1213 			if (rrsig.keyid == dst_key_id(keys[i])) {
1214 				found = ISC_TRUE;
1215 				if (!dst_key_isprivate(keys[i]) &&
1216 				    !dst_key_inactive(keys[i]))
1217 				{
1218 					/*
1219 					 * The re-signing code in zone.c
1220 					 * will mark this as offline.
1221 					 * Just skip the record for now.
1222 					 */
1223 					break;
1224 				}
1225 				result = update_one_rr(db, ver, diff,
1226 						       DNS_DIFFOP_DEL, name,
1227 						       rdataset.ttl, &rdata);
1228 				break;
1229 			}
1230 		}
1231 		/*
1232 		 * If there is not a matching DNSKEY then delete the RRSIG.
1233 		 */
1234 		if (!found)
1235 			result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
1236 					       name, rdataset.ttl, &rdata);
1237 		dns_rdata_reset(&rdata);
1238 		if (result != ISC_R_SUCCESS)
1239 			break;
1240 	}
1241 	dns_rdataset_disassociate(&rdataset);
1242 	if (result == ISC_R_NOMORE)
1243 		result = ISC_R_SUCCESS;
1244 failure:
1245 	if (node != NULL)
1246 		dns_db_detachnode(db, &node);
1247 	return (result);
1248 }
1249 
1250 static isc_result_t
1251 add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1252 		 dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut,
1253 		 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1254 		 isc_stdtime_t inception, isc_stdtime_t expire,
1255 		 isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
1256 {
1257 	isc_result_t result;
1258 	dns_dbnode_t *node;
1259 	dns_rdatasetiter_t *iter;
1260 
1261 	node = NULL;
1262 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
1263 	if (result == ISC_R_NOTFOUND)
1264 		return (ISC_R_SUCCESS);
1265 	if (result != ISC_R_SUCCESS)
1266 		return (result);
1267 
1268 	iter = NULL;
1269 	result = dns_db_allrdatasets(db, node, ver,
1270 				     (isc_stdtime_t) 0, &iter);
1271 	if (result != ISC_R_SUCCESS)
1272 		goto cleanup_node;
1273 
1274 	for (result = dns_rdatasetiter_first(iter);
1275 	     result == ISC_R_SUCCESS;
1276 	     result = dns_rdatasetiter_next(iter))
1277 	{
1278 		dns_rdataset_t rdataset;
1279 		dns_rdatatype_t type;
1280 		isc_boolean_t flag;
1281 
1282 		dns_rdataset_init(&rdataset);
1283 		dns_rdatasetiter_current(iter, &rdataset);
1284 		type = rdataset.type;
1285 		dns_rdataset_disassociate(&rdataset);
1286 
1287 		/*
1288 		 * We don't need to sign unsigned NSEC records at the cut
1289 		 * as they are handled elsewhere.
1290 		 */
1291 		if ((type == dns_rdatatype_rrsig) ||
1292 		    (cut && type != dns_rdatatype_ds))
1293 			continue;
1294 		result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
1295 				      type, &flag);
1296 		if (result != ISC_R_SUCCESS)
1297 			goto cleanup_iterator;
1298 		if (flag)
1299 			continue;;
1300 		result = add_sigs(log, zone, db, ver, name, type, diff,
1301 					  keys, nkeys, inception, expire,
1302 					  check_ksk, keyset_kskonly);
1303 		if (result != ISC_R_SUCCESS)
1304 			goto cleanup_iterator;
1305 	}
1306 	if (result == ISC_R_NOMORE)
1307 		result = ISC_R_SUCCESS;
1308 
1309  cleanup_iterator:
1310 	dns_rdatasetiter_destroy(&iter);
1311 
1312  cleanup_node:
1313 	dns_db_detachnode(db, &node);
1314 
1315 	return (result);
1316 }
1317 
1318 /*%
1319  * Update RRSIG, NSEC and NSEC3 records affected by an update.  The original
1320  * update, including the SOA serial update but excluding the RRSIG & NSEC
1321  * changes, is in "diff" and has already been applied to "newver" of "db".
1322  * The database version prior to the update is "oldver".
1323  *
1324  * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
1325  * and added (as a minimal diff) to "diff".
1326  *
1327  * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
1328  */
1329 isc_result_t
1330 dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1331 		      dns_dbversion_t *oldver, dns_dbversion_t *newver,
1332 		      dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
1333 {
1334 	isc_result_t result;
1335 	dns_difftuple_t *t;
1336 	dns_diff_t diffnames;
1337 	dns_diff_t affected;
1338 	dns_diff_t sig_diff;
1339 	dns_diff_t nsec_diff;
1340 	dns_diff_t nsec_mindiff;
1341 	isc_boolean_t flag, build_nsec, build_nsec3;
1342 	dst_key_t *zone_keys[DNS_MAXZONEKEYS];
1343 	unsigned int nkeys = 0;
1344 	unsigned int i;
1345 	isc_stdtime_t now, inception, expire;
1346 	dns_ttl_t nsecttl;
1347 	dns_rdata_soa_t soa;
1348 	dns_rdata_t rdata = DNS_RDATA_INIT;
1349 	dns_rdataset_t rdataset;
1350 	dns_dbnode_t *node = NULL;
1351 	isc_boolean_t check_ksk, keyset_kskonly;
1352 	isc_boolean_t unsecure;
1353 	isc_boolean_t cut;
1354 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
1355 
1356 	dns_diff_init(diff->mctx, &diffnames);
1357 	dns_diff_init(diff->mctx, &affected);
1358 
1359 	dns_diff_init(diff->mctx, &sig_diff);
1360 	dns_diff_init(diff->mctx, &nsec_diff);
1361 	dns_diff_init(diff->mctx, &nsec_mindiff);
1362 
1363 	result = find_zone_keys(zone, db, newver, diff->mctx,
1364 				DNS_MAXZONEKEYS, zone_keys, &nkeys);
1365 	if (result != ISC_R_SUCCESS) {
1366 		update_log(log, zone, ISC_LOG_ERROR,
1367 			   "could not get zone keys for secure dynamic update");
1368 		goto failure;
1369 	}
1370 
1371 	isc_stdtime_get(&now);
1372 	inception = now - 3600; /* Allow for some clock skew. */
1373 	expire = now + sigvalidityinterval;
1374 
1375 	/*
1376 	 * Do we look at the KSK flag on the DNSKEY to determining which
1377 	 * keys sign which RRsets?  First check the zone option then
1378 	 * check the keys flags to make sure at least one has a ksk set
1379 	 * and one doesn't.
1380 	 */
1381 	check_ksk = ISC_TF((dns_zone_getoptions(zone) &
1382 			    DNS_ZONEOPT_UPDATECHECKKSK) != 0);
1383 	keyset_kskonly = ISC_TF((dns_zone_getoptions(zone) &
1384 				DNS_ZONEOPT_DNSKEYKSKONLY) != 0);
1385 
1386 	/*
1387 	 * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
1388 	 */
1389 	CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1390 	dns_rdataset_init(&rdataset);
1391 	CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0,
1392 				  (isc_stdtime_t) 0, &rdataset, NULL));
1393 	CHECK(dns_rdataset_first(&rdataset));
1394 	dns_rdataset_current(&rdataset, &rdata);
1395 	CHECK(dns_rdata_tostruct(&rdata, &soa, NULL));
1396 	nsecttl = soa.minimum;
1397 	dns_rdataset_disassociate(&rdataset);
1398 	dns_db_detachnode(db, &node);
1399 
1400 	/*
1401 	 * Find all RRsets directly affected by the update, and
1402 	 * update their RRSIGs.  Also build a list of names affected
1403 	 * by the update in "diffnames".
1404 	 */
1405 	CHECK(dns_diff_sort(diff, temp_order));
1406 
1407 	t = ISC_LIST_HEAD(diff->tuples);
1408 	while (t != NULL) {
1409 		dns_name_t *name = &t->name;
1410 		/* Now "name" is a new, unique name affected by the update. */
1411 
1412 		CHECK(namelist_append_name(&diffnames, name));
1413 
1414 		while (t != NULL && dns_name_equal(&t->name, name)) {
1415 			dns_rdatatype_t type;
1416 			type = t->rdata.type;
1417 
1418 			/*
1419 			 * Now "name" and "type" denote a new unique RRset
1420 			 * affected by the update.
1421 			 */
1422 
1423 			/* Don't sign RRSIGs. */
1424 			if (type == dns_rdatatype_rrsig)
1425 				goto skip;
1426 
1427 			/*
1428 			 * Delete all old RRSIGs covering this type, since they
1429 			 * are all invalid when the signed RRset has changed.
1430 			 * We may not be able to recreate all of them - tough.
1431 			 * Special case changes to the zone's DNSKEY records
1432 			 * to support offline KSKs.
1433 			 */
1434 			if (type == dns_rdatatype_dnskey)
1435 				del_keysigs(db, newver, name, &sig_diff,
1436 					    zone_keys, nkeys);
1437 			else
1438 				CHECK(delete_if(true_p, db, newver, name,
1439 						dns_rdatatype_rrsig, type,
1440 						NULL, &sig_diff));
1441 
1442 			/*
1443 			 * If this RRset is still visible after the update,
1444 			 * add a new signature for it.
1445 			 */
1446 			CHECK(rrset_visible(db, newver, name, type, &flag));
1447 			if (flag) {
1448 				CHECK(add_sigs(log, zone, db, newver, name,
1449 					       type, &sig_diff, zone_keys,
1450 					       nkeys, inception, expire,
1451 					       check_ksk, keyset_kskonly));
1452 			}
1453 		skip:
1454 			/* Skip any other updates to the same RRset. */
1455 			while (t != NULL &&
1456 			       dns_name_equal(&t->name, name) &&
1457 			       t->rdata.type == type)
1458 			{
1459 				t = ISC_LIST_NEXT(t, link);
1460 			}
1461 		}
1462 	}
1463 	update_log(log, zone, ISC_LOG_DEBUG(3), "updated data signatures");
1464 
1465 	/* Remove orphaned NSECs and RRSIG NSECs. */
1466 	for (t = ISC_LIST_HEAD(diffnames.tuples);
1467 	     t != NULL;
1468 	     t = ISC_LIST_NEXT(t, link))
1469 	{
1470 		CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag));
1471 		if (! flag) {
1472 			CHECK(delete_if(true_p, db, newver, &t->name,
1473 					dns_rdatatype_any, 0,
1474 					NULL, &sig_diff));
1475 		}
1476 	}
1477 	update_log(log, zone, ISC_LOG_DEBUG(3),
1478 		   "removed any orphaned NSEC records");
1479 
1480 	/*
1481 	 * See if we need to build NSEC or NSEC3 chains.
1482 	 */
1483 	CHECK(dns_private_chains(db, newver, privatetype, &build_nsec,
1484 				 &build_nsec3));
1485 	if (!build_nsec)
1486 		goto update_nsec3;
1487 
1488 	update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
1489 
1490 	/*
1491 	 * When a name is created or deleted, its predecessor needs to
1492 	 * have its NSEC updated.
1493 	 */
1494 	for (t = ISC_LIST_HEAD(diffnames.tuples);
1495 	     t != NULL;
1496 	     t = ISC_LIST_NEXT(t, link))
1497 	{
1498 		isc_boolean_t existed, exists;
1499 		dns_fixedname_t fixedname;
1500 		dns_name_t *prevname;
1501 
1502 		dns_fixedname_init(&fixedname);
1503 		prevname = dns_fixedname_name(&fixedname);
1504 
1505 		if (oldver != NULL)
1506 			CHECK(name_exists(db, oldver, &t->name, &existed));
1507 		else
1508 			existed = ISC_FALSE;
1509 		CHECK(name_exists(db, newver, &t->name, &exists));
1510 		if (exists == existed)
1511 			continue;
1512 
1513 		/*
1514 		 * Find the predecessor.
1515 		 * When names become obscured or unobscured in this update
1516 		 * transaction, we may find the wrong predecessor because
1517 		 * the NSECs have not yet been updated to reflect the delegation
1518 		 * change.  This should not matter because in this case,
1519 		 * the correct predecessor is either the delegation node or
1520 		 * a newly unobscured node, and those nodes are on the
1521 		 * "affected" list in any case.
1522 		 */
1523 		CHECK(next_active(log, zone, db, newver,
1524 				  &t->name, prevname, ISC_FALSE));
1525 		CHECK(namelist_append_name(&affected, prevname));
1526 	}
1527 
1528 	/*
1529 	 * Find names potentially affected by delegation changes
1530 	 * (obscured by adding an NS or DNAME, or unobscured by
1531 	 * removing one).
1532 	 */
1533 	for (t = ISC_LIST_HEAD(diffnames.tuples);
1534 	     t != NULL;
1535 	     t = ISC_LIST_NEXT(t, link))
1536 	{
1537 		isc_boolean_t ns_existed, dname_existed;
1538 		isc_boolean_t ns_exists, dname_exists;
1539 
1540 		if (oldver != NULL)
1541 			CHECK(rrset_exists(db, oldver, &t->name,
1542 					  dns_rdatatype_ns, 0, &ns_existed));
1543 		else
1544 			ns_existed = ISC_FALSE;
1545 		if (oldver != NULL)
1546 			CHECK(rrset_exists(db, oldver, &t->name,
1547 					   dns_rdatatype_dname, 0,
1548 					   &dname_existed));
1549 		else
1550 			dname_existed = ISC_FALSE;
1551 		CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0,
1552 				   &ns_exists));
1553 		CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0,
1554 				   &dname_exists));
1555 		if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
1556 			continue;
1557 		/*
1558 		 * There was a delegation change.  Mark all subdomains
1559 		 * of t->name as potentially needing a NSEC update.
1560 		 */
1561 		CHECK(namelist_append_subdomain(db, &t->name, &affected));
1562 	}
1563 
1564 	ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link);
1565 	INSIST(ISC_LIST_EMPTY(diffnames.tuples));
1566 
1567 	CHECK(uniqify_name_list(&affected));
1568 
1569 	/*
1570 	 * Determine which names should have NSECs, and delete/create
1571 	 * NSECs to make it so.  We don't know the final NSEC targets yet,
1572 	 * so we just create placeholder NSECs with arbitrary contents
1573 	 * to indicate that their respective owner names should be part of
1574 	 * the NSEC chain.
1575 	 */
1576 	for (t = ISC_LIST_HEAD(affected.tuples);
1577 	     t != NULL;
1578 	     t = ISC_LIST_NEXT(t, link))
1579 	{
1580 		isc_boolean_t exists;
1581 		dns_name_t *name = &t->name;
1582 
1583 		CHECK(name_exists(db, newver, name, &exists));
1584 		if (! exists)
1585 			continue;
1586 		CHECK(is_active(db, newver, name, &flag, &cut, NULL));
1587 		if (!flag) {
1588 			/*
1589 			 * This name is obscured.  Delete any
1590 			 * existing NSEC record.
1591 			 */
1592 			CHECK(delete_if(true_p, db, newver, name,
1593 					dns_rdatatype_nsec, 0,
1594 					NULL, &nsec_diff));
1595 			CHECK(delete_if(rrsig_p, db, newver, name,
1596 					dns_rdatatype_any, 0, NULL, diff));
1597 		} else {
1598 			/*
1599 			 * This name is not obscured.  It needs to have a
1600 			 * NSEC unless it is the at the origin, in which
1601 			 * case it should already exist if there is a complete
1602 			 * NSEC chain and if there isn't a complete NSEC chain
1603 			 * we don't want to add one as that would signal that
1604 			 * there is a complete NSEC chain.
1605 			 */
1606 			if (!dns_name_equal(name, dns_db_origin(db))) {
1607 				CHECK(rrset_exists(db, newver, name,
1608 						   dns_rdatatype_nsec, 0,
1609 						   &flag));
1610 				if (!flag)
1611 					CHECK(add_placeholder_nsec(db, newver,
1612 								   name, diff));
1613 			}
1614 			CHECK(add_exposed_sigs(log, zone, db, newver, name,
1615 					       cut, &sig_diff, zone_keys, nkeys,
1616 					       inception, expire, check_ksk,
1617 					       keyset_kskonly));
1618 		}
1619 	}
1620 
1621 	/*
1622 	 * Now we know which names are part of the NSEC chain.
1623 	 * Make them all point at their correct targets.
1624 	 */
1625 	for (t = ISC_LIST_HEAD(affected.tuples);
1626 	     t != NULL;
1627 	     t = ISC_LIST_NEXT(t, link))
1628 	{
1629 		CHECK(rrset_exists(db, newver, &t->name,
1630 				   dns_rdatatype_nsec, 0, &flag));
1631 		if (flag) {
1632 			/*
1633 			 * There is a NSEC, but we don't know if it is correct.
1634 			 * Delete it and create a correct one to be sure.
1635 			 * If the update was unnecessary, the diff minimization
1636 			 * will take care of eliminating it from the journal,
1637 			 * IXFRs, etc.
1638 			 *
1639 			 * The RRSIG bit should always be set in the NSECs
1640 			 * we generate, because they will all get RRSIG NSECs.
1641 			 * (XXX what if the zone keys are missing?).
1642 			 * Because the RRSIG NSECs have not necessarily been
1643 			 * created yet, the correctness of the bit mask relies
1644 			 * on the assumption that NSECs are only created if
1645 			 * there is other data, and if there is other data,
1646 			 * there are other RRSIGs.
1647 			 */
1648 			CHECK(add_nsec(log, zone, db, newver, &t->name,
1649 				       nsecttl, &nsec_diff));
1650 		}
1651 	}
1652 
1653 	/*
1654 	 * Minimize the set of NSEC updates so that we don't
1655 	 * have to regenerate the RRSIG NSECs for NSECs that were
1656 	 * replaced with identical ones.
1657 	 */
1658 	while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
1659 		ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
1660 		dns_diff_appendminimal(&nsec_mindiff, &t);
1661 	}
1662 
1663 	update_log(log, zone, ISC_LOG_DEBUG(3), "signing rebuilt NSEC chain");
1664 
1665 	/* Update RRSIG NSECs. */
1666 	for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
1667 	     t != NULL;
1668 	     t = ISC_LIST_NEXT(t, link))
1669 	{
1670 		if (t->op == DNS_DIFFOP_DEL) {
1671 			CHECK(delete_if(true_p, db, newver, &t->name,
1672 					dns_rdatatype_rrsig, dns_rdatatype_nsec,
1673 					NULL, &sig_diff));
1674 		} else if (t->op == DNS_DIFFOP_ADD) {
1675 			CHECK(add_sigs(log, zone, db, newver, &t->name,
1676 				       dns_rdatatype_nsec, &sig_diff,
1677 				       zone_keys, nkeys, inception, expire,
1678 				       check_ksk, keyset_kskonly));
1679 		} else {
1680 			INSIST(0);
1681 		}
1682 	}
1683 
1684  update_nsec3:
1685 
1686 	/* Record our changes for the journal. */
1687 	while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
1688 		ISC_LIST_UNLINK(sig_diff.tuples, t, link);
1689 		dns_diff_appendminimal(diff, &t);
1690 	}
1691 	while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
1692 		ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
1693 		dns_diff_appendminimal(diff, &t);
1694 	}
1695 
1696 	INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
1697 	INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
1698 	INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
1699 
1700 	if (!build_nsec3) {
1701 		update_log(log, zone, ISC_LOG_DEBUG(3),
1702 			   "no NSEC3 chains to rebuild");
1703 		goto failure;
1704 	}
1705 
1706 	update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC3 chains");
1707 
1708 	dns_diff_clear(&diffnames);
1709 	dns_diff_clear(&affected);
1710 
1711 	CHECK(dns_diff_sort(diff, temp_order));
1712 
1713 	/*
1714 	 * Find names potentially affected by delegation changes
1715 	 * (obscured by adding an NS or DNAME, or unobscured by
1716 	 * removing one).
1717 	 */
1718 	t = ISC_LIST_HEAD(diff->tuples);
1719 	while (t != NULL) {
1720 		dns_name_t *name = &t->name;
1721 
1722 		isc_boolean_t ns_existed, dname_existed;
1723 		isc_boolean_t ns_exists, dname_exists;
1724 		isc_boolean_t exists, existed;
1725 
1726 		if (t->rdata.type == dns_rdatatype_nsec ||
1727 		    t->rdata.type == dns_rdatatype_rrsig) {
1728 			t = ISC_LIST_NEXT(t, link);
1729 			continue;
1730 		}
1731 
1732 		CHECK(namelist_append_name(&affected, name));
1733 
1734 		if (oldver != NULL)
1735 			CHECK(rrset_exists(db, oldver, name, dns_rdatatype_ns,
1736 					   0, &ns_existed));
1737 		else
1738 			ns_existed = ISC_FALSE;
1739 		if (oldver != NULL)
1740 			CHECK(rrset_exists(db, oldver, name,
1741 					   dns_rdatatype_dname, 0,
1742 					   &dname_existed));
1743 		else
1744 			dname_existed = ISC_FALSE;
1745 		CHECK(rrset_exists(db, newver, name, dns_rdatatype_ns, 0,
1746 				   &ns_exists));
1747 		CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0,
1748 				   &dname_exists));
1749 
1750 		exists = ns_exists || dname_exists;
1751 		existed = ns_existed || dname_existed;
1752 		if (exists == existed)
1753 			goto nextname;
1754 		/*
1755 		 * There was a delegation change.  Mark all subdomains
1756 		 * of t->name as potentially needing a NSEC3 update.
1757 		 */
1758 		CHECK(namelist_append_subdomain(db, name, &affected));
1759 
1760 	nextname:
1761 		while (t != NULL && dns_name_equal(&t->name, name))
1762 			t = ISC_LIST_NEXT(t, link);
1763 	}
1764 
1765 	for (t = ISC_LIST_HEAD(affected.tuples);
1766 	     t != NULL;
1767 	     t = ISC_LIST_NEXT(t, link)) {
1768 		dns_name_t *name = &t->name;
1769 
1770 		unsecure = ISC_FALSE;	/* Silence compiler warning. */
1771 		CHECK(is_active(db, newver, name, &flag, &cut, &unsecure));
1772 
1773 		if (!flag) {
1774 			CHECK(delete_if(rrsig_p, db, newver, name,
1775 					dns_rdatatype_any, 0, NULL, diff));
1776 			CHECK(dns_nsec3_delnsec3sx(db, newver, name,
1777 						   privatetype, &nsec_diff));
1778 		} else {
1779 			CHECK(add_exposed_sigs(log, zone, db, newver, name,
1780 					       cut, &sig_diff, zone_keys, nkeys,
1781 					       inception, expire, check_ksk,
1782 					       keyset_kskonly));
1783 			CHECK(dns_nsec3_addnsec3sx(db, newver, name, nsecttl,
1784 						   unsecure, privatetype,
1785 						   &nsec_diff));
1786 		}
1787 	}
1788 
1789 	/*
1790 	 * Minimize the set of NSEC3 updates so that we don't
1791 	 * have to regenerate the RRSIG NSEC3s for NSEC3s that were
1792 	 * replaced with identical ones.
1793 	 */
1794 	while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
1795 		ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
1796 		dns_diff_appendminimal(&nsec_mindiff, &t);
1797 	}
1798 
1799 	update_log(log, zone, ISC_LOG_DEBUG(3),
1800 		   "signing rebuilt NSEC3 chain");
1801 
1802 	/* Update RRSIG NSEC3s. */
1803 	for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
1804 	     t != NULL;
1805 	     t = ISC_LIST_NEXT(t, link))
1806 	{
1807 		if (t->op == DNS_DIFFOP_DEL) {
1808 			CHECK(delete_if(true_p, db, newver, &t->name,
1809 					dns_rdatatype_rrsig,
1810 					dns_rdatatype_nsec3,
1811 					NULL, &sig_diff));
1812 		} else if (t->op == DNS_DIFFOP_ADD) {
1813 			CHECK(add_sigs(log, zone, db, newver, &t->name,
1814 				       dns_rdatatype_nsec3,
1815 				       &sig_diff, zone_keys, nkeys,
1816 				       inception, expire, check_ksk,
1817 				       keyset_kskonly));
1818 		} else {
1819 			INSIST(0);
1820 		}
1821 	}
1822 
1823 	/* Record our changes for the journal. */
1824 	while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
1825 		ISC_LIST_UNLINK(sig_diff.tuples, t, link);
1826 		dns_diff_appendminimal(diff, &t);
1827 	}
1828 	while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
1829 		ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
1830 		dns_diff_appendminimal(diff, &t);
1831 	}
1832 
1833 	INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
1834 	INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
1835 	INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
1836 
1837  failure:
1838 	dns_diff_clear(&sig_diff);
1839 	dns_diff_clear(&nsec_diff);
1840 	dns_diff_clear(&nsec_mindiff);
1841 
1842 	dns_diff_clear(&affected);
1843 	dns_diff_clear(&diffnames);
1844 
1845 	for (i = 0; i < nkeys; i++)
1846 		dst_key_free(&zone_keys[i]);
1847 
1848 	return (result);
1849 }
1850 
1851 isc_uint32_t
1852 dns_update_soaserial(isc_uint32_t serial, dns_updatemethod_t method) {
1853 	isc_stdtime_t now;
1854 
1855 	if (method == dns_updatemethod_unixtime) {
1856 		isc_stdtime_get(&now);
1857 		if (now != 0 && isc_serial_gt(now, serial))
1858 			return (now);
1859 	}
1860 
1861 	/* RFC1982 */
1862 	serial = (serial + 1) & 0xFFFFFFFF;
1863 	if (serial == 0)
1864 		serial = 1;
1865 
1866 	return (serial);
1867 }
1868