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