4 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: lookup.c,v 1.21 2007/06/18 23:47:40 tbox Exp */
27 #include <isc/netaddr.h>
28 #include <isc/string.h> /* Required for HP/UX (and others?) */
33 #include <dns/events.h>
34 #include <dns/lookup.h>
35 #include <dns/rdata.h>
36 #include <dns/rdataset.h>
37 #include <dns/rdatastruct.h>
38 #include <dns/resolver.h>
39 #include <dns/result.h>
53 dns_lookupevent_t
* event
;
55 unsigned int restarts
;
56 isc_boolean_t canceled
;
57 dns_rdataset_t rdataset
;
58 dns_rdataset_t sigrdataset
;
61 #define LOOKUP_MAGIC ISC_MAGIC('l', 'o', 'o', 'k')
62 #define VALID_LOOKUP(l) ISC_MAGIC_VALID((l), LOOKUP_MAGIC)
64 #define MAX_RESTARTS 16
66 static void lookup_find(dns_lookup_t
*lookup
, dns_fetchevent_t
*event
);
69 fetch_done(isc_task_t
*task
, isc_event_t
*event
) {
70 dns_lookup_t
*lookup
= event
->ev_arg
;
71 dns_fetchevent_t
*fevent
;
74 REQUIRE(event
->ev_type
== DNS_EVENT_FETCHDONE
);
75 REQUIRE(VALID_LOOKUP(lookup
));
76 REQUIRE(lookup
->task
== task
);
77 fevent
= (dns_fetchevent_t
*)event
;
78 REQUIRE(fevent
->fetch
== lookup
->fetch
);
80 lookup_find(lookup
, fevent
);
83 static inline isc_result_t
84 start_fetch(dns_lookup_t
*lookup
) {
88 * The caller must be holding the lookup's lock.
91 REQUIRE(lookup
->fetch
== NULL
);
93 result
= dns_resolver_createfetch(lookup
->view
->resolver
,
94 dns_fixedname_name(&lookup
->name
),
97 lookup
->task
, fetch_done
, lookup
,
106 build_event(dns_lookup_t
*lookup
) {
107 dns_name_t
*name
= NULL
;
108 dns_rdataset_t
*rdataset
= NULL
;
109 dns_rdataset_t
*sigrdataset
= NULL
;
112 name
= isc_mem_get(lookup
->mctx
, sizeof(dns_name_t
));
114 result
= ISC_R_NOMEMORY
;
117 dns_name_init(name
, NULL
);
118 result
= dns_name_dup(dns_fixedname_name(&lookup
->name
),
120 if (result
!= ISC_R_SUCCESS
)
123 if (dns_rdataset_isassociated(&lookup
->rdataset
)) {
124 rdataset
= isc_mem_get(lookup
->mctx
, sizeof(dns_rdataset_t
));
125 if (rdataset
== NULL
) {
126 result
= ISC_R_NOMEMORY
;
129 dns_rdataset_init(rdataset
);
130 dns_rdataset_clone(&lookup
->rdataset
, rdataset
);
133 if (dns_rdataset_isassociated(&lookup
->sigrdataset
)) {
134 sigrdataset
= isc_mem_get(lookup
->mctx
,
135 sizeof(dns_rdataset_t
));
136 if (sigrdataset
== NULL
) {
137 result
= ISC_R_NOMEMORY
;
140 dns_rdataset_init(sigrdataset
);
141 dns_rdataset_clone(&lookup
->sigrdataset
, sigrdataset
);
144 lookup
->event
->name
= name
;
145 lookup
->event
->rdataset
= rdataset
;
146 lookup
->event
->sigrdataset
= sigrdataset
;
148 return (ISC_R_SUCCESS
);
152 if (dns_name_dynamic(name
))
153 dns_name_free(name
, lookup
->mctx
);
154 isc_mem_put(lookup
->mctx
, name
, sizeof(dns_name_t
));
156 if (rdataset
!= NULL
) {
157 if (dns_rdataset_isassociated(rdataset
))
158 dns_rdataset_disassociate(rdataset
);
159 isc_mem_put(lookup
->mctx
, rdataset
, sizeof(dns_rdataset_t
));
165 view_find(dns_lookup_t
*lookup
, dns_name_t
*foundname
) {
167 dns_name_t
*name
= dns_fixedname_name(&lookup
->name
);
168 dns_rdatatype_t type
;
170 if (lookup
->type
== dns_rdatatype_rrsig
)
171 type
= dns_rdatatype_any
;
175 result
= dns_view_find(lookup
->view
, name
, type
, 0, 0, ISC_FALSE
,
176 &lookup
->event
->db
, &lookup
->event
->node
,
177 foundname
, &lookup
->rdataset
,
178 &lookup
->sigrdataset
);
183 lookup_find(dns_lookup_t
*lookup
, dns_fetchevent_t
*event
) {
185 isc_boolean_t want_restart
;
186 isc_boolean_t send_event
;
187 dns_name_t
*name
, *fname
, *prefix
;
188 dns_fixedname_t foundname
, fixed
;
189 dns_rdata_t rdata
= DNS_RDATA_INIT
;
190 unsigned int nlabels
;
192 dns_namereln_t namereln
;
193 dns_rdata_cname_t cname
;
194 dns_rdata_dname_t dname
;
196 REQUIRE(VALID_LOOKUP(lookup
));
200 result
= ISC_R_SUCCESS
;
201 name
= dns_fixedname_name(&lookup
->name
);
205 want_restart
= ISC_FALSE
;
206 send_event
= ISC_TRUE
;
208 if (event
== NULL
&& !lookup
->canceled
) {
209 dns_fixedname_init(&foundname
);
210 fname
= dns_fixedname_name(&foundname
);
211 INSIST(!dns_rdataset_isassociated(&lookup
->rdataset
));
212 INSIST(!dns_rdataset_isassociated
213 (&lookup
->sigrdataset
));
215 * If we have restarted then clear the old node. */
216 if (lookup
->event
->node
!= NULL
) {
217 INSIST(lookup
->event
->db
!= NULL
);
218 dns_db_detachnode(lookup
->event
->db
,
219 &lookup
->event
->node
);
221 if (lookup
->event
->db
!= NULL
)
222 dns_db_detach(&lookup
->event
->db
);
223 result
= view_find(lookup
, fname
);
224 if (result
== ISC_R_NOTFOUND
) {
226 * We don't know anything about the name.
229 if (lookup
->event
->node
!= NULL
) {
230 INSIST(lookup
->event
->db
!= NULL
);
231 dns_db_detachnode(lookup
->event
->db
,
232 &lookup
->event
->node
);
234 if (lookup
->event
->db
!= NULL
)
235 dns_db_detach(&lookup
->event
->db
);
236 result
= start_fetch(lookup
);
237 if (result
== ISC_R_SUCCESS
)
238 send_event
= ISC_FALSE
;
241 } else if (event
!= NULL
) {
242 result
= event
->result
;
243 fname
= dns_fixedname_name(&event
->foundname
);
244 dns_resolver_destroyfetch(&lookup
->fetch
);
245 INSIST(event
->rdataset
== &lookup
->rdataset
);
246 INSIST(event
->sigrdataset
== &lookup
->sigrdataset
);
248 fname
= NULL
; /* Silence compiler warning. */
251 * If we've been canceled, forget about the result.
253 if (lookup
->canceled
)
254 result
= ISC_R_CANCELED
;
258 result
= build_event(lookup
);
261 if (event
->db
!= NULL
)
262 dns_db_attach(event
->db
, &lookup
->event
->db
);
263 if (event
->node
!= NULL
)
264 dns_db_attachnode(lookup
->event
->db
,
266 &lookup
->event
->node
);
270 * Copy the CNAME's target into the lookup's
271 * query name and start over.
273 result
= dns_rdataset_first(&lookup
->rdataset
);
274 if (result
!= ISC_R_SUCCESS
)
276 dns_rdataset_current(&lookup
->rdataset
, &rdata
);
277 result
= dns_rdata_tostruct(&rdata
, &cname
, NULL
);
278 dns_rdata_reset(&rdata
);
279 if (result
!= ISC_R_SUCCESS
)
281 result
= dns_name_copy(&cname
.cname
, name
, NULL
);
282 dns_rdata_freestruct(&cname
);
283 if (result
== ISC_R_SUCCESS
) {
284 want_restart
= ISC_TRUE
;
285 send_event
= ISC_FALSE
;
289 namereln
= dns_name_fullcompare(name
, fname
, &order
,
291 INSIST(namereln
== dns_namereln_subdomain
);
293 * Get the target name of the DNAME.
295 result
= dns_rdataset_first(&lookup
->rdataset
);
296 if (result
!= ISC_R_SUCCESS
)
298 dns_rdataset_current(&lookup
->rdataset
, &rdata
);
299 result
= dns_rdata_tostruct(&rdata
, &dname
, NULL
);
300 dns_rdata_reset(&rdata
);
301 if (result
!= ISC_R_SUCCESS
)
304 * Construct the new query name and start over.
306 dns_fixedname_init(&fixed
);
307 prefix
= dns_fixedname_name(&fixed
);
308 dns_name_split(name
, nlabels
, prefix
, NULL
);
309 result
= dns_name_concatenate(prefix
, &dname
.dname
,
311 dns_rdata_freestruct(&dname
);
312 if (result
== ISC_R_SUCCESS
) {
313 want_restart
= ISC_TRUE
;
314 send_event
= ISC_FALSE
;
318 send_event
= ISC_TRUE
;
321 if (dns_rdataset_isassociated(&lookup
->rdataset
))
322 dns_rdataset_disassociate(&lookup
->rdataset
);
323 if (dns_rdataset_isassociated(&lookup
->sigrdataset
))
324 dns_rdataset_disassociate(&lookup
->sigrdataset
);
328 if (event
->node
!= NULL
)
329 dns_db_detachnode(event
->db
, &event
->node
);
330 if (event
->db
!= NULL
)
331 dns_db_detach(&event
->db
);
332 isc_event_free(ISC_EVENT_PTR(&event
));
336 * Limit the number of restarts.
338 if (want_restart
&& lookup
->restarts
== MAX_RESTARTS
) {
339 want_restart
= ISC_FALSE
;
340 result
= ISC_R_QUOTA
;
341 send_event
= ISC_TRUE
;
344 } while (want_restart
);
347 lookup
->event
->result
= result
;
348 lookup
->event
->ev_sender
= lookup
;
349 isc_task_sendanddetach(&lookup
->task
,
350 (isc_event_t
**)&lookup
->event
);
351 dns_view_detach(&lookup
->view
);
354 UNLOCK(&lookup
->lock
);
358 levent_destroy(isc_event_t
*event
) {
359 dns_lookupevent_t
*levent
;
362 REQUIRE(event
->ev_type
== DNS_EVENT_LOOKUPDONE
);
363 mctx
= event
->ev_destroy_arg
;
364 levent
= (dns_lookupevent_t
*)event
;
366 if (levent
->name
!= NULL
) {
367 if (dns_name_dynamic(levent
->name
))
368 dns_name_free(levent
->name
, mctx
);
369 isc_mem_put(mctx
, levent
->name
, sizeof(dns_name_t
));
371 if (levent
->rdataset
!= NULL
) {
372 dns_rdataset_disassociate(levent
->rdataset
);
373 isc_mem_put(mctx
, levent
->rdataset
, sizeof(dns_rdataset_t
));
375 if (levent
->sigrdataset
!= NULL
) {
376 dns_rdataset_disassociate(levent
->sigrdataset
);
377 isc_mem_put(mctx
, levent
->sigrdataset
, sizeof(dns_rdataset_t
));
379 if (levent
->node
!= NULL
)
380 dns_db_detachnode(levent
->db
, &levent
->node
);
381 if (levent
->db
!= NULL
)
382 dns_db_detach(&levent
->db
);
383 isc_mem_put(mctx
, event
, event
->ev_size
);
387 dns_lookup_create(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdatatype_t type
,
388 dns_view_t
*view
, unsigned int options
, isc_task_t
*task
,
389 isc_taskaction_t action
, void *arg
, dns_lookup_t
**lookupp
)
392 dns_lookup_t
*lookup
;
395 lookup
= isc_mem_get(mctx
, sizeof(*lookup
));
397 return (ISC_R_NOMEMORY
);
399 lookup
->options
= options
;
401 ievent
= isc_event_allocate(mctx
, lookup
, DNS_EVENT_LOOKUPDONE
,
402 action
, arg
, sizeof(*lookup
->event
));
403 if (ievent
== NULL
) {
404 result
= ISC_R_NOMEMORY
;
407 lookup
->event
= (dns_lookupevent_t
*)ievent
;
408 lookup
->event
->ev_destroy
= levent_destroy
;
409 lookup
->event
->ev_destroy_arg
= mctx
;
410 lookup
->event
->result
= ISC_R_FAILURE
;
411 lookup
->event
->name
= NULL
;
412 lookup
->event
->rdataset
= NULL
;
413 lookup
->event
->sigrdataset
= NULL
;
414 lookup
->event
->db
= NULL
;
415 lookup
->event
->node
= NULL
;
418 isc_task_attach(task
, &lookup
->task
);
420 result
= isc_mutex_init(&lookup
->lock
);
421 if (result
!= ISC_R_SUCCESS
)
424 dns_fixedname_init(&lookup
->name
);
426 result
= dns_name_copy(name
, dns_fixedname_name(&lookup
->name
), NULL
);
427 if (result
!= ISC_R_SUCCESS
)
432 dns_view_attach(view
, &lookup
->view
);
433 lookup
->fetch
= NULL
;
434 lookup
->restarts
= 0;
435 lookup
->canceled
= ISC_FALSE
;
436 dns_rdataset_init(&lookup
->rdataset
);
437 dns_rdataset_init(&lookup
->sigrdataset
);
438 lookup
->magic
= LOOKUP_MAGIC
;
442 lookup_find(lookup
, NULL
);
444 return (ISC_R_SUCCESS
);
447 DESTROYLOCK(&lookup
->lock
);
450 ievent
= (isc_event_t
*)lookup
->event
;
451 isc_event_free(&ievent
);
452 lookup
->event
= NULL
;
454 isc_task_detach(&lookup
->task
);
457 isc_mem_put(mctx
, lookup
, sizeof(*lookup
));
463 dns_lookup_cancel(dns_lookup_t
*lookup
) {
464 REQUIRE(VALID_LOOKUP(lookup
));
468 if (!lookup
->canceled
) {
469 lookup
->canceled
= ISC_TRUE
;
470 if (lookup
->fetch
!= NULL
) {
471 INSIST(lookup
->view
!= NULL
);
472 dns_resolver_cancelfetch(lookup
->fetch
);
476 UNLOCK(&lookup
->lock
);
480 dns_lookup_destroy(dns_lookup_t
**lookupp
) {
481 dns_lookup_t
*lookup
;
483 REQUIRE(lookupp
!= NULL
);
485 REQUIRE(VALID_LOOKUP(lookup
));
486 REQUIRE(lookup
->event
== NULL
);
487 REQUIRE(lookup
->task
== NULL
);
488 REQUIRE(lookup
->view
== NULL
);
489 if (dns_rdataset_isassociated(&lookup
->rdataset
))
490 dns_rdataset_disassociate(&lookup
->rdataset
);
491 if (dns_rdataset_isassociated(&lookup
->sigrdataset
))
492 dns_rdataset_disassociate(&lookup
->sigrdataset
);
494 DESTROYLOCK(&lookup
->lock
);
496 isc_mem_put(lookup
->mctx
, lookup
, sizeof(*lookup
));