1 /* $NetBSD: catz.c,v 1.8 2022/09/23 12:15:29 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 /*! \file */ 17 18 #include <inttypes.h> 19 #include <stdbool.h> 20 21 #include <isc/hex.h> 22 #include <isc/md.h> 23 #include <isc/mem.h> 24 #include <isc/parseint.h> 25 #include <isc/print.h> 26 #include <isc/result.h> 27 #include <isc/task.h> 28 #include <isc/util.h> 29 30 #include <dns/catz.h> 31 #include <dns/dbiterator.h> 32 #include <dns/events.h> 33 #include <dns/rdatasetiter.h> 34 #include <dns/view.h> 35 #include <dns/zone.h> 36 37 #define DNS_CATZ_ZONE_MAGIC ISC_MAGIC('c', 'a', 't', 'z') 38 #define DNS_CATZ_ZONES_MAGIC ISC_MAGIC('c', 'a', 't', 's') 39 #define DNS_CATZ_ENTRY_MAGIC ISC_MAGIC('c', 'a', 't', 'e') 40 41 #define DNS_CATZ_ZONE_VALID(catz) ISC_MAGIC_VALID(catz, DNS_CATZ_ZONE_MAGIC) 42 #define DNS_CATZ_ZONES_VALID(catzs) ISC_MAGIC_VALID(catzs, DNS_CATZ_ZONES_MAGIC) 43 #define DNS_CATZ_ENTRY_VALID(entry) ISC_MAGIC_VALID(entry, DNS_CATZ_ENTRY_MAGIC) 44 45 /*% 46 * Single member zone in a catalog 47 */ 48 struct dns_catz_entry { 49 unsigned int magic; 50 dns_name_t name; 51 dns_catz_options_t opts; 52 isc_refcount_t refs; 53 }; 54 55 /*% 56 * Catalog zone 57 */ 58 struct dns_catz_zone { 59 unsigned int magic; 60 dns_name_t name; 61 dns_catz_zones_t *catzs; 62 dns_rdata_t soa; 63 /* key in entries is 'mhash', not domain name! */ 64 isc_ht_t *entries; 65 /* 66 * defoptions are taken from named.conf 67 * zoneoptions are global options from zone 68 */ 69 dns_catz_options_t defoptions; 70 dns_catz_options_t zoneoptions; 71 isc_time_t lastupdated; 72 bool updatepending; 73 uint32_t version; 74 75 dns_db_t *db; 76 dns_dbversion_t *dbversion; 77 78 isc_timer_t *updatetimer; 79 isc_event_t updateevent; 80 81 bool active; 82 bool db_registered; 83 84 isc_refcount_t refs; 85 }; 86 87 static isc_result_t 88 catz_process_zones_entry(dns_catz_zone_t *zone, dns_rdataset_t *value, 89 dns_label_t *mhash); 90 static isc_result_t 91 catz_process_zones_suboption(dns_catz_zone_t *zone, dns_rdataset_t *value, 92 dns_label_t *mhash, dns_name_t *name); 93 static void 94 catz_entry_add_or_mod(dns_catz_zone_t *target, isc_ht_t *ht, unsigned char *key, 95 size_t keysize, dns_catz_entry_t *nentry, 96 dns_catz_entry_t *oentry, const char *msg, 97 const char *zname, const char *czname); 98 99 /*% 100 * Collection of catalog zones for a view 101 */ 102 struct dns_catz_zones { 103 unsigned int magic; 104 isc_ht_t *zones; 105 isc_mem_t *mctx; 106 isc_refcount_t refs; 107 isc_mutex_t lock; 108 dns_catz_zonemodmethods_t *zmm; 109 isc_taskmgr_t *taskmgr; 110 isc_timermgr_t *timermgr; 111 dns_view_t *view; 112 isc_task_t *updater; 113 }; 114 115 void 116 dns_catz_options_init(dns_catz_options_t *options) { 117 REQUIRE(options != NULL); 118 119 dns_ipkeylist_init(&options->masters); 120 121 options->allow_query = NULL; 122 options->allow_transfer = NULL; 123 124 options->allow_query = NULL; 125 options->allow_transfer = NULL; 126 127 options->in_memory = false; 128 options->min_update_interval = 5; 129 options->zonedir = NULL; 130 } 131 132 void 133 dns_catz_options_free(dns_catz_options_t *options, isc_mem_t *mctx) { 134 REQUIRE(options != NULL); 135 REQUIRE(mctx != NULL); 136 137 if (options->masters.count != 0) { 138 dns_ipkeylist_clear(mctx, &options->masters); 139 } 140 if (options->zonedir != NULL) { 141 isc_mem_free(mctx, options->zonedir); 142 options->zonedir = NULL; 143 } 144 if (options->allow_query != NULL) { 145 isc_buffer_free(&options->allow_query); 146 } 147 if (options->allow_transfer != NULL) { 148 isc_buffer_free(&options->allow_transfer); 149 } 150 } 151 152 isc_result_t 153 dns_catz_options_copy(isc_mem_t *mctx, const dns_catz_options_t *src, 154 dns_catz_options_t *dst) { 155 REQUIRE(mctx != NULL); 156 REQUIRE(src != NULL); 157 REQUIRE(dst != NULL); 158 REQUIRE(dst->masters.count == 0); 159 REQUIRE(dst->allow_query == NULL); 160 REQUIRE(dst->allow_transfer == NULL); 161 162 if (src->masters.count != 0) { 163 dns_ipkeylist_copy(mctx, &src->masters, &dst->masters); 164 } 165 166 if (dst->zonedir != NULL) { 167 isc_mem_free(mctx, dst->zonedir); 168 dst->zonedir = NULL; 169 } 170 171 if (src->zonedir != NULL) { 172 dst->zonedir = isc_mem_strdup(mctx, src->zonedir); 173 } 174 175 if (src->allow_query != NULL) { 176 isc_buffer_dup(mctx, &dst->allow_query, src->allow_query); 177 } 178 179 if (src->allow_transfer != NULL) { 180 isc_buffer_dup(mctx, &dst->allow_transfer, src->allow_transfer); 181 } 182 183 return (ISC_R_SUCCESS); 184 } 185 186 isc_result_t 187 dns_catz_options_setdefault(isc_mem_t *mctx, const dns_catz_options_t *defaults, 188 dns_catz_options_t *opts) { 189 REQUIRE(mctx != NULL); 190 REQUIRE(defaults != NULL); 191 REQUIRE(opts != NULL); 192 193 if (opts->masters.count == 0 && defaults->masters.count != 0) { 194 dns_ipkeylist_copy(mctx, &defaults->masters, &opts->masters); 195 } 196 197 if (defaults->zonedir != NULL) { 198 opts->zonedir = isc_mem_strdup(mctx, defaults->zonedir); 199 } 200 201 if (opts->allow_query == NULL && defaults->allow_query != NULL) { 202 isc_buffer_dup(mctx, &opts->allow_query, defaults->allow_query); 203 } 204 if (opts->allow_transfer == NULL && defaults->allow_transfer != NULL) { 205 isc_buffer_dup(mctx, &opts->allow_transfer, 206 defaults->allow_transfer); 207 } 208 209 /* This option is always taken from config, so it's always 'default' */ 210 opts->in_memory = defaults->in_memory; 211 return (ISC_R_SUCCESS); 212 } 213 214 isc_result_t 215 dns_catz_entry_new(isc_mem_t *mctx, const dns_name_t *domain, 216 dns_catz_entry_t **nentryp) { 217 dns_catz_entry_t *nentry; 218 219 REQUIRE(mctx != NULL); 220 REQUIRE(nentryp != NULL && *nentryp == NULL); 221 222 nentry = isc_mem_get(mctx, sizeof(dns_catz_entry_t)); 223 224 dns_name_init(&nentry->name, NULL); 225 if (domain != NULL) { 226 dns_name_dup(domain, mctx, &nentry->name); 227 } 228 229 dns_catz_options_init(&nentry->opts); 230 isc_refcount_init(&nentry->refs, 1); 231 nentry->magic = DNS_CATZ_ENTRY_MAGIC; 232 *nentryp = nentry; 233 return (ISC_R_SUCCESS); 234 } 235 236 dns_name_t * 237 dns_catz_entry_getname(dns_catz_entry_t *entry) { 238 REQUIRE(DNS_CATZ_ENTRY_VALID(entry)); 239 return (&entry->name); 240 } 241 242 isc_result_t 243 dns_catz_entry_copy(dns_catz_zone_t *zone, const dns_catz_entry_t *entry, 244 dns_catz_entry_t **nentryp) { 245 isc_result_t result; 246 dns_catz_entry_t *nentry = NULL; 247 248 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 249 REQUIRE(DNS_CATZ_ENTRY_VALID(entry)); 250 REQUIRE(nentryp != NULL && *nentryp == NULL); 251 252 result = dns_catz_entry_new(zone->catzs->mctx, &entry->name, &nentry); 253 if (result != ISC_R_SUCCESS) { 254 return (result); 255 } 256 257 result = dns_catz_options_copy(zone->catzs->mctx, &entry->opts, 258 &nentry->opts); 259 if (result != ISC_R_SUCCESS) { 260 dns_catz_entry_detach(zone, &nentry); 261 } 262 263 *nentryp = nentry; 264 return (result); 265 } 266 267 void 268 dns_catz_entry_attach(dns_catz_entry_t *entry, dns_catz_entry_t **entryp) { 269 REQUIRE(DNS_CATZ_ENTRY_VALID(entry)); 270 REQUIRE(entryp != NULL && *entryp == NULL); 271 272 isc_refcount_increment(&entry->refs); 273 *entryp = entry; 274 } 275 276 void 277 dns_catz_entry_detach(dns_catz_zone_t *zone, dns_catz_entry_t **entryp) { 278 dns_catz_entry_t *entry; 279 280 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 281 REQUIRE(entryp != NULL); 282 entry = *entryp; 283 *entryp = NULL; 284 REQUIRE(DNS_CATZ_ENTRY_VALID(entry)); 285 286 if (isc_refcount_decrement(&entry->refs) == 1) { 287 isc_mem_t *mctx = zone->catzs->mctx; 288 entry->magic = 0; 289 isc_refcount_destroy(&entry->refs); 290 dns_catz_options_free(&entry->opts, mctx); 291 if (dns_name_dynamic(&entry->name)) { 292 dns_name_free(&entry->name, mctx); 293 } 294 isc_mem_put(mctx, entry, sizeof(dns_catz_entry_t)); 295 } 296 } 297 298 bool 299 dns_catz_entry_validate(const dns_catz_entry_t *entry) { 300 REQUIRE(DNS_CATZ_ENTRY_VALID(entry)); 301 UNUSED(entry); 302 303 return (true); 304 } 305 306 bool 307 dns_catz_entry_cmp(const dns_catz_entry_t *ea, const dns_catz_entry_t *eb) { 308 isc_region_t ra, rb; 309 310 REQUIRE(DNS_CATZ_ENTRY_VALID(ea)); 311 REQUIRE(DNS_CATZ_ENTRY_VALID(eb)); 312 313 if (ea == eb) { 314 return (true); 315 } 316 317 if (ea->opts.masters.count != eb->opts.masters.count) { 318 return (false); 319 } 320 321 if (memcmp(ea->opts.masters.addrs, eb->opts.masters.addrs, 322 ea->opts.masters.count * sizeof(isc_sockaddr_t))) 323 { 324 return (false); 325 } 326 327 /* If one is NULL and the other isn't, the entries don't match */ 328 if ((ea->opts.allow_query == NULL) != (eb->opts.allow_query == NULL)) { 329 return (false); 330 } 331 332 /* If one is non-NULL, then they both are */ 333 if (ea->opts.allow_query != NULL) { 334 isc_buffer_usedregion(ea->opts.allow_query, &ra); 335 isc_buffer_usedregion(eb->opts.allow_query, &rb); 336 if (isc_region_compare(&ra, &rb)) { 337 return (false); 338 } 339 } 340 341 /* Repeat the above checks with allow_transfer */ 342 if ((ea->opts.allow_transfer == NULL) != 343 (eb->opts.allow_transfer == NULL)) { 344 return (false); 345 } 346 347 if (ea->opts.allow_transfer != NULL) { 348 isc_buffer_usedregion(ea->opts.allow_transfer, &ra); 349 isc_buffer_usedregion(eb->opts.allow_transfer, &rb); 350 if (isc_region_compare(&ra, &rb)) { 351 return (false); 352 } 353 } 354 355 /* xxxwpk TODO compare dscps/keys! */ 356 return (true); 357 } 358 359 dns_name_t * 360 dns_catz_zone_getname(dns_catz_zone_t *zone) { 361 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 362 363 return (&zone->name); 364 } 365 366 dns_catz_options_t * 367 dns_catz_zone_getdefoptions(dns_catz_zone_t *zone) { 368 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 369 370 return (&zone->defoptions); 371 } 372 373 void 374 dns_catz_zone_resetdefoptions(dns_catz_zone_t *zone) { 375 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 376 377 dns_catz_options_free(&zone->defoptions, zone->catzs->mctx); 378 dns_catz_options_init(&zone->defoptions); 379 } 380 381 isc_result_t 382 dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) { 383 isc_result_t result; 384 isc_ht_iter_t *iter1 = NULL, *iter2 = NULL; 385 isc_ht_iter_t *iteradd = NULL, *itermod = NULL; 386 isc_ht_t *toadd = NULL, *tomod = NULL; 387 bool delcur = false; 388 char czname[DNS_NAME_FORMATSIZE]; 389 char zname[DNS_NAME_FORMATSIZE]; 390 dns_catz_zoneop_fn_t addzone, modzone, delzone; 391 392 REQUIRE(DNS_CATZ_ZONE_VALID(newzone)); 393 REQUIRE(DNS_CATZ_ZONE_VALID(target)); 394 395 /* TODO verify the new zone first! */ 396 397 addzone = target->catzs->zmm->addzone; 398 modzone = target->catzs->zmm->modzone; 399 delzone = target->catzs->zmm->delzone; 400 401 /* Copy zoneoptions from newzone into target. */ 402 403 dns_catz_options_free(&target->zoneoptions, target->catzs->mctx); 404 dns_catz_options_copy(target->catzs->mctx, &newzone->zoneoptions, 405 &target->zoneoptions); 406 dns_catz_options_setdefault(target->catzs->mctx, &target->defoptions, 407 &target->zoneoptions); 408 409 dns_name_format(&target->name, czname, DNS_NAME_FORMATSIZE); 410 411 isc_ht_init(&toadd, target->catzs->mctx, 16); 412 413 isc_ht_init(&tomod, target->catzs->mctx, 16); 414 415 isc_ht_iter_create(newzone->entries, &iter1); 416 417 isc_ht_iter_create(target->entries, &iter2); 418 419 /* 420 * We can create those iterators now, even though toadd and tomod are 421 * empty 422 */ 423 isc_ht_iter_create(toadd, &iteradd); 424 425 isc_ht_iter_create(tomod, &itermod); 426 427 /* 428 * First - walk the new zone and find all nodes that are not in the 429 * old zone, or are in both zones and are modified. 430 */ 431 for (result = isc_ht_iter_first(iter1); result == ISC_R_SUCCESS; 432 result = delcur ? isc_ht_iter_delcurrent_next(iter1) 433 : isc_ht_iter_next(iter1)) 434 { 435 dns_catz_entry_t *nentry = NULL; 436 dns_catz_entry_t *oentry = NULL; 437 dns_zone_t *zone = NULL; 438 unsigned char *key = NULL; 439 size_t keysize; 440 delcur = false; 441 442 isc_ht_iter_current(iter1, (void **)&nentry); 443 isc_ht_iter_currentkey(iter1, &key, &keysize); 444 445 /* 446 * Spurious record that came from suboption without main 447 * record, removed. 448 * xxxwpk: make it a separate verification phase? 449 */ 450 if (dns_name_countlabels(&nentry->name) == 0) { 451 dns_catz_entry_detach(newzone, &nentry); 452 delcur = true; 453 continue; 454 } 455 456 dns_name_format(&nentry->name, zname, DNS_NAME_FORMATSIZE); 457 458 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 459 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3), 460 "catz: iterating over '%s' from catalog '%s'", 461 zname, czname); 462 dns_catz_options_setdefault(target->catzs->mctx, 463 &target->zoneoptions, 464 &nentry->opts); 465 466 result = isc_ht_find(target->entries, key, (uint32_t)keysize, 467 (void **)&oentry); 468 if (result != ISC_R_SUCCESS) { 469 catz_entry_add_or_mod(target, toadd, key, keysize, 470 nentry, NULL, "adding", zname, 471 czname); 472 continue; 473 } 474 475 result = dns_zt_find(target->catzs->view->zonetable, 476 dns_catz_entry_getname(nentry), 0, NULL, 477 &zone); 478 if (result != ISC_R_SUCCESS) { 479 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 480 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3), 481 "catz: zone '%s' was expected to exist " 482 "but can not be found, will be restored", 483 zname); 484 catz_entry_add_or_mod(target, toadd, key, keysize, 485 nentry, oentry, "adding", zname, 486 czname); 487 continue; 488 } 489 dns_zone_detach(&zone); 490 491 if (dns_catz_entry_cmp(oentry, nentry) != true) { 492 catz_entry_add_or_mod(target, tomod, key, keysize, 493 nentry, oentry, "modifying", 494 zname, czname); 495 continue; 496 } 497 498 /* 499 * Delete the old entry so that it won't accidentally be 500 * removed as a non-existing entry below. 501 */ 502 dns_catz_entry_detach(target, &oentry); 503 result = isc_ht_delete(target->entries, key, (uint32_t)keysize); 504 RUNTIME_CHECK(result == ISC_R_SUCCESS); 505 } 506 RUNTIME_CHECK(result == ISC_R_NOMORE); 507 isc_ht_iter_destroy(&iter1); 508 509 /* 510 * Then - walk the old zone; only deleted entries should remain. 511 */ 512 for (result = isc_ht_iter_first(iter2); result == ISC_R_SUCCESS; 513 result = isc_ht_iter_delcurrent_next(iter2)) 514 { 515 dns_catz_entry_t *entry = NULL; 516 isc_ht_iter_current(iter2, (void **)&entry); 517 518 dns_name_format(&entry->name, zname, DNS_NAME_FORMATSIZE); 519 result = delzone(entry, target, target->catzs->view, 520 target->catzs->taskmgr, 521 target->catzs->zmm->udata); 522 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 523 DNS_LOGMODULE_MASTER, ISC_LOG_INFO, 524 "catz: deleting zone '%s' from catalog '%s' - %s", 525 zname, czname, isc_result_totext(result)); 526 dns_catz_entry_detach(target, &entry); 527 } 528 RUNTIME_CHECK(result == ISC_R_NOMORE); 529 isc_ht_iter_destroy(&iter2); 530 /* At this moment target->entries has to be be empty. */ 531 INSIST(isc_ht_count(target->entries) == 0); 532 isc_ht_destroy(&target->entries); 533 534 for (result = isc_ht_iter_first(iteradd); result == ISC_R_SUCCESS; 535 result = isc_ht_iter_delcurrent_next(iteradd)) 536 { 537 dns_catz_entry_t *entry = NULL; 538 isc_ht_iter_current(iteradd, (void **)&entry); 539 540 dns_name_format(&entry->name, zname, DNS_NAME_FORMATSIZE); 541 result = addzone(entry, target, target->catzs->view, 542 target->catzs->taskmgr, 543 target->catzs->zmm->udata); 544 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 545 DNS_LOGMODULE_MASTER, ISC_LOG_INFO, 546 "catz: adding zone '%s' from catalog " 547 "'%s' - %s", 548 zname, czname, isc_result_totext(result)); 549 } 550 551 for (result = isc_ht_iter_first(itermod); result == ISC_R_SUCCESS; 552 result = isc_ht_iter_delcurrent_next(itermod)) 553 { 554 dns_catz_entry_t *entry = NULL; 555 isc_ht_iter_current(itermod, (void **)&entry); 556 557 dns_name_format(&entry->name, zname, DNS_NAME_FORMATSIZE); 558 result = modzone(entry, target, target->catzs->view, 559 target->catzs->taskmgr, 560 target->catzs->zmm->udata); 561 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 562 DNS_LOGMODULE_MASTER, ISC_LOG_INFO, 563 "catz: modifying zone '%s' from catalog " 564 "'%s' - %s", 565 zname, czname, isc_result_totext(result)); 566 } 567 568 target->entries = newzone->entries; 569 newzone->entries = NULL; 570 571 result = ISC_R_SUCCESS; 572 573 isc_ht_iter_destroy(&iteradd); 574 isc_ht_iter_destroy(&itermod); 575 isc_ht_destroy(&toadd); 576 isc_ht_destroy(&tomod); 577 578 return (result); 579 } 580 581 isc_result_t 582 dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm, 583 isc_mem_t *mctx, isc_taskmgr_t *taskmgr, 584 isc_timermgr_t *timermgr) { 585 dns_catz_zones_t *new_zones; 586 isc_result_t result; 587 588 REQUIRE(catzsp != NULL && *catzsp == NULL); 589 REQUIRE(zmm != NULL); 590 591 new_zones = isc_mem_get(mctx, sizeof(*new_zones)); 592 memset(new_zones, 0, sizeof(*new_zones)); 593 594 isc_mutex_init(&new_zones->lock); 595 596 isc_refcount_init(&new_zones->refs, 1); 597 598 isc_ht_init(&new_zones->zones, mctx, 4); 599 600 isc_mem_attach(mctx, &new_zones->mctx); 601 new_zones->zmm = zmm; 602 new_zones->timermgr = timermgr; 603 new_zones->taskmgr = taskmgr; 604 605 result = isc_task_create(taskmgr, 0, &new_zones->updater); 606 if (result != ISC_R_SUCCESS) { 607 goto cleanup_ht; 608 } 609 new_zones->magic = DNS_CATZ_ZONES_MAGIC; 610 611 *catzsp = new_zones; 612 return (ISC_R_SUCCESS); 613 614 cleanup_ht: 615 isc_ht_destroy(&new_zones->zones); 616 isc_refcount_destroy(&new_zones->refs); 617 isc_mutex_destroy(&new_zones->lock); 618 isc_mem_put(mctx, new_zones, sizeof(*new_zones)); 619 620 return (result); 621 } 622 623 void 624 dns_catz_catzs_set_view(dns_catz_zones_t *catzs, dns_view_t *view) { 625 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 626 REQUIRE(view != NULL); 627 /* Either it's a new one or it's being reconfigured. */ 628 REQUIRE(catzs->view == NULL || !strcmp(catzs->view->name, view->name)); 629 630 catzs->view = view; 631 } 632 633 isc_result_t 634 dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep, 635 const dns_name_t *name) { 636 isc_result_t result; 637 dns_catz_zone_t *new_zone; 638 639 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 640 REQUIRE(zonep != NULL && *zonep == NULL); 641 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC)); 642 643 new_zone = isc_mem_get(catzs->mctx, sizeof(*new_zone)); 644 645 memset(new_zone, 0, sizeof(*new_zone)); 646 647 dns_name_init(&new_zone->name, NULL); 648 dns_name_dup(name, catzs->mctx, &new_zone->name); 649 650 isc_ht_init(&new_zone->entries, catzs->mctx, 4); 651 652 new_zone->updatetimer = NULL; 653 result = isc_timer_create(catzs->timermgr, isc_timertype_inactive, NULL, 654 NULL, catzs->updater, 655 dns_catz_update_taskaction, new_zone, 656 &new_zone->updatetimer); 657 if (result != ISC_R_SUCCESS) { 658 goto cleanup_ht; 659 } 660 661 isc_time_settoepoch(&new_zone->lastupdated); 662 new_zone->updatepending = false; 663 new_zone->db = NULL; 664 new_zone->dbversion = NULL; 665 new_zone->catzs = catzs; 666 dns_catz_options_init(&new_zone->defoptions); 667 dns_catz_options_init(&new_zone->zoneoptions); 668 new_zone->active = true; 669 new_zone->db_registered = false; 670 new_zone->version = (uint32_t)(-1); 671 isc_refcount_init(&new_zone->refs, 1); 672 new_zone->magic = DNS_CATZ_ZONE_MAGIC; 673 674 *zonep = new_zone; 675 676 return (ISC_R_SUCCESS); 677 678 cleanup_ht: 679 isc_ht_destroy(&new_zone->entries); 680 dns_name_free(&new_zone->name, catzs->mctx); 681 isc_mem_put(catzs->mctx, new_zone, sizeof(*new_zone)); 682 683 return (result); 684 } 685 686 isc_result_t 687 dns_catz_add_zone(dns_catz_zones_t *catzs, const dns_name_t *name, 688 dns_catz_zone_t **zonep) { 689 dns_catz_zone_t *new_zone = NULL; 690 isc_result_t result, tresult; 691 char zname[DNS_NAME_FORMATSIZE]; 692 693 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 694 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC)); 695 REQUIRE(zonep != NULL && *zonep == NULL); 696 697 dns_name_format(name, zname, DNS_NAME_FORMATSIZE); 698 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, 699 ISC_LOG_DEBUG(3), "catz: dns_catz_add_zone %s", zname); 700 701 LOCK(&catzs->lock); 702 703 result = dns_catz_new_zone(catzs, &new_zone, name); 704 if (result != ISC_R_SUCCESS) { 705 goto cleanup; 706 } 707 708 result = isc_ht_add(catzs->zones, new_zone->name.ndata, 709 new_zone->name.length, new_zone); 710 if (result != ISC_R_SUCCESS) { 711 dns_catz_zone_detach(&new_zone); 712 if (result != ISC_R_EXISTS) { 713 goto cleanup; 714 } 715 } 716 717 if (result == ISC_R_EXISTS) { 718 tresult = isc_ht_find(catzs->zones, name->ndata, name->length, 719 (void **)&new_zone); 720 INSIST(tresult == ISC_R_SUCCESS && !new_zone->active); 721 new_zone->active = true; 722 } 723 724 *zonep = new_zone; 725 726 cleanup: 727 UNLOCK(&catzs->lock); 728 729 return (result); 730 } 731 732 dns_catz_zone_t * 733 dns_catz_get_zone(dns_catz_zones_t *catzs, const dns_name_t *name) { 734 isc_result_t result; 735 dns_catz_zone_t *found = NULL; 736 737 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 738 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC)); 739 740 result = isc_ht_find(catzs->zones, name->ndata, name->length, 741 (void **)&found); 742 if (result != ISC_R_SUCCESS) { 743 return (NULL); 744 } 745 746 return (found); 747 } 748 749 void 750 dns_catz_catzs_attach(dns_catz_zones_t *catzs, dns_catz_zones_t **catzsp) { 751 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 752 REQUIRE(catzsp != NULL && *catzsp == NULL); 753 754 isc_refcount_increment(&catzs->refs); 755 *catzsp = catzs; 756 } 757 758 void 759 dns_catz_zone_attach(dns_catz_zone_t *zone, dns_catz_zone_t **zonep) { 760 REQUIRE(zonep != NULL && *zonep == NULL); 761 762 isc_refcount_increment(&zone->refs); 763 *zonep = zone; 764 } 765 766 void 767 dns_catz_zone_detach(dns_catz_zone_t **zonep) { 768 REQUIRE(zonep != NULL && *zonep != NULL); 769 dns_catz_zone_t *zone = *zonep; 770 *zonep = NULL; 771 772 if (isc_refcount_decrement(&zone->refs) == 1) { 773 isc_mem_t *mctx = zone->catzs->mctx; 774 isc_refcount_destroy(&zone->refs); 775 if (zone->entries != NULL) { 776 isc_ht_iter_t *iter = NULL; 777 isc_result_t result; 778 isc_ht_iter_create(zone->entries, &iter); 779 for (result = isc_ht_iter_first(iter); 780 result == ISC_R_SUCCESS; 781 result = isc_ht_iter_delcurrent_next(iter)) 782 { 783 dns_catz_entry_t *entry = NULL; 784 785 isc_ht_iter_current(iter, (void **)&entry); 786 dns_catz_entry_detach(zone, &entry); 787 } 788 INSIST(result == ISC_R_NOMORE); 789 isc_ht_iter_destroy(&iter); 790 791 /* The hashtable has to be empty now. */ 792 INSIST(isc_ht_count(zone->entries) == 0); 793 isc_ht_destroy(&zone->entries); 794 } 795 zone->magic = 0; 796 isc_timer_detach(&zone->updatetimer); 797 if (zone->db_registered) { 798 INSIST(dns_db_updatenotify_unregister( 799 zone->db, dns_catz_dbupdate_callback, 800 zone->catzs) == ISC_R_SUCCESS); 801 } 802 if (zone->dbversion) { 803 dns_db_closeversion(zone->db, &zone->dbversion, false); 804 } 805 if (zone->db != NULL) { 806 dns_db_detach(&zone->db); 807 } 808 809 dns_name_free(&zone->name, mctx); 810 dns_catz_options_free(&zone->defoptions, mctx); 811 dns_catz_options_free(&zone->zoneoptions, mctx); 812 813 zone->catzs = NULL; 814 isc_mem_put(mctx, zone, sizeof(dns_catz_zone_t)); 815 } 816 } 817 818 void 819 dns_catz_catzs_detach(dns_catz_zones_t **catzsp) { 820 dns_catz_zones_t *catzs; 821 822 REQUIRE(catzsp != NULL && *catzsp != NULL); 823 824 catzs = *catzsp; 825 *catzsp = NULL; 826 827 if (isc_refcount_decrement(&catzs->refs) == 1) { 828 catzs->magic = 0; 829 isc_task_destroy(&catzs->updater); 830 isc_mutex_destroy(&catzs->lock); 831 if (catzs->zones != NULL) { 832 isc_ht_iter_t *iter = NULL; 833 isc_result_t result; 834 isc_ht_iter_create(catzs->zones, &iter); 835 for (result = isc_ht_iter_first(iter); 836 result == ISC_R_SUCCESS;) { 837 dns_catz_zone_t *zone = NULL; 838 isc_ht_iter_current(iter, (void **)&zone); 839 result = isc_ht_iter_delcurrent_next(iter); 840 dns_catz_zone_detach(&zone); 841 } 842 INSIST(result == ISC_R_NOMORE); 843 isc_ht_iter_destroy(&iter); 844 INSIST(isc_ht_count(catzs->zones) == 0); 845 isc_ht_destroy(&catzs->zones); 846 } 847 isc_refcount_destroy(&catzs->refs); 848 isc_mem_putanddetach(&catzs->mctx, catzs, sizeof(*catzs)); 849 } 850 } 851 852 typedef enum { 853 CATZ_OPT_NONE, 854 CATZ_OPT_ZONES, 855 CATZ_OPT_MASTERS, 856 CATZ_OPT_ALLOW_QUERY, 857 CATZ_OPT_ALLOW_TRANSFER, 858 CATZ_OPT_VERSION, 859 } catz_opt_t; 860 861 static bool 862 catz_opt_cmp(const dns_label_t *option, const char *opt) { 863 unsigned int l = strlen(opt); 864 if (option->length - 1 == l && 865 memcmp(opt, option->base + 1, l - 1) == 0) { 866 return (true); 867 } else { 868 return (false); 869 } 870 } 871 872 static catz_opt_t 873 catz_get_option(const dns_label_t *option) { 874 if (catz_opt_cmp(option, "zones")) { 875 return (CATZ_OPT_ZONES); 876 } else if (catz_opt_cmp(option, "masters")) { 877 return (CATZ_OPT_MASTERS); 878 } else if (catz_opt_cmp(option, "allow-query")) { 879 return (CATZ_OPT_ALLOW_QUERY); 880 } else if (catz_opt_cmp(option, "allow-transfer")) { 881 return (CATZ_OPT_ALLOW_TRANSFER); 882 } else if (catz_opt_cmp(option, "version")) { 883 return (CATZ_OPT_VERSION); 884 } else { 885 return (CATZ_OPT_NONE); 886 } 887 } 888 889 static isc_result_t 890 catz_process_zones(dns_catz_zone_t *zone, dns_rdataset_t *value, 891 dns_name_t *name) { 892 dns_label_t mhash; 893 dns_name_t opt; 894 895 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 896 REQUIRE(DNS_RDATASET_VALID(value)); 897 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC)); 898 899 if (value->rdclass != dns_rdataclass_in) { 900 return (ISC_R_FAILURE); 901 } 902 903 if (name->labels == 0) { 904 return (ISC_R_FAILURE); 905 } 906 907 dns_name_getlabel(name, name->labels - 1, &mhash); 908 909 if (name->labels == 1) { 910 return (catz_process_zones_entry(zone, value, &mhash)); 911 } else { 912 dns_name_init(&opt, NULL); 913 dns_name_split(name, 1, &opt, NULL); 914 return (catz_process_zones_suboption(zone, value, &mhash, 915 &opt)); 916 } 917 } 918 919 static isc_result_t 920 catz_process_zones_entry(dns_catz_zone_t *zone, dns_rdataset_t *value, 921 dns_label_t *mhash) { 922 isc_result_t result; 923 dns_rdata_t rdata; 924 dns_rdata_ptr_t ptr; 925 dns_catz_entry_t *entry = NULL; 926 927 /* 928 * We only take -first- value, as mhash must be 929 * different. 930 */ 931 if (value->type != dns_rdatatype_ptr) { 932 return (ISC_R_FAILURE); 933 } 934 935 result = dns_rdataset_first(value); 936 if (result != ISC_R_SUCCESS) { 937 return (ISC_R_FAILURE); 938 } 939 940 dns_rdata_init(&rdata); 941 dns_rdataset_current(value, &rdata); 942 943 result = dns_rdata_tostruct(&rdata, &ptr, NULL); 944 RUNTIME_CHECK(result == ISC_R_SUCCESS); 945 946 result = isc_ht_find(zone->entries, mhash->base, mhash->length, 947 (void **)&entry); 948 if (result == ISC_R_SUCCESS) { 949 if (dns_name_countlabels(&entry->name) != 0) { 950 /* We have a duplicate. */ 951 dns_rdata_freestruct(&ptr); 952 return (ISC_R_FAILURE); 953 } else { 954 dns_name_dup(&ptr.ptr, zone->catzs->mctx, &entry->name); 955 } 956 } else { 957 result = dns_catz_entry_new(zone->catzs->mctx, &ptr.ptr, 958 &entry); 959 if (result != ISC_R_SUCCESS) { 960 dns_rdata_freestruct(&ptr); 961 return (result); 962 } 963 964 result = isc_ht_add(zone->entries, mhash->base, mhash->length, 965 entry); 966 if (result != ISC_R_SUCCESS) { 967 dns_rdata_freestruct(&ptr); 968 dns_catz_entry_detach(zone, &entry); 969 return (result); 970 } 971 } 972 973 dns_rdata_freestruct(&ptr); 974 975 return (ISC_R_SUCCESS); 976 } 977 978 static isc_result_t 979 catz_process_version(dns_catz_zone_t *zone, dns_rdataset_t *value) { 980 isc_result_t result; 981 dns_rdata_t rdata; 982 dns_rdata_txt_t rdatatxt; 983 dns_rdata_txt_string_t rdatastr; 984 uint32_t tversion; 985 char t[16]; 986 987 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 988 REQUIRE(DNS_RDATASET_VALID(value)); 989 990 if (value->rdclass != dns_rdataclass_in || 991 value->type != dns_rdatatype_txt) { 992 return (ISC_R_FAILURE); 993 } 994 995 result = dns_rdataset_first(value); 996 if (result != ISC_R_SUCCESS) { 997 return (result); 998 } 999 1000 dns_rdata_init(&rdata); 1001 dns_rdataset_current(value, &rdata); 1002 1003 result = dns_rdata_tostruct(&rdata, &rdatatxt, NULL); 1004 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1005 1006 result = dns_rdata_txt_first(&rdatatxt); 1007 if (result != ISC_R_SUCCESS) { 1008 goto cleanup; 1009 } 1010 1011 result = dns_rdata_txt_current(&rdatatxt, &rdatastr); 1012 if (result != ISC_R_SUCCESS) { 1013 goto cleanup; 1014 } 1015 1016 result = dns_rdata_txt_next(&rdatatxt); 1017 if (result != ISC_R_NOMORE) { 1018 result = ISC_R_FAILURE; 1019 goto cleanup; 1020 } 1021 if (rdatastr.length > 15) { 1022 result = ISC_R_BADNUMBER; 1023 goto cleanup; 1024 } 1025 memmove(t, rdatastr.data, rdatastr.length); 1026 t[rdatastr.length] = 0; 1027 result = isc_parse_uint32(&tversion, t, 10); 1028 if (result != ISC_R_SUCCESS) { 1029 goto cleanup; 1030 } 1031 zone->version = tversion; 1032 result = ISC_R_SUCCESS; 1033 1034 cleanup: 1035 dns_rdata_freestruct(&rdatatxt); 1036 return (result); 1037 } 1038 1039 static isc_result_t 1040 catz_process_masters(dns_catz_zone_t *zone, dns_ipkeylist_t *ipkl, 1041 dns_rdataset_t *value, dns_name_t *name) { 1042 isc_result_t result; 1043 dns_rdata_t rdata; 1044 dns_rdata_in_a_t rdata_a; 1045 dns_rdata_in_aaaa_t rdata_aaaa; 1046 dns_rdata_txt_t rdata_txt; 1047 dns_rdata_txt_string_t rdatastr; 1048 dns_name_t *keyname = NULL; 1049 isc_mem_t *mctx; 1050 char keycbuf[DNS_NAME_FORMATSIZE]; 1051 isc_buffer_t keybuf; 1052 unsigned int rcount; 1053 unsigned int i; 1054 1055 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1056 REQUIRE(ipkl != NULL); 1057 REQUIRE(DNS_RDATASET_VALID(value)); 1058 REQUIRE(dns_rdataset_isassociated(value)); 1059 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC)); 1060 1061 mctx = zone->catzs->mctx; 1062 memset(&rdata_a, 0, sizeof(rdata_a)); 1063 memset(&rdata_aaaa, 0, sizeof(rdata_aaaa)); 1064 memset(&rdata_txt, 0, sizeof(rdata_txt)); 1065 isc_buffer_init(&keybuf, keycbuf, sizeof(keycbuf)); 1066 1067 /* 1068 * We have three possibilities here: 1069 * - either empty name and IN A/IN AAAA record 1070 * - label and IN A/IN AAAA 1071 * - label and IN TXT - TSIG key name 1072 */ 1073 if (value->rdclass != dns_rdataclass_in) { 1074 return (ISC_R_FAILURE); 1075 } 1076 1077 if (name->labels > 0) { 1078 isc_sockaddr_t sockaddr; 1079 1080 /* 1081 * We're pre-preparing the data once, we'll put it into 1082 * the right spot in the masters array once we find it. 1083 */ 1084 result = dns_rdataset_first(value); 1085 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1086 dns_rdata_init(&rdata); 1087 dns_rdataset_current(value, &rdata); 1088 switch (value->type) { 1089 case dns_rdatatype_a: 1090 result = dns_rdata_tostruct(&rdata, &rdata_a, NULL); 1091 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1092 isc_sockaddr_fromin(&sockaddr, &rdata_a.in_addr, 0); 1093 break; 1094 case dns_rdatatype_aaaa: 1095 result = dns_rdata_tostruct(&rdata, &rdata_aaaa, NULL); 1096 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1097 isc_sockaddr_fromin6(&sockaddr, &rdata_aaaa.in6_addr, 1098 0); 1099 break; 1100 case dns_rdatatype_txt: 1101 result = dns_rdata_tostruct(&rdata, &rdata_txt, NULL); 1102 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1103 1104 result = dns_rdata_txt_first(&rdata_txt); 1105 if (result != ISC_R_SUCCESS) { 1106 return (result); 1107 } 1108 1109 result = dns_rdata_txt_current(&rdata_txt, &rdatastr); 1110 if (result != ISC_R_SUCCESS) { 1111 return (result); 1112 } 1113 1114 result = dns_rdata_txt_next(&rdata_txt); 1115 if (result != ISC_R_NOMORE) { 1116 return (ISC_R_FAILURE); 1117 } 1118 1119 /* rdatastr.length < DNS_NAME_MAXTEXT */ 1120 keyname = isc_mem_get(mctx, sizeof(dns_name_t)); 1121 dns_name_init(keyname, 0); 1122 memmove(keycbuf, rdatastr.data, rdatastr.length); 1123 keycbuf[rdatastr.length] = 0; 1124 result = dns_name_fromstring(keyname, keycbuf, 0, mctx); 1125 if (result != ISC_R_SUCCESS) { 1126 dns_name_free(keyname, mctx); 1127 isc_mem_put(mctx, keyname, sizeof(dns_name_t)); 1128 return (result); 1129 } 1130 break; 1131 default: 1132 return (ISC_R_FAILURE); 1133 } 1134 1135 /* 1136 * We have to find the appropriate labeled record in masters 1137 * if it exists. 1138 * In common case we'll have no more than 3-4 records here so 1139 * no optimization. 1140 */ 1141 for (i = 0; i < ipkl->count; i++) { 1142 if (ipkl->labels[i] != NULL && 1143 !dns_name_compare(name, ipkl->labels[i])) { 1144 break; 1145 } 1146 } 1147 1148 if (i < ipkl->count) { /* we have this record already */ 1149 if (value->type == dns_rdatatype_txt) { 1150 ipkl->keys[i] = keyname; 1151 } else { /* A/AAAA */ 1152 memmove(&ipkl->addrs[i], &sockaddr, 1153 sizeof(isc_sockaddr_t)); 1154 } 1155 } else { 1156 result = dns_ipkeylist_resize(mctx, ipkl, i + 1); 1157 if (result != ISC_R_SUCCESS) { 1158 return (result); 1159 } 1160 1161 ipkl->labels[i] = isc_mem_get(mctx, sizeof(dns_name_t)); 1162 dns_name_init(ipkl->labels[i], NULL); 1163 dns_name_dup(name, mctx, ipkl->labels[i]); 1164 1165 if (value->type == dns_rdatatype_txt) { 1166 ipkl->keys[i] = keyname; 1167 } else { /* A/AAAA */ 1168 memmove(&ipkl->addrs[i], &sockaddr, 1169 sizeof(isc_sockaddr_t)); 1170 } 1171 ipkl->count++; 1172 } 1173 return (ISC_R_SUCCESS); 1174 } 1175 /* else - 'simple' case - without labels */ 1176 1177 if (value->type != dns_rdatatype_a && value->type != dns_rdatatype_aaaa) 1178 { 1179 return (ISC_R_FAILURE); 1180 } 1181 1182 rcount = dns_rdataset_count(value) + ipkl->count; 1183 1184 result = dns_ipkeylist_resize(mctx, ipkl, rcount); 1185 if (result != ISC_R_SUCCESS) { 1186 return (result); 1187 } 1188 1189 for (result = dns_rdataset_first(value); result == ISC_R_SUCCESS; 1190 result = dns_rdataset_next(value)) 1191 { 1192 dns_rdata_init(&rdata); 1193 dns_rdataset_current(value, &rdata); 1194 /* 1195 * port 0 == take the default 1196 */ 1197 if (value->type == dns_rdatatype_a) { 1198 result = dns_rdata_tostruct(&rdata, &rdata_a, NULL); 1199 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1200 isc_sockaddr_fromin(&ipkl->addrs[ipkl->count], 1201 &rdata_a.in_addr, 0); 1202 } else { 1203 result = dns_rdata_tostruct(&rdata, &rdata_aaaa, NULL); 1204 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1205 isc_sockaddr_fromin6(&ipkl->addrs[ipkl->count], 1206 &rdata_aaaa.in6_addr, 0); 1207 } 1208 ipkl->keys[ipkl->count] = NULL; 1209 ipkl->labels[ipkl->count] = NULL; 1210 ipkl->count++; 1211 dns_rdata_freestruct(&rdata_a); 1212 } 1213 return (ISC_R_SUCCESS); 1214 } 1215 1216 static isc_result_t 1217 catz_process_apl(dns_catz_zone_t *zone, isc_buffer_t **aclbp, 1218 dns_rdataset_t *value) { 1219 isc_result_t result = ISC_R_SUCCESS; 1220 dns_rdata_t rdata; 1221 dns_rdata_in_apl_t rdata_apl; 1222 dns_rdata_apl_ent_t apl_ent; 1223 isc_netaddr_t addr; 1224 isc_buffer_t *aclb = NULL; 1225 unsigned char buf[256]; /* larger than INET6_ADDRSTRLEN */ 1226 1227 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1228 REQUIRE(aclbp != NULL); 1229 REQUIRE(*aclbp == NULL); 1230 REQUIRE(DNS_RDATASET_VALID(value)); 1231 REQUIRE(dns_rdataset_isassociated(value)); 1232 1233 if (value->rdclass != dns_rdataclass_in || 1234 value->type != dns_rdatatype_apl) { 1235 return (ISC_R_FAILURE); 1236 } 1237 1238 if (dns_rdataset_count(value) > 1) { 1239 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1240 DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, 1241 "catz: more than one APL entry for member zone, " 1242 "result is undefined"); 1243 } 1244 result = dns_rdataset_first(value); 1245 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1246 dns_rdata_init(&rdata); 1247 dns_rdataset_current(value, &rdata); 1248 result = dns_rdata_tostruct(&rdata, &rdata_apl, zone->catzs->mctx); 1249 if (result != ISC_R_SUCCESS) { 1250 return (result); 1251 } 1252 isc_buffer_allocate(zone->catzs->mctx, &aclb, 16); 1253 isc_buffer_setautorealloc(aclb, true); 1254 for (result = dns_rdata_apl_first(&rdata_apl); result == ISC_R_SUCCESS; 1255 result = dns_rdata_apl_next(&rdata_apl)) 1256 { 1257 result = dns_rdata_apl_current(&rdata_apl, &apl_ent); 1258 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1259 memset(buf, 0, sizeof(buf)); 1260 if (apl_ent.data != NULL && apl_ent.length > 0) { 1261 memmove(buf, apl_ent.data, apl_ent.length); 1262 } 1263 if (apl_ent.family == 1) { 1264 isc_netaddr_fromin(&addr, (struct in_addr *)buf); 1265 } else if (apl_ent.family == 2) { 1266 isc_netaddr_fromin6(&addr, (struct in6_addr *)buf); 1267 } else { 1268 continue; /* xxxwpk log it or simply ignore? */ 1269 } 1270 if (apl_ent.negative) { 1271 isc_buffer_putuint8(aclb, '!'); 1272 } 1273 isc_buffer_reserve(&aclb, INET6_ADDRSTRLEN); 1274 result = isc_netaddr_totext(&addr, aclb); 1275 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1276 if ((apl_ent.family == 1 && apl_ent.prefix < 32) || 1277 (apl_ent.family == 2 && apl_ent.prefix < 128)) 1278 { 1279 isc_buffer_putuint8(aclb, '/'); 1280 isc_buffer_putdecint(aclb, apl_ent.prefix); 1281 } 1282 isc_buffer_putstr(aclb, "; "); 1283 } 1284 if (result == ISC_R_NOMORE) { 1285 result = ISC_R_SUCCESS; 1286 } else { 1287 goto cleanup; 1288 } 1289 *aclbp = aclb; 1290 aclb = NULL; 1291 cleanup: 1292 if (aclb != NULL) { 1293 isc_buffer_free(&aclb); 1294 } 1295 dns_rdata_freestruct(&rdata_apl); 1296 return (result); 1297 } 1298 1299 static isc_result_t 1300 catz_process_zones_suboption(dns_catz_zone_t *zone, dns_rdataset_t *value, 1301 dns_label_t *mhash, dns_name_t *name) { 1302 isc_result_t result; 1303 dns_catz_entry_t *entry = NULL; 1304 dns_label_t option; 1305 dns_name_t prefix; 1306 catz_opt_t opt; 1307 1308 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1309 REQUIRE(mhash != NULL); 1310 REQUIRE(DNS_RDATASET_VALID(value)); 1311 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC)); 1312 1313 if (name->labels == 0) { 1314 return (ISC_R_FAILURE); 1315 } 1316 dns_name_getlabel(name, name->labels - 1, &option); 1317 opt = catz_get_option(&option); 1318 1319 /* 1320 * We're adding this entry now, in case the option is invalid we'll get 1321 * rid of it in verification phase. 1322 */ 1323 result = isc_ht_find(zone->entries, mhash->base, mhash->length, 1324 (void **)&entry); 1325 if (result != ISC_R_SUCCESS) { 1326 result = dns_catz_entry_new(zone->catzs->mctx, NULL, &entry); 1327 if (result != ISC_R_SUCCESS) { 1328 return (result); 1329 } 1330 result = isc_ht_add(zone->entries, mhash->base, mhash->length, 1331 entry); 1332 if (result != ISC_R_SUCCESS) { 1333 dns_catz_entry_detach(zone, &entry); 1334 return (result); 1335 } 1336 } 1337 1338 dns_name_init(&prefix, NULL); 1339 dns_name_split(name, 1, &prefix, NULL); 1340 switch (opt) { 1341 case CATZ_OPT_MASTERS: 1342 return (catz_process_masters(zone, &entry->opts.masters, value, 1343 &prefix)); 1344 case CATZ_OPT_ALLOW_QUERY: 1345 if (prefix.labels != 0) { 1346 return (ISC_R_FAILURE); 1347 } 1348 return (catz_process_apl(zone, &entry->opts.allow_query, 1349 value)); 1350 case CATZ_OPT_ALLOW_TRANSFER: 1351 if (prefix.labels != 0) { 1352 return (ISC_R_FAILURE); 1353 } 1354 return (catz_process_apl(zone, &entry->opts.allow_transfer, 1355 value)); 1356 default: 1357 return (ISC_R_FAILURE); 1358 } 1359 1360 return (ISC_R_FAILURE); 1361 } 1362 1363 static void 1364 catz_entry_add_or_mod(dns_catz_zone_t *target, isc_ht_t *ht, unsigned char *key, 1365 size_t keysize, dns_catz_entry_t *nentry, 1366 dns_catz_entry_t *oentry, const char *msg, 1367 const char *zname, const char *czname) { 1368 isc_result_t result = isc_ht_add(ht, key, (uint32_t)keysize, nentry); 1369 1370 if (result != ISC_R_SUCCESS) { 1371 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1372 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1373 "catz: error %s zone '%s' from catalog '%s' - %s", 1374 msg, zname, czname, isc_result_totext(result)); 1375 } 1376 if (oentry != NULL) { 1377 dns_catz_entry_detach(target, &oentry); 1378 result = isc_ht_delete(target->entries, key, (uint32_t)keysize); 1379 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1380 } 1381 } 1382 1383 static isc_result_t 1384 catz_process_value(dns_catz_zone_t *zone, dns_name_t *name, 1385 dns_rdataset_t *rdataset) { 1386 dns_label_t option; 1387 dns_name_t prefix; 1388 catz_opt_t opt; 1389 1390 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1391 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC)); 1392 REQUIRE(DNS_RDATASET_VALID(rdataset)); 1393 1394 dns_name_getlabel(name, name->labels - 1, &option); 1395 opt = catz_get_option(&option); 1396 dns_name_init(&prefix, NULL); 1397 dns_name_split(name, 1, &prefix, NULL); 1398 switch (opt) { 1399 case CATZ_OPT_ZONES: 1400 return (catz_process_zones(zone, rdataset, &prefix)); 1401 case CATZ_OPT_MASTERS: 1402 return (catz_process_masters(zone, &zone->zoneoptions.masters, 1403 rdataset, &prefix)); 1404 case CATZ_OPT_ALLOW_QUERY: 1405 if (prefix.labels != 0) { 1406 return (ISC_R_FAILURE); 1407 } 1408 return (catz_process_apl(zone, &zone->zoneoptions.allow_query, 1409 rdataset)); 1410 case CATZ_OPT_ALLOW_TRANSFER: 1411 if (prefix.labels != 0) { 1412 return (ISC_R_FAILURE); 1413 } 1414 return (catz_process_apl( 1415 zone, &zone->zoneoptions.allow_transfer, rdataset)); 1416 case CATZ_OPT_VERSION: 1417 if (prefix.labels != 0) { 1418 return (ISC_R_FAILURE); 1419 } 1420 return (catz_process_version(zone, rdataset)); 1421 default: 1422 return (ISC_R_FAILURE); 1423 } 1424 } 1425 1426 isc_result_t 1427 dns_catz_update_process(dns_catz_zones_t *catzs, dns_catz_zone_t *zone, 1428 const dns_name_t *src_name, dns_rdataset_t *rdataset) { 1429 isc_result_t result; 1430 int order; 1431 unsigned int nlabels; 1432 dns_namereln_t nrres; 1433 dns_rdata_t rdata = DNS_RDATA_INIT; 1434 dns_rdata_soa_t soa; 1435 dns_name_t prefix; 1436 1437 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 1438 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1439 REQUIRE(ISC_MAGIC_VALID(src_name, DNS_NAME_MAGIC)); 1440 1441 nrres = dns_name_fullcompare(src_name, &zone->name, &order, &nlabels); 1442 if (nrres == dns_namereln_equal) { 1443 if (rdataset->type == dns_rdatatype_soa) { 1444 result = dns_rdataset_first(rdataset); 1445 if (result != ISC_R_SUCCESS) { 1446 return (result); 1447 } 1448 1449 dns_rdataset_current(rdataset, &rdata); 1450 result = dns_rdata_tostruct(&rdata, &soa, NULL); 1451 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1452 1453 /* 1454 * xxxwpk TODO do we want to save something from SOA? 1455 */ 1456 return (result); 1457 } else if (rdataset->type == dns_rdatatype_ns) { 1458 return (ISC_R_SUCCESS); 1459 } else { 1460 return (ISC_R_UNEXPECTED); 1461 } 1462 } else if (nrres != dns_namereln_subdomain) { 1463 return (ISC_R_UNEXPECTED); 1464 } 1465 1466 dns_name_init(&prefix, NULL); 1467 dns_name_split(src_name, zone->name.labels, &prefix, NULL); 1468 result = catz_process_value(zone, &prefix, rdataset); 1469 1470 return (result); 1471 } 1472 1473 static isc_result_t 1474 digest2hex(unsigned char *digest, unsigned int digestlen, char *hash, 1475 size_t hashlen) { 1476 unsigned int i; 1477 int ret; 1478 for (i = 0; i < digestlen; i++) { 1479 size_t left = hashlen - i * 2; 1480 ret = snprintf(hash + i * 2, left, "%02x", digest[i]); 1481 if (ret < 0 || (size_t)ret >= left) { 1482 return (ISC_R_NOSPACE); 1483 } 1484 } 1485 return (ISC_R_SUCCESS); 1486 } 1487 1488 isc_result_t 1489 dns_catz_generate_masterfilename(dns_catz_zone_t *zone, dns_catz_entry_t *entry, 1490 isc_buffer_t **buffer) { 1491 isc_buffer_t *tbuf = NULL; 1492 isc_region_t r; 1493 isc_result_t result; 1494 size_t rlen; 1495 bool special = false; 1496 1497 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1498 REQUIRE(entry != NULL); 1499 REQUIRE(buffer != NULL && *buffer != NULL); 1500 1501 isc_buffer_allocate(zone->catzs->mctx, &tbuf, 1502 strlen(zone->catzs->view->name) + 1503 2 * DNS_NAME_FORMATSIZE + 2); 1504 1505 isc_buffer_putstr(tbuf, zone->catzs->view->name); 1506 isc_buffer_putstr(tbuf, "_"); 1507 result = dns_name_totext(&zone->name, true, tbuf); 1508 if (result != ISC_R_SUCCESS) { 1509 goto cleanup; 1510 } 1511 1512 isc_buffer_putstr(tbuf, "_"); 1513 result = dns_name_totext(&entry->name, true, tbuf); 1514 if (result != ISC_R_SUCCESS) { 1515 goto cleanup; 1516 } 1517 1518 /* 1519 * Search for slash and other special characters in the view and 1520 * zone names. Add a null terminator so we can use strpbrk(), then 1521 * remove it. 1522 */ 1523 isc_buffer_putuint8(tbuf, 0); 1524 if (strpbrk(isc_buffer_base(tbuf), "\\/:") != NULL) { 1525 special = true; 1526 } 1527 isc_buffer_subtract(tbuf, 1); 1528 1529 /* __catz__<digest>.db */ 1530 rlen = (isc_md_type_get_size(ISC_MD_SHA256) * 2 + 1) + 12; 1531 1532 /* optionally prepend with <zonedir>/ */ 1533 if (entry->opts.zonedir != NULL) { 1534 rlen += strlen(entry->opts.zonedir) + 1; 1535 } 1536 1537 result = isc_buffer_reserve(buffer, (unsigned int)rlen); 1538 if (result != ISC_R_SUCCESS) { 1539 goto cleanup; 1540 } 1541 1542 if (entry->opts.zonedir != NULL) { 1543 isc_buffer_putstr(*buffer, entry->opts.zonedir); 1544 isc_buffer_putstr(*buffer, "/"); 1545 } 1546 1547 isc_buffer_usedregion(tbuf, &r); 1548 isc_buffer_putstr(*buffer, "__catz__"); 1549 if (special || tbuf->used > ISC_SHA256_DIGESTLENGTH * 2 + 1) { 1550 unsigned char digest[ISC_MAX_MD_SIZE]; 1551 unsigned int digestlen; 1552 1553 /* we can do that because digest string < 2 * DNS_NAME */ 1554 result = isc_md(ISC_MD_SHA256, r.base, r.length, digest, 1555 &digestlen); 1556 if (result != ISC_R_SUCCESS) { 1557 goto cleanup; 1558 } 1559 result = digest2hex(digest, digestlen, (char *)r.base, 1560 ISC_SHA256_DIGESTLENGTH * 2 + 1); 1561 if (result != ISC_R_SUCCESS) { 1562 goto cleanup; 1563 } 1564 isc_buffer_putstr(*buffer, (char *)r.base); 1565 } else { 1566 isc_buffer_copyregion(*buffer, &r); 1567 } 1568 1569 isc_buffer_putstr(*buffer, ".db"); 1570 result = ISC_R_SUCCESS; 1571 1572 cleanup: 1573 isc_buffer_free(&tbuf); 1574 return (result); 1575 } 1576 1577 isc_result_t 1578 dns_catz_generate_zonecfg(dns_catz_zone_t *zone, dns_catz_entry_t *entry, 1579 isc_buffer_t **buf) { 1580 /* 1581 * We have to generate a text buffer with regular zone config: 1582 * zone "foo.bar" { 1583 * type slave; 1584 * masters [ dscp X ] { ip1 port port1; ip2 port port2; }; 1585 * } 1586 */ 1587 isc_buffer_t *buffer = NULL; 1588 isc_region_t region; 1589 isc_result_t result; 1590 uint32_t i; 1591 isc_netaddr_t netaddr; 1592 char pbuf[sizeof("65535")]; /* used both for port number and DSCP */ 1593 char zname[DNS_NAME_FORMATSIZE]; 1594 1595 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1596 REQUIRE(entry != NULL); 1597 REQUIRE(buf != NULL && *buf == NULL); 1598 1599 /* 1600 * The buffer will be reallocated if something won't fit, 1601 * ISC_BUFFER_INCR seems like a good start. 1602 */ 1603 isc_buffer_allocate(zone->catzs->mctx, &buffer, ISC_BUFFER_INCR); 1604 1605 isc_buffer_setautorealloc(buffer, true); 1606 isc_buffer_putstr(buffer, "zone \""); 1607 dns_name_totext(&entry->name, true, buffer); 1608 isc_buffer_putstr(buffer, "\" { type slave; masters"); 1609 1610 /* 1611 * DSCP value has no default, but when it is specified, it is identical 1612 * for all masters and cannot be overridden for a specific master IP, so 1613 * use the DSCP value set for the first master 1614 */ 1615 if (entry->opts.masters.count > 0 && entry->opts.masters.dscps[0] >= 0) 1616 { 1617 isc_buffer_putstr(buffer, " dscp "); 1618 snprintf(pbuf, sizeof(pbuf), "%hd", 1619 entry->opts.masters.dscps[0]); 1620 isc_buffer_putstr(buffer, pbuf); 1621 } 1622 1623 isc_buffer_putstr(buffer, " { "); 1624 for (i = 0; i < entry->opts.masters.count; i++) { 1625 /* 1626 * Every master must have an IP address assigned. 1627 */ 1628 switch (entry->opts.masters.addrs[i].type.sa.sa_family) { 1629 case AF_INET: 1630 case AF_INET6: 1631 break; 1632 default: 1633 dns_name_format(&entry->name, zname, 1634 DNS_NAME_FORMATSIZE); 1635 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1636 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1637 "catz: zone '%s' uses an invalid master " 1638 "(no IP address assigned)", 1639 zname); 1640 result = ISC_R_FAILURE; 1641 goto cleanup; 1642 } 1643 isc_netaddr_fromsockaddr(&netaddr, 1644 &entry->opts.masters.addrs[i]); 1645 isc_buffer_reserve(&buffer, INET6_ADDRSTRLEN); 1646 result = isc_netaddr_totext(&netaddr, buffer); 1647 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1648 1649 isc_buffer_putstr(buffer, " port "); 1650 snprintf(pbuf, sizeof(pbuf), "%u", 1651 isc_sockaddr_getport(&entry->opts.masters.addrs[i])); 1652 isc_buffer_putstr(buffer, pbuf); 1653 1654 if (entry->opts.masters.keys[i] != NULL) { 1655 isc_buffer_putstr(buffer, " key "); 1656 result = dns_name_totext(entry->opts.masters.keys[i], 1657 true, buffer); 1658 if (result != ISC_R_SUCCESS) { 1659 goto cleanup; 1660 } 1661 } 1662 isc_buffer_putstr(buffer, "; "); 1663 } 1664 isc_buffer_putstr(buffer, "}; "); 1665 if (!entry->opts.in_memory) { 1666 isc_buffer_putstr(buffer, "file \""); 1667 result = dns_catz_generate_masterfilename(zone, entry, &buffer); 1668 if (result != ISC_R_SUCCESS) { 1669 goto cleanup; 1670 } 1671 isc_buffer_putstr(buffer, "\"; "); 1672 } 1673 if (entry->opts.allow_query != NULL) { 1674 isc_buffer_putstr(buffer, "allow-query { "); 1675 isc_buffer_usedregion(entry->opts.allow_query, ®ion); 1676 isc_buffer_copyregion(buffer, ®ion); 1677 isc_buffer_putstr(buffer, "}; "); 1678 } 1679 if (entry->opts.allow_transfer != NULL) { 1680 isc_buffer_putstr(buffer, "allow-transfer { "); 1681 isc_buffer_usedregion(entry->opts.allow_transfer, ®ion); 1682 isc_buffer_copyregion(buffer, ®ion); 1683 isc_buffer_putstr(buffer, "}; "); 1684 } 1685 1686 isc_buffer_putstr(buffer, "};"); 1687 *buf = buffer; 1688 1689 return (ISC_R_SUCCESS); 1690 1691 cleanup: 1692 isc_buffer_free(&buffer); 1693 return (result); 1694 } 1695 1696 void 1697 dns_catz_update_taskaction(isc_task_t *task, isc_event_t *event) { 1698 isc_result_t result; 1699 dns_catz_zone_t *zone; 1700 (void)task; 1701 1702 REQUIRE(event != NULL); 1703 zone = event->ev_arg; 1704 REQUIRE(DNS_CATZ_ZONE_VALID(zone)); 1705 1706 LOCK(&zone->catzs->lock); 1707 zone->updatepending = false; 1708 dns_catz_update_from_db(zone->db, zone->catzs); 1709 result = isc_timer_reset(zone->updatetimer, isc_timertype_inactive, 1710 NULL, NULL, true); 1711 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1712 isc_event_free(&event); 1713 result = isc_time_now(&zone->lastupdated); 1714 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1715 UNLOCK(&zone->catzs->lock); 1716 } 1717 1718 isc_result_t 1719 dns_catz_dbupdate_callback(dns_db_t *db, void *fn_arg) { 1720 dns_catz_zones_t *catzs; 1721 dns_catz_zone_t *zone = NULL; 1722 isc_time_t now; 1723 uint64_t tdiff; 1724 isc_result_t result = ISC_R_SUCCESS; 1725 isc_region_t r; 1726 1727 REQUIRE(DNS_DB_VALID(db)); 1728 REQUIRE(fn_arg != NULL); 1729 catzs = (dns_catz_zones_t *)fn_arg; 1730 1731 dns_name_toregion(&db->origin, &r); 1732 1733 LOCK(&catzs->lock); 1734 result = isc_ht_find(catzs->zones, r.base, r.length, (void **)&zone); 1735 if (result != ISC_R_SUCCESS) { 1736 goto cleanup; 1737 } 1738 1739 /* New zone came as AXFR */ 1740 if (zone->db != NULL && zone->db != db) { 1741 if (zone->dbversion != NULL) { 1742 dns_db_closeversion(zone->db, &zone->dbversion, false); 1743 } 1744 dns_db_detach(&zone->db); 1745 /* 1746 * We're not registering db update callback, it will be 1747 * registered at the end of update_from_db 1748 */ 1749 zone->db_registered = false; 1750 } 1751 if (zone->db == NULL) { 1752 dns_db_attach(db, &zone->db); 1753 } 1754 1755 if (!zone->updatepending) { 1756 zone->updatepending = true; 1757 isc_time_now(&now); 1758 tdiff = isc_time_microdiff(&now, &zone->lastupdated) / 1000000; 1759 if (tdiff < zone->defoptions.min_update_interval) { 1760 isc_interval_t interval; 1761 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1762 DNS_LOGMODULE_MASTER, ISC_LOG_INFO, 1763 "catz: new zone version came too soon, " 1764 "deferring update"); 1765 isc_interval_set(&interval, 1766 zone->defoptions.min_update_interval - 1767 (unsigned int)tdiff, 1768 0); 1769 dns_db_currentversion(db, &zone->dbversion); 1770 result = isc_timer_reset(zone->updatetimer, 1771 isc_timertype_once, NULL, 1772 &interval, true); 1773 if (result != ISC_R_SUCCESS) { 1774 goto cleanup; 1775 } 1776 } else { 1777 isc_event_t *event; 1778 1779 dns_db_currentversion(db, &zone->dbversion); 1780 ISC_EVENT_INIT(&zone->updateevent, 1781 sizeof(zone->updateevent), 0, NULL, 1782 DNS_EVENT_CATZUPDATED, 1783 dns_catz_update_taskaction, zone, zone, 1784 NULL, NULL); 1785 event = &zone->updateevent; 1786 isc_task_send(catzs->updater, &event); 1787 } 1788 } else { 1789 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1790 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3), 1791 "catz: update already queued"); 1792 if (zone->dbversion != NULL) { 1793 dns_db_closeversion(zone->db, &zone->dbversion, false); 1794 } 1795 dns_db_currentversion(zone->db, &zone->dbversion); 1796 } 1797 1798 cleanup: 1799 UNLOCK(&catzs->lock); 1800 1801 return (result); 1802 } 1803 1804 static bool 1805 catz_rdatatype_is_processable(const dns_rdatatype_t type) { 1806 return (!dns_rdatatype_isdnssec(type) && type != dns_rdatatype_cds && 1807 type != dns_rdatatype_cdnskey && type != dns_rdatatype_zonemd); 1808 } 1809 1810 void 1811 dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) { 1812 dns_catz_zone_t *oldzone = NULL, *newzone = NULL; 1813 isc_result_t result; 1814 isc_region_t r; 1815 dns_dbnode_t *node = NULL; 1816 dns_dbiterator_t *it = NULL; 1817 dns_fixedname_t fixname; 1818 dns_name_t *name; 1819 dns_rdatasetiter_t *rdsiter = NULL; 1820 dns_rdataset_t rdataset; 1821 char bname[DNS_NAME_FORMATSIZE]; 1822 isc_buffer_t ibname; 1823 uint32_t vers; 1824 1825 REQUIRE(DNS_DB_VALID(db)); 1826 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 1827 1828 /* 1829 * Create a new catz in the same context as current catz. 1830 */ 1831 dns_name_toregion(&db->origin, &r); 1832 result = isc_ht_find(catzs->zones, r.base, r.length, (void **)&oldzone); 1833 if (result != ISC_R_SUCCESS) { 1834 /* This can happen if we remove the zone in the meantime. */ 1835 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1836 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1837 "catz: zone '%s' not in config", bname); 1838 return; 1839 } 1840 1841 isc_buffer_init(&ibname, bname, DNS_NAME_FORMATSIZE); 1842 result = dns_name_totext(&db->origin, true, &ibname); 1843 INSIST(result == ISC_R_SUCCESS); 1844 1845 result = dns_db_getsoaserial(db, oldzone->dbversion, &vers); 1846 if (result != ISC_R_SUCCESS) { 1847 /* A zone without SOA record?!? */ 1848 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1849 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1850 "catz: zone '%s' has no SOA record (%s)", bname, 1851 isc_result_totext(result)); 1852 return; 1853 } 1854 1855 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, 1856 ISC_LOG_INFO, 1857 "catz: updating catalog zone '%s' with serial %d", bname, 1858 vers); 1859 1860 result = dns_catz_new_zone(catzs, &newzone, &db->origin); 1861 if (result != ISC_R_SUCCESS) { 1862 dns_db_closeversion(db, &oldzone->dbversion, false); 1863 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1864 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1865 "catz: failed to create new zone - %s", 1866 isc_result_totext(result)); 1867 return; 1868 } 1869 1870 result = dns_db_createiterator(db, DNS_DB_NONSEC3, &it); 1871 if (result != ISC_R_SUCCESS) { 1872 dns_catz_zone_detach(&newzone); 1873 dns_db_closeversion(db, &oldzone->dbversion, false); 1874 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1875 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1876 "catz: failed to create DB iterator - %s", 1877 isc_result_totext(result)); 1878 return; 1879 } 1880 1881 name = dns_fixedname_initname(&fixname); 1882 1883 /* 1884 * Iterate over database to fill the new zone. 1885 */ 1886 result = dns_dbiterator_first(it); 1887 if (result != ISC_R_SUCCESS) { 1888 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1889 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1890 "catz: failed to get db iterator - %s", 1891 isc_result_totext(result)); 1892 } 1893 1894 while (result == ISC_R_SUCCESS) { 1895 result = dns_dbiterator_current(it, &node, name); 1896 if (result != ISC_R_SUCCESS) { 1897 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1898 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1899 "catz: failed to get db iterator - %s", 1900 isc_result_totext(result)); 1901 break; 1902 } 1903 1904 result = dns_db_allrdatasets(db, node, oldzone->dbversion, 0, 1905 &rdsiter); 1906 if (result != ISC_R_SUCCESS) { 1907 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1908 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1909 "catz: failed to fetch rrdatasets - %s", 1910 isc_result_totext(result)); 1911 dns_db_detachnode(db, &node); 1912 break; 1913 } 1914 1915 dns_rdataset_init(&rdataset); 1916 result = dns_rdatasetiter_first(rdsiter); 1917 while (result == ISC_R_SUCCESS) { 1918 dns_rdatasetiter_current(rdsiter, &rdataset); 1919 1920 /* 1921 * Skip processing DNSSEC-related and ZONEMD types, 1922 * because we are not interested in them in the context 1923 * of a catalog zone, and processing them will fail 1924 * and produce an unnecessary warning message. 1925 */ 1926 if (!catz_rdatatype_is_processable(rdataset.type)) { 1927 goto next; 1928 } 1929 1930 result = dns_catz_update_process(catzs, newzone, name, 1931 &rdataset); 1932 if (result != ISC_R_SUCCESS) { 1933 char cname[DNS_NAME_FORMATSIZE]; 1934 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 1935 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 1936 1937 dns_name_format(name, cname, 1938 DNS_NAME_FORMATSIZE); 1939 dns_rdataclass_format(rdataset.rdclass, 1940 classbuf, 1941 sizeof(classbuf)); 1942 dns_rdatatype_format(rdataset.type, typebuf, 1943 sizeof(typebuf)); 1944 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1945 DNS_LOGMODULE_MASTER, 1946 ISC_LOG_WARNING, 1947 "catz: unknown record in catalog " 1948 "zone - %s %s %s(%s) - ignoring", 1949 cname, classbuf, typebuf, 1950 isc_result_totext(result)); 1951 } 1952 next: 1953 dns_rdataset_disassociate(&rdataset); 1954 result = dns_rdatasetiter_next(rdsiter); 1955 } 1956 1957 dns_rdatasetiter_destroy(&rdsiter); 1958 1959 dns_db_detachnode(db, &node); 1960 result = dns_dbiterator_next(it); 1961 } 1962 1963 dns_dbiterator_destroy(&it); 1964 dns_db_closeversion(db, &oldzone->dbversion, false); 1965 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, 1966 ISC_LOG_DEBUG(3), 1967 "catz: update_from_db: iteration finished"); 1968 1969 /* 1970 * Finally merge new zone into old zone. 1971 */ 1972 result = dns_catz_zones_merge(oldzone, newzone); 1973 dns_catz_zone_detach(&newzone); 1974 if (result != ISC_R_SUCCESS) { 1975 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1976 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, 1977 "catz: failed merging zones: %s", 1978 isc_result_totext(result)); 1979 1980 return; 1981 } 1982 1983 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, 1984 ISC_LOG_DEBUG(3), 1985 "catz: update_from_db: new zone merged"); 1986 1987 /* 1988 * When we're doing reconfig and setting a new catalog zone 1989 * from an existing zone we won't have a chance to set up 1990 * update callback in zone_startload or axfr_makedb, but we will 1991 * call onupdate() artificially so we can register the callback here. 1992 */ 1993 if (!oldzone->db_registered) { 1994 result = dns_db_updatenotify_register( 1995 db, dns_catz_dbupdate_callback, oldzone->catzs); 1996 if (result == ISC_R_SUCCESS) { 1997 oldzone->db_registered = true; 1998 } 1999 } 2000 } 2001 2002 void 2003 dns_catz_prereconfig(dns_catz_zones_t *catzs) { 2004 isc_result_t result; 2005 isc_ht_iter_t *iter = NULL; 2006 2007 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 2008 2009 isc_ht_iter_create(catzs->zones, &iter); 2010 for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS; 2011 result = isc_ht_iter_next(iter)) 2012 { 2013 dns_catz_zone_t *zone = NULL; 2014 isc_ht_iter_current(iter, (void **)&zone); 2015 zone->active = false; 2016 } 2017 INSIST(result == ISC_R_NOMORE); 2018 isc_ht_iter_destroy(&iter); 2019 } 2020 2021 void 2022 dns_catz_postreconfig(dns_catz_zones_t *catzs) { 2023 isc_result_t result; 2024 dns_catz_zone_t *newzone = NULL; 2025 isc_ht_iter_t *iter = NULL; 2026 2027 REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); 2028 2029 LOCK(&catzs->lock); 2030 isc_ht_iter_create(catzs->zones, &iter); 2031 for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;) { 2032 dns_catz_zone_t *zone = NULL; 2033 2034 isc_ht_iter_current(iter, (void **)&zone); 2035 if (!zone->active) { 2036 char cname[DNS_NAME_FORMATSIZE]; 2037 dns_name_format(&zone->name, cname, 2038 DNS_NAME_FORMATSIZE); 2039 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 2040 DNS_LOGMODULE_MASTER, ISC_LOG_WARNING, 2041 "catz: removing catalog zone %s", cname); 2042 2043 /* 2044 * Merge the old zone with an empty one to remove 2045 * all members. 2046 */ 2047 result = dns_catz_new_zone(catzs, &newzone, 2048 &zone->name); 2049 INSIST(result == ISC_R_SUCCESS); 2050 dns_catz_zones_merge(zone, newzone); 2051 dns_catz_zone_detach(&newzone); 2052 2053 /* Make sure that we have an empty catalog zone. */ 2054 INSIST(isc_ht_count(zone->entries) == 0); 2055 result = isc_ht_iter_delcurrent_next(iter); 2056 dns_catz_zone_detach(&zone); 2057 } else { 2058 result = isc_ht_iter_next(iter); 2059 } 2060 } 2061 UNLOCK(&catzs->lock); 2062 RUNTIME_CHECK(result == ISC_R_NOMORE); 2063 isc_ht_iter_destroy(&iter); 2064 } 2065 2066 void 2067 dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp) { 2068 REQUIRE(DNS_CATZ_ZONE_VALID(catz)); 2069 2070 isc_ht_iter_create(catz->entries, itp); 2071 } 2072