1 /* $NetBSD: zt.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004-2007, 2011-2015 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2002 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <isc/file.h> 27 #include <isc/magic.h> 28 #include <isc/mem.h> 29 #include <isc/string.h> 30 #include <isc/task.h> 31 #include <isc/util.h> 32 33 #include <dns/log.h> 34 #include <dns/name.h> 35 #include <dns/rbt.h> 36 #include <dns/rdataclass.h> 37 #include <dns/result.h> 38 #include <dns/view.h> 39 #include <dns/zone.h> 40 #include <dns/zt.h> 41 42 struct dns_zt { 43 /* Unlocked. */ 44 unsigned int magic; 45 isc_mem_t *mctx; 46 dns_rdataclass_t rdclass; 47 isc_rwlock_t rwlock; 48 dns_zt_allloaded_t loaddone; 49 void * loaddone_arg; 50 /* Locked by lock. */ 51 isc_boolean_t flush; 52 isc_uint32_t references; 53 unsigned int loads_pending; 54 dns_rbt_t *table; 55 }; 56 57 #define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l') 58 #define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC) 59 60 static void 61 auto_detach(void *, void *); 62 63 static isc_result_t 64 load(dns_zone_t *zone, void *uap); 65 66 static isc_result_t 67 asyncload(dns_zone_t *zone, void *callback); 68 69 static isc_result_t 70 loadnew(dns_zone_t *zone, void *uap); 71 72 static isc_result_t 73 freezezones(dns_zone_t *zone, void *uap); 74 75 static isc_result_t 76 doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task); 77 78 isc_result_t 79 dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) { 80 dns_zt_t *zt; 81 isc_result_t result; 82 83 REQUIRE(ztp != NULL && *ztp == NULL); 84 85 zt = isc_mem_get(mctx, sizeof(*zt)); 86 if (zt == NULL) 87 return (ISC_R_NOMEMORY); 88 89 zt->table = NULL; 90 result = dns_rbt_create(mctx, auto_detach, zt, &zt->table); 91 if (result != ISC_R_SUCCESS) 92 goto cleanup_zt; 93 94 result = isc_rwlock_init(&zt->rwlock, 0, 0); 95 if (result != ISC_R_SUCCESS) 96 goto cleanup_rbt; 97 98 zt->mctx = NULL; 99 isc_mem_attach(mctx, &zt->mctx); 100 zt->references = 1; 101 zt->flush = ISC_FALSE; 102 zt->rdclass = rdclass; 103 zt->magic = ZTMAGIC; 104 zt->loaddone = NULL; 105 zt->loaddone_arg = NULL; 106 zt->loads_pending = 0; 107 *ztp = zt; 108 109 return (ISC_R_SUCCESS); 110 111 cleanup_rbt: 112 dns_rbt_destroy(&zt->table); 113 114 cleanup_zt: 115 isc_mem_put(mctx, zt, sizeof(*zt)); 116 117 return (result); 118 } 119 120 isc_result_t 121 dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) { 122 isc_result_t result; 123 dns_zone_t *dummy = NULL; 124 dns_name_t *name; 125 126 REQUIRE(VALID_ZT(zt)); 127 128 name = dns_zone_getorigin(zone); 129 130 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 131 132 result = dns_rbt_addname(zt->table, name, zone); 133 if (result == ISC_R_SUCCESS) 134 dns_zone_attach(zone, &dummy); 135 136 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 137 138 return (result); 139 } 140 141 isc_result_t 142 dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) { 143 isc_result_t result; 144 dns_name_t *name; 145 146 REQUIRE(VALID_ZT(zt)); 147 148 name = dns_zone_getorigin(zone); 149 150 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 151 152 result = dns_rbt_deletename(zt->table, name, ISC_FALSE); 153 154 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 155 156 return (result); 157 } 158 159 isc_result_t 160 dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options, 161 dns_name_t *foundname, dns_zone_t **zonep) 162 { 163 isc_result_t result; 164 dns_zone_t *dummy = NULL; 165 unsigned int rbtoptions = 0; 166 167 REQUIRE(VALID_ZT(zt)); 168 169 if ((options & DNS_ZTFIND_NOEXACT) != 0) 170 rbtoptions |= DNS_RBTFIND_NOEXACT; 171 172 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 173 174 result = dns_rbt_findname(zt->table, name, rbtoptions, foundname, 175 (void **) (void*)&dummy); 176 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) 177 dns_zone_attach(dummy, zonep); 178 179 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 180 181 return (result); 182 } 183 184 void 185 dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) { 186 187 REQUIRE(VALID_ZT(zt)); 188 REQUIRE(ztp != NULL && *ztp == NULL); 189 190 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 191 192 INSIST(zt->references > 0); 193 zt->references++; 194 INSIST(zt->references != 0); 195 196 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 197 198 *ztp = zt; 199 } 200 201 static isc_result_t 202 flush(dns_zone_t *zone, void *uap) { 203 UNUSED(uap); 204 return (dns_zone_flush(zone)); 205 } 206 207 static void 208 zt_destroy(dns_zt_t *zt) { 209 if (zt->flush) 210 (void)dns_zt_apply(zt, ISC_FALSE, flush, NULL); 211 dns_rbt_destroy(&zt->table); 212 isc_rwlock_destroy(&zt->rwlock); 213 zt->magic = 0; 214 isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt)); 215 } 216 217 static void 218 zt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) { 219 isc_boolean_t destroy = ISC_FALSE; 220 dns_zt_t *zt; 221 222 REQUIRE(ztp != NULL && VALID_ZT(*ztp)); 223 224 zt = *ztp; 225 226 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 227 228 INSIST(zt->references > 0); 229 zt->references--; 230 if (zt->references == 0) 231 destroy = ISC_TRUE; 232 if (need_flush) 233 zt->flush = ISC_TRUE; 234 235 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 236 237 if (destroy) 238 zt_destroy(zt); 239 240 *ztp = NULL; 241 } 242 243 void 244 dns_zt_flushanddetach(dns_zt_t **ztp) { 245 zt_flushanddetach(ztp, ISC_TRUE); 246 } 247 248 void 249 dns_zt_detach(dns_zt_t **ztp) { 250 zt_flushanddetach(ztp, ISC_FALSE); 251 } 252 253 isc_result_t 254 dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) { 255 isc_result_t result; 256 257 REQUIRE(VALID_ZT(zt)); 258 259 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 260 result = dns_zt_apply(zt, stop, load, NULL); 261 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 262 return (result); 263 } 264 265 static isc_result_t 266 load(dns_zone_t *zone, void *uap) { 267 isc_result_t result; 268 UNUSED(uap); 269 270 result = dns_zone_load(zone); 271 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE) 272 result = ISC_R_SUCCESS; 273 274 return (result); 275 } 276 277 isc_result_t 278 dns_zt_asyncload(dns_zt_t *zt, dns_zt_allloaded_t alldone, void *arg) { 279 isc_result_t result; 280 static dns_zt_zoneloaded_t dl = doneloading; 281 int pending; 282 283 REQUIRE(VALID_ZT(zt)); 284 285 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 286 287 INSIST(zt->loads_pending == 0); 288 result = dns_zt_apply2(zt, ISC_FALSE, NULL, asyncload, &dl); 289 290 pending = zt->loads_pending; 291 if (pending != 0) { 292 zt->loaddone = alldone; 293 zt->loaddone_arg = arg; 294 } 295 296 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 297 298 if (pending == 0) 299 alldone(arg); 300 301 return (result); 302 } 303 304 /* 305 * Initiates asynchronous loading of zone 'zone'. 'callback' is a 306 * pointer to a function which will be used to inform the caller when 307 * the zone loading is complete. 308 */ 309 static isc_result_t 310 asyncload(dns_zone_t *zone, void *callback) { 311 isc_result_t result; 312 dns_zt_zoneloaded_t *loaded = callback; 313 dns_zt_t *zt; 314 315 REQUIRE(zone != NULL); 316 zt = dns_zone_getview(zone)->zonetable; 317 INSIST(VALID_ZT(zt)); 318 319 INSIST(zt->references > 0); 320 zt->references++; 321 zt->loads_pending++; 322 323 result = dns_zone_asyncload(zone, *loaded, zt); 324 if (result != ISC_R_SUCCESS) { 325 zt->references--; 326 zt->loads_pending--; 327 INSIST(zt->references > 0); 328 } 329 return (ISC_R_SUCCESS); 330 } 331 332 isc_result_t 333 dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) { 334 isc_result_t result; 335 336 REQUIRE(VALID_ZT(zt)); 337 338 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 339 result = dns_zt_apply(zt, stop, loadnew, NULL); 340 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 341 return (result); 342 } 343 344 static isc_result_t 345 loadnew(dns_zone_t *zone, void *uap) { 346 isc_result_t result; 347 UNUSED(uap); 348 349 result = dns_zone_loadnew(zone); 350 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE || 351 result == DNS_R_DYNAMIC) 352 result = ISC_R_SUCCESS; 353 return (result); 354 } 355 356 isc_result_t 357 dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) { 358 isc_result_t result, tresult; 359 360 REQUIRE(VALID_ZT(zt)); 361 362 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 363 result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze); 364 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 365 if (tresult == ISC_R_NOTFOUND) 366 tresult = ISC_R_SUCCESS; 367 return ((result == ISC_R_SUCCESS) ? tresult : result); 368 } 369 370 static isc_result_t 371 freezezones(dns_zone_t *zone, void *uap) { 372 isc_boolean_t freeze = *(isc_boolean_t *)uap; 373 isc_boolean_t frozen; 374 isc_result_t result = ISC_R_SUCCESS; 375 char classstr[DNS_RDATACLASS_FORMATSIZE]; 376 char zonename[DNS_NAME_FORMATSIZE]; 377 dns_zone_t *raw = NULL; 378 dns_view_t *view; 379 const char *vname; 380 const char *sep; 381 int level; 382 383 dns_zone_getraw(zone, &raw); 384 if (raw != NULL) 385 zone = raw; 386 if (dns_zone_gettype(zone) != dns_zone_master) { 387 if (raw != NULL) 388 dns_zone_detach(&raw); 389 return (ISC_R_SUCCESS); 390 } 391 if (!dns_zone_isdynamic(zone, ISC_TRUE)) { 392 if (raw != NULL) 393 dns_zone_detach(&raw); 394 return (ISC_R_SUCCESS); 395 } 396 397 frozen = dns_zone_getupdatedisabled(zone); 398 if (freeze) { 399 if (frozen) 400 result = DNS_R_FROZEN; 401 if (result == ISC_R_SUCCESS) 402 result = dns_zone_flush(zone); 403 if (result == ISC_R_SUCCESS) 404 dns_zone_setupdatedisabled(zone, freeze); 405 } else { 406 if (frozen) { 407 result = dns_zone_loadandthaw(zone); 408 if (result == DNS_R_CONTINUE || 409 result == DNS_R_UPTODATE) 410 result = ISC_R_SUCCESS; 411 } 412 } 413 view = dns_zone_getview(zone); 414 if (strcmp(view->name, "_bind") == 0 || 415 strcmp(view->name, "_default") == 0) 416 { 417 vname = ""; 418 sep = ""; 419 } else { 420 vname = view->name; 421 sep = " "; 422 } 423 dns_rdataclass_format(dns_zone_getclass(zone), classstr, 424 sizeof(classstr)); 425 dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); 426 level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1); 427 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, 428 level, "%s zone '%s/%s'%s%s: %s", 429 freeze ? "freezing" : "thawing", 430 zonename, classstr, sep, vname, 431 isc_result_totext(result)); 432 if (raw != NULL) 433 dns_zone_detach(&raw); 434 return (result); 435 } 436 437 isc_result_t 438 dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop, 439 isc_result_t (*action)(dns_zone_t *, void *), void *uap) 440 { 441 return (dns_zt_apply2(zt, stop, NULL, action, uap)); 442 } 443 444 isc_result_t 445 dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub, 446 isc_result_t (*action)(dns_zone_t *, void *), void *uap) 447 { 448 dns_rbtnode_t *node; 449 dns_rbtnodechain_t chain; 450 isc_result_t result, tresult = ISC_R_SUCCESS; 451 dns_zone_t *zone; 452 453 REQUIRE(VALID_ZT(zt)); 454 REQUIRE(action != NULL); 455 456 dns_rbtnodechain_init(&chain, zt->mctx); 457 result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); 458 if (result == ISC_R_NOTFOUND) { 459 /* 460 * The tree is empty. 461 */ 462 tresult = result; 463 result = ISC_R_NOMORE; 464 } 465 while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 466 result = dns_rbtnodechain_current(&chain, NULL, NULL, 467 &node); 468 if (result == ISC_R_SUCCESS) { 469 zone = node->data; 470 if (zone != NULL) 471 result = (action)(zone, uap); 472 if (result != ISC_R_SUCCESS && stop) { 473 tresult = result; 474 goto cleanup; /* don't break */ 475 } else if (result != ISC_R_SUCCESS && 476 tresult == ISC_R_SUCCESS) 477 tresult = result; 478 } 479 result = dns_rbtnodechain_next(&chain, NULL, NULL); 480 } 481 if (result == ISC_R_NOMORE) 482 result = ISC_R_SUCCESS; 483 484 cleanup: 485 dns_rbtnodechain_invalidate(&chain); 486 if (sub != NULL) 487 *sub = tresult; 488 489 return (result); 490 } 491 492 /* 493 * Decrement the loads_pending counter; when counter reaches 494 * zero, call the loaddone callback that was initially set by 495 * dns_zt_asyncload(). 496 */ 497 static isc_result_t 498 doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) { 499 isc_boolean_t destroy = ISC_FALSE; 500 dns_zt_allloaded_t alldone = NULL; 501 void *arg = NULL; 502 503 UNUSED(zone); 504 UNUSED(task); 505 506 REQUIRE(VALID_ZT(zt)); 507 508 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 509 INSIST(zt->loads_pending != 0); 510 INSIST(zt->references != 0); 511 zt->references--; 512 if (zt->references == 0) 513 destroy = ISC_TRUE; 514 zt->loads_pending--; 515 if (zt->loads_pending == 0) { 516 alldone = zt->loaddone; 517 arg = zt->loaddone_arg; 518 zt->loaddone = NULL; 519 zt->loaddone_arg = NULL; 520 } 521 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 522 523 if (alldone != NULL) 524 alldone(arg); 525 526 if (destroy) 527 zt_destroy(zt); 528 529 return (ISC_R_SUCCESS); 530 } 531 532 /*** 533 *** Private 534 ***/ 535 536 static void 537 auto_detach(void *data, void *arg) { 538 dns_zone_t *zone = data; 539 540 UNUSED(arg); 541 dns_zone_detach(&zone); 542 } 543