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