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