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