00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/mem.h>
00025 #include <isc/netaddr.h>
00026 #include <isc/string.h>
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
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
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
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
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
00225
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;
00247
00248
00249
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
00269
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
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
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
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 }