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