Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / update.c
blob75b4aa5bc7bb630186331d5c29cec07e453178a5
1 /* $NetBSD: update.c,v 1.4 2014/12/10 04:37:58 christos Exp $ */
3 /*
4 * Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
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.
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.
19 /* Id */
21 #include <config.h>
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>
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>
61 /**************************************************************************/
63 /*%
64 * Log level for tracing dynamic update protocol requests.
66 #define LOGLEVEL_PROTOCOL ISC_LOG_INFO
68 /*%
69 * Log level for low-level debug tracing.
71 #define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8)
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.
78 #define CHECK(op) \
79 do { result = (op); \
80 if (result != ISC_R_SUCCESS) goto failure; \
81 } while (/*CONSTCOND*/0)
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.
88 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
89 * from complaining about "end-of-loop code not reached".
92 #define FAIL(code) \
93 do { \
94 result = (code); \
95 if (result != ISC_R_SUCCESS) goto failure; \
96 } while (/*CONSTCOND*/0)
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".
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"; \
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)
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"; \
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)); \
138 if (result != ISC_R_SUCCESS) goto failure; \
139 } while (/*CONSTCOND*/0)
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"; \
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)); \
162 if (result != ISC_R_SUCCESS) goto failure; \
163 } while (/*CONSTCOND*/0)
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".
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)
179 /**************************************************************************/
181 typedef struct rr rr_t;
183 struct rr {
184 /* dns_name_t name; */
185 isc_uint32_t ttl;
186 dns_rdata_t rdata;
189 typedef struct update_event update_event_t;
191 /**************************************************************************/
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);
197 static void
198 update_log(dns_update_log_t *callback, dns_zone_t *zone,
199 int level, const char *fmt, ...)
201 va_list ap;
202 char message[4096];
204 if (callback == NULL)
205 return;
207 if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
208 return;
211 va_start(ap, fmt);
212 vsnprintf(message, sizeof(message), fmt, ap);
213 va_end(ap);
215 (callback->func)(callback->arg, zone, level, message);
219 * Update a single RR in version 'ver' of 'db' and log the
220 * update in 'diff'.
222 * Ensures:
223 * \li '*tuple' == NULL. Either the tuple is freed, or its
224 * ownership has been transferred to the diff.
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)
230 dns_diff_t temp_diff;
231 isc_result_t result;
234 * Create a singleton diff.
236 dns_diff_init(diff->mctx, &temp_diff);
237 ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
240 * Apply it to the database.
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);
250 * Merge it into the current pending journal entry.
252 dns_diff_appendminimal(diff, tuple);
255 * Do not clear temp_diff.
257 return (ISC_R_SUCCESS);
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)
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));
274 /**************************************************************************/
276 * Callback-style iteration over rdatasets and rdatas.
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.
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".
291 * XXXRTH We might want to make this public somewhere in libdns.
295 * Function type for foreach_rrset() iterator actions.
297 typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
300 * Function type for foreach_rr() iterator actions.
302 typedef isc_result_t rr_func(void *data, rr_t *rr);
305 * Internal context struct for foreach_node_rr().
307 typedef struct {
308 rr_func * rr_action;
309 void * rr_action_data;
310 } foreach_node_rr_ctx_t;
313 * Internal helper function for foreach_node_rr().
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))
323 rr_t rr = { 0, DNS_RDATA_INIT };
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);
331 if (result != ISC_R_NOMORE)
332 return (result);
333 return (ISC_R_SUCCESS);
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.
341 * If 'action' returns an error, abort iteration and return the error.
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)
347 isc_result_t result;
348 dns_dbnode_t *node;
349 dns_rdatasetiter_t *iter;
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);
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;
364 for (result = dns_rdatasetiter_first(iter);
365 result == ISC_R_SUCCESS;
366 result = dns_rdatasetiter_next(iter))
368 dns_rdataset_t rdataset;
370 dns_rdataset_init(&rdataset);
371 dns_rdatasetiter_current(iter, &rdataset);
373 result = (*action)(action_data, &rdataset);
375 dns_rdataset_disassociate(&rdataset);
376 if (result != ISC_R_SUCCESS)
377 goto cleanup_iterator;
379 if (result == ISC_R_NOMORE)
380 result = ISC_R_SUCCESS;
382 cleanup_iterator:
383 dns_rdatasetiter_destroy(&iter);
385 cleanup_node:
386 dns_db_detachnode(db, &node);
388 return (result);
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.
396 * If 'action' returns an error, abort iteration
397 * and return the error.
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)
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));
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.
418 * If 'action' returns an error, abort iteration and return the error.
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)
426 isc_result_t result;
427 dns_dbnode_t *node;
428 dns_rdataset_t rdataset;
430 if (type == dns_rdatatype_any)
431 return (foreach_node_rr(db, ver, name,
432 rr_action, rr_action_data));
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);
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;
452 if (result != ISC_R_SUCCESS)
453 goto cleanup_node;
455 for (result = dns_rdataset_first(&rdataset);
456 result == ISC_R_SUCCESS;
457 result = dns_rdataset_next(&rdataset))
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;
466 if (result != ISC_R_NOMORE)
467 goto cleanup_rdataset;
468 result = ISC_R_SUCCESS;
470 cleanup_rdataset:
471 dns_rdataset_disassociate(&rdataset);
472 cleanup_node:
473 dns_db_detachnode(db, &node);
475 return (result);
478 /**************************************************************************/
480 * Various tests on the database contents (for prerequisites, etc).
484 * Function type for predicate functions that compare a database RR 'db_rr'
485 * against an update RR 'update_rr'.
487 typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
490 * Helper function for rrset_exists().
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);
500 * Utility macro for RR existence checking functions.
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.
506 * If 'result' has any other value, there was a failure.
507 * Return the failure result code and do not set *exists.
509 * This would be more readable as "do { if ... } while(0)",
510 * but that form generates tons of warnings on Solaris 2.6.
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))
520 * Set '*exists' to true iff an rrset of the given type exists,
521 * to false otherwise.
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)
528 isc_result_t result;
529 result = foreach_rr(db, ver, name, type, covers,
530 rrset_exists_action, NULL);
531 RETURN_EXISTENCE_FLAG;
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.
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)
543 isc_result_t result;
544 dns_fixedname_t fixed;
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;
555 * Glue, obscured, deleted or replaced records.
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;
570 return (result);
574 * Context struct and helper function for name_exists().
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);
585 * Set '*exists' to true iff the given name exists, to false otherwise.
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)
591 isc_result_t result;
592 result = foreach_rrset(db, ver, name,
593 name_exists_action, NULL);
594 RETURN_EXISTENCE_FLAG;
597 /**************************************************************************/
599 * Checking of "RRset exists (value dependent)" prerequisites.
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.
604 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
605 * where each tuple has op==DNS_DIFFOP_EXISTS.
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.
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);
630 /**************************************************************************/
632 * Conditional deletion of RRs.
636 * Context structure for delete_if().
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;
649 * Predicate functions for delete_if().
653 * Return true always.
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);
663 * Return true if the record is a RRSIG.
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);
673 * Internal helper function for delete_if().
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);
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'.
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)
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));
712 /**************************************************************************/
714 * Incremental updating of NSECs and RRSIGs.
718 * We abuse the dns_diff_t type to represent a set of domain names
719 * affected by the update.
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;
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);
734 static isc_result_t
735 namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
737 isc_result_t result;
738 dns_fixedname_t fixedname;
739 dns_name_t *child;
740 dns_dbiterator_t *dbit = NULL;
742 dns_fixedname_init(&fixedname);
743 child = dns_fixedname_name(&fixedname);
745 CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
747 for (result = dns_dbiterator_seek(dbit, name);
748 result == ISC_R_SUCCESS;
749 result = dns_dbiterator_next(dbit))
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));
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);
769 * Helper function for non_nsec_rrset_exists().
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);
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.
788 * If such an rrset exists, set '*exists' to ISC_TRUE.
789 * Otherwise, set it to ISC_FALSE.
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)
795 isc_result_t result;
796 result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
797 RETURN_EXISTENCE_FLAG;
801 * A comparison function for sorting dns_diff_t:s by name.
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));
812 static isc_result_t
813 uniqify_name_list(dns_diff_t *list) {
814 isc_result_t result;
815 dns_difftuple_t *p, *q;
817 CHECK(dns_diff_sort(list, name_order));
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);
830 failure:
831 return (result);
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)
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) {
857 * We are at the zonecut. Check to see if there
858 * is a DS RRset.
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;
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 {
878 * Silence compiler.
880 *flag = ISC_FALSE;
881 *cut = ISC_FALSE;
882 if (unsecure != NULL)
883 *unsecure = ISC_FALSE;
884 return (result);
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.
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)
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);
905 CHECK(dns_db_createiterator(db, 0, &dbit));
907 CHECK(dns_dbiterator_seek(dbit, oldname));
908 do {
909 dns_dbnode_t *node = NULL;
911 if (forward)
912 result = dns_dbiterator_next(dbit);
913 else
914 result = dns_dbiterator_prev(dbit);
915 if (result == ISC_R_NOMORE) {
917 * Wrap around.
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;
931 CHECK(dns_dbiterator_current(dbit, &node, newname));
932 dns_db_detachnode(db, &node);
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.
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;
964 } while (! has_nsec);
965 failure:
966 if (dbit != NULL)
967 dns_dbiterator_destroy(&dbit);
969 return (result);
973 * Add a NSEC record for "name", recording the change in "diff".
974 * The existing NSEC is removed.
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)
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;
989 dns_fixedname_init(&fixedname);
990 target = dns_fixedname_name(&fixedname);
993 * Find the successor name, aka NSEC target.
995 CHECK(next_active(log, zone, db, ver, name, target, ISC_TRUE));
998 * Create the NSEC RDATA.
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);
1006 * Delete the old NSEC and record the change.
1008 CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0,
1009 NULL, diff));
1011 * Add the new NSEC and record the change.
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);
1018 failure:
1019 if (node != NULL)
1020 dns_db_detachnode(db, &node);
1021 return (result);
1025 * Add a placeholder NSEC record for "name", recording the change in "diff".
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)
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;
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);
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)
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);
1065 * Add RRSIG records for an RRset, recording the change in "diff".
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)
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;
1084 dns_rdataset_init(&rdataset);
1085 isc_buffer_init(&buffer, data, sizeof(data));
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);
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)
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.
1105 for (i = 0; i < nkeys; i++) {
1106 isc_boolean_t both = ISC_FALSE;
1108 if (!dst_key_isprivate(keys[i]))
1109 continue;
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;
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;
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;
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));
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;
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;
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);
1173 * Delete expired RRsigs and any RRsigs we are about to re-sign.
1174 * See also zone.c:del_sigs().
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)
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;
1188 dns_rdataset_init(&rdataset);
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);
1200 if (result == ISC_R_NOTFOUND)
1201 return (ISC_R_SUCCESS);
1202 if (result != ISC_R_SUCCESS)
1203 goto failure;
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]))
1219 * The re-signing code in zone.c
1220 * will mark this as offline.
1221 * Just skip the record for now.
1223 break;
1225 result = update_one_rr(db, ver, diff,
1226 DNS_DIFFOP_DEL, name,
1227 rdataset.ttl, &rdata);
1228 break;
1232 * If there is not a matching DNSKEY then delete the RRSIG.
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;
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);
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)
1257 isc_result_t result;
1258 dns_dbnode_t *node;
1259 dns_rdatasetiter_t *iter;
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);
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;
1274 for (result = dns_rdatasetiter_first(iter);
1275 result == ISC_R_SUCCESS;
1276 result = dns_rdatasetiter_next(iter))
1278 dns_rdataset_t rdataset;
1279 dns_rdatatype_t type;
1280 isc_boolean_t flag;
1282 dns_rdataset_init(&rdataset);
1283 dns_rdatasetiter_current(iter, &rdataset);
1284 type = rdataset.type;
1285 dns_rdataset_disassociate(&rdataset);
1288 * We don't need to sign unsigned NSEC records at the cut
1289 * as they are handled elsewhere.
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;
1306 if (result == ISC_R_NOMORE)
1307 result = ISC_R_SUCCESS;
1309 cleanup_iterator:
1310 dns_rdatasetiter_destroy(&iter);
1312 cleanup_node:
1313 dns_db_detachnode(db, &node);
1315 return (result);
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".
1324 * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
1325 * and added (as a minimal diff) to "diff".
1327 * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
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)
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);
1356 dns_diff_init(diff->mctx, &diffnames);
1357 dns_diff_init(diff->mctx, &affected);
1359 dns_diff_init(diff->mctx, &sig_diff);
1360 dns_diff_init(diff->mctx, &nsec_diff);
1361 dns_diff_init(diff->mctx, &nsec_mindiff);
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;
1371 isc_stdtime_get(&now);
1372 inception = now - 3600; /* Allow for some clock skew. */
1373 expire = now + sigvalidityinterval;
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.
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);
1387 * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
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);
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".
1405 CHECK(dns_diff_sort(diff, temp_order));
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. */
1412 CHECK(namelist_append_name(&diffnames, name));
1414 while (t != NULL && dns_name_equal(&t->name, name)) {
1415 dns_rdatatype_t type;
1416 type = t->rdata.type;
1419 * Now "name" and "type" denote a new unique RRset
1420 * affected by the update.
1423 /* Don't sign RRSIGs. */
1424 if (type == dns_rdatatype_rrsig)
1425 goto skip;
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.
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));
1443 * If this RRset is still visible after the update,
1444 * add a new signature for it.
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));
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)
1459 t = ISC_LIST_NEXT(t, link);
1463 update_log(log, zone, ISC_LOG_DEBUG(3), "updated data signatures");
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))
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));
1477 update_log(log, zone, ISC_LOG_DEBUG(3),
1478 "removed any orphaned NSEC records");
1481 * See if we need to build NSEC or NSEC3 chains.
1483 CHECK(dns_private_chains(db, newver, privatetype, &build_nsec,
1484 &build_nsec3));
1485 if (!build_nsec)
1486 goto update_nsec3;
1488 update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
1491 * When a name is created or deleted, its predecessor needs to
1492 * have its NSEC updated.
1494 for (t = ISC_LIST_HEAD(diffnames.tuples);
1495 t != NULL;
1496 t = ISC_LIST_NEXT(t, link))
1498 isc_boolean_t existed, exists;
1499 dns_fixedname_t fixedname;
1500 dns_name_t *prevname;
1502 dns_fixedname_init(&fixedname);
1503 prevname = dns_fixedname_name(&fixedname);
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;
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.
1523 CHECK(next_active(log, zone, db, newver,
1524 &t->name, prevname, ISC_FALSE));
1525 CHECK(namelist_append_name(&affected, prevname));
1529 * Find names potentially affected by delegation changes
1530 * (obscured by adding an NS or DNAME, or unobscured by
1531 * removing one).
1533 for (t = ISC_LIST_HEAD(diffnames.tuples);
1534 t != NULL;
1535 t = ISC_LIST_NEXT(t, link))
1537 isc_boolean_t ns_existed, dname_existed;
1538 isc_boolean_t ns_exists, dname_exists;
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;
1558 * There was a delegation change. Mark all subdomains
1559 * of t->name as potentially needing a NSEC update.
1561 CHECK(namelist_append_subdomain(db, &t->name, &affected));
1564 ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link);
1565 INSIST(ISC_LIST_EMPTY(diffnames.tuples));
1567 CHECK(uniqify_name_list(&affected));
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.
1576 for (t = ISC_LIST_HEAD(affected.tuples);
1577 t != NULL;
1578 t = ISC_LIST_NEXT(t, link))
1580 isc_boolean_t exists;
1581 dns_name_t *name = &t->name;
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) {
1589 * This name is obscured. Delete any
1590 * existing NSEC record.
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 {
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.
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));
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));
1622 * Now we know which names are part of the NSEC chain.
1623 * Make them all point at their correct targets.
1625 for (t = ISC_LIST_HEAD(affected.tuples);
1626 t != NULL;
1627 t = ISC_LIST_NEXT(t, link))
1629 CHECK(rrset_exists(db, newver, &t->name,
1630 dns_rdatatype_nsec, 0, &flag));
1631 if (flag) {
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.
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.
1648 CHECK(add_nsec(log, zone, db, newver, &t->name,
1649 nsecttl, &nsec_diff));
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.
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);
1663 update_log(log, zone, ISC_LOG_DEBUG(3), "signing rebuilt NSEC chain");
1665 /* Update RRSIG NSECs. */
1666 for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
1667 t != NULL;
1668 t = ISC_LIST_NEXT(t, link))
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);
1684 update_nsec3:
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);
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);
1696 INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
1697 INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
1698 INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
1700 if (!build_nsec3) {
1701 update_log(log, zone, ISC_LOG_DEBUG(3),
1702 "no NSEC3 chains to rebuild");
1703 goto failure;
1706 update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC3 chains");
1708 dns_diff_clear(&diffnames);
1709 dns_diff_clear(&affected);
1711 CHECK(dns_diff_sort(diff, temp_order));
1714 * Find names potentially affected by delegation changes
1715 * (obscured by adding an NS or DNAME, or unobscured by
1716 * removing one).
1718 t = ISC_LIST_HEAD(diff->tuples);
1719 while (t != NULL) {
1720 dns_name_t *name = &t->name;
1722 isc_boolean_t ns_existed, dname_existed;
1723 isc_boolean_t ns_exists, dname_exists;
1724 isc_boolean_t exists, existed;
1726 if (t->rdata.type == dns_rdatatype_nsec ||
1727 t->rdata.type == dns_rdatatype_rrsig) {
1728 t = ISC_LIST_NEXT(t, link);
1729 continue;
1732 CHECK(namelist_append_name(&affected, name));
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));
1750 exists = ns_exists || dname_exists;
1751 existed = ns_existed || dname_existed;
1752 if (exists == existed)
1753 goto nextname;
1755 * There was a delegation change. Mark all subdomains
1756 * of t->name as potentially needing a NSEC3 update.
1758 CHECK(namelist_append_subdomain(db, name, &affected));
1760 nextname:
1761 while (t != NULL && dns_name_equal(&t->name, name))
1762 t = ISC_LIST_NEXT(t, link);
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;
1770 unsecure = ISC_FALSE; /* Silence compiler warning. */
1771 CHECK(is_active(db, newver, name, &flag, &cut, &unsecure));
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));
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.
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);
1799 update_log(log, zone, ISC_LOG_DEBUG(3),
1800 "signing rebuilt NSEC3 chain");
1802 /* Update RRSIG NSEC3s. */
1803 for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
1804 t != NULL;
1805 t = ISC_LIST_NEXT(t, link))
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);
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);
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);
1833 INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
1834 INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
1835 INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
1837 failure:
1838 dns_diff_clear(&sig_diff);
1839 dns_diff_clear(&nsec_diff);
1840 dns_diff_clear(&nsec_mindiff);
1842 dns_diff_clear(&affected);
1843 dns_diff_clear(&diffnames);
1845 for (i = 0; i < nkeys; i++)
1846 dst_key_free(&zone_keys[i]);
1848 return (result);
1851 isc_uint32_t
1852 dns_update_soaserial(isc_uint32_t serial, dns_updatemethod_t method) {
1853 isc_stdtime_t now;
1855 if (method == dns_updatemethod_unixtime) {
1856 isc_stdtime_get(&now);
1857 if (now != 0 && isc_serial_gt(now, serial))
1858 return (now);
1861 /* RFC1982 */
1862 serial = (serial + 1) & 0xFFFFFFFF;
1863 if (serial == 0)
1864 serial = 1;
1866 return (serial);