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