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