lookup.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2013  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: lookup.c,v 1.21 2007/06/18 23:47:40 tbox Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/mem.h>
00025 #include <isc/netaddr.h>
00026 #include <isc/string.h>         /* Required for HP/UX (and others?) */
00027 #include <isc/task.h>
00028 #include <isc/util.h>
00029 
00030 #include <dns/db.h>
00031 #include <dns/events.h>
00032 #include <dns/lookup.h>
00033 #include <dns/rdata.h>
00034 #include <dns/rdataset.h>
00035 #include <dns/rdatastruct.h>
00036 #include <dns/resolver.h>
00037 #include <dns/result.h>
00038 #include <dns/view.h>
00039 
00040 struct dns_lookup {
00041         /* Unlocked. */
00042         unsigned int            magic;
00043         isc_mem_t *             mctx;
00044         isc_mutex_t             lock;
00045         dns_rdatatype_t         type;
00046         dns_fixedname_t         name;
00047         /* Locked by lock. */
00048         unsigned int            options;
00049         isc_task_t *            task;
00050         dns_view_t *            view;
00051         dns_lookupevent_t *     event;
00052         dns_fetch_t *           fetch;
00053         unsigned int            restarts;
00054         isc_boolean_t           canceled;
00055         dns_rdataset_t          rdataset;
00056         dns_rdataset_t          sigrdataset;
00057 };
00058 
00059 #define LOOKUP_MAGIC                    ISC_MAGIC('l', 'o', 'o', 'k')
00060 #define VALID_LOOKUP(l)                 ISC_MAGIC_VALID((l), LOOKUP_MAGIC)
00061 
00062 #define MAX_RESTARTS 16
00063 
00064 static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event);
00065 
00066 static void
00067 fetch_done(isc_task_t *task, isc_event_t *event) {
00068         dns_lookup_t *lookup = event->ev_arg;
00069         dns_fetchevent_t *fevent;
00070 
00071         UNUSED(task);
00072         REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
00073         REQUIRE(VALID_LOOKUP(lookup));
00074         REQUIRE(lookup->task == task);
00075         fevent = (dns_fetchevent_t *)event;
00076         REQUIRE(fevent->fetch == lookup->fetch);
00077 
00078         lookup_find(lookup, fevent);
00079 }
00080 
00081 static inline isc_result_t
00082 start_fetch(dns_lookup_t *lookup) {
00083         isc_result_t result;
00084 
00085         /*
00086          * The caller must be holding the lookup's lock.
00087          */
00088 
00089         REQUIRE(lookup->fetch == NULL);
00090 
00091         result = dns_resolver_createfetch(lookup->view->resolver,
00092                                           dns_fixedname_name(&lookup->name),
00093                                           lookup->type,
00094                                           NULL, NULL, NULL, 0,
00095                                           lookup->task, fetch_done, lookup,
00096                                           &lookup->rdataset,
00097                                           &lookup->sigrdataset,
00098                                           &lookup->fetch);
00099 
00100         return (result);
00101 }
00102 
00103 static isc_result_t
00104 build_event(dns_lookup_t *lookup) {
00105         dns_name_t *name = NULL;
00106         dns_rdataset_t *rdataset = NULL;
00107         dns_rdataset_t *sigrdataset = NULL;
00108         isc_result_t result;
00109 
00110         name = isc_mem_get(lookup->mctx, sizeof(dns_name_t));
00111         if (name == NULL) {
00112                 result = ISC_R_NOMEMORY;
00113                 goto fail;
00114         }
00115         dns_name_init(name, NULL);
00116         result = dns_name_dup(dns_fixedname_name(&lookup->name),
00117                               lookup->mctx, name);
00118         if (result != ISC_R_SUCCESS)
00119                 goto fail;
00120 
00121         if (dns_rdataset_isassociated(&lookup->rdataset)) {
00122                 rdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t));
00123                 if (rdataset == NULL) {
00124                         result = ISC_R_NOMEMORY;
00125                         goto fail;
00126                 }
00127                 dns_rdataset_init(rdataset);
00128                 dns_rdataset_clone(&lookup->rdataset, rdataset);
00129         }
00130 
00131         if (dns_rdataset_isassociated(&lookup->sigrdataset)) {
00132                 sigrdataset = isc_mem_get(lookup->mctx,
00133                                           sizeof(dns_rdataset_t));
00134                 if (sigrdataset == NULL) {
00135                         result = ISC_R_NOMEMORY;
00136                         goto fail;
00137                 }
00138                 dns_rdataset_init(sigrdataset);
00139                 dns_rdataset_clone(&lookup->sigrdataset, sigrdataset);
00140         }
00141 
00142         lookup->event->name = name;
00143         lookup->event->rdataset = rdataset;
00144         lookup->event->sigrdataset = sigrdataset;
00145 
00146         return (ISC_R_SUCCESS);
00147 
00148  fail:
00149         if (name != NULL) {
00150                 if (dns_name_dynamic(name))
00151                         dns_name_free(name, lookup->mctx);
00152                 isc_mem_put(lookup->mctx, name, sizeof(dns_name_t));
00153         }
00154         if (rdataset != NULL) {
00155                 if (dns_rdataset_isassociated(rdataset))
00156                         dns_rdataset_disassociate(rdataset);
00157                 isc_mem_put(lookup->mctx, rdataset, sizeof(dns_rdataset_t));
00158         }
00159         return (result);
00160 }
00161 
00162 static isc_result_t
00163 view_find(dns_lookup_t *lookup, dns_name_t *foundname) {
00164         isc_result_t result;
00165         dns_name_t *name = dns_fixedname_name(&lookup->name);
00166         dns_rdatatype_t type;
00167 
00168         if (lookup->type == dns_rdatatype_rrsig)
00169                 type = dns_rdatatype_any;
00170         else
00171                 type = lookup->type;
00172 
00173         result = dns_view_find(lookup->view, name, type, 0, 0, ISC_FALSE,
00174                                &lookup->event->db, &lookup->event->node,
00175                                foundname, &lookup->rdataset,
00176                                &lookup->sigrdataset);
00177         return (result);
00178 }
00179 
00180 static void
00181 lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) {
00182         isc_result_t result;
00183         isc_boolean_t want_restart;
00184         isc_boolean_t send_event;
00185         dns_name_t *name, *fname, *prefix;
00186         dns_fixedname_t foundname, fixed;
00187         dns_rdata_t rdata = DNS_RDATA_INIT;
00188         unsigned int nlabels;
00189         int order;
00190         dns_namereln_t namereln;
00191         dns_rdata_cname_t cname;
00192         dns_rdata_dname_t dname;
00193 
00194         REQUIRE(VALID_LOOKUP(lookup));
00195 
00196         LOCK(&lookup->lock);
00197 
00198         result = ISC_R_SUCCESS;
00199         name = dns_fixedname_name(&lookup->name);
00200 
00201         do {
00202                 lookup->restarts++;
00203                 want_restart = ISC_FALSE;
00204                 send_event = ISC_TRUE;
00205 
00206                 if (event == NULL && !lookup->canceled) {
00207                         dns_fixedname_init(&foundname);
00208                         fname = dns_fixedname_name(&foundname);
00209                         INSIST(!dns_rdataset_isassociated(&lookup->rdataset));
00210                         INSIST(!dns_rdataset_isassociated
00211                                                 (&lookup->sigrdataset));
00212                         /*
00213                          * If we have restarted then clear the old node.                                 */
00214                         if  (lookup->event->node != NULL) {
00215                                 INSIST(lookup->event->db != NULL);
00216                                 dns_db_detachnode(lookup->event->db,
00217                                                  &lookup->event->node);
00218                         }
00219                         if (lookup->event->db != NULL)
00220                                 dns_db_detach(&lookup->event->db);
00221                         result = view_find(lookup, fname);
00222                         if (result == ISC_R_NOTFOUND) {
00223                                 /*
00224                                  * We don't know anything about the name.
00225                                  * Launch a fetch.
00226                                  */
00227                                 if  (lookup->event->node != NULL) {
00228                                         INSIST(lookup->event->db != NULL);
00229                                         dns_db_detachnode(lookup->event->db,
00230                                                          &lookup->event->node);
00231                                 }
00232                                 if (lookup->event->db != NULL)
00233                                         dns_db_detach(&lookup->event->db);
00234                                 result = start_fetch(lookup);
00235                                 if (result == ISC_R_SUCCESS)
00236                                         send_event = ISC_FALSE;
00237                                 goto done;
00238                         }
00239                 } else if (event != NULL) {
00240                         result = event->result;
00241                         fname = dns_fixedname_name(&event->foundname);
00242                         dns_resolver_destroyfetch(&lookup->fetch);
00243                         INSIST(event->rdataset == &lookup->rdataset);
00244                         INSIST(event->sigrdataset == &lookup->sigrdataset);
00245                 } else
00246                         fname = NULL;   /* Silence compiler warning. */
00247 
00248                 /*
00249                  * If we've been canceled, forget about the result.
00250                  */
00251                 if (lookup->canceled)
00252                         result = ISC_R_CANCELED;
00253 
00254                 switch (result) {
00255                 case ISC_R_SUCCESS:
00256                         result = build_event(lookup);
00257                         if (event == NULL)
00258                                 break;
00259                         if (event->db != NULL)
00260                                 dns_db_attach(event->db, &lookup->event->db);
00261                         if (event->node != NULL)
00262                                 dns_db_attachnode(lookup->event->db,
00263                                                   event->node,
00264                                                   &lookup->event->node);
00265                         break;
00266                 case DNS_R_CNAME:
00267                         /*
00268                          * Copy the CNAME's target into the lookup's
00269                          * query name and start over.
00270                          */
00271                         result = dns_rdataset_first(&lookup->rdataset);
00272                         if (result != ISC_R_SUCCESS)
00273                                 break;
00274                         dns_rdataset_current(&lookup->rdataset, &rdata);
00275                         result = dns_rdata_tostruct(&rdata, &cname, NULL);
00276                         dns_rdata_reset(&rdata);
00277                         if (result != ISC_R_SUCCESS)
00278                                 break;
00279                         result = dns_name_copy(&cname.cname, name, NULL);
00280                         dns_rdata_freestruct(&cname);
00281                         if (result == ISC_R_SUCCESS) {
00282                                 want_restart = ISC_TRUE;
00283                                 send_event = ISC_FALSE;
00284                         }
00285                         break;
00286                 case DNS_R_DNAME:
00287                         namereln = dns_name_fullcompare(name, fname, &order,
00288                                                         &nlabels);
00289                         INSIST(namereln == dns_namereln_subdomain);
00290                         /*
00291                          * Get the target name of the DNAME.
00292                          */
00293                         result = dns_rdataset_first(&lookup->rdataset);
00294                         if (result != ISC_R_SUCCESS)
00295                                 break;
00296                         dns_rdataset_current(&lookup->rdataset, &rdata);
00297                         result = dns_rdata_tostruct(&rdata, &dname, NULL);
00298                         dns_rdata_reset(&rdata);
00299                         if (result != ISC_R_SUCCESS)
00300                                 break;
00301                         /*
00302                          * Construct the new query name and start over.
00303                          */
00304                         dns_fixedname_init(&fixed);
00305                         prefix = dns_fixedname_name(&fixed);
00306                         dns_name_split(name, nlabels, prefix, NULL);
00307                         result = dns_name_concatenate(prefix, &dname.dname,
00308                                                       name, NULL);
00309                         dns_rdata_freestruct(&dname);
00310                         if (result == ISC_R_SUCCESS) {
00311                                 want_restart = ISC_TRUE;
00312                                 send_event = ISC_FALSE;
00313                         }
00314                         break;
00315                 default:
00316                         send_event = ISC_TRUE;
00317                 }
00318 
00319                 if (dns_rdataset_isassociated(&lookup->rdataset))
00320                         dns_rdataset_disassociate(&lookup->rdataset);
00321                 if (dns_rdataset_isassociated(&lookup->sigrdataset))
00322                         dns_rdataset_disassociate(&lookup->sigrdataset);
00323 
00324         done:
00325                 if (event != NULL) {
00326                         if (event->node != NULL)
00327                                 dns_db_detachnode(event->db, &event->node);
00328                         if (event->db != NULL)
00329                                 dns_db_detach(&event->db);
00330                         isc_event_free(ISC_EVENT_PTR(&event));
00331                 }
00332 
00333                 /*
00334                  * Limit the number of restarts.
00335                  */
00336                 if (want_restart && lookup->restarts == MAX_RESTARTS) {
00337                         want_restart = ISC_FALSE;
00338                         result = ISC_R_QUOTA;
00339                         send_event = ISC_TRUE;
00340                 }
00341 
00342         } while (want_restart);
00343 
00344         if (send_event) {
00345                 lookup->event->result = result;
00346                 lookup->event->ev_sender = lookup;
00347                 isc_task_sendanddetach(&lookup->task,
00348                                        (isc_event_t **)&lookup->event);
00349                 dns_view_detach(&lookup->view);
00350         }
00351 
00352         UNLOCK(&lookup->lock);
00353 }
00354 
00355 static void
00356 levent_destroy(isc_event_t *event) {
00357         dns_lookupevent_t *levent;
00358         isc_mem_t *mctx;
00359 
00360         REQUIRE(event->ev_type == DNS_EVENT_LOOKUPDONE);
00361         mctx = event->ev_destroy_arg;
00362         levent = (dns_lookupevent_t *)event;
00363 
00364         if (levent->name != NULL) {
00365                 if (dns_name_dynamic(levent->name))
00366                         dns_name_free(levent->name, mctx);
00367                 isc_mem_put(mctx, levent->name, sizeof(dns_name_t));
00368         }
00369         if (levent->rdataset != NULL) {
00370                 dns_rdataset_disassociate(levent->rdataset);
00371                 isc_mem_put(mctx, levent->rdataset, sizeof(dns_rdataset_t));
00372         }
00373         if (levent->sigrdataset != NULL) {
00374                 dns_rdataset_disassociate(levent->sigrdataset);
00375                 isc_mem_put(mctx, levent->sigrdataset, sizeof(dns_rdataset_t));
00376         }
00377         if (levent->node != NULL)
00378                 dns_db_detachnode(levent->db, &levent->node);
00379         if (levent->db != NULL)
00380                 dns_db_detach(&levent->db);
00381         isc_mem_put(mctx, event, event->ev_size);
00382 }
00383 
00384 isc_result_t
00385 dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
00386                   dns_view_t *view, unsigned int options, isc_task_t *task,
00387                   isc_taskaction_t action, void *arg, dns_lookup_t **lookupp)
00388 {
00389         isc_result_t result;
00390         dns_lookup_t *lookup;
00391         isc_event_t *ievent;
00392 
00393         lookup = isc_mem_get(mctx, sizeof(*lookup));
00394         if (lookup == NULL)
00395                 return (ISC_R_NOMEMORY);
00396         lookup->mctx = NULL;
00397         isc_mem_attach(mctx, &lookup->mctx);
00398         lookup->options = options;
00399 
00400         ievent = isc_event_allocate(mctx, lookup, DNS_EVENT_LOOKUPDONE,
00401                                     action, arg, sizeof(*lookup->event));
00402         if (ievent == NULL) {
00403                 result = ISC_R_NOMEMORY;
00404                 goto cleanup_lookup;
00405         }
00406         lookup->event = (dns_lookupevent_t *)ievent;
00407         lookup->event->ev_destroy = levent_destroy;
00408         lookup->event->ev_destroy_arg = mctx;
00409         lookup->event->result = ISC_R_FAILURE;
00410         lookup->event->name = NULL;
00411         lookup->event->rdataset = NULL;
00412         lookup->event->sigrdataset = NULL;
00413         lookup->event->db = NULL;
00414         lookup->event->node = NULL;
00415 
00416         lookup->task = NULL;
00417         isc_task_attach(task, &lookup->task);
00418 
00419         result = isc_mutex_init(&lookup->lock);
00420         if (result != ISC_R_SUCCESS)
00421                 goto cleanup_event;
00422 
00423         dns_fixedname_init(&lookup->name);
00424 
00425         result = dns_name_copy(name, dns_fixedname_name(&lookup->name), NULL);
00426         if (result != ISC_R_SUCCESS)
00427                 goto cleanup_lock;
00428 
00429         lookup->type = type;
00430         lookup->view = NULL;
00431         dns_view_attach(view, &lookup->view);
00432         lookup->fetch = NULL;
00433         lookup->restarts = 0;
00434         lookup->canceled = ISC_FALSE;
00435         dns_rdataset_init(&lookup->rdataset);
00436         dns_rdataset_init(&lookup->sigrdataset);
00437         lookup->magic = LOOKUP_MAGIC;
00438 
00439         *lookupp = lookup;
00440 
00441         lookup_find(lookup, NULL);
00442 
00443         return (ISC_R_SUCCESS);
00444 
00445  cleanup_lock:
00446         DESTROYLOCK(&lookup->lock);
00447 
00448  cleanup_event:
00449         ievent = (isc_event_t *)lookup->event;
00450         isc_event_free(&ievent);
00451         lookup->event = NULL;
00452 
00453         isc_task_detach(&lookup->task);
00454 
00455  cleanup_lookup:
00456         isc_mem_putanddetach(&mctx, lookup, sizeof(*lookup));
00457 
00458         return (result);
00459 }
00460 
00461 void
00462 dns_lookup_cancel(dns_lookup_t *lookup) {
00463         REQUIRE(VALID_LOOKUP(lookup));
00464 
00465         LOCK(&lookup->lock);
00466 
00467         if (!lookup->canceled) {
00468                 lookup->canceled = ISC_TRUE;
00469                 if (lookup->fetch != NULL) {
00470                         INSIST(lookup->view != NULL);
00471                         dns_resolver_cancelfetch(lookup->fetch);
00472                 }
00473         }
00474 
00475         UNLOCK(&lookup->lock);
00476 }
00477 
00478 void
00479 dns_lookup_destroy(dns_lookup_t **lookupp) {
00480         dns_lookup_t *lookup;
00481 
00482         REQUIRE(lookupp != NULL);
00483         lookup = *lookupp;
00484         REQUIRE(VALID_LOOKUP(lookup));
00485         REQUIRE(lookup->event == NULL);
00486         REQUIRE(lookup->task == NULL);
00487         REQUIRE(lookup->view == NULL);
00488         if (dns_rdataset_isassociated(&lookup->rdataset))
00489                 dns_rdataset_disassociate(&lookup->rdataset);
00490         if (dns_rdataset_isassociated(&lookup->sigrdataset))
00491                 dns_rdataset_disassociate(&lookup->sigrdataset);
00492 
00493         DESTROYLOCK(&lookup->lock);
00494         lookup->magic = 0;
00495         isc_mem_putanddetach(&lookup->mctx, lookup, sizeof(*lookup));
00496 
00497         *lookupp = NULL;
00498 }

Generated on Tue Apr 28 17:40:57 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha