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