zt.c revision 193149
1135446Strhodes/* 2193149Sdougb * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2002 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18193149Sdougb/* $Id: zt.c,v 1.47 2007/06/19 23:47:16 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24170222Sdougb#include <isc/file.h> 25135446Strhodes#include <isc/magic.h> 26135446Strhodes#include <isc/mem.h> 27170222Sdougb#include <isc/string.h> 28135446Strhodes#include <isc/util.h> 29135446Strhodes 30170222Sdougb#include <dns/log.h> 31170222Sdougb#include <dns/name.h> 32135446Strhodes#include <dns/rbt.h> 33170222Sdougb#include <dns/rdataclass.h> 34135446Strhodes#include <dns/result.h> 35170222Sdougb#include <dns/view.h> 36135446Strhodes#include <dns/zone.h> 37135446Strhodes#include <dns/zt.h> 38135446Strhodes 39135446Strhodesstruct dns_zt { 40135446Strhodes /* Unlocked. */ 41135446Strhodes unsigned int magic; 42135446Strhodes isc_mem_t *mctx; 43135446Strhodes dns_rdataclass_t rdclass; 44135446Strhodes isc_rwlock_t rwlock; 45135446Strhodes /* Locked by lock. */ 46135446Strhodes isc_uint32_t references; 47135446Strhodes dns_rbt_t *table; 48135446Strhodes}; 49135446Strhodes 50135446Strhodes#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l') 51135446Strhodes#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC) 52135446Strhodes 53135446Strhodesstatic void 54135446Strhodesauto_detach(void *, void *); 55135446Strhodes 56135446Strhodesstatic isc_result_t 57135446Strhodesload(dns_zone_t *zone, void *uap); 58135446Strhodes 59135446Strhodesstatic isc_result_t 60135446Strhodesloadnew(dns_zone_t *zone, void *uap); 61135446Strhodes 62170222Sdougbstatic isc_result_t 63170222Sdougbfreezezones(dns_zone_t *zone, void *uap); 64170222Sdougb 65135446Strhodesisc_result_t 66193149Sdougbdns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) 67193149Sdougb{ 68135446Strhodes dns_zt_t *zt; 69135446Strhodes isc_result_t result; 70135446Strhodes 71135446Strhodes REQUIRE(ztp != NULL && *ztp == NULL); 72135446Strhodes 73135446Strhodes zt = isc_mem_get(mctx, sizeof(*zt)); 74135446Strhodes if (zt == NULL) 75135446Strhodes return (ISC_R_NOMEMORY); 76135446Strhodes 77135446Strhodes zt->table = NULL; 78135446Strhodes result = dns_rbt_create(mctx, auto_detach, zt, &zt->table); 79135446Strhodes if (result != ISC_R_SUCCESS) 80135446Strhodes goto cleanup_zt; 81135446Strhodes 82135446Strhodes result = isc_rwlock_init(&zt->rwlock, 0, 0); 83170222Sdougb if (result != ISC_R_SUCCESS) 84135446Strhodes goto cleanup_rbt; 85135446Strhodes 86135446Strhodes zt->mctx = mctx; 87135446Strhodes zt->references = 1; 88135446Strhodes zt->rdclass = rdclass; 89135446Strhodes zt->magic = ZTMAGIC; 90135446Strhodes *ztp = zt; 91135446Strhodes 92135446Strhodes return (ISC_R_SUCCESS); 93135446Strhodes 94135446Strhodes cleanup_rbt: 95135446Strhodes dns_rbt_destroy(&zt->table); 96135446Strhodes 97135446Strhodes cleanup_zt: 98135446Strhodes isc_mem_put(mctx, zt, sizeof(*zt)); 99135446Strhodes 100135446Strhodes return (result); 101135446Strhodes} 102135446Strhodes 103135446Strhodesisc_result_t 104135446Strhodesdns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) { 105135446Strhodes isc_result_t result; 106135446Strhodes dns_zone_t *dummy = NULL; 107135446Strhodes dns_name_t *name; 108135446Strhodes 109135446Strhodes REQUIRE(VALID_ZT(zt)); 110135446Strhodes 111135446Strhodes name = dns_zone_getorigin(zone); 112135446Strhodes 113135446Strhodes RWLOCK(&zt->rwlock, isc_rwlocktype_write); 114135446Strhodes 115135446Strhodes result = dns_rbt_addname(zt->table, name, zone); 116135446Strhodes if (result == ISC_R_SUCCESS) 117135446Strhodes dns_zone_attach(zone, &dummy); 118135446Strhodes 119135446Strhodes RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 120135446Strhodes 121135446Strhodes return (result); 122135446Strhodes} 123135446Strhodes 124135446Strhodesisc_result_t 125135446Strhodesdns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) { 126135446Strhodes isc_result_t result; 127135446Strhodes dns_name_t *name; 128135446Strhodes 129135446Strhodes REQUIRE(VALID_ZT(zt)); 130135446Strhodes 131135446Strhodes name = dns_zone_getorigin(zone); 132135446Strhodes 133135446Strhodes RWLOCK(&zt->rwlock, isc_rwlocktype_write); 134135446Strhodes 135135446Strhodes result = dns_rbt_deletename(zt->table, name, ISC_FALSE); 136135446Strhodes 137135446Strhodes RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 138135446Strhodes 139135446Strhodes return (result); 140135446Strhodes} 141135446Strhodes 142135446Strhodesisc_result_t 143135446Strhodesdns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options, 144135446Strhodes dns_name_t *foundname, dns_zone_t **zonep) 145135446Strhodes{ 146135446Strhodes isc_result_t result; 147135446Strhodes dns_zone_t *dummy = NULL; 148135446Strhodes unsigned int rbtoptions = 0; 149135446Strhodes 150135446Strhodes REQUIRE(VALID_ZT(zt)); 151135446Strhodes 152135446Strhodes if ((options & DNS_ZTFIND_NOEXACT) != 0) 153135446Strhodes rbtoptions |= DNS_RBTFIND_NOEXACT; 154135446Strhodes 155135446Strhodes RWLOCK(&zt->rwlock, isc_rwlocktype_read); 156135446Strhodes 157135446Strhodes result = dns_rbt_findname(zt->table, name, rbtoptions, foundname, 158135446Strhodes (void **) (void*)&dummy); 159135446Strhodes if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) 160135446Strhodes dns_zone_attach(dummy, zonep); 161135446Strhodes 162135446Strhodes RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 163135446Strhodes 164135446Strhodes return (result); 165135446Strhodes} 166135446Strhodes 167135446Strhodesvoid 168135446Strhodesdns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) { 169135446Strhodes 170135446Strhodes REQUIRE(VALID_ZT(zt)); 171135446Strhodes REQUIRE(ztp != NULL && *ztp == NULL); 172135446Strhodes 173135446Strhodes RWLOCK(&zt->rwlock, isc_rwlocktype_write); 174135446Strhodes 175135446Strhodes INSIST(zt->references > 0); 176135446Strhodes zt->references++; 177135446Strhodes INSIST(zt->references != 0); 178135446Strhodes 179135446Strhodes RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 180135446Strhodes 181135446Strhodes *ztp = zt; 182135446Strhodes} 183135446Strhodes 184135446Strhodesstatic isc_result_t 185135446Strhodesflush(dns_zone_t *zone, void *uap) { 186135446Strhodes UNUSED(uap); 187135446Strhodes return (dns_zone_flush(zone)); 188135446Strhodes} 189135446Strhodes 190135446Strhodesstatic void 191135446Strhodeszt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) { 192135446Strhodes isc_boolean_t destroy = ISC_FALSE; 193135446Strhodes dns_zt_t *zt; 194135446Strhodes 195135446Strhodes REQUIRE(ztp != NULL && VALID_ZT(*ztp)); 196135446Strhodes 197135446Strhodes zt = *ztp; 198135446Strhodes 199135446Strhodes RWLOCK(&zt->rwlock, isc_rwlocktype_write); 200135446Strhodes 201135446Strhodes INSIST(zt->references > 0); 202135446Strhodes zt->references--; 203135446Strhodes if (zt->references == 0) 204135446Strhodes destroy = ISC_TRUE; 205135446Strhodes 206135446Strhodes RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 207135446Strhodes 208135446Strhodes if (destroy) { 209135446Strhodes if (need_flush) 210135446Strhodes (void)dns_zt_apply(zt, ISC_FALSE, flush, NULL); 211135446Strhodes dns_rbt_destroy(&zt->table); 212135446Strhodes isc_rwlock_destroy(&zt->rwlock); 213135446Strhodes zt->magic = 0; 214135446Strhodes isc_mem_put(zt->mctx, zt, sizeof(*zt)); 215135446Strhodes } 216135446Strhodes 217135446Strhodes *ztp = NULL; 218135446Strhodes} 219135446Strhodes 220135446Strhodesvoid 221135446Strhodesdns_zt_flushanddetach(dns_zt_t **ztp) { 222135446Strhodes zt_flushanddetach(ztp, ISC_TRUE); 223135446Strhodes} 224135446Strhodes 225135446Strhodesvoid 226135446Strhodesdns_zt_detach(dns_zt_t **ztp) { 227135446Strhodes zt_flushanddetach(ztp, ISC_FALSE); 228135446Strhodes} 229135446Strhodes 230135446Strhodesisc_result_t 231135446Strhodesdns_zt_load(dns_zt_t *zt, isc_boolean_t stop) { 232135446Strhodes isc_result_t result; 233135446Strhodes 234135446Strhodes REQUIRE(VALID_ZT(zt)); 235135446Strhodes 236135446Strhodes RWLOCK(&zt->rwlock, isc_rwlocktype_read); 237135446Strhodes result = dns_zt_apply(zt, stop, load, NULL); 238135446Strhodes RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 239135446Strhodes return (result); 240135446Strhodes} 241135446Strhodes 242135446Strhodesstatic isc_result_t 243135446Strhodesload(dns_zone_t *zone, void *uap) { 244135446Strhodes isc_result_t result; 245135446Strhodes UNUSED(uap); 246135446Strhodes result = dns_zone_load(zone); 247135446Strhodes if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE) 248135446Strhodes result = ISC_R_SUCCESS; 249135446Strhodes return (result); 250135446Strhodes} 251135446Strhodes 252135446Strhodesisc_result_t 253135446Strhodesdns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) { 254135446Strhodes isc_result_t result; 255135446Strhodes 256135446Strhodes REQUIRE(VALID_ZT(zt)); 257135446Strhodes 258135446Strhodes RWLOCK(&zt->rwlock, isc_rwlocktype_read); 259135446Strhodes result = dns_zt_apply(zt, stop, loadnew, NULL); 260135446Strhodes RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 261135446Strhodes return (result); 262135446Strhodes} 263135446Strhodes 264135446Strhodesstatic isc_result_t 265135446Strhodesloadnew(dns_zone_t *zone, void *uap) { 266135446Strhodes isc_result_t result; 267135446Strhodes UNUSED(uap); 268135446Strhodes result = dns_zone_loadnew(zone); 269135446Strhodes if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE || 270135446Strhodes result == DNS_R_DYNAMIC) 271135446Strhodes result = ISC_R_SUCCESS; 272135446Strhodes return (result); 273135446Strhodes} 274135446Strhodes 275135446Strhodesisc_result_t 276170222Sdougbdns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) { 277170222Sdougb isc_result_t result, tresult; 278170222Sdougb 279170222Sdougb REQUIRE(VALID_ZT(zt)); 280170222Sdougb 281170222Sdougb RWLOCK(&zt->rwlock, isc_rwlocktype_read); 282170222Sdougb result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze); 283170222Sdougb RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 284170222Sdougb return ((result == ISC_R_SUCCESS) ? tresult : result); 285170222Sdougb} 286170222Sdougb 287170222Sdougbstatic isc_result_t 288170222Sdougbfreezezones(dns_zone_t *zone, void *uap) { 289170222Sdougb isc_boolean_t freeze = *(isc_boolean_t *)uap; 290170222Sdougb isc_boolean_t frozen; 291170222Sdougb isc_result_t result = ISC_R_SUCCESS; 292170222Sdougb char classstr[DNS_RDATACLASS_FORMATSIZE]; 293170222Sdougb char zonename[DNS_NAME_FORMATSIZE]; 294170222Sdougb dns_view_t *view; 295170222Sdougb char *journal; 296170222Sdougb const char *vname; 297170222Sdougb const char *sep; 298170222Sdougb int level; 299170222Sdougb 300170222Sdougb if (dns_zone_gettype(zone) != dns_zone_master) 301170222Sdougb return (ISC_R_SUCCESS); 302170222Sdougb 303170222Sdougb frozen = dns_zone_getupdatedisabled(zone); 304170222Sdougb if (freeze) { 305170222Sdougb if (frozen) 306170222Sdougb result = DNS_R_FROZEN; 307170222Sdougb if (result == ISC_R_SUCCESS) 308170222Sdougb result = dns_zone_flush(zone); 309170222Sdougb if (result == ISC_R_SUCCESS) { 310170222Sdougb journal = dns_zone_getjournal(zone); 311170222Sdougb if (journal != NULL) 312170222Sdougb (void)isc_file_remove(journal); 313170222Sdougb } 314170222Sdougb } else { 315170222Sdougb if (frozen) { 316170222Sdougb result = dns_zone_load(zone); 317170222Sdougb if (result == DNS_R_CONTINUE || 318170222Sdougb result == DNS_R_UPTODATE) 319170222Sdougb result = ISC_R_SUCCESS; 320170222Sdougb } 321170222Sdougb } 322170222Sdougb if (result == ISC_R_SUCCESS) 323170222Sdougb dns_zone_setupdatedisabled(zone, freeze); 324170222Sdougb view = dns_zone_getview(zone); 325170222Sdougb if (strcmp(view->name, "_bind") == 0 || 326170222Sdougb strcmp(view->name, "_default") == 0) 327170222Sdougb { 328170222Sdougb vname = ""; 329170222Sdougb sep = ""; 330170222Sdougb } else { 331170222Sdougb vname = view->name; 332170222Sdougb sep = " "; 333170222Sdougb } 334170222Sdougb dns_rdataclass_format(dns_zone_getclass(zone), classstr, 335170222Sdougb sizeof(classstr)); 336170222Sdougb dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); 337170222Sdougb level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1); 338170222Sdougb isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, 339170222Sdougb level, "%s zone '%s/%s'%s%s: %s", 340170222Sdougb freeze ? "freezing" : "thawing", 341170222Sdougb zonename, classstr, sep, vname, 342170222Sdougb isc_result_totext(result)); 343170222Sdougb return (result); 344170222Sdougb} 345170222Sdougb 346170222Sdougbisc_result_t 347135446Strhodesdns_zt_apply(dns_zt_t *zt, isc_boolean_t stop, 348135446Strhodes isc_result_t (*action)(dns_zone_t *, void *), void *uap) 349135446Strhodes{ 350170222Sdougb return (dns_zt_apply2(zt, stop, NULL, action, uap)); 351170222Sdougb} 352170222Sdougb 353170222Sdougbisc_result_t 354170222Sdougbdns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub, 355170222Sdougb isc_result_t (*action)(dns_zone_t *, void *), void *uap) 356170222Sdougb{ 357135446Strhodes dns_rbtnode_t *node; 358135446Strhodes dns_rbtnodechain_t chain; 359170222Sdougb isc_result_t result, tresult = ISC_R_SUCCESS; 360135446Strhodes dns_zone_t *zone; 361135446Strhodes 362135446Strhodes REQUIRE(VALID_ZT(zt)); 363135446Strhodes REQUIRE(action != NULL); 364135446Strhodes 365135446Strhodes dns_rbtnodechain_init(&chain, zt->mctx); 366135446Strhodes result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); 367135446Strhodes if (result == ISC_R_NOTFOUND) { 368135446Strhodes /* 369135446Strhodes * The tree is empty. 370135446Strhodes */ 371135446Strhodes result = ISC_R_NOMORE; 372135446Strhodes } 373135446Strhodes while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 374135446Strhodes result = dns_rbtnodechain_current(&chain, NULL, NULL, 375135446Strhodes &node); 376135446Strhodes if (result == ISC_R_SUCCESS) { 377135446Strhodes zone = node->data; 378135446Strhodes if (zone != NULL) 379135446Strhodes result = (action)(zone, uap); 380170222Sdougb if (result != ISC_R_SUCCESS && stop) { 381170222Sdougb tresult = result; 382135446Strhodes goto cleanup; /* don't break */ 383170222Sdougb } else if (result != ISC_R_SUCCESS && 384170222Sdougb tresult == ISC_R_SUCCESS) 385170222Sdougb tresult = result; 386135446Strhodes } 387135446Strhodes result = dns_rbtnodechain_next(&chain, NULL, NULL); 388135446Strhodes } 389135446Strhodes if (result == ISC_R_NOMORE) 390135446Strhodes result = ISC_R_SUCCESS; 391135446Strhodes 392135446Strhodes cleanup: 393135446Strhodes dns_rbtnodechain_invalidate(&chain); 394170222Sdougb if (sub != NULL) 395170222Sdougb *sub = tresult; 396135446Strhodes 397135446Strhodes return (result); 398135446Strhodes} 399135446Strhodes 400135446Strhodes/*** 401135446Strhodes *** Private 402135446Strhodes ***/ 403135446Strhodes 404135446Strhodesstatic void 405135446Strhodesauto_detach(void *data, void *arg) { 406135446Strhodes dns_zone_t *zone = data; 407135446Strhodes 408135446Strhodes UNUSED(arg); 409135446Strhodes 410135446Strhodes dns_zone_detach(&zone); 411135446Strhodes} 412