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