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