update.c revision 165071
1/* 2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: update.c,v 1.88.2.5.2.29 2006/01/06 00:01:42 marka Exp $ */ 19 20#include <config.h> 21 22#include <isc/print.h> 23#include <isc/string.h> 24#include <isc/taskpool.h> 25#include <isc/util.h> 26 27#include <dns/db.h> 28#include <dns/dbiterator.h> 29#include <dns/diff.h> 30#include <dns/dnssec.h> 31#include <dns/events.h> 32#include <dns/fixedname.h> 33#include <dns/journal.h> 34#include <dns/message.h> 35#include <dns/nsec.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/view.h> 44#include <dns/zone.h> 45#include <dns/zt.h> 46 47#include <named/client.h> 48#include <named/log.h> 49#include <named/update.h> 50 51/* 52 * This module implements dynamic update as in RFC2136. 53 */ 54 55/* 56 XXX TODO: 57 - document strict minimality 58*/ 59 60/**************************************************************************/ 61 62/* 63 * Log level for tracing dynamic update protocol requests. 64 */ 65#define LOGLEVEL_PROTOCOL ISC_LOG_INFO 66 67/* 68 * Log level for low-level debug tracing. 69 */ 70#define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8) 71 72/* 73 * Check an operation for failure. These macros all assume that 74 * the function using them has a 'result' variable and a 'failure' 75 * label. 76 */ 77#define CHECK(op) \ 78 do { result = (op); \ 79 if (result != ISC_R_SUCCESS) goto failure; \ 80 } while (0) 81 82/* 83 * Fail unconditionally with result 'code', which must not 84 * be ISC_R_SUCCESS. The reason for failure presumably has 85 * been logged already. 86 * 87 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 88 * from complaining about "end-of-loop code not reached". 89 */ 90 91#define FAIL(code) \ 92 do { \ 93 result = (code); \ 94 if (result != ISC_R_SUCCESS) goto failure; \ 95 } while (0) 96 97/* 98 * Fail unconditionally and log as a client error. 99 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 100 * from complaining about "end-of-loop code not reached". 101 */ 102#define FAILC(code, msg) \ 103 do { \ 104 const char *_what = "failed"; \ 105 result = (code); \ 106 switch (result) { \ 107 case DNS_R_NXDOMAIN: \ 108 case DNS_R_YXDOMAIN: \ 109 case DNS_R_YXRRSET: \ 110 case DNS_R_NXRRSET: \ 111 _what = "unsuccessful"; \ 112 } \ 113 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 114 "update %s: %s (%s)", _what, \ 115 msg, isc_result_totext(result)); \ 116 if (result != ISC_R_SUCCESS) goto failure; \ 117 } while (0) 118 119#define FAILN(code, name, msg) \ 120 do { \ 121 const char *_what = "failed"; \ 122 result = (code); \ 123 switch (result) { \ 124 case DNS_R_NXDOMAIN: \ 125 case DNS_R_YXDOMAIN: \ 126 case DNS_R_YXRRSET: \ 127 case DNS_R_NXRRSET: \ 128 _what = "unsuccessful"; \ 129 } \ 130 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ 131 char _nbuf[DNS_NAME_FORMATSIZE]; \ 132 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 133 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 134 "update %s: %s: %s (%s)", _what, _nbuf, \ 135 msg, isc_result_totext(result)); \ 136 } \ 137 if (result != ISC_R_SUCCESS) goto failure; \ 138 } while (0) 139 140#define FAILNT(code, name, type, msg) \ 141 do { \ 142 const char *_what = "failed"; \ 143 result = (code); \ 144 switch (result) { \ 145 case DNS_R_NXDOMAIN: \ 146 case DNS_R_YXDOMAIN: \ 147 case DNS_R_YXRRSET: \ 148 case DNS_R_NXRRSET: \ 149 _what = "unsuccessful"; \ 150 } \ 151 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ 152 char _nbuf[DNS_NAME_FORMATSIZE]; \ 153 char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \ 154 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 155 dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \ 156 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 157 "update %s: %s/%s: %s (%s)", \ 158 _what, _nbuf, _tbuf, msg, \ 159 isc_result_totext(result)); \ 160 } \ 161 if (result != ISC_R_SUCCESS) goto failure; \ 162 } while (0) 163/* 164 * Fail unconditionally and log as a server error. 165 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 166 * from complaining about "end-of-loop code not reached". 167 */ 168#define FAILS(code, msg) \ 169 do { \ 170 result = (code); \ 171 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 172 "error: %s: %s", \ 173 msg, isc_result_totext(result)); \ 174 if (result != ISC_R_SUCCESS) goto failure; \ 175 } while (0) 176 177/**************************************************************************/ 178 179typedef struct rr rr_t; 180 181struct rr { 182 /* dns_name_t name; */ 183 isc_uint32_t ttl; 184 dns_rdata_t rdata; 185}; 186 187typedef struct update_event update_event_t; 188 189struct update_event { 190 ISC_EVENT_COMMON(update_event_t); 191 dns_zone_t *zone; 192 isc_result_t result; 193 dns_message_t *answer; 194}; 195 196/**************************************************************************/ 197/* 198 * Forward declarations. 199 */ 200 201static void update_action(isc_task_t *task, isc_event_t *event); 202static void updatedone_action(isc_task_t *task, isc_event_t *event); 203static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone); 204static void forward_done(isc_task_t *task, isc_event_t *event); 205 206/**************************************************************************/ 207 208static void 209update_log(ns_client_t *client, dns_zone_t *zone, 210 int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); 211 212static void 213update_log(ns_client_t *client, dns_zone_t *zone, 214 int level, const char *fmt, ...) 215{ 216 va_list ap; 217 char message[4096]; 218 char namebuf[DNS_NAME_FORMATSIZE]; 219 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 220 221 if (client == NULL || zone == NULL) 222 return; 223 224 if (isc_log_wouldlog(ns_g_lctx, level) == ISC_FALSE) 225 return; 226 227 dns_name_format(dns_zone_getorigin(zone), namebuf, 228 sizeof(namebuf)); 229 dns_rdataclass_format(dns_zone_getclass(zone), classbuf, 230 sizeof(classbuf)); 231 232 va_start(ap, fmt); 233 vsnprintf(message, sizeof(message), fmt, ap); 234 va_end(ap); 235 236 ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 237 level, "updating zone '%s/%s': %s", 238 namebuf, classbuf, message); 239} 240 241static isc_result_t 242checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message, 243 dns_name_t *zonename, isc_boolean_t slave) 244{ 245 char namebuf[DNS_NAME_FORMATSIZE]; 246 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 247 int level = ISC_LOG_ERROR; 248 const char *msg = "denied"; 249 isc_result_t result; 250 251 if (slave && acl == NULL) { 252 result = DNS_R_NOTIMP; 253 level = ISC_LOG_DEBUG(3); 254 msg = "disabled"; 255 } else 256 result = ns_client_checkaclsilent(client, acl, ISC_FALSE); 257 258 if (result == ISC_R_SUCCESS) { 259 level = ISC_LOG_DEBUG(3); 260 msg = "approved"; 261 } 262 263 dns_name_format(zonename, namebuf, sizeof(namebuf)); 264 dns_rdataclass_format(client->view->rdclass, classbuf, 265 sizeof(classbuf)); 266 267 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 268 NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s", 269 message, namebuf, classbuf, msg); 270 return (result); 271} 272 273/* 274 * Update a single RR in version 'ver' of 'db' and log the 275 * update in 'diff'. 276 * 277 * Ensures: 278 * '*tuple' == NULL. Either the tuple is freed, or its 279 * ownership has been transferred to the diff. 280 */ 281static isc_result_t 282do_one_tuple(dns_difftuple_t **tuple, 283 dns_db_t *db, dns_dbversion_t *ver, 284 dns_diff_t *diff) 285{ 286 dns_diff_t temp_diff; 287 isc_result_t result; 288 289 /* 290 * Create a singleton diff. 291 */ 292 dns_diff_init(diff->mctx, &temp_diff); 293 ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); 294 295 /* 296 * Apply it to the database. 297 */ 298 result = dns_diff_apply(&temp_diff, db, ver); 299 ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); 300 if (result != ISC_R_SUCCESS) { 301 dns_difftuple_free(tuple); 302 return (result); 303 } 304 305 /* 306 * Merge it into the current pending journal entry. 307 */ 308 dns_diff_appendminimal(diff, tuple); 309 310 /* 311 * Do not clear temp_diff. 312 */ 313 return (ISC_R_SUCCESS); 314} 315 316/* 317 * Perform the updates in 'updates' in version 'ver' of 'db' and log the 318 * update in 'diff'. 319 * 320 * Ensures: 321 * 'updates' is empty. 322 */ 323static isc_result_t 324do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver, 325 dns_diff_t *diff) 326{ 327 isc_result_t result; 328 while (! ISC_LIST_EMPTY(updates->tuples)) { 329 dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples); 330 ISC_LIST_UNLINK(updates->tuples, t, link); 331 CHECK(do_one_tuple(&t, db, ver, diff)); 332 } 333 return (ISC_R_SUCCESS); 334 335 failure: 336 dns_diff_clear(diff); 337 return (result); 338} 339 340static isc_result_t 341update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, 342 dns_diffop_t op, dns_name_t *name, 343 dns_ttl_t ttl, dns_rdata_t *rdata) 344{ 345 dns_difftuple_t *tuple = NULL; 346 isc_result_t result; 347 result = dns_difftuple_create(diff->mctx, op, 348 name, ttl, rdata, &tuple); 349 if (result != ISC_R_SUCCESS) 350 return (result); 351 return (do_one_tuple(&tuple, db, ver, diff)); 352} 353 354/**************************************************************************/ 355/* 356 * Callback-style iteration over rdatasets and rdatas. 357 * 358 * foreach_rrset() can be used to iterate over the RRsets 359 * of a name and call a callback function with each 360 * one. Similarly, foreach_rr() can be used to iterate 361 * over the individual RRs at name, optionally restricted 362 * to RRs of a given type. 363 * 364 * The callback functions are called "actions" and take 365 * two arguments: a void pointer for passing arbitrary 366 * context information, and a pointer to the current RRset 367 * or RR. By convention, their names end in "_action". 368 */ 369 370/* 371 * XXXRTH We might want to make this public somewhere in libdns. 372 */ 373 374/* 375 * Function type for foreach_rrset() iterator actions. 376 */ 377typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset); 378 379/* 380 * Function type for foreach_rr() iterator actions. 381 */ 382typedef isc_result_t rr_func(void *data, rr_t *rr); 383 384/* 385 * Internal context struct for foreach_node_rr(). 386 */ 387typedef struct { 388 rr_func * rr_action; 389 void * rr_action_data; 390} foreach_node_rr_ctx_t; 391 392/* 393 * Internal helper function for foreach_node_rr(). 394 */ 395static isc_result_t 396foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) { 397 isc_result_t result; 398 foreach_node_rr_ctx_t *ctx = data; 399 for (result = dns_rdataset_first(rdataset); 400 result == ISC_R_SUCCESS; 401 result = dns_rdataset_next(rdataset)) 402 { 403 rr_t rr = { 0, DNS_RDATA_INIT }; 404 405 dns_rdataset_current(rdataset, &rr.rdata); 406 rr.ttl = rdataset->ttl; 407 result = (*ctx->rr_action)(ctx->rr_action_data, &rr); 408 if (result != ISC_R_SUCCESS) 409 return (result); 410 } 411 if (result != ISC_R_NOMORE) 412 return (result); 413 return (ISC_R_SUCCESS); 414} 415 416/* 417 * For each rdataset of 'name' in 'ver' of 'db', call 'action' 418 * with the rdataset and 'action_data' as arguments. If the name 419 * does not exist, do nothing. 420 * 421 * If 'action' returns an error, abort iteration and return the error. 422 */ 423static isc_result_t 424foreach_rrset(dns_db_t *db, 425 dns_dbversion_t *ver, 426 dns_name_t *name, 427 rrset_func *action, 428 void *action_data) 429{ 430 isc_result_t result; 431 dns_dbnode_t *node; 432 dns_rdatasetiter_t *iter; 433 434 node = NULL; 435 result = dns_db_findnode(db, name, ISC_FALSE, &node); 436 if (result == ISC_R_NOTFOUND) 437 return (ISC_R_SUCCESS); 438 if (result != ISC_R_SUCCESS) 439 return (result); 440 441 iter = NULL; 442 result = dns_db_allrdatasets(db, node, ver, 443 (isc_stdtime_t) 0, &iter); 444 if (result != ISC_R_SUCCESS) 445 goto cleanup_node; 446 447 for (result = dns_rdatasetiter_first(iter); 448 result == ISC_R_SUCCESS; 449 result = dns_rdatasetiter_next(iter)) 450 { 451 dns_rdataset_t rdataset; 452 453 dns_rdataset_init(&rdataset); 454 dns_rdatasetiter_current(iter, &rdataset); 455 456 result = (*action)(action_data, &rdataset); 457 458 dns_rdataset_disassociate(&rdataset); 459 if (result != ISC_R_SUCCESS) 460 goto cleanup_iterator; 461 } 462 if (result == ISC_R_NOMORE) 463 result = ISC_R_SUCCESS; 464 465 cleanup_iterator: 466 dns_rdatasetiter_destroy(&iter); 467 468 cleanup_node: 469 dns_db_detachnode(db, &node); 470 471 return (result); 472} 473 474/* 475 * For each RR of 'name' in 'ver' of 'db', call 'action' 476 * with the RR and 'action_data' as arguments. If the name 477 * does not exist, do nothing. 478 * 479 * If 'action' returns an error, abort iteration 480 * and return the error. 481 */ 482static isc_result_t 483foreach_node_rr(dns_db_t *db, 484 dns_dbversion_t *ver, 485 dns_name_t *name, 486 rr_func *rr_action, 487 void *rr_action_data) 488{ 489 foreach_node_rr_ctx_t ctx; 490 ctx.rr_action = rr_action; 491 ctx.rr_action_data = rr_action_data; 492 return (foreach_rrset(db, ver, name, 493 foreach_node_rr_action, &ctx)); 494} 495 496 497/* 498 * For each of the RRs specified by 'db', 'ver', 'name', 'type', 499 * (which can be dns_rdatatype_any to match any type), and 'covers', call 500 * 'action' with the RR and 'action_data' as arguments. If the name 501 * does not exist, or if no RRset of the given type exists at the name, 502 * do nothing. 503 * 504 * If 'action' returns an error, abort iteration and return the error. 505 */ 506static isc_result_t 507foreach_rr(dns_db_t *db, 508 dns_dbversion_t *ver, 509 dns_name_t *name, 510 dns_rdatatype_t type, 511 dns_rdatatype_t covers, 512 rr_func *rr_action, 513 void *rr_action_data) 514{ 515 516 isc_result_t result; 517 dns_dbnode_t *node; 518 dns_rdataset_t rdataset; 519 520 if (type == dns_rdatatype_any) 521 return (foreach_node_rr(db, ver, name, 522 rr_action, rr_action_data)); 523 524 node = NULL; 525 result = dns_db_findnode(db, name, ISC_FALSE, &node); 526 if (result == ISC_R_NOTFOUND) 527 return (ISC_R_SUCCESS); 528 if (result != ISC_R_SUCCESS) 529 return (result); 530 531 dns_rdataset_init(&rdataset); 532 result = dns_db_findrdataset(db, node, ver, type, covers, 533 (isc_stdtime_t) 0, &rdataset, NULL); 534 if (result == ISC_R_NOTFOUND) { 535 result = ISC_R_SUCCESS; 536 goto cleanup_node; 537 } 538 if (result != ISC_R_SUCCESS) 539 goto cleanup_node; 540 541 for (result = dns_rdataset_first(&rdataset); 542 result == ISC_R_SUCCESS; 543 result = dns_rdataset_next(&rdataset)) 544 { 545 rr_t rr = { 0, DNS_RDATA_INIT }; 546 dns_rdataset_current(&rdataset, &rr.rdata); 547 rr.ttl = rdataset.ttl; 548 result = (*rr_action)(rr_action_data, &rr); 549 if (result != ISC_R_SUCCESS) 550 goto cleanup_rdataset; 551 } 552 if (result != ISC_R_NOMORE) 553 goto cleanup_rdataset; 554 result = ISC_R_SUCCESS; 555 556 cleanup_rdataset: 557 dns_rdataset_disassociate(&rdataset); 558 cleanup_node: 559 dns_db_detachnode(db, &node); 560 561 return (result); 562} 563 564/**************************************************************************/ 565/* 566 * Various tests on the database contents (for prerequisites, etc). 567 */ 568 569/* 570 * Function type for predicate functions that compare a database RR 'db_rr' 571 * against an update RR 'update_rr'. 572 */ 573typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr); 574 575/* 576 * Helper function for rrset_exists(). 577 */ 578static isc_result_t 579rrset_exists_action(void *data, rr_t *rr) { 580 UNUSED(data); 581 UNUSED(rr); 582 return (ISC_R_EXISTS); 583} 584 585/* 586 * Utility macro for RR existence checking functions. 587 * 588 * If the variable 'result' has the value ISC_R_EXISTS or 589 * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE, 590 * respectively, and return success. 591 * 592 * If 'result' has any other value, there was a failure. 593 * Return the failure result code and do not set *exists. 594 * 595 * This would be more readable as "do { if ... } while(0)", 596 * but that form generates tons of warnings on Solaris 2.6. 597 */ 598#define RETURN_EXISTENCE_FLAG \ 599 return ((result == ISC_R_EXISTS) ? \ 600 (*exists = ISC_TRUE, ISC_R_SUCCESS) : \ 601 ((result == ISC_R_SUCCESS) ? \ 602 (*exists = ISC_FALSE, ISC_R_SUCCESS) : \ 603 result)) 604 605/* 606 * Set '*exists' to true iff an rrset of the given type exists, 607 * to false otherwise. 608 */ 609static isc_result_t 610rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 611 dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, 612 isc_boolean_t *exists) 613{ 614 isc_result_t result; 615 result = foreach_rr(db, ver, name, type, covers, 616 rrset_exists_action, NULL); 617 RETURN_EXISTENCE_FLAG; 618} 619 620/* 621 * Helper function for cname_incompatible_rrset_exists. 622 */ 623static isc_result_t 624cname_compatibility_action(void *data, dns_rdataset_t *rrset) { 625 UNUSED(data); 626 if (rrset->type != dns_rdatatype_cname && 627 ! dns_rdatatype_isdnssec(rrset->type)) 628 return (ISC_R_EXISTS); 629 return (ISC_R_SUCCESS); 630} 631 632/* 633 * Check whether there is an rrset incompatible with adding a CNAME RR, 634 * i.e., anything but another CNAME (which can be replaced) or a 635 * DNSSEC RR (which can coexist). 636 * 637 * If such an incompatible rrset exists, set '*exists' to ISC_TRUE. 638 * Otherwise, set it to ISC_FALSE. 639 */ 640static isc_result_t 641cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 642 dns_name_t *name, isc_boolean_t *exists) { 643 isc_result_t result; 644 result = foreach_rrset(db, ver, name, 645 cname_compatibility_action, NULL); 646 RETURN_EXISTENCE_FLAG; 647} 648 649/* 650 * Helper function for rr_count(). 651 */ 652static isc_result_t 653count_rr_action(void *data, rr_t *rr) { 654 int *countp = data; 655 UNUSED(rr); 656 (*countp)++; 657 return (ISC_R_SUCCESS); 658} 659 660/* 661 * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'. 662 */ 663static isc_result_t 664rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 665 dns_rdatatype_t type, dns_rdatatype_t covers, int *countp) 666{ 667 *countp = 0; 668 return (foreach_rr(db, ver, name, type, covers, 669 count_rr_action, countp)); 670} 671 672/* 673 * Context struct and helper function for name_exists(). 674 */ 675 676static isc_result_t 677name_exists_action(void *data, dns_rdataset_t *rrset) { 678 UNUSED(data); 679 UNUSED(rrset); 680 return (ISC_R_EXISTS); 681} 682 683/* 684 * Set '*exists' to true iff the given name exists, to false otherwise. 685 */ 686static isc_result_t 687name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 688 isc_boolean_t *exists) 689{ 690 isc_result_t result; 691 result = foreach_rrset(db, ver, name, 692 name_exists_action, NULL); 693 RETURN_EXISTENCE_FLAG; 694} 695 696typedef struct { 697 dns_name_t *name, *signer; 698 dns_ssutable_t *table; 699} ssu_check_t; 700 701static isc_result_t 702ssu_checkrule(void *data, dns_rdataset_t *rrset) { 703 ssu_check_t *ssuinfo = data; 704 isc_boolean_t result; 705 706 /* 707 * If we're deleting all records, it's ok to delete RRSIG and NSEC even 708 * if we're normally not allowed to. 709 */ 710 if (rrset->type == dns_rdatatype_rrsig || 711 rrset->type == dns_rdatatype_nsec) 712 return (ISC_R_SUCCESS); 713 result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer, 714 ssuinfo->name, rrset->type); 715 return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE); 716} 717 718static isc_boolean_t 719ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 720 dns_ssutable_t *ssutable, dns_name_t *signer) 721{ 722 isc_result_t result; 723 ssu_check_t ssuinfo; 724 725 ssuinfo.name = name; 726 ssuinfo.table = ssutable; 727 ssuinfo.signer = signer; 728 result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); 729 return (ISC_TF(result == ISC_R_SUCCESS)); 730} 731 732/**************************************************************************/ 733/* 734 * Checking of "RRset exists (value dependent)" prerequisites. 735 * 736 * In the RFC2136 section 3.2.5, this is the pseudocode involving 737 * a variable called "temp", a mapping of <name, type> tuples to rrsets. 738 * 739 * Here, we represent the "temp" data structure as (non-minimial) "dns_diff_t" 740 * where each typle has op==DNS_DIFFOP_EXISTS. 741 */ 742 743 744/* 745 * Append a tuple asserting the existence of the RR with 746 * 'name' and 'rdata' to 'diff'. 747 */ 748static isc_result_t 749temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) { 750 isc_result_t result; 751 dns_difftuple_t *tuple = NULL; 752 753 REQUIRE(DNS_DIFF_VALID(diff)); 754 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, 755 name, 0, rdata, &tuple)); 756 ISC_LIST_APPEND(diff->tuples, tuple, link); 757 failure: 758 return (result); 759} 760 761/* 762 * Compare two rdatasets represented as sorted lists of tuples. 763 * All list elements must have the same owner name and type. 764 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset) 765 * if not. 766 */ 767static isc_result_t 768temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { 769 for (;;) { 770 if (a == NULL || b == NULL) 771 break; 772 INSIST(a->op == DNS_DIFFOP_EXISTS && 773 b->op == DNS_DIFFOP_EXISTS); 774 INSIST(a->rdata.type == b->rdata.type); 775 INSIST(dns_name_equal(&a->name, &b->name)); 776 if (dns_rdata_compare(&a->rdata, &b->rdata) != 0) 777 return (DNS_R_NXRRSET); 778 a = ISC_LIST_NEXT(a, link); 779 b = ISC_LIST_NEXT(b, link); 780 } 781 if (a != NULL || b != NULL) 782 return (DNS_R_NXRRSET); 783 return (ISC_R_SUCCESS); 784} 785 786/* 787 * A comparison function defining the sorting order for the entries 788 * in the "temp" data structure. The major sort key is the owner name, 789 * followed by the type and rdata. 790 */ 791static int 792temp_order(const void *av, const void *bv) { 793 dns_difftuple_t const * const *ap = av; 794 dns_difftuple_t const * const *bp = bv; 795 dns_difftuple_t const *a = *ap; 796 dns_difftuple_t const *b = *bp; 797 int r; 798 r = dns_name_compare(&a->name, &b->name); 799 if (r != 0) 800 return (r); 801 r = (b->rdata.type - a->rdata.type); 802 if (r != 0) 803 return (r); 804 r = dns_rdata_compare(&a->rdata, &b->rdata); 805 return (r); 806} 807 808/* 809 * Check the "RRset exists (value dependent)" prerequisite information 810 * in 'temp' against the contents of the database 'db'. 811 * 812 * Return ISC_R_SUCCESS if the prerequisites are satisfied, 813 * rcode(dns_rcode_nxrrset) if not. 814 * 815 * 'temp' must be pre-sorted. 816 */ 817 818static isc_result_t 819temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, 820 dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep) 821{ 822 isc_result_t result; 823 dns_name_t *name; 824 dns_dbnode_t *node; 825 dns_difftuple_t *t; 826 dns_diff_t trash; 827 828 dns_diff_init(mctx, &trash); 829 830 /* 831 * For each name and type in the prerequisites, 832 * construct a sorted rdata list of the corresponding 833 * database contents, and compare the lists. 834 */ 835 t = ISC_LIST_HEAD(temp->tuples); 836 while (t != NULL) { 837 name = &t->name; 838 (void)dns_name_copy(name, tmpname, NULL); 839 *typep = t->rdata.type; 840 841 /* A new unique name begins here. */ 842 node = NULL; 843 result = dns_db_findnode(db, name, ISC_FALSE, &node); 844 if (result == ISC_R_NOTFOUND) 845 return (DNS_R_NXRRSET); 846 if (result != ISC_R_SUCCESS) 847 return (result); 848 849 /* A new unique type begins here. */ 850 while (t != NULL && dns_name_equal(&t->name, name)) { 851 dns_rdatatype_t type, covers; 852 dns_rdataset_t rdataset; 853 dns_diff_t d_rrs; /* Database RRs with 854 this name and type */ 855 dns_diff_t u_rrs; /* Update RRs with 856 this name and type */ 857 858 *typep = type = t->rdata.type; 859 if (type == dns_rdatatype_rrsig || 860 type == dns_rdatatype_sig) 861 covers = dns_rdata_covers(&t->rdata); 862 else 863 covers = 0; 864 865 /* 866 * Collect all database RRs for this name and type 867 * onto d_rrs and sort them. 868 */ 869 dns_rdataset_init(&rdataset); 870 result = dns_db_findrdataset(db, node, ver, type, 871 covers, (isc_stdtime_t) 0, 872 &rdataset, NULL); 873 if (result != ISC_R_SUCCESS) { 874 dns_db_detachnode(db, &node); 875 return (DNS_R_NXRRSET); 876 } 877 878 dns_diff_init(mctx, &d_rrs); 879 dns_diff_init(mctx, &u_rrs); 880 881 for (result = dns_rdataset_first(&rdataset); 882 result == ISC_R_SUCCESS; 883 result = dns_rdataset_next(&rdataset)) 884 { 885 dns_rdata_t rdata = DNS_RDATA_INIT; 886 dns_rdataset_current(&rdataset, &rdata); 887 result = temp_append(&d_rrs, name, &rdata); 888 if (result != ISC_R_SUCCESS) 889 goto failure; 890 } 891 if (result != ISC_R_NOMORE) 892 goto failure; 893 result = dns_diff_sort(&d_rrs, temp_order); 894 if (result != ISC_R_SUCCESS) 895 goto failure; 896 897 /* 898 * Collect all update RRs for this name and type 899 * onto u_rrs. No need to sort them here - 900 * they are already sorted. 901 */ 902 while (t != NULL && 903 dns_name_equal(&t->name, name) && 904 t->rdata.type == type) 905 { 906 dns_difftuple_t *next = 907 ISC_LIST_NEXT(t, link); 908 ISC_LIST_UNLINK(temp->tuples, t, link); 909 ISC_LIST_APPEND(u_rrs.tuples, t, link); 910 t = next; 911 } 912 913 /* Compare the two sorted lists. */ 914 result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples), 915 ISC_LIST_HEAD(d_rrs.tuples)); 916 if (result != ISC_R_SUCCESS) 917 goto failure; 918 919 /* 920 * We are done with the tuples, but we can't free 921 * them yet because "name" still points into one 922 * of them. Move them on a temporary list. 923 */ 924 ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link); 925 ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link); 926 dns_rdataset_disassociate(&rdataset); 927 928 continue; 929 930 failure: 931 dns_diff_clear(&d_rrs); 932 dns_diff_clear(&u_rrs); 933 dns_diff_clear(&trash); 934 dns_rdataset_disassociate(&rdataset); 935 dns_db_detachnode(db, &node); 936 return (result); 937 } 938 939 dns_db_detachnode(db, &node); 940 } 941 942 dns_diff_clear(&trash); 943 return (ISC_R_SUCCESS); 944} 945 946/**************************************************************************/ 947/* 948 * Conditional deletion of RRs. 949 */ 950 951/* 952 * Context structure for delete_if(). 953 */ 954 955typedef struct { 956 rr_predicate *predicate; 957 dns_db_t *db; 958 dns_dbversion_t *ver; 959 dns_diff_t *diff; 960 dns_name_t *name; 961 dns_rdata_t *update_rr; 962} conditional_delete_ctx_t; 963 964/* 965 * Predicate functions for delete_if(). 966 */ 967 968/* 969 * Return true iff 'db_rr' is neither a SOA nor an NS RR nor 970 * an RRSIG nor a NSEC. 971 */ 972static isc_boolean_t 973type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 974 UNUSED(update_rr); 975 return ((db_rr->type != dns_rdatatype_soa && 976 db_rr->type != dns_rdatatype_ns && 977 db_rr->type != dns_rdatatype_rrsig && 978 db_rr->type != dns_rdatatype_nsec) ? 979 ISC_TRUE : ISC_FALSE); 980} 981 982/* 983 * Return true iff 'db_rr' is neither a RRSIG nor a NSEC. 984 */ 985static isc_boolean_t 986type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 987 UNUSED(update_rr); 988 return ((db_rr->type != dns_rdatatype_rrsig && 989 db_rr->type != dns_rdatatype_nsec) ? 990 ISC_TRUE : ISC_FALSE); 991} 992 993/* 994 * Return true always. 995 */ 996static isc_boolean_t 997true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 998 UNUSED(update_rr); 999 UNUSED(db_rr); 1000 return (ISC_TRUE); 1001} 1002 1003/* 1004 * Return true iff the two RRs have identical rdata. 1005 */ 1006static isc_boolean_t 1007rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1008 /* 1009 * XXXRTH This is not a problem, but we should consider creating 1010 * dns_rdata_equal() (that used dns_name_equal()), since it 1011 * would be faster. Not a priority. 1012 */ 1013 return (dns_rdata_compare(update_rr, db_rr) == 0 ? 1014 ISC_TRUE : ISC_FALSE); 1015} 1016 1017/* 1018 * Return true iff 'update_rr' should replace 'db_rr' according 1019 * to the special RFC2136 rules for CNAME, SOA, and WKS records. 1020 * 1021 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs 1022 * make little sense, so we replace those, too. 1023 */ 1024static isc_boolean_t 1025replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1026 if (db_rr->type != update_rr->type) 1027 return (ISC_FALSE); 1028 if (db_rr->type == dns_rdatatype_cname) 1029 return (ISC_TRUE); 1030 if (db_rr->type == dns_rdatatype_dname) 1031 return (ISC_TRUE); 1032 if (db_rr->type == dns_rdatatype_soa) 1033 return (ISC_TRUE); 1034 if (db_rr->type == dns_rdatatype_nsec) 1035 return (ISC_TRUE); 1036 if (db_rr->type == dns_rdatatype_wks) { 1037 /* 1038 * Compare the address and protocol fields only. These 1039 * form the first five bytes of the RR data. Do a 1040 * raw binary comparison; unpacking the WKS RRs using 1041 * dns_rdata_tostruct() might be cleaner in some ways, 1042 * but it would require us to pass around an mctx. 1043 */ 1044 INSIST(db_rr->length >= 5 && update_rr->length >= 5); 1045 return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? 1046 ISC_TRUE : ISC_FALSE); 1047 } 1048 return (ISC_FALSE); 1049} 1050 1051/* 1052 * Internal helper function for delete_if(). 1053 */ 1054static isc_result_t 1055delete_if_action(void *data, rr_t *rr) { 1056 conditional_delete_ctx_t *ctx = data; 1057 if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) { 1058 isc_result_t result; 1059 result = update_one_rr(ctx->db, ctx->ver, ctx->diff, 1060 DNS_DIFFOP_DEL, ctx->name, 1061 rr->ttl, &rr->rdata); 1062 return (result); 1063 } else { 1064 return (ISC_R_SUCCESS); 1065 } 1066} 1067 1068/* 1069 * Conditionally delete RRs. Apply 'predicate' to the RRs 1070 * specified by 'db', 'ver', 'name', and 'type' (which can 1071 * be dns_rdatatype_any to match any type). Delete those 1072 * RRs for which the predicate returns true, and log the 1073 * deletions in 'diff'. 1074 */ 1075static isc_result_t 1076delete_if(rr_predicate *predicate, 1077 dns_db_t *db, 1078 dns_dbversion_t *ver, 1079 dns_name_t *name, 1080 dns_rdatatype_t type, 1081 dns_rdatatype_t covers, 1082 dns_rdata_t *update_rr, 1083 dns_diff_t *diff) 1084{ 1085 conditional_delete_ctx_t ctx; 1086 ctx.predicate = predicate; 1087 ctx.db = db; 1088 ctx.ver = ver; 1089 ctx.diff = diff; 1090 ctx.name = name; 1091 ctx.update_rr = update_rr; 1092 return (foreach_rr(db, ver, name, type, covers, 1093 delete_if_action, &ctx)); 1094} 1095 1096/**************************************************************************/ 1097/* 1098 * Prepare an RR for the addition of the new RR 'ctx->update_rr', 1099 * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting 1100 * the RRs if it is replaced by the new RR or has a conflicting TTL. 1101 * The necessary changes are appended to ctx->del_diff and ctx->add_diff; 1102 * we need to do all deletions before any additions so that we don't run 1103 * into transient states with conflicting TTLs. 1104 */ 1105 1106typedef struct { 1107 dns_db_t *db; 1108 dns_dbversion_t *ver; 1109 dns_diff_t *diff; 1110 dns_name_t *name; 1111 dns_rdata_t *update_rr; 1112 dns_ttl_t update_rr_ttl; 1113 isc_boolean_t ignore_add; 1114 dns_diff_t del_diff; 1115 dns_diff_t add_diff; 1116} add_rr_prepare_ctx_t; 1117 1118static isc_result_t 1119add_rr_prepare_action(void *data, rr_t *rr) { 1120 isc_result_t result = ISC_R_SUCCESS; 1121 add_rr_prepare_ctx_t *ctx = data; 1122 dns_difftuple_t *tuple = NULL; 1123 isc_boolean_t equal; 1124 1125 /* 1126 * If the update RR is a "duplicate" of the update RR, 1127 * the update should be silently ignored. 1128 */ 1129 equal = ISC_TF(dns_rdata_compare(&rr->rdata, ctx->update_rr) == 0); 1130 if (equal && rr->ttl == ctx->update_rr_ttl) { 1131 ctx->ignore_add = ISC_TRUE; 1132 return (ISC_R_SUCCESS); 1133 } 1134 1135 /* 1136 * If this RR is "equal" to the update RR, it should 1137 * be deleted before the update RR is added. 1138 */ 1139 if (replaces_p(ctx->update_rr, &rr->rdata)) { 1140 CHECK(dns_difftuple_create(ctx->del_diff.mctx, 1141 DNS_DIFFOP_DEL, ctx->name, 1142 rr->ttl, 1143 &rr->rdata, 1144 &tuple)); 1145 dns_diff_append(&ctx->del_diff, &tuple); 1146 return (ISC_R_SUCCESS); 1147 } 1148 1149 /* 1150 * If this RR differs in TTL from the update RR, 1151 * its TTL must be adjusted. 1152 */ 1153 if (rr->ttl != ctx->update_rr_ttl) { 1154 CHECK(dns_difftuple_create(ctx->del_diff.mctx, 1155 DNS_DIFFOP_DEL, ctx->name, 1156 rr->ttl, 1157 &rr->rdata, 1158 &tuple)); 1159 dns_diff_append(&ctx->del_diff, &tuple); 1160 if (!equal) { 1161 CHECK(dns_difftuple_create(ctx->add_diff.mctx, 1162 DNS_DIFFOP_ADD, ctx->name, 1163 ctx->update_rr_ttl, 1164 &rr->rdata, 1165 &tuple)); 1166 dns_diff_append(&ctx->add_diff, &tuple); 1167 } 1168 } 1169 failure: 1170 return (result); 1171} 1172 1173/**************************************************************************/ 1174/* 1175 * Miscellaneous subroutines. 1176 */ 1177 1178/* 1179 * Extract a single update RR from 'section' of dynamic update message 1180 * 'msg', with consistency checking. 1181 * 1182 * Stores the owner name, rdata, and TTL of the update RR at 'name', 1183 * 'rdata', and 'ttl', respectively. 1184 */ 1185static void 1186get_current_rr(dns_message_t *msg, dns_section_t section, 1187 dns_rdataclass_t zoneclass, 1188 dns_name_t **name, dns_rdata_t *rdata, dns_rdatatype_t *covers, 1189 dns_ttl_t *ttl, 1190 dns_rdataclass_t *update_class) 1191{ 1192 dns_rdataset_t *rdataset; 1193 isc_result_t result; 1194 dns_message_currentname(msg, section, name); 1195 rdataset = ISC_LIST_HEAD((*name)->list); 1196 INSIST(rdataset != NULL); 1197 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); 1198 *covers = rdataset->covers; 1199 *ttl = rdataset->ttl; 1200 result = dns_rdataset_first(rdataset); 1201 INSIST(result == ISC_R_SUCCESS); 1202 dns_rdataset_current(rdataset, rdata); 1203 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); 1204 *update_class = rdata->rdclass; 1205 rdata->rdclass = zoneclass; 1206} 1207 1208/* 1209 * Increment the SOA serial number of database 'db', version 'ver'. 1210 * Replace the SOA record in the database, and log the 1211 * change in 'diff'. 1212 */ 1213 1214 /* 1215 * XXXRTH Failures in this routine will be worth logging, when 1216 * we have a logging system. Failure to find the zonename 1217 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR(). 1218 */ 1219 1220static isc_result_t 1221increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver, 1222 dns_diff_t *diff, isc_mem_t *mctx) 1223{ 1224 dns_difftuple_t *deltuple = NULL; 1225 dns_difftuple_t *addtuple = NULL; 1226 isc_uint32_t serial; 1227 isc_result_t result; 1228 1229 CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); 1230 CHECK(dns_difftuple_copy(deltuple, &addtuple)); 1231 addtuple->op = DNS_DIFFOP_ADD; 1232 1233 serial = dns_soa_getserial(&addtuple->rdata); 1234 1235 /* RFC1982 */ 1236 serial = (serial + 1) & 0xFFFFFFFF; 1237 if (serial == 0) 1238 serial = 1; 1239 1240 dns_soa_setserial(serial, &addtuple->rdata); 1241 CHECK(do_one_tuple(&deltuple, db, ver, diff)); 1242 CHECK(do_one_tuple(&addtuple, db, ver, diff)); 1243 result = ISC_R_SUCCESS; 1244 1245 failure: 1246 if (addtuple != NULL) 1247 dns_difftuple_free(&addtuple); 1248 if (deltuple != NULL) 1249 dns_difftuple_free(&deltuple); 1250 return (result); 1251} 1252 1253/* 1254 * Check that the new SOA record at 'update_rdata' does not 1255 * illegally cause the SOA serial number to decrease or stay 1256 * unchanged relative to the existing SOA in 'db'. 1257 * 1258 * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not. 1259 * 1260 * William King points out that RFC2136 is inconsistent about 1261 * the case where the serial number stays unchanged: 1262 * 1263 * section 3.4.2.2 requires a server to ignore a SOA update request 1264 * if the serial number on the update SOA is less_than_or_equal to 1265 * the zone SOA serial. 1266 * 1267 * section 3.6 requires a server to ignore a SOA update request if 1268 * the serial is less_than the zone SOA serial. 1269 * 1270 * Paul says 3.4.2.2 is correct. 1271 * 1272 */ 1273static isc_result_t 1274check_soa_increment(dns_db_t *db, dns_dbversion_t *ver, 1275 dns_rdata_t *update_rdata, 1276 isc_boolean_t *ok) 1277{ 1278 isc_uint32_t db_serial; 1279 isc_uint32_t update_serial; 1280 isc_result_t result; 1281 1282 update_serial = dns_soa_getserial(update_rdata); 1283 1284 result = dns_db_getsoaserial(db, ver, &db_serial); 1285 if (result != ISC_R_SUCCESS) 1286 return (result); 1287 1288 if (DNS_SERIAL_GE(db_serial, update_serial)) { 1289 *ok = ISC_FALSE; 1290 } else { 1291 *ok = ISC_TRUE; 1292 } 1293 1294 return (ISC_R_SUCCESS); 1295 1296} 1297 1298/**************************************************************************/ 1299/* 1300 * Incremental updating of NSECs and RRSIGs. 1301 */ 1302 1303#define MAXZONEKEYS 32 /* Maximum number of zone keys supported. */ 1304 1305/* 1306 * We abuse the dns_diff_t type to represent a set of domain names 1307 * affected by the update. 1308 */ 1309static isc_result_t 1310namelist_append_name(dns_diff_t *list, dns_name_t *name) { 1311 isc_result_t result; 1312 dns_difftuple_t *tuple = NULL; 1313 static dns_rdata_t dummy_rdata = { NULL, 0, 0, 0, 0, 1314 { (void*)(-1), (void*)(-1) } }; 1315 CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0, 1316 &dummy_rdata, &tuple)); 1317 dns_diff_append(list, &tuple); 1318 failure: 1319 return (result); 1320} 1321 1322static isc_result_t 1323namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected) 1324{ 1325 isc_result_t result; 1326 dns_fixedname_t fixedname; 1327 dns_name_t *child; 1328 dns_dbiterator_t *dbit = NULL; 1329 1330 dns_fixedname_init(&fixedname); 1331 child = dns_fixedname_name(&fixedname); 1332 1333 CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); 1334 1335 for (result = dns_dbiterator_seek(dbit, name); 1336 result == ISC_R_SUCCESS; 1337 result = dns_dbiterator_next(dbit)) 1338 { 1339 dns_dbnode_t *node = NULL; 1340 CHECK(dns_dbiterator_current(dbit, &node, child)); 1341 dns_db_detachnode(db, &node); 1342 if (! dns_name_issubdomain(child, name)) 1343 break; 1344 CHECK(namelist_append_name(affected, child)); 1345 } 1346 if (result == ISC_R_NOMORE) 1347 result = ISC_R_SUCCESS; 1348 failure: 1349 if (dbit != NULL) 1350 dns_dbiterator_destroy(&dbit); 1351 return (result); 1352} 1353 1354 1355 1356/* 1357 * Helper function for non_nsec_rrset_exists(). 1358 */ 1359static isc_result_t 1360is_non_nsec_action(void *data, dns_rdataset_t *rrset) { 1361 UNUSED(data); 1362 if (!(rrset->type == dns_rdatatype_nsec || 1363 (rrset->type == dns_rdatatype_rrsig && 1364 rrset->covers == dns_rdatatype_nsec))) 1365 return (ISC_R_EXISTS); 1366 return (ISC_R_SUCCESS); 1367} 1368 1369/* 1370 * Check whether there is an rrset other than a NSEC or RRSIG NSEC, 1371 * i.e., anything that justifies the continued existence of a name 1372 * after a secure update. 1373 * 1374 * If such an rrset exists, set '*exists' to ISC_TRUE. 1375 * Otherwise, set it to ISC_FALSE. 1376 */ 1377static isc_result_t 1378non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 1379 dns_name_t *name, isc_boolean_t *exists) 1380{ 1381 isc_result_t result; 1382 result = foreach_rrset(db, ver, name, 1383 is_non_nsec_action, NULL); 1384 RETURN_EXISTENCE_FLAG; 1385} 1386 1387/* 1388 * A comparison function for sorting dns_diff_t:s by name. 1389 */ 1390static int 1391name_order(const void *av, const void *bv) { 1392 dns_difftuple_t const * const *ap = av; 1393 dns_difftuple_t const * const *bp = bv; 1394 dns_difftuple_t const *a = *ap; 1395 dns_difftuple_t const *b = *bp; 1396 return (dns_name_compare(&a->name, &b->name)); 1397} 1398 1399static isc_result_t 1400uniqify_name_list(dns_diff_t *list) { 1401 isc_result_t result; 1402 dns_difftuple_t *p, *q; 1403 1404 CHECK(dns_diff_sort(list, name_order)); 1405 1406 p = ISC_LIST_HEAD(list->tuples); 1407 while (p != NULL) { 1408 do { 1409 q = ISC_LIST_NEXT(p, link); 1410 if (q == NULL || ! dns_name_equal(&p->name, &q->name)) 1411 break; 1412 ISC_LIST_UNLINK(list->tuples, q, link); 1413 dns_difftuple_free(&q); 1414 } while (1); 1415 p = ISC_LIST_NEXT(p, link); 1416 } 1417 failure: 1418 return (result); 1419} 1420 1421 1422static isc_result_t 1423is_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1424 isc_boolean_t *flag) 1425{ 1426 isc_result_t result; 1427 dns_fixedname_t foundname; 1428 dns_fixedname_init(&foundname); 1429 result = dns_db_find(db, name, ver, dns_rdatatype_any, 1430 DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD, 1431 (isc_stdtime_t) 0, NULL, 1432 dns_fixedname_name(&foundname), 1433 NULL, NULL); 1434 if (result == ISC_R_SUCCESS) { 1435 *flag = ISC_FALSE; 1436 return (ISC_R_SUCCESS); 1437 } else if (result == DNS_R_ZONECUT) { 1438 /* 1439 * We are at the zonecut. The name will have an NSEC, but 1440 * non-delegation will be omitted from the type bit map. 1441 */ 1442 *flag = ISC_FALSE; 1443 return (ISC_R_SUCCESS); 1444 } else if (result == DNS_R_GLUE || result == DNS_R_DNAME) { 1445 *flag = ISC_TRUE; 1446 return (ISC_R_SUCCESS); 1447 } else { 1448 return (result); 1449 } 1450} 1451 1452/* 1453 * Find the next/previous name that has a NSEC record. 1454 * In other words, skip empty database nodes and names that 1455 * have had their NSECs removed because they are obscured by 1456 * a zone cut. 1457 */ 1458static isc_result_t 1459next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1460 dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname, 1461 isc_boolean_t forward) 1462{ 1463 isc_result_t result; 1464 dns_dbiterator_t *dbit = NULL; 1465 isc_boolean_t has_nsec; 1466 unsigned int wraps = 0; 1467 1468 CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); 1469 1470 CHECK(dns_dbiterator_seek(dbit, oldname)); 1471 do { 1472 dns_dbnode_t *node = NULL; 1473 1474 if (forward) 1475 result = dns_dbiterator_next(dbit); 1476 else 1477 result = dns_dbiterator_prev(dbit); 1478 if (result == ISC_R_NOMORE) { 1479 /* 1480 * Wrap around. 1481 */ 1482 if (forward) 1483 CHECK(dns_dbiterator_first(dbit)); 1484 else 1485 CHECK(dns_dbiterator_last(dbit)); 1486 wraps++; 1487 if (wraps == 2) { 1488 update_log(client, zone, ISC_LOG_ERROR, 1489 "secure zone with no NSECs"); 1490 result = DNS_R_BADZONE; 1491 goto failure; 1492 } 1493 } 1494 CHECK(dns_dbiterator_current(dbit, &node, newname)); 1495 dns_db_detachnode(db, &node); 1496 1497 /* 1498 * The iterator may hold the tree lock, and 1499 * rrset_exists() calls dns_db_findnode() which 1500 * may try to reacquire it. To avoid deadlock 1501 * we must pause the iterator first. 1502 */ 1503 CHECK(dns_dbiterator_pause(dbit)); 1504 CHECK(rrset_exists(db, ver, newname, 1505 dns_rdatatype_nsec, 0, &has_nsec)); 1506 1507 } while (! has_nsec); 1508 failure: 1509 if (dbit != NULL) 1510 dns_dbiterator_destroy(&dbit); 1511 1512 return (result); 1513} 1514 1515/* 1516 * Add a NSEC record for "name", recording the change in "diff". 1517 * The existing NSEC is removed. 1518 */ 1519static isc_result_t 1520add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1521 dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl, 1522 dns_diff_t *diff) 1523{ 1524 isc_result_t result; 1525 dns_dbnode_t *node = NULL; 1526 unsigned char buffer[DNS_NSEC_BUFFERSIZE]; 1527 dns_rdata_t rdata = DNS_RDATA_INIT; 1528 dns_difftuple_t *tuple = NULL; 1529 dns_fixedname_t fixedname; 1530 dns_name_t *target; 1531 1532 dns_fixedname_init(&fixedname); 1533 target = dns_fixedname_name(&fixedname); 1534 1535 /* 1536 * Find the successor name, aka NSEC target. 1537 */ 1538 CHECK(next_active(client, zone, db, ver, name, target, ISC_TRUE)); 1539 1540 /* 1541 * Create the NSEC RDATA. 1542 */ 1543 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); 1544 dns_rdata_init(&rdata); 1545 CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata)); 1546 dns_db_detachnode(db, &node); 1547 1548 /* 1549 * Delete the old NSEC and record the change. 1550 */ 1551 CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0, 1552 NULL, diff)); 1553 /* 1554 * Add the new NSEC and record the change. 1555 */ 1556 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 1557 nsecttl, &rdata, &tuple)); 1558 CHECK(do_one_tuple(&tuple, db, ver, diff)); 1559 INSIST(tuple == NULL); 1560 1561 failure: 1562 if (node != NULL) 1563 dns_db_detachnode(db, &node); 1564 return (result); 1565} 1566 1567/* 1568 * Add a placeholder NSEC record for "name", recording the change in "diff". 1569 */ 1570static isc_result_t 1571add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1572 dns_diff_t *diff) { 1573 isc_result_t result; 1574 dns_difftuple_t *tuple = NULL; 1575 isc_region_t r; 1576 unsigned char data[1] = { 0 }; /* The root domain, no bits. */ 1577 dns_rdata_t rdata = DNS_RDATA_INIT; 1578 1579 r.base = data; 1580 r.length = sizeof(data); 1581 dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r); 1582 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0, 1583 &rdata, &tuple)); 1584 CHECK(do_one_tuple(&tuple, db, ver, diff)); 1585 failure: 1586 return (result); 1587} 1588 1589static isc_result_t 1590find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, 1591 isc_mem_t *mctx, unsigned int maxkeys, 1592 dst_key_t **keys, unsigned int *nkeys) 1593{ 1594 isc_result_t result; 1595 dns_dbnode_t *node = NULL; 1596 const char *directory = dns_zone_getkeydirectory(zone); 1597 CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); 1598 CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), 1599 directory, mctx, maxkeys, keys, nkeys)); 1600 failure: 1601 if (node != NULL) 1602 dns_db_detachnode(db, &node); 1603 return (result); 1604} 1605 1606/* 1607 * Add RRSIG records for an RRset, recording the change in "diff". 1608 */ 1609static isc_result_t 1610add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1611 dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, 1612 unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, 1613 isc_stdtime_t expire) 1614{ 1615 isc_result_t result; 1616 dns_dbnode_t *node = NULL; 1617 dns_rdataset_t rdataset; 1618 dns_rdata_t sig_rdata = DNS_RDATA_INIT; 1619 isc_buffer_t buffer; 1620 unsigned char data[1024]; /* XXX */ 1621 unsigned int i; 1622 1623 dns_rdataset_init(&rdataset); 1624 isc_buffer_init(&buffer, data, sizeof(data)); 1625 1626 /* Get the rdataset to sign. */ 1627 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); 1628 CHECK(dns_db_findrdataset(db, node, ver, type, 0, 1629 (isc_stdtime_t) 0, 1630 &rdataset, NULL)); 1631 dns_db_detachnode(db, &node); 1632 1633 for (i = 0; i < nkeys; i++) { 1634 /* Calculate the signature, creating a RRSIG RDATA. */ 1635 CHECK(dns_dnssec_sign(name, &rdataset, keys[i], 1636 &inception, &expire, 1637 mctx, &buffer, &sig_rdata)); 1638 1639 /* Update the database and journal with the RRSIG. */ 1640 /* XXX inefficient - will cause dataset merging */ 1641 CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, 1642 rdataset.ttl, &sig_rdata)); 1643 dns_rdata_reset(&sig_rdata); 1644 } 1645 1646 failure: 1647 if (dns_rdataset_isassociated(&rdataset)) 1648 dns_rdataset_disassociate(&rdataset); 1649 if (node != NULL) 1650 dns_db_detachnode(db, &node); 1651 return (result); 1652} 1653 1654/* 1655 * Update RRSIG and NSEC records affected by an update. The original 1656 * update, including the SOA serial update but exluding the RRSIG & NSEC 1657 * changes, is in "diff" and has already been applied to "newver" of "db". 1658 * The database version prior to the update is "oldver". 1659 * 1660 * The necessary RRSIG and NSEC changes will be applied to "newver" 1661 * and added (as a minimal diff) to "diff". 1662 * 1663 * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds. 1664 */ 1665static isc_result_t 1666update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1667 dns_dbversion_t *oldver, dns_dbversion_t *newver, 1668 dns_diff_t *diff, isc_uint32_t sigvalidityinterval) 1669{ 1670 isc_result_t result; 1671 dns_difftuple_t *t; 1672 dns_diff_t diffnames; 1673 dns_diff_t affected; 1674 dns_diff_t sig_diff; 1675 dns_diff_t nsec_diff; 1676 dns_diff_t nsec_mindiff; 1677 isc_boolean_t flag; 1678 dst_key_t *zone_keys[MAXZONEKEYS]; 1679 unsigned int nkeys = 0; 1680 unsigned int i; 1681 isc_stdtime_t now, inception, expire; 1682 dns_ttl_t nsecttl; 1683 dns_rdata_soa_t soa; 1684 dns_rdata_t rdata = DNS_RDATA_INIT; 1685 dns_rdataset_t rdataset; 1686 dns_dbnode_t *node = NULL; 1687 1688 dns_diff_init(client->mctx, &diffnames); 1689 dns_diff_init(client->mctx, &affected); 1690 1691 dns_diff_init(client->mctx, &sig_diff); 1692 dns_diff_init(client->mctx, &nsec_diff); 1693 dns_diff_init(client->mctx, &nsec_mindiff); 1694 1695 result = find_zone_keys(zone, db, newver, client->mctx, 1696 MAXZONEKEYS, zone_keys, &nkeys); 1697 if (result != ISC_R_SUCCESS) { 1698 update_log(client, zone, ISC_LOG_ERROR, 1699 "could not get zone keys for secure dynamic update"); 1700 goto failure; 1701 } 1702 1703 isc_stdtime_get(&now); 1704 inception = now - 3600; /* Allow for some clock skew. */ 1705 expire = now + sigvalidityinterval; 1706 1707 /* 1708 * Get the NSEC's TTL from the SOA MINIMUM field. 1709 */ 1710 CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); 1711 dns_rdataset_init(&rdataset); 1712 CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0, 1713 (isc_stdtime_t) 0, &rdataset, NULL)); 1714 CHECK(dns_rdataset_first(&rdataset)); 1715 dns_rdataset_current(&rdataset, &rdata); 1716 CHECK(dns_rdata_tostruct(&rdata, &soa, NULL)); 1717 nsecttl = soa.minimum; 1718 dns_rdataset_disassociate(&rdataset); 1719 dns_db_detachnode(db, &node); 1720 1721 /* 1722 * Find all RRsets directly affected by the update, and 1723 * update their RRSIGs. Also build a list of names affected 1724 * by the update in "diffnames". 1725 */ 1726 CHECK(dns_diff_sort(diff, temp_order)); 1727 1728 t = ISC_LIST_HEAD(diff->tuples); 1729 while (t != NULL) { 1730 dns_name_t *name = &t->name; 1731 /* Now "name" is a new, unique name affected by the update. */ 1732 1733 CHECK(namelist_append_name(&diffnames, name)); 1734 1735 while (t != NULL && dns_name_equal(&t->name, name)) { 1736 dns_rdatatype_t type; 1737 type = t->rdata.type; 1738 1739 /* 1740 * Now "name" and "type" denote a new unique RRset 1741 * affected by the update. 1742 */ 1743 1744 /* Don't sign RRSIGs. */ 1745 if (type == dns_rdatatype_rrsig) 1746 goto skip; 1747 1748 /* 1749 * Delete all old RRSIGs covering this type, since they 1750 * are all invalid when the signed RRset has changed. 1751 * We may not be able to recreate all of them - tough. 1752 */ 1753 CHECK(delete_if(true_p, db, newver, name, 1754 dns_rdatatype_rrsig, type, 1755 NULL, &sig_diff)); 1756 1757 /* 1758 * If this RRset still exists after the update, 1759 * add a new signature for it. 1760 */ 1761 CHECK(rrset_exists(db, newver, name, type, 0, &flag)); 1762 if (flag) { 1763 CHECK(add_sigs(db, newver, name, type, 1764 &sig_diff, zone_keys, nkeys, 1765 client->mctx, inception, 1766 expire)); 1767 } 1768 skip: 1769 /* Skip any other updates to the same RRset. */ 1770 while (t != NULL && 1771 dns_name_equal(&t->name, name) && 1772 t->rdata.type == type) 1773 { 1774 t = ISC_LIST_NEXT(t, link); 1775 } 1776 } 1777 } 1778 1779 /* Remove orphaned NSECs and RRSIG NSECs. */ 1780 for (t = ISC_LIST_HEAD(diffnames.tuples); 1781 t != NULL; 1782 t = ISC_LIST_NEXT(t, link)) 1783 { 1784 CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag)); 1785 if (! flag) { 1786 CHECK(delete_if(true_p, db, newver, &t->name, 1787 dns_rdatatype_any, 0, 1788 NULL, &sig_diff)); 1789 } 1790 } 1791 1792 /* 1793 * When a name is created or deleted, its predecessor needs to 1794 * have its NSEC updated. 1795 */ 1796 for (t = ISC_LIST_HEAD(diffnames.tuples); 1797 t != NULL; 1798 t = ISC_LIST_NEXT(t, link)) 1799 { 1800 isc_boolean_t existed, exists; 1801 dns_fixedname_t fixedname; 1802 dns_name_t *prevname; 1803 1804 dns_fixedname_init(&fixedname); 1805 prevname = dns_fixedname_name(&fixedname); 1806 1807 CHECK(name_exists(db, oldver, &t->name, &existed)); 1808 CHECK(name_exists(db, newver, &t->name, &exists)); 1809 if (exists == existed) 1810 continue; 1811 1812 /* 1813 * Find the predecessor. 1814 * When names become obscured or unobscured in this update 1815 * transaction, we may find the wrong predecessor because 1816 * the NSECs have not yet been updated to reflect the delegation 1817 * change. This should not matter because in this case, 1818 * the correct predecessor is either the delegation node or 1819 * a newly unobscured node, and those nodes are on the 1820 * "affected" list in any case. 1821 */ 1822 CHECK(next_active(client, zone, db, newver, 1823 &t->name, prevname, ISC_FALSE)); 1824 CHECK(namelist_append_name(&affected, prevname)); 1825 } 1826 1827 /* 1828 * Find names potentially affected by delegation changes 1829 * (obscured by adding an NS or DNAME, or unobscured by 1830 * removing one). 1831 */ 1832 for (t = ISC_LIST_HEAD(diffnames.tuples); 1833 t != NULL; 1834 t = ISC_LIST_NEXT(t, link)) 1835 { 1836 isc_boolean_t ns_existed, dname_existed; 1837 isc_boolean_t ns_exists, dname_exists; 1838 1839 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_ns, 0, 1840 &ns_existed)); 1841 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_dname, 0, 1842 &dname_existed)); 1843 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, 1844 &ns_exists)); 1845 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0, 1846 &dname_exists)); 1847 if ((ns_exists || dname_exists) == (ns_existed || dname_existed)) 1848 continue; 1849 /* 1850 * There was a delegation change. Mark all subdomains 1851 * of t->name as potentially needing a NSEC update. 1852 */ 1853 CHECK(namelist_append_subdomain(db, &t->name, &affected)); 1854 } 1855 1856 ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link); 1857 INSIST(ISC_LIST_EMPTY(diffnames.tuples)); 1858 1859 CHECK(uniqify_name_list(&affected)); 1860 1861 /* 1862 * Determine which names should have NSECs, and delete/create 1863 * NSECs to make it so. We don't know the final NSEC targets yet, 1864 * so we just create placeholder NSECs with arbitrary contents 1865 * to indicate that their respective owner names should be part of 1866 * the NSEC chain. 1867 */ 1868 for (t = ISC_LIST_HEAD(affected.tuples); 1869 t != NULL; 1870 t = ISC_LIST_NEXT(t, link)) 1871 { 1872 isc_boolean_t exists; 1873 CHECK(name_exists(db, newver, &t->name, &exists)); 1874 if (! exists) 1875 continue; 1876 CHECK(is_glue(db, newver, &t->name, &flag)); 1877 if (flag) { 1878 /* 1879 * This name is obscured. Delete any 1880 * existing NSEC record. 1881 */ 1882 CHECK(delete_if(true_p, db, newver, &t->name, 1883 dns_rdatatype_nsec, 0, 1884 NULL, &nsec_diff)); 1885 } else { 1886 /* 1887 * This name is not obscured. It should have a NSEC. 1888 */ 1889 CHECK(rrset_exists(db, newver, &t->name, 1890 dns_rdatatype_nsec, 0, &flag)); 1891 if (! flag) 1892 CHECK(add_placeholder_nsec(db, newver, &t->name, 1893 diff)); 1894 } 1895 } 1896 1897 /* 1898 * Now we know which names are part of the NSEC chain. 1899 * Make them all point at their correct targets. 1900 */ 1901 for (t = ISC_LIST_HEAD(affected.tuples); 1902 t != NULL; 1903 t = ISC_LIST_NEXT(t, link)) 1904 { 1905 CHECK(rrset_exists(db, newver, &t->name, 1906 dns_rdatatype_nsec, 0, &flag)); 1907 if (flag) { 1908 /* 1909 * There is a NSEC, but we don't know if it is correct. 1910 * Delete it and create a correct one to be sure. 1911 * If the update was unnecessary, the diff minimization 1912 * will take care of eliminating it from the journal, 1913 * IXFRs, etc. 1914 * 1915 * The RRSIG bit should always be set in the NSECs 1916 * we generate, because they will all get RRSIG NSECs. 1917 * (XXX what if the zone keys are missing?). 1918 * Because the RRSIG NSECs have not necessarily been 1919 * created yet, the correctness of the bit mask relies 1920 * on the assumption that NSECs are only created if 1921 * there is other data, and if there is other data, 1922 * there are other RRSIGs. 1923 */ 1924 CHECK(add_nsec(client, zone, db, newver, &t->name, 1925 nsecttl, &nsec_diff)); 1926 } 1927 } 1928 1929 /* 1930 * Minimize the set of NSEC updates so that we don't 1931 * have to regenerate the RRSIG NSECs for NSECs that were 1932 * replaced with identical ones. 1933 */ 1934 while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) { 1935 ISC_LIST_UNLINK(nsec_diff.tuples, t, link); 1936 dns_diff_appendminimal(&nsec_mindiff, &t); 1937 } 1938 1939 /* Update RRSIG NSECs. */ 1940 for (t = ISC_LIST_HEAD(nsec_mindiff.tuples); 1941 t != NULL; 1942 t = ISC_LIST_NEXT(t, link)) 1943 { 1944 if (t->op == DNS_DIFFOP_DEL) { 1945 CHECK(delete_if(true_p, db, newver, &t->name, 1946 dns_rdatatype_rrsig, dns_rdatatype_nsec, 1947 NULL, &sig_diff)); 1948 } else if (t->op == DNS_DIFFOP_ADD) { 1949 CHECK(add_sigs(db, newver, &t->name, dns_rdatatype_nsec, 1950 &sig_diff, zone_keys, nkeys, 1951 client->mctx, inception, expire)); 1952 } else { 1953 INSIST(0); 1954 } 1955 } 1956 1957 /* Record our changes for the journal. */ 1958 while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) { 1959 ISC_LIST_UNLINK(sig_diff.tuples, t, link); 1960 dns_diff_appendminimal(diff, &t); 1961 } 1962 while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) { 1963 ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link); 1964 dns_diff_appendminimal(diff, &t); 1965 } 1966 1967 INSIST(ISC_LIST_EMPTY(sig_diff.tuples)); 1968 INSIST(ISC_LIST_EMPTY(nsec_diff.tuples)); 1969 INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples)); 1970 1971 failure: 1972 dns_diff_clear(&sig_diff); 1973 dns_diff_clear(&nsec_diff); 1974 dns_diff_clear(&nsec_mindiff); 1975 1976 dns_diff_clear(&affected); 1977 dns_diff_clear(&diffnames); 1978 1979 for (i = 0; i < nkeys; i++) 1980 dst_key_free(&zone_keys[i]); 1981 1982 return (result); 1983} 1984 1985 1986/**************************************************************************/ 1987/* 1988 * The actual update code in all its glory. We try to follow 1989 * the RFC2136 pseudocode as closely as possible. 1990 */ 1991 1992static isc_result_t 1993send_update_event(ns_client_t *client, dns_zone_t *zone) { 1994 isc_result_t result = ISC_R_SUCCESS; 1995 update_event_t *event = NULL; 1996 isc_task_t *zonetask = NULL; 1997 ns_client_t *evclient; 1998 1999 event = (update_event_t *) 2000 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, 2001 update_action, NULL, sizeof(*event)); 2002 if (event == NULL) 2003 FAIL(ISC_R_NOMEMORY); 2004 event->zone = zone; 2005 event->result = ISC_R_SUCCESS; 2006 2007 evclient = NULL; 2008 ns_client_attach(client, &evclient); 2009 INSIST(client->nupdates == 0); 2010 client->nupdates++; 2011 event->ev_arg = evclient; 2012 2013 dns_zone_gettask(zone, &zonetask); 2014 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 2015 2016 failure: 2017 if (event != NULL) 2018 isc_event_free(ISC_EVENT_PTR(&event)); 2019 return (result); 2020} 2021 2022static void 2023respond(ns_client_t *client, isc_result_t result) { 2024 isc_result_t msg_result; 2025 2026 msg_result = dns_message_reply(client->message, ISC_TRUE); 2027 if (msg_result != ISC_R_SUCCESS) 2028 goto msg_failure; 2029 client->message->rcode = dns_result_torcode(result); 2030 2031 ns_client_send(client); 2032 return; 2033 2034 msg_failure: 2035 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 2036 ISC_LOG_ERROR, 2037 "could not create update response message: %s", 2038 isc_result_totext(msg_result)); 2039 ns_client_next(client, msg_result); 2040} 2041 2042void 2043ns_update_start(ns_client_t *client, isc_result_t sigresult) { 2044 dns_message_t *request = client->message; 2045 isc_result_t result; 2046 dns_name_t *zonename; 2047 dns_rdataset_t *zone_rdataset; 2048 dns_zone_t *zone = NULL; 2049 2050 /* 2051 * Interpret the zone section. 2052 */ 2053 result = dns_message_firstname(request, DNS_SECTION_ZONE); 2054 if (result != ISC_R_SUCCESS) 2055 FAILC(DNS_R_FORMERR, 2056 "update zone section empty"); 2057 2058 /* 2059 * The zone section must contain exactly one "question", and 2060 * it must be of type SOA. 2061 */ 2062 zonename = NULL; 2063 dns_message_currentname(request, DNS_SECTION_ZONE, &zonename); 2064 zone_rdataset = ISC_LIST_HEAD(zonename->list); 2065 if (zone_rdataset->type != dns_rdatatype_soa) 2066 FAILC(DNS_R_FORMERR, 2067 "update zone section contains non-SOA"); 2068 if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) 2069 FAILC(DNS_R_FORMERR, 2070 "update zone section contains multiple RRs"); 2071 2072 /* The zone section must have exactly one name. */ 2073 result = dns_message_nextname(request, DNS_SECTION_ZONE); 2074 if (result != ISC_R_NOMORE) 2075 FAILC(DNS_R_FORMERR, 2076 "update zone section contains multiple RRs"); 2077 2078 result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, 2079 &zone); 2080 if (result != ISC_R_SUCCESS) 2081 FAILC(DNS_R_NOTAUTH, 2082 "not authoritative for update zone"); 2083 2084 switch(dns_zone_gettype(zone)) { 2085 case dns_zone_master: 2086 /* 2087 * We can now fail due to a bad signature as we now know 2088 * that we are the master. 2089 */ 2090 if (sigresult != ISC_R_SUCCESS) 2091 FAIL(sigresult); 2092 CHECK(send_update_event(client, zone)); 2093 break; 2094 case dns_zone_slave: 2095 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone), 2096 "update forwarding", zonename, ISC_TRUE)); 2097 CHECK(send_forward_event(client, zone)); 2098 break; 2099 default: 2100 FAILC(DNS_R_NOTAUTH, 2101 "not authoritative for update zone"); 2102 } 2103 return; 2104 2105 failure: 2106 /* 2107 * We failed without having sent an update event to the zone. 2108 * We are still in the client task context, so we can 2109 * simply give an error response without switching tasks. 2110 */ 2111 respond(client, result); 2112 if (zone != NULL) 2113 dns_zone_detach(&zone); 2114} 2115 2116/* 2117 * DS records are not allowed to exist without corresponding NS records, 2118 * draft-ietf-dnsext-delegation-signer-11.txt, 2.2 Protocol Change, 2119 * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex". 2120 */ 2121 2122static isc_result_t 2123remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) { 2124 isc_result_t result; 2125 isc_boolean_t ns_exists, ds_exists; 2126 dns_difftuple_t *t; 2127 2128 for (t = ISC_LIST_HEAD(diff->tuples); 2129 t != NULL; 2130 t = ISC_LIST_NEXT(t, link)) { 2131 if (t->op != DNS_DIFFOP_DEL || 2132 t->rdata.type != dns_rdatatype_ns) 2133 continue; 2134 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, 2135 &ns_exists)); 2136 if (ns_exists) 2137 continue; 2138 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ds, 0, 2139 &ds_exists)); 2140 if (!ds_exists) 2141 continue; 2142 CHECK(delete_if(true_p, db, newver, &t->name, 2143 dns_rdatatype_ds, 0, NULL, diff)); 2144 } 2145 return (ISC_R_SUCCESS); 2146 2147 failure: 2148 return (result); 2149} 2150 2151static void 2152update_action(isc_task_t *task, isc_event_t *event) { 2153 update_event_t *uev = (update_event_t *) event; 2154 dns_zone_t *zone = uev->zone; 2155 ns_client_t *client = (ns_client_t *)event->ev_arg; 2156 2157 isc_result_t result; 2158 dns_db_t *db = NULL; 2159 dns_dbversion_t *oldver = NULL; 2160 dns_dbversion_t *ver = NULL; 2161 dns_diff_t diff; /* Pending updates. */ 2162 dns_diff_t temp; /* Pending RR existence assertions. */ 2163 isc_boolean_t soa_serial_changed = ISC_FALSE; 2164 isc_mem_t *mctx = client->mctx; 2165 dns_rdatatype_t covers; 2166 dns_message_t *request = client->message; 2167 dns_rdataclass_t zoneclass; 2168 dns_name_t *zonename; 2169 dns_ssutable_t *ssutable = NULL; 2170 dns_fixedname_t tmpnamefixed; 2171 dns_name_t *tmpname = NULL; 2172 2173 INSIST(event->ev_type == DNS_EVENT_UPDATE); 2174 2175 dns_diff_init(mctx, &diff); 2176 dns_diff_init(mctx, &temp); 2177 2178 CHECK(dns_zone_getdb(zone, &db)); 2179 zonename = dns_db_origin(db); 2180 zoneclass = dns_db_class(db); 2181 dns_zone_getssutable(zone, &ssutable); 2182 dns_db_currentversion(db, &oldver); 2183 CHECK(dns_db_newversion(db, &ver)); 2184 2185 /* 2186 * Check prerequisites. 2187 */ 2188 2189 for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE); 2190 result == ISC_R_SUCCESS; 2191 result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE)) 2192 { 2193 dns_name_t *name = NULL; 2194 dns_rdata_t rdata = DNS_RDATA_INIT; 2195 dns_ttl_t ttl; 2196 dns_rdataclass_t update_class; 2197 isc_boolean_t flag; 2198 2199 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass, 2200 &name, &rdata, &covers, &ttl, &update_class); 2201 2202 if (ttl != 0) 2203 FAILC(DNS_R_FORMERR, "prerequisite TTL is not zero"); 2204 2205 if (! dns_name_issubdomain(name, zonename)) 2206 FAILN(DNS_R_NOTZONE, name, 2207 "prerequisite name is out of zone"); 2208 2209 if (update_class == dns_rdataclass_any) { 2210 if (rdata.length != 0) 2211 FAILC(DNS_R_FORMERR, 2212 "class ANY prerequisite " 2213 "RDATA is not empty"); 2214 if (rdata.type == dns_rdatatype_any) { 2215 CHECK(name_exists(db, ver, name, &flag)); 2216 if (! flag) { 2217 FAILN(DNS_R_NXDOMAIN, name, 2218 "'name in use' prerequisite " 2219 "not satisfied"); 2220 } 2221 } else { 2222 CHECK(rrset_exists(db, ver, name, 2223 rdata.type, covers, &flag)); 2224 if (! flag) { 2225 /* RRset does not exist. */ 2226 FAILNT(DNS_R_NXRRSET, name, rdata.type, 2227 "'rrset exists (value independent)' " 2228 "prerequisite not satisfied"); 2229 } 2230 } 2231 } else if (update_class == dns_rdataclass_none) { 2232 if (rdata.length != 0) 2233 FAILC(DNS_R_FORMERR, 2234 "class NONE prerequisite " 2235 "RDATA is not empty"); 2236 if (rdata.type == dns_rdatatype_any) { 2237 CHECK(name_exists(db, ver, name, &flag)); 2238 if (flag) { 2239 FAILN(DNS_R_YXDOMAIN, name, 2240 "'name not in use' prerequisite " 2241 "not satisfied"); 2242 } 2243 } else { 2244 CHECK(rrset_exists(db, ver, name, 2245 rdata.type, covers, &flag)); 2246 if (flag) { 2247 /* RRset exists. */ 2248 FAILNT(DNS_R_YXRRSET, name, rdata.type, 2249 "'rrset does not exist' " 2250 "prerequisite not satisfied"); 2251 } 2252 } 2253 } else if (update_class == zoneclass) { 2254 /* "temp<rr.name, rr.type> += rr;" */ 2255 result = temp_append(&temp, name, &rdata); 2256 if (result != ISC_R_SUCCESS) { 2257 UNEXPECTED_ERROR(__FILE__, __LINE__, 2258 "temp entry creation failed: %s", 2259 dns_result_totext(result)); 2260 FAIL(ISC_R_UNEXPECTED); 2261 } 2262 } else { 2263 FAILC(DNS_R_FORMERR, "malformed prerequisite"); 2264 } 2265 } 2266 if (result != ISC_R_NOMORE) 2267 FAIL(result); 2268 2269 2270 /* 2271 * Perform the final check of the "rrset exists (value dependent)" 2272 * prerequisites. 2273 */ 2274 if (ISC_LIST_HEAD(temp.tuples) != NULL) { 2275 dns_rdatatype_t type; 2276 2277 /* 2278 * Sort the prerequisite records by owner name, 2279 * type, and rdata. 2280 */ 2281 result = dns_diff_sort(&temp, temp_order); 2282 if (result != ISC_R_SUCCESS) 2283 FAILC(result, "'RRset exists (value dependent)' " 2284 "prerequisite not satisfied"); 2285 2286 dns_fixedname_init(&tmpnamefixed); 2287 tmpname = dns_fixedname_name(&tmpnamefixed); 2288 result = temp_check(mctx, &temp, db, ver, tmpname, &type); 2289 if (result != ISC_R_SUCCESS) 2290 FAILNT(result, tmpname, type, 2291 "'RRset exists (value dependent)' " 2292 "prerequisite not satisfied"); 2293 } 2294 2295 update_log(client, zone, LOGLEVEL_DEBUG, 2296 "prerequisites are OK"); 2297 2298 /* 2299 * Check Requestor's Permissions. It seems a bit silly to do this 2300 * only after prerequisite testing, but that is what RFC2136 says. 2301 */ 2302 result = ISC_R_SUCCESS; 2303 if (ssutable == NULL) 2304 CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), 2305 "update", zonename, ISC_FALSE)); 2306 else if (client->signer == NULL) 2307 CHECK(checkupdateacl(client, NULL, "update", zonename, 2308 ISC_FALSE)); 2309 2310 if (dns_zone_getupdatedisabled(zone)) 2311 FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled"); 2312 2313 /* 2314 * Perform the Update Section Prescan. 2315 */ 2316 2317 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2318 result == ISC_R_SUCCESS; 2319 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2320 { 2321 dns_name_t *name = NULL; 2322 dns_rdata_t rdata = DNS_RDATA_INIT; 2323 dns_ttl_t ttl; 2324 dns_rdataclass_t update_class; 2325 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, 2326 &name, &rdata, &covers, &ttl, &update_class); 2327 2328 if (! dns_name_issubdomain(name, zonename)) 2329 FAILC(DNS_R_NOTZONE, 2330 "update RR is outside zone"); 2331 if (update_class == zoneclass) { 2332 /* 2333 * Check for meta-RRs. The RFC2136 pseudocode says 2334 * check for ANY|AXFR|MAILA|MAILB, but the text adds 2335 * "or any other QUERY metatype" 2336 */ 2337 if (dns_rdatatype_ismeta(rdata.type)) { 2338 FAILC(DNS_R_FORMERR, 2339 "meta-RR in update"); 2340 } 2341 result = dns_zone_checknames(zone, name, &rdata); 2342 if (result != ISC_R_SUCCESS) 2343 FAIL(DNS_R_REFUSED); 2344 } else if (update_class == dns_rdataclass_any) { 2345 if (ttl != 0 || rdata.length != 0 || 2346 (dns_rdatatype_ismeta(rdata.type) && 2347 rdata.type != dns_rdatatype_any)) 2348 FAILC(DNS_R_FORMERR, 2349 "meta-RR in update"); 2350 } else if (update_class == dns_rdataclass_none) { 2351 if (ttl != 0 || 2352 dns_rdatatype_ismeta(rdata.type)) 2353 FAILC(DNS_R_FORMERR, 2354 "meta-RR in update"); 2355 } else { 2356 update_log(client, zone, ISC_LOG_WARNING, 2357 "update RR has incorrect class %d", 2358 update_class); 2359 FAIL(DNS_R_FORMERR); 2360 } 2361 /* 2362 * draft-ietf-dnsind-simple-secure-update-01 says 2363 * "Unlike traditional dynamic update, the client 2364 * is forbidden from updating NSEC records." 2365 */ 2366 if (dns_db_issecure(db)) { 2367 if (rdata.type == dns_rdatatype_nsec) { 2368 FAILC(DNS_R_REFUSED, 2369 "explicit NSEC updates are not allowed " 2370 "in secure zones"); 2371 } 2372 else if (rdata.type == dns_rdatatype_rrsig) { 2373 FAILC(DNS_R_REFUSED, 2374 "explicit RRSIG updates are currently not " 2375 "supported in secure zones"); 2376 } 2377 } 2378 2379 if (ssutable != NULL && client->signer != NULL) { 2380 if (rdata.type != dns_rdatatype_any) { 2381 if (!dns_ssutable_checkrules(ssutable, 2382 client->signer, 2383 name, rdata.type)) 2384 FAILC(DNS_R_REFUSED, 2385 "rejected by secure update"); 2386 } 2387 else { 2388 if (!ssu_checkall(db, ver, name, ssutable, 2389 client->signer)) 2390 FAILC(DNS_R_REFUSED, 2391 "rejected by secure update"); 2392 } 2393 } 2394 } 2395 if (result != ISC_R_NOMORE) 2396 FAIL(result); 2397 2398 update_log(client, zone, LOGLEVEL_DEBUG, 2399 "update section prescan OK"); 2400 2401 /* 2402 * Process the Update Section. 2403 */ 2404 2405 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2406 result == ISC_R_SUCCESS; 2407 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2408 { 2409 dns_name_t *name = NULL; 2410 dns_rdata_t rdata = DNS_RDATA_INIT; 2411 dns_ttl_t ttl; 2412 dns_rdataclass_t update_class; 2413 isc_boolean_t flag; 2414 2415 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, 2416 &name, &rdata, &covers, &ttl, &update_class); 2417 2418 if (update_class == zoneclass) { 2419 2420 /* 2421 * RFC 1123 doesn't allow MF and MD in master zones. */ 2422 if (rdata.type == dns_rdatatype_md || 2423 rdata.type == dns_rdatatype_mf) { 2424 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2425 2426 dns_rdatatype_format(rdata.type, typebuf, 2427 sizeof(typebuf)); 2428 update_log(client, zone, LOGLEVEL_PROTOCOL, 2429 "attempt to add %s ignored", 2430 typebuf); 2431 continue; 2432 } 2433 if (rdata.type == dns_rdatatype_ns && 2434 dns_name_iswildcard(name)) { 2435 update_log(client, zone, 2436 LOGLEVEL_PROTOCOL, 2437 "attempt to add wildcard NS record" 2438 "ignored"); 2439 continue; 2440 } 2441 if (rdata.type == dns_rdatatype_cname) { 2442 CHECK(cname_incompatible_rrset_exists(db, ver, 2443 name, 2444 &flag)); 2445 if (flag) { 2446 update_log(client, zone, 2447 LOGLEVEL_PROTOCOL, 2448 "attempt to add CNAME " 2449 "alongside non-CNAME " 2450 "ignored"); 2451 continue; 2452 } 2453 } else { 2454 CHECK(rrset_exists(db, ver, name, 2455 dns_rdatatype_cname, 0, 2456 &flag)); 2457 if (flag && 2458 ! dns_rdatatype_isdnssec(rdata.type)) 2459 { 2460 update_log(client, zone, 2461 LOGLEVEL_PROTOCOL, 2462 "attempt to add non-CNAME " 2463 "alongside CNAME ignored"); 2464 continue; 2465 } 2466 } 2467 if (rdata.type == dns_rdatatype_soa) { 2468 isc_boolean_t ok; 2469 CHECK(rrset_exists(db, ver, name, 2470 dns_rdatatype_soa, 0, 2471 &flag)); 2472 if (! flag) { 2473 update_log(client, zone, 2474 LOGLEVEL_PROTOCOL, 2475 "attempt to create 2nd " 2476 "SOA ignored"); 2477 continue; 2478 } 2479 CHECK(check_soa_increment(db, ver, &rdata, 2480 &ok)); 2481 if (! ok) { 2482 update_log(client, zone, 2483 LOGLEVEL_PROTOCOL, 2484 "SOA update failed to " 2485 "increment serial, " 2486 "ignoring it"); 2487 continue; 2488 } 2489 soa_serial_changed = ISC_TRUE; 2490 } 2491 2492 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { 2493 char namestr[DNS_NAME_FORMATSIZE]; 2494 char typestr[DNS_RDATATYPE_FORMATSIZE]; 2495 dns_name_format(name, namestr, 2496 sizeof(namestr)); 2497 dns_rdatatype_format(rdata.type, typestr, 2498 sizeof(typestr)); 2499 update_log(client, zone, 2500 LOGLEVEL_PROTOCOL, 2501 "adding an RR at '%s' %s", 2502 namestr, typestr); 2503 } 2504 2505 /* Prepare the affected RRset for the addition. */ 2506 { 2507 add_rr_prepare_ctx_t ctx; 2508 ctx.db = db; 2509 ctx.ver = ver; 2510 ctx.diff = &diff; 2511 ctx.name = name; 2512 ctx.update_rr = &rdata; 2513 ctx.update_rr_ttl = ttl; 2514 ctx.ignore_add = ISC_FALSE; 2515 dns_diff_init(mctx, &ctx.del_diff); 2516 dns_diff_init(mctx, &ctx.add_diff); 2517 CHECK(foreach_rr(db, ver, name, rdata.type, 2518 covers, add_rr_prepare_action, 2519 &ctx)); 2520 2521 if (ctx.ignore_add) { 2522 dns_diff_clear(&ctx.del_diff); 2523 dns_diff_clear(&ctx.add_diff); 2524 } else { 2525 CHECK(do_diff(&ctx.del_diff, db, ver, &diff)); 2526 CHECK(do_diff(&ctx.add_diff, db, ver, &diff)); 2527 CHECK(update_one_rr(db, ver, &diff, 2528 DNS_DIFFOP_ADD, 2529 name, ttl, &rdata)); 2530 } 2531 } 2532 } else if (update_class == dns_rdataclass_any) { 2533 if (rdata.type == dns_rdatatype_any) { 2534 if (isc_log_wouldlog(ns_g_lctx, 2535 LOGLEVEL_PROTOCOL)) 2536 { 2537 char namestr[DNS_NAME_FORMATSIZE]; 2538 dns_name_format(name, namestr, 2539 sizeof(namestr)); 2540 update_log(client, zone, 2541 LOGLEVEL_PROTOCOL, 2542 "delete all rrsets from " 2543 "name '%s'", namestr); 2544 } 2545 if (dns_name_equal(name, zonename)) { 2546 CHECK(delete_if(type_not_soa_nor_ns_p, 2547 db, ver, name, 2548 dns_rdatatype_any, 0, 2549 &rdata, &diff)); 2550 } else { 2551 CHECK(delete_if(type_not_dnssec, 2552 db, ver, name, 2553 dns_rdatatype_any, 0, 2554 &rdata, &diff)); 2555 } 2556 } else if (dns_name_equal(name, zonename) && 2557 (rdata.type == dns_rdatatype_soa || 2558 rdata.type == dns_rdatatype_ns)) { 2559 update_log(client, zone, 2560 LOGLEVEL_PROTOCOL, 2561 "attempt to delete all SOA " 2562 "or NS records ignored"); 2563 continue; 2564 } else { 2565 if (isc_log_wouldlog(ns_g_lctx, 2566 LOGLEVEL_PROTOCOL)) 2567 { 2568 char namestr[DNS_NAME_FORMATSIZE]; 2569 char typestr[DNS_RDATATYPE_FORMATSIZE]; 2570 dns_name_format(name, namestr, 2571 sizeof(namestr)); 2572 dns_rdatatype_format(rdata.type, 2573 typestr, 2574 sizeof(typestr)); 2575 update_log(client, zone, 2576 LOGLEVEL_PROTOCOL, 2577 "deleting rrset at '%s' %s", 2578 namestr, typestr); 2579 } 2580 CHECK(delete_if(true_p, db, ver, name, 2581 rdata.type, covers, &rdata, 2582 &diff)); 2583 } 2584 } else if (update_class == dns_rdataclass_none) { 2585 /* 2586 * The (name == zonename) condition appears in 2587 * RFC2136 3.4.2.4 but is missing from the pseudocode. 2588 */ 2589 if (dns_name_equal(name, zonename)) { 2590 if (rdata.type == dns_rdatatype_soa) { 2591 update_log(client, zone, 2592 LOGLEVEL_PROTOCOL, 2593 "attempt to delete SOA " 2594 "ignored"); 2595 continue; 2596 } 2597 if (rdata.type == dns_rdatatype_ns) { 2598 int count; 2599 CHECK(rr_count(db, ver, name, 2600 dns_rdatatype_ns, 2601 0, &count)); 2602 if (count == 1) { 2603 update_log(client, zone, 2604 LOGLEVEL_PROTOCOL, 2605 "attempt to " 2606 "delete last " 2607 "NS ignored"); 2608 continue; 2609 } 2610 } 2611 } 2612 update_log(client, zone, 2613 LOGLEVEL_PROTOCOL, 2614 "deleting an RR"); 2615 CHECK(delete_if(rr_equal_p, db, ver, name, 2616 rdata.type, covers, &rdata, &diff)); 2617 } 2618 } 2619 if (result != ISC_R_NOMORE) 2620 FAIL(result); 2621 2622 /* 2623 * If any changes were made, increment the SOA serial number, 2624 * update RRSIGs and NSECs (if zone is secure), and write the update 2625 * to the journal. 2626 */ 2627 if (! ISC_LIST_EMPTY(diff.tuples)) { 2628 char *journalfile; 2629 dns_journal_t *journal; 2630 2631 /* 2632 * Increment the SOA serial, but only if it was not 2633 * changed as a result of an update operation. 2634 */ 2635 if (! soa_serial_changed) { 2636 CHECK(increment_soa_serial(db, ver, &diff, mctx)); 2637 } 2638 2639 CHECK(remove_orphaned_ds(db, ver, &diff)); 2640 2641 if (dns_db_issecure(db)) { 2642 result = update_signatures(client, zone, db, oldver, 2643 ver, &diff, 2644 dns_zone_getsigvalidityinterval(zone)); 2645 if (result != ISC_R_SUCCESS) { 2646 update_log(client, zone, 2647 ISC_LOG_ERROR, 2648 "RRSIG/NSEC update failed: %s", 2649 isc_result_totext(result)); 2650 goto failure; 2651 } 2652 } 2653 2654 journalfile = dns_zone_getjournal(zone); 2655 if (journalfile != NULL) { 2656 update_log(client, zone, LOGLEVEL_DEBUG, 2657 "writing journal %s", journalfile); 2658 2659 journal = NULL; 2660 result = dns_journal_open(mctx, journalfile, 2661 ISC_TRUE, &journal); 2662 if (result != ISC_R_SUCCESS) 2663 FAILS(result, "journal open failed"); 2664 2665 result = dns_journal_write_transaction(journal, &diff); 2666 if (result != ISC_R_SUCCESS) { 2667 dns_journal_destroy(&journal); 2668 FAILS(result, "journal write failed"); 2669 } 2670 2671 dns_journal_destroy(&journal); 2672 } 2673 2674 /* 2675 * XXXRTH Just a note that this committing code will have 2676 * to change to handle databases that need two-phase 2677 * commit, but this isn't a priority. 2678 */ 2679 update_log(client, zone, LOGLEVEL_DEBUG, 2680 "committing update transaction"); 2681 dns_db_closeversion(db, &ver, ISC_TRUE); 2682 2683 /* 2684 * Mark the zone as dirty so that it will be written to disk. 2685 */ 2686 dns_zone_markdirty(zone); 2687 2688 /* 2689 * Notify slaves of the change we just made. 2690 */ 2691 dns_zone_notify(zone); 2692 } else { 2693 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request"); 2694 dns_db_closeversion(db, &ver, ISC_TRUE); 2695 } 2696 result = ISC_R_SUCCESS; 2697 goto common; 2698 2699 failure: 2700 /* 2701 * The reason for failure should have been logged at this point. 2702 */ 2703 if (ver != NULL) { 2704 update_log(client, zone, LOGLEVEL_DEBUG, 2705 "rolling back"); 2706 dns_db_closeversion(db, &ver, ISC_FALSE); 2707 } 2708 2709 common: 2710 dns_diff_clear(&temp); 2711 dns_diff_clear(&diff); 2712 2713 if (oldver != NULL) 2714 dns_db_closeversion(db, &oldver, ISC_FALSE); 2715 2716 if (db != NULL) 2717 dns_db_detach(&db); 2718 2719 if (ssutable != NULL) 2720 dns_ssutable_detach(&ssutable); 2721 2722 if (zone != NULL) 2723 dns_zone_detach(&zone); 2724 2725 isc_task_detach(&task); 2726 uev->result = result; 2727 uev->ev_type = DNS_EVENT_UPDATEDONE; 2728 uev->ev_action = updatedone_action; 2729 isc_task_send(client->task, &event); 2730 INSIST(event == NULL); 2731} 2732 2733static void 2734updatedone_action(isc_task_t *task, isc_event_t *event) { 2735 update_event_t *uev = (update_event_t *) event; 2736 ns_client_t *client = (ns_client_t *) event->ev_arg; 2737 2738 UNUSED(task); 2739 2740 INSIST(event->ev_type == DNS_EVENT_UPDATEDONE); 2741 INSIST(task == client->task); 2742 2743 INSIST(client->nupdates > 0); 2744 client->nupdates--; 2745 respond(client, uev->result); 2746 isc_event_free(&event); 2747 ns_client_detach(&client); 2748} 2749 2750/* 2751 * Update forwarding support. 2752 */ 2753 2754static void 2755forward_fail(isc_task_t *task, isc_event_t *event) { 2756 ns_client_t *client = (ns_client_t *)event->ev_arg; 2757 2758 UNUSED(task); 2759 2760 INSIST(client->nupdates > 0); 2761 client->nupdates--; 2762 respond(client, DNS_R_SERVFAIL); 2763 isc_event_free(&event); 2764 ns_client_detach(&client); 2765} 2766 2767 2768static void 2769forward_callback(void *arg, isc_result_t result, dns_message_t *answer) { 2770 update_event_t *uev = arg; 2771 ns_client_t *client = uev->ev_arg; 2772 2773 if (result != ISC_R_SUCCESS) { 2774 INSIST(answer == NULL); 2775 uev->ev_type = DNS_EVENT_UPDATEDONE; 2776 uev->ev_action = forward_fail; 2777 } else { 2778 uev->ev_type = DNS_EVENT_UPDATEDONE; 2779 uev->ev_action = forward_done; 2780 uev->answer = answer; 2781 } 2782 isc_task_send(client->task, ISC_EVENT_PTR(&uev)); 2783} 2784 2785static void 2786forward_done(isc_task_t *task, isc_event_t *event) { 2787 update_event_t *uev = (update_event_t *) event; 2788 ns_client_t *client = (ns_client_t *)event->ev_arg; 2789 2790 UNUSED(task); 2791 2792 INSIST(client->nupdates > 0); 2793 client->nupdates--; 2794 ns_client_sendraw(client, uev->answer); 2795 dns_message_destroy(&uev->answer); 2796 isc_event_free(&event); 2797 ns_client_detach(&client); 2798} 2799 2800static void 2801forward_action(isc_task_t *task, isc_event_t *event) { 2802 update_event_t *uev = (update_event_t *) event; 2803 dns_zone_t *zone = uev->zone; 2804 ns_client_t *client = (ns_client_t *)event->ev_arg; 2805 isc_result_t result; 2806 2807 result = dns_zone_forwardupdate(zone, client->message, 2808 forward_callback, event); 2809 if (result != ISC_R_SUCCESS) { 2810 uev->ev_type = DNS_EVENT_UPDATEDONE; 2811 uev->ev_action = forward_fail; 2812 isc_task_send(client->task, &event); 2813 } 2814 dns_zone_detach(&zone); 2815 isc_task_detach(&task); 2816} 2817 2818static isc_result_t 2819send_forward_event(ns_client_t *client, dns_zone_t *zone) { 2820 isc_result_t result = ISC_R_SUCCESS; 2821 update_event_t *event = NULL; 2822 isc_task_t *zonetask = NULL; 2823 ns_client_t *evclient; 2824 2825 event = (update_event_t *) 2826 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, 2827 forward_action, NULL, sizeof(*event)); 2828 if (event == NULL) 2829 FAIL(ISC_R_NOMEMORY); 2830 event->zone = zone; 2831 event->result = ISC_R_SUCCESS; 2832 2833 evclient = NULL; 2834 ns_client_attach(client, &evclient); 2835 INSIST(client->nupdates == 0); 2836 client->nupdates++; 2837 event->ev_arg = evclient; 2838 2839 dns_zone_gettask(zone, &zonetask); 2840 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 2841 2842 failure: 2843 if (event != NULL) 2844 isc_event_free(ISC_EVENT_PTR(&event)); 2845 return (result); 2846} 2847