1/* 2 * Copyright (C) 2004-2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2002 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <isc/file.h> 25#include <isc/magic.h> 26#include <isc/mem.h> 27#include <isc/string.h> 28#include <isc/util.h> 29 30#include <dns/log.h> 31#include <dns/name.h> 32#include <dns/rbt.h> 33#include <dns/rdataclass.h> 34#include <dns/result.h> 35#include <dns/view.h> 36#include <dns/zone.h> 37#include <dns/zt.h> 38 39struct dns_zt { 40 /* Unlocked. */ 41 unsigned int magic; 42 isc_mem_t *mctx; 43 dns_rdataclass_t rdclass; 44 isc_rwlock_t rwlock; 45 /* Locked by lock. */ 46 isc_uint32_t references; 47 dns_rbt_t *table; 48}; 49 50#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l') 51#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC) 52 53static void 54auto_detach(void *, void *); 55 56static isc_result_t 57load(dns_zone_t *zone, void *uap); 58 59static isc_result_t 60loadnew(dns_zone_t *zone, void *uap); 61 62static isc_result_t 63freezezones(dns_zone_t *zone, void *uap); 64 65isc_result_t 66dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) 67{ 68 dns_zt_t *zt; 69 isc_result_t result; 70 71 REQUIRE(ztp != NULL && *ztp == NULL); 72 73 zt = isc_mem_get(mctx, sizeof(*zt)); 74 if (zt == NULL) 75 return (ISC_R_NOMEMORY); 76 77 zt->table = NULL; 78 result = dns_rbt_create(mctx, auto_detach, zt, &zt->table); 79 if (result != ISC_R_SUCCESS) 80 goto cleanup_zt; 81 82 result = isc_rwlock_init(&zt->rwlock, 0, 0); 83 if (result != ISC_R_SUCCESS) 84 goto cleanup_rbt; 85 86 zt->mctx = mctx; 87 zt->references = 1; 88 zt->rdclass = rdclass; 89 zt->magic = ZTMAGIC; 90 *ztp = zt; 91 92 return (ISC_R_SUCCESS); 93 94 cleanup_rbt: 95 dns_rbt_destroy(&zt->table); 96 97 cleanup_zt: 98 isc_mem_put(mctx, zt, sizeof(*zt)); 99 100 return (result); 101} 102 103isc_result_t 104dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) { 105 isc_result_t result; 106 dns_zone_t *dummy = NULL; 107 dns_name_t *name; 108 109 REQUIRE(VALID_ZT(zt)); 110 111 name = dns_zone_getorigin(zone); 112 113 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 114 115 result = dns_rbt_addname(zt->table, name, zone); 116 if (result == ISC_R_SUCCESS) 117 dns_zone_attach(zone, &dummy); 118 119 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 120 121 return (result); 122} 123 124isc_result_t 125dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) { 126 isc_result_t result; 127 dns_name_t *name; 128 129 REQUIRE(VALID_ZT(zt)); 130 131 name = dns_zone_getorigin(zone); 132 133 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 134 135 result = dns_rbt_deletename(zt->table, name, ISC_FALSE); 136 137 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 138 139 return (result); 140} 141 142isc_result_t 143dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options, 144 dns_name_t *foundname, dns_zone_t **zonep) 145{ 146 isc_result_t result; 147 dns_zone_t *dummy = NULL; 148 unsigned int rbtoptions = 0; 149 150 REQUIRE(VALID_ZT(zt)); 151 152 if ((options & DNS_ZTFIND_NOEXACT) != 0) 153 rbtoptions |= DNS_RBTFIND_NOEXACT; 154 155 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 156 157 result = dns_rbt_findname(zt->table, name, rbtoptions, foundname, 158 (void **) (void*)&dummy); 159 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) 160 dns_zone_attach(dummy, zonep); 161 162 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 163 164 return (result); 165} 166 167void 168dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) { 169 170 REQUIRE(VALID_ZT(zt)); 171 REQUIRE(ztp != NULL && *ztp == NULL); 172 173 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 174 175 INSIST(zt->references > 0); 176 zt->references++; 177 INSIST(zt->references != 0); 178 179 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 180 181 *ztp = zt; 182} 183 184static isc_result_t 185flush(dns_zone_t *zone, void *uap) { 186 UNUSED(uap); 187 return (dns_zone_flush(zone)); 188} 189 190static void 191zt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) { 192 isc_boolean_t destroy = ISC_FALSE; 193 dns_zt_t *zt; 194 195 REQUIRE(ztp != NULL && VALID_ZT(*ztp)); 196 197 zt = *ztp; 198 199 RWLOCK(&zt->rwlock, isc_rwlocktype_write); 200 201 INSIST(zt->references > 0); 202 zt->references--; 203 if (zt->references == 0) 204 destroy = ISC_TRUE; 205 206 RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 207 208 if (destroy) { 209 if (need_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_put(zt->mctx, zt, sizeof(*zt)); 215 } 216 217 *ztp = NULL; 218} 219 220void 221dns_zt_flushanddetach(dns_zt_t **ztp) { 222 zt_flushanddetach(ztp, ISC_TRUE); 223} 224 225void 226dns_zt_detach(dns_zt_t **ztp) { 227 zt_flushanddetach(ztp, ISC_FALSE); 228} 229 230isc_result_t 231dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) { 232 isc_result_t result; 233 234 REQUIRE(VALID_ZT(zt)); 235 236 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 237 result = dns_zt_apply(zt, stop, load, NULL); 238 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 239 return (result); 240} 241 242static isc_result_t 243load(dns_zone_t *zone, void *uap) { 244 isc_result_t result; 245 UNUSED(uap); 246 result = dns_zone_load(zone); 247 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE) 248 result = ISC_R_SUCCESS; 249 return (result); 250} 251 252isc_result_t 253dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) { 254 isc_result_t result; 255 256 REQUIRE(VALID_ZT(zt)); 257 258 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 259 result = dns_zt_apply(zt, stop, loadnew, NULL); 260 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 261 return (result); 262} 263 264static isc_result_t 265loadnew(dns_zone_t *zone, void *uap) { 266 isc_result_t result; 267 UNUSED(uap); 268 result = dns_zone_loadnew(zone); 269 if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE || 270 result == DNS_R_DYNAMIC) 271 result = ISC_R_SUCCESS; 272 return (result); 273} 274 275isc_result_t 276dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) { 277 isc_result_t result, tresult; 278 279 REQUIRE(VALID_ZT(zt)); 280 281 RWLOCK(&zt->rwlock, isc_rwlocktype_read); 282 result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze); 283 RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 284 return ((result == ISC_R_SUCCESS) ? tresult : result); 285} 286 287static isc_result_t 288freezezones(dns_zone_t *zone, void *uap) { 289 isc_boolean_t freeze = *(isc_boolean_t *)uap; 290 isc_boolean_t frozen; 291 isc_result_t result = ISC_R_SUCCESS; 292 char classstr[DNS_RDATACLASS_FORMATSIZE]; 293 char zonename[DNS_NAME_FORMATSIZE]; 294 dns_view_t *view; 295 char *journal; 296 const char *vname; 297 const char *sep; 298 int level; 299 300 if (dns_zone_gettype(zone) != dns_zone_master) 301 return (ISC_R_SUCCESS); 302 303 frozen = dns_zone_getupdatedisabled(zone); 304 if (freeze) { 305 if (frozen) 306 result = DNS_R_FROZEN; 307 if (result == ISC_R_SUCCESS) 308 result = dns_zone_flush(zone); 309 if (result == ISC_R_SUCCESS) { 310 journal = dns_zone_getjournal(zone); 311 if (journal != NULL) 312 (void)isc_file_remove(journal); 313 } 314 } else { 315 if (frozen) { 316 result = dns_zone_load(zone); 317 if (result == DNS_R_CONTINUE || 318 result == DNS_R_UPTODATE) 319 result = ISC_R_SUCCESS; 320 } 321 } 322 if (result == ISC_R_SUCCESS) 323 dns_zone_setupdatedisabled(zone, freeze); 324 view = dns_zone_getview(zone); 325 if (strcmp(view->name, "_bind") == 0 || 326 strcmp(view->name, "_default") == 0) 327 { 328 vname = ""; 329 sep = ""; 330 } else { 331 vname = view->name; 332 sep = " "; 333 } 334 dns_rdataclass_format(dns_zone_getclass(zone), classstr, 335 sizeof(classstr)); 336 dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); 337 level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1); 338 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, 339 level, "%s zone '%s/%s'%s%s: %s", 340 freeze ? "freezing" : "thawing", 341 zonename, classstr, sep, vname, 342 isc_result_totext(result)); 343 return (result); 344} 345 346isc_result_t 347dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop, 348 isc_result_t (*action)(dns_zone_t *, void *), void *uap) 349{ 350 return (dns_zt_apply2(zt, stop, NULL, action, uap)); 351} 352 353isc_result_t 354dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub, 355 isc_result_t (*action)(dns_zone_t *, void *), void *uap) 356{ 357 dns_rbtnode_t *node; 358 dns_rbtnodechain_t chain; 359 isc_result_t result, tresult = ISC_R_SUCCESS; 360 dns_zone_t *zone; 361 362 REQUIRE(VALID_ZT(zt)); 363 REQUIRE(action != NULL); 364 365 dns_rbtnodechain_init(&chain, zt->mctx); 366 result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); 367 if (result == ISC_R_NOTFOUND) { 368 /* 369 * The tree is empty. 370 */ 371 result = ISC_R_NOMORE; 372 } 373 while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 374 result = dns_rbtnodechain_current(&chain, NULL, NULL, 375 &node); 376 if (result == ISC_R_SUCCESS) { 377 zone = node->data; 378 if (zone != NULL) 379 result = (action)(zone, uap); 380 if (result != ISC_R_SUCCESS && stop) { 381 tresult = result; 382 goto cleanup; /* don't break */ 383 } else if (result != ISC_R_SUCCESS && 384 tresult == ISC_R_SUCCESS) 385 tresult = result; 386 } 387 result = dns_rbtnodechain_next(&chain, NULL, NULL); 388 } 389 if (result == ISC_R_NOMORE) 390 result = ISC_R_SUCCESS; 391 392 cleanup: 393 dns_rbtnodechain_invalidate(&chain); 394 if (sub != NULL) 395 *sub = tresult; 396 397 return (result); 398} 399 400/*** 401 *** Private 402 ***/ 403 404static void 405auto_detach(void *data, void *arg) { 406 dns_zone_t *zone = data; 407 408 UNUSED(arg); 409 410 dns_zone_detach(&zone); 411} 412