2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: lookup.c,v 1.21 2007/06/18 23:47:40 tbox Exp $ */
25 #include <isc/netaddr.h>
26 #include <isc/string.h> /* Required for HP/UX (and others?) */
31 #include <dns/events.h>
32 #include <dns/lookup.h>
33 #include <dns/rdata.h>
34 #include <dns/rdataset.h>
35 #include <dns/rdatastruct.h>
36 #include <dns/resolver.h>
37 #include <dns/result.h>
51 dns_lookupevent_t * event;
53 unsigned int restarts;
54 isc_boolean_t canceled;
55 dns_rdataset_t rdataset;
56 dns_rdataset_t sigrdataset;
59 #define LOOKUP_MAGIC ISC_MAGIC('l', 'o', 'o', 'k')
60 #define VALID_LOOKUP(l) ISC_MAGIC_VALID((l), LOOKUP_MAGIC)
62 #define MAX_RESTARTS 16
64 static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event);
67 fetch_done(isc_task_t *task, isc_event_t *event) {
68 dns_lookup_t *lookup = event->ev_arg;
69 dns_fetchevent_t *fevent;
72 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
73 REQUIRE(VALID_LOOKUP(lookup));
74 REQUIRE(lookup->task == task);
75 fevent = (dns_fetchevent_t *)event;
76 REQUIRE(fevent->fetch == lookup->fetch);
78 lookup_find(lookup, fevent);
81 static inline isc_result_t
82 start_fetch(dns_lookup_t *lookup) {
86 * The caller must be holding the lookup's lock.
89 REQUIRE(lookup->fetch == NULL);
91 result = dns_resolver_createfetch(lookup->view->resolver,
92 dns_fixedname_name(&lookup->name),
95 lookup->task, fetch_done, lookup,
104 build_event(dns_lookup_t *lookup) {
105 dns_name_t *name = NULL;
106 dns_rdataset_t *rdataset = NULL;
107 dns_rdataset_t *sigrdataset = NULL;
110 name = isc_mem_get(lookup->mctx, sizeof(dns_name_t));
112 result = ISC_R_NOMEMORY;
115 dns_name_init(name, NULL);
116 result = dns_name_dup(dns_fixedname_name(&lookup->name),
118 if (result != ISC_R_SUCCESS)
121 if (dns_rdataset_isassociated(&lookup->rdataset)) {
122 rdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t));
123 if (rdataset == NULL) {
124 result = ISC_R_NOMEMORY;
127 dns_rdataset_init(rdataset);
128 dns_rdataset_clone(&lookup->rdataset, rdataset);
131 if (dns_rdataset_isassociated(&lookup->sigrdataset)) {
132 sigrdataset = isc_mem_get(lookup->mctx,
133 sizeof(dns_rdataset_t));
134 if (sigrdataset == NULL) {
135 result = ISC_R_NOMEMORY;
138 dns_rdataset_init(sigrdataset);
139 dns_rdataset_clone(&lookup->sigrdataset, sigrdataset);
142 lookup->event->name = name;
143 lookup->event->rdataset = rdataset;
144 lookup->event->sigrdataset = sigrdataset;
146 return (ISC_R_SUCCESS);
150 if (dns_name_dynamic(name))
151 dns_name_free(name, lookup->mctx);
152 isc_mem_put(lookup->mctx, name, sizeof(dns_name_t));
154 if (rdataset != NULL) {
155 if (dns_rdataset_isassociated(rdataset))
156 dns_rdataset_disassociate(rdataset);
157 isc_mem_put(lookup->mctx, rdataset, sizeof(dns_rdataset_t));
163 view_find(dns_lookup_t *lookup, dns_name_t *foundname) {
165 dns_name_t *name = dns_fixedname_name(&lookup->name);
166 dns_rdatatype_t type;
168 if (lookup->type == dns_rdatatype_rrsig)
169 type = dns_rdatatype_any;
173 result = dns_view_find(lookup->view, name, type, 0, 0, ISC_FALSE,
174 &lookup->event->db, &lookup->event->node,
175 foundname, &lookup->rdataset,
176 &lookup->sigrdataset);
181 lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) {
183 isc_boolean_t want_restart;
184 isc_boolean_t send_event;
185 dns_name_t *name, *fname, *prefix;
186 dns_fixedname_t foundname, fixed;
187 dns_rdata_t rdata = DNS_RDATA_INIT;
188 unsigned int nlabels;
190 dns_namereln_t namereln;
191 dns_rdata_cname_t cname;
192 dns_rdata_dname_t dname;
194 REQUIRE(VALID_LOOKUP(lookup));
198 result = ISC_R_SUCCESS;
199 name = dns_fixedname_name(&lookup->name);
203 want_restart = ISC_FALSE;
204 send_event = ISC_TRUE;
206 if (event == NULL && !lookup->canceled) {
207 dns_fixedname_init(&foundname);
208 fname = dns_fixedname_name(&foundname);
209 INSIST(!dns_rdataset_isassociated(&lookup->rdataset));
210 INSIST(!dns_rdataset_isassociated
211 (&lookup->sigrdataset));
213 * If we have restarted then clear the old node. */
214 if (lookup->event->node != NULL) {
215 INSIST(lookup->event->db != NULL);
216 dns_db_detachnode(lookup->event->db,
217 &lookup->event->node);
219 if (lookup->event->db != NULL)
220 dns_db_detach(&lookup->event->db);
221 result = view_find(lookup, fname);
222 if (result == ISC_R_NOTFOUND) {
224 * We don't know anything about the name.
227 if (lookup->event->node != NULL) {
228 INSIST(lookup->event->db != NULL);
229 dns_db_detachnode(lookup->event->db,
230 &lookup->event->node);
232 if (lookup->event->db != NULL)
233 dns_db_detach(&lookup->event->db);
234 result = start_fetch(lookup);
235 if (result == ISC_R_SUCCESS)
236 send_event = ISC_FALSE;
239 } else if (event != NULL) {
240 result = event->result;
241 fname = dns_fixedname_name(&event->foundname);
242 dns_resolver_destroyfetch(&lookup->fetch);
243 INSIST(event->rdataset == &lookup->rdataset);
244 INSIST(event->sigrdataset == &lookup->sigrdataset);
246 fname = NULL; /* Silence compiler warning. */
249 * If we've been canceled, forget about the result.
251 if (lookup->canceled)
252 result = ISC_R_CANCELED;
256 result = build_event(lookup);
259 if (event->db != NULL)
260 dns_db_attach(event->db, &lookup->event->db);
261 if (event->node != NULL)
262 dns_db_attachnode(lookup->event->db,
264 &lookup->event->node);
268 * Copy the CNAME's target into the lookup's
269 * query name and start over.
271 result = dns_rdataset_first(&lookup->rdataset);
272 if (result != ISC_R_SUCCESS)
274 dns_rdataset_current(&lookup->rdataset, &rdata);
275 result = dns_rdata_tostruct(&rdata, &cname, NULL);
276 dns_rdata_reset(&rdata);
277 if (result != ISC_R_SUCCESS)
279 result = dns_name_copy(&cname.cname, name, NULL);
280 dns_rdata_freestruct(&cname);
281 if (result == ISC_R_SUCCESS) {
282 want_restart = ISC_TRUE;
283 send_event = ISC_FALSE;
287 namereln = dns_name_fullcompare(name, fname, &order,
289 INSIST(namereln == dns_namereln_subdomain);
291 * Get the target name of the DNAME.
293 result = dns_rdataset_first(&lookup->rdataset);
294 if (result != ISC_R_SUCCESS)
296 dns_rdataset_current(&lookup->rdataset, &rdata);
297 result = dns_rdata_tostruct(&rdata, &dname, NULL);
298 dns_rdata_reset(&rdata);
299 if (result != ISC_R_SUCCESS)
302 * Construct the new query name and start over.
304 dns_fixedname_init(&fixed);
305 prefix = dns_fixedname_name(&fixed);
306 dns_name_split(name, nlabels, prefix, NULL);
307 result = dns_name_concatenate(prefix, &dname.dname,
309 dns_rdata_freestruct(&dname);
310 if (result == ISC_R_SUCCESS) {
311 want_restart = ISC_TRUE;
312 send_event = ISC_FALSE;
316 send_event = ISC_TRUE;
319 if (dns_rdataset_isassociated(&lookup->rdataset))
320 dns_rdataset_disassociate(&lookup->rdataset);
321 if (dns_rdataset_isassociated(&lookup->sigrdataset))
322 dns_rdataset_disassociate(&lookup->sigrdataset);
326 if (event->node != NULL)
327 dns_db_detachnode(event->db, &event->node);
328 if (event->db != NULL)
329 dns_db_detach(&event->db);
330 isc_event_free(ISC_EVENT_PTR(&event));
334 * Limit the number of restarts.
336 if (want_restart && lookup->restarts == MAX_RESTARTS) {
337 want_restart = ISC_FALSE;
338 result = ISC_R_QUOTA;
339 send_event = ISC_TRUE;
342 } while (want_restart);
345 lookup->event->result = result;
346 lookup->event->ev_sender = lookup;
347 isc_task_sendanddetach(&lookup->task,
348 (isc_event_t **)&lookup->event);
349 dns_view_detach(&lookup->view);
352 UNLOCK(&lookup->lock);
356 levent_destroy(isc_event_t *event) {
357 dns_lookupevent_t *levent;
360 REQUIRE(event->ev_type == DNS_EVENT_LOOKUPDONE);
361 mctx = event->ev_destroy_arg;
362 levent = (dns_lookupevent_t *)event;
364 if (levent->name != NULL) {
365 if (dns_name_dynamic(levent->name))
366 dns_name_free(levent->name, mctx);
367 isc_mem_put(mctx, levent->name, sizeof(dns_name_t));
369 if (levent->rdataset != NULL) {
370 dns_rdataset_disassociate(levent->rdataset);
371 isc_mem_put(mctx, levent->rdataset, sizeof(dns_rdataset_t));
373 if (levent->sigrdataset != NULL) {
374 dns_rdataset_disassociate(levent->sigrdataset);
375 isc_mem_put(mctx, levent->sigrdataset, sizeof(dns_rdataset_t));
377 if (levent->node != NULL)
378 dns_db_detachnode(levent->db, &levent->node);
379 if (levent->db != NULL)
380 dns_db_detach(&levent->db);
381 isc_mem_put(mctx, event, event->ev_size);
385 dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
386 dns_view_t *view, unsigned int options, isc_task_t *task,
387 isc_taskaction_t action, void *arg, dns_lookup_t **lookupp)
390 dns_lookup_t *lookup;
393 lookup = isc_mem_get(mctx, sizeof(*lookup));
395 return (ISC_R_NOMEMORY);
397 lookup->options = options;
399 ievent = isc_event_allocate(mctx, lookup, DNS_EVENT_LOOKUPDONE,
400 action, arg, sizeof(*lookup->event));
401 if (ievent == NULL) {
402 result = ISC_R_NOMEMORY;
405 lookup->event = (dns_lookupevent_t *)ievent;
406 lookup->event->ev_destroy = levent_destroy;
407 lookup->event->ev_destroy_arg = mctx;
408 lookup->event->result = ISC_R_FAILURE;
409 lookup->event->name = NULL;
410 lookup->event->rdataset = NULL;
411 lookup->event->sigrdataset = NULL;
412 lookup->event->db = NULL;
413 lookup->event->node = NULL;
416 isc_task_attach(task, &lookup->task);
418 result = isc_mutex_init(&lookup->lock);
419 if (result != ISC_R_SUCCESS)
422 dns_fixedname_init(&lookup->name);
424 result = dns_name_copy(name, dns_fixedname_name(&lookup->name), NULL);
425 if (result != ISC_R_SUCCESS)
430 dns_view_attach(view, &lookup->view);
431 lookup->fetch = NULL;
432 lookup->restarts = 0;
433 lookup->canceled = ISC_FALSE;
434 dns_rdataset_init(&lookup->rdataset);
435 dns_rdataset_init(&lookup->sigrdataset);
436 lookup->magic = LOOKUP_MAGIC;
440 lookup_find(lookup, NULL);
442 return (ISC_R_SUCCESS);
445 DESTROYLOCK(&lookup->lock);
448 ievent = (isc_event_t *)lookup->event;
449 isc_event_free(&ievent);
450 lookup->event = NULL;
452 isc_task_detach(&lookup->task);
455 isc_mem_put(mctx, lookup, sizeof(*lookup));
461 dns_lookup_cancel(dns_lookup_t *lookup) {
462 REQUIRE(VALID_LOOKUP(lookup));
466 if (!lookup->canceled) {
467 lookup->canceled = ISC_TRUE;
468 if (lookup->fetch != NULL) {
469 INSIST(lookup->view != NULL);
470 dns_resolver_cancelfetch(lookup->fetch);
474 UNLOCK(&lookup->lock);
478 dns_lookup_destroy(dns_lookup_t **lookupp) {
479 dns_lookup_t *lookup;
481 REQUIRE(lookupp != NULL);
483 REQUIRE(VALID_LOOKUP(lookup));
484 REQUIRE(lookup->event == NULL);
485 REQUIRE(lookup->task == NULL);
486 REQUIRE(lookup->view == NULL);
487 if (dns_rdataset_isassociated(&lookup->rdataset))
488 dns_rdataset_disassociate(&lookup->rdataset);
489 if (dns_rdataset_isassociated(&lookup->sigrdataset))
490 dns_rdataset_disassociate(&lookup->sigrdataset);
492 DESTROYLOCK(&lookup->lock);
494 isc_mem_put(lookup->mctx, lookup, sizeof(*lookup));