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