2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001 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.2.3 2004/04/15 02:16:27 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
));
157 if (sigrdataset
!= NULL
) {
158 if (dns_rdataset_isassociated(sigrdataset
))
159 dns_rdataset_disassociate(sigrdataset
);
160 isc_mem_put(lookup
->mctx
, sigrdataset
, sizeof(dns_rdataset_t
));
166 view_find(dns_lookup_t
*lookup
, dns_name_t
*foundname
) {
168 dns_name_t
*name
= dns_fixedname_name(&lookup
->name
);
169 dns_rdatatype_t type
;
171 if (lookup
->type
== dns_rdatatype_sig
)
172 type
= dns_rdatatype_any
;
176 result
= dns_view_find(lookup
->view
, name
, type
, 0, 0, ISC_FALSE
,
177 &lookup
->event
->db
, &lookup
->event
->node
,
178 foundname
, &lookup
->rdataset
,
179 &lookup
->sigrdataset
);
184 lookup_find(dns_lookup_t
*lookup
, dns_fetchevent_t
*event
) {
186 isc_boolean_t want_restart
;
187 isc_boolean_t send_event
= ISC_FALSE
;
188 dns_name_t
*name
, *fname
, *prefix
;
189 dns_fixedname_t foundname
, fixed
;
190 dns_rdata_t rdata
= DNS_RDATA_INIT
;
191 unsigned int nlabels
, nbits
;
193 dns_namereln_t namereln
;
194 dns_rdata_cname_t cname
;
195 dns_rdata_dname_t dname
;
197 REQUIRE(VALID_LOOKUP(lookup
));
201 result
= ISC_R_SUCCESS
;
202 name
= dns_fixedname_name(&lookup
->name
);
206 want_restart
= ISC_FALSE
;
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
));
214 result
= view_find(lookup
, fname
);
215 if (result
== ISC_R_NOTFOUND
) {
217 * We don't know anything about the name.
220 if (lookup
->event
->node
!= NULL
) {
221 INSIST(lookup
->event
->db
!= NULL
);
222 dns_db_detachnode(lookup
->event
->db
,
223 &lookup
->event
->node
);
225 if (lookup
->event
->db
!= NULL
)
226 dns_db_detach(&lookup
->event
->db
);
227 result
= start_fetch(lookup
);
228 if (result
!= ISC_R_SUCCESS
)
229 send_event
= ISC_TRUE
;
233 result
= event
->result
;
234 fname
= dns_fixedname_name(&event
->foundname
);
235 dns_resolver_destroyfetch(&lookup
->fetch
);
236 INSIST(event
->rdataset
== &lookup
->rdataset
);
237 INSIST(event
->sigrdataset
== &lookup
->sigrdataset
);
241 * If we've been canceled, forget about the result.
243 if (lookup
->canceled
)
244 result
= ISC_R_CANCELED
;
248 result
= build_event(lookup
);
249 send_event
= ISC_TRUE
;
252 if (event
->db
!= NULL
)
253 dns_db_attach(event
->db
, &lookup
->event
->db
);
254 if (event
->node
!= NULL
)
255 dns_db_attachnode(lookup
->event
->db
,
257 &lookup
->event
->node
);
261 * Copy the CNAME's target into the lookup's
262 * query name and start over.
264 result
= dns_rdataset_first(&lookup
->rdataset
);
265 if (result
!= ISC_R_SUCCESS
)
267 dns_rdataset_current(&lookup
->rdataset
, &rdata
);
268 result
= dns_rdata_tostruct(&rdata
, &cname
, NULL
);
269 dns_rdata_reset(&rdata
);
270 if (result
!= ISC_R_SUCCESS
)
272 result
= dns_name_copy(&cname
.cname
, name
, NULL
);
273 dns_rdata_freestruct(&cname
);
274 if (result
== ISC_R_SUCCESS
)
275 want_restart
= ISC_TRUE
;
278 namereln
= dns_name_fullcompare(name
, fname
, &order
,
280 INSIST(namereln
== dns_namereln_subdomain
);
282 * Get the target name of the DNAME.
284 result
= dns_rdataset_first(&lookup
->rdataset
);
285 if (result
!= ISC_R_SUCCESS
)
287 dns_rdataset_current(&lookup
->rdataset
, &rdata
);
288 result
= dns_rdata_tostruct(&rdata
, &dname
, NULL
);
289 dns_rdata_reset(&rdata
);
290 if (result
!= ISC_R_SUCCESS
)
293 * Construct the new query name and start over.
295 dns_fixedname_init(&fixed
);
296 prefix
= dns_fixedname_name(&fixed
);
297 result
= dns_name_split(name
, nlabels
, nbits
, prefix
,
299 if (result
!= ISC_R_SUCCESS
) {
300 dns_rdata_freestruct(&dname
);
303 result
= dns_name_concatenate(prefix
, &dname
.dname
,
305 dns_rdata_freestruct(&dname
);
306 if (result
== ISC_R_SUCCESS
)
307 want_restart
= ISC_TRUE
;
310 send_event
= ISC_TRUE
;
313 if (dns_rdataset_isassociated(&lookup
->rdataset
))
314 dns_rdataset_disassociate(&lookup
->rdataset
);
315 if (dns_rdataset_isassociated(&lookup
->sigrdataset
))
316 dns_rdataset_disassociate(&lookup
->sigrdataset
);
320 if (event
->node
!= NULL
)
321 dns_db_detachnode(event
->db
, &event
->node
);
322 if (event
->db
!= NULL
)
323 dns_db_detach(&event
->db
);
324 isc_event_free(ISC_EVENT_PTR(&event
));
328 * Limit the number of restarts.
330 if (want_restart
&& lookup
->restarts
== MAX_RESTARTS
) {
331 want_restart
= ISC_FALSE
;
332 result
= ISC_R_QUOTA
;
333 send_event
= ISC_TRUE
;
336 } while (want_restart
);
339 lookup
->event
->result
= result
;
340 lookup
->event
->ev_sender
= lookup
;
341 isc_task_sendanddetach(&lookup
->task
,
342 (isc_event_t
**)&lookup
->event
);
343 dns_view_detach(&lookup
->view
);
346 UNLOCK(&lookup
->lock
);
350 levent_destroy(isc_event_t
*event
) {
351 dns_lookupevent_t
*levent
;
354 REQUIRE(event
->ev_type
== DNS_EVENT_LOOKUPDONE
);
355 mctx
= event
->ev_destroy_arg
;
356 levent
= (dns_lookupevent_t
*)event
;
358 if (levent
->name
!= NULL
) {
359 if (dns_name_dynamic(levent
->name
))
360 dns_name_free(levent
->name
, mctx
);
361 isc_mem_put(mctx
, levent
->name
, sizeof(dns_name_t
));
363 if (levent
->rdataset
!= NULL
) {
364 dns_rdataset_disassociate(levent
->rdataset
);
365 isc_mem_put(mctx
, levent
->rdataset
, sizeof(dns_rdataset_t
));
367 if (levent
->sigrdataset
!= NULL
) {
368 dns_rdataset_disassociate(levent
->sigrdataset
);
369 isc_mem_put(mctx
, levent
->sigrdataset
, sizeof(dns_rdataset_t
));
371 if (levent
->node
!= NULL
)
372 dns_db_detachnode(levent
->db
, &levent
->node
);
373 if (levent
->db
!= NULL
)
374 dns_db_detach(&levent
->db
);
375 isc_mem_put(mctx
, event
, event
->ev_size
);
380 dns_lookup_create(isc_mem_t
*mctx
, dns_name_t
*name
, dns_rdatatype_t type
,
381 dns_view_t
*view
, unsigned int options
, isc_task_t
*task
,
382 isc_taskaction_t action
, void *arg
, dns_lookup_t
**lookupp
)
385 dns_lookup_t
*lookup
;
388 lookup
= isc_mem_get(mctx
, sizeof *lookup
);
390 return (ISC_R_NOMEMORY
);
392 lookup
->options
= options
;
394 ievent
= isc_event_allocate(mctx
, lookup
, DNS_EVENT_LOOKUPDONE
,
395 action
, arg
, sizeof *lookup
->event
);
396 if (ievent
== NULL
) {
397 result
= ISC_R_NOMEMORY
;
400 lookup
->event
= (dns_lookupevent_t
*)ievent
;
401 lookup
->event
->ev_destroy
= levent_destroy
;
402 lookup
->event
->ev_destroy_arg
= mctx
;
403 lookup
->event
->result
= ISC_R_FAILURE
;
404 lookup
->event
->name
= NULL
;
405 lookup
->event
->rdataset
= NULL
;
406 lookup
->event
->sigrdataset
= NULL
;
407 lookup
->event
->db
= NULL
;
408 lookup
->event
->node
= NULL
;
411 isc_task_attach(task
, &lookup
->task
);
413 result
= isc_mutex_init(&lookup
->lock
);
414 if (result
!= ISC_R_SUCCESS
)
417 dns_fixedname_init(&lookup
->name
);
419 result
= dns_name_copy(name
, dns_fixedname_name(&lookup
->name
), NULL
);
420 if (result
!= ISC_R_SUCCESS
)
425 dns_view_attach(view
, &lookup
->view
);
426 lookup
->fetch
= NULL
;
427 lookup
->restarts
= 0;
428 lookup
->canceled
= ISC_FALSE
;
429 dns_rdataset_init(&lookup
->rdataset
);
430 dns_rdataset_init(&lookup
->sigrdataset
);
431 lookup
->magic
= LOOKUP_MAGIC
;
435 lookup_find(lookup
, NULL
);
437 return (ISC_R_SUCCESS
);
440 DESTROYLOCK(&lookup
->lock
);
443 ievent
= (isc_event_t
*)lookup
->event
;
444 isc_event_free(&ievent
);
445 lookup
->event
= NULL
;
447 isc_task_detach(&lookup
->task
);
450 isc_mem_put(mctx
, lookup
, sizeof *lookup
);
456 dns_lookup_cancel(dns_lookup_t
*lookup
) {
457 REQUIRE(VALID_LOOKUP(lookup
));
461 if (!lookup
->canceled
) {
462 lookup
->canceled
= ISC_TRUE
;
463 if (lookup
->fetch
!= NULL
) {
464 INSIST(lookup
->view
!= NULL
);
465 dns_resolver_cancelfetch(lookup
->fetch
);
469 UNLOCK(&lookup
->lock
);
473 dns_lookup_destroy(dns_lookup_t
**lookupp
) {
474 dns_lookup_t
*lookup
;
476 REQUIRE(lookupp
!= NULL
);
478 REQUIRE(VALID_LOOKUP(lookup
));
479 REQUIRE(lookup
->event
== NULL
);
480 REQUIRE(lookup
->task
== NULL
);
481 REQUIRE(lookup
->view
== NULL
);
482 if (dns_rdataset_isassociated(&lookup
->rdataset
))
483 dns_rdataset_disassociate(&lookup
->rdataset
);
484 if (dns_rdataset_isassociated(&lookup
->sigrdataset
))
485 dns_rdataset_disassociate(&lookup
->sigrdataset
);
487 DESTROYLOCK(&lookup
->lock
);
489 isc_mem_put(lookup
->mctx
, lookup
, sizeof *lookup
);