"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/dns/zt.c" (7 Sep 2020, 13226 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "zt.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.17.3_vs_9.17.4.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 
   13 /*! \file */
   14 
   15 #include <config.h>
   16 
   17 #include <inttypes.h>
   18 #include <stdbool.h>
   19 
   20 #include <isc/file.h>
   21 #include <isc/magic.h>
   22 #include <isc/mem.h>
   23 #include <isc/string.h>
   24 #include <isc/task.h>
   25 #include <isc/util.h>
   26 
   27 #include <dns/log.h>
   28 #include <dns/name.h>
   29 #include <dns/rbt.h>
   30 #include <dns/rdataclass.h>
   31 #include <dns/result.h>
   32 #include <dns/view.h>
   33 #include <dns/zone.h>
   34 #include <dns/zt.h>
   35 
   36 struct dns_zt {
   37     /* Unlocked. */
   38     unsigned int        magic;
   39     isc_mem_t       *mctx;
   40     dns_rdataclass_t    rdclass;
   41     isc_rwlock_t        rwlock;
   42     dns_zt_allloaded_t  loaddone;
   43     void *          loaddone_arg;
   44     /* Locked by lock. */
   45     bool        flush;
   46     uint32_t        references;
   47     unsigned int        loads_pending;
   48     dns_rbt_t       *table;
   49 };
   50 
   51 #define ZTMAGIC         ISC_MAGIC('Z', 'T', 'b', 'l')
   52 #define VALID_ZT(zt)        ISC_MAGIC_VALID(zt, ZTMAGIC)
   53 
   54 struct zt_load_params {
   55     dns_zt_zoneloaded_t dl;
   56     bool newonly;
   57     struct dns_zt* zt;
   58 };
   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 = 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, 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, const 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, 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, bool need_flush) {
  219     bool destroy = 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 = true;
  232     if (need_flush)
  233         zt->flush = 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, true);
  246 }
  247 
  248 void
  249 dns_zt_detach(dns_zt_t **ztp) {
  250     zt_flushanddetach(ztp, false);
  251 }
  252 
  253 isc_result_t
  254 dns_zt_load(dns_zt_t *zt, bool 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     return (dns_zt_asyncload2(zt, alldone, arg, false));
  280 }
  281 
  282 isc_result_t
  283 dns_zt_asyncload2(dns_zt_t *zt, dns_zt_allloaded_t alldone, void *arg,
  284           bool newonly)
  285 {
  286     isc_result_t result;
  287     struct zt_load_params params;
  288     int pending;
  289 
  290     params.dl = doneloading;
  291     params.newonly = newonly;
  292     params.zt = zt;
  293 
  294     REQUIRE(VALID_ZT(zt));
  295 
  296     RWLOCK(&zt->rwlock, isc_rwlocktype_write);
  297 
  298     INSIST(zt->loads_pending == 0);
  299     result = dns_zt_apply2(zt, false, NULL, asyncload, &params);
  300 
  301     pending = zt->loads_pending;
  302     if (pending != 0) {
  303         zt->loaddone = alldone;
  304         zt->loaddone_arg = arg;
  305     }
  306 
  307     RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
  308 
  309     if (pending == 0)
  310         alldone(arg);
  311 
  312     return (result);
  313 }
  314 
  315 /*
  316  * Initiates asynchronous loading of zone 'zone'.  'callback' is a
  317  * pointer to a function which will be used to inform the caller when
  318  * the zone loading is complete.
  319  */
  320 static isc_result_t
  321 asyncload(dns_zone_t *zone, void *paramsv) {
  322     isc_result_t result;
  323     struct zt_load_params * params = (struct zt_load_params*) paramsv;
  324 
  325     dns_zt_t *zt;
  326 
  327     REQUIRE(zone != NULL);
  328     zt = dns_zone_getview(zone)->zonetable;
  329     INSIST(VALID_ZT(zt));
  330 
  331     INSIST(zt->references > 0);
  332     zt->references++;
  333     zt->loads_pending++;
  334 
  335     result = dns_zone_asyncload2(zone, *params->dl, zt, params->newonly);
  336     if (result != ISC_R_SUCCESS) {
  337         zt->references--;
  338         zt->loads_pending--;
  339         INSIST(zt->references > 0);
  340     }
  341     return (ISC_R_SUCCESS);
  342 }
  343 
  344 isc_result_t
  345 dns_zt_loadnew(dns_zt_t *zt, bool stop) {
  346     isc_result_t result;
  347 
  348     REQUIRE(VALID_ZT(zt));
  349 
  350     RWLOCK(&zt->rwlock, isc_rwlocktype_read);
  351     result = dns_zt_apply(zt, stop, loadnew, NULL);
  352     RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
  353     return (result);
  354 }
  355 
  356 static isc_result_t
  357 loadnew(dns_zone_t *zone, void *uap) {
  358     isc_result_t result;
  359     UNUSED(uap);
  360 
  361     result = dns_zone_loadnew(zone);
  362     if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
  363         result == DNS_R_DYNAMIC)
  364         result = ISC_R_SUCCESS;
  365     return (result);
  366 }
  367 
  368 isc_result_t
  369 dns_zt_freezezones(dns_zt_t *zt, bool freeze) {
  370     isc_result_t result, tresult;
  371 
  372     REQUIRE(VALID_ZT(zt));
  373 
  374     RWLOCK(&zt->rwlock, isc_rwlocktype_read);
  375     result = dns_zt_apply2(zt, false, &tresult, freezezones, &freeze);
  376     RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
  377     if (tresult == ISC_R_NOTFOUND)
  378         tresult = ISC_R_SUCCESS;
  379     return ((result == ISC_R_SUCCESS) ? tresult : result);
  380 }
  381 
  382 static isc_result_t
  383 freezezones(dns_zone_t *zone, void *uap) {
  384     bool freeze = *(bool *)uap;
  385     bool frozen;
  386     isc_result_t result = ISC_R_SUCCESS;
  387     char classstr[DNS_RDATACLASS_FORMATSIZE];
  388     char zonename[DNS_NAME_FORMATSIZE];
  389     dns_zone_t *raw = NULL;
  390     dns_view_t *view;
  391     const char *vname;
  392     const char *sep;
  393     int level;
  394 
  395     dns_zone_getraw(zone, &raw);
  396     if (raw != NULL)
  397         zone = raw;
  398     if (dns_zone_gettype(zone) != dns_zone_master) {
  399         if (raw != NULL)
  400             dns_zone_detach(&raw);
  401         return (ISC_R_SUCCESS);
  402     }
  403     if (!dns_zone_isdynamic(zone, true)) {
  404         if (raw != NULL)
  405             dns_zone_detach(&raw);
  406         return (ISC_R_SUCCESS);
  407     }
  408 
  409     frozen = dns_zone_getupdatedisabled(zone);
  410     if (freeze) {
  411         if (frozen)
  412             result = DNS_R_FROZEN;
  413         if (result == ISC_R_SUCCESS)
  414             result = dns_zone_flush(zone);
  415         if (result == ISC_R_SUCCESS)
  416             dns_zone_setupdatedisabled(zone, freeze);
  417     } else {
  418         if (frozen) {
  419             result = dns_zone_loadandthaw(zone);
  420             if (result == DNS_R_CONTINUE ||
  421                 result == DNS_R_UPTODATE)
  422                 result = ISC_R_SUCCESS;
  423         }
  424     }
  425     view = dns_zone_getview(zone);
  426     if (strcmp(view->name, "_bind") == 0 ||
  427         strcmp(view->name, "_default") == 0)
  428     {
  429         vname = "";
  430         sep = "";
  431     } else {
  432         vname = view->name;
  433         sep = " ";
  434     }
  435     dns_rdataclass_format(dns_zone_getclass(zone), classstr,
  436                   sizeof(classstr));
  437     dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
  438     level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1);
  439     isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
  440               level, "%s zone '%s/%s'%s%s: %s",
  441               freeze ? "freezing" : "thawing",
  442               zonename, classstr, sep, vname,
  443               isc_result_totext(result));
  444     if (raw != NULL)
  445         dns_zone_detach(&raw);
  446     return (result);
  447 }
  448 
  449 void
  450 dns_zt_setviewcommit(dns_zt_t *zt) {
  451     dns_rbtnode_t *node;
  452     dns_rbtnodechain_t chain;
  453     isc_result_t result;
  454 
  455     REQUIRE(VALID_ZT(zt));
  456 
  457     dns_rbtnodechain_init(&chain, zt->mctx);
  458 
  459     result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
  460     while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
  461         result = dns_rbtnodechain_current(&chain, NULL, NULL,
  462                           &node);
  463         if (result == ISC_R_SUCCESS && node->data != NULL) {
  464             dns_zone_setviewcommit(node->data);
  465         }
  466 
  467         result = dns_rbtnodechain_next(&chain, NULL, NULL);
  468     }
  469 
  470     dns_rbtnodechain_invalidate(&chain);
  471 }
  472 
  473 void
  474 dns_zt_setviewrevert(dns_zt_t *zt) {
  475     dns_rbtnode_t *node;
  476     dns_rbtnodechain_t chain;
  477     isc_result_t result;
  478 
  479     REQUIRE(VALID_ZT(zt));
  480 
  481     dns_rbtnodechain_init(&chain, zt->mctx);
  482 
  483     result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
  484     while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
  485         result = dns_rbtnodechain_current(&chain, NULL, NULL,
  486                           &node);
  487         if (result == ISC_R_SUCCESS && node->data != NULL) {
  488             dns_zone_setviewrevert(node->data);
  489         }
  490 
  491         result = dns_rbtnodechain_next(&chain, NULL, NULL);
  492     }
  493 
  494     dns_rbtnodechain_invalidate(&chain);
  495 }
  496 
  497 isc_result_t
  498 dns_zt_apply(dns_zt_t *zt, bool stop,
  499          isc_result_t (*action)(dns_zone_t *, void *), void *uap)
  500 {
  501     return (dns_zt_apply2(zt, stop, NULL, action, uap));
  502 }
  503 
  504 isc_result_t
  505 dns_zt_apply2(dns_zt_t *zt, bool stop, isc_result_t *sub,
  506           isc_result_t (*action)(dns_zone_t *, void *), void *uap)
  507 {
  508     dns_rbtnode_t *node;
  509     dns_rbtnodechain_t chain;
  510     isc_result_t result, tresult = ISC_R_SUCCESS;
  511     dns_zone_t *zone;
  512 
  513     REQUIRE(VALID_ZT(zt));
  514     REQUIRE(action != NULL);
  515 
  516     dns_rbtnodechain_init(&chain, zt->mctx);
  517     result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
  518     if (result == ISC_R_NOTFOUND) {
  519         /*
  520          * The tree is empty.
  521          */
  522         tresult = result;
  523         result = ISC_R_NOMORE;
  524     }
  525     while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
  526         result = dns_rbtnodechain_current(&chain, NULL, NULL,
  527                           &node);
  528         if (result == ISC_R_SUCCESS) {
  529             zone = node->data;
  530             if (zone != NULL)
  531                 result = (action)(zone, uap);
  532             if (result != ISC_R_SUCCESS && stop) {
  533                 tresult = result;
  534                 goto cleanup;   /* don't break */
  535             } else if (result != ISC_R_SUCCESS &&
  536                    tresult == ISC_R_SUCCESS)
  537                 tresult = result;
  538         }
  539         result = dns_rbtnodechain_next(&chain, NULL, NULL);
  540     }
  541     if (result == ISC_R_NOMORE)
  542         result = ISC_R_SUCCESS;
  543 
  544  cleanup:
  545     dns_rbtnodechain_invalidate(&chain);
  546     if (sub != NULL)
  547         *sub = tresult;
  548 
  549     return (result);
  550 }
  551 
  552 /*
  553  * Decrement the loads_pending counter; when counter reaches
  554  * zero, call the loaddone callback that was initially set by
  555  * dns_zt_asyncload().
  556  */
  557 static isc_result_t
  558 doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
  559     bool destroy = false;
  560     dns_zt_allloaded_t alldone = NULL;
  561     void *arg = NULL;
  562 
  563     UNUSED(zone);
  564     UNUSED(task);
  565 
  566     REQUIRE(VALID_ZT(zt));
  567 
  568     RWLOCK(&zt->rwlock, isc_rwlocktype_write);
  569     INSIST(zt->loads_pending != 0);
  570     INSIST(zt->references != 0);
  571     zt->references--;
  572     if (zt->references == 0)
  573         destroy = true;
  574     zt->loads_pending--;
  575     if (zt->loads_pending == 0) {
  576         alldone = zt->loaddone;
  577         arg = zt->loaddone_arg;
  578         zt->loaddone = NULL;
  579         zt->loaddone_arg = NULL;
  580     }
  581     RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
  582 
  583     if (alldone != NULL)
  584         alldone(arg);
  585 
  586     if (destroy)
  587         zt_destroy(zt);
  588 
  589     return (ISC_R_SUCCESS);
  590 }
  591 
  592 /***
  593  *** Private
  594  ***/
  595 
  596 static void
  597 auto_detach(void *data, void *arg) {
  598     dns_zone_t *zone = data;
  599 
  600     UNUSED(arg);
  601     dns_zone_detach(&zone);
  602 }