2 * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.9.12.7 2006/01/04 23:50:20 marka Exp $ */
23 #include <isc/netaddr.h>
24 #include <isc/string.h> /* Required for HP/UX (and others?) */
29 #include <dns/events.h>
30 #include <dns/lookup.h>
31 #include <dns/rdata.h>
32 #include <dns/rdataset.h>
33 #include <dns/rdatastruct.h>
34 #include <dns/resolver.h>
35 #include <dns/result.h>
49 dns_lookupevent_t
* event
;
51 unsigned int restarts
;
52 isc_boolean_t canceled
;
53 dns_rdataset_t rdataset
;
54 dns_rdataset_t sigrdataset
;
57 #define LOOKUP_MAGIC ISC_MAGIC('l', 'o', 'o', 'k')
58 #define VALID_LOOKUP(l) ISC_MAGIC_VALID((l), LOOKUP_MAGIC)
60 #define MAX_RESTARTS 16
62 static void lookup_find(dns_lookup_t
*lookup
, dns_fetchevent_t
*event
);
65 fetch_done(isc_task_t
*task
, isc_event_t
*event
) {
66 dns_lookup_t
*lookup
= event
->ev_arg
;
67 dns_fetchevent_t
*fevent
;
70 REQUIRE(event
->ev_type
== DNS_EVENT_FETCHDONE
);
71 REQUIRE(VALID_LOOKUP(lookup
));
72 REQUIRE(lookup
->task
== task
);
73 fevent
= (dns_fetchevent_t
*)event
;
74 REQUIRE(fevent
->fetch
== lookup
->fetch
);
76 lookup_find(lookup
, fevent
);
79 static inline isc_result_t
80 start_fetch(dns_lookup_t
*lookup
) {
84 * The caller must be holding the lookup's lock.
87 REQUIRE(lookup
->fetch
== NULL
);
89 result
= dns_resolver_createfetch(lookup
->view
->resolver
,
90 dns_fixedname_name(&lookup
->name
),
93 lookup
->task
, fetch_done
, lookup
,
102 build_event(dns_lookup_t
*lookup
) {
103 dns_name_t
*name
= NULL
;
104 dns_rdataset_t
*rdataset
= NULL
;
105 dns_rdataset_t
*sigrdataset
= NULL
;
108 name
= isc_mem_get(lookup
->mctx
, sizeof(dns_name_t
));
110 result
= ISC_R_NOMEMORY
;
113 dns_name_init(name
, NULL
);
114 result
= dns_name_dup(dns_fixedname_name(&lookup
->name
),
116 if (result
!= ISC_R_SUCCESS
)
119 if (dns_rdataset_isassociated(&lookup
->rdataset
)) {
120 rdataset
= isc_mem_get(lookup
->mctx
, sizeof(dns_rdataset_t
));
121 if (rdataset
== NULL
) {
122 result
= ISC_R_NOMEMORY
;
125 dns_rdataset_init(rdataset
);
126 dns_rdataset_clone(&lookup
->rdataset
, rdataset
);
129 if (dns_rdataset_isassociated(&lookup
->sigrdataset
)) {
130 sigrdataset
= isc_mem_get(lookup
->mctx
,
131 sizeof(dns_rdataset_t
));
132 if (sigrdataset
== NULL
) {
133 result
= ISC_R_NOMEMORY
;
136 dns_rdataset_init(sigrdataset
);
137 dns_rdataset_clone(&lookup
->sigrdataset
, sigrdataset
);
140 lookup
->event
->name
= name
;
141 lookup
->event
->rdataset
= rdataset
;
142 lookup
->event
->sigrdataset
= sigrdataset
;
144 return (ISC_R_SUCCESS
);
148 if (dns_name_dynamic(name
))
149 dns_name_free(name
, lookup
->mctx
);
150 isc_mem_put(lookup
->mctx
, name
, sizeof(dns_name_t
));
152 if (rdataset
!= NULL
) {
153 if (dns_rdataset_isassociated(rdataset
))
154 dns_rdataset_disassociate(rdataset
);
155 isc_mem_put(lookup
->mctx
, rdataset
, sizeof(dns_rdataset_t
));
161 view_find(dns_lookup_t
*lookup
, dns_name_t
*foundname
) {
163 dns_name_t
*name
= dns_fixedname_name(&lookup
->name
);
164 dns_rdatatype_t type
;
166 if (lookup
->type
== dns_rdatatype_rrsig
)
167 type
= dns_rdatatype_any
;
171 result
= dns_view_find(lookup
->view
, name
, type
, 0, 0, ISC_FALSE
,
172 &lookup
->event
->db
, &lookup
->event
->node
,
173 foundname
, &lookup
->rdataset
,
174 &lookup
->sigrdataset
);
179 lookup_find(dns_lookup_t
*lookup
, dns_fetchevent_t
*event
) {
181 isc_boolean_t want_restart
;
182 isc_boolean_t send_event
= ISC_FALSE
;
183 dns_name_t
*name
, *fname
, *prefix
;
184 dns_fixedname_t foundname
, fixed
;
185 dns_rdata_t rdata
= DNS_RDATA_INIT
;
186 unsigned int nlabels
;
188 dns_namereln_t namereln
;
189 dns_rdata_cname_t cname
;
190 dns_rdata_dname_t dname
;
192 REQUIRE(VALID_LOOKUP(lookup
));
196 result
= ISC_R_SUCCESS
;
197 name
= dns_fixedname_name(&lookup
->name
);
201 want_restart
= ISC_FALSE
;
203 if (event
== NULL
&& !lookup
->canceled
) {
204 dns_fixedname_init(&foundname
);
205 fname
= dns_fixedname_name(&foundname
);
206 INSIST(!dns_rdataset_isassociated(&lookup
->rdataset
));
207 INSIST(!dns_rdataset_isassociated
208 (&lookup
->sigrdataset
));
209 result
= view_find(lookup
, fname
);
210 if (result
== ISC_R_NOTFOUND
) {
212 * We don't know anything about the name.
215 if (lookup
->event
->node
!= NULL
) {
216 INSIST(lookup
->event
->db
!= NULL
);
217 dns_db_detachnode(lookup
->event
->db
,
218 &lookup
->event
->node
);
220 if (lookup
->event
->db
!= NULL
)
221 dns_db_detach(&lookup
->event
->db
);
222 result
= start_fetch(lookup
);
223 if (result
!= ISC_R_SUCCESS
)
224 send_event
= ISC_TRUE
;
227 } else if (event
!= NULL
) {
228 result
= event
->result
;
229 fname
= dns_fixedname_name(&event
->foundname
);
230 dns_resolver_destroyfetch(&lookup
->fetch
);
231 INSIST(event
->rdataset
== &lookup
->rdataset
);
232 INSIST(event
->sigrdataset
== &lookup
->sigrdataset
);
234 fname
= NULL
; /* Silence compiler warning. */
237 * If we've been canceled, forget about the result.
239 if (lookup
->canceled
)
240 result
= ISC_R_CANCELED
;
244 result
= build_event(lookup
);
245 send_event
= ISC_TRUE
;
248 if (event
->db
!= NULL
)
249 dns_db_attach(event
->db
, &lookup
->event
->db
);
250 if (event
->node
!= NULL
)
251 dns_db_attachnode(lookup
->event
->db
,
253 &lookup
->event
->node
);
257 * Copy the CNAME's target into the lookup's
258 * query name and start over.
260 result
= dns_rdataset_first(&lookup
->rdataset
);
261 if (result
!= ISC_R_SUCCESS
)
263 dns_rdataset_current(&lookup
->rdataset
, &rdata
);
264 result
= dns_rdata_tostruct(&rdata
, &cname
, NULL
);
265 dns_rdata_reset(&rdata
);
266 if (result
!= ISC_R_SUCCESS
)
268 result
= dns_name_copy(&cname
.cname
, name
, NULL
);
269 dns_rdata_freestruct(&cname
);
270 if (result
== ISC_R_SUCCESS
)
271 want_restart
= ISC_TRUE
;
274 namereln
= dns_name_fullcompare(name
, fname
, &order
,
276 INSIST(namereln
== dns_namereln_subdomain
);
278 * Get the target name of the DNAME.
280 result
= dns_rdataset_first(&lookup
->rdataset
);
281 if (result
!= ISC_R_SUCCESS
)
283 dns_rdataset_current(&lookup
->rdataset
, &rdata
);
284 result
= dns_rdata_tostruct(&rdata
, &dname
, NULL
);
285 dns_rdata_reset(&rdata
);
286 if (result
!= ISC_R_SUCCESS
)
289 * Construct the new query name and start over.
291 dns_fixedname_init(&fixed
);
292 prefix
= dns_fixedname_name(&fixed
);
293 dns_name_split(name
, nlabels
, prefix
, NULL
);
294 result
= dns_name_concatenate(prefix
, &dname
.dname
,
296 dns_rdata_freestruct(&dname
);
297 if (result
== ISC_R_SUCCESS
)
298 want_restart
= ISC_TRUE
;
301 send_event
= ISC_TRUE
;
304 if (dns_rdataset_isassociated(&lookup
->rdataset
))
305 dns_rdataset_disassociate(&lookup
->rdataset
);
306 if (dns_rdataset_isassociated(&lookup
->sigrdataset
))
307 dns_rdataset_disassociate(&lookup
->sigrdataset
);
311 if (event
->node
!= NULL
)
312 dns_db_detachnode(event
->db
, &event
->node
);
313 if (event
->db
!= NULL
)
314 dns_db_detach(&event
->db
);
315 isc_event_free(ISC_EVENT_PTR(&event
));
319 * Limit the number of restarts.
321 if (want_restart
&& lookup
->restarts
== MAX_RESTARTS
) {
322 want_restart
= ISC_FALSE
;
323 result
= ISC_R_QUOTA
;
324 send_event
= ISC_TRUE
;
327 } while (want_restart
);
330 lookup
->event
->result
= result
;
331 lookup
->event
->ev_sender
= lookup
;
332 isc_task_sendanddetach(&lookup
->task
,
333 (isc_event_t
**)&lookup
->event
);
334 dns_view_detach(&lookup
->view
);
337 UNLOCK(&lookup
->lock
);
341 levent_destroy(isc_event_t
*event
) {
342 dns_lookupevent_t
*levent
;
345 REQUIRE(event
->ev_type
== DNS_EVENT_LOOKUPDONE
);
346 mctx
= event
->ev_destroy_arg
;
347 levent
= (dns_lookupevent_t
*)event
;
349 if (levent
->name
!= NULL
) {
350 if (dns_name_dynamic(levent
->name
))
351 dns_name_free(levent
->name
, mctx
);
352 isc_mem_put(mctx
, levent
->name
, sizeof(dns_name_t
));
354 if (levent
->rdataset
!= NULL
) {
355 dns_rdataset_disassociate(levent
->rdataset
);
356 isc_mem_put(mctx
, levent
->rdataset
, sizeof(dns_rdataset_t
));
358 if (levent
->sigrdataset
!= NULL
) {
359 dns_rdataset_disassociate(levent
->sigrdataset
);
360 isc_mem_put(mctx
, levent
->sigrdataset
, sizeof(dns_rdataset_t
));
362 if (levent
->node
!= NULL
)
363 dns_db_detachnode(levent
->db
, &levent
->node
);
364 if (levent
->db
!= NULL
)
365 dns_db_detach(&levent
->db
);
366 isc_mem_put(mctx
, event
, event
->ev_size
);
371 dns_lookup_create(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdatatype_t type
,
372 dns_view_t
*view
, unsigned int options
, isc_task_t
*task
,
373 isc_taskaction_t action
, void *arg
, dns_lookup_t
**lookupp
)
376 dns_lookup_t
*lookup
;
379 lookup
= isc_mem_get(mctx
, sizeof(*lookup
));
381 return (ISC_R_NOMEMORY
);
383 lookup
->options
= options
;
385 ievent
= isc_event_allocate(mctx
, lookup
, DNS_EVENT_LOOKUPDONE
,
386 action
, arg
, sizeof(*lookup
->event
));
387 if (ievent
== NULL
) {
388 result
= ISC_R_NOMEMORY
;
391 lookup
->event
= (dns_lookupevent_t
*)ievent
;
392 lookup
->event
->ev_destroy
= levent_destroy
;
393 lookup
->event
->ev_destroy_arg
= mctx
;
394 lookup
->event
->result
= ISC_R_FAILURE
;
395 lookup
->event
->name
= NULL
;
396 lookup
->event
->rdataset
= NULL
;
397 lookup
->event
->sigrdataset
= NULL
;
398 lookup
->event
->db
= NULL
;
399 lookup
->event
->node
= NULL
;
402 isc_task_attach(task
, &lookup
->task
);
404 result
= isc_mutex_init(&lookup
->lock
);
405 if (result
!= ISC_R_SUCCESS
)
408 dns_fixedname_init(&lookup
->name
);
410 result
= dns_name_copy(name
, dns_fixedname_name(&lookup
->name
), NULL
);
411 if (result
!= ISC_R_SUCCESS
)
416 dns_view_attach(view
, &lookup
->view
);
417 lookup
->fetch
= NULL
;
418 lookup
->restarts
= 0;
419 lookup
->canceled
= ISC_FALSE
;
420 dns_rdataset_init(&lookup
->rdataset
);
421 dns_rdataset_init(&lookup
->sigrdataset
);
422 lookup
->magic
= LOOKUP_MAGIC
;
426 lookup_find(lookup
, NULL
);
428 return (ISC_R_SUCCESS
);
431 DESTROYLOCK(&lookup
->lock
);
434 ievent
= (isc_event_t
*)lookup
->event
;
435 isc_event_free(&ievent
);
436 lookup
->event
= NULL
;
438 isc_task_detach(&lookup
->task
);
441 isc_mem_put(mctx
, lookup
, sizeof(*lookup
));
447 dns_lookup_cancel(dns_lookup_t
*lookup
) {
448 REQUIRE(VALID_LOOKUP(lookup
));
452 if (!lookup
->canceled
) {
453 lookup
->canceled
= ISC_TRUE
;
454 if (lookup
->fetch
!= NULL
) {
455 INSIST(lookup
->view
!= NULL
);
456 dns_resolver_cancelfetch(lookup
->fetch
);
460 UNLOCK(&lookup
->lock
);
464 dns_lookup_destroy(dns_lookup_t
**lookupp
) {
465 dns_lookup_t
*lookup
;
467 REQUIRE(lookupp
!= NULL
);
469 REQUIRE(VALID_LOOKUP(lookup
));
470 REQUIRE(lookup
->event
== NULL
);
471 REQUIRE(lookup
->task
== NULL
);
472 REQUIRE(lookup
->view
== NULL
);
473 if (dns_rdataset_isassociated(&lookup
->rdataset
))
474 dns_rdataset_disassociate(&lookup
->rdataset
);
475 if (dns_rdataset_isassociated(&lookup
->sigrdataset
))
476 dns_rdataset_disassociate(&lookup
->sigrdataset
);
478 DESTROYLOCK(&lookup
->lock
);
480 isc_mem_put(lookup
->mctx
, lookup
, sizeof(*lookup
));