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