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