1/*	$NetBSD: update.c,v 1.2 2012/12/04 23:38:43 spz Exp $	*/
2
3/*
4 * Copyright (C) 2011, 2012  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
181typedef struct rr rr_t;
182
183struct rr {
184	/* dns_name_t name; */
185	isc_uint32_t		ttl;
186	dns_rdata_t		rdata;
187};
188
189typedef struct update_event update_event_t;
190
191/**************************************************************************/
192
193static void
194update_log(dns_update_log_t *callback, dns_zone_t *zone,
195	   int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
196
197static void
198update_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 */
226static isc_result_t
227do_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	temp_diff.resign = diff->resign;
238	ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
239
240	/*
241	 * Apply it to the database.
242	 */
243	result = dns_diff_apply(&temp_diff, db, ver);
244	ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
245	if (result != ISC_R_SUCCESS) {
246		dns_difftuple_free(tuple);
247		return (result);
248	}
249
250	/*
251	 * Merge it into the current pending journal entry.
252	 */
253	dns_diff_appendminimal(diff, tuple);
254
255	/*
256	 * Do not clear temp_diff.
257	 */
258	return (ISC_R_SUCCESS);
259}
260
261static isc_result_t
262update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
263	      dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
264	      dns_rdata_t *rdata)
265{
266	dns_difftuple_t *tuple = NULL;
267	isc_result_t result;
268	result = dns_difftuple_create(diff->mctx, op,
269				      name, ttl, rdata, &tuple);
270	if (result != ISC_R_SUCCESS)
271		return (result);
272	return (do_one_tuple(&tuple, db, ver, diff));
273}
274
275/**************************************************************************/
276/*
277 * Callback-style iteration over rdatasets and rdatas.
278 *
279 * foreach_rrset() can be used to iterate over the RRsets
280 * of a name and call a callback function with each
281 * one.  Similarly, foreach_rr() can be used to iterate
282 * over the individual RRs at name, optionally restricted
283 * to RRs of a given type.
284 *
285 * The callback functions are called "actions" and take
286 * two arguments: a void pointer for passing arbitrary
287 * context information, and a pointer to the current RRset
288 * or RR.  By convention, their names end in "_action".
289 */
290
291/*
292 * XXXRTH  We might want to make this public somewhere in libdns.
293 */
294
295/*%
296 * Function type for foreach_rrset() iterator actions.
297 */
298typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
299
300/*%
301 * Function type for foreach_rr() iterator actions.
302 */
303typedef isc_result_t rr_func(void *data, rr_t *rr);
304
305/*%
306 * Internal context struct for foreach_node_rr().
307 */
308typedef struct {
309	rr_func *	rr_action;
310	void *		rr_action_data;
311} foreach_node_rr_ctx_t;
312
313/*%
314 * Internal helper function for foreach_node_rr().
315 */
316static isc_result_t
317foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
318	isc_result_t result;
319	foreach_node_rr_ctx_t *ctx = data;
320	for (result = dns_rdataset_first(rdataset);
321	     result == ISC_R_SUCCESS;
322	     result = dns_rdataset_next(rdataset))
323	{
324		rr_t rr = { 0, DNS_RDATA_INIT };
325
326		dns_rdataset_current(rdataset, &rr.rdata);
327		rr.ttl = rdataset->ttl;
328		result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
329		if (result != ISC_R_SUCCESS)
330			return (result);
331	}
332	if (result != ISC_R_NOMORE)
333		return (result);
334	return (ISC_R_SUCCESS);
335}
336
337/*%
338 * For each rdataset of 'name' in 'ver' of 'db', call 'action'
339 * with the rdataset and 'action_data' as arguments.  If the name
340 * does not exist, do nothing.
341 *
342 * If 'action' returns an error, abort iteration and return the error.
343 */
344static isc_result_t
345foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
346	      rrset_func *action, void *action_data)
347{
348	isc_result_t result;
349	dns_dbnode_t *node;
350	dns_rdatasetiter_t *iter;
351
352	node = NULL;
353	result = dns_db_findnode(db, name, ISC_FALSE, &node);
354	if (result == ISC_R_NOTFOUND)
355		return (ISC_R_SUCCESS);
356	if (result != ISC_R_SUCCESS)
357		return (result);
358
359	iter = NULL;
360	result = dns_db_allrdatasets(db, node, ver,
361				     (isc_stdtime_t) 0, &iter);
362	if (result != ISC_R_SUCCESS)
363		goto cleanup_node;
364
365	for (result = dns_rdatasetiter_first(iter);
366	     result == ISC_R_SUCCESS;
367	     result = dns_rdatasetiter_next(iter))
368	{
369		dns_rdataset_t rdataset;
370
371		dns_rdataset_init(&rdataset);
372		dns_rdatasetiter_current(iter, &rdataset);
373
374		result = (*action)(action_data, &rdataset);
375
376		dns_rdataset_disassociate(&rdataset);
377		if (result != ISC_R_SUCCESS)
378			goto cleanup_iterator;
379	}
380	if (result == ISC_R_NOMORE)
381		result = ISC_R_SUCCESS;
382
383 cleanup_iterator:
384	dns_rdatasetiter_destroy(&iter);
385
386 cleanup_node:
387	dns_db_detachnode(db, &node);
388
389	return (result);
390}
391
392/*%
393 * For each RR of 'name' in 'ver' of 'db', call 'action'
394 * with the RR and 'action_data' as arguments.  If the name
395 * does not exist, do nothing.
396 *
397 * If 'action' returns an error, abort iteration
398 * and return the error.
399 */
400static isc_result_t
401foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
402		rr_func *rr_action, void *rr_action_data)
403{
404	foreach_node_rr_ctx_t ctx;
405	ctx.rr_action = rr_action;
406	ctx.rr_action_data = rr_action_data;
407	return (foreach_rrset(db, ver, name,
408			      foreach_node_rr_action, &ctx));
409}
410
411
412/*%
413 * For each of the RRs specified by 'db', 'ver', 'name', 'type',
414 * (which can be dns_rdatatype_any to match any type), and 'covers', call
415 * 'action' with the RR and 'action_data' as arguments. If the name
416 * does not exist, or if no RRset of the given type exists at the name,
417 * do nothing.
418 *
419 * If 'action' returns an error, abort iteration and return the error.
420 */
421static isc_result_t
422foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
423	   dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
424	   void *rr_action_data)
425{
426
427	isc_result_t result;
428	dns_dbnode_t *node;
429	dns_rdataset_t rdataset;
430
431	if (type == dns_rdatatype_any)
432		return (foreach_node_rr(db, ver, name,
433					rr_action, rr_action_data));
434
435	node = NULL;
436	if (type == dns_rdatatype_nsec3 ||
437	    (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
438		result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
439	else
440		result = dns_db_findnode(db, name, ISC_FALSE, &node);
441	if (result == ISC_R_NOTFOUND)
442		return (ISC_R_SUCCESS);
443	if (result != ISC_R_SUCCESS)
444		return (result);
445
446	dns_rdataset_init(&rdataset);
447	result = dns_db_findrdataset(db, node, ver, type, covers,
448				     (isc_stdtime_t) 0, &rdataset, NULL);
449	if (result == ISC_R_NOTFOUND) {
450		result = ISC_R_SUCCESS;
451		goto cleanup_node;
452	}
453	if (result != ISC_R_SUCCESS)
454		goto cleanup_node;
455
456	for (result = dns_rdataset_first(&rdataset);
457	     result == ISC_R_SUCCESS;
458	     result = dns_rdataset_next(&rdataset))
459	{
460		rr_t rr = { 0, DNS_RDATA_INIT };
461		dns_rdataset_current(&rdataset, &rr.rdata);
462		rr.ttl = rdataset.ttl;
463		result = (*rr_action)(rr_action_data, &rr);
464		if (result != ISC_R_SUCCESS)
465			goto cleanup_rdataset;
466	}
467	if (result != ISC_R_NOMORE)
468		goto cleanup_rdataset;
469	result = ISC_R_SUCCESS;
470
471 cleanup_rdataset:
472	dns_rdataset_disassociate(&rdataset);
473 cleanup_node:
474	dns_db_detachnode(db, &node);
475
476	return (result);
477}
478
479/**************************************************************************/
480/*
481 * Various tests on the database contents (for prerequisites, etc).
482 */
483
484/*%
485 * Function type for predicate functions that compare a database RR 'db_rr'
486 * against an update RR 'update_rr'.
487 */
488typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
489
490/*%
491 * Helper function for rrset_exists().
492 */
493static isc_result_t
494rrset_exists_action(void *data, rr_t *rr) {
495	UNUSED(data);
496	UNUSED(rr);
497	return (ISC_R_EXISTS);
498}
499
500/*%
501 * Utility macro for RR existence checking functions.
502 *
503 * If the variable 'result' has the value ISC_R_EXISTS or
504 * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
505 * respectively, and return success.
506 *
507 * If 'result' has any other value, there was a failure.
508 * Return the failure result code and do not set *exists.
509 *
510 * This would be more readable as "do { if ... } while(0)",
511 * but that form generates tons of warnings on Solaris 2.6.
512 */
513#define RETURN_EXISTENCE_FLAG				\
514	return ((result == ISC_R_EXISTS) ?		\
515		(*exists = ISC_TRUE, ISC_R_SUCCESS) :	\
516		((result == ISC_R_SUCCESS) ?		\
517		 (*exists = ISC_FALSE, ISC_R_SUCCESS) :	\
518		 result))
519
520/*%
521 * Set '*exists' to true iff an rrset of the given type exists,
522 * to false otherwise.
523 */
524static isc_result_t
525rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
526	     dns_rdatatype_t type, dns_rdatatype_t covers,
527	     isc_boolean_t *exists)
528{
529	isc_result_t result;
530	result = foreach_rr(db, ver, name, type, covers,
531			    rrset_exists_action, NULL);
532	RETURN_EXISTENCE_FLAG;
533}
534
535/*%
536 * Set '*visible' to true if the RRset exists and is part of the
537 * visible zone.  Otherwise '*visible' is set to false unless a
538 * error occurs.
539 */
540static isc_result_t
541rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
542	      dns_rdatatype_t type, isc_boolean_t *visible)
543{
544	isc_result_t result;
545	dns_fixedname_t fixed;
546
547	dns_fixedname_init(&fixed);
548	result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD,
549			     (isc_stdtime_t) 0, NULL,
550			     dns_fixedname_name(&fixed), NULL, NULL);
551	switch (result) {
552	case ISC_R_SUCCESS:
553		*visible = ISC_TRUE;
554		break;
555	/*
556	 * Glue, obscured, deleted or replaced records.
557	 */
558	case DNS_R_DELEGATION:
559	case DNS_R_DNAME:
560	case DNS_R_CNAME:
561	case DNS_R_NXDOMAIN:
562	case DNS_R_NXRRSET:
563	case DNS_R_EMPTYNAME:
564	case DNS_R_COVERINGNSEC:
565		*visible = ISC_FALSE;
566		result = ISC_R_SUCCESS;
567		break;
568	default:
569		break;
570	}
571	return (result);
572}
573
574/*%
575 * Context struct and helper function for name_exists().
576 */
577
578static isc_result_t
579name_exists_action(void *data, dns_rdataset_t *rrset) {
580	UNUSED(data);
581	UNUSED(rrset);
582	return (ISC_R_EXISTS);
583}
584
585/*%
586 * Set '*exists' to true iff the given name exists, to false otherwise.
587 */
588static isc_result_t
589name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
590	    isc_boolean_t *exists)
591{
592	isc_result_t result;
593	result = foreach_rrset(db, ver, name,
594			       name_exists_action, NULL);
595	RETURN_EXISTENCE_FLAG;
596}
597
598/**************************************************************************/
599/*
600 * Checking of "RRset exists (value dependent)" prerequisites.
601 *
602 * In the RFC2136 section 3.2.5, this is the pseudocode involving
603 * a variable called "temp", a mapping of <name, type> tuples to rrsets.
604 *
605 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
606 * where each tuple has op==DNS_DIFFOP_EXISTS.
607 */
608
609/*%
610 * A comparison function defining the sorting order for the entries
611 * in the "temp" data structure.  The major sort key is the owner name,
612 * followed by the type and rdata.
613 */
614static int
615temp_order(const void *av, const void *bv) {
616	dns_difftuple_t const * const *ap = av;
617	dns_difftuple_t const * const *bp = bv;
618	dns_difftuple_t const *a = *ap;
619	dns_difftuple_t const *b = *bp;
620	int r;
621	r = dns_name_compare(&a->name, &b->name);
622	if (r != 0)
623		return (r);
624	r = (b->rdata.type - a->rdata.type);
625	if (r != 0)
626		return (r);
627	r = dns_rdata_casecompare(&a->rdata, &b->rdata);
628	return (r);
629}
630
631/**************************************************************************/
632/*
633 * Conditional deletion of RRs.
634 */
635
636/*%
637 * Context structure for delete_if().
638 */
639
640typedef struct {
641	rr_predicate *predicate;
642	dns_db_t *db;
643	dns_dbversion_t *ver;
644	dns_diff_t *diff;
645	dns_name_t *name;
646	dns_rdata_t *update_rr;
647} conditional_delete_ctx_t;
648
649/*%
650 * Predicate functions for delete_if().
651 */
652
653/*%
654 * Return true always.
655 */
656static isc_boolean_t
657true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
658	UNUSED(update_rr);
659	UNUSED(db_rr);
660	return (ISC_TRUE);
661}
662
663/*%
664 * Return true if the record is a RRSIG.
665 */
666static isc_boolean_t
667rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
668	UNUSED(update_rr);
669	return ((db_rr->type == dns_rdatatype_rrsig) ?
670		ISC_TRUE : ISC_FALSE);
671}
672
673/*%
674 * Internal helper function for delete_if().
675 */
676static isc_result_t
677delete_if_action(void *data, rr_t *rr) {
678	conditional_delete_ctx_t *ctx = data;
679	if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
680		isc_result_t result;
681		result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
682				       DNS_DIFFOP_DEL, ctx->name,
683				       rr->ttl, &rr->rdata);
684		return (result);
685	} else {
686		return (ISC_R_SUCCESS);
687	}
688}
689
690/*%
691 * Conditionally delete RRs.  Apply 'predicate' to the RRs
692 * specified by 'db', 'ver', 'name', and 'type' (which can
693 * be dns_rdatatype_any to match any type).  Delete those
694 * RRs for which the predicate returns true, and log the
695 * deletions in 'diff'.
696 */
697static isc_result_t
698delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
699	  dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
700	  dns_rdata_t *update_rr, dns_diff_t *diff)
701{
702	conditional_delete_ctx_t ctx;
703	ctx.predicate = predicate;
704	ctx.db = db;
705	ctx.ver = ver;
706	ctx.diff = diff;
707	ctx.name = name;
708	ctx.update_rr = update_rr;
709	return (foreach_rr(db, ver, name, type, covers,
710			   delete_if_action, &ctx));
711}
712
713/**************************************************************************/
714/*
715 * Incremental updating of NSECs and RRSIGs.
716 */
717
718/*%
719 * We abuse the dns_diff_t type to represent a set of domain names
720 * affected by the update.
721 */
722static isc_result_t
723namelist_append_name(dns_diff_t *list, dns_name_t *name) {
724	isc_result_t result;
725	dns_difftuple_t *tuple = NULL;
726	static dns_rdata_t dummy_rdata = DNS_RDATA_INIT;
727
728	CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0,
729				   &dummy_rdata, &tuple));
730	dns_diff_append(list, &tuple);
731 failure:
732	return (result);
733}
734
735static isc_result_t
736namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
737{
738	isc_result_t result;
739	dns_fixedname_t fixedname;
740	dns_name_t *child;
741	dns_dbiterator_t *dbit = NULL;
742
743	dns_fixedname_init(&fixedname);
744	child = dns_fixedname_name(&fixedname);
745
746	CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
747
748	for (result = dns_dbiterator_seek(dbit, name);
749	     result == ISC_R_SUCCESS;
750	     result = dns_dbiterator_next(dbit))
751	{
752		dns_dbnode_t *node = NULL;
753		CHECK(dns_dbiterator_current(dbit, &node, child));
754		dns_db_detachnode(db, &node);
755		if (! dns_name_issubdomain(child, name))
756			break;
757		CHECK(namelist_append_name(affected, child));
758	}
759	if (result == ISC_R_NOMORE)
760		result = ISC_R_SUCCESS;
761 failure:
762	if (dbit != NULL)
763		dns_dbiterator_destroy(&dbit);
764	return (result);
765}
766
767
768
769/*%
770 * Helper function for non_nsec_rrset_exists().
771 */
772static isc_result_t
773is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
774	UNUSED(data);
775	if (!(rrset->type == dns_rdatatype_nsec ||
776	      rrset->type == dns_rdatatype_nsec3 ||
777	      (rrset->type == dns_rdatatype_rrsig &&
778	       (rrset->covers == dns_rdatatype_nsec ||
779		rrset->covers == dns_rdatatype_nsec3))))
780		return (ISC_R_EXISTS);
781	return (ISC_R_SUCCESS);
782}
783
784/*%
785 * Check whether there is an rrset other than a NSEC or RRSIG NSEC,
786 * i.e., anything that justifies the continued existence of a name
787 * after a secure update.
788 *
789 * If such an rrset exists, set '*exists' to ISC_TRUE.
790 * Otherwise, set it to ISC_FALSE.
791 */
792static isc_result_t
793non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
794		     dns_name_t *name, isc_boolean_t *exists)
795{
796	isc_result_t result;
797	result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
798	RETURN_EXISTENCE_FLAG;
799}
800
801/*%
802 * A comparison function for sorting dns_diff_t:s by name.
803 */
804static int
805name_order(const void *av, const void *bv) {
806	dns_difftuple_t const * const *ap = av;
807	dns_difftuple_t const * const *bp = bv;
808	dns_difftuple_t const *a = *ap;
809	dns_difftuple_t const *b = *bp;
810	return (dns_name_compare(&a->name, &b->name));
811}
812
813static isc_result_t
814uniqify_name_list(dns_diff_t *list) {
815	isc_result_t result;
816	dns_difftuple_t *p, *q;
817
818	CHECK(dns_diff_sort(list, name_order));
819
820	p = ISC_LIST_HEAD(list->tuples);
821	while (p != NULL) {
822		do {
823			q = ISC_LIST_NEXT(p, link);
824			if (q == NULL || ! dns_name_equal(&p->name, &q->name))
825				break;
826			ISC_LIST_UNLINK(list->tuples, q, link);
827			dns_difftuple_free(&q);
828		} while (1);
829		p = ISC_LIST_NEXT(p, link);
830	}
831 failure:
832	return (result);
833}
834
835static isc_result_t
836is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
837	  isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure)
838{
839	isc_result_t result;
840	dns_fixedname_t foundname;
841	dns_fixedname_init(&foundname);
842	result = dns_db_find(db, name, ver, dns_rdatatype_any,
843			     DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
844			     (isc_stdtime_t) 0, NULL,
845			     dns_fixedname_name(&foundname),
846			     NULL, NULL);
847	if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
848		*flag = ISC_TRUE;
849		*cut = ISC_FALSE;
850		if (unsecure != NULL)
851			*unsecure = ISC_FALSE;
852		return (ISC_R_SUCCESS);
853	} else if (result == DNS_R_ZONECUT) {
854		*flag = ISC_TRUE;
855		*cut = ISC_TRUE;
856		if (unsecure != NULL) {
857			/*
858			 * We are at the zonecut.  Check to see if there
859			 * is a DS RRset.
860			 */
861			if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
862					(isc_stdtime_t) 0, NULL,
863					dns_fixedname_name(&foundname),
864					NULL, NULL) == DNS_R_NXRRSET)
865				*unsecure = ISC_TRUE;
866			else
867				*unsecure = ISC_FALSE;
868		}
869		return (ISC_R_SUCCESS);
870	} else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
871		   result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
872		*flag = ISC_FALSE;
873		*cut = ISC_FALSE;
874		if (unsecure != NULL)
875			*unsecure = ISC_FALSE;
876		return (ISC_R_SUCCESS);
877	} else {
878		/*
879		 * Silence compiler.
880		 */
881		*flag = ISC_FALSE;
882		*cut = ISC_FALSE;
883		if (unsecure != NULL)
884			*unsecure = ISC_FALSE;
885		return (result);
886	}
887}
888
889/*%
890 * Find the next/previous name that has a NSEC record.
891 * In other words, skip empty database nodes and names that
892 * have had their NSECs removed because they are obscured by
893 * a zone cut.
894 */
895static isc_result_t
896next_active(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
897	    dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname,
898	    isc_boolean_t forward)
899{
900	isc_result_t result;
901	dns_dbiterator_t *dbit = NULL;
902	isc_boolean_t has_nsec = ISC_FALSE;
903	unsigned int wraps = 0;
904	isc_boolean_t secure = dns_db_issecure(db);
905
906	CHECK(dns_db_createiterator(db, 0, &dbit));
907
908	CHECK(dns_dbiterator_seek(dbit, oldname));
909	do {
910		dns_dbnode_t *node = NULL;
911
912		if (forward)
913			result = dns_dbiterator_next(dbit);
914		else
915			result = dns_dbiterator_prev(dbit);
916		if (result == ISC_R_NOMORE) {
917			/*
918			 * Wrap around.
919			 */
920			if (forward)
921				CHECK(dns_dbiterator_first(dbit));
922			else
923				CHECK(dns_dbiterator_last(dbit));
924			wraps++;
925			if (wraps == 2) {
926				update_log(log, zone, ISC_LOG_ERROR,
927					   "secure zone with no NSECs");
928				result = DNS_R_BADZONE;
929				goto failure;
930			}
931		}
932		CHECK(dns_dbiterator_current(dbit, &node, newname));
933		dns_db_detachnode(db, &node);
934
935		/*
936		 * The iterator may hold the tree lock, and
937		 * rrset_exists() calls dns_db_findnode() which
938		 * may try to reacquire it.  To avoid deadlock
939		 * we must pause the iterator first.
940		 */
941		CHECK(dns_dbiterator_pause(dbit));
942		if (secure) {
943			CHECK(rrset_exists(db, ver, newname,
944					   dns_rdatatype_nsec, 0, &has_nsec));
945		} else {
946			dns_fixedname_t ffound;
947			dns_name_t *found;
948			dns_fixedname_init(&ffound);
949			found = dns_fixedname_name(&ffound);
950			result = dns_db_find(db, newname, ver,
951					     dns_rdatatype_soa,
952					     DNS_DBFIND_NOWILD, 0, NULL, found,
953					     NULL, NULL);
954			if (result == ISC_R_SUCCESS ||
955			    result == DNS_R_EMPTYNAME ||
956			    result == DNS_R_NXRRSET ||
957			    result == DNS_R_CNAME ||
958			    (result == DNS_R_DELEGATION &&
959			     dns_name_equal(newname, found))) {
960				has_nsec = ISC_TRUE;
961				result = ISC_R_SUCCESS;
962			} else if (result != DNS_R_NXDOMAIN)
963				break;
964		}
965	} while (! has_nsec);
966 failure:
967	if (dbit != NULL)
968		dns_dbiterator_destroy(&dbit);
969
970	return (result);
971}
972
973/*%
974 * Add a NSEC record for "name", recording the change in "diff".
975 * The existing NSEC is removed.
976 */
977static isc_result_t
978add_nsec(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
979	 dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl,
980	 dns_diff_t *diff)
981{
982	isc_result_t result;
983	dns_dbnode_t *node = NULL;
984	unsigned char buffer[DNS_NSEC_BUFFERSIZE];
985	dns_rdata_t rdata = DNS_RDATA_INIT;
986	dns_difftuple_t *tuple = NULL;
987	dns_fixedname_t fixedname;
988	dns_name_t *target;
989
990	dns_fixedname_init(&fixedname);
991	target = dns_fixedname_name(&fixedname);
992
993	/*
994	 * Find the successor name, aka NSEC target.
995	 */
996	CHECK(next_active(log, zone, db, ver, name, target, ISC_TRUE));
997
998	/*
999	 * Create the NSEC RDATA.
1000	 */
1001	CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1002	dns_rdata_init(&rdata);
1003	CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
1004	dns_db_detachnode(db, &node);
1005
1006	/*
1007	 * Delete the old NSEC and record the change.
1008	 */
1009	CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0,
1010			NULL, diff));
1011	/*
1012	 * Add the new NSEC and record the change.
1013	 */
1014	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
1015				   nsecttl, &rdata, &tuple));
1016	CHECK(do_one_tuple(&tuple, db, ver, diff));
1017	INSIST(tuple == NULL);
1018
1019 failure:
1020	if (node != NULL)
1021		dns_db_detachnode(db, &node);
1022	return (result);
1023}
1024
1025/*%
1026 * Add a placeholder NSEC record for "name", recording the change in "diff".
1027 */
1028static isc_result_t
1029add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1030		     dns_diff_t *diff)
1031{
1032	isc_result_t result;
1033	dns_difftuple_t *tuple = NULL;
1034	isc_region_t r;
1035	unsigned char data[1] = { 0 }; /* The root domain, no bits. */
1036	dns_rdata_t rdata = DNS_RDATA_INIT;
1037
1038	r.base = data;
1039	r.length = sizeof(data);
1040	dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
1041	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
1042				   &rdata, &tuple));
1043	CHECK(do_one_tuple(&tuple, db, ver, diff));
1044 failure:
1045	return (result);
1046}
1047
1048static isc_result_t
1049find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
1050	       isc_mem_t *mctx, unsigned int maxkeys,
1051	       dst_key_t **keys, unsigned int *nkeys)
1052{
1053	isc_result_t result;
1054	dns_dbnode_t *node = NULL;
1055	const char *directory = dns_zone_getkeydirectory(zone);
1056	CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1057	CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
1058				       directory, mctx, maxkeys, keys, nkeys));
1059 failure:
1060	if (node != NULL)
1061		dns_db_detachnode(db, &node);
1062	return (result);
1063}
1064
1065/*%
1066 * Add RRSIG records for an RRset, recording the change in "diff".
1067 */
1068static isc_result_t
1069add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1070	 dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type,
1071	 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1072	 isc_stdtime_t inception, isc_stdtime_t expire,
1073	 isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
1074{
1075	isc_result_t result;
1076	dns_dbnode_t *node = NULL;
1077	dns_rdataset_t rdataset;
1078	dns_rdata_t sig_rdata = DNS_RDATA_INIT;
1079	isc_buffer_t buffer;
1080	unsigned char data[1024]; /* XXX */
1081	unsigned int i, j;
1082	isc_boolean_t added_sig = ISC_FALSE;
1083	isc_mem_t *mctx = diff->mctx;
1084
1085	dns_rdataset_init(&rdataset);
1086	isc_buffer_init(&buffer, data, sizeof(data));
1087
1088	/* Get the rdataset to sign. */
1089	if (type == dns_rdatatype_nsec3)
1090		CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
1091	else
1092		CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1093	CHECK(dns_db_findrdataset(db, node, ver, type, 0,
1094				  (isc_stdtime_t) 0, &rdataset, NULL));
1095	dns_db_detachnode(db, &node);
1096
1097#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
1098#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
1099#define ALG(x) dst_key_alg(x)
1100
1101	/*
1102	 * If we are honoring KSK flags then we need to check that we
1103	 * have both KSK and non-KSK keys that are not revoked per
1104	 * algorithm.
1105	 */
1106	for (i = 0; i < nkeys; i++) {
1107		isc_boolean_t both = ISC_FALSE;
1108
1109		if (!dst_key_isprivate(keys[i]))
1110			continue;
1111
1112		if (check_ksk && !REVOKE(keys[i])) {
1113			isc_boolean_t have_ksk, have_nonksk;
1114			if (KSK(keys[i])) {
1115				have_ksk = ISC_TRUE;
1116				have_nonksk = ISC_FALSE;
1117			} else {
1118				have_ksk = ISC_FALSE;
1119				have_nonksk = ISC_TRUE;
1120			}
1121			for (j = 0; j < nkeys; j++) {
1122				if (j == i || ALG(keys[i]) != ALG(keys[j]))
1123					continue;
1124				if (REVOKE(keys[j]))
1125					continue;
1126				if (KSK(keys[j]))
1127					have_ksk = ISC_TRUE;
1128				else
1129					have_nonksk = ISC_TRUE;
1130				both = have_ksk && have_nonksk;
1131				if (both)
1132					break;
1133			}
1134		}
1135
1136		if (both) {
1137			if (type == dns_rdatatype_dnskey) {
1138				if (!KSK(keys[i]) && keyset_kskonly)
1139					continue;
1140			} else if (KSK(keys[i]))
1141				continue;
1142		} else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey)
1143			continue;
1144
1145		/* Calculate the signature, creating a RRSIG RDATA. */
1146		CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
1147				      &inception, &expire,
1148				      mctx, &buffer, &sig_rdata));
1149
1150		/* Update the database and journal with the RRSIG. */
1151		/* XXX inefficient - will cause dataset merging */
1152		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, name,
1153				    rdataset.ttl, &sig_rdata));
1154		dns_rdata_reset(&sig_rdata);
1155		isc_buffer_init(&buffer, data, sizeof(data));
1156		added_sig = ISC_TRUE;
1157	}
1158	if (!added_sig) {
1159		update_log(log, zone, ISC_LOG_ERROR,
1160			   "found no active private keys, "
1161			   "unable to generate any signatures");
1162		result = ISC_R_NOTFOUND;
1163	}
1164
1165 failure:
1166	if (dns_rdataset_isassociated(&rdataset))
1167		dns_rdataset_disassociate(&rdataset);
1168	if (node != NULL)
1169		dns_db_detachnode(db, &node);
1170	return (result);
1171}
1172
1173/*
1174 * Delete expired RRsigs and any RRsigs we are about to re-sign.
1175 * See also zone.c:del_sigs().
1176 */
1177static isc_result_t
1178del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1179	    dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys)
1180{
1181	isc_result_t result;
1182	dns_dbnode_t *node = NULL;
1183	dns_rdataset_t rdataset;
1184	dns_rdata_t rdata = DNS_RDATA_INIT;
1185	unsigned int i;
1186	dns_rdata_rrsig_t rrsig;
1187	isc_boolean_t found;
1188
1189	dns_rdataset_init(&rdataset);
1190
1191	result = dns_db_findnode(db, name, ISC_FALSE, &node);
1192	if (result == ISC_R_NOTFOUND)
1193		return (ISC_R_SUCCESS);
1194	if (result != ISC_R_SUCCESS)
1195		goto failure;
1196	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
1197				     dns_rdatatype_dnskey, (isc_stdtime_t) 0,
1198				     &rdataset, NULL);
1199	dns_db_detachnode(db, &node);
1200
1201	if (result == ISC_R_NOTFOUND)
1202		return (ISC_R_SUCCESS);
1203	if (result != ISC_R_SUCCESS)
1204		goto failure;
1205
1206	for (result = dns_rdataset_first(&rdataset);
1207	     result == ISC_R_SUCCESS;
1208	     result = dns_rdataset_next(&rdataset)) {
1209		dns_rdataset_current(&rdataset, &rdata);
1210		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
1211		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1212		found = ISC_FALSE;
1213		for (i = 0; i < nkeys; i++) {
1214			if (rrsig.keyid == dst_key_id(keys[i])) {
1215				found = ISC_TRUE;
1216				if (!dst_key_isprivate(keys[i])) {
1217					/*
1218					 * The re-signing code in zone.c
1219					 * will mark this as offline.
1220					 * Just skip the record for now.
1221					 */
1222					break;
1223				}
1224				result = update_one_rr(db, ver, diff,
1225						       DNS_DIFFOP_DEL, name,
1226						       rdataset.ttl, &rdata);
1227				break;
1228			}
1229		}
1230		/*
1231		 * If there is not a matching DNSKEY then delete the RRSIG.
1232		 */
1233		if (!found)
1234			result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
1235					       name, rdataset.ttl, &rdata);
1236		dns_rdata_reset(&rdata);
1237		if (result != ISC_R_SUCCESS)
1238			break;
1239	}
1240	dns_rdataset_disassociate(&rdataset);
1241	if (result == ISC_R_NOMORE)
1242		result = ISC_R_SUCCESS;
1243failure:
1244	if (node != NULL)
1245		dns_db_detachnode(db, &node);
1246	return (result);
1247}
1248
1249static isc_result_t
1250add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1251		 dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut,
1252		 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1253		 isc_stdtime_t inception, isc_stdtime_t expire,
1254		 isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
1255{
1256	isc_result_t result;
1257	dns_dbnode_t *node;
1258	dns_rdatasetiter_t *iter;
1259
1260	node = NULL;
1261	result = dns_db_findnode(db, name, ISC_FALSE, &node);
1262	if (result == ISC_R_NOTFOUND)
1263		return (ISC_R_SUCCESS);
1264	if (result != ISC_R_SUCCESS)
1265		return (result);
1266
1267	iter = NULL;
1268	result = dns_db_allrdatasets(db, node, ver,
1269				     (isc_stdtime_t) 0, &iter);
1270	if (result != ISC_R_SUCCESS)
1271		goto cleanup_node;
1272
1273	for (result = dns_rdatasetiter_first(iter);
1274	     result == ISC_R_SUCCESS;
1275	     result = dns_rdatasetiter_next(iter))
1276	{
1277		dns_rdataset_t rdataset;
1278		dns_rdatatype_t type;
1279		isc_boolean_t flag;
1280
1281		dns_rdataset_init(&rdataset);
1282		dns_rdatasetiter_current(iter, &rdataset);
1283		type = rdataset.type;
1284		dns_rdataset_disassociate(&rdataset);
1285
1286		/*
1287		 * We don't need to sign unsigned NSEC records at the cut
1288		 * as they are handled elsewhere.
1289		 */
1290		if ((type == dns_rdatatype_rrsig) ||
1291		    (cut && type != dns_rdatatype_ds))
1292			continue;
1293		result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
1294				      type, &flag);
1295		if (result != ISC_R_SUCCESS)
1296			goto cleanup_iterator;
1297		if (flag)
1298			continue;;
1299		result = add_sigs(log, zone, db, ver, name, type, diff,
1300					  keys, nkeys, inception, expire,
1301					  check_ksk, keyset_kskonly);
1302		if (result != ISC_R_SUCCESS)
1303			goto cleanup_iterator;
1304	}
1305	if (result == ISC_R_NOMORE)
1306		result = ISC_R_SUCCESS;
1307
1308 cleanup_iterator:
1309	dns_rdatasetiter_destroy(&iter);
1310
1311 cleanup_node:
1312	dns_db_detachnode(db, &node);
1313
1314	return (result);
1315}
1316
1317/*%
1318 * Update RRSIG, NSEC and NSEC3 records affected by an update.  The original
1319 * update, including the SOA serial update but excluding the RRSIG & NSEC
1320 * changes, is in "diff" and has already been applied to "newver" of "db".
1321 * The database version prior to the update is "oldver".
1322 *
1323 * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
1324 * and added (as a minimal diff) to "diff".
1325 *
1326 * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
1327 */
1328isc_result_t
1329dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1330		      dns_dbversion_t *oldver, dns_dbversion_t *newver,
1331		      dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
1332{
1333	isc_result_t result;
1334	dns_difftuple_t *t;
1335	dns_diff_t diffnames;
1336	dns_diff_t affected;
1337	dns_diff_t sig_diff;
1338	dns_diff_t nsec_diff;
1339	dns_diff_t nsec_mindiff;
1340	isc_boolean_t flag, build_nsec, build_nsec3;
1341	dst_key_t *zone_keys[DNS_MAXZONEKEYS];
1342	unsigned int nkeys = 0;
1343	unsigned int i;
1344	isc_stdtime_t now, inception, expire;
1345	dns_ttl_t nsecttl;
1346	dns_rdata_soa_t soa;
1347	dns_rdata_t rdata = DNS_RDATA_INIT;
1348	dns_rdataset_t rdataset;
1349	dns_dbnode_t *node = NULL;
1350	isc_boolean_t check_ksk, keyset_kskonly;
1351	isc_boolean_t unsecure;
1352	isc_boolean_t cut;
1353	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
1354
1355	dns_diff_init(diff->mctx, &diffnames);
1356	dns_diff_init(diff->mctx, &affected);
1357
1358	dns_diff_init(diff->mctx, &sig_diff);
1359	sig_diff.resign = dns_zone_getsigresigninginterval(zone);
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
1851isc_uint32_t
1852dns_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