update.c revision 1.7
1/* $NetBSD: update.c,v 1.7 2020/05/24 19:46:29 christos 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 http://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 (/*CONSTCOND*/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 (/*CONSTCOND*/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 (/*CONSTCOND*/0) 131#define PREREQFAILC(code, msg) \ 132 do { \ 133 inc_stats(client, zone, ns_statscounter_updatebadprereq); \ 134 FAILC(code, msg); \ 135 } while (/*CONSTCOND*/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 (/*CONSTCOND*/0) 158#define PREREQFAILN(code, name, msg) \ 159 do { \ 160 inc_stats(client, zone, ns_statscounter_updatebadprereq); \ 161 FAILN(code, name, msg); \ 162 } while (/*CONSTCOND*/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 (/*CONSTCOND*/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 (/*CONSTCOND*/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 (/*CONSTCOND*/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 214typedef struct rr rr_t; 215 216struct rr { 217 /* dns_name_t name; */ 218 uint32_t ttl; 219 dns_rdata_t rdata; 220}; 221 222typedef struct update_event update_event_t; 223 224struct 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 240typedef 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 258static void 259update_action(isc_task_t *task, isc_event_t *event); 260static void 261updatedone_action(isc_task_t *task, isc_event_t *event); 262static isc_result_t 263send_forward_event(ns_client_t *client, dns_zone_t *zone); 264static void 265forward_done(isc_task_t *task, isc_event_t *event); 266static isc_result_t 267add_rr_prepare_action(void *data, rr_t *rr); 268 269/**************************************************************************/ 270 271static void 272update_log(ns_client_t *client, dns_zone_t *zone, int level, const char *fmt, 273 ...) ISC_FORMAT_PRINTF(4, 5); 274 275static void 276update_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) == false) { 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 311static void 312update_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 */ 319static inline void 320inc_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 */ 337static isc_result_t 338checkqueryacl(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 */ 387static isc_result_t 388checkupdateacl(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 */ 436static isc_result_t 437do_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 */ 476static isc_result_t 477do_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 487failure: 488 dns_diff_clear(diff); 489 return (result); 490} 491 492static isc_result_t 493update_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 */ 528typedef isc_result_t 529rrset_func(void *data, dns_rdataset_t *rrset); 530 531/*% 532 * Function type for foreach_rr() iterator actions. 533 */ 534typedef isc_result_t 535rr_func(void *data, rr_t *rr); 536 537/*% 538 * Internal context struct for foreach_node_rr(). 539 */ 540typedef 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 */ 548static isc_result_t 549foreach_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 */ 577static isc_result_t 578foreach_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 631cleanup_iterator: 632 dns_rdatasetiter_destroy(&iter); 633 634cleanup_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 */ 648static isc_result_t 649foreach_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 */ 666static isc_result_t 667foreach_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 743cleanup_rdataset: 744 dns_rdataset_disassociate(&rdataset); 745cleanup_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 */ 760typedef bool 761rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr); 762 763/*% 764 * Helper function for rrset_exists(). 765 */ 766static isc_result_t 767rrset_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 */ 797static isc_result_t 798rrset_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 */ 809static isc_result_t 810cname_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 */ 827static isc_result_t 828cname_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 */ 838static isc_result_t 839count_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 */ 849static isc_result_t 850rr_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 861static isc_result_t 862name_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 */ 871static isc_result_t 872name_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 */ 884typedef 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 907static isc_result_t 908ssu_checkrule(void *data, dns_rdataset_t *rrset) { 909 ssu_check_t *ssuinfo = data; 910 bool result; 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 result = dns_ssutable_checkrules( 921 ssuinfo->table, ssuinfo->signer, ssuinfo->name, ssuinfo->addr, 922 ssuinfo->tcp, ssuinfo->aclenv, rrset->type, ssuinfo->key); 923 return (result == true ? ISC_R_SUCCESS : ISC_R_FAILURE); 924} 925 926static bool 927ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 928 dns_ssutable_t *ssutable, dns_name_t *signer, isc_netaddr_t *addr, 929 dns_aclenv_t *aclenv, bool tcp, dst_key_t *key) { 930 isc_result_t result; 931 ssu_check_t ssuinfo; 932 933 ssuinfo.name = name; 934 ssuinfo.table = ssutable; 935 ssuinfo.signer = signer; 936 ssuinfo.addr = addr; 937 ssuinfo.aclenv = aclenv; 938 ssuinfo.tcp = tcp; 939 ssuinfo.key = key; 940 result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); 941 return (result == ISC_R_SUCCESS); 942} 943 944/**************************************************************************/ 945/* 946 * Checking of "RRset exists (value dependent)" prerequisites. 947 * 948 * In the RFC2136 section 3.2.5, this is the pseudocode involving 949 * a variable called "temp", a mapping of <name, type> tuples to rrsets. 950 * 951 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t" 952 * where each tuple has op==DNS_DIFFOP_EXISTS. 953 */ 954 955/*% 956 * Append a tuple asserting the existence of the RR with 957 * 'name' and 'rdata' to 'diff'. 958 */ 959static isc_result_t 960temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) { 961 isc_result_t result; 962 dns_difftuple_t *tuple = NULL; 963 964 REQUIRE(DNS_DIFF_VALID(diff)); 965 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, name, 0, 966 rdata, &tuple)); 967 ISC_LIST_APPEND(diff->tuples, tuple, link); 968failure: 969 return (result); 970} 971 972/*% 973 * Compare two rdatasets represented as sorted lists of tuples. 974 * All list elements must have the same owner name and type. 975 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset) 976 * if not. 977 */ 978static isc_result_t 979temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { 980 for (;;) { 981 if (a == NULL || b == NULL) { 982 break; 983 } 984 INSIST(a->op == DNS_DIFFOP_EXISTS && 985 b->op == DNS_DIFFOP_EXISTS); 986 INSIST(a->rdata.type == b->rdata.type); 987 INSIST(dns_name_equal(&a->name, &b->name)); 988 if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0) { 989 return (DNS_R_NXRRSET); 990 } 991 a = ISC_LIST_NEXT(a, link); 992 b = ISC_LIST_NEXT(b, link); 993 } 994 if (a != NULL || b != NULL) { 995 return (DNS_R_NXRRSET); 996 } 997 return (ISC_R_SUCCESS); 998} 999 1000/*% 1001 * A comparison function defining the sorting order for the entries 1002 * in the "temp" data structure. The major sort key is the owner name, 1003 * followed by the type and rdata. 1004 */ 1005static int 1006temp_order(const void *av, const void *bv) { 1007 dns_difftuple_t const *const *ap = av; 1008 dns_difftuple_t const *const *bp = bv; 1009 dns_difftuple_t const *a = *ap; 1010 dns_difftuple_t const *b = *bp; 1011 int r; 1012 r = dns_name_compare(&a->name, &b->name); 1013 if (r != 0) { 1014 return (r); 1015 } 1016 r = (b->rdata.type - a->rdata.type); 1017 if (r != 0) { 1018 return (r); 1019 } 1020 r = dns_rdata_casecompare(&a->rdata, &b->rdata); 1021 return (r); 1022} 1023 1024/*% 1025 * Check the "RRset exists (value dependent)" prerequisite information 1026 * in 'temp' against the contents of the database 'db'. 1027 * 1028 * Return ISC_R_SUCCESS if the prerequisites are satisfied, 1029 * rcode(dns_rcode_nxrrset) if not. 1030 * 1031 * 'temp' must be pre-sorted. 1032 */ 1033 1034static isc_result_t 1035temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, 1036 dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep) { 1037 isc_result_t result; 1038 dns_name_t *name; 1039 dns_dbnode_t *node; 1040 dns_difftuple_t *t; 1041 dns_diff_t trash; 1042 1043 dns_diff_init(mctx, &trash); 1044 1045 /* 1046 * For each name and type in the prerequisites, 1047 * construct a sorted rdata list of the corresponding 1048 * database contents, and compare the lists. 1049 */ 1050 t = ISC_LIST_HEAD(temp->tuples); 1051 while (t != NULL) { 1052 name = &t->name; 1053 dns_name_copynf(name, tmpname); 1054 *typep = t->rdata.type; 1055 1056 /* A new unique name begins here. */ 1057 node = NULL; 1058 result = dns_db_findnode(db, name, false, &node); 1059 if (result == ISC_R_NOTFOUND) { 1060 dns_diff_clear(&trash); 1061 return (DNS_R_NXRRSET); 1062 } 1063 if (result != ISC_R_SUCCESS) { 1064 dns_diff_clear(&trash); 1065 return (result); 1066 } 1067 1068 /* A new unique type begins here. */ 1069 while (t != NULL && dns_name_equal(&t->name, name)) { 1070 dns_rdatatype_t type, covers; 1071 dns_rdataset_t rdataset; 1072 dns_diff_t d_rrs; /* Database RRs with 1073 * this name and type */ 1074 dns_diff_t u_rrs; /* Update RRs with 1075 * this name and type */ 1076 1077 *typep = type = t->rdata.type; 1078 if (type == dns_rdatatype_rrsig || 1079 type == dns_rdatatype_sig) { 1080 covers = dns_rdata_covers(&t->rdata); 1081 } else if (type == dns_rdatatype_any) { 1082 dns_db_detachnode(db, &node); 1083 dns_diff_clear(&trash); 1084 return (DNS_R_NXRRSET); 1085 } else { 1086 covers = 0; 1087 } 1088 1089 /* 1090 * Collect all database RRs for this name and type 1091 * onto d_rrs and sort them. 1092 */ 1093 dns_rdataset_init(&rdataset); 1094 result = dns_db_findrdataset(db, node, ver, type, 1095 covers, (isc_stdtime_t)0, 1096 &rdataset, NULL); 1097 if (result != ISC_R_SUCCESS) { 1098 dns_db_detachnode(db, &node); 1099 dns_diff_clear(&trash); 1100 return (DNS_R_NXRRSET); 1101 } 1102 1103 dns_diff_init(mctx, &d_rrs); 1104 dns_diff_init(mctx, &u_rrs); 1105 1106 for (result = dns_rdataset_first(&rdataset); 1107 result == ISC_R_SUCCESS; 1108 result = dns_rdataset_next(&rdataset)) 1109 { 1110 dns_rdata_t rdata = DNS_RDATA_INIT; 1111 dns_rdataset_current(&rdataset, &rdata); 1112 result = temp_append(&d_rrs, name, &rdata); 1113 if (result != ISC_R_SUCCESS) { 1114 goto failure; 1115 } 1116 } 1117 if (result != ISC_R_NOMORE) { 1118 goto failure; 1119 } 1120 result = dns_diff_sort(&d_rrs, temp_order); 1121 if (result != ISC_R_SUCCESS) { 1122 goto failure; 1123 } 1124 1125 /* 1126 * Collect all update RRs for this name and type 1127 * onto u_rrs. No need to sort them here - 1128 * they are already sorted. 1129 */ 1130 while (t != NULL && dns_name_equal(&t->name, name) && 1131 t->rdata.type == type) { 1132 dns_difftuple_t *next = ISC_LIST_NEXT(t, link); 1133 ISC_LIST_UNLINK(temp->tuples, t, link); 1134 ISC_LIST_APPEND(u_rrs.tuples, t, link); 1135 t = next; 1136 } 1137 1138 /* Compare the two sorted lists. */ 1139 result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples), 1140 ISC_LIST_HEAD(d_rrs.tuples)); 1141 if (result != ISC_R_SUCCESS) { 1142 goto failure; 1143 } 1144 1145 /* 1146 * We are done with the tuples, but we can't free 1147 * them yet because "name" still points into one 1148 * of them. Move them on a temporary list. 1149 */ 1150 ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link); 1151 ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link); 1152 dns_rdataset_disassociate(&rdataset); 1153 1154 continue; 1155 1156 failure: 1157 dns_diff_clear(&d_rrs); 1158 dns_diff_clear(&u_rrs); 1159 dns_diff_clear(&trash); 1160 dns_rdataset_disassociate(&rdataset); 1161 dns_db_detachnode(db, &node); 1162 return (result); 1163 } 1164 1165 dns_db_detachnode(db, &node); 1166 } 1167 1168 dns_diff_clear(&trash); 1169 return (ISC_R_SUCCESS); 1170} 1171 1172/**************************************************************************/ 1173/* 1174 * Conditional deletion of RRs. 1175 */ 1176 1177/*% 1178 * Context structure for delete_if(). 1179 */ 1180 1181typedef struct { 1182 rr_predicate *predicate; 1183 dns_db_t *db; 1184 dns_dbversion_t *ver; 1185 dns_diff_t *diff; 1186 dns_name_t *name; 1187 dns_rdata_t *update_rr; 1188} conditional_delete_ctx_t; 1189 1190/*% 1191 * Predicate functions for delete_if(). 1192 */ 1193 1194/*% 1195 * Return true iff 'db_rr' is neither a SOA nor an NS RR nor 1196 * an RRSIG nor an NSEC3PARAM nor a NSEC. 1197 */ 1198static bool 1199type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1200 UNUSED(update_rr); 1201 return ((db_rr->type != dns_rdatatype_soa && 1202 db_rr->type != dns_rdatatype_ns && 1203 db_rr->type != dns_rdatatype_nsec3param && 1204 db_rr->type != dns_rdatatype_rrsig && 1205 db_rr->type != dns_rdatatype_nsec) 1206 ? true 1207 : false); 1208} 1209 1210/*% 1211 * Return true iff 'db_rr' is neither a RRSIG nor a NSEC. 1212 */ 1213static bool 1214type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1215 UNUSED(update_rr); 1216 return ((db_rr->type != dns_rdatatype_rrsig && 1217 db_rr->type != dns_rdatatype_nsec) 1218 ? true 1219 : false); 1220} 1221 1222/*% 1223 * Return true always. 1224 */ 1225static bool 1226true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1227 UNUSED(update_rr); 1228 UNUSED(db_rr); 1229 return (true); 1230} 1231 1232/*% 1233 * Return true iff the two RRs have identical rdata. 1234 */ 1235static bool 1236rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1237 /* 1238 * XXXRTH This is not a problem, but we should consider creating 1239 * dns_rdata_equal() (that used dns_name_equal()), since it 1240 * would be faster. Not a priority. 1241 */ 1242 return (dns_rdata_casecompare(update_rr, db_rr) == 0 ? true : false); 1243} 1244 1245/*% 1246 * Return true iff 'update_rr' should replace 'db_rr' according 1247 * to the special RFC2136 rules for CNAME, SOA, and WKS records. 1248 * 1249 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs 1250 * make little sense, so we replace those, too. 1251 * 1252 * Additionally replace RRSIG that have been generated by the same key 1253 * for the same type. This simplifies refreshing a offline KSK by not 1254 * requiring that the old RRSIG be deleted. It also simplifies key 1255 * rollover by only requiring that the new RRSIG be added. 1256 */ 1257static bool 1258replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1259 dns_rdata_rrsig_t updatesig, dbsig; 1260 isc_result_t result; 1261 1262 if (db_rr->type != update_rr->type) { 1263 return (false); 1264 } 1265 if (db_rr->type == dns_rdatatype_cname) { 1266 return (true); 1267 } 1268 if (db_rr->type == dns_rdatatype_dname) { 1269 return (true); 1270 } 1271 if (db_rr->type == dns_rdatatype_soa) { 1272 return (true); 1273 } 1274 if (db_rr->type == dns_rdatatype_nsec) { 1275 return (true); 1276 } 1277 if (db_rr->type == dns_rdatatype_rrsig) { 1278 /* 1279 * Replace existing RRSIG with the same keyid, 1280 * covered and algorithm. 1281 */ 1282 result = dns_rdata_tostruct(db_rr, &dbsig, NULL); 1283 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1284 result = dns_rdata_tostruct(update_rr, &updatesig, NULL); 1285 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1286 if (dbsig.keyid == updatesig.keyid && 1287 dbsig.covered == updatesig.covered && 1288 dbsig.algorithm == updatesig.algorithm) 1289 { 1290 return (true); 1291 } 1292 } 1293 if (db_rr->type == dns_rdatatype_wks) { 1294 /* 1295 * Compare the address and protocol fields only. These 1296 * form the first five bytes of the RR data. Do a 1297 * raw binary comparison; unpacking the WKS RRs using 1298 * dns_rdata_tostruct() might be cleaner in some ways. 1299 */ 1300 INSIST(db_rr->length >= 5 && update_rr->length >= 5); 1301 return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? true 1302 : false); 1303 } 1304 1305 if (db_rr->type == dns_rdatatype_nsec3param) { 1306 if (db_rr->length != update_rr->length) { 1307 return (false); 1308 } 1309 INSIST(db_rr->length >= 4 && update_rr->length >= 4); 1310 /* 1311 * Replace NSEC3PARAM records that only differ by the 1312 * flags field. 1313 */ 1314 if (db_rr->data[0] == update_rr->data[0] && 1315 memcmp(db_rr->data + 2, update_rr->data + 2, 1316 update_rr->length - 2) == 0) 1317 { 1318 return (true); 1319 } 1320 } 1321 return (false); 1322} 1323 1324/*% 1325 * Internal helper function for delete_if(). 1326 */ 1327static isc_result_t 1328delete_if_action(void *data, rr_t *rr) { 1329 conditional_delete_ctx_t *ctx = data; 1330 if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) { 1331 isc_result_t result; 1332 result = update_one_rr(ctx->db, ctx->ver, ctx->diff, 1333 DNS_DIFFOP_DEL, ctx->name, rr->ttl, 1334 &rr->rdata); 1335 return (result); 1336 } else { 1337 return (ISC_R_SUCCESS); 1338 } 1339} 1340 1341/*% 1342 * Conditionally delete RRs. Apply 'predicate' to the RRs 1343 * specified by 'db', 'ver', 'name', and 'type' (which can 1344 * be dns_rdatatype_any to match any type). Delete those 1345 * RRs for which the predicate returns true, and log the 1346 * deletions in 'diff'. 1347 */ 1348static isc_result_t 1349delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver, 1350 dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, 1351 dns_rdata_t *update_rr, dns_diff_t *diff) { 1352 conditional_delete_ctx_t ctx; 1353 ctx.predicate = predicate; 1354 ctx.db = db; 1355 ctx.ver = ver; 1356 ctx.diff = diff; 1357 ctx.name = name; 1358 ctx.update_rr = update_rr; 1359 return (foreach_rr(db, ver, name, type, covers, delete_if_action, 1360 &ctx)); 1361} 1362 1363/**************************************************************************/ 1364 1365static isc_result_t 1366add_rr_prepare_action(void *data, rr_t *rr) { 1367 isc_result_t result = ISC_R_SUCCESS; 1368 add_rr_prepare_ctx_t *ctx = data; 1369 dns_difftuple_t *tuple = NULL; 1370 bool equal, case_equal, ttl_equal; 1371 1372 /* 1373 * Are the new and old cases equal? 1374 */ 1375 case_equal = dns_name_caseequal(ctx->name, ctx->oldname); 1376 1377 /* 1378 * Are the ttl's equal? 1379 */ 1380 ttl_equal = rr->ttl == ctx->update_rr_ttl; 1381 1382 /* 1383 * If the update RR is a "duplicate" of a existing RR, 1384 * the update should be silently ignored. 1385 */ 1386 equal = (dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0); 1387 if (equal && case_equal && ttl_equal) { 1388 ctx->ignore_add = true; 1389 return (ISC_R_SUCCESS); 1390 } 1391 1392 /* 1393 * If this RR is "equal" to the update RR, it should 1394 * be deleted before the update RR is added. 1395 */ 1396 if (replaces_p(ctx->update_rr, &rr->rdata)) { 1397 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, 1398 ctx->oldname, rr->ttl, &rr->rdata, 1399 &tuple)); 1400 dns_diff_append(&ctx->del_diff, &tuple); 1401 return (ISC_R_SUCCESS); 1402 } 1403 1404 /* 1405 * If this RR differs in TTL or case from the update RR, 1406 * its TTL and case must be adjusted. 1407 */ 1408 if (!ttl_equal || !case_equal) { 1409 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, 1410 ctx->oldname, rr->ttl, &rr->rdata, 1411 &tuple)); 1412 dns_diff_append(&ctx->del_diff, &tuple); 1413 if (!equal) { 1414 CHECK(dns_difftuple_create( 1415 ctx->add_diff.mctx, DNS_DIFFOP_ADD, ctx->name, 1416 ctx->update_rr_ttl, &rr->rdata, &tuple)); 1417 dns_diff_append(&ctx->add_diff, &tuple); 1418 } 1419 } 1420failure: 1421 return (result); 1422} 1423 1424/**************************************************************************/ 1425/* 1426 * Miscellaneous subroutines. 1427 */ 1428 1429/*% 1430 * Extract a single update RR from 'section' of dynamic update message 1431 * 'msg', with consistency checking. 1432 * 1433 * Stores the owner name, rdata, and TTL of the update RR at 'name', 1434 * 'rdata', and 'ttl', respectively. 1435 */ 1436static void 1437get_current_rr(dns_message_t *msg, dns_section_t section, 1438 dns_rdataclass_t zoneclass, dns_name_t **name, 1439 dns_rdata_t *rdata, dns_rdatatype_t *covers, dns_ttl_t *ttl, 1440 dns_rdataclass_t *update_class) { 1441 dns_rdataset_t *rdataset; 1442 isc_result_t result; 1443 dns_message_currentname(msg, section, name); 1444 rdataset = ISC_LIST_HEAD((*name)->list); 1445 INSIST(rdataset != NULL); 1446 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); 1447 *covers = rdataset->covers; 1448 *ttl = rdataset->ttl; 1449 result = dns_rdataset_first(rdataset); 1450 INSIST(result == ISC_R_SUCCESS); 1451 dns_rdataset_current(rdataset, rdata); 1452 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); 1453 *update_class = rdata->rdclass; 1454 rdata->rdclass = zoneclass; 1455} 1456 1457/*% 1458 * Increment the SOA serial number of database 'db', version 'ver'. 1459 * Replace the SOA record in the database, and log the 1460 * change in 'diff'. 1461 */ 1462 1463/* 1464 * XXXRTH Failures in this routine will be worth logging, when 1465 * we have a logging system. Failure to find the zonename 1466 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR(). 1467 */ 1468 1469static isc_result_t 1470update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, 1471 isc_mem_t *mctx, dns_updatemethod_t method) { 1472 dns_difftuple_t *deltuple = NULL; 1473 dns_difftuple_t *addtuple = NULL; 1474 uint32_t serial; 1475 isc_result_t result; 1476 1477 CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); 1478 CHECK(dns_difftuple_copy(deltuple, &addtuple)); 1479 addtuple->op = DNS_DIFFOP_ADD; 1480 1481 serial = dns_soa_getserial(&addtuple->rdata); 1482 serial = dns_update_soaserial(serial, method); 1483 dns_soa_setserial(serial, &addtuple->rdata); 1484 CHECK(do_one_tuple(&deltuple, db, ver, diff)); 1485 CHECK(do_one_tuple(&addtuple, db, ver, diff)); 1486 result = ISC_R_SUCCESS; 1487 1488failure: 1489 if (addtuple != NULL) { 1490 dns_difftuple_free(&addtuple); 1491 } 1492 if (deltuple != NULL) { 1493 dns_difftuple_free(&deltuple); 1494 } 1495 return (result); 1496} 1497 1498/*% 1499 * Check that the new SOA record at 'update_rdata' does not 1500 * illegally cause the SOA serial number to decrease or stay 1501 * unchanged relative to the existing SOA in 'db'. 1502 * 1503 * Sets '*ok' to true if the update is legal, false if not. 1504 * 1505 * William King points out that RFC2136 is inconsistent about 1506 * the case where the serial number stays unchanged: 1507 * 1508 * section 3.4.2.2 requires a server to ignore a SOA update request 1509 * if the serial number on the update SOA is less_than_or_equal to 1510 * the zone SOA serial. 1511 * 1512 * section 3.6 requires a server to ignore a SOA update request if 1513 * the serial is less_than the zone SOA serial. 1514 * 1515 * Paul says 3.4.2.2 is correct. 1516 * 1517 */ 1518static isc_result_t 1519check_soa_increment(dns_db_t *db, dns_dbversion_t *ver, 1520 dns_rdata_t *update_rdata, bool *ok) { 1521 uint32_t db_serial; 1522 uint32_t update_serial; 1523 isc_result_t result; 1524 1525 update_serial = dns_soa_getserial(update_rdata); 1526 1527 result = dns_db_getsoaserial(db, ver, &db_serial); 1528 if (result != ISC_R_SUCCESS) { 1529 return (result); 1530 } 1531 1532 if (DNS_SERIAL_GE(db_serial, update_serial)) { 1533 *ok = false; 1534 } else { 1535 *ok = true; 1536 } 1537 1538 return (ISC_R_SUCCESS); 1539} 1540 1541/**************************************************************************/ 1542/*% 1543 * The actual update code in all its glory. We try to follow 1544 * the RFC2136 pseudocode as closely as possible. 1545 */ 1546 1547static isc_result_t 1548send_update_event(ns_client_t *client, dns_zone_t *zone) { 1549 isc_result_t result = ISC_R_SUCCESS; 1550 update_event_t *event = NULL; 1551 isc_task_t *zonetask = NULL; 1552 1553 event = (update_event_t *)isc_event_allocate( 1554 client->mctx, client, DNS_EVENT_UPDATE, update_action, NULL, 1555 sizeof(*event)); 1556 event->zone = zone; 1557 event->result = ISC_R_SUCCESS; 1558 1559 INSIST(client->nupdates == 0); 1560 client->nupdates++; 1561 event->ev_arg = client; 1562 1563 isc_nmhandle_ref(client->handle); 1564 dns_zone_gettask(zone, &zonetask); 1565 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 1566 1567 return (result); 1568} 1569 1570static void 1571respond(ns_client_t *client, isc_result_t result) { 1572 isc_result_t msg_result; 1573 1574 msg_result = dns_message_reply(client->message, true); 1575 if (msg_result != ISC_R_SUCCESS) { 1576 goto msg_failure; 1577 } 1578 client->message->rcode = dns_result_torcode(result); 1579 1580 ns_client_send(client); 1581 isc_nmhandle_unref(client->handle); 1582 return; 1583 1584msg_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_unref(client->handle); 1591} 1592 1593void 1594ns_update_start(ns_client_t *client, isc_result_t sigresult) { 1595 dns_message_t *request = client->message; 1596 isc_result_t result; 1597 dns_name_t *zonename; 1598 dns_rdataset_t *zone_rdataset; 1599 dns_zone_t *zone = NULL, *raw = NULL; 1600 1601 /* 1602 * Interpret the zone section. 1603 */ 1604 result = dns_message_firstname(request, DNS_SECTION_ZONE); 1605 if (result != ISC_R_SUCCESS) { 1606 FAILC(DNS_R_FORMERR, "update zone section empty"); 1607 } 1608 1609 /* 1610 * The zone section must contain exactly one "question", and 1611 * it must be of type SOA. 1612 */ 1613 zonename = NULL; 1614 dns_message_currentname(request, DNS_SECTION_ZONE, &zonename); 1615 zone_rdataset = ISC_LIST_HEAD(zonename->list); 1616 if (zone_rdataset->type != dns_rdatatype_soa) { 1617 FAILC(DNS_R_FORMERR, "update zone section contains non-SOA"); 1618 } 1619 if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) { 1620 FAILC(DNS_R_FORMERR, "update zone section contains multiple " 1621 "RRs"); 1622 } 1623 1624 /* The zone section must have exactly one name. */ 1625 result = dns_message_nextname(request, DNS_SECTION_ZONE); 1626 if (result != ISC_R_NOMORE) { 1627 FAILC(DNS_R_FORMERR, "update zone section contains multiple " 1628 "RRs"); 1629 } 1630 1631 result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone); 1632 if (result != ISC_R_SUCCESS) { 1633 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); 1634 } 1635 1636 /* 1637 * If there is a raw (unsigned) zone associated with this 1638 * zone then it processes the UPDATE request. 1639 */ 1640 dns_zone_getraw(zone, &raw); 1641 if (raw != NULL) { 1642 dns_zone_detach(&zone); 1643 dns_zone_attach(raw, &zone); 1644 dns_zone_detach(&raw); 1645 } 1646 1647 switch (dns_zone_gettype(zone)) { 1648 case dns_zone_master: 1649 case dns_zone_dlz: 1650 /* 1651 * We can now fail due to a bad signature as we now know 1652 * that we are the master. 1653 */ 1654 if (sigresult != ISC_R_SUCCESS) { 1655 FAIL(sigresult); 1656 } 1657 CHECK(send_update_event(client, zone)); 1658 break; 1659 case dns_zone_slave: 1660 case dns_zone_mirror: 1661 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone), 1662 "update forwarding", zonename, true, 1663 false)); 1664 CHECK(send_forward_event(client, zone)); 1665 break; 1666 default: 1667 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); 1668 } 1669 return; 1670 1671failure: 1672 if (result == DNS_R_REFUSED) { 1673 INSIST(dns_zone_gettype(zone) == dns_zone_slave || 1674 dns_zone_gettype(zone) == dns_zone_mirror); 1675 inc_stats(client, zone, ns_statscounter_updaterej); 1676 } 1677 /* 1678 * We failed without having sent an update event to the zone. 1679 * We are still in the client task context, so we can 1680 * simply give an error response without switching tasks. 1681 */ 1682 respond(client, result); 1683 if (zone != NULL) { 1684 dns_zone_detach(&zone); 1685 } 1686} 1687 1688/*% 1689 * DS records are not allowed to exist without corresponding NS records, 1690 * RFC 3658, 2.2 Protocol Change, 1691 * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex". 1692 */ 1693 1694static isc_result_t 1695remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) { 1696 isc_result_t result; 1697 bool ns_exists; 1698 dns_difftuple_t *tuple; 1699 dns_diff_t temp_diff; 1700 1701 dns_diff_init(diff->mctx, &temp_diff); 1702 1703 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; 1704 tuple = ISC_LIST_NEXT(tuple, link)) 1705 { 1706 if (!((tuple->op == DNS_DIFFOP_DEL && 1707 tuple->rdata.type == dns_rdatatype_ns) || 1708 (tuple->op == DNS_DIFFOP_ADD && 1709 tuple->rdata.type == dns_rdatatype_ds))) 1710 { 1711 continue; 1712 } 1713 CHECK(rrset_exists(db, newver, &tuple->name, dns_rdatatype_ns, 1714 0, &ns_exists)); 1715 if (ns_exists && 1716 !dns_name_equal(&tuple->name, dns_db_origin(db))) { 1717 continue; 1718 } 1719 CHECK(delete_if(true_p, db, newver, &tuple->name, 1720 dns_rdatatype_ds, 0, NULL, &temp_diff)); 1721 } 1722 result = ISC_R_SUCCESS; 1723 1724failure: 1725 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; 1726 tuple = ISC_LIST_HEAD(temp_diff.tuples)) 1727 { 1728 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 1729 dns_diff_appendminimal(diff, &tuple); 1730 } 1731 return (result); 1732} 1733 1734/* 1735 * This implements the post load integrity checks for mx records. 1736 */ 1737static isc_result_t 1738check_mx(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1739 dns_dbversion_t *newver, dns_diff_t *diff) { 1740 char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")]; 1741 char ownerbuf[DNS_NAME_FORMATSIZE]; 1742 char namebuf[DNS_NAME_FORMATSIZE]; 1743 char altbuf[DNS_NAME_FORMATSIZE]; 1744 dns_difftuple_t *t; 1745 dns_fixedname_t fixed; 1746 dns_name_t *foundname; 1747 dns_rdata_mx_t mx; 1748 dns_rdata_t rdata; 1749 bool ok = true; 1750 bool isaddress; 1751 isc_result_t result; 1752 struct in6_addr addr6; 1753 struct in_addr addr; 1754 dns_zoneopt_t options; 1755 1756 foundname = dns_fixedname_initname(&fixed); 1757 dns_rdata_init(&rdata); 1758 options = dns_zone_getoptions(zone); 1759 1760 for (t = ISC_LIST_HEAD(diff->tuples); t != NULL; 1761 t = ISC_LIST_NEXT(t, link)) { 1762 if (t->op != DNS_DIFFOP_ADD || 1763 t->rdata.type != dns_rdatatype_mx) { 1764 continue; 1765 } 1766 1767 result = dns_rdata_tostruct(&t->rdata, &mx, NULL); 1768 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1769 /* 1770 * Check if we will error out if we attempt to reload the 1771 * zone. 1772 */ 1773 dns_name_format(&mx.mx, namebuf, sizeof(namebuf)); 1774 dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf)); 1775 isaddress = false; 1776 if ((options & DNS_ZONEOPT_CHECKMX) != 0 && 1777 strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) 1778 { 1779 if (tmp[strlen(tmp) - 1] == '.') { 1780 tmp[strlen(tmp) - 1] = '\0'; 1781 } 1782 if (inet_pton(AF_INET, tmp, &addr) == 1 || 1783 inet_pton(AF_INET6, tmp, &addr6) == 1) 1784 { 1785 isaddress = true; 1786 } 1787 } 1788 1789 if (isaddress && (options & DNS_ZONEOPT_CHECKMXFAIL) != 0) { 1790 update_log(client, zone, ISC_LOG_ERROR, 1791 "%s/MX: '%s': %s", ownerbuf, namebuf, 1792 dns_result_totext(DNS_R_MXISADDRESS)); 1793 ok = false; 1794 } else if (isaddress) { 1795 update_log(client, zone, ISC_LOG_WARNING, 1796 "%s/MX: warning: '%s': %s", ownerbuf, 1797 namebuf, 1798 dns_result_totext(DNS_R_MXISADDRESS)); 1799 } 1800 1801 /* 1802 * Check zone integrity checks. 1803 */ 1804 if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0) { 1805 continue; 1806 } 1807 result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a, 0, 0, 1808 NULL, foundname, NULL, NULL); 1809 if (result == ISC_R_SUCCESS) { 1810 continue; 1811 } 1812 1813 if (result == DNS_R_NXRRSET) { 1814 result = dns_db_find(db, &mx.mx, newver, 1815 dns_rdatatype_aaaa, 0, 0, NULL, 1816 foundname, NULL, NULL); 1817 if (result == ISC_R_SUCCESS) { 1818 continue; 1819 } 1820 } 1821 1822 if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) { 1823 update_log(client, zone, ISC_LOG_ERROR, 1824 "%s/MX '%s' has no address records " 1825 "(A or AAAA)", 1826 ownerbuf, namebuf); 1827 ok = false; 1828 } else if (result == DNS_R_CNAME) { 1829 update_log(client, zone, ISC_LOG_ERROR, 1830 "%s/MX '%s' is a CNAME (illegal)", ownerbuf, 1831 namebuf); 1832 ok = false; 1833 } else if (result == DNS_R_DNAME) { 1834 dns_name_format(foundname, altbuf, sizeof altbuf); 1835 update_log(client, zone, ISC_LOG_ERROR, 1836 "%s/MX '%s' is below a DNAME '%s' (illegal)", 1837 ownerbuf, namebuf, altbuf); 1838 ok = false; 1839 } 1840 } 1841 return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED); 1842} 1843 1844static isc_result_t 1845rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1846 const dns_rdata_t *rdata, bool *flag) { 1847 dns_rdataset_t rdataset; 1848 dns_dbnode_t *node = NULL; 1849 isc_result_t result; 1850 1851 dns_rdataset_init(&rdataset); 1852 if (rdata->type == dns_rdatatype_nsec3) { 1853 CHECK(dns_db_findnsec3node(db, name, false, &node)); 1854 } else { 1855 CHECK(dns_db_findnode(db, name, false, &node)); 1856 } 1857 result = dns_db_findrdataset(db, node, ver, rdata->type, 0, 1858 (isc_stdtime_t)0, &rdataset, NULL); 1859 if (result == ISC_R_NOTFOUND) { 1860 *flag = false; 1861 result = ISC_R_SUCCESS; 1862 goto failure; 1863 } 1864 1865 for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; 1866 result = dns_rdataset_next(&rdataset)) 1867 { 1868 dns_rdata_t myrdata = DNS_RDATA_INIT; 1869 dns_rdataset_current(&rdataset, &myrdata); 1870 if (!dns_rdata_casecompare(&myrdata, rdata)) { 1871 break; 1872 } 1873 } 1874 dns_rdataset_disassociate(&rdataset); 1875 if (result == ISC_R_SUCCESS) { 1876 *flag = true; 1877 } else if (result == ISC_R_NOMORE) { 1878 *flag = false; 1879 result = ISC_R_SUCCESS; 1880 } 1881 1882failure: 1883 if (node != NULL) { 1884 dns_db_detachnode(db, &node); 1885 } 1886 return (result); 1887} 1888 1889static isc_result_t 1890get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype, 1891 unsigned int *iterationsp) { 1892 dns_dbnode_t *node = NULL; 1893 dns_rdata_nsec3param_t nsec3param; 1894 dns_rdataset_t rdataset; 1895 isc_result_t result; 1896 unsigned int iterations = 0; 1897 1898 dns_rdataset_init(&rdataset); 1899 1900 result = dns_db_getoriginnode(db, &node); 1901 if (result != ISC_R_SUCCESS) { 1902 return (result); 1903 } 1904 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0, 1905 (isc_stdtime_t)0, &rdataset, NULL); 1906 if (result == ISC_R_NOTFOUND) { 1907 goto try_private; 1908 } 1909 if (result != ISC_R_SUCCESS) { 1910 goto failure; 1911 } 1912 1913 for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; 1914 result = dns_rdataset_next(&rdataset)) 1915 { 1916 dns_rdata_t rdata = DNS_RDATA_INIT; 1917 dns_rdataset_current(&rdataset, &rdata); 1918 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); 1919 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) { 1920 continue; 1921 } 1922 if (nsec3param.iterations > iterations) { 1923 iterations = nsec3param.iterations; 1924 } 1925 } 1926 if (result != ISC_R_NOMORE) { 1927 goto failure; 1928 } 1929 1930 dns_rdataset_disassociate(&rdataset); 1931 1932try_private: 1933 if (privatetype == 0) { 1934 goto success; 1935 } 1936 1937 result = dns_db_findrdataset(db, node, ver, privatetype, 0, 1938 (isc_stdtime_t)0, &rdataset, NULL); 1939 if (result == ISC_R_NOTFOUND) { 1940 goto success; 1941 } 1942 if (result != ISC_R_SUCCESS) { 1943 goto failure; 1944 } 1945 1946 for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; 1947 result = dns_rdataset_next(&rdataset)) 1948 { 1949 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 1950 dns_rdata_t private = DNS_RDATA_INIT; 1951 dns_rdata_t rdata = DNS_RDATA_INIT; 1952 1953 dns_rdataset_current(&rdataset, &rdata); 1954 if (!dns_nsec3param_fromprivate(&private, &rdata, buf, 1955 sizeof(buf))) { 1956 continue; 1957 } 1958 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); 1959 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) { 1960 continue; 1961 } 1962 if (nsec3param.iterations > iterations) { 1963 iterations = nsec3param.iterations; 1964 } 1965 } 1966 if (result != ISC_R_NOMORE) { 1967 goto failure; 1968 } 1969 1970success: 1971 *iterationsp = iterations; 1972 result = ISC_R_SUCCESS; 1973 1974failure: 1975 if (node != NULL) { 1976 dns_db_detachnode(db, &node); 1977 } 1978 if (dns_rdataset_isassociated(&rdataset)) { 1979 dns_rdataset_disassociate(&rdataset); 1980 } 1981 return (result); 1982} 1983 1984/* 1985 * Prevent the zone entering a inconsistent state where 1986 * NSEC only DNSKEYs are present with NSEC3 chains. 1987 */ 1988static isc_result_t 1989check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1990 dns_dbversion_t *ver, dns_diff_t *diff) { 1991 dns_difftuple_t *tuple; 1992 bool nseconly = false, nsec3 = false; 1993 isc_result_t result; 1994 unsigned int iterations = 0, max; 1995 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); 1996 1997 /* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */ 1998 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; 1999 tuple = ISC_LIST_NEXT(tuple, link)) 2000 { 2001 if (tuple->op != DNS_DIFFOP_ADD) { 2002 continue; 2003 } 2004 2005 if (tuple->rdata.type == dns_rdatatype_dnskey) { 2006 uint8_t alg; 2007 alg = tuple->rdata.data[3]; 2008 if (alg == DST_ALG_RSASHA1) { 2009 nseconly = true; 2010 break; 2011 } 2012 } else if (tuple->rdata.type == dns_rdatatype_nsec3param) { 2013 nsec3 = true; 2014 break; 2015 } 2016 } 2017 2018 /* Check existing DB for NSEC-only DNSKEY */ 2019 if (!nseconly) { 2020 result = dns_nsec_nseconly(db, ver, &nseconly); 2021 2022 /* 2023 * An NSEC3PARAM update can proceed without a DNSKEY (it 2024 * will trigger a delayed change), so we can ignore 2025 * ISC_R_NOTFOUND here. 2026 */ 2027 if (result == ISC_R_NOTFOUND) { 2028 result = ISC_R_SUCCESS; 2029 } 2030 2031 CHECK(result); 2032 } 2033 2034 /* Check existing DB for NSEC3 */ 2035 if (!nsec3) { 2036 CHECK(dns_nsec3_activex(db, ver, false, privatetype, &nsec3)); 2037 } 2038 2039 /* Refuse to allow NSEC3 with NSEC-only keys */ 2040 if (nseconly && nsec3) { 2041 update_log(client, zone, ISC_LOG_ERROR, 2042 "NSEC only DNSKEYs and NSEC3 chains not allowed"); 2043 result = DNS_R_REFUSED; 2044 goto failure; 2045 } 2046 2047 /* Verify NSEC3 params */ 2048 CHECK(get_iterations(db, ver, privatetype, &iterations)); 2049 CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max)); 2050 if (max != 0 && iterations > max) { 2051 update_log(client, zone, ISC_LOG_ERROR, 2052 "too many NSEC3 iterations (%u) for " 2053 "weakest DNSKEY (%u)", 2054 iterations, max); 2055 result = DNS_R_REFUSED; 2056 goto failure; 2057 } 2058 2059failure: 2060 return (result); 2061} 2062 2063/* 2064 * Delay NSEC3PARAM changes as they need to be applied to the whole zone. 2065 */ 2066static isc_result_t 2067add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 2068 dns_dbversion_t *ver, dns_diff_t *diff) { 2069 isc_result_t result = ISC_R_SUCCESS; 2070 dns_difftuple_t *tuple, *newtuple = NULL, *next; 2071 dns_rdata_t rdata = DNS_RDATA_INIT; 2072 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1]; 2073 dns_diff_t temp_diff; 2074 dns_diffop_t op; 2075 bool flag; 2076 dns_name_t *name = dns_zone_getorigin(zone); 2077 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); 2078 uint32_t ttl = 0; 2079 bool ttl_good = false; 2080 2081 update_log(client, zone, ISC_LOG_DEBUG(3), 2082 "checking for NSEC3PARAM changes"); 2083 2084 dns_diff_init(diff->mctx, &temp_diff); 2085 2086 /* 2087 * Extract NSEC3PARAM tuples from list. 2088 */ 2089 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; tuple = next) { 2090 next = ISC_LIST_NEXT(tuple, link); 2091 2092 if (tuple->rdata.type != dns_rdatatype_nsec3param || 2093 !dns_name_equal(name, &tuple->name)) 2094 { 2095 continue; 2096 } 2097 ISC_LIST_UNLINK(diff->tuples, tuple, link); 2098 ISC_LIST_APPEND(temp_diff.tuples, tuple, link); 2099 } 2100 2101 /* 2102 * Extract TTL changes pairs, we don't need to convert these to 2103 * delayed changes. 2104 */ 2105 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; 2106 tuple = next) { 2107 if (tuple->op == DNS_DIFFOP_ADD) { 2108 if (!ttl_good) { 2109 /* 2110 * Any adds here will contain the final 2111 * NSEC3PARAM RRset TTL. 2112 */ 2113 ttl = tuple->ttl; 2114 ttl_good = true; 2115 } 2116 /* 2117 * Walk the temp_diff list looking for the 2118 * corresponding delete. 2119 */ 2120 next = ISC_LIST_HEAD(temp_diff.tuples); 2121 while (next != NULL) { 2122 unsigned char *next_data = next->rdata.data; 2123 unsigned char *tuple_data = tuple->rdata.data; 2124 if (next->op == DNS_DIFFOP_DEL && 2125 next->rdata.length == tuple->rdata.length && 2126 !memcmp(next_data, tuple_data, 2127 next->rdata.length)) 2128 { 2129 ISC_LIST_UNLINK(temp_diff.tuples, next, 2130 link); 2131 ISC_LIST_APPEND(diff->tuples, next, 2132 link); 2133 break; 2134 } 2135 next = ISC_LIST_NEXT(next, link); 2136 } 2137 /* 2138 * If we have not found a pair move onto the next 2139 * tuple. 2140 */ 2141 if (next == NULL) { 2142 next = ISC_LIST_NEXT(tuple, link); 2143 continue; 2144 } 2145 /* 2146 * Find the next tuple to be processed before 2147 * unlinking then complete moving the pair to 'diff'. 2148 */ 2149 next = ISC_LIST_NEXT(tuple, link); 2150 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2151 ISC_LIST_APPEND(diff->tuples, tuple, link); 2152 } else { 2153 next = ISC_LIST_NEXT(tuple, link); 2154 } 2155 } 2156 2157 /* 2158 * Preserve any ongoing changes from a BIND 9.6.x upgrade. 2159 * 2160 * Any NSEC3PARAM records with flags other than OPTOUT named 2161 * in managing and should not be touched so revert such changes 2162 * taking into account any TTL change of the NSEC3PARAM RRset. 2163 */ 2164 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; 2165 tuple = next) { 2166 next = ISC_LIST_NEXT(tuple, link); 2167 if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) { 2168 /* 2169 * If we haven't had any adds then the tuple->ttl must 2170 * be the original ttl and should be used for any 2171 * future changes. 2172 */ 2173 if (!ttl_good) { 2174 ttl = tuple->ttl; 2175 ttl_good = true; 2176 } 2177 op = (tuple->op == DNS_DIFFOP_DEL) ? DNS_DIFFOP_ADD 2178 : DNS_DIFFOP_DEL; 2179 CHECK(dns_difftuple_create(diff->mctx, op, name, ttl, 2180 &tuple->rdata, &newtuple)); 2181 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2182 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2183 dns_diff_appendminimal(diff, &tuple); 2184 } 2185 } 2186 2187 /* 2188 * We now have just the actual changes to the NSEC3PARAM RRset. 2189 * Convert the adds to delayed adds and the deletions into delayed 2190 * deletions. 2191 */ 2192 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; 2193 tuple = next) { 2194 /* 2195 * If we haven't had any adds then the tuple->ttl must be the 2196 * original ttl and should be used for any future changes. 2197 */ 2198 if (!ttl_good) { 2199 ttl = tuple->ttl; 2200 ttl_good = true; 2201 } 2202 if (tuple->op == DNS_DIFFOP_ADD) { 2203 bool nseconly = false; 2204 2205 /* 2206 * Look for any deletes which match this ADD ignoring 2207 * flags. We don't need to explicitly remove them as 2208 * they will be removed a side effect of processing 2209 * the add. 2210 */ 2211 next = ISC_LIST_HEAD(temp_diff.tuples); 2212 while (next != NULL) { 2213 unsigned char *next_data = next->rdata.data; 2214 unsigned char *tuple_data = tuple->rdata.data; 2215 if (next->op != DNS_DIFFOP_DEL || 2216 next->rdata.length != tuple->rdata.length || 2217 next_data[0] != tuple_data[0] || 2218 next_data[2] != tuple_data[2] || 2219 next_data[3] != tuple_data[3] || 2220 memcmp(next_data + 4, tuple_data + 4, 2221 tuple->rdata.length - 4)) 2222 { 2223 next = ISC_LIST_NEXT(next, link); 2224 continue; 2225 } 2226 ISC_LIST_UNLINK(temp_diff.tuples, next, link); 2227 ISC_LIST_APPEND(diff->tuples, next, link); 2228 next = ISC_LIST_HEAD(temp_diff.tuples); 2229 } 2230 2231 /* 2232 * Create a private-type record to signal that 2233 * we want a delayed NSEC3 chain add/delete 2234 */ 2235 dns_nsec3param_toprivate(&tuple->rdata, &rdata, 2236 privatetype, buf, sizeof(buf)); 2237 buf[2] |= DNS_NSEC3FLAG_CREATE; 2238 2239 /* 2240 * If the zone is not currently capable of 2241 * supporting an NSEC3 chain, then we set the 2242 * INITIAL flag to indicate that these parameters 2243 * are to be used later. 2244 */ 2245 result = dns_nsec_nseconly(db, ver, &nseconly); 2246 if (result == ISC_R_NOTFOUND || nseconly) { 2247 buf[2] |= DNS_NSEC3FLAG_INITIAL; 2248 } 2249 2250 /* 2251 * See if this CREATE request already exists. 2252 */ 2253 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2254 2255 if (!flag) { 2256 CHECK(dns_difftuple_create( 2257 diff->mctx, DNS_DIFFOP_ADD, name, 0, 2258 &rdata, &newtuple)); 2259 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2260 } 2261 2262 /* 2263 * Remove any existing CREATE request to add an 2264 * otherwise identical chain with a reversed 2265 * OPTOUT state. 2266 */ 2267 buf[2] ^= DNS_NSEC3FLAG_OPTOUT; 2268 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2269 2270 if (flag) { 2271 CHECK(dns_difftuple_create( 2272 diff->mctx, DNS_DIFFOP_DEL, name, 0, 2273 &rdata, &newtuple)); 2274 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2275 } 2276 2277 /* 2278 * Find the next tuple to be processed and remove the 2279 * temporary add record. 2280 */ 2281 next = ISC_LIST_NEXT(tuple, link); 2282 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, 2283 name, ttl, &tuple->rdata, 2284 &newtuple)); 2285 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2286 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2287 dns_diff_appendminimal(diff, &tuple); 2288 dns_rdata_reset(&rdata); 2289 } else { 2290 next = ISC_LIST_NEXT(tuple, link); 2291 } 2292 } 2293 2294 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; 2295 tuple = next) { 2296 INSIST(ttl_good); 2297 2298 next = ISC_LIST_NEXT(tuple, link); 2299 /* 2300 * See if we already have a REMOVE request in progress. 2301 */ 2302 dns_nsec3param_toprivate(&tuple->rdata, &rdata, privatetype, 2303 buf, sizeof(buf)); 2304 2305 buf[2] |= DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; 2306 2307 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2308 if (!flag) { 2309 buf[2] &= ~DNS_NSEC3FLAG_NONSEC; 2310 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2311 } 2312 2313 if (!flag) { 2314 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, 2315 name, 0, &rdata, &newtuple)); 2316 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2317 } 2318 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 2319 ttl, &tuple->rdata, &newtuple)); 2320 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2321 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2322 dns_diff_appendminimal(diff, &tuple); 2323 dns_rdata_reset(&rdata); 2324 } 2325 2326 result = ISC_R_SUCCESS; 2327failure: 2328 dns_diff_clear(&temp_diff); 2329 return (result); 2330} 2331 2332static isc_result_t 2333rollback_private(dns_db_t *db, dns_rdatatype_t privatetype, 2334 dns_dbversion_t *ver, dns_diff_t *diff) { 2335 dns_diff_t temp_diff; 2336 dns_diffop_t op; 2337 dns_difftuple_t *tuple, *newtuple = NULL, *next; 2338 dns_name_t *name = dns_db_origin(db); 2339 isc_mem_t *mctx = diff->mctx; 2340 isc_result_t result; 2341 2342 if (privatetype == 0) { 2343 return (ISC_R_SUCCESS); 2344 } 2345 2346 dns_diff_init(mctx, &temp_diff); 2347 2348 /* 2349 * Extract the changes to be rolled back. 2350 */ 2351 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; tuple = next) { 2352 next = ISC_LIST_NEXT(tuple, link); 2353 2354 if (tuple->rdata.type != privatetype || 2355 !dns_name_equal(name, &tuple->name)) { 2356 continue; 2357 } 2358 2359 /* 2360 * Allow records which indicate that a zone has been 2361 * signed with a DNSKEY to be removed. 2362 */ 2363 if (tuple->op == DNS_DIFFOP_DEL && tuple->rdata.length == 5 && 2364 tuple->rdata.data[0] != 0 && tuple->rdata.data[4] != 0) 2365 { 2366 continue; 2367 } 2368 2369 ISC_LIST_UNLINK(diff->tuples, tuple, link); 2370 ISC_LIST_PREPEND(temp_diff.tuples, tuple, link); 2371 } 2372 2373 /* 2374 * Rollback the changes. 2375 */ 2376 while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) { 2377 op = (tuple->op == DNS_DIFFOP_DEL) ? DNS_DIFFOP_ADD 2378 : DNS_DIFFOP_DEL; 2379 CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl, 2380 &tuple->rdata, &newtuple)); 2381 CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff)); 2382 } 2383 result = ISC_R_SUCCESS; 2384 2385failure: 2386 dns_diff_clear(&temp_diff); 2387 return (result); 2388} 2389 2390/* 2391 * Add records to cause the delayed signing of the zone by added DNSKEY 2392 * to remove the RRSIG records generated by a deleted DNSKEY. 2393 */ 2394static isc_result_t 2395add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype, 2396 dns_dbversion_t *ver, dns_diff_t *diff) { 2397 dns_difftuple_t *tuple, *newtuple = NULL, *next; 2398 dns_rdata_dnskey_t dnskey; 2399 dns_rdata_t rdata = DNS_RDATA_INIT; 2400 bool flag; 2401 isc_region_t r; 2402 isc_result_t result = ISC_R_SUCCESS; 2403 uint16_t keyid; 2404 unsigned char buf[5]; 2405 dns_name_t *name = dns_db_origin(db); 2406 dns_diff_t temp_diff; 2407 2408 dns_diff_init(diff->mctx, &temp_diff); 2409 2410 /* 2411 * Extract the DNSKEY tuples from the list. 2412 */ 2413 for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; tuple = next) { 2414 next = ISC_LIST_NEXT(tuple, link); 2415 2416 if (tuple->rdata.type != dns_rdatatype_dnskey) { 2417 continue; 2418 } 2419 2420 ISC_LIST_UNLINK(diff->tuples, tuple, link); 2421 ISC_LIST_APPEND(temp_diff.tuples, tuple, link); 2422 } 2423 2424 /* 2425 * Extract TTL changes pairs, we don't need signing records for these. 2426 */ 2427 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; 2428 tuple = next) { 2429 if (tuple->op == DNS_DIFFOP_ADD) { 2430 /* 2431 * Walk the temp_diff list looking for the 2432 * corresponding delete. 2433 */ 2434 next = ISC_LIST_HEAD(temp_diff.tuples); 2435 while (next != NULL) { 2436 unsigned char *next_data = next->rdata.data; 2437 unsigned char *tuple_data = tuple->rdata.data; 2438 if (next->op == DNS_DIFFOP_DEL && 2439 dns_name_equal(&tuple->name, &next->name) && 2440 next->rdata.length == tuple->rdata.length && 2441 !memcmp(next_data, tuple_data, 2442 next->rdata.length)) 2443 { 2444 ISC_LIST_UNLINK(temp_diff.tuples, next, 2445 link); 2446 ISC_LIST_APPEND(diff->tuples, next, 2447 link); 2448 break; 2449 } 2450 next = ISC_LIST_NEXT(next, link); 2451 } 2452 /* 2453 * If we have not found a pair move onto the next 2454 * tuple. 2455 */ 2456 if (next == NULL) { 2457 next = ISC_LIST_NEXT(tuple, link); 2458 continue; 2459 } 2460 /* 2461 * Find the next tuple to be processed before 2462 * unlinking then complete moving the pair to 'diff'. 2463 */ 2464 next = ISC_LIST_NEXT(tuple, link); 2465 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2466 ISC_LIST_APPEND(diff->tuples, tuple, link); 2467 } else { 2468 next = ISC_LIST_NEXT(tuple, link); 2469 } 2470 } 2471 2472 /* 2473 * Process the remaining DNSKEY entries. 2474 */ 2475 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; 2476 tuple = ISC_LIST_HEAD(temp_diff.tuples)) 2477 { 2478 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2479 ISC_LIST_APPEND(diff->tuples, tuple, link); 2480 2481 result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL); 2482 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2483 if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK | 2484 DNS_KEYTYPE_NOAUTH)) != DNS_KEYOWNER_ZONE) 2485 { 2486 continue; 2487 } 2488 2489 dns_rdata_toregion(&tuple->rdata, &r); 2490 2491 keyid = dst_region_computeid(&r); 2492 2493 buf[0] = dnskey.algorithm; 2494 buf[1] = (keyid & 0xff00) >> 8; 2495 buf[2] = (keyid & 0xff); 2496 buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1; 2497 buf[4] = 0; 2498 rdata.data = buf; 2499 rdata.length = sizeof(buf); 2500 rdata.type = privatetype; 2501 rdata.rdclass = tuple->rdata.rdclass; 2502 2503 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2504 if (flag) { 2505 continue; 2506 } 2507 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0, 2508 &rdata, &newtuple)); 2509 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2510 INSIST(newtuple == NULL); 2511 /* 2512 * Remove any record which says this operation has already 2513 * completed. 2514 */ 2515 buf[4] = 1; 2516 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2517 if (flag) { 2518 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, 2519 name, 0, &rdata, &newtuple)); 2520 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2521 INSIST(newtuple == NULL); 2522 } 2523 } 2524 2525failure: 2526 dns_diff_clear(&temp_diff); 2527 return (result); 2528} 2529 2530static bool 2531isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) { 2532 isc_result_t result; 2533 bool build_nsec, build_nsec3; 2534 2535 if (dns_db_issecure(db)) { 2536 return (true); 2537 } 2538 2539 result = dns_private_chains(db, ver, privatetype, &build_nsec, 2540 &build_nsec3); 2541 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2542 return (build_nsec || build_nsec3); 2543} 2544 2545static void 2546update_action(isc_task_t *task, isc_event_t *event) { 2547 update_event_t *uev = (update_event_t *)event; 2548 dns_zone_t *zone = uev->zone; 2549 ns_client_t *client = (ns_client_t *)event->ev_arg; 2550 isc_result_t result; 2551 dns_db_t *db = NULL; 2552 dns_dbversion_t *oldver = NULL; 2553 dns_dbversion_t *ver = NULL; 2554 dns_diff_t diff; /* Pending updates. */ 2555 dns_diff_t temp; /* Pending RR existence assertions. */ 2556 bool soa_serial_changed = false; 2557 isc_mem_t *mctx = client->mctx; 2558 dns_rdatatype_t covers; 2559 dns_message_t *request = client->message; 2560 dns_rdataclass_t zoneclass; 2561 dns_name_t *zonename; 2562 dns_ssutable_t *ssutable = NULL; 2563 dns_fixedname_t tmpnamefixed; 2564 dns_name_t *tmpname = NULL; 2565 dns_zoneopt_t options; 2566 dns_difftuple_t *tuple; 2567 dns_rdata_dnskey_t dnskey; 2568 bool had_dnskey; 2569 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); 2570 dns_ttl_t maxttl = 0; 2571 uint32_t maxrecords; 2572 uint64_t records; 2573 dns_aclenv_t *env = 2574 ns_interfacemgr_getaclenv(client->manager->interface->mgr); 2575 2576 INSIST(event->ev_type == DNS_EVENT_UPDATE); 2577 2578 dns_diff_init(mctx, &diff); 2579 dns_diff_init(mctx, &temp); 2580 2581 CHECK(dns_zone_getdb(zone, &db)); 2582 zonename = dns_db_origin(db); 2583 zoneclass = dns_db_class(db); 2584 dns_zone_getssutable(zone, &ssutable); 2585 2586 /* 2587 * Update message processing can leak record existence information 2588 * so check that we are allowed to query this zone. Additionally 2589 * if we would refuse all updates for this zone we bail out here. 2590 */ 2591 CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename, 2592 dns_zone_getupdateacl(zone), ssutable)); 2593 2594 /* 2595 * Get old and new versions now that queryacl has been checked. 2596 */ 2597 dns_db_currentversion(db, &oldver); 2598 CHECK(dns_db_newversion(db, &ver)); 2599 2600 /* 2601 * Check prerequisites. 2602 */ 2603 2604 for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE); 2605 result == ISC_R_SUCCESS; 2606 result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE)) 2607 { 2608 dns_name_t *name = NULL; 2609 dns_rdata_t rdata = DNS_RDATA_INIT; 2610 dns_ttl_t ttl; 2611 dns_rdataclass_t update_class; 2612 bool flag; 2613 2614 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass, 2615 &name, &rdata, &covers, &ttl, &update_class); 2616 2617 if (ttl != 0) { 2618 PREREQFAILC(DNS_R_FORMERR, "prerequisite TTL is not " 2619 "zero"); 2620 } 2621 2622 if (!dns_name_issubdomain(name, zonename)) { 2623 PREREQFAILN(DNS_R_NOTZONE, name, 2624 "prerequisite name is out of zone"); 2625 } 2626 2627 if (update_class == dns_rdataclass_any) { 2628 if (rdata.length != 0) { 2629 PREREQFAILC(DNS_R_FORMERR, "class ANY " 2630 "prerequisite " 2631 "RDATA is not " 2632 "empty"); 2633 } 2634 if (rdata.type == dns_rdatatype_any) { 2635 CHECK(name_exists(db, ver, name, &flag)); 2636 if (!flag) { 2637 PREREQFAILN(DNS_R_NXDOMAIN, name, 2638 "'name in use' " 2639 "prerequisite not " 2640 "satisfied"); 2641 } 2642 } else { 2643 CHECK(rrset_exists(db, ver, name, rdata.type, 2644 covers, &flag)); 2645 if (!flag) { 2646 /* RRset does not exist. */ 2647 PREREQFAILNT(DNS_R_NXRRSET, name, 2648 rdata.type, 2649 "'rrset exists (value " 2650 "independent)' " 2651 "prerequisite not " 2652 "satisfied"); 2653 } 2654 } 2655 } else if (update_class == dns_rdataclass_none) { 2656 if (rdata.length != 0) { 2657 PREREQFAILC(DNS_R_FORMERR, "class NONE " 2658 "prerequisite " 2659 "RDATA is not " 2660 "empty"); 2661 } 2662 if (rdata.type == dns_rdatatype_any) { 2663 CHECK(name_exists(db, ver, name, &flag)); 2664 if (flag) { 2665 PREREQFAILN(DNS_R_YXDOMAIN, name, 2666 "'name not in use' " 2667 "prerequisite not " 2668 "satisfied"); 2669 } 2670 } else { 2671 CHECK(rrset_exists(db, ver, name, rdata.type, 2672 covers, &flag)); 2673 if (flag) { 2674 /* RRset exists. */ 2675 PREREQFAILNT(DNS_R_YXRRSET, name, 2676 rdata.type, 2677 "'rrset does not exist' " 2678 "prerequisite not " 2679 "satisfied"); 2680 } 2681 } 2682 } else if (update_class == zoneclass) { 2683 /* "temp<rr.name, rr.type> += rr;" */ 2684 result = temp_append(&temp, name, &rdata); 2685 if (result != ISC_R_SUCCESS) { 2686 UNEXPECTED_ERROR(__FILE__, __LINE__, 2687 "temp entry creation failed: " 2688 "%s", 2689 dns_result_totext(result)); 2690 FAIL(ISC_R_UNEXPECTED); 2691 } 2692 } else { 2693 PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite"); 2694 } 2695 } 2696 if (result != ISC_R_NOMORE) { 2697 FAIL(result); 2698 } 2699 2700 /* 2701 * Perform the final check of the "rrset exists (value dependent)" 2702 * prerequisites. 2703 */ 2704 if (ISC_LIST_HEAD(temp.tuples) != NULL) { 2705 dns_rdatatype_t type; 2706 2707 /* 2708 * Sort the prerequisite records by owner name, 2709 * type, and rdata. 2710 */ 2711 result = dns_diff_sort(&temp, temp_order); 2712 if (result != ISC_R_SUCCESS) { 2713 FAILC(result, "'RRset exists (value dependent)' " 2714 "prerequisite not satisfied"); 2715 } 2716 2717 tmpname = dns_fixedname_initname(&tmpnamefixed); 2718 result = temp_check(mctx, &temp, db, ver, tmpname, &type); 2719 if (result != ISC_R_SUCCESS) { 2720 FAILNT(result, tmpname, type, 2721 "'RRset exists (value dependent)' " 2722 "prerequisite not satisfied"); 2723 } 2724 } 2725 2726 update_log(client, zone, LOGLEVEL_DEBUG, "prerequisites are OK"); 2727 2728 /* 2729 * Check Requestor's Permissions. It seems a bit silly to do this 2730 * only after prerequisite testing, but that is what RFC2136 says. 2731 */ 2732 if (ssutable == NULL) { 2733 CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), 2734 "update", zonename, false, false)); 2735 } else if (client->signer == NULL && !TCPCLIENT(client)) { 2736 CHECK(checkupdateacl(client, NULL, "update", zonename, false, 2737 true)); 2738 } 2739 2740 if (dns_zone_getupdatedisabled(zone)) { 2741 FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled " 2742 "because the zone is frozen. Use " 2743 "'rndc thaw' to re-enable updates."); 2744 } 2745 2746 /* 2747 * Perform the Update Section Prescan. 2748 */ 2749 2750 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2751 result == ISC_R_SUCCESS; 2752 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2753 { 2754 dns_name_t *name = NULL; 2755 dns_rdata_t rdata = DNS_RDATA_INIT; 2756 dns_ttl_t ttl; 2757 dns_rdataclass_t update_class; 2758 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name, 2759 &rdata, &covers, &ttl, &update_class); 2760 2761 if (!dns_name_issubdomain(name, zonename)) { 2762 FAILC(DNS_R_NOTZONE, "update RR is outside zone"); 2763 } 2764 if (update_class == zoneclass) { 2765 /* 2766 * Check for meta-RRs. The RFC2136 pseudocode says 2767 * check for ANY|AXFR|MAILA|MAILB, but the text adds 2768 * "or any other QUERY metatype" 2769 */ 2770 if (dns_rdatatype_ismeta(rdata.type)) { 2771 FAILC(DNS_R_FORMERR, "meta-RR in update"); 2772 } 2773 result = dns_zone_checknames(zone, name, &rdata); 2774 if (result != ISC_R_SUCCESS) { 2775 FAIL(DNS_R_REFUSED); 2776 } 2777 } else if (update_class == dns_rdataclass_any) { 2778 if (ttl != 0 || rdata.length != 0 || 2779 (dns_rdatatype_ismeta(rdata.type) && 2780 rdata.type != dns_rdatatype_any)) 2781 { 2782 FAILC(DNS_R_FORMERR, "meta-RR in update"); 2783 } 2784 } else if (update_class == dns_rdataclass_none) { 2785 if (ttl != 0 || dns_rdatatype_ismeta(rdata.type)) { 2786 FAILC(DNS_R_FORMERR, "meta-RR in update"); 2787 } 2788 } else { 2789 update_log(client, zone, ISC_LOG_WARNING, 2790 "update RR has incorrect class %d", 2791 update_class); 2792 FAIL(DNS_R_FORMERR); 2793 } 2794 2795 /* 2796 * draft-ietf-dnsind-simple-secure-update-01 says 2797 * "Unlike traditional dynamic update, the client 2798 * is forbidden from updating NSEC records." 2799 */ 2800 if (rdata.type == dns_rdatatype_nsec3) { 2801 FAILC(DNS_R_REFUSED, "explicit NSEC3 updates are not " 2802 "allowed " 2803 "in secure zones"); 2804 } else if (rdata.type == dns_rdatatype_nsec) { 2805 FAILC(DNS_R_REFUSED, "explicit NSEC updates are not " 2806 "allowed " 2807 "in secure zones"); 2808 } else if (rdata.type == dns_rdatatype_rrsig && 2809 !dns_name_equal(name, zonename)) { 2810 FAILC(DNS_R_REFUSED, "explicit RRSIG updates are " 2811 "currently " 2812 "not supported in secure zones " 2813 "except " 2814 "at the apex"); 2815 } 2816 2817 if (ssutable != NULL) { 2818 isc_netaddr_t netaddr; 2819 dst_key_t *tsigkey = NULL; 2820 isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); 2821 2822 if (client->message->tsigkey != NULL) { 2823 tsigkey = client->message->tsigkey->key; 2824 } 2825 2826 if (rdata.type != dns_rdatatype_any) { 2827 if (!dns_ssutable_checkrules( 2828 ssutable, client->signer, name, 2829 &netaddr, TCPCLIENT(client), env, 2830 rdata.type, tsigkey)) 2831 { 2832 FAILC(DNS_R_REFUSED, "rejected by " 2833 "secure update"); 2834 } 2835 } else { 2836 if (!ssu_checkall(db, ver, name, ssutable, 2837 client->signer, &netaddr, env, 2838 TCPCLIENT(client), tsigkey)) 2839 { 2840 FAILC(DNS_R_REFUSED, "rejected by " 2841 "secure update"); 2842 } 2843 } 2844 } 2845 } 2846 if (result != ISC_R_NOMORE) { 2847 FAIL(result); 2848 } 2849 2850 update_log(client, zone, LOGLEVEL_DEBUG, "update section prescan OK"); 2851 2852 /* 2853 * Process the Update Section. 2854 */ 2855 2856 options = dns_zone_getoptions(zone); 2857 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2858 result == ISC_R_SUCCESS; 2859 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2860 { 2861 dns_name_t *name = NULL; 2862 dns_rdata_t rdata = DNS_RDATA_INIT; 2863 dns_ttl_t ttl; 2864 dns_rdataclass_t update_class; 2865 bool flag; 2866 2867 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name, 2868 &rdata, &covers, &ttl, &update_class); 2869 2870 if (update_class == zoneclass) { 2871 /* 2872 * RFC1123 doesn't allow MF and MD in master zones. 2873 */ 2874 if (rdata.type == dns_rdatatype_md || 2875 rdata.type == dns_rdatatype_mf) { 2876 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2877 2878 dns_rdatatype_format(rdata.type, typebuf, 2879 sizeof(typebuf)); 2880 update_log(client, zone, LOGLEVEL_PROTOCOL, 2881 "attempt to add %s ignored", 2882 typebuf); 2883 continue; 2884 } 2885 if ((rdata.type == dns_rdatatype_ns || 2886 rdata.type == dns_rdatatype_dname) && 2887 dns_name_iswildcard(name)) 2888 { 2889 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2890 2891 dns_rdatatype_format(rdata.type, typebuf, 2892 sizeof(typebuf)); 2893 update_log(client, zone, LOGLEVEL_PROTOCOL, 2894 "attempt to add wildcard %s record " 2895 "ignored", 2896 typebuf); 2897 continue; 2898 } 2899 if (rdata.type == dns_rdatatype_cname) { 2900 CHECK(cname_incompatible_rrset_exists( 2901 db, ver, name, &flag)); 2902 if (flag) { 2903 update_log(client, zone, 2904 LOGLEVEL_PROTOCOL, 2905 "attempt to add CNAME " 2906 "alongside non-CNAME " 2907 "ignored"); 2908 continue; 2909 } 2910 } else { 2911 CHECK(rrset_exists(db, ver, name, 2912 dns_rdatatype_cname, 0, 2913 &flag)); 2914 if (flag && !dns_rdatatype_atcname(rdata.type)) 2915 { 2916 update_log(client, zone, 2917 LOGLEVEL_PROTOCOL, 2918 "attempt to add non-CNAME " 2919 "alongside CNAME ignored"); 2920 continue; 2921 } 2922 } 2923 if (rdata.type == dns_rdatatype_soa) { 2924 bool ok; 2925 CHECK(rrset_exists(db, ver, name, 2926 dns_rdatatype_soa, 0, 2927 &flag)); 2928 if (!flag) { 2929 update_log(client, zone, 2930 LOGLEVEL_PROTOCOL, 2931 "attempt to create 2nd " 2932 "SOA ignored"); 2933 continue; 2934 } 2935 CHECK(check_soa_increment(db, ver, &rdata, 2936 &ok)); 2937 if (!ok) { 2938 update_log(client, zone, 2939 LOGLEVEL_PROTOCOL, 2940 "SOA update failed to " 2941 "increment serial, " 2942 "ignoring it"); 2943 continue; 2944 } 2945 soa_serial_changed = true; 2946 } 2947 2948 if (rdata.type == privatetype) { 2949 update_log(client, zone, LOGLEVEL_PROTOCOL, 2950 "attempt to add a private type " 2951 "(%u) record rejected internal " 2952 "use only", 2953 privatetype); 2954 continue; 2955 } 2956 2957 if (rdata.type == dns_rdatatype_nsec3param) { 2958 /* 2959 * Ignore attempts to add NSEC3PARAM records 2960 * with any flags other than OPTOUT. 2961 */ 2962 if ((rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 2963 0) { 2964 update_log(client, zone, 2965 LOGLEVEL_PROTOCOL, 2966 "attempt to add NSEC3PARAM " 2967 "record with non OPTOUT " 2968 "flag"); 2969 continue; 2970 } 2971 } 2972 2973 if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 && 2974 dns_name_internalwildcard(name)) 2975 { 2976 char namestr[DNS_NAME_FORMATSIZE]; 2977 dns_name_format(name, namestr, sizeof(namestr)); 2978 update_log(client, zone, LOGLEVEL_PROTOCOL, 2979 "warning: ownername '%s' contains " 2980 "a non-terminal wildcard", 2981 namestr); 2982 } 2983 2984 if ((options & DNS_ZONEOPT_CHECKTTL) != 0) { 2985 maxttl = dns_zone_getmaxttl(zone); 2986 if (ttl > maxttl) { 2987 ttl = maxttl; 2988 update_log(client, zone, 2989 LOGLEVEL_PROTOCOL, 2990 "reducing TTL to the " 2991 "configured max-zone-ttl %d", 2992 maxttl); 2993 } 2994 } 2995 2996 if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) { 2997 char namestr[DNS_NAME_FORMATSIZE]; 2998 char typestr[DNS_RDATATYPE_FORMATSIZE]; 2999 char rdstr[2048]; 3000 isc_buffer_t buf; 3001 int len = 0; 3002 const char *truncated = ""; 3003 3004 dns_name_format(name, namestr, sizeof(namestr)); 3005 dns_rdatatype_format(rdata.type, typestr, 3006 sizeof(typestr)); 3007 isc_buffer_init(&buf, rdstr, sizeof(rdstr)); 3008 result = dns_rdata_totext(&rdata, NULL, &buf); 3009 if (result == ISC_R_NOSPACE) { 3010 len = (int)isc_buffer_usedlength(&buf); 3011 truncated = " [TRUNCATED]"; 3012 } else if (result != ISC_R_SUCCESS) { 3013 snprintf(rdstr, sizeof(rdstr), 3014 "[dns_" 3015 "rdata_totext failed: %s]", 3016 dns_result_totext(result)); 3017 len = strlen(rdstr); 3018 } else { 3019 len = (int)isc_buffer_usedlength(&buf); 3020 } 3021 update_log(client, zone, LOGLEVEL_PROTOCOL, 3022 "adding an RR at '%s' %s %.*s%s", 3023 namestr, typestr, len, rdstr, 3024 truncated); 3025 } 3026 3027 /* Prepare the affected RRset for the addition. */ 3028 { 3029 add_rr_prepare_ctx_t ctx; 3030 ctx.db = db; 3031 ctx.ver = ver; 3032 ctx.diff = &diff; 3033 ctx.name = name; 3034 ctx.oldname = name; 3035 ctx.update_rr = &rdata; 3036 ctx.update_rr_ttl = ttl; 3037 ctx.ignore_add = false; 3038 dns_diff_init(mctx, &ctx.del_diff); 3039 dns_diff_init(mctx, &ctx.add_diff); 3040 CHECK(foreach_rr(db, ver, name, rdata.type, 3041 covers, add_rr_prepare_action, 3042 &ctx)); 3043 3044 if (ctx.ignore_add) { 3045 dns_diff_clear(&ctx.del_diff); 3046 dns_diff_clear(&ctx.add_diff); 3047 } else { 3048 result = do_diff(&ctx.del_diff, db, ver, 3049 &diff); 3050 if (result == ISC_R_SUCCESS) { 3051 result = do_diff(&ctx.add_diff, 3052 db, ver, 3053 &diff); 3054 } 3055 if (result != ISC_R_SUCCESS) { 3056 dns_diff_clear(&ctx.del_diff); 3057 dns_diff_clear(&ctx.add_diff); 3058 goto failure; 3059 } 3060 CHECK(update_one_rr(db, ver, &diff, 3061 DNS_DIFFOP_ADD, 3062 name, ttl, &rdata)); 3063 } 3064 } 3065 } else if (update_class == dns_rdataclass_any) { 3066 if (rdata.type == dns_rdatatype_any) { 3067 if (isc_log_wouldlog(ns_lctx, 3068 LOGLEVEL_PROTOCOL)) { 3069 char namestr[DNS_NAME_FORMATSIZE]; 3070 dns_name_format(name, namestr, 3071 sizeof(namestr)); 3072 update_log(client, zone, 3073 LOGLEVEL_PROTOCOL, 3074 "delete all rrsets from " 3075 "name '%s'", 3076 namestr); 3077 } 3078 if (dns_name_equal(name, zonename)) { 3079 CHECK(delete_if(type_not_soa_nor_ns_p, 3080 db, ver, name, 3081 dns_rdatatype_any, 0, 3082 &rdata, &diff)); 3083 } else { 3084 CHECK(delete_if(type_not_dnssec, db, 3085 ver, name, 3086 dns_rdatatype_any, 0, 3087 &rdata, &diff)); 3088 } 3089 } else if (dns_name_equal(name, zonename) && 3090 (rdata.type == dns_rdatatype_soa || 3091 rdata.type == dns_rdatatype_ns)) 3092 { 3093 update_log(client, zone, LOGLEVEL_PROTOCOL, 3094 "attempt to delete all SOA " 3095 "or NS records ignored"); 3096 continue; 3097 } else { 3098 if (isc_log_wouldlog(ns_lctx, 3099 LOGLEVEL_PROTOCOL)) { 3100 char namestr[DNS_NAME_FORMATSIZE]; 3101 char typestr[DNS_RDATATYPE_FORMATSIZE]; 3102 dns_name_format(name, namestr, 3103 sizeof(namestr)); 3104 dns_rdatatype_format(rdata.type, 3105 typestr, 3106 sizeof(typestr)); 3107 update_log(client, zone, 3108 LOGLEVEL_PROTOCOL, 3109 "deleting rrset at '%s' %s", 3110 namestr, typestr); 3111 } 3112 CHECK(delete_if(true_p, db, ver, name, 3113 rdata.type, covers, &rdata, 3114 &diff)); 3115 } 3116 } else if (update_class == dns_rdataclass_none) { 3117 char namestr[DNS_NAME_FORMATSIZE]; 3118 char typestr[DNS_RDATATYPE_FORMATSIZE]; 3119 3120 /* 3121 * The (name == zonename) condition appears in 3122 * RFC2136 3.4.2.4 but is missing from the pseudocode. 3123 */ 3124 if (dns_name_equal(name, zonename)) { 3125 if (rdata.type == dns_rdatatype_soa) { 3126 update_log(client, zone, 3127 LOGLEVEL_PROTOCOL, 3128 "attempt to delete SOA " 3129 "ignored"); 3130 continue; 3131 } 3132 if (rdata.type == dns_rdatatype_ns) { 3133 int count; 3134 CHECK(rr_count(db, ver, name, 3135 dns_rdatatype_ns, 0, 3136 &count)); 3137 if (count == 1) { 3138 update_log(client, zone, 3139 LOGLEVEL_PROTOCOL, 3140 "attempt to " 3141 "delete last " 3142 "NS ignored"); 3143 continue; 3144 } 3145 } 3146 } 3147 dns_name_format(name, namestr, sizeof(namestr)); 3148 dns_rdatatype_format(rdata.type, typestr, 3149 sizeof(typestr)); 3150 update_log(client, zone, LOGLEVEL_PROTOCOL, 3151 "deleting an RR at %s %s", namestr, typestr); 3152 CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type, 3153 covers, &rdata, &diff)); 3154 } 3155 } 3156 if (result != ISC_R_NOMORE) { 3157 FAIL(result); 3158 } 3159 3160 /* 3161 * Check that any changes to DNSKEY/NSEC3PARAM records make sense. 3162 * If they don't then back out all changes to DNSKEY/NSEC3PARAM 3163 * records. 3164 */ 3165 if (!ISC_LIST_EMPTY(diff.tuples)) { 3166 CHECK(check_dnssec(client, zone, db, ver, &diff)); 3167 } 3168 3169 if (!ISC_LIST_EMPTY(diff.tuples)) { 3170 unsigned int errors = 0; 3171 CHECK(dns_zone_nscheck(zone, db, ver, &errors)); 3172 if (errors != 0) { 3173 update_log(client, zone, LOGLEVEL_PROTOCOL, 3174 "update rejected: post update name server " 3175 "sanity check failed"); 3176 result = DNS_R_REFUSED; 3177 goto failure; 3178 } 3179 } 3180 if (!ISC_LIST_EMPTY(diff.tuples)) { 3181 result = dns_zone_cdscheck(zone, db, ver); 3182 if (result == DNS_R_BADCDS || result == DNS_R_BADCDNSKEY) { 3183 update_log(client, zone, LOGLEVEL_PROTOCOL, 3184 "update rejected: bad %s RRset", 3185 result == DNS_R_BADCDS ? "CDS" : "CDNSKEY"); 3186 result = DNS_R_REFUSED; 3187 goto failure; 3188 } 3189 if (result != ISC_R_SUCCESS) { 3190 goto failure; 3191 } 3192 } 3193 3194 /* 3195 * If any changes were made, increment the SOA serial number, 3196 * update RRSIGs and NSECs (if zone is secure), and write the update 3197 * to the journal. 3198 */ 3199 if (!ISC_LIST_EMPTY(diff.tuples)) { 3200 char *journalfile; 3201 dns_journal_t *journal; 3202 bool has_dnskey; 3203 3204 /* 3205 * Increment the SOA serial, but only if it was not 3206 * changed as a result of an update operation. 3207 */ 3208 if (!soa_serial_changed) { 3209 CHECK(update_soa_serial( 3210 db, ver, &diff, mctx, 3211 dns_zone_getserialupdatemethod(zone))); 3212 } 3213 3214 CHECK(check_mx(client, zone, db, ver, &diff)); 3215 3216 CHECK(remove_orphaned_ds(db, ver, &diff)); 3217 3218 CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey, 0, 3219 &has_dnskey)); 3220 3221#define ALLOW_SECURE_TO_INSECURE(zone) \ 3222 ((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0) 3223 3224 CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey, 3225 0, &had_dnskey)); 3226 if (!ALLOW_SECURE_TO_INSECURE(zone)) { 3227 if (had_dnskey && !has_dnskey) { 3228 update_log(client, zone, LOGLEVEL_PROTOCOL, 3229 "update rejected: all DNSKEY " 3230 "records removed and " 3231 "'dnssec-secure-to-insecure' " 3232 "not set"); 3233 result = DNS_R_REFUSED; 3234 goto failure; 3235 } 3236 } 3237 3238 CHECK(rollback_private(db, privatetype, ver, &diff)); 3239 3240 CHECK(add_signing_records(db, privatetype, ver, &diff)); 3241 3242 CHECK(add_nsec3param_records(client, zone, db, ver, &diff)); 3243 3244 if (had_dnskey && !has_dnskey) { 3245 /* 3246 * We are transitioning from secure to insecure. 3247 * Cause all NSEC3 chains to be deleted. When the 3248 * the last signature for the DNSKEY records are 3249 * remove any NSEC chain present will also be removed. 3250 */ 3251 CHECK(dns_nsec3param_deletechains(db, ver, zone, true, 3252 &diff)); 3253 } else if (has_dnskey && isdnssec(db, ver, privatetype)) { 3254 dns_update_log_t log; 3255 uint32_t interval = 3256 dns_zone_getsigvalidityinterval(zone); 3257 3258 log.func = update_log_cb; 3259 log.arg = client; 3260 result = dns_update_signatures(&log, zone, db, oldver, 3261 ver, &diff, interval); 3262 3263 if (result != ISC_R_SUCCESS) { 3264 update_log(client, zone, ISC_LOG_ERROR, 3265 "RRSIG/NSEC/NSEC3 update failed: %s", 3266 isc_result_totext(result)); 3267 goto failure; 3268 } 3269 } 3270 3271 maxrecords = dns_zone_getmaxrecords(zone); 3272 if (maxrecords != 0U) { 3273 result = dns_db_getsize(db, ver, &records, NULL); 3274 if (result == ISC_R_SUCCESS && records > maxrecords) { 3275 update_log(client, zone, ISC_LOG_ERROR, 3276 "records in zone (%" PRIu64 ") " 3277 "exceeds" 3278 " max-" 3279 "records" 3280 " (%u)", 3281 records, maxrecords); 3282 result = DNS_R_TOOMANYRECORDS; 3283 goto failure; 3284 } 3285 } 3286 3287 journalfile = dns_zone_getjournal(zone); 3288 if (journalfile != NULL) { 3289 update_log(client, zone, LOGLEVEL_DEBUG, 3290 "writing journal %s", journalfile); 3291 3292 journal = NULL; 3293 result = dns_journal_open(mctx, journalfile, 3294 DNS_JOURNAL_CREATE, &journal); 3295 if (result != ISC_R_SUCCESS) { 3296 FAILS(result, "journal open failed"); 3297 } 3298 3299 result = dns_journal_write_transaction(journal, &diff); 3300 if (result != ISC_R_SUCCESS) { 3301 dns_journal_destroy(&journal); 3302 FAILS(result, "journal write failed"); 3303 } 3304 3305 dns_journal_destroy(&journal); 3306 } 3307 3308 /* 3309 * XXXRTH Just a note that this committing code will have 3310 * to change to handle databases that need two-phase 3311 * commit, but this isn't a priority. 3312 */ 3313 update_log(client, zone, LOGLEVEL_DEBUG, 3314 "committing update transaction"); 3315 3316 dns_db_closeversion(db, &ver, true); 3317 3318 /* 3319 * Mark the zone as dirty so that it will be written to disk. 3320 */ 3321 dns_zone_markdirty(zone); 3322 3323 /* 3324 * Notify slaves of the change we just made. 3325 */ 3326 dns_zone_notify(zone); 3327 3328 /* 3329 * Cause the zone to be signed with the key that we 3330 * have just added or have the corresponding signatures 3331 * deleted. 3332 * 3333 * Note: we are already committed to this course of action. 3334 */ 3335 for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL; 3336 tuple = ISC_LIST_NEXT(tuple, link)) 3337 { 3338 isc_region_t r; 3339 dns_secalg_t algorithm; 3340 uint16_t keyid; 3341 3342 if (tuple->rdata.type != dns_rdatatype_dnskey) { 3343 continue; 3344 } 3345 3346 dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL); 3347 if ((dnskey.flags & 3348 (DNS_KEYFLAG_OWNERMASK | DNS_KEYTYPE_NOAUTH)) != 3349 DNS_KEYOWNER_ZONE) 3350 { 3351 continue; 3352 } 3353 3354 dns_rdata_toregion(&tuple->rdata, &r); 3355 algorithm = dnskey.algorithm; 3356 keyid = dst_region_computeid(&r); 3357 3358 result = dns_zone_signwithkey( 3359 zone, algorithm, keyid, 3360 (tuple->op == DNS_DIFFOP_DEL)); 3361 if (result != ISC_R_SUCCESS) { 3362 update_log(client, zone, ISC_LOG_ERROR, 3363 "dns_zone_signwithkey failed: %s", 3364 dns_result_totext(result)); 3365 } 3366 } 3367 3368 /* 3369 * Cause the zone to add/delete NSEC3 chains for the 3370 * deferred NSEC3PARAM changes. 3371 * 3372 * Note: we are already committed to this course of action. 3373 */ 3374 for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL; 3375 tuple = ISC_LIST_NEXT(tuple, link)) 3376 { 3377 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 3378 dns_rdata_t rdata = DNS_RDATA_INIT; 3379 dns_rdata_nsec3param_t nsec3param; 3380 3381 if (tuple->rdata.type != privatetype || 3382 tuple->op != DNS_DIFFOP_ADD) { 3383 continue; 3384 } 3385 3386 if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata, 3387 buf, sizeof(buf))) { 3388 continue; 3389 } 3390 dns_rdata_tostruct(&rdata, &nsec3param, NULL); 3391 if (nsec3param.flags == 0) { 3392 continue; 3393 } 3394 3395 result = dns_zone_addnsec3chain(zone, &nsec3param); 3396 if (result != ISC_R_SUCCESS) { 3397 update_log(client, zone, ISC_LOG_ERROR, 3398 "dns_zone_addnsec3chain failed: %s", 3399 dns_result_totext(result)); 3400 } 3401 } 3402 } else { 3403 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request"); 3404 dns_db_closeversion(db, &ver, true); 3405 } 3406 result = ISC_R_SUCCESS; 3407 goto common; 3408 3409failure: 3410 /* 3411 * The reason for failure should have been logged at this point. 3412 */ 3413 if (ver != NULL) { 3414 update_log(client, zone, LOGLEVEL_DEBUG, "rolling back"); 3415 dns_db_closeversion(db, &ver, false); 3416 } 3417 3418common: 3419 dns_diff_clear(&temp); 3420 dns_diff_clear(&diff); 3421 3422 if (oldver != NULL) { 3423 dns_db_closeversion(db, &oldver, false); 3424 } 3425 3426 if (db != NULL) { 3427 dns_db_detach(&db); 3428 } 3429 3430 if (ssutable != NULL) { 3431 dns_ssutable_detach(&ssutable); 3432 } 3433 3434 isc_task_detach(&task); 3435 uev->result = result; 3436 if (zone != NULL) { 3437 INSIST(uev->zone == zone); /* we use this later */ 3438 } 3439 uev->ev_type = DNS_EVENT_UPDATEDONE; 3440 uev->ev_action = updatedone_action; 3441 isc_task_send(client->task, &event); 3442 3443 INSIST(ver == NULL); 3444 INSIST(event == NULL); 3445} 3446 3447static void 3448updatedone_action(isc_task_t *task, isc_event_t *event) { 3449 update_event_t *uev = (update_event_t *)event; 3450 ns_client_t *client = (ns_client_t *)event->ev_arg; 3451 3452 UNUSED(task); 3453 3454 INSIST(event->ev_type == DNS_EVENT_UPDATEDONE); 3455 INSIST(task == client->task); 3456 3457 INSIST(client->nupdates > 0); 3458 switch (uev->result) { 3459 case ISC_R_SUCCESS: 3460 inc_stats(client, uev->zone, ns_statscounter_updatedone); 3461 break; 3462 case DNS_R_REFUSED: 3463 inc_stats(client, uev->zone, ns_statscounter_updaterej); 3464 break; 3465 default: 3466 inc_stats(client, uev->zone, ns_statscounter_updatefail); 3467 break; 3468 } 3469 if (uev->zone != NULL) { 3470 dns_zone_detach(&uev->zone); 3471 } 3472 client->nupdates--; 3473 respond(client, uev->result); 3474 isc_event_free(&event); 3475 isc_nmhandle_unref(client->handle); 3476} 3477 3478/*% 3479 * Update forwarding support. 3480 */ 3481 3482static void 3483forward_fail(isc_task_t *task, isc_event_t *event) { 3484 ns_client_t *client = (ns_client_t *)event->ev_arg; 3485 3486 UNUSED(task); 3487 3488 INSIST(client->nupdates > 0); 3489 client->nupdates--; 3490 respond(client, DNS_R_SERVFAIL); 3491 isc_event_free(&event); 3492 isc_nmhandle_unref(client->handle); 3493} 3494 3495static void 3496forward_callback(void *arg, isc_result_t result, dns_message_t *answer) { 3497 update_event_t *uev = arg; 3498 ns_client_t *client = uev->ev_arg; 3499 dns_zone_t *zone = uev->zone; 3500 3501 if (result != ISC_R_SUCCESS) { 3502 INSIST(answer == NULL); 3503 uev->ev_type = DNS_EVENT_UPDATEDONE; 3504 uev->ev_action = forward_fail; 3505 inc_stats(client, zone, ns_statscounter_updatefwdfail); 3506 } else { 3507 uev->ev_type = DNS_EVENT_UPDATEDONE; 3508 uev->ev_action = forward_done; 3509 uev->answer = answer; 3510 inc_stats(client, zone, ns_statscounter_updaterespfwd); 3511 } 3512 isc_task_send(client->task, ISC_EVENT_PTR(&uev)); 3513 dns_zone_detach(&zone); 3514} 3515 3516static void 3517forward_done(isc_task_t *task, isc_event_t *event) { 3518 update_event_t *uev = (update_event_t *)event; 3519 ns_client_t *client = (ns_client_t *)event->ev_arg; 3520 3521 UNUSED(task); 3522 3523 INSIST(client->nupdates > 0); 3524 client->nupdates--; 3525 ns_client_sendraw(client, uev->answer); 3526 dns_message_destroy(&uev->answer); 3527 isc_event_free(&event); 3528 isc_nmhandle_unref(client->handle); 3529} 3530 3531static void 3532forward_action(isc_task_t *task, isc_event_t *event) { 3533 update_event_t *uev = (update_event_t *)event; 3534 dns_zone_t *zone = uev->zone; 3535 ns_client_t *client = (ns_client_t *)event->ev_arg; 3536 isc_result_t result; 3537 3538 result = dns_zone_forwardupdate(zone, client->message, forward_callback, 3539 event); 3540 if (result != ISC_R_SUCCESS) { 3541 uev->ev_type = DNS_EVENT_UPDATEDONE; 3542 uev->ev_action = forward_fail; 3543 isc_task_send(client->task, &event); 3544 inc_stats(client, zone, ns_statscounter_updatefwdfail); 3545 dns_zone_detach(&zone); 3546 } else { 3547 inc_stats(client, zone, ns_statscounter_updatereqfwd); 3548 } 3549 3550 isc_task_detach(&task); 3551} 3552 3553static isc_result_t 3554send_forward_event(ns_client_t *client, dns_zone_t *zone) { 3555 char namebuf[DNS_NAME_FORMATSIZE]; 3556 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 3557 isc_result_t result = ISC_R_SUCCESS; 3558 update_event_t *event = NULL; 3559 isc_task_t *zonetask = NULL; 3560 3561 event = (update_event_t *)isc_event_allocate( 3562 client->mctx, client, DNS_EVENT_UPDATE, forward_action, NULL, 3563 sizeof(*event)); 3564 event->zone = zone; 3565 event->result = ISC_R_SUCCESS; 3566 3567 INSIST(client->nupdates == 0); 3568 client->nupdates++; 3569 event->ev_arg = client; 3570 3571 dns_name_format(dns_zone_getorigin(zone), namebuf, sizeof(namebuf)); 3572 dns_rdataclass_format(dns_zone_getclass(zone), classbuf, 3573 sizeof(classbuf)); 3574 3575 ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 3576 LOGLEVEL_PROTOCOL, "forwarding update for zone '%s/%s'", 3577 namebuf, classbuf); 3578 3579 dns_zone_gettask(zone, &zonetask); 3580 isc_nmhandle_ref(client->handle); 3581 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 3582 3583 if (event != NULL) { 3584 isc_event_free(ISC_EVENT_PTR(&event)); 3585 } 3586 return (result); 3587} 3588