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