No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / lookup.c
blob57eb98979d9ade4ac90927d6abdf0819aab09a21
1 /* $NetBSD$ */
3 /*
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 */
22 /*! \file */
24 #include <config.h>
26 #include <isc/mem.h>
27 #include <isc/netaddr.h>
28 #include <isc/string.h> /* Required for HP/UX (and others?) */
29 #include <isc/task.h>
30 #include <isc/util.h>
32 #include <dns/db.h>
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>
40 #include <dns/view.h>
42 struct dns_lookup {
43 /* Unlocked. */
44 unsigned int magic;
45 isc_mem_t * mctx;
46 isc_mutex_t lock;
47 dns_rdatatype_t type;
48 dns_fixedname_t name;
49 /* Locked by lock. */
50 unsigned int options;
51 isc_task_t * task;
52 dns_view_t * view;
53 dns_lookupevent_t * event;
54 dns_fetch_t * fetch;
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);
68 static void
69 fetch_done(isc_task_t *task, isc_event_t *event) {
70 dns_lookup_t *lookup = event->ev_arg;
71 dns_fetchevent_t *fevent;
73 UNUSED(task);
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) {
85 isc_result_t result;
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),
95 lookup->type,
96 NULL, NULL, NULL, 0,
97 lookup->task, fetch_done, lookup,
98 &lookup->rdataset,
99 &lookup->sigrdataset,
100 &lookup->fetch);
102 return (result);
105 static isc_result_t
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;
110 isc_result_t result;
112 name = isc_mem_get(lookup->mctx, sizeof(dns_name_t));
113 if (name == NULL) {
114 result = ISC_R_NOMEMORY;
115 goto fail;
117 dns_name_init(name, NULL);
118 result = dns_name_dup(dns_fixedname_name(&lookup->name),
119 lookup->mctx, name);
120 if (result != ISC_R_SUCCESS)
121 goto fail;
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;
127 goto fail;
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;
138 goto fail;
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);
150 fail:
151 if (name != NULL) {
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));
161 return (result);
164 static isc_result_t
165 view_find(dns_lookup_t *lookup, dns_name_t *foundname) {
166 isc_result_t result;
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;
172 else
173 type = lookup->type;
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);
179 return (result);
182 static void
183 lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) {
184 isc_result_t result;
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;
191 int order;
192 dns_namereln_t namereln;
193 dns_rdata_cname_t cname;
194 dns_rdata_dname_t dname;
196 REQUIRE(VALID_LOOKUP(lookup));
198 LOCK(&lookup->lock);
200 result = ISC_R_SUCCESS;
201 name = dns_fixedname_name(&lookup->name);
203 do {
204 lookup->restarts++;
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.
227 * Launch a fetch.
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;
239 goto done;
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);
247 } else
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;
256 switch (result) {
257 case ISC_R_SUCCESS:
258 result = build_event(lookup);
259 if (event == NULL)
260 break;
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,
265 event->node,
266 &lookup->event->node);
267 break;
268 case DNS_R_CNAME:
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)
275 break;
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)
280 break;
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;
287 break;
288 case DNS_R_DNAME:
289 namereln = dns_name_fullcompare(name, fname, &order,
290 &nlabels);
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)
297 break;
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)
302 break;
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,
310 name, NULL);
311 dns_rdata_freestruct(&dname);
312 if (result == ISC_R_SUCCESS) {
313 want_restart = ISC_TRUE;
314 send_event = ISC_FALSE;
316 break;
317 default:
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);
326 done:
327 if (event != NULL) {
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);
346 if (send_event) {
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);
357 static void
358 levent_destroy(isc_event_t *event) {
359 dns_lookupevent_t *levent;
360 isc_mem_t *mctx;
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);
386 isc_result_t
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)
391 isc_result_t result;
392 dns_lookup_t *lookup;
393 isc_event_t *ievent;
395 lookup = isc_mem_get(mctx, sizeof(*lookup));
396 if (lookup == NULL)
397 return (ISC_R_NOMEMORY);
398 lookup->mctx = mctx;
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;
405 goto cleanup_lookup;
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;
417 lookup->task = NULL;
418 isc_task_attach(task, &lookup->task);
420 result = isc_mutex_init(&lookup->lock);
421 if (result != ISC_R_SUCCESS)
422 goto cleanup_event;
424 dns_fixedname_init(&lookup->name);
426 result = dns_name_copy(name, dns_fixedname_name(&lookup->name), NULL);
427 if (result != ISC_R_SUCCESS)
428 goto cleanup_lock;
430 lookup->type = type;
431 lookup->view = NULL;
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;
440 *lookupp = lookup;
442 lookup_find(lookup, NULL);
444 return (ISC_R_SUCCESS);
446 cleanup_lock:
447 DESTROYLOCK(&lookup->lock);
449 cleanup_event:
450 ievent = (isc_event_t *)lookup->event;
451 isc_event_free(&ievent);
452 lookup->event = NULL;
454 isc_task_detach(&lookup->task);
456 cleanup_lookup:
457 isc_mem_put(mctx, lookup, sizeof(*lookup));
459 return (result);
462 void
463 dns_lookup_cancel(dns_lookup_t *lookup) {
464 REQUIRE(VALID_LOOKUP(lookup));
466 LOCK(&lookup->lock);
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);
479 void
480 dns_lookup_destroy(dns_lookup_t **lookupp) {
481 dns_lookup_t *lookup;
483 REQUIRE(lookupp != NULL);
484 lookup = *lookupp;
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);
495 lookup->magic = 0;
496 isc_mem_put(lookup->mctx, lookup, sizeof(*lookup));
498 *lookupp = NULL;