"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/lookup.c" (4 Sep 2020, 11394 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


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 "lookup.c" see the Fossies "Dox" file reference documentation.

    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 /*! \file */
   13 
   14 #include <stdbool.h>
   15 
   16 #include <isc/mem.h>
   17 #include <isc/netaddr.h>
   18 #include <isc/string.h> /* Required for HP/UX (and others?) */
   19 #include <isc/task.h>
   20 #include <isc/util.h>
   21 
   22 #include <dns/db.h>
   23 #include <dns/events.h>
   24 #include <dns/lookup.h>
   25 #include <dns/rdata.h>
   26 #include <dns/rdataset.h>
   27 #include <dns/rdatastruct.h>
   28 #include <dns/resolver.h>
   29 #include <dns/result.h>
   30 #include <dns/view.h>
   31 
   32 struct dns_lookup {
   33     /* Unlocked. */
   34     unsigned int magic;
   35     isc_mem_t *mctx;
   36     isc_mutex_t lock;
   37     dns_rdatatype_t type;
   38     dns_fixedname_t name;
   39     /* Locked by lock. */
   40     unsigned int options;
   41     isc_task_t *task;
   42     dns_view_t *view;
   43     dns_lookupevent_t *event;
   44     dns_fetch_t *fetch;
   45     unsigned int restarts;
   46     bool canceled;
   47     dns_rdataset_t rdataset;
   48     dns_rdataset_t sigrdataset;
   49 };
   50 
   51 #define LOOKUP_MAGIC    ISC_MAGIC('l', 'o', 'o', 'k')
   52 #define VALID_LOOKUP(l) ISC_MAGIC_VALID((l), LOOKUP_MAGIC)
   53 
   54 #define MAX_RESTARTS 16
   55 
   56 static void
   57 lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event);
   58 
   59 static void
   60 fetch_done(isc_task_t *task, isc_event_t *event) {
   61     dns_lookup_t *lookup = event->ev_arg;
   62     dns_fetchevent_t *fevent;
   63 
   64     UNUSED(task);
   65     REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
   66     REQUIRE(VALID_LOOKUP(lookup));
   67     REQUIRE(lookup->task == task);
   68     fevent = (dns_fetchevent_t *)event;
   69     REQUIRE(fevent->fetch == lookup->fetch);
   70 
   71     lookup_find(lookup, fevent);
   72 }
   73 
   74 static inline isc_result_t
   75 start_fetch(dns_lookup_t *lookup) {
   76     isc_result_t result;
   77 
   78     /*
   79      * The caller must be holding the lookup's lock.
   80      */
   81 
   82     REQUIRE(lookup->fetch == NULL);
   83 
   84     result = dns_resolver_createfetch(
   85         lookup->view->resolver, dns_fixedname_name(&lookup->name),
   86         lookup->type, NULL, NULL, NULL, NULL, 0, 0, 0, NULL,
   87         lookup->task, fetch_done, lookup, &lookup->rdataset,
   88         &lookup->sigrdataset, &lookup->fetch);
   89 
   90     return (result);
   91 }
   92 
   93 static isc_result_t
   94 build_event(dns_lookup_t *lookup) {
   95     dns_name_t *name = NULL;
   96     dns_rdataset_t *rdataset = NULL;
   97     dns_rdataset_t *sigrdataset = NULL;
   98 
   99     name = isc_mem_get(lookup->mctx, sizeof(dns_name_t));
  100     dns_name_init(name, NULL);
  101     dns_name_dup(dns_fixedname_name(&lookup->name), lookup->mctx, name);
  102 
  103     if (dns_rdataset_isassociated(&lookup->rdataset)) {
  104         rdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t));
  105         dns_rdataset_init(rdataset);
  106         dns_rdataset_clone(&lookup->rdataset, rdataset);
  107     }
  108 
  109     if (dns_rdataset_isassociated(&lookup->sigrdataset)) {
  110         sigrdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t));
  111         dns_rdataset_init(sigrdataset);
  112         dns_rdataset_clone(&lookup->sigrdataset, sigrdataset);
  113     }
  114 
  115     lookup->event->name = name;
  116     lookup->event->rdataset = rdataset;
  117     lookup->event->sigrdataset = sigrdataset;
  118 
  119     return (ISC_R_SUCCESS);
  120 }
  121 
  122 static isc_result_t
  123 view_find(dns_lookup_t *lookup, dns_name_t *foundname) {
  124     isc_result_t result;
  125     dns_name_t *name = dns_fixedname_name(&lookup->name);
  126     dns_rdatatype_t type;
  127 
  128     if (lookup->type == dns_rdatatype_rrsig) {
  129         type = dns_rdatatype_any;
  130     } else {
  131         type = lookup->type;
  132     }
  133 
  134     result = dns_view_find(lookup->view, name, type, 0, 0, false, false,
  135                    &lookup->event->db, &lookup->event->node,
  136                    foundname, &lookup->rdataset,
  137                    &lookup->sigrdataset);
  138     return (result);
  139 }
  140 
  141 static void
  142 lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) {
  143     isc_result_t result;
  144     bool want_restart;
  145     bool send_event;
  146     dns_name_t *name, *fname, *prefix;
  147     dns_fixedname_t foundname, fixed;
  148     dns_rdata_t rdata = DNS_RDATA_INIT;
  149     unsigned int nlabels;
  150     int order;
  151     dns_namereln_t namereln;
  152     dns_rdata_cname_t cname;
  153     dns_rdata_dname_t dname;
  154 
  155     REQUIRE(VALID_LOOKUP(lookup));
  156 
  157     LOCK(&lookup->lock);
  158 
  159     result = ISC_R_SUCCESS;
  160     name = dns_fixedname_name(&lookup->name);
  161 
  162     do {
  163         lookup->restarts++;
  164         want_restart = false;
  165         send_event = true;
  166 
  167         if (event == NULL && !lookup->canceled) {
  168             fname = dns_fixedname_initname(&foundname);
  169             INSIST(!dns_rdataset_isassociated(&lookup->rdataset));
  170             INSIST(!dns_rdataset_isassociated(
  171                 &lookup->sigrdataset));
  172             /*
  173              * If we have restarted then clear the old node.
  174              */
  175             if (lookup->event->node != NULL) {
  176                 INSIST(lookup->event->db != NULL);
  177                 dns_db_detachnode(lookup->event->db,
  178                           &lookup->event->node);
  179             }
  180             if (lookup->event->db != NULL) {
  181                 dns_db_detach(&lookup->event->db);
  182             }
  183             result = view_find(lookup, fname);
  184             if (result == ISC_R_NOTFOUND) {
  185                 /*
  186                  * We don't know anything about the name.
  187                  * Launch a fetch.
  188                  */
  189                 if (lookup->event->node != NULL) {
  190                     INSIST(lookup->event->db != NULL);
  191                     dns_db_detachnode(lookup->event->db,
  192                               &lookup->event->node);
  193                 }
  194                 if (lookup->event->db != NULL) {
  195                     dns_db_detach(&lookup->event->db);
  196                 }
  197                 result = start_fetch(lookup);
  198                 if (result == ISC_R_SUCCESS) {
  199                     send_event = false;
  200                 }
  201                 goto done;
  202             }
  203         } else if (event != NULL) {
  204             result = event->result;
  205             fname = dns_fixedname_name(&event->foundname);
  206             dns_resolver_destroyfetch(&lookup->fetch);
  207             INSIST(event->rdataset == &lookup->rdataset);
  208             INSIST(event->sigrdataset == &lookup->sigrdataset);
  209         } else {
  210             fname = NULL; /* Silence compiler warning. */
  211         }
  212 
  213         /*
  214          * If we've been canceled, forget about the result.
  215          */
  216         if (lookup->canceled) {
  217             result = ISC_R_CANCELED;
  218         }
  219 
  220         switch (result) {
  221         case ISC_R_SUCCESS:
  222             result = build_event(lookup);
  223             if (event == NULL) {
  224                 break;
  225             }
  226             if (event->db != NULL) {
  227                 dns_db_attach(event->db, &lookup->event->db);
  228             }
  229             if (event->node != NULL) {
  230                 dns_db_attachnode(lookup->event->db,
  231                           event->node,
  232                           &lookup->event->node);
  233             }
  234             break;
  235         case DNS_R_CNAME:
  236             /*
  237              * Copy the CNAME's target into the lookup's
  238              * query name and start over.
  239              */
  240             result = dns_rdataset_first(&lookup->rdataset);
  241             if (result != ISC_R_SUCCESS) {
  242                 break;
  243             }
  244             dns_rdataset_current(&lookup->rdataset, &rdata);
  245             result = dns_rdata_tostruct(&rdata, &cname, NULL);
  246             dns_rdata_reset(&rdata);
  247             if (result != ISC_R_SUCCESS) {
  248                 break;
  249             }
  250             dns_name_copynf(&cname.cname, name);
  251             dns_rdata_freestruct(&cname);
  252             want_restart = true;
  253             send_event = false;
  254             break;
  255         case DNS_R_DNAME:
  256             namereln = dns_name_fullcompare(name, fname, &order,
  257                             &nlabels);
  258             INSIST(namereln == dns_namereln_subdomain);
  259             /*
  260              * Get the target name of the DNAME.
  261              */
  262             result = dns_rdataset_first(&lookup->rdataset);
  263             if (result != ISC_R_SUCCESS) {
  264                 break;
  265             }
  266             dns_rdataset_current(&lookup->rdataset, &rdata);
  267             result = dns_rdata_tostruct(&rdata, &dname, NULL);
  268             dns_rdata_reset(&rdata);
  269             if (result != ISC_R_SUCCESS) {
  270                 break;
  271             }
  272             /*
  273              * Construct the new query name and start over.
  274              */
  275             prefix = dns_fixedname_initname(&fixed);
  276             dns_name_split(name, nlabels, prefix, NULL);
  277             result = dns_name_concatenate(prefix, &dname.dname,
  278                               name, NULL);
  279             dns_rdata_freestruct(&dname);
  280             if (result == ISC_R_SUCCESS) {
  281                 want_restart = true;
  282                 send_event = false;
  283             }
  284             break;
  285         default:
  286             send_event = true;
  287         }
  288 
  289         if (dns_rdataset_isassociated(&lookup->rdataset)) {
  290             dns_rdataset_disassociate(&lookup->rdataset);
  291         }
  292         if (dns_rdataset_isassociated(&lookup->sigrdataset)) {
  293             dns_rdataset_disassociate(&lookup->sigrdataset);
  294         }
  295 
  296     done:
  297         if (event != NULL) {
  298             if (event->node != NULL) {
  299                 dns_db_detachnode(event->db, &event->node);
  300             }
  301             if (event->db != NULL) {
  302                 dns_db_detach(&event->db);
  303             }
  304             isc_event_free(ISC_EVENT_PTR(&event));
  305         }
  306 
  307         /*
  308          * Limit the number of restarts.
  309          */
  310         if (want_restart && lookup->restarts == MAX_RESTARTS) {
  311             want_restart = false;
  312             result = ISC_R_QUOTA;
  313             send_event = true;
  314         }
  315     } while (want_restart);
  316 
  317     if (send_event) {
  318         lookup->event->result = result;
  319         lookup->event->ev_sender = lookup;
  320         isc_task_sendanddetach(&lookup->task,
  321                        (isc_event_t **)&lookup->event);
  322         dns_view_detach(&lookup->view);
  323     }
  324 
  325     UNLOCK(&lookup->lock);
  326 }
  327 
  328 static void
  329 levent_destroy(isc_event_t *event) {
  330     dns_lookupevent_t *levent;
  331     isc_mem_t *mctx;
  332 
  333     REQUIRE(event->ev_type == DNS_EVENT_LOOKUPDONE);
  334     mctx = event->ev_destroy_arg;
  335     levent = (dns_lookupevent_t *)event;
  336 
  337     if (levent->name != NULL) {
  338         if (dns_name_dynamic(levent->name)) {
  339             dns_name_free(levent->name, mctx);
  340         }
  341         isc_mem_put(mctx, levent->name, sizeof(dns_name_t));
  342     }
  343     if (levent->rdataset != NULL) {
  344         dns_rdataset_disassociate(levent->rdataset);
  345         isc_mem_put(mctx, levent->rdataset, sizeof(dns_rdataset_t));
  346     }
  347     if (levent->sigrdataset != NULL) {
  348         dns_rdataset_disassociate(levent->sigrdataset);
  349         isc_mem_put(mctx, levent->sigrdataset, sizeof(dns_rdataset_t));
  350     }
  351     if (levent->node != NULL) {
  352         dns_db_detachnode(levent->db, &levent->node);
  353     }
  354     if (levent->db != NULL) {
  355         dns_db_detach(&levent->db);
  356     }
  357     isc_mem_put(mctx, event, event->ev_size);
  358 }
  359 
  360 isc_result_t
  361 dns_lookup_create(isc_mem_t *mctx, const dns_name_t *name, dns_rdatatype_t type,
  362           dns_view_t *view, unsigned int options, isc_task_t *task,
  363           isc_taskaction_t action, void *arg, dns_lookup_t **lookupp) {
  364     dns_lookup_t *lookup;
  365     isc_event_t *ievent;
  366 
  367     lookup = isc_mem_get(mctx, sizeof(*lookup));
  368     lookup->mctx = NULL;
  369     isc_mem_attach(mctx, &lookup->mctx);
  370     lookup->options = options;
  371 
  372     ievent = isc_event_allocate(mctx, lookup, DNS_EVENT_LOOKUPDONE, action,
  373                     arg, sizeof(*lookup->event));
  374     lookup->event = (dns_lookupevent_t *)ievent;
  375     lookup->event->ev_destroy = levent_destroy;
  376     lookup->event->ev_destroy_arg = mctx;
  377     lookup->event->result = ISC_R_FAILURE;
  378     lookup->event->name = NULL;
  379     lookup->event->rdataset = NULL;
  380     lookup->event->sigrdataset = NULL;
  381     lookup->event->db = NULL;
  382     lookup->event->node = NULL;
  383 
  384     lookup->task = NULL;
  385     isc_task_attach(task, &lookup->task);
  386 
  387     isc_mutex_init(&lookup->lock);
  388 
  389     dns_fixedname_init(&lookup->name);
  390 
  391     dns_name_copynf(name, dns_fixedname_name(&lookup->name));
  392 
  393     lookup->type = type;
  394     lookup->view = NULL;
  395     dns_view_attach(view, &lookup->view);
  396     lookup->fetch = NULL;
  397     lookup->restarts = 0;
  398     lookup->canceled = false;
  399     dns_rdataset_init(&lookup->rdataset);
  400     dns_rdataset_init(&lookup->sigrdataset);
  401     lookup->magic = LOOKUP_MAGIC;
  402 
  403     *lookupp = lookup;
  404 
  405     lookup_find(lookup, NULL);
  406 
  407     return (ISC_R_SUCCESS);
  408 }
  409 
  410 void
  411 dns_lookup_cancel(dns_lookup_t *lookup) {
  412     REQUIRE(VALID_LOOKUP(lookup));
  413 
  414     LOCK(&lookup->lock);
  415 
  416     if (!lookup->canceled) {
  417         lookup->canceled = true;
  418         if (lookup->fetch != NULL) {
  419             INSIST(lookup->view != NULL);
  420             dns_resolver_cancelfetch(lookup->fetch);
  421         }
  422     }
  423 
  424     UNLOCK(&lookup->lock);
  425 }
  426 
  427 void
  428 dns_lookup_destroy(dns_lookup_t **lookupp) {
  429     dns_lookup_t *lookup;
  430 
  431     REQUIRE(lookupp != NULL);
  432     lookup = *lookupp;
  433     *lookupp = NULL;
  434     REQUIRE(VALID_LOOKUP(lookup));
  435     REQUIRE(lookup->event == NULL);
  436     REQUIRE(lookup->task == NULL);
  437     REQUIRE(lookup->view == NULL);
  438     if (dns_rdataset_isassociated(&lookup->rdataset)) {
  439         dns_rdataset_disassociate(&lookup->rdataset);
  440     }
  441     if (dns_rdataset_isassociated(&lookup->sigrdataset)) {
  442         dns_rdataset_disassociate(&lookup->sigrdataset);
  443     }
  444 
  445     isc_mutex_destroy(&lookup->lock);
  446     lookup->magic = 0;
  447     isc_mem_putanddetach(&lookup->mctx, lookup, sizeof(*lookup));
  448 }