update.c revision 1.9 1 /* $NetBSD: update.c,v 1.9 2021/02/19 16:42:22 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 https://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)) {
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 rule_ok;
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
921 rule_ok = dns_ssutable_checkrules(
922 ssuinfo->table, ssuinfo->signer, ssuinfo->name, ssuinfo->addr,
923 ssuinfo->tcp, ssuinfo->aclenv, rrset->type, ssuinfo->key);
924 return (rule_ok ? ISC_R_SUCCESS : ISC_R_FAILURE);
925 }
926
927 static bool
928 ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
929 dns_ssutable_t *ssutable, dns_name_t *signer, isc_netaddr_t *addr,
930 dns_aclenv_t *aclenv, bool tcp, dst_key_t *key) {
931 isc_result_t result;
932 ssu_check_t ssuinfo;
933
934 ssuinfo.name = name;
935 ssuinfo.table = ssutable;
936 ssuinfo.signer = signer;
937 ssuinfo.addr = addr;
938 ssuinfo.aclenv = aclenv;
939 ssuinfo.tcp = tcp;
940 ssuinfo.key = key;
941 result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
942 return (result == ISC_R_SUCCESS);
943 }
944
945 /**************************************************************************/
946 /*
947 * Checking of "RRset exists (value dependent)" prerequisites.
948 *
949 * In the RFC2136 section 3.2.5, this is the pseudocode involving
950 * a variable called "temp", a mapping of <name, type> tuples to rrsets.
951 *
952 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
953 * where each tuple has op==DNS_DIFFOP_EXISTS.
954 */
955
956 /*%
957 * Append a tuple asserting the existence of the RR with
958 * 'name' and 'rdata' to 'diff'.
959 */
960 static isc_result_t
961 temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) {
962 isc_result_t result;
963 dns_difftuple_t *tuple = NULL;
964
965 REQUIRE(DNS_DIFF_VALID(diff));
966 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, name, 0,
967 rdata, &tuple));
968 ISC_LIST_APPEND(diff->tuples, tuple, link);
969 failure:
970 return (result);
971 }
972
973 /*%
974 * Compare two rdatasets represented as sorted lists of tuples.
975 * All list elements must have the same owner name and type.
976 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset)
977 * if not.
978 */
979 static isc_result_t
980 temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) {
981 for (;;) {
982 if (a == NULL || b == NULL) {
983 break;
984 }
985 INSIST(a->op == DNS_DIFFOP_EXISTS &&
986 b->op == DNS_DIFFOP_EXISTS);
987 INSIST(a->rdata.type == b->rdata.type);
988 INSIST(dns_name_equal(&a->name, &b->name));
989 if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0) {
990 return (DNS_R_NXRRSET);
991 }
992 a = ISC_LIST_NEXT(a, link);
993 b = ISC_LIST_NEXT(b, link);
994 }
995 if (a != NULL || b != NULL) {
996 return (DNS_R_NXRRSET);
997 }
998 return (ISC_R_SUCCESS);
999 }
1000
1001 /*%
1002 * A comparison function defining the sorting order for the entries
1003 * in the "temp" data structure. The major sort key is the owner name,
1004 * followed by the type and rdata.
1005 */
1006 static int
1007 temp_order(const void *av, const void *bv) {
1008 dns_difftuple_t const *const *ap = av;
1009 dns_difftuple_t const *const *bp = bv;
1010 dns_difftuple_t const *a = *ap;
1011 dns_difftuple_t const *b = *bp;
1012 int r;
1013 r = dns_name_compare(&a->name, &b->name);
1014 if (r != 0) {
1015 return (r);
1016 }
1017 r = (b->rdata.type - a->rdata.type);
1018 if (r != 0) {
1019 return (r);
1020 }
1021 r = dns_rdata_casecompare(&a->rdata, &b->rdata);
1022 return (r);
1023 }
1024
1025 /*%
1026 * Check the "RRset exists (value dependent)" prerequisite information
1027 * in 'temp' against the contents of the database 'db'.
1028 *
1029 * Return ISC_R_SUCCESS if the prerequisites are satisfied,
1030 * rcode(dns_rcode_nxrrset) if not.
1031 *
1032 * 'temp' must be pre-sorted.
1033 */
1034
1035 static isc_result_t
1036 temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
1037 dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep) {
1038 isc_result_t result;
1039 dns_name_t *name;
1040 dns_dbnode_t *node;
1041 dns_difftuple_t *t;
1042 dns_diff_t trash;
1043
1044 dns_diff_init(mctx, &trash);
1045
1046 /*
1047 * For each name and type in the prerequisites,
1048 * construct a sorted rdata list of the corresponding
1049 * database contents, and compare the lists.
1050 */
1051 t = ISC_LIST_HEAD(temp->tuples);
1052 while (t != NULL) {
1053 name = &t->name;
1054 dns_name_copynf(name, tmpname);
1055 *typep = t->rdata.type;
1056
1057 /* A new unique name begins here. */
1058 node = NULL;
1059 result = dns_db_findnode(db, name, false, &node);
1060 if (result == ISC_R_NOTFOUND) {
1061 dns_diff_clear(&trash);
1062 return (DNS_R_NXRRSET);
1063 }
1064 if (result != ISC_R_SUCCESS) {
1065 dns_diff_clear(&trash);
1066 return (result);
1067 }
1068
1069 /* A new unique type begins here. */
1070 while (t != NULL && dns_name_equal(&t->name, name)) {
1071 dns_rdatatype_t type, covers;
1072 dns_rdataset_t rdataset;
1073 dns_diff_t d_rrs; /* Database RRs with
1074 * this name and type */
1075 dns_diff_t u_rrs; /* Update RRs with
1076 * this name and type */
1077
1078 *typep = type = t->rdata.type;
1079 if (type == dns_rdatatype_rrsig ||
1080 type == dns_rdatatype_sig) {
1081 covers = dns_rdata_covers(&t->rdata);
1082 } else if (type == dns_rdatatype_any) {
1083 dns_db_detachnode(db, &node);
1084 dns_diff_clear(&trash);
1085 return (DNS_R_NXRRSET);
1086 } else {
1087 covers = 0;
1088 }
1089
1090 /*
1091 * Collect all database RRs for this name and type
1092 * onto d_rrs and sort them.
1093 */
1094 dns_rdataset_init(&rdataset);
1095 result = dns_db_findrdataset(db, node, ver, type,
1096 covers, (isc_stdtime_t)0,
1097 &rdataset, NULL);
1098 if (result != ISC_R_SUCCESS) {
1099 dns_db_detachnode(db, &node);
1100 dns_diff_clear(&trash);
1101 return (DNS_R_NXRRSET);
1102 }
1103
1104 dns_diff_init(mctx, &d_rrs);
1105 dns_diff_init(mctx, &u_rrs);
1106
1107 for (result = dns_rdataset_first(&rdataset);
1108 result == ISC_R_SUCCESS;
1109 result = dns_rdataset_next(&rdataset))
1110 {
1111 dns_rdata_t rdata = DNS_RDATA_INIT;
1112 dns_rdataset_current(&rdataset, &rdata);
1113 result = temp_append(&d_rrs, name, &rdata);
1114 if (result != ISC_R_SUCCESS) {
1115 goto failure;
1116 }
1117 }
1118 if (result != ISC_R_NOMORE) {
1119 goto failure;
1120 }
1121 result = dns_diff_sort(&d_rrs, temp_order);
1122 if (result != ISC_R_SUCCESS) {
1123 goto failure;
1124 }
1125
1126 /*
1127 * Collect all update RRs for this name and type
1128 * onto u_rrs. No need to sort them here -
1129 * they are already sorted.
1130 */
1131 while (t != NULL && dns_name_equal(&t->name, name) &&
1132 t->rdata.type == type) {
1133 dns_difftuple_t *next = ISC_LIST_NEXT(t, link);
1134 ISC_LIST_UNLINK(temp->tuples, t, link);
1135 ISC_LIST_APPEND(u_rrs.tuples, t, link);
1136 t = next;
1137 }
1138
1139 /* Compare the two sorted lists. */
1140 result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples),
1141 ISC_LIST_HEAD(d_rrs.tuples));
1142 if (result != ISC_R_SUCCESS) {
1143 goto failure;
1144 }
1145
1146 /*
1147 * We are done with the tuples, but we can't free
1148 * them yet because "name" still points into one
1149 * of them. Move them on a temporary list.
1150 */
1151 ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link);
1152 ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link);
1153 dns_rdataset_disassociate(&rdataset);
1154
1155 continue;
1156
1157 failure:
1158 dns_diff_clear(&d_rrs);
1159 dns_diff_clear(&u_rrs);
1160 dns_diff_clear(&trash);
1161 dns_rdataset_disassociate(&rdataset);
1162 dns_db_detachnode(db, &node);
1163 return (result);
1164 }
1165
1166 dns_db_detachnode(db, &node);
1167 }
1168
1169 dns_diff_clear(&trash);
1170 return (ISC_R_SUCCESS);
1171 }
1172
1173 /**************************************************************************/
1174 /*
1175 * Conditional deletion of RRs.
1176 */
1177
1178 /*%
1179 * Context structure for delete_if().
1180 */
1181
1182 typedef struct {
1183 rr_predicate *predicate;
1184 dns_db_t *db;
1185 dns_dbversion_t *ver;
1186 dns_diff_t *diff;
1187 dns_name_t *name;
1188 dns_rdata_t *update_rr;
1189 } conditional_delete_ctx_t;
1190
1191 /*%
1192 * Predicate functions for delete_if().
1193 */
1194
1195 /*%
1196 * Return true iff 'db_rr' is neither a SOA nor an NS RR nor
1197 * an RRSIG nor an NSEC3PARAM nor a NSEC.
1198 */
1199 static bool
1200 type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1201 UNUSED(update_rr);
1202 return ((db_rr->type != dns_rdatatype_soa &&
1203 db_rr->type != dns_rdatatype_ns &&
1204 db_rr->type != dns_rdatatype_nsec3param &&
1205 db_rr->type != dns_rdatatype_rrsig &&
1206 db_rr->type != dns_rdatatype_nsec)
1207 ? true
1208 : false);
1209 }
1210
1211 /*%
1212 * Return true iff 'db_rr' is neither a RRSIG nor a NSEC.
1213 */
1214 static bool
1215 type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1216 UNUSED(update_rr);
1217 return ((db_rr->type != dns_rdatatype_rrsig &&
1218 db_rr->type != dns_rdatatype_nsec)
1219 ? true
1220 : false);
1221 }
1222
1223 /*%
1224 * Return true always.
1225 */
1226 static bool
1227 true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1228 UNUSED(update_rr);
1229 UNUSED(db_rr);
1230 return (true);
1231 }
1232
1233 /*%
1234 * Return true iff the two RRs have identical rdata.
1235 */
1236 static bool
1237 rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1238 /*
1239 * XXXRTH This is not a problem, but we should consider creating
1240 * dns_rdata_equal() (that used dns_name_equal()), since it
1241 * would be faster. Not a priority.
1242 */
1243 return (dns_rdata_casecompare(update_rr, db_rr) == 0 ? true : false);
1244 }
1245
1246 /*%
1247 * Return true iff 'update_rr' should replace 'db_rr' according
1248 * to the special RFC2136 rules for CNAME, SOA, and WKS records.
1249 *
1250 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
1251 * make little sense, so we replace those, too.
1252 *
1253 * Additionally replace RRSIG that have been generated by the same key
1254 * for the same type. This simplifies refreshing a offline KSK by not
1255 * requiring that the old RRSIG be deleted. It also simplifies key
1256 * rollover by only requiring that the new RRSIG be added.
1257 */
1258 static bool
1259 replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1260 dns_rdata_rrsig_t updatesig, dbsig;
1261 isc_result_t result;
1262
1263 if (db_rr->type != update_rr->type) {
1264 return (false);
1265 }
1266 if (db_rr->type == dns_rdatatype_cname) {
1267 return (true);
1268 }
1269 if (db_rr->type == dns_rdatatype_dname) {
1270 return (true);
1271 }
1272 if (db_rr->type == dns_rdatatype_soa) {
1273 return (true);
1274 }
1275 if (db_rr->type == dns_rdatatype_nsec) {
1276 return (true);
1277 }
1278 if (db_rr->type == dns_rdatatype_rrsig) {
1279 /*
1280 * Replace existing RRSIG with the same keyid,
1281 * covered and algorithm.
1282 */
1283 result = dns_rdata_tostruct(db_rr, &dbsig, NULL);
1284 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1285 result = dns_rdata_tostruct(update_rr, &updatesig, NULL);
1286 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1287 if (dbsig.keyid == updatesig.keyid &&
1288 dbsig.covered == updatesig.covered &&
1289 dbsig.algorithm == updatesig.algorithm)
1290 {
1291 return (true);
1292 }
1293 }
1294 if (db_rr->type == dns_rdatatype_wks) {
1295 /*
1296 * Compare the address and protocol fields only. These
1297 * form the first five bytes of the RR data. Do a
1298 * raw binary comparison; unpacking the WKS RRs using
1299 * dns_rdata_tostruct() might be cleaner in some ways.
1300 */
1301 INSIST(db_rr->length >= 5 && update_rr->length >= 5);
1302 return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? true
1303 : false);
1304 }
1305
1306 if (db_rr->type == dns_rdatatype_nsec3param) {
1307 if (db_rr->length != update_rr->length) {
1308 return (false);
1309 }
1310 INSIST(db_rr->length >= 4 && update_rr->length >= 4);
1311 /*
1312 * Replace NSEC3PARAM records that only differ by the
1313 * flags field.
1314 */
1315 if (db_rr->data[0] == update_rr->data[0] &&
1316 memcmp(db_rr->data + 2, update_rr->data + 2,
1317 update_rr->length - 2) == 0)
1318 {
1319 return (true);
1320 }
1321 }
1322 return (false);
1323 }
1324
1325 /*%
1326 * Internal helper function for delete_if().
1327 */
1328 static isc_result_t
1329 delete_if_action(void *data, rr_t *rr) {
1330 conditional_delete_ctx_t *ctx = data;
1331 if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
1332 isc_result_t result;
1333 result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
1334 DNS_DIFFOP_DEL, ctx->name, rr->ttl,
1335 &rr->rdata);
1336 return (result);
1337 } else {
1338 return (ISC_R_SUCCESS);
1339 }
1340 }
1341
1342 /*%
1343 * Conditionally delete RRs. Apply 'predicate' to the RRs
1344 * specified by 'db', 'ver', 'name', and 'type' (which can
1345 * be dns_rdatatype_any to match any type). Delete those
1346 * RRs for which the predicate returns true, and log the
1347 * deletions in 'diff'.
1348 */
1349 static isc_result_t
1350 delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
1351 dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
1352 dns_rdata_t *update_rr, dns_diff_t *diff) {
1353 conditional_delete_ctx_t ctx;
1354 ctx.predicate = predicate;
1355 ctx.db = db;
1356 ctx.ver = ver;
1357 ctx.diff = diff;
1358 ctx.name = name;
1359 ctx.update_rr = update_rr;
1360 return (foreach_rr(db, ver, name, type, covers, delete_if_action,
1361 &ctx));
1362 }
1363
1364 /**************************************************************************/
1365
1366 static isc_result_t
1367 add_rr_prepare_action(void *data, rr_t *rr) {
1368 isc_result_t result = ISC_R_SUCCESS;
1369 add_rr_prepare_ctx_t *ctx = data;
1370 dns_difftuple_t *tuple = NULL;
1371 bool equal, case_equal, ttl_equal;
1372
1373 /*
1374 * Are the new and old cases equal?
1375 */
1376 case_equal = dns_name_caseequal(ctx->name, ctx->oldname);
1377
1378 /*
1379 * Are the ttl's equal?
1380 */
1381 ttl_equal = rr->ttl == ctx->update_rr_ttl;
1382
1383 /*
1384 * If the update RR is a "duplicate" of a existing RR,
1385 * the update should be silently ignored.
1386 */
1387 equal = (dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0);
1388 if (equal && case_equal && ttl_equal) {
1389 ctx->ignore_add = true;
1390 return (ISC_R_SUCCESS);
1391 }
1392
1393 /*
1394 * If this RR is "equal" to the update RR, it should
1395 * be deleted before the update RR is added.
1396 */
1397 if (replaces_p(ctx->update_rr, &rr->rdata)) {
1398 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
1399 ctx->oldname, rr->ttl, &rr->rdata,
1400 &tuple));
1401 dns_diff_append(&ctx->del_diff, &tuple);
1402 return (ISC_R_SUCCESS);
1403 }
1404
1405 /*
1406 * If this RR differs in TTL or case from the update RR,
1407 * its TTL and case must be adjusted.
1408 */
1409 if (!ttl_equal || !case_equal) {
1410 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
1411 ctx->oldname, rr->ttl, &rr->rdata,
1412 &tuple));
1413 dns_diff_append(&ctx->del_diff, &tuple);
1414 if (!equal) {
1415 CHECK(dns_difftuple_create(
1416 ctx->add_diff.mctx, DNS_DIFFOP_ADD, ctx->name,
1417 ctx->update_rr_ttl, &rr->rdata, &tuple));
1418 dns_diff_append(&ctx->add_diff, &tuple);
1419 }
1420 }
1421 failure:
1422 return (result);
1423 }
1424
1425 /**************************************************************************/
1426 /*
1427 * Miscellaneous subroutines.
1428 */
1429
1430 /*%
1431 * Extract a single update RR from 'section' of dynamic update message
1432 * 'msg', with consistency checking.
1433 *
1434 * Stores the owner name, rdata, and TTL of the update RR at 'name',
1435 * 'rdata', and 'ttl', respectively.
1436 */
1437 static void
1438 get_current_rr(dns_message_t *msg, dns_section_t section,
1439 dns_rdataclass_t zoneclass, dns_name_t **name,
1440 dns_rdata_t *rdata, dns_rdatatype_t *covers, dns_ttl_t *ttl,
1441 dns_rdataclass_t *update_class) {
1442 dns_rdataset_t *rdataset;
1443 isc_result_t result;
1444 dns_message_currentname(msg, section, name);
1445 rdataset = ISC_LIST_HEAD((*name)->list);
1446 INSIST(rdataset != NULL);
1447 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
1448 *covers = rdataset->covers;
1449 *ttl = rdataset->ttl;
1450 result = dns_rdataset_first(rdataset);
1451 INSIST(result == ISC_R_SUCCESS);
1452 dns_rdataset_current(rdataset, rdata);
1453 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
1454 *update_class = rdata->rdclass;
1455 rdata->rdclass = zoneclass;
1456 }
1457
1458 /*%
1459 * Increment the SOA serial number of database 'db', version 'ver'.
1460 * Replace the SOA record in the database, and log the
1461 * change in 'diff'.
1462 */
1463
1464 /*
1465 * XXXRTH Failures in this routine will be worth logging, when
1466 * we have a logging system. Failure to find the zonename
1467 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR().
1468 */
1469
1470 static isc_result_t
1471 update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
1472 isc_mem_t *mctx, dns_updatemethod_t method) {
1473 dns_difftuple_t *deltuple = NULL;
1474 dns_difftuple_t *addtuple = NULL;
1475 uint32_t serial;
1476 isc_result_t result;
1477
1478 CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
1479 CHECK(dns_difftuple_copy(deltuple, &addtuple));
1480 addtuple->op = DNS_DIFFOP_ADD;
1481
1482 serial = dns_soa_getserial(&addtuple->rdata);
1483 serial = dns_update_soaserial(serial, method, NULL);
1484 dns_soa_setserial(serial, &addtuple->rdata);
1485 CHECK(do_one_tuple(&deltuple, db, ver, diff));
1486 CHECK(do_one_tuple(&addtuple, db, ver, diff));
1487 result = ISC_R_SUCCESS;
1488
1489 failure:
1490 if (addtuple != NULL) {
1491 dns_difftuple_free(&addtuple);
1492 }
1493 if (deltuple != NULL) {
1494 dns_difftuple_free(&deltuple);
1495 }
1496 return (result);
1497 }
1498
1499 /*%
1500 * Check that the new SOA record at 'update_rdata' does not
1501 * illegally cause the SOA serial number to decrease or stay
1502 * unchanged relative to the existing SOA in 'db'.
1503 *
1504 * Sets '*ok' to true if the update is legal, false if not.
1505 *
1506 * William King points out that RFC2136 is inconsistent about
1507 * the case where the serial number stays unchanged:
1508 *
1509 * section 3.4.2.2 requires a server to ignore a SOA update request
1510 * if the serial number on the update SOA is less_than_or_equal to
1511 * the zone SOA serial.
1512 *
1513 * section 3.6 requires a server to ignore a SOA update request if
1514 * the serial is less_than the zone SOA serial.
1515 *
1516 * Paul says 3.4.2.2 is correct.
1517 *
1518 */
1519 static isc_result_t
1520 check_soa_increment(dns_db_t *db, dns_dbversion_t *ver,
1521 dns_rdata_t *update_rdata, bool *ok) {
1522 uint32_t db_serial;
1523 uint32_t update_serial;
1524 isc_result_t result;
1525
1526 update_serial = dns_soa_getserial(update_rdata);
1527
1528 result = dns_db_getsoaserial(db, ver, &db_serial);
1529 if (result != ISC_R_SUCCESS) {
1530 return (result);
1531 }
1532
1533 if (DNS_SERIAL_GE(db_serial, update_serial)) {
1534 *ok = false;
1535 } else {
1536 *ok = true;
1537 }
1538
1539 return (ISC_R_SUCCESS);
1540 }
1541
1542 /**************************************************************************/
1543 /*%
1544 * The actual update code in all its glory. We try to follow
1545 * the RFC2136 pseudocode as closely as possible.
1546 */
1547
1548 static isc_result_t
1549 send_update_event(ns_client_t *client, dns_zone_t *zone) {
1550 isc_result_t result = ISC_R_SUCCESS;
1551 update_event_t *event = NULL;
1552 isc_task_t *zonetask = NULL;
1553
1554 event = (update_event_t *)isc_event_allocate(
1555 client->mctx, client, DNS_EVENT_UPDATE, update_action, NULL,
1556 sizeof(*event));
1557 event->zone = zone;
1558 event->result = ISC_R_SUCCESS;
1559
1560 INSIST(client->nupdates == 0);
1561 client->nupdates++;
1562 event->ev_arg = client;
1563
1564 isc_nmhandle_attach(client->handle, &client->updatehandle);
1565 dns_zone_gettask(zone, &zonetask);
1566 isc_task_send(zonetask, ISC_EVENT_PTR(&event));
1567
1568 return (result);
1569 }
1570
1571 static void
1572 respond(ns_client_t *client, isc_result_t result) {
1573 isc_result_t msg_result;
1574
1575 msg_result = dns_message_reply(client->message, true);
1576 if (msg_result != ISC_R_SUCCESS) {
1577 goto msg_failure;
1578 }
1579 client->message->rcode = dns_result_torcode(result);
1580
1581 ns_client_send(client);
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_detach(&client->reqhandle);
1591 }
1592
1593 void
1594 ns_update_start(ns_client_t *client, isc_nmhandle_t *handle,
1595 isc_result_t sigresult) {
1596 dns_message_t *request = client->message;
1597 isc_result_t result;
1598 dns_name_t *zonename;
1599 dns_rdataset_t *zone_rdataset;
1600 dns_zone_t *zone = NULL, *raw = NULL;
1601
1602 /*
1603 * Attach to the request handle
1604 */
1605 isc_nmhandle_attach(handle, &client->reqhandle);
1606
1607 /*
1608 * Interpret the zone section.
1609 */
1610 result = dns_message_firstname(request, DNS_SECTION_ZONE);
1611 if (result != ISC_R_SUCCESS) {
1612 FAILC(DNS_R_FORMERR, "update zone section empty");
1613 }
1614
1615 /*
1616 * The zone section must contain exactly one "question", and
1617 * it must be of type SOA.
1618 */
1619 zonename = NULL;
1620 dns_message_currentname(request, DNS_SECTION_ZONE, &zonename);
1621 zone_rdataset = ISC_LIST_HEAD(zonename->list);
1622 if (zone_rdataset->type != dns_rdatatype_soa) {
1623 FAILC(DNS_R_FORMERR, "update zone section contains non-SOA");
1624 }
1625 if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) {
1626 FAILC(DNS_R_FORMERR, "update zone section contains multiple "
1627 "RRs");
1628 }
1629
1630 /* The zone section must have exactly one name. */
1631 result = dns_message_nextname(request, DNS_SECTION_ZONE);
1632 if (result != ISC_R_NOMORE) {
1633 FAILC(DNS_R_FORMERR, "update zone section contains multiple "
1634 "RRs");
1635 }
1636
1637 result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone);
1638 if (result != ISC_R_SUCCESS) {
1639 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
1640 }
1641
1642 /*
1643 * If there is a raw (unsigned) zone associated with this
1644 * zone then it processes the UPDATE request.
1645 */
1646 dns_zone_getraw(zone, &raw);
1647 if (raw != NULL) {
1648 dns_zone_detach(&zone);
1649 dns_zone_attach(raw, &zone);
1650 dns_zone_detach(&raw);
1651 }
1652
1653 switch (dns_zone_gettype(zone)) {
1654 case dns_zone_master:
1655 case dns_zone_dlz:
1656 /*
1657 * We can now fail due to a bad signature as we now know
1658 * that we are the master.
1659 */
1660 if (sigresult != ISC_R_SUCCESS) {
1661 FAIL(sigresult);
1662 }
1663 dns_message_clonebuffer(client->message);
1664 CHECK(send_update_event(client, zone));
1665 break;
1666 case dns_zone_slave:
1667 case dns_zone_mirror:
1668 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
1669 "update forwarding", zonename, true,
1670 false));
1671 CHECK(send_forward_event(client, zone));
1672 break;
1673 default:
1674 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
1675 }
1676
1677 isc_nmhandle_detach(&client->reqhandle);
1678 return;
1679
1680 failure:
1681 if (result == DNS_R_REFUSED) {
1682 INSIST(dns_zone_gettype(zone) == dns_zone_slave ||
1683 dns_zone_gettype(zone) == dns_zone_mirror);
1684 inc_stats(client, zone, ns_statscounter_updaterej);
1685 }
1686 /*
1687 * We failed without having sent an update event to the zone.
1688 * We are still in the client task context, so we can
1689 * simply give an error response without switching tasks.
1690 */
1691 respond(client, result);
1692 if (zone != NULL) {
1693 dns_zone_detach(&zone);
1694 }
1695 isc_nmhandle_detach(&client->reqhandle);
1696 }
1697
1698 /*%
1699 * DS records are not allowed to exist without corresponding NS records,
1700 * RFC 3658, 2.2 Protocol Change,
1701 * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
1702 */
1703
1704 static isc_result_t
1705 remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) {
1706 isc_result_t result;
1707 bool ns_exists;
1708 dns_difftuple_t *tuple;
1709 dns_diff_t temp_diff;
1710
1711 dns_diff_init(diff->mctx, &temp_diff);
1712
1713 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL;
1714 tuple = ISC_LIST_NEXT(tuple, link))
1715 {
1716 if (!((tuple->op == DNS_DIFFOP_DEL &&
1717 tuple->rdata.type == dns_rdatatype_ns) ||
1718 (tuple->op == DNS_DIFFOP_ADD &&
1719 tuple->rdata.type == dns_rdatatype_ds)))
1720 {
1721 continue;
1722 }
1723 CHECK(rrset_exists(db, newver, &tuple->name, dns_rdatatype_ns,
1724 0, &ns_exists));
1725 if (ns_exists &&
1726 !dns_name_equal(&tuple->name, dns_db_origin(db))) {
1727 continue;
1728 }
1729 CHECK(delete_if(true_p, db, newver, &tuple->name,
1730 dns_rdatatype_ds, 0, NULL, &temp_diff));
1731 }
1732 result = ISC_R_SUCCESS;
1733
1734 failure:
1735 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL;
1736 tuple = ISC_LIST_HEAD(temp_diff.tuples))
1737 {
1738 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
1739 dns_diff_appendminimal(diff, &tuple);
1740 }
1741 return (result);
1742 }
1743
1744 /*
1745 * This implements the post load integrity checks for mx records.
1746 */
1747 static isc_result_t
1748 check_mx(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1749 dns_dbversion_t *newver, dns_diff_t *diff) {
1750 char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
1751 char ownerbuf[DNS_NAME_FORMATSIZE];
1752 char namebuf[DNS_NAME_FORMATSIZE];
1753 char altbuf[DNS_NAME_FORMATSIZE];
1754 dns_difftuple_t *t;
1755 dns_fixedname_t fixed;
1756 dns_name_t *foundname;
1757 dns_rdata_mx_t mx;
1758 dns_rdata_t rdata;
1759 bool ok = true;
1760 bool isaddress;
1761 isc_result_t result;
1762 struct in6_addr addr6;
1763 struct in_addr addr;
1764 dns_zoneopt_t options;
1765
1766 foundname = dns_fixedname_initname(&fixed);
1767 dns_rdata_init(&rdata);
1768 options = dns_zone_getoptions(zone);
1769
1770 for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
1771 t = ISC_LIST_NEXT(t, link)) {
1772 if (t->op != DNS_DIFFOP_ADD ||
1773 t->rdata.type != dns_rdatatype_mx) {
1774 continue;
1775 }
1776
1777 result = dns_rdata_tostruct(&t->rdata, &mx, NULL);
1778 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1779 /*
1780 * Check if we will error out if we attempt to reload the
1781 * zone.
1782 */
1783 dns_name_format(&mx.mx, namebuf, sizeof(namebuf));
1784 dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf));
1785 isaddress = false;
1786 if ((options & DNS_ZONEOPT_CHECKMX) != 0 &&
1787 strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp))
1788 {
1789 if (tmp[strlen(tmp) - 1] == '.') {
1790 tmp[strlen(tmp) - 1] = '\0';
1791 }
1792 if (inet_pton(AF_INET, tmp, &addr) == 1 ||
1793 inet_pton(AF_INET6, tmp, &addr6) == 1)
1794 {
1795 isaddress = true;
1796 }
1797 }
1798
1799 if (isaddress && (options & DNS_ZONEOPT_CHECKMXFAIL) != 0) {
1800 update_log(client, zone, ISC_LOG_ERROR,
1801 "%s/MX: '%s': %s", ownerbuf, namebuf,
1802 dns_result_totext(DNS_R_MXISADDRESS));
1803 ok = false;
1804 } else if (isaddress) {
1805 update_log(client, zone, ISC_LOG_WARNING,
1806 "%s/MX: warning: '%s': %s", ownerbuf,
1807 namebuf,
1808 dns_result_totext(DNS_R_MXISADDRESS));
1809 }
1810
1811 /*
1812 * Check zone integrity checks.
1813 */
1814 if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0) {
1815 continue;
1816 }
1817 result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a, 0, 0,
1818 NULL, foundname, NULL, NULL);
1819 if (result == ISC_R_SUCCESS) {
1820 continue;
1821 }
1822
1823 if (result == DNS_R_NXRRSET) {
1824 result = dns_db_find(db, &mx.mx, newver,
1825 dns_rdatatype_aaaa, 0, 0, NULL,
1826 foundname, NULL, NULL);
1827 if (result == ISC_R_SUCCESS) {
1828 continue;
1829 }
1830 }
1831
1832 if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
1833 update_log(client, zone, ISC_LOG_ERROR,
1834 "%s/MX '%s' has no address records "
1835 "(A or AAAA)",
1836 ownerbuf, namebuf);
1837 ok = false;
1838 } else if (result == DNS_R_CNAME) {
1839 update_log(client, zone, ISC_LOG_ERROR,
1840 "%s/MX '%s' is a CNAME (illegal)", ownerbuf,
1841 namebuf);
1842 ok = false;
1843 } else if (result == DNS_R_DNAME) {
1844 dns_name_format(foundname, altbuf, sizeof altbuf);
1845 update_log(client, zone, ISC_LOG_ERROR,
1846 "%s/MX '%s' is below a DNAME '%s' (illegal)",
1847 ownerbuf, namebuf, altbuf);
1848 ok = false;
1849 }
1850 }
1851 return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
1852 }
1853
1854 static isc_result_t
1855 rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1856 const dns_rdata_t *rdata, bool *flag) {
1857 dns_rdataset_t rdataset;
1858 dns_dbnode_t *node = NULL;
1859 isc_result_t result;
1860
1861 dns_rdataset_init(&rdataset);
1862 if (rdata->type == dns_rdatatype_nsec3) {
1863 CHECK(dns_db_findnsec3node(db, name, false, &node));
1864 } else {
1865 CHECK(dns_db_findnode(db, name, false, &node));
1866 }
1867 result = dns_db_findrdataset(db, node, ver, rdata->type, 0,
1868 (isc_stdtime_t)0, &rdataset, NULL);
1869 if (result == ISC_R_NOTFOUND) {
1870 *flag = false;
1871 result = ISC_R_SUCCESS;
1872 goto failure;
1873 }
1874
1875 for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
1876 result = dns_rdataset_next(&rdataset))
1877 {
1878 dns_rdata_t myrdata = DNS_RDATA_INIT;
1879 dns_rdataset_current(&rdataset, &myrdata);
1880 if (!dns_rdata_casecompare(&myrdata, rdata)) {
1881 break;
1882 }
1883 }
1884 dns_rdataset_disassociate(&rdataset);
1885 if (result == ISC_R_SUCCESS) {
1886 *flag = true;
1887 } else if (result == ISC_R_NOMORE) {
1888 *flag = false;
1889 result = ISC_R_SUCCESS;
1890 }
1891
1892 failure:
1893 if (node != NULL) {
1894 dns_db_detachnode(db, &node);
1895 }
1896 return (result);
1897 }
1898
1899 static isc_result_t
1900 get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype,
1901 unsigned int *iterationsp) {
1902 dns_dbnode_t *node = NULL;
1903 dns_rdata_nsec3param_t nsec3param;
1904 dns_rdataset_t rdataset;
1905 isc_result_t result;
1906 unsigned int iterations = 0;
1907
1908 dns_rdataset_init(&rdataset);
1909
1910 result = dns_db_getoriginnode(db, &node);
1911 if (result != ISC_R_SUCCESS) {
1912 return (result);
1913 }
1914 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0,
1915 (isc_stdtime_t)0, &rdataset, NULL);
1916 if (result == ISC_R_NOTFOUND) {
1917 goto try_private;
1918 }
1919 if (result != ISC_R_SUCCESS) {
1920 goto failure;
1921 }
1922
1923 for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
1924 result = dns_rdataset_next(&rdataset))
1925 {
1926 dns_rdata_t rdata = DNS_RDATA_INIT;
1927 dns_rdataset_current(&rdataset, &rdata);
1928 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
1929 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) {
1930 continue;
1931 }
1932 if (nsec3param.iterations > iterations) {
1933 iterations = nsec3param.iterations;
1934 }
1935 }
1936 if (result != ISC_R_NOMORE) {
1937 goto failure;
1938 }
1939
1940 dns_rdataset_disassociate(&rdataset);
1941
1942 try_private:
1943 if (privatetype == 0) {
1944 goto success;
1945 }
1946
1947 result = dns_db_findrdataset(db, node, ver, privatetype, 0,
1948 (isc_stdtime_t)0, &rdataset, NULL);
1949 if (result == ISC_R_NOTFOUND) {
1950 goto success;
1951 }
1952 if (result != ISC_R_SUCCESS) {
1953 goto failure;
1954 }
1955
1956 for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
1957 result = dns_rdataset_next(&rdataset))
1958 {
1959 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
1960 dns_rdata_t private = DNS_RDATA_INIT;
1961 dns_rdata_t rdata = DNS_RDATA_INIT;
1962
1963 dns_rdataset_current(&rdataset, &rdata);
1964 if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
1965 sizeof(buf))) {
1966 continue;
1967 }
1968 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
1969 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) {
1970 continue;
1971 }
1972 if (nsec3param.iterations > iterations) {
1973 iterations = nsec3param.iterations;
1974 }
1975 }
1976 if (result != ISC_R_NOMORE) {
1977 goto failure;
1978 }
1979
1980 success:
1981 *iterationsp = iterations;
1982 result = ISC_R_SUCCESS;
1983
1984 failure:
1985 if (node != NULL) {
1986 dns_db_detachnode(db, &node);
1987 }
1988 if (dns_rdataset_isassociated(&rdataset)) {
1989 dns_rdataset_disassociate(&rdataset);
1990 }
1991 return (result);
1992 }
1993
1994 /*
1995 * Prevent the zone entering a inconsistent state where
1996 * NSEC only DNSKEYs are present with NSEC3 chains.
1997 */
1998 static isc_result_t
1999 check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
2000 dns_dbversion_t *ver, dns_diff_t *diff) {
2001 dns_difftuple_t *tuple;
2002 bool nseconly = false, nsec3 = false;
2003 isc_result_t result;
2004 unsigned int iterations = 0, max;
2005 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
2006
2007 /* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */
2008 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL;
2009 tuple = ISC_LIST_NEXT(tuple, link))
2010 {
2011 if (tuple->op != DNS_DIFFOP_ADD) {
2012 continue;
2013 }
2014
2015 if (tuple->rdata.type == dns_rdatatype_dnskey) {
2016 uint8_t alg;
2017 alg = tuple->rdata.data[3];
2018 if (alg == DST_ALG_RSASHA1) {
2019 nseconly = true;
2020 break;
2021 }
2022 } else if (tuple->rdata.type == dns_rdatatype_nsec3param) {
2023 nsec3 = true;
2024 break;
2025 }
2026 }
2027
2028 /* Check existing DB for NSEC-only DNSKEY */
2029 if (!nseconly) {
2030 result = dns_nsec_nseconly(db, ver, &nseconly);
2031
2032 /*
2033 * An NSEC3PARAM update can proceed without a DNSKEY (it
2034 * will trigger a delayed change), so we can ignore
2035 * ISC_R_NOTFOUND here.
2036 */
2037 if (result == ISC_R_NOTFOUND) {
2038 result = ISC_R_SUCCESS;
2039 }
2040
2041 CHECK(result);
2042 }
2043
2044 /* Check existing DB for NSEC3 */
2045 if (!nsec3) {
2046 CHECK(dns_nsec3_activex(db, ver, false, privatetype, &nsec3));
2047 }
2048
2049 /* Refuse to allow NSEC3 with NSEC-only keys */
2050 if (nseconly && nsec3) {
2051 update_log(client, zone, ISC_LOG_ERROR,
2052 "NSEC only DNSKEYs and NSEC3 chains not allowed");
2053 result = DNS_R_REFUSED;
2054 goto failure;
2055 }
2056
2057 /* Verify NSEC3 params */
2058 CHECK(get_iterations(db, ver, privatetype, &iterations));
2059 CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
2060 if (max != 0 && iterations > max) {
2061 update_log(client, zone, ISC_LOG_ERROR,
2062 "too many NSEC3 iterations (%u) for "
2063 "weakest DNSKEY (%u)",
2064 iterations, max);
2065 result = DNS_R_REFUSED;
2066 goto failure;
2067 }
2068
2069 failure:
2070 return (result);
2071 }
2072
2073 /*
2074 * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
2075 */
2076 static isc_result_t
2077 add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
2078 dns_dbversion_t *ver, dns_diff_t *diff) {
2079 isc_result_t result = ISC_R_SUCCESS;
2080 dns_difftuple_t *tuple, *newtuple = NULL, *next;
2081 dns_rdata_t rdata = DNS_RDATA_INIT;
2082 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1];
2083 dns_diff_t temp_diff;
2084 dns_diffop_t op;
2085 bool flag;
2086 dns_name_t *name = dns_zone_getorigin(zone);
2087 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
2088 uint32_t ttl = 0;
2089 bool ttl_good = false;
2090
2091 update_log(client, zone, ISC_LOG_DEBUG(3),
2092 "checking for NSEC3PARAM changes");
2093
2094 dns_diff_init(diff->mctx, &temp_diff);
2095
2096 /*
2097 * Extract NSEC3PARAM tuples from list.
2098 */
2099 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; tuple = next) {
2100 next = ISC_LIST_NEXT(tuple, link);
2101
2102 if (tuple->rdata.type != dns_rdatatype_nsec3param ||
2103 !dns_name_equal(name, &tuple->name))
2104 {
2105 continue;
2106 }
2107 ISC_LIST_UNLINK(diff->tuples, tuple, link);
2108 ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
2109 }
2110
2111 /*
2112 * Extract TTL changes pairs, we don't need to convert these to
2113 * delayed changes.
2114 */
2115 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL;
2116 tuple = next) {
2117 if (tuple->op == DNS_DIFFOP_ADD) {
2118 if (!ttl_good) {
2119 /*
2120 * Any adds here will contain the final
2121 * NSEC3PARAM RRset TTL.
2122 */
2123 ttl = tuple->ttl;
2124 ttl_good = true;
2125 }
2126 /*
2127 * Walk the temp_diff list looking for the
2128 * corresponding delete.
2129 */
2130 next = ISC_LIST_HEAD(temp_diff.tuples);
2131 while (next != NULL) {
2132 unsigned char *next_data = next->rdata.data;
2133 unsigned char *tuple_data = tuple->rdata.data;
2134 if (next->op == DNS_DIFFOP_DEL &&
2135 next->rdata.length == tuple->rdata.length &&
2136 !memcmp(next_data, tuple_data,
2137 next->rdata.length))
2138 {
2139 ISC_LIST_UNLINK(temp_diff.tuples, next,
2140 link);
2141 ISC_LIST_APPEND(diff->tuples, next,
2142 link);
2143 break;
2144 }
2145 next = ISC_LIST_NEXT(next, link);
2146 }
2147 /*
2148 * If we have not found a pair move onto the next
2149 * tuple.
2150 */
2151 if (next == NULL) {
2152 next = ISC_LIST_NEXT(tuple, link);
2153 continue;
2154 }
2155 /*
2156 * Find the next tuple to be processed before
2157 * unlinking then complete moving the pair to 'diff'.
2158 */
2159 next = ISC_LIST_NEXT(tuple, link);
2160 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2161 ISC_LIST_APPEND(diff->tuples, tuple, link);
2162 } else {
2163 next = ISC_LIST_NEXT(tuple, link);
2164 }
2165 }
2166
2167 /*
2168 * Preserve any ongoing changes from a BIND 9.6.x upgrade.
2169 *
2170 * Any NSEC3PARAM records with flags other than OPTOUT named
2171 * in managing and should not be touched so revert such changes
2172 * taking into account any TTL change of the NSEC3PARAM RRset.
2173 */
2174 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL;
2175 tuple = next) {
2176 next = ISC_LIST_NEXT(tuple, link);
2177 if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
2178 /*
2179 * If we haven't had any adds then the tuple->ttl must
2180 * be the original ttl and should be used for any
2181 * future changes.
2182 */
2183 if (!ttl_good) {
2184 ttl = tuple->ttl;
2185 ttl_good = true;
2186 }
2187 op = (tuple->op == DNS_DIFFOP_DEL) ? DNS_DIFFOP_ADD
2188 : DNS_DIFFOP_DEL;
2189 CHECK(dns_difftuple_create(diff->mctx, op, name, ttl,
2190 &tuple->rdata, &newtuple));
2191 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2192 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2193 dns_diff_appendminimal(diff, &tuple);
2194 }
2195 }
2196
2197 /*
2198 * We now have just the actual changes to the NSEC3PARAM RRset.
2199 * Convert the adds to delayed adds and the deletions into delayed
2200 * deletions.
2201 */
2202 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL;
2203 tuple = next) {
2204 /*
2205 * If we haven't had any adds then the tuple->ttl must be the
2206 * original ttl and should be used for any future changes.
2207 */
2208 if (!ttl_good) {
2209 ttl = tuple->ttl;
2210 ttl_good = true;
2211 }
2212 if (tuple->op == DNS_DIFFOP_ADD) {
2213 bool nseconly = false;
2214
2215 /*
2216 * Look for any deletes which match this ADD ignoring
2217 * flags. We don't need to explicitly remove them as
2218 * they will be removed a side effect of processing
2219 * the add.
2220 */
2221 next = ISC_LIST_HEAD(temp_diff.tuples);
2222 while (next != NULL) {
2223 unsigned char *next_data = next->rdata.data;
2224 unsigned char *tuple_data = tuple->rdata.data;
2225 if (next->op != DNS_DIFFOP_DEL ||
2226 next->rdata.length != tuple->rdata.length ||
2227 next_data[0] != tuple_data[0] ||
2228 next_data[2] != tuple_data[2] ||
2229 next_data[3] != tuple_data[3] ||
2230 memcmp(next_data + 4, tuple_data + 4,
2231 tuple->rdata.length - 4))
2232 {
2233 next = ISC_LIST_NEXT(next, link);
2234 continue;
2235 }
2236 ISC_LIST_UNLINK(temp_diff.tuples, next, link);
2237 ISC_LIST_APPEND(diff->tuples, next, link);
2238 next = ISC_LIST_HEAD(temp_diff.tuples);
2239 }
2240
2241 /*
2242 * Create a private-type record to signal that
2243 * we want a delayed NSEC3 chain add/delete
2244 */
2245 dns_nsec3param_toprivate(&tuple->rdata, &rdata,
2246 privatetype, buf, sizeof(buf));
2247 buf[2] |= DNS_NSEC3FLAG_CREATE;
2248
2249 /*
2250 * If the zone is not currently capable of
2251 * supporting an NSEC3 chain, then we set the
2252 * INITIAL flag to indicate that these parameters
2253 * are to be used later.
2254 */
2255 result = dns_nsec_nseconly(db, ver, &nseconly);
2256 if (result == ISC_R_NOTFOUND || nseconly) {
2257 buf[2] |= DNS_NSEC3FLAG_INITIAL;
2258 }
2259
2260 /*
2261 * See if this CREATE request already exists.
2262 */
2263 CHECK(rr_exists(db, ver, name, &rdata, &flag));
2264
2265 if (!flag) {
2266 CHECK(dns_difftuple_create(
2267 diff->mctx, DNS_DIFFOP_ADD, name, 0,
2268 &rdata, &newtuple));
2269 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2270 }
2271
2272 /*
2273 * Remove any existing CREATE request to add an
2274 * otherwise identical chain with a reversed
2275 * OPTOUT state.
2276 */
2277 buf[2] ^= DNS_NSEC3FLAG_OPTOUT;
2278 CHECK(rr_exists(db, ver, name, &rdata, &flag));
2279
2280 if (flag) {
2281 CHECK(dns_difftuple_create(
2282 diff->mctx, DNS_DIFFOP_DEL, name, 0,
2283 &rdata, &newtuple));
2284 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2285 }
2286
2287 /*
2288 * Find the next tuple to be processed and remove the
2289 * temporary add record.
2290 */
2291 next = ISC_LIST_NEXT(tuple, link);
2292 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
2293 name, ttl, &tuple->rdata,
2294 &newtuple));
2295 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2296 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2297 dns_diff_appendminimal(diff, &tuple);
2298 dns_rdata_reset(&rdata);
2299 } else {
2300 next = ISC_LIST_NEXT(tuple, link);
2301 }
2302 }
2303
2304 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL;
2305 tuple = next) {
2306 INSIST(ttl_good);
2307
2308 next = ISC_LIST_NEXT(tuple, link);
2309 /*
2310 * See if we already have a REMOVE request in progress.
2311 */
2312 dns_nsec3param_toprivate(&tuple->rdata, &rdata, privatetype,
2313 buf, sizeof(buf));
2314
2315 buf[2] |= DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
2316
2317 CHECK(rr_exists(db, ver, name, &rdata, &flag));
2318 if (!flag) {
2319 buf[2] &= ~DNS_NSEC3FLAG_NONSEC;
2320 CHECK(rr_exists(db, ver, name, &rdata, &flag));
2321 }
2322
2323 if (!flag) {
2324 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
2325 name, 0, &rdata, &newtuple));
2326 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2327 }
2328 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
2329 ttl, &tuple->rdata, &newtuple));
2330 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2331 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2332 dns_diff_appendminimal(diff, &tuple);
2333 dns_rdata_reset(&rdata);
2334 }
2335
2336 result = ISC_R_SUCCESS;
2337 failure:
2338 dns_diff_clear(&temp_diff);
2339 return (result);
2340 }
2341
2342 static isc_result_t
2343 rollback_private(dns_db_t *db, dns_rdatatype_t privatetype,
2344 dns_dbversion_t *ver, dns_diff_t *diff) {
2345 dns_diff_t temp_diff;
2346 dns_diffop_t op;
2347 dns_difftuple_t *tuple, *newtuple = NULL, *next;
2348 dns_name_t *name = dns_db_origin(db);
2349 isc_mem_t *mctx = diff->mctx;
2350 isc_result_t result;
2351
2352 if (privatetype == 0) {
2353 return (ISC_R_SUCCESS);
2354 }
2355
2356 dns_diff_init(mctx, &temp_diff);
2357
2358 /*
2359 * Extract the changes to be rolled back.
2360 */
2361 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; tuple = next) {
2362 next = ISC_LIST_NEXT(tuple, link);
2363
2364 if (tuple->rdata.type != privatetype ||
2365 !dns_name_equal(name, &tuple->name)) {
2366 continue;
2367 }
2368
2369 /*
2370 * Allow records which indicate that a zone has been
2371 * signed with a DNSKEY to be removed.
2372 */
2373 if (tuple->op == DNS_DIFFOP_DEL && tuple->rdata.length == 5 &&
2374 tuple->rdata.data[0] != 0 && tuple->rdata.data[4] != 0)
2375 {
2376 continue;
2377 }
2378
2379 ISC_LIST_UNLINK(diff->tuples, tuple, link);
2380 ISC_LIST_PREPEND(temp_diff.tuples, tuple, link);
2381 }
2382
2383 /*
2384 * Rollback the changes.
2385 */
2386 while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) {
2387 op = (tuple->op == DNS_DIFFOP_DEL) ? DNS_DIFFOP_ADD
2388 : DNS_DIFFOP_DEL;
2389 CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl,
2390 &tuple->rdata, &newtuple));
2391 CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff));
2392 }
2393 result = ISC_R_SUCCESS;
2394
2395 failure:
2396 dns_diff_clear(&temp_diff);
2397 return (result);
2398 }
2399
2400 /*
2401 * Add records to cause the delayed signing of the zone by added DNSKEY
2402 * to remove the RRSIG records generated by a deleted DNSKEY.
2403 */
2404 static isc_result_t
2405 add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
2406 dns_dbversion_t *ver, dns_diff_t *diff) {
2407 dns_difftuple_t *tuple, *newtuple = NULL, *next;
2408 dns_rdata_dnskey_t dnskey;
2409 dns_rdata_t rdata = DNS_RDATA_INIT;
2410 bool flag;
2411 isc_region_t r;
2412 isc_result_t result = ISC_R_SUCCESS;
2413 uint16_t keyid;
2414 unsigned char buf[5];
2415 dns_name_t *name = dns_db_origin(db);
2416 dns_diff_t temp_diff;
2417
2418 dns_diff_init(diff->mctx, &temp_diff);
2419
2420 /*
2421 * Extract the DNSKEY tuples from the list.
2422 */
2423 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; tuple = next) {
2424 next = ISC_LIST_NEXT(tuple, link);
2425
2426 if (tuple->rdata.type != dns_rdatatype_dnskey) {
2427 continue;
2428 }
2429
2430 ISC_LIST_UNLINK(diff->tuples, tuple, link);
2431 ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
2432 }
2433
2434 /*
2435 * Extract TTL changes pairs, we don't need signing records for these.
2436 */
2437 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL;
2438 tuple = next) {
2439 if (tuple->op == DNS_DIFFOP_ADD) {
2440 /*
2441 * Walk the temp_diff list looking for the
2442 * corresponding delete.
2443 */
2444 next = ISC_LIST_HEAD(temp_diff.tuples);
2445 while (next != NULL) {
2446 unsigned char *next_data = next->rdata.data;
2447 unsigned char *tuple_data = tuple->rdata.data;
2448 if (next->op == DNS_DIFFOP_DEL &&
2449 dns_name_equal(&tuple->name, &next->name) &&
2450 next->rdata.length == tuple->rdata.length &&
2451 !memcmp(next_data, tuple_data,
2452 next->rdata.length))
2453 {
2454 ISC_LIST_UNLINK(temp_diff.tuples, next,
2455 link);
2456 ISC_LIST_APPEND(diff->tuples, next,
2457 link);
2458 break;
2459 }
2460 next = ISC_LIST_NEXT(next, link);
2461 }
2462 /*
2463 * If we have not found a pair move onto the next
2464 * tuple.
2465 */
2466 if (next == NULL) {
2467 next = ISC_LIST_NEXT(tuple, link);
2468 continue;
2469 }
2470 /*
2471 * Find the next tuple to be processed before
2472 * unlinking then complete moving the pair to 'diff'.
2473 */
2474 next = ISC_LIST_NEXT(tuple, link);
2475 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2476 ISC_LIST_APPEND(diff->tuples, tuple, link);
2477 } else {
2478 next = ISC_LIST_NEXT(tuple, link);
2479 }
2480 }
2481
2482 /*
2483 * Process the remaining DNSKEY entries.
2484 */
2485 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL;
2486 tuple = ISC_LIST_HEAD(temp_diff.tuples))
2487 {
2488 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2489 ISC_LIST_APPEND(diff->tuples, tuple, link);
2490
2491 result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
2492 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2493 if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK |
2494 DNS_KEYTYPE_NOAUTH)) != DNS_KEYOWNER_ZONE)
2495 {
2496 continue;
2497 }
2498
2499 dns_rdata_toregion(&tuple->rdata, &r);
2500
2501 keyid = dst_region_computeid(&r);
2502
2503 buf[0] = dnskey.algorithm;
2504 buf[1] = (keyid & 0xff00) >> 8;
2505 buf[2] = (keyid & 0xff);
2506 buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
2507 buf[4] = 0;
2508 rdata.data = buf;
2509 rdata.length = sizeof(buf);
2510 rdata.type = privatetype;
2511 rdata.rdclass = tuple->rdata.rdclass;
2512
2513 CHECK(rr_exists(db, ver, name, &rdata, &flag));
2514 if (flag) {
2515 continue;
2516 }
2517 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
2518 &rdata, &newtuple));
2519 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2520 INSIST(newtuple == NULL);
2521 /*
2522 * Remove any record which says this operation has already
2523 * completed.
2524 */
2525 buf[4] = 1;
2526 CHECK(rr_exists(db, ver, name, &rdata, &flag));
2527 if (flag) {
2528 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
2529 name, 0, &rdata, &newtuple));
2530 CHECK(do_one_tuple(&newtuple, db, ver, diff));
2531 INSIST(newtuple == NULL);
2532 }
2533 }
2534
2535 failure:
2536 dns_diff_clear(&temp_diff);
2537 return (result);
2538 }
2539
2540 static bool
2541 isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) {
2542 isc_result_t result;
2543 bool build_nsec, build_nsec3;
2544
2545 if (dns_db_issecure(db)) {
2546 return (true);
2547 }
2548
2549 result = dns_private_chains(db, ver, privatetype, &build_nsec,
2550 &build_nsec3);
2551 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2552 return (build_nsec || build_nsec3);
2553 }
2554
2555 static void
2556 update_action(isc_task_t *task, isc_event_t *event) {
2557 update_event_t *uev = (update_event_t *)event;
2558 dns_zone_t *zone = uev->zone;
2559 ns_client_t *client = (ns_client_t *)event->ev_arg;
2560 isc_result_t result;
2561 dns_db_t *db = NULL;
2562 dns_dbversion_t *oldver = NULL;
2563 dns_dbversion_t *ver = NULL;
2564 dns_diff_t diff; /* Pending updates. */
2565 dns_diff_t temp; /* Pending RR existence assertions. */
2566 bool soa_serial_changed = false;
2567 isc_mem_t *mctx = client->mctx;
2568 dns_rdatatype_t covers;
2569 dns_message_t *request = client->message;
2570 dns_rdataclass_t zoneclass;
2571 dns_name_t *zonename;
2572 dns_ssutable_t *ssutable = NULL;
2573 dns_fixedname_t tmpnamefixed;
2574 dns_name_t *tmpname = NULL;
2575 dns_zoneopt_t options;
2576 dns_difftuple_t *tuple;
2577 dns_rdata_dnskey_t dnskey;
2578 bool had_dnskey;
2579 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
2580 dns_ttl_t maxttl = 0;
2581 uint32_t maxrecords;
2582 uint64_t records;
2583 dns_aclenv_t *env =
2584 ns_interfacemgr_getaclenv(client->manager->interface->mgr);
2585
2586 INSIST(event->ev_type == DNS_EVENT_UPDATE);
2587
2588 dns_diff_init(mctx, &diff);
2589 dns_diff_init(mctx, &temp);
2590
2591 CHECK(dns_zone_getdb(zone, &db));
2592 zonename = dns_db_origin(db);
2593 zoneclass = dns_db_class(db);
2594 dns_zone_getssutable(zone, &ssutable);
2595
2596 /*
2597 * Update message processing can leak record existence information
2598 * so check that we are allowed to query this zone. Additionally
2599 * if we would refuse all updates for this zone we bail out here.
2600 */
2601 CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename,
2602 dns_zone_getupdateacl(zone), ssutable));
2603
2604 /*
2605 * Get old and new versions now that queryacl has been checked.
2606 */
2607 dns_db_currentversion(db, &oldver);
2608 CHECK(dns_db_newversion(db, &ver));
2609
2610 /*
2611 * Check prerequisites.
2612 */
2613
2614 for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
2615 result == ISC_R_SUCCESS;
2616 result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
2617 {
2618 dns_name_t *name = NULL;
2619 dns_rdata_t rdata = DNS_RDATA_INIT;
2620 dns_ttl_t ttl;
2621 dns_rdataclass_t update_class;
2622 bool flag;
2623
2624 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
2625 &name, &rdata, &covers, &ttl, &update_class);
2626
2627 if (ttl != 0) {
2628 PREREQFAILC(DNS_R_FORMERR, "prerequisite TTL is not "
2629 "zero");
2630 }
2631
2632 if (!dns_name_issubdomain(name, zonename)) {
2633 PREREQFAILN(DNS_R_NOTZONE, name,
2634 "prerequisite name is out of zone");
2635 }
2636
2637 if (update_class == dns_rdataclass_any) {
2638 if (rdata.length != 0) {
2639 PREREQFAILC(DNS_R_FORMERR, "class ANY "
2640 "prerequisite "
2641 "RDATA is not "
2642 "empty");
2643 }
2644 if (rdata.type == dns_rdatatype_any) {
2645 CHECK(name_exists(db, ver, name, &flag));
2646 if (!flag) {
2647 PREREQFAILN(DNS_R_NXDOMAIN, name,
2648 "'name in use' "
2649 "prerequisite not "
2650 "satisfied");
2651 }
2652 } else {
2653 CHECK(rrset_exists(db, ver, name, rdata.type,
2654 covers, &flag));
2655 if (!flag) {
2656 /* RRset does not exist. */
2657 PREREQFAILNT(DNS_R_NXRRSET, name,
2658 rdata.type,
2659 "'rrset exists (value "
2660 "independent)' "
2661 "prerequisite not "
2662 "satisfied");
2663 }
2664 }
2665 } else if (update_class == dns_rdataclass_none) {
2666 if (rdata.length != 0) {
2667 PREREQFAILC(DNS_R_FORMERR, "class NONE "
2668 "prerequisite "
2669 "RDATA is not "
2670 "empty");
2671 }
2672 if (rdata.type == dns_rdatatype_any) {
2673 CHECK(name_exists(db, ver, name, &flag));
2674 if (flag) {
2675 PREREQFAILN(DNS_R_YXDOMAIN, name,
2676 "'name not in use' "
2677 "prerequisite not "
2678 "satisfied");
2679 }
2680 } else {
2681 CHECK(rrset_exists(db, ver, name, rdata.type,
2682 covers, &flag));
2683 if (flag) {
2684 /* RRset exists. */
2685 PREREQFAILNT(DNS_R_YXRRSET, name,
2686 rdata.type,
2687 "'rrset does not exist' "
2688 "prerequisite not "
2689 "satisfied");
2690 }
2691 }
2692 } else if (update_class == zoneclass) {
2693 /* "temp<rr.name, rr.type> += rr;" */
2694 result = temp_append(&temp, name, &rdata);
2695 if (result != ISC_R_SUCCESS) {
2696 UNEXPECTED_ERROR(__FILE__, __LINE__,
2697 "temp entry creation failed: "
2698 "%s",
2699 dns_result_totext(result));
2700 FAIL(ISC_R_UNEXPECTED);
2701 }
2702 } else {
2703 PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite");
2704 }
2705 }
2706 if (result != ISC_R_NOMORE) {
2707 FAIL(result);
2708 }
2709
2710 /*
2711 * Perform the final check of the "rrset exists (value dependent)"
2712 * prerequisites.
2713 */
2714 if (ISC_LIST_HEAD(temp.tuples) != NULL) {
2715 dns_rdatatype_t type;
2716
2717 /*
2718 * Sort the prerequisite records by owner name,
2719 * type, and rdata.
2720 */
2721 result = dns_diff_sort(&temp, temp_order);
2722 if (result != ISC_R_SUCCESS) {
2723 FAILC(result, "'RRset exists (value dependent)' "
2724 "prerequisite not satisfied");
2725 }
2726
2727 tmpname = dns_fixedname_initname(&tmpnamefixed);
2728 result = temp_check(mctx, &temp, db, ver, tmpname, &type);
2729 if (result != ISC_R_SUCCESS) {
2730 FAILNT(result, tmpname, type,
2731 "'RRset exists (value dependent)' "
2732 "prerequisite not satisfied");
2733 }
2734 }
2735
2736 update_log(client, zone, LOGLEVEL_DEBUG, "prerequisites are OK");
2737
2738 /*
2739 * Check Requestor's Permissions. It seems a bit silly to do this
2740 * only after prerequisite testing, but that is what RFC2136 says.
2741 */
2742 if (ssutable == NULL) {
2743 CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
2744 "update", zonename, false, false));
2745 } else if (client->signer == NULL && !TCPCLIENT(client)) {
2746 CHECK(checkupdateacl(client, NULL, "update", zonename, false,
2747 true));
2748 }
2749
2750 if (dns_zone_getupdatedisabled(zone)) {
2751 FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
2752 "because the zone is frozen. Use "
2753 "'rndc thaw' to re-enable updates.");
2754 }
2755
2756 /*
2757 * Perform the Update Section Prescan.
2758 */
2759
2760 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
2761 result == ISC_R_SUCCESS;
2762 result = dns_message_nextname(request, DNS_SECTION_UPDATE))
2763 {
2764 dns_name_t *name = NULL;
2765 dns_rdata_t rdata = DNS_RDATA_INIT;
2766 dns_ttl_t ttl;
2767 dns_rdataclass_t update_class;
2768 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
2769 &rdata, &covers, &ttl, &update_class);
2770
2771 if (!dns_name_issubdomain(name, zonename)) {
2772 FAILC(DNS_R_NOTZONE, "update RR is outside zone");
2773 }
2774 if (update_class == zoneclass) {
2775 /*
2776 * Check for meta-RRs. The RFC2136 pseudocode says
2777 * check for ANY|AXFR|MAILA|MAILB, but the text adds
2778 * "or any other QUERY metatype"
2779 */
2780 if (dns_rdatatype_ismeta(rdata.type)) {
2781 FAILC(DNS_R_FORMERR, "meta-RR in update");
2782 }
2783 result = dns_zone_checknames(zone, name, &rdata);
2784 if (result != ISC_R_SUCCESS) {
2785 FAIL(DNS_R_REFUSED);
2786 }
2787 } else if (update_class == dns_rdataclass_any) {
2788 if (ttl != 0 || rdata.length != 0 ||
2789 (dns_rdatatype_ismeta(rdata.type) &&
2790 rdata.type != dns_rdatatype_any))
2791 {
2792 FAILC(DNS_R_FORMERR, "meta-RR in update");
2793 }
2794 } else if (update_class == dns_rdataclass_none) {
2795 if (ttl != 0 || dns_rdatatype_ismeta(rdata.type)) {
2796 FAILC(DNS_R_FORMERR, "meta-RR in update");
2797 }
2798 } else {
2799 update_log(client, zone, ISC_LOG_WARNING,
2800 "update RR has incorrect class %d",
2801 update_class);
2802 FAIL(DNS_R_FORMERR);
2803 }
2804
2805 /*
2806 * draft-ietf-dnsind-simple-secure-update-01 says
2807 * "Unlike traditional dynamic update, the client
2808 * is forbidden from updating NSEC records."
2809 */
2810 if (rdata.type == dns_rdatatype_nsec3) {
2811 FAILC(DNS_R_REFUSED, "explicit NSEC3 updates are not "
2812 "allowed "
2813 "in secure zones");
2814 } else if (rdata.type == dns_rdatatype_nsec) {
2815 FAILC(DNS_R_REFUSED, "explicit NSEC updates are not "
2816 "allowed "
2817 "in secure zones");
2818 } else if (rdata.type == dns_rdatatype_rrsig &&
2819 !dns_name_equal(name, zonename)) {
2820 FAILC(DNS_R_REFUSED, "explicit RRSIG updates are "
2821 "currently "
2822 "not supported in secure zones "
2823 "except "
2824 "at the apex");
2825 }
2826
2827 if (ssutable != NULL) {
2828 isc_netaddr_t netaddr;
2829 dst_key_t *tsigkey = NULL;
2830 isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
2831
2832 if (client->message->tsigkey != NULL) {
2833 tsigkey = client->message->tsigkey->key;
2834 }
2835
2836 if (rdata.type != dns_rdatatype_any) {
2837 if (!dns_ssutable_checkrules(
2838 ssutable, client->signer, name,
2839 &netaddr, TCPCLIENT(client), env,
2840 rdata.type, tsigkey))
2841 {
2842 FAILC(DNS_R_REFUSED, "rejected by "
2843 "secure update");
2844 }
2845 } else {
2846 if (!ssu_checkall(db, ver, name, ssutable,
2847 client->signer, &netaddr, env,
2848 TCPCLIENT(client), tsigkey))
2849 {
2850 FAILC(DNS_R_REFUSED, "rejected by "
2851 "secure update");
2852 }
2853 }
2854 }
2855 }
2856 if (result != ISC_R_NOMORE) {
2857 FAIL(result);
2858 }
2859
2860 update_log(client, zone, LOGLEVEL_DEBUG, "update section prescan OK");
2861
2862 /*
2863 * Process the Update Section.
2864 */
2865
2866 options = dns_zone_getoptions(zone);
2867 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
2868 result == ISC_R_SUCCESS;
2869 result = dns_message_nextname(request, DNS_SECTION_UPDATE))
2870 {
2871 dns_name_t *name = NULL;
2872 dns_rdata_t rdata = DNS_RDATA_INIT;
2873 dns_ttl_t ttl;
2874 dns_rdataclass_t update_class;
2875 bool flag;
2876
2877 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
2878 &rdata, &covers, &ttl, &update_class);
2879
2880 if (update_class == zoneclass) {
2881 /*
2882 * RFC1123 doesn't allow MF and MD in master zones.
2883 */
2884 if (rdata.type == dns_rdatatype_md ||
2885 rdata.type == dns_rdatatype_mf) {
2886 char typebuf[DNS_RDATATYPE_FORMATSIZE];
2887
2888 dns_rdatatype_format(rdata.type, typebuf,
2889 sizeof(typebuf));
2890 update_log(client, zone, LOGLEVEL_PROTOCOL,
2891 "attempt to add %s ignored",
2892 typebuf);
2893 continue;
2894 }
2895 if ((rdata.type == dns_rdatatype_ns ||
2896 rdata.type == dns_rdatatype_dname) &&
2897 dns_name_iswildcard(name))
2898 {
2899 char typebuf[DNS_RDATATYPE_FORMATSIZE];
2900
2901 dns_rdatatype_format(rdata.type, typebuf,
2902 sizeof(typebuf));
2903 update_log(client, zone, LOGLEVEL_PROTOCOL,
2904 "attempt to add wildcard %s record "
2905 "ignored",
2906 typebuf);
2907 continue;
2908 }
2909 if (rdata.type == dns_rdatatype_cname) {
2910 CHECK(cname_incompatible_rrset_exists(
2911 db, ver, name, &flag));
2912 if (flag) {
2913 update_log(client, zone,
2914 LOGLEVEL_PROTOCOL,
2915 "attempt to add CNAME "
2916 "alongside non-CNAME "
2917 "ignored");
2918 continue;
2919 }
2920 } else {
2921 CHECK(rrset_exists(db, ver, name,
2922 dns_rdatatype_cname, 0,
2923 &flag));
2924 if (flag && !dns_rdatatype_atcname(rdata.type))
2925 {
2926 update_log(client, zone,
2927 LOGLEVEL_PROTOCOL,
2928 "attempt to add non-CNAME "
2929 "alongside CNAME ignored");
2930 continue;
2931 }
2932 }
2933 if (rdata.type == dns_rdatatype_soa) {
2934 bool ok;
2935 CHECK(rrset_exists(db, ver, name,
2936 dns_rdatatype_soa, 0,
2937 &flag));
2938 if (!flag) {
2939 update_log(client, zone,
2940 LOGLEVEL_PROTOCOL,
2941 "attempt to create 2nd "
2942 "SOA ignored");
2943 continue;
2944 }
2945 CHECK(check_soa_increment(db, ver, &rdata,
2946 &ok));
2947 if (!ok) {
2948 update_log(client, zone,
2949 LOGLEVEL_PROTOCOL,
2950 "SOA update failed to "
2951 "increment serial, "
2952 "ignoring it");
2953 continue;
2954 }
2955 soa_serial_changed = true;
2956 }
2957
2958 if (dns_rdatatype_atparent(rdata.type) &&
2959 dns_name_equal(name, zonename)) {
2960 char typebuf[DNS_RDATATYPE_FORMATSIZE];
2961
2962 dns_rdatatype_format(rdata.type, typebuf,
2963 sizeof(typebuf));
2964 update_log(client, zone, LOGLEVEL_PROTOCOL,
2965 "attempt to add a %s record at "
2966 "zone apex ignored",
2967 typebuf);
2968 continue;
2969 }
2970
2971 if (rdata.type == privatetype) {
2972 update_log(client, zone, LOGLEVEL_PROTOCOL,
2973 "attempt to add a private type "
2974 "(%u) record rejected internal "
2975 "use only",
2976 privatetype);
2977 continue;
2978 }
2979
2980 if (rdata.type == dns_rdatatype_nsec3param) {
2981 /*
2982 * Ignore attempts to add NSEC3PARAM records
2983 * with any flags other than OPTOUT.
2984 */
2985 if ((rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) !=
2986 0) {
2987 update_log(client, zone,
2988 LOGLEVEL_PROTOCOL,
2989 "attempt to add NSEC3PARAM "
2990 "record with non OPTOUT "
2991 "flag");
2992 continue;
2993 }
2994 }
2995
2996 if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
2997 dns_name_internalwildcard(name))
2998 {
2999 char namestr[DNS_NAME_FORMATSIZE];
3000 dns_name_format(name, namestr, sizeof(namestr));
3001 update_log(client, zone, LOGLEVEL_PROTOCOL,
3002 "warning: ownername '%s' contains "
3003 "a non-terminal wildcard",
3004 namestr);
3005 }
3006
3007 if ((options & DNS_ZONEOPT_CHECKTTL) != 0) {
3008 maxttl = dns_zone_getmaxttl(zone);
3009 if (ttl > maxttl) {
3010 ttl = maxttl;
3011 update_log(client, zone,
3012 LOGLEVEL_PROTOCOL,
3013 "reducing TTL to the "
3014 "configured max-zone-ttl %d",
3015 maxttl);
3016 }
3017 }
3018
3019 if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) {
3020 char namestr[DNS_NAME_FORMATSIZE];
3021 char typestr[DNS_RDATATYPE_FORMATSIZE];
3022 char rdstr[2048];
3023 isc_buffer_t buf;
3024 int len = 0;
3025 const char *truncated = "";
3026
3027 dns_name_format(name, namestr, sizeof(namestr));
3028 dns_rdatatype_format(rdata.type, typestr,
3029 sizeof(typestr));
3030 isc_buffer_init(&buf, rdstr, sizeof(rdstr));
3031 result = dns_rdata_totext(&rdata, NULL, &buf);
3032 if (result == ISC_R_NOSPACE) {
3033 len = (int)isc_buffer_usedlength(&buf);
3034 truncated = " [TRUNCATED]";
3035 } else if (result != ISC_R_SUCCESS) {
3036 snprintf(rdstr, sizeof(rdstr),
3037 "[dns_"
3038 "rdata_totext failed: %s]",
3039 dns_result_totext(result));
3040 len = strlen(rdstr);
3041 } else {
3042 len = (int)isc_buffer_usedlength(&buf);
3043 }
3044 update_log(client, zone, LOGLEVEL_PROTOCOL,
3045 "adding an RR at '%s' %s %.*s%s",
3046 namestr, typestr, len, rdstr,
3047 truncated);
3048 }
3049
3050 /* Prepare the affected RRset for the addition. */
3051 {
3052 add_rr_prepare_ctx_t ctx;
3053 ctx.db = db;
3054 ctx.ver = ver;
3055 ctx.diff = &diff;
3056 ctx.name = name;
3057 ctx.oldname = name;
3058 ctx.update_rr = &rdata;
3059 ctx.update_rr_ttl = ttl;
3060 ctx.ignore_add = false;
3061 dns_diff_init(mctx, &ctx.del_diff);
3062 dns_diff_init(mctx, &ctx.add_diff);
3063 CHECK(foreach_rr(db, ver, name, rdata.type,
3064 covers, add_rr_prepare_action,
3065 &ctx));
3066
3067 if (ctx.ignore_add) {
3068 dns_diff_clear(&ctx.del_diff);
3069 dns_diff_clear(&ctx.add_diff);
3070 } else {
3071 result = do_diff(&ctx.del_diff, db, ver,
3072 &diff);
3073 if (result == ISC_R_SUCCESS) {
3074 result = do_diff(&ctx.add_diff,
3075 db, ver,
3076 &diff);
3077 }
3078 if (result != ISC_R_SUCCESS) {
3079 dns_diff_clear(&ctx.del_diff);
3080 dns_diff_clear(&ctx.add_diff);
3081 goto failure;
3082 }
3083 CHECK(update_one_rr(db, ver, &diff,
3084 DNS_DIFFOP_ADD,
3085 name, ttl, &rdata));
3086 }
3087 }
3088 } else if (update_class == dns_rdataclass_any) {
3089 if (rdata.type == dns_rdatatype_any) {
3090 if (isc_log_wouldlog(ns_lctx,
3091 LOGLEVEL_PROTOCOL)) {
3092 char namestr[DNS_NAME_FORMATSIZE];
3093 dns_name_format(name, namestr,
3094 sizeof(namestr));
3095 update_log(client, zone,
3096 LOGLEVEL_PROTOCOL,
3097 "delete all rrsets from "
3098 "name '%s'",
3099 namestr);
3100 }
3101 if (dns_name_equal(name, zonename)) {
3102 CHECK(delete_if(type_not_soa_nor_ns_p,
3103 db, ver, name,
3104 dns_rdatatype_any, 0,
3105 &rdata, &diff));
3106 } else {
3107 CHECK(delete_if(type_not_dnssec, db,
3108 ver, name,
3109 dns_rdatatype_any, 0,
3110 &rdata, &diff));
3111 }
3112 } else if (dns_name_equal(name, zonename) &&
3113 (rdata.type == dns_rdatatype_soa ||
3114 rdata.type == dns_rdatatype_ns))
3115 {
3116 update_log(client, zone, LOGLEVEL_PROTOCOL,
3117 "attempt to delete all SOA "
3118 "or NS records ignored");
3119 continue;
3120 } else {
3121 if (isc_log_wouldlog(ns_lctx,
3122 LOGLEVEL_PROTOCOL)) {
3123 char namestr[DNS_NAME_FORMATSIZE];
3124 char typestr[DNS_RDATATYPE_FORMATSIZE];
3125 dns_name_format(name, namestr,
3126 sizeof(namestr));
3127 dns_rdatatype_format(rdata.type,
3128 typestr,
3129 sizeof(typestr));
3130 update_log(client, zone,
3131 LOGLEVEL_PROTOCOL,
3132 "deleting rrset at '%s' %s",
3133 namestr, typestr);
3134 }
3135 CHECK(delete_if(true_p, db, ver, name,
3136 rdata.type, covers, &rdata,
3137 &diff));
3138 }
3139 } else if (update_class == dns_rdataclass_none) {
3140 char namestr[DNS_NAME_FORMATSIZE];
3141 char typestr[DNS_RDATATYPE_FORMATSIZE];
3142
3143 /*
3144 * The (name == zonename) condition appears in
3145 * RFC2136 3.4.2.4 but is missing from the pseudocode.
3146 */
3147 if (dns_name_equal(name, zonename)) {
3148 if (rdata.type == dns_rdatatype_soa) {
3149 update_log(client, zone,
3150 LOGLEVEL_PROTOCOL,
3151 "attempt to delete SOA "
3152 "ignored");
3153 continue;
3154 }
3155 if (rdata.type == dns_rdatatype_ns) {
3156 int count;
3157 CHECK(rr_count(db, ver, name,
3158 dns_rdatatype_ns, 0,
3159 &count));
3160 if (count == 1) {
3161 update_log(client, zone,
3162 LOGLEVEL_PROTOCOL,
3163 "attempt to "
3164 "delete last "
3165 "NS ignored");
3166 continue;
3167 }
3168 }
3169 }
3170 dns_name_format(name, namestr, sizeof(namestr));
3171 dns_rdatatype_format(rdata.type, typestr,
3172 sizeof(typestr));
3173 update_log(client, zone, LOGLEVEL_PROTOCOL,
3174 "deleting an RR at %s %s", namestr, typestr);
3175 CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type,
3176 covers, &rdata, &diff));
3177 }
3178 }
3179 if (result != ISC_R_NOMORE) {
3180 FAIL(result);
3181 }
3182
3183 /*
3184 * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
3185 * If they don't then back out all changes to DNSKEY/NSEC3PARAM
3186 * records.
3187 */
3188 if (!ISC_LIST_EMPTY(diff.tuples)) {
3189 CHECK(check_dnssec(client, zone, db, ver, &diff));
3190 }
3191
3192 if (!ISC_LIST_EMPTY(diff.tuples)) {
3193 unsigned int errors = 0;
3194 CHECK(dns_zone_nscheck(zone, db, ver, &errors));
3195 if (errors != 0) {
3196 update_log(client, zone, LOGLEVEL_PROTOCOL,
3197 "update rejected: post update name server "
3198 "sanity check failed");
3199 result = DNS_R_REFUSED;
3200 goto failure;
3201 }
3202 }
3203 if (!ISC_LIST_EMPTY(diff.tuples)) {
3204 result = dns_zone_cdscheck(zone, db, ver);
3205 if (result == DNS_R_BADCDS || result == DNS_R_BADCDNSKEY) {
3206 update_log(client, zone, LOGLEVEL_PROTOCOL,
3207 "update rejected: bad %s RRset",
3208 result == DNS_R_BADCDS ? "CDS" : "CDNSKEY");
3209 result = DNS_R_REFUSED;
3210 goto failure;
3211 }
3212 if (result != ISC_R_SUCCESS) {
3213 goto failure;
3214 }
3215 }
3216
3217 /*
3218 * If any changes were made, increment the SOA serial number,
3219 * update RRSIGs and NSECs (if zone is secure), and write the update
3220 * to the journal.
3221 */
3222 if (!ISC_LIST_EMPTY(diff.tuples)) {
3223 char *journalfile;
3224 dns_journal_t *journal;
3225 bool has_dnskey;
3226
3227 /*
3228 * Increment the SOA serial, but only if it was not
3229 * changed as a result of an update operation.
3230 */
3231 if (!soa_serial_changed) {
3232 CHECK(update_soa_serial(
3233 db, ver, &diff, mctx,
3234 dns_zone_getserialupdatemethod(zone)));
3235 }
3236
3237 CHECK(check_mx(client, zone, db, ver, &diff));
3238
3239 CHECK(remove_orphaned_ds(db, ver, &diff));
3240
3241 CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey, 0,
3242 &has_dnskey));
3243
3244 #define ALLOW_SECURE_TO_INSECURE(zone) \
3245 ((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0)
3246
3247 CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
3248 0, &had_dnskey));
3249 if (!ALLOW_SECURE_TO_INSECURE(zone)) {
3250 if (had_dnskey && !has_dnskey) {
3251 update_log(client, zone, LOGLEVEL_PROTOCOL,
3252 "update rejected: all DNSKEY "
3253 "records removed and "
3254 "'dnssec-secure-to-insecure' "
3255 "not set");
3256 result = DNS_R_REFUSED;
3257 goto failure;
3258 }
3259 }
3260
3261 CHECK(rollback_private(db, privatetype, ver, &diff));
3262
3263 CHECK(add_signing_records(db, privatetype, ver, &diff));
3264
3265 CHECK(add_nsec3param_records(client, zone, db, ver, &diff));
3266
3267 if (had_dnskey && !has_dnskey) {
3268 /*
3269 * We are transitioning from secure to insecure.
3270 * Cause all NSEC3 chains to be deleted. When the
3271 * the last signature for the DNSKEY records are
3272 * remove any NSEC chain present will also be removed.
3273 */
3274 CHECK(dns_nsec3param_deletechains(db, ver, zone, true,
3275 &diff));
3276 } else if (has_dnskey && isdnssec(db, ver, privatetype)) {
3277 dns_update_log_t log;
3278 uint32_t interval =
3279 dns_zone_getsigvalidityinterval(zone);
3280
3281 log.func = update_log_cb;
3282 log.arg = client;
3283 result = dns_update_signatures(&log, zone, db, oldver,
3284 ver, &diff, interval);
3285
3286 if (result != ISC_R_SUCCESS) {
3287 update_log(client, zone, ISC_LOG_ERROR,
3288 "RRSIG/NSEC/NSEC3 update failed: %s",
3289 isc_result_totext(result));
3290 goto failure;
3291 }
3292 }
3293
3294 maxrecords = dns_zone_getmaxrecords(zone);
3295 if (maxrecords != 0U) {
3296 result = dns_db_getsize(db, ver, &records, NULL);
3297 if (result == ISC_R_SUCCESS && records > maxrecords) {
3298 update_log(client, zone, ISC_LOG_ERROR,
3299 "records in zone (%" PRIu64 ") "
3300 "exceeds"
3301 " max-"
3302 "records"
3303 " (%u)",
3304 records, maxrecords);
3305 result = DNS_R_TOOMANYRECORDS;
3306 goto failure;
3307 }
3308 }
3309
3310 journalfile = dns_zone_getjournal(zone);
3311 if (journalfile != NULL) {
3312 update_log(client, zone, LOGLEVEL_DEBUG,
3313 "writing journal %s", journalfile);
3314
3315 journal = NULL;
3316 result = dns_journal_open(mctx, journalfile,
3317 DNS_JOURNAL_CREATE, &journal);
3318 if (result != ISC_R_SUCCESS) {
3319 FAILS(result, "journal open failed");
3320 }
3321
3322 result = dns_journal_write_transaction(journal, &diff);
3323 if (result != ISC_R_SUCCESS) {
3324 dns_journal_destroy(&journal);
3325 FAILS(result, "journal write failed");
3326 }
3327
3328 dns_journal_destroy(&journal);
3329 }
3330
3331 /*
3332 * XXXRTH Just a note that this committing code will have
3333 * to change to handle databases that need two-phase
3334 * commit, but this isn't a priority.
3335 */
3336 update_log(client, zone, LOGLEVEL_DEBUG,
3337 "committing update transaction");
3338
3339 dns_db_closeversion(db, &ver, true);
3340
3341 /*
3342 * Mark the zone as dirty so that it will be written to disk.
3343 */
3344 dns_zone_markdirty(zone);
3345
3346 /*
3347 * Notify slaves of the change we just made.
3348 */
3349 dns_zone_notify(zone);
3350
3351 /*
3352 * Cause the zone to be signed with the key that we
3353 * have just added or have the corresponding signatures
3354 * deleted.
3355 *
3356 * Note: we are already committed to this course of action.
3357 */
3358 for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL;
3359 tuple = ISC_LIST_NEXT(tuple, link))
3360 {
3361 isc_region_t r;
3362 dns_secalg_t algorithm;
3363 uint16_t keyid;
3364
3365 if (tuple->rdata.type != dns_rdatatype_dnskey) {
3366 continue;
3367 }
3368
3369 dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
3370 if ((dnskey.flags &
3371 (DNS_KEYFLAG_OWNERMASK | DNS_KEYTYPE_NOAUTH)) !=
3372 DNS_KEYOWNER_ZONE)
3373 {
3374 continue;
3375 }
3376
3377 dns_rdata_toregion(&tuple->rdata, &r);
3378 algorithm = dnskey.algorithm;
3379 keyid = dst_region_computeid(&r);
3380
3381 result = dns_zone_signwithkey(
3382 zone, algorithm, keyid,
3383 (tuple->op == DNS_DIFFOP_DEL));
3384 if (result != ISC_R_SUCCESS) {
3385 update_log(client, zone, ISC_LOG_ERROR,
3386 "dns_zone_signwithkey failed: %s",
3387 dns_result_totext(result));
3388 }
3389 }
3390
3391 /*
3392 * Cause the zone to add/delete NSEC3 chains for the
3393 * deferred NSEC3PARAM changes.
3394 *
3395 * Note: we are already committed to this course of action.
3396 */
3397 for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL;
3398 tuple = ISC_LIST_NEXT(tuple, link))
3399 {
3400 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
3401 dns_rdata_t rdata = DNS_RDATA_INIT;
3402 dns_rdata_nsec3param_t nsec3param;
3403
3404 if (tuple->rdata.type != privatetype ||
3405 tuple->op != DNS_DIFFOP_ADD) {
3406 continue;
3407 }
3408
3409 if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
3410 buf, sizeof(buf))) {
3411 continue;
3412 }
3413 dns_rdata_tostruct(&rdata, &nsec3param, NULL);
3414 if (nsec3param.flags == 0) {
3415 continue;
3416 }
3417
3418 result = dns_zone_addnsec3chain(zone, &nsec3param);
3419 if (result != ISC_R_SUCCESS) {
3420 update_log(client, zone, ISC_LOG_ERROR,
3421 "dns_zone_addnsec3chain failed: %s",
3422 dns_result_totext(result));
3423 }
3424 }
3425 } else {
3426 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
3427 dns_db_closeversion(db, &ver, true);
3428 }
3429 result = ISC_R_SUCCESS;
3430 goto common;
3431
3432 failure:
3433 /*
3434 * The reason for failure should have been logged at this point.
3435 */
3436 if (ver != NULL) {
3437 update_log(client, zone, LOGLEVEL_DEBUG, "rolling back");
3438 dns_db_closeversion(db, &ver, false);
3439 }
3440
3441 common:
3442 dns_diff_clear(&temp);
3443 dns_diff_clear(&diff);
3444
3445 if (oldver != NULL) {
3446 dns_db_closeversion(db, &oldver, false);
3447 }
3448
3449 if (db != NULL) {
3450 dns_db_detach(&db);
3451 }
3452
3453 if (ssutable != NULL) {
3454 dns_ssutable_detach(&ssutable);
3455 }
3456
3457 isc_task_detach(&task);
3458 uev->result = result;
3459 if (zone != NULL) {
3460 INSIST(uev->zone == zone); /* we use this later */
3461 }
3462 uev->ev_type = DNS_EVENT_UPDATEDONE;
3463 uev->ev_action = updatedone_action;
3464
3465 isc_task_send(client->task, &event);
3466
3467 INSIST(ver == NULL);
3468 INSIST(event == NULL);
3469 }
3470
3471 static void
3472 updatedone_action(isc_task_t *task, isc_event_t *event) {
3473 update_event_t *uev = (update_event_t *)event;
3474 ns_client_t *client = (ns_client_t *)event->ev_arg;
3475
3476 UNUSED(task);
3477
3478 REQUIRE(event->ev_type == DNS_EVENT_UPDATEDONE);
3479 REQUIRE(task == client->task);
3480 REQUIRE(client->updatehandle == client->handle);
3481
3482 INSIST(client->nupdates > 0);
3483 switch (uev->result) {
3484 case ISC_R_SUCCESS:
3485 inc_stats(client, uev->zone, ns_statscounter_updatedone);
3486 break;
3487 case DNS_R_REFUSED:
3488 inc_stats(client, uev->zone, ns_statscounter_updaterej);
3489 break;
3490 default:
3491 inc_stats(client, uev->zone, ns_statscounter_updatefail);
3492 break;
3493 }
3494 if (uev->zone != NULL) {
3495 dns_zone_detach(&uev->zone);
3496 }
3497
3498 client->nupdates--;
3499
3500 respond(client, uev->result);
3501
3502 isc_event_free(&event);
3503 isc_nmhandle_detach(&client->updatehandle);
3504 }
3505
3506 /*%
3507 * Update forwarding support.
3508 */
3509 static void
3510 forward_fail(isc_task_t *task, isc_event_t *event) {
3511 ns_client_t *client = (ns_client_t *)event->ev_arg;
3512
3513 UNUSED(task);
3514
3515 INSIST(client->nupdates > 0);
3516 client->nupdates--;
3517 respond(client, DNS_R_SERVFAIL);
3518 isc_event_free(&event);
3519 isc_nmhandle_detach(&client->updatehandle);
3520 }
3521
3522 static void
3523 forward_callback(void *arg, isc_result_t result, dns_message_t *answer) {
3524 update_event_t *uev = arg;
3525 ns_client_t *client = uev->ev_arg;
3526 dns_zone_t *zone = uev->zone;
3527
3528 if (result != ISC_R_SUCCESS) {
3529 INSIST(answer == NULL);
3530 uev->ev_type = DNS_EVENT_UPDATEDONE;
3531 uev->ev_action = forward_fail;
3532 inc_stats(client, zone, ns_statscounter_updatefwdfail);
3533 } else {
3534 uev->ev_type = DNS_EVENT_UPDATEDONE;
3535 uev->ev_action = forward_done;
3536 uev->answer = answer;
3537 inc_stats(client, zone, ns_statscounter_updaterespfwd);
3538 }
3539
3540 isc_task_send(client->task, ISC_EVENT_PTR(&uev));
3541 dns_zone_detach(&zone);
3542 }
3543
3544 static void
3545 forward_done(isc_task_t *task, isc_event_t *event) {
3546 update_event_t *uev = (update_event_t *)event;
3547 ns_client_t *client = (ns_client_t *)event->ev_arg;
3548
3549 UNUSED(task);
3550
3551 INSIST(client->nupdates > 0);
3552 client->nupdates--;
3553 ns_client_sendraw(client, uev->answer);
3554 dns_message_detach(&uev->answer);
3555 isc_event_free(&event);
3556 isc_nmhandle_detach(&client->updatehandle);
3557 }
3558
3559 static void
3560 forward_action(isc_task_t *task, isc_event_t *event) {
3561 update_event_t *uev = (update_event_t *)event;
3562 dns_zone_t *zone = uev->zone;
3563 ns_client_t *client = (ns_client_t *)event->ev_arg;
3564 isc_result_t result;
3565
3566 result = dns_zone_forwardupdate(zone, client->message, forward_callback,
3567 event);
3568 if (result != ISC_R_SUCCESS) {
3569 uev->ev_type = DNS_EVENT_UPDATEDONE;
3570 uev->ev_action = forward_fail;
3571 isc_task_send(client->task, &event);
3572 inc_stats(client, zone, ns_statscounter_updatefwdfail);
3573 dns_zone_detach(&zone);
3574 } else {
3575 inc_stats(client, zone, ns_statscounter_updatereqfwd);
3576 }
3577
3578 isc_task_detach(&task);
3579 }
3580
3581 static isc_result_t
3582 send_forward_event(ns_client_t *client, dns_zone_t *zone) {
3583 char namebuf[DNS_NAME_FORMATSIZE];
3584 char classbuf[DNS_RDATACLASS_FORMATSIZE];
3585 isc_result_t result = ISC_R_SUCCESS;
3586 update_event_t *event = NULL;
3587 isc_task_t *zonetask = NULL;
3588
3589 event = (update_event_t *)isc_event_allocate(
3590 client->mctx, client, DNS_EVENT_UPDATE, forward_action, NULL,
3591 sizeof(*event));
3592 event->zone = zone;
3593 event->result = ISC_R_SUCCESS;
3594
3595 INSIST(client->nupdates == 0);
3596 client->nupdates++;
3597 event->ev_arg = client;
3598
3599 dns_name_format(dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
3600 dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
3601 sizeof(classbuf));
3602
3603 ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
3604 LOGLEVEL_PROTOCOL, "forwarding update for zone '%s/%s'",
3605 namebuf, classbuf);
3606
3607 dns_zone_gettask(zone, &zonetask);
3608 isc_nmhandle_attach(client->handle, &client->updatehandle);
3609 isc_task_send(zonetask, ISC_EVENT_PTR(&event));
3610
3611 if (event != NULL) {
3612 isc_event_free(ISC_EVENT_PTR(&event));
3613 }
3614 return (result);
3615 }
3616