Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / resolver.c
blob2c519eb8ef04c3840fc5112147dcbc54cbe8bafb
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-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: resolver.c,v 1.218.2.34 2004/07/03 00:56:55 marka Exp $ */
20 #include <config.h>
22 #include <isc/string.h>
23 #include <isc/task.h>
24 #include <isc/timer.h>
25 #include <isc/util.h>
27 #include <dns/acl.h>
28 #include <dns/adb.h>
29 #include <dns/db.h>
30 #include <dns/dispatch.h>
31 #include <dns/events.h>
32 #include <dns/forward.h>
33 #include <dns/keytable.h>
34 #include <dns/log.h>
35 #include <dns/message.h>
36 #include <dns/ncache.h>
37 #include <dns/peer.h>
38 #include <dns/rdata.h>
39 #include <dns/rdataclass.h>
40 #include <dns/rdatalist.h>
41 #include <dns/rdataset.h>
42 #include <dns/rdatastruct.h>
43 #include <dns/rdatatype.h>
44 #include <dns/resolver.h>
45 #include <dns/result.h>
46 #include <dns/tsig.h>
47 #include <dns/validator.h>
49 #define DNS_RESOLVER_TRACE
50 #ifdef DNS_RESOLVER_TRACE
51 #define RTRACE(m) isc_log_write(dns_lctx, \
52 DNS_LOGCATEGORY_RESOLVER, \
53 DNS_LOGMODULE_RESOLVER, \
54 ISC_LOG_DEBUG(3), \
55 "res %p: %s", res, (m))
56 #define RRTRACE(r, m) isc_log_write(dns_lctx, \
57 DNS_LOGCATEGORY_RESOLVER, \
58 DNS_LOGMODULE_RESOLVER, \
59 ISC_LOG_DEBUG(3), \
60 "res %p: %s", (r), (m))
61 #define FCTXTRACE(m) isc_log_write(dns_lctx, \
62 DNS_LOGCATEGORY_RESOLVER, \
63 DNS_LOGMODULE_RESOLVER, \
64 ISC_LOG_DEBUG(3), \
65 "fctx %p: %s", fctx, (m))
66 #define FCTXTRACE2(m1, m2) \
67 isc_log_write(dns_lctx, \
68 DNS_LOGCATEGORY_RESOLVER, \
69 DNS_LOGMODULE_RESOLVER, \
70 ISC_LOG_DEBUG(3), \
71 "fctx %p: %s %s", fctx, (m1), (m2))
72 #define FTRACE(m) isc_log_write(dns_lctx, \
73 DNS_LOGCATEGORY_RESOLVER, \
74 DNS_LOGMODULE_RESOLVER, \
75 ISC_LOG_DEBUG(3), \
76 "fetch %p (fctx %p): %s", \
77 fetch, fetch->private, (m))
78 #define QTRACE(m) isc_log_write(dns_lctx, \
79 DNS_LOGCATEGORY_RESOLVER, \
80 DNS_LOGMODULE_RESOLVER, \
81 ISC_LOG_DEBUG(3), \
82 "resquery %p (fctx %p): %s", \
83 query, query->fctx, (m))
84 #else
85 #define RTRACE(m)
86 #define RRTRACE(r, m)
87 #define FCTXTRACE(m)
88 #define FTRACE(m)
89 #define QTRACE(m)
90 #endif
93 * Maximum EDNS0 input packet size.
95 #define SEND_BUFFER_SIZE 2048 /* XXXRTH Constant. */
98 * This defines the maximum number of timeouts we will permit before we
99 * disable EDNS0 on the query.
101 #define MAX_EDNS0_TIMEOUTS 3
103 typedef struct fetchctx fetchctx_t;
105 typedef struct query {
106 /* Locked by task event serialization. */
107 unsigned int magic;
108 fetchctx_t * fctx;
109 isc_mem_t * mctx;
110 dns_dispatchmgr_t * dispatchmgr;
111 dns_dispatch_t * dispatch;
112 dns_adbaddrinfo_t * addrinfo;
113 isc_socket_t * tcpsocket;
114 isc_time_t start;
115 dns_messageid_t id;
116 dns_dispentry_t * dispentry;
117 ISC_LINK(struct query) link;
118 isc_buffer_t buffer;
119 isc_buffer_t *tsig;
120 dns_tsigkey_t *tsigkey;
121 unsigned int options;
122 unsigned int attributes;
123 unsigned int sends;
124 unsigned int connects;
125 unsigned char data[512];
126 } resquery_t;
128 #define QUERY_MAGIC ISC_MAGIC('Q', '!', '!', '!')
129 #define VALID_QUERY(query) ISC_MAGIC_VALID(query, QUERY_MAGIC)
131 #define RESQUERY_ATTR_CANCELED 0x02
133 #define RESQUERY_CONNECTING(q) ((q)->connects > 0)
134 #define RESQUERY_CANCELED(q) (((q)->attributes & \
135 RESQUERY_ATTR_CANCELED) != 0)
136 #define RESQUERY_SENDING(q) ((q)->sends > 0)
138 typedef enum {
139 fetchstate_init = 0, /* Start event has not run yet. */
140 fetchstate_active,
141 fetchstate_done /* FETCHDONE events posted. */
142 } fetchstate;
144 struct fetchctx {
145 /* Not locked. */
146 unsigned int magic;
147 dns_resolver_t * res;
148 dns_name_t name;
149 dns_rdatatype_t type;
150 unsigned int options;
151 unsigned int bucketnum;
152 /* Locked by appropriate bucket lock. */
153 fetchstate state;
154 isc_boolean_t want_shutdown;
155 isc_boolean_t cloned;
156 unsigned int references;
157 isc_event_t control_event;
158 ISC_LINK(struct fetchctx) link;
159 ISC_LIST(dns_fetchevent_t) events;
160 /* Locked by task event serialization. */
161 dns_name_t domain;
162 dns_rdataset_t nameservers;
163 unsigned int attributes;
164 isc_timer_t * timer;
165 isc_time_t expires;
166 isc_interval_t interval;
167 dns_message_t * qmessage;
168 dns_message_t * rmessage;
169 ISC_LIST(resquery_t) queries;
170 dns_adbfindlist_t finds;
171 dns_adbfind_t * find;
172 dns_adbaddrinfolist_t forwaddrs;
173 isc_sockaddrlist_t forwarders;
174 dns_fwdpolicy_t fwdpolicy;
175 isc_sockaddrlist_t bad;
176 ISC_LIST(dns_validator_t) validators;
177 dns_db_t * cache;
178 dns_adb_t * adb;
181 * The number of events we're waiting for.
183 unsigned int pending;
186 * The number of times we've "restarted" the current
187 * nameserver set. This acts as a failsafe to prevent
188 * us from pounding constantly on a particular set of
189 * servers that, for whatever reason, are not giving
190 * us useful responses, but are responding in such a
191 * way that they are not marked "bad".
193 unsigned int restarts;
196 * The number of timeouts that have occurred since we
197 * last successfully received a response packet. This
198 * is used for EDNS0 black hole detection.
200 unsigned int timeouts;
203 #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
204 #define VALID_FCTX(fctx) ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
206 #define FCTX_ATTR_HAVEANSWER 0x01
207 #define FCTX_ATTR_GLUING 0x02
208 #define FCTX_ATTR_ADDRWAIT 0x04
209 #define FCTX_ATTR_SHUTTINGDOWN 0x08
210 #define FCTX_ATTR_WANTCACHE 0x10
211 #define FCTX_ATTR_WANTNCACHE 0x20
212 #define FCTX_ATTR_NEEDEDNS0 0x40
214 #define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
216 #define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \
218 #define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
220 #define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
221 != 0)
222 #define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
223 #define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
224 #define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
226 struct dns_fetch {
227 unsigned int magic;
228 fetchctx_t * private;
231 #define DNS_FETCH_MAGIC ISC_MAGIC('F', 't', 'c', 'h')
232 #define DNS_FETCH_VALID(fetch) ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
234 typedef struct fctxbucket {
235 isc_task_t * task;
236 isc_mutex_t lock;
237 ISC_LIST(fetchctx_t) fctxs;
238 isc_boolean_t exiting;
239 } fctxbucket_t;
241 struct dns_resolver {
242 /* Unlocked. */
243 unsigned int magic;
244 isc_mem_t * mctx;
245 isc_mutex_t lock;
246 isc_mutex_t primelock;
247 dns_rdataclass_t rdclass;
248 isc_socketmgr_t * socketmgr;
249 isc_timermgr_t * timermgr;
250 isc_taskmgr_t * taskmgr;
251 dns_view_t * view;
252 isc_boolean_t frozen;
253 unsigned int options;
254 dns_dispatchmgr_t * dispatchmgr;
255 dns_dispatch_t * dispatchv4;
256 dns_dispatch_t * dispatchv6;
257 unsigned int nbuckets;
258 fctxbucket_t * buckets;
259 isc_uint32_t lame_ttl;
260 /* Locked by lock. */
261 unsigned int references;
262 isc_boolean_t exiting;
263 isc_eventlist_t whenshutdown;
264 unsigned int activebuckets;
265 isc_boolean_t priming;
266 /* Locked by primelock. */
267 dns_fetch_t * primefetch;
270 #define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!')
271 #define VALID_RESOLVER(res) ISC_MAGIC_VALID(res, RES_MAGIC)
274 * Private addrinfo flags. These must not conflict with DNS_FETCHOPT_NOEDNS0,
275 * which we also use as an addrinfo flag.
277 #define FCTX_ADDRINFO_MARK 0x0001
278 #define FCTX_ADDRINFO_FORWARDER 0x1000
279 #define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \
280 == 0)
281 #define ISFORWARDER(a) (((a)->flags & \
282 FCTX_ADDRINFO_FORWARDER) != 0)
284 #define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
286 static void destroy(dns_resolver_t *res);
287 static void empty_bucket(dns_resolver_t *res);
288 static isc_result_t resquery_send(resquery_t *query);
289 static void resquery_response(isc_task_t *task, isc_event_t *event);
290 static void resquery_connected(isc_task_t *task, isc_event_t *event);
291 static void fctx_try(fetchctx_t *fctx);
292 static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
293 static isc_result_t ncache_adderesult(dns_message_t *message,
294 dns_db_t *cache, dns_dbnode_t *node,
295 dns_rdatatype_t covers,
296 isc_stdtime_t now, dns_ttl_t maxttl,
297 dns_rdataset_t *ardataset,
298 isc_result_t *eresultp);
300 static isc_boolean_t
301 fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
302 dns_name_t *name;
303 dns_name_t *domain = &fctx->domain;
304 dns_rdataset_t *rdataset;
305 dns_rdatatype_t type;
306 isc_result_t result;
307 isc_boolean_t keep_auth = ISC_FALSE;
309 if (message->rcode == dns_rcode_nxdomain)
310 return (ISC_FALSE);
313 * Look for BIND 8 style delegations.
314 * Also look for answers to ANY queries where the duplicate NS RRset
315 * may have been stripped from the authority section.
317 if (message->counts[DNS_SECTION_ANSWER] != 0 &&
318 (fctx->type == dns_rdatatype_ns ||
319 fctx->type == dns_rdatatype_any)) {
320 result = dns_message_firstname(message, DNS_SECTION_ANSWER);
321 while (result == ISC_R_SUCCESS) {
322 name = NULL;
323 dns_message_currentname(message, DNS_SECTION_ANSWER,
324 &name);
325 for (rdataset = ISC_LIST_HEAD(name->list);
326 rdataset != NULL;
327 rdataset = ISC_LIST_NEXT(rdataset, link)) {
328 type = rdataset->type;
329 if (type != dns_rdatatype_ns)
330 continue;
331 if (dns_name_issubdomain(name, domain))
332 return (ISC_FALSE);
334 result = dns_message_nextname(message,
335 DNS_SECTION_ANSWER);
339 /* Look for referral. */
340 if (message->counts[DNS_SECTION_AUTHORITY] == 0)
341 goto munge;
343 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
344 while (result == ISC_R_SUCCESS) {
345 name = NULL;
346 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
347 for (rdataset = ISC_LIST_HEAD(name->list);
348 rdataset != NULL;
349 rdataset = ISC_LIST_NEXT(rdataset, link)) {
350 type = rdataset->type;
351 if (type == dns_rdatatype_soa &&
352 dns_name_equal(name, domain))
353 keep_auth = ISC_TRUE;
354 if (type != dns_rdatatype_ns &&
355 type != dns_rdatatype_soa)
356 continue;
357 if (dns_name_equal(name, domain))
358 goto munge;
359 if (dns_name_issubdomain(name, domain))
360 return (ISC_FALSE);
362 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
365 munge:
366 message->rcode = dns_rcode_nxdomain;
367 message->counts[DNS_SECTION_ANSWER] = 0;
368 if (!keep_auth)
369 message->counts[DNS_SECTION_AUTHORITY] = 0;
370 message->counts[DNS_SECTION_ADDITIONAL] = 0;
371 return (ISC_TRUE);
374 static inline isc_result_t
375 fctx_starttimer(fetchctx_t *fctx) {
377 * Start the lifetime timer for fctx.
379 * This is also used for stopping the idle timer; in that
380 * case we must purge events already posted to ensure that
381 * no further idle events are delivered.
383 return (isc_timer_reset(fctx->timer, isc_timertype_once,
384 &fctx->expires, NULL,
385 ISC_TRUE));
388 static inline void
389 fctx_stoptimer(fetchctx_t *fctx) {
390 isc_result_t result;
393 * We don't return a result if resetting the timer to inactive fails
394 * since there's nothing to be done about it. Resetting to inactive
395 * should never fail anyway, since the code as currently written
396 * cannot fail in that case.
398 result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
399 NULL, NULL, ISC_TRUE);
400 if (result != ISC_R_SUCCESS) {
401 UNEXPECTED_ERROR(__FILE__, __LINE__,
402 "isc_timer_reset(): %s",
403 isc_result_totext(result));
408 static inline isc_result_t
409 fctx_startidletimer(fetchctx_t *fctx) {
411 * Start the idle timer for fctx. The lifetime timer continues
412 * to be in effect.
414 return (isc_timer_reset(fctx->timer, isc_timertype_once,
415 &fctx->expires, &fctx->interval,
416 ISC_FALSE));
420 * Stopping the idle timer is equivalent to calling fctx_starttimer(), but
421 * we use fctx_stopidletimer for readability in the code below.
423 #define fctx_stopidletimer fctx_starttimer
426 static inline void
427 resquery_destroy(resquery_t **queryp) {
428 resquery_t *query;
430 REQUIRE(queryp != NULL);
431 query = *queryp;
432 REQUIRE(!ISC_LINK_LINKED(query, link));
434 INSIST(query->tcpsocket == NULL);
436 query->magic = 0;
437 isc_mem_put(query->mctx, query, sizeof(*query));
438 *queryp = NULL;
441 static void
442 fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
443 isc_time_t *finish, isc_boolean_t no_response)
445 fetchctx_t *fctx;
446 resquery_t *query;
447 unsigned int rtt;
448 unsigned int factor;
450 query = *queryp;
451 fctx = query->fctx;
453 FCTXTRACE("cancelquery");
455 REQUIRE(!RESQUERY_CANCELED(query));
457 query->attributes |= RESQUERY_ATTR_CANCELED;
460 * Should we update the RTT?
462 if (finish != NULL || no_response) {
463 if (finish != NULL) {
465 * We have both the start and finish times for this
466 * packet, so we can compute a real RTT.
468 rtt = (unsigned int)isc_time_microdiff(finish,
469 &query->start);
470 factor = DNS_ADB_RTTADJDEFAULT;
471 } else {
473 * We don't have an RTT for this query. Maybe the
474 * packet was lost, or maybe this server is very
475 * slow. We don't know. Increase the RTT.
477 INSIST(no_response);
478 rtt = query->addrinfo->srtt +
479 (100000 * fctx->restarts);
480 if (rtt > 10000000)
481 rtt = 10000000;
483 * Replace the current RTT with our value.
485 factor = DNS_ADB_RTTADJREPLACE;
487 dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
491 * Age RTTs of servers not tried.
493 if (finish != NULL) {
494 dns_adbfind_t *find;
495 dns_adbaddrinfo_t *addrinfo;
497 factor = DNS_ADB_RTTADJAGE;
498 for (find = ISC_LIST_HEAD(fctx->finds);
499 find != NULL;
500 find = ISC_LIST_NEXT(find, publink))
501 for (addrinfo = ISC_LIST_HEAD(find->list);
502 addrinfo != NULL;
503 addrinfo = ISC_LIST_NEXT(addrinfo, publink))
504 if (UNMARKED(addrinfo))
505 dns_adb_adjustsrtt(fctx->adb, addrinfo,
506 0, factor);
509 if (query->dispentry != NULL)
510 dns_dispatch_removeresponse(&query->dispentry, deventp);
512 ISC_LIST_UNLINK(fctx->queries, query, link);
514 if (query->tsig != NULL)
515 isc_buffer_free(&query->tsig);
517 if (query->tsigkey != NULL)
518 dns_tsigkey_detach(&query->tsigkey);
521 * Check for any outstanding socket events. If they exist, cancel
522 * them and let the event handlers finish the cleanup. The resolver
523 * only needs to worry about managing the connect and send events;
524 * the dispatcher manages the recv events.
526 if (RESQUERY_CONNECTING(query))
528 * Cancel the connect.
530 isc_socket_cancel(query->tcpsocket, NULL,
531 ISC_SOCKCANCEL_CONNECT);
532 else if (RESQUERY_SENDING(query))
534 * Cancel the pending send.
536 isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
537 NULL, ISC_SOCKCANCEL_SEND);
539 if (query->dispatch != NULL)
540 dns_dispatch_detach(&query->dispatch);
542 if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
544 * It's safe to destroy the query now.
546 resquery_destroy(&query);
549 static void
550 fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
551 resquery_t *query, *next_query;
553 FCTXTRACE("cancelqueries");
555 for (query = ISC_LIST_HEAD(fctx->queries);
556 query != NULL;
557 query = next_query) {
558 next_query = ISC_LIST_NEXT(query, link);
559 fctx_cancelquery(&query, NULL, NULL, no_response);
563 static void
564 fctx_cleanupfinds(fetchctx_t *fctx) {
565 dns_adbfind_t *find, *next_find;
567 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
569 for (find = ISC_LIST_HEAD(fctx->finds);
570 find != NULL;
571 find = next_find) {
572 next_find = ISC_LIST_NEXT(find, publink);
573 ISC_LIST_UNLINK(fctx->finds, find, publink);
574 dns_adb_destroyfind(&find);
576 fctx->find = NULL;
579 static void
580 fctx_cleanupforwaddrs(fetchctx_t *fctx) {
581 dns_adbaddrinfo_t *addr, *next_addr;
583 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
585 for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
586 addr != NULL;
587 addr = next_addr) {
588 next_addr = ISC_LIST_NEXT(addr, publink);
589 ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
590 dns_adb_freeaddrinfo(fctx->adb, &addr);
594 static inline void
595 fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
596 FCTXTRACE("stopeverything");
597 fctx_cancelqueries(fctx, no_response);
598 fctx_cleanupfinds(fctx);
599 fctx_cleanupforwaddrs(fctx);
600 fctx_stoptimer(fctx);
603 static inline void
604 fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
605 dns_fetchevent_t *event, *next_event;
606 isc_task_t *task;
609 * Caller must be holding the appropriate bucket lock.
611 REQUIRE(fctx->state == fetchstate_done);
613 FCTXTRACE("sendevents");
615 for (event = ISC_LIST_HEAD(fctx->events);
616 event != NULL;
617 event = next_event) {
618 next_event = ISC_LIST_NEXT(event, ev_link);
619 ISC_LIST_UNLINK(fctx->events, event, ev_link);
620 task = event->ev_sender;
621 event->ev_sender = fctx;
622 if (!HAVE_ANSWER(fctx))
623 event->result = result;
625 INSIST(result != ISC_R_SUCCESS ||
626 dns_rdataset_isassociated(event->rdataset) ||
627 fctx->type == dns_rdatatype_any ||
628 fctx->type == dns_rdatatype_sig);
630 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
634 static void
635 fctx_done(fetchctx_t *fctx, isc_result_t result) {
636 dns_resolver_t *res;
637 isc_boolean_t no_response;
639 FCTXTRACE("done");
641 res = fctx->res;
643 if (result == ISC_R_SUCCESS)
644 no_response = ISC_TRUE;
645 else
646 no_response = ISC_FALSE;
647 fctx_stopeverything(fctx, no_response);
649 LOCK(&res->buckets[fctx->bucketnum].lock);
651 fctx->state = fetchstate_done;
652 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
653 fctx_sendevents(fctx, result);
655 UNLOCK(&res->buckets[fctx->bucketnum].lock);
658 static void
659 resquery_senddone(isc_task_t *task, isc_event_t *event) {
660 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
661 resquery_t *query = event->ev_arg;
663 REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
665 QTRACE("senddone");
668 * XXXRTH
670 * Currently we don't wait for the senddone event before retrying
671 * a query. This means that if we get really behind, we may end
672 * up doing extra work!
675 UNUSED(task);
677 INSIST(RESQUERY_SENDING(query));
679 query->sends--;
681 if (RESQUERY_CANCELED(query)) {
682 if (query->sends == 0) {
684 * This query was canceled while the
685 * isc_socket_sendto() was in progress.
687 if (query->tcpsocket != NULL)
688 isc_socket_detach(&query->tcpsocket);
689 resquery_destroy(&query);
691 } else if (sevent->result != ISC_R_SUCCESS)
692 fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
694 isc_event_free(&event);
697 static inline isc_result_t
698 fctx_addopt(dns_message_t *message) {
699 dns_rdataset_t *rdataset;
700 dns_rdatalist_t *rdatalist;
701 dns_rdata_t *rdata;
702 isc_result_t result;
704 rdatalist = NULL;
705 result = dns_message_gettemprdatalist(message, &rdatalist);
706 if (result != ISC_R_SUCCESS)
707 return (result);
708 rdata = NULL;
709 result = dns_message_gettemprdata(message, &rdata);
710 if (result != ISC_R_SUCCESS)
711 return (result);
712 rdataset = NULL;
713 result = dns_message_gettemprdataset(message, &rdataset);
714 if (result != ISC_R_SUCCESS)
715 return (result);
716 dns_rdataset_init(rdataset);
718 rdatalist->type = dns_rdatatype_opt;
719 rdatalist->covers = 0;
722 * Set Maximum UDP buffer size.
724 rdatalist->rdclass = SEND_BUFFER_SIZE;
727 * Set EXTENDED-RCODE, VERSION, and Z to 0, and the DO bit to 1.
729 #ifdef ISC_RFC2535
730 rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO;
731 #else
732 rdatalist->ttl = 0;
733 #endif
736 * No EDNS options.
738 rdata->data = NULL;
739 rdata->length = 0;
740 rdata->rdclass = rdatalist->rdclass;
741 rdata->type = rdatalist->type;
742 rdata->flags = 0;
744 ISC_LIST_INIT(rdatalist->rdata);
745 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
746 dns_rdatalist_tordataset(rdatalist, rdataset);
748 return (dns_message_setopt(message, rdataset));
751 static inline void
752 fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
753 unsigned int seconds;
756 * We retry every 2 seconds the first two times through the address
757 * list, and then we do exponential back-off.
759 if (fctx->restarts < 3)
760 seconds = 2;
761 else
762 seconds = (2 << (fctx->restarts - 1));
765 * Double the round-trip time and convert to seconds.
767 rtt /= 500000;
770 * Always wait for at least the doubled round-trip time.
772 if (seconds < rtt)
773 seconds = rtt;
776 * But don't ever wait for more than 30 seconds.
778 if (seconds > 30)
779 seconds = 30;
781 isc_interval_set(&fctx->interval, seconds, 0);
784 static isc_result_t
785 fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
786 unsigned int options)
788 dns_resolver_t *res;
789 isc_task_t *task;
790 isc_result_t result;
791 resquery_t *query;
793 FCTXTRACE("query");
795 res = fctx->res;
796 task = res->buckets[fctx->bucketnum].task;
798 fctx_setretryinterval(fctx, addrinfo->srtt);
799 result = fctx_startidletimer(fctx);
800 if (result != ISC_R_SUCCESS)
801 return (result);
803 dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
805 query = isc_mem_get(res->mctx, sizeof *query);
806 if (query == NULL) {
807 result = ISC_R_NOMEMORY;
808 goto stop_idle_timer;
810 query->mctx = res->mctx;
811 query->options = options;
812 query->attributes = 0;
813 query->sends = 0;
814 query->connects = 0;
816 * Note that the caller MUST guarantee that 'addrinfo' will remain
817 * valid until this query is canceled.
819 query->addrinfo = addrinfo;
820 result = isc_time_now(&query->start);
821 if (result != ISC_R_SUCCESS)
822 goto cleanup_query;
825 * If this is a TCP query, then we need to make a socket and
826 * a dispatch for it here. Otherwise we use the resolver's
827 * shared dispatch.
829 query->dispatchmgr = res->dispatchmgr;
830 query->dispatch = NULL;
831 query->tcpsocket = NULL;
832 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
833 isc_sockaddr_t addr;
834 int pf;
836 pf = isc_sockaddr_pf(&addrinfo->sockaddr);
838 switch (pf) {
839 case PF_INET:
840 result = dns_dispatch_getlocaladdress(res->dispatchv4,
841 &addr);
842 break;
843 case PF_INET6:
844 result = dns_dispatch_getlocaladdress(res->dispatchv6,
845 &addr);
846 break;
847 default:
848 result = ISC_R_NOTIMPLEMENTED;
849 break;
851 if (result != ISC_R_SUCCESS)
852 goto cleanup_query;
854 isc_sockaddr_setport(&addr, 0);
856 result = isc_socket_create(res->socketmgr, pf,
857 isc_sockettype_tcp,
858 &query->tcpsocket);
859 if (result != ISC_R_SUCCESS)
860 goto cleanup_query;
862 result = isc_socket_bind(query->tcpsocket, &addr);
863 if (result != ISC_R_SUCCESS)
864 goto cleanup_socket;
867 * A dispatch will be created once the connect succeeds.
869 } else {
870 switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
871 case PF_INET:
872 dns_dispatch_attach(res->dispatchv4, &query->dispatch);
873 break;
874 case PF_INET6:
875 dns_dispatch_attach(res->dispatchv6, &query->dispatch);
876 break;
877 default:
878 result = ISC_R_NOTIMPLEMENTED;
879 goto cleanup_query;
882 * We should always have a valid dispatcher here. If we
883 * don't support a protocol family, then its dispatcher
884 * will be NULL, but we shouldn't be finding addresses for
885 * protocol types we don't support, so the dispatcher
886 * we found should never be NULL.
888 INSIST(query->dispatch != NULL);
891 query->dispentry = NULL;
892 query->fctx = fctx;
893 query->tsig = NULL;
894 query->tsigkey = NULL;
895 ISC_LINK_INIT(query, link);
896 query->magic = QUERY_MAGIC;
898 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
900 * Connect to the remote server.
902 * XXXRTH Should we attach to the socket?
904 result = isc_socket_connect(query->tcpsocket,
905 &addrinfo->sockaddr, task,
906 resquery_connected, query);
907 if (result != ISC_R_SUCCESS)
908 goto cleanup_socket;
909 query->connects++;
910 QTRACE("connecting via TCP");
911 } else {
912 result = resquery_send(query);
913 if (result != ISC_R_SUCCESS)
914 goto cleanup_dispatch;
917 ISC_LIST_APPEND(fctx->queries, query, link);
919 return (ISC_R_SUCCESS);
921 cleanup_socket:
922 isc_socket_detach(&query->tcpsocket);
924 cleanup_dispatch:
925 if (query->dispatch != NULL)
926 dns_dispatch_detach(&query->dispatch);
928 cleanup_query:
929 query->magic = 0;
930 isc_mem_put(res->mctx, query, sizeof *query);
932 stop_idle_timer:
933 fctx_stopidletimer(fctx);
935 return (result);
938 static isc_result_t
939 resquery_send(resquery_t *query) {
940 fetchctx_t *fctx;
941 isc_result_t result;
942 dns_name_t *qname = NULL;
943 dns_rdataset_t *qrdataset = NULL;
944 isc_region_t r;
945 dns_resolver_t *res;
946 isc_task_t *task;
947 isc_socket_t *socket;
948 isc_buffer_t tcpbuffer;
949 isc_sockaddr_t *address;
950 isc_buffer_t *buffer;
951 isc_netaddr_t ipaddr;
952 dns_tsigkey_t *tsigkey = NULL;
953 dns_peer_t *peer = NULL;
954 isc_boolean_t useedns;
955 dns_compress_t cctx;
956 isc_boolean_t cleanup_cctx = ISC_FALSE;
958 fctx = query->fctx;
959 QTRACE("send");
961 res = fctx->res;
962 task = res->buckets[fctx->bucketnum].task;
963 address = NULL;
965 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
967 * Reserve space for the TCP message length.
969 isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data));
970 isc_buffer_init(&query->buffer, query->data + 2,
971 sizeof(query->data) - 2);
972 buffer = &tcpbuffer;
973 } else {
974 isc_buffer_init(&query->buffer, query->data,
975 sizeof(query->data));
976 buffer = &query->buffer;
979 result = dns_message_gettempname(fctx->qmessage, &qname);
980 if (result != ISC_R_SUCCESS)
981 goto cleanup_temps;
982 result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
983 if (result != ISC_R_SUCCESS)
984 goto cleanup_temps;
987 * Get a query id from the dispatch.
989 result = dns_dispatch_addresponse(query->dispatch,
990 &query->addrinfo->sockaddr,
991 task,
992 resquery_response,
993 query,
994 &query->id,
995 &query->dispentry);
996 if (result != ISC_R_SUCCESS)
997 goto cleanup_temps;
999 fctx->qmessage->opcode = dns_opcode_query;
1002 * Set up question.
1004 dns_name_init(qname, NULL);
1005 dns_name_clone(&fctx->name, qname);
1006 dns_rdataset_init(qrdataset);
1007 dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
1008 ISC_LIST_APPEND(qname->list, qrdataset, link);
1009 dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
1010 qname = NULL;
1011 qrdataset = NULL;
1014 * Set RD if the client has requested that we do a recursive query,
1015 * or if we're sending to a forwarder.
1017 if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||
1018 ISFORWARDER(query->addrinfo))
1019 fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;
1022 * We don't have to set opcode because it defaults to query.
1024 fctx->qmessage->id = query->id;
1027 * Convert the question to wire format.
1029 result = dns_compress_init(&cctx, -1, fctx->res->mctx);
1030 if (result != ISC_R_SUCCESS)
1031 goto cleanup_message;
1032 cleanup_cctx = ISC_TRUE;
1034 result = dns_message_renderbegin(fctx->qmessage, &cctx,
1035 &query->buffer);
1036 if (result != ISC_R_SUCCESS)
1037 goto cleanup_message;
1039 result = dns_message_rendersection(fctx->qmessage,
1040 DNS_SECTION_QUESTION, 0);
1041 if (result != ISC_R_SUCCESS)
1042 goto cleanup_message;
1044 peer = NULL;
1045 isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr);
1046 (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer);
1049 * The ADB does not know about servers with "edns no". Check this,
1050 * and then inform the ADB for future use.
1052 if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 &&
1053 peer != NULL &&
1054 dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS &&
1055 !useedns)
1057 query->options |= DNS_FETCHOPT_NOEDNS0;
1058 dns_adb_changeflags(fctx->adb,
1059 query->addrinfo,
1060 DNS_FETCHOPT_NOEDNS0,
1061 DNS_FETCHOPT_NOEDNS0);
1065 * Use EDNS0, unless the caller doesn't want it, or we know that
1066 * the remote server doesn't like it.
1068 if (fctx->timeouts >= MAX_EDNS0_TIMEOUTS &&
1069 (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
1070 query->options |= DNS_FETCHOPT_NOEDNS0;
1071 FCTXTRACE("too many timeouts, disabling EDNS0");
1074 if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
1075 if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
1076 result = fctx_addopt(fctx->qmessage);
1077 if (result != ISC_R_SUCCESS) {
1079 * We couldn't add the OPT, but we'll press on.
1080 * We're not using EDNS0, so set the NOEDNS0
1081 * bit.
1083 query->options |= DNS_FETCHOPT_NOEDNS0;
1085 } else {
1087 * We know this server doesn't like EDNS0, so we
1088 * won't use it. Set the NOEDNS0 bit since we're
1089 * not using EDNS0.
1091 query->options |= DNS_FETCHOPT_NOEDNS0;
1096 * If we need EDNS0 to do this query and aren't using it, we lose.
1098 if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) {
1099 result = DNS_R_SERVFAIL;
1100 goto cleanup_message;
1104 * If we're using EDNS, set CD. CD and EDNS aren't really related,
1105 * but if we send a non EDNS query, there's a chance the server
1106 * won't understand CD either.
1108 if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
1109 fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
1112 * Add TSIG record tailored to the current recipient.
1114 result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey);
1115 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
1116 goto cleanup_message;
1118 if (tsigkey != NULL) {
1119 dns_message_settsigkey(fctx->qmessage, tsigkey);
1120 dns_tsigkey_detach(&tsigkey);
1123 result = dns_message_rendersection(fctx->qmessage,
1124 DNS_SECTION_ADDITIONAL, 0);
1125 if (result != ISC_R_SUCCESS)
1126 goto cleanup_message;
1128 result = dns_message_renderend(fctx->qmessage);
1129 if (result != ISC_R_SUCCESS)
1130 goto cleanup_message;
1132 dns_compress_invalidate(&cctx);
1133 cleanup_cctx = ISC_FALSE;
1135 if (dns_message_gettsigkey(fctx->qmessage) != NULL) {
1136 dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage),
1137 &query->tsigkey);
1138 result = dns_message_getquerytsig(fctx->qmessage,
1139 fctx->res->mctx,
1140 &query->tsig);
1141 if (result != ISC_R_SUCCESS)
1142 goto cleanup_message;
1146 * If using TCP, write the length of the message at the beginning
1147 * of the buffer.
1149 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1150 isc_buffer_usedregion(&query->buffer, &r);
1151 isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
1152 isc_buffer_add(&tcpbuffer, r.length);
1156 * We're now done with the query message.
1158 dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
1160 socket = dns_dispatch_getsocket(query->dispatch);
1162 * Send the query!
1164 if ((query->options & DNS_FETCHOPT_TCP) == 0)
1165 address = &query->addrinfo->sockaddr;
1166 isc_buffer_usedregion(buffer, &r);
1169 * XXXRTH Make sure we don't send to ourselves! We should probably
1170 * prune out these addresses when we get them from the ADB.
1172 result = isc_socket_sendto(socket, &r, task, resquery_senddone,
1173 query, address, NULL);
1174 if (result != ISC_R_SUCCESS)
1175 goto cleanup_message;
1176 query->sends++;
1177 QTRACE("sent");
1179 return (ISC_R_SUCCESS);
1181 cleanup_message:
1182 if (cleanup_cctx)
1183 dns_compress_invalidate(&cctx);
1185 dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
1188 * Stop the dispatcher from listening.
1190 dns_dispatch_removeresponse(&query->dispentry, NULL);
1192 cleanup_temps:
1193 if (qname != NULL)
1194 dns_message_puttempname(fctx->qmessage, &qname);
1195 if (qrdataset != NULL)
1196 dns_message_puttemprdataset(fctx->qmessage, &qrdataset);
1198 return (result);
1201 static void
1202 resquery_connected(isc_task_t *task, isc_event_t *event) {
1203 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1204 resquery_t *query = event->ev_arg;
1205 isc_result_t result;
1207 REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1208 REQUIRE(VALID_QUERY(query));
1210 QTRACE("connected");
1212 UNUSED(task);
1215 * XXXRTH
1217 * Currently we don't wait for the connect event before retrying
1218 * a query. This means that if we get really behind, we may end
1219 * up doing extra work!
1222 query->connects--;
1224 if (RESQUERY_CANCELED(query)) {
1226 * This query was canceled while the connect() was in
1227 * progress.
1229 isc_socket_detach(&query->tcpsocket);
1230 resquery_destroy(&query);
1231 } else {
1232 if (sevent->result == ISC_R_SUCCESS) {
1233 unsigned int attrs;
1236 * We are connected. Create a dispatcher and
1237 * send the query.
1239 attrs = 0;
1240 attrs |= DNS_DISPATCHATTR_TCP;
1241 attrs |= DNS_DISPATCHATTR_PRIVATE;
1242 attrs |= DNS_DISPATCHATTR_CONNECTED;
1243 if (isc_sockaddr_pf(&query->addrinfo->sockaddr) ==
1244 AF_INET)
1245 attrs |= DNS_DISPATCHATTR_IPV4;
1246 else
1247 attrs |= DNS_DISPATCHATTR_IPV6;
1248 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
1250 result = dns_dispatch_createtcp(query->dispatchmgr,
1251 query->tcpsocket,
1252 query->fctx->res->taskmgr,
1253 4096, 2, 1, 1, 3, attrs,
1254 &query->dispatch);
1257 * Regardless of whether dns_dispatch_create()
1258 * succeeded or not, we don't need our reference
1259 * to the socket anymore.
1261 isc_socket_detach(&query->tcpsocket);
1263 if (result == ISC_R_SUCCESS)
1264 result = resquery_send(query);
1266 if (result != ISC_R_SUCCESS) {
1267 fetchctx_t *fctx = query->fctx;
1268 fctx_cancelquery(&query, NULL, NULL,
1269 ISC_FALSE);
1270 fctx_done(fctx, result);
1272 } else {
1273 isc_socket_detach(&query->tcpsocket);
1274 fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
1278 isc_event_free(&event);
1283 static void
1284 fctx_finddone(isc_task_t *task, isc_event_t *event) {
1285 fetchctx_t *fctx;
1286 dns_adbfind_t *find;
1287 dns_resolver_t *res;
1288 isc_boolean_t want_try = ISC_FALSE;
1289 isc_boolean_t want_done = ISC_FALSE;
1290 isc_boolean_t bucket_empty = ISC_FALSE;
1291 unsigned int bucketnum;
1293 find = event->ev_sender;
1294 fctx = event->ev_arg;
1295 REQUIRE(VALID_FCTX(fctx));
1296 res = fctx->res;
1298 UNUSED(task);
1300 FCTXTRACE("finddone");
1302 INSIST(fctx->pending > 0);
1303 fctx->pending--;
1305 if (ADDRWAIT(fctx)) {
1307 * The fetch is waiting for a name to be found.
1309 INSIST(!SHUTTINGDOWN(fctx));
1310 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1311 if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
1312 want_try = ISC_TRUE;
1313 else if (fctx->pending == 0) {
1315 * We've got nothing else to wait for and don't
1316 * know the answer. There's nothing to do but
1317 * fail the fctx.
1319 want_done = ISC_TRUE;
1321 } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
1322 ISC_LIST_EMPTY(fctx->validators)) {
1323 bucketnum = fctx->bucketnum;
1324 LOCK(&res->buckets[bucketnum].lock);
1326 * Note that we had to wait until we had the lock before
1327 * looking at fctx->references.
1329 if (fctx->references == 0)
1330 bucket_empty = fctx_destroy(fctx);
1331 UNLOCK(&res->buckets[bucketnum].lock);
1334 isc_event_free(&event);
1335 dns_adb_destroyfind(&find);
1337 if (want_try)
1338 fctx_try(fctx);
1339 else if (want_done)
1340 fctx_done(fctx, ISC_R_FAILURE);
1341 else if (bucket_empty)
1342 empty_bucket(res);
1346 static inline isc_boolean_t
1347 bad_server(fetchctx_t *fctx, isc_sockaddr_t *address) {
1348 isc_sockaddr_t *sa;
1350 for (sa = ISC_LIST_HEAD(fctx->bad);
1351 sa != NULL;
1352 sa = ISC_LIST_NEXT(sa, link)) {
1353 if (isc_sockaddr_equal(sa, address))
1354 return (ISC_TRUE);
1357 return (ISC_FALSE);
1360 static inline isc_boolean_t
1361 mark_bad(fetchctx_t *fctx) {
1362 dns_adbfind_t *curr;
1363 dns_adbaddrinfo_t *addrinfo;
1364 isc_boolean_t all_bad = ISC_TRUE;
1367 * Mark all known bad servers, so we don't try to talk to them
1368 * again.
1372 * Mark any bad nameservers.
1374 for (curr = ISC_LIST_HEAD(fctx->finds);
1375 curr != NULL;
1376 curr = ISC_LIST_NEXT(curr, publink)) {
1377 for (addrinfo = ISC_LIST_HEAD(curr->list);
1378 addrinfo != NULL;
1379 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1380 if (bad_server(fctx, &addrinfo->sockaddr))
1381 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1382 else
1383 all_bad = ISC_FALSE;
1388 * Mark any bad forwarders.
1390 for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
1391 addrinfo != NULL;
1392 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1393 if (bad_server(fctx, &addrinfo->sockaddr))
1394 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1395 else
1396 all_bad = ISC_FALSE;
1399 return (all_bad);
1402 static void
1403 add_bad(fetchctx_t *fctx, isc_sockaddr_t *address) {
1404 isc_sockaddr_t *sa;
1406 if (bad_server(fctx, address)) {
1408 * We already know this server is bad.
1410 return;
1413 FCTXTRACE("add_bad");
1415 sa = isc_mem_get(fctx->res->mctx, sizeof *sa);
1416 if (sa == NULL)
1417 return;
1418 *sa = *address;
1419 ISC_LIST_INITANDAPPEND(fctx->bad, sa, link);
1422 static void
1423 sort_adbfind(dns_adbfind_t *find) {
1424 dns_adbaddrinfo_t *best, *curr;
1425 dns_adbaddrinfolist_t sorted;
1428 * Lame N^2 bubble sort.
1431 ISC_LIST_INIT(sorted);
1432 while (!ISC_LIST_EMPTY(find->list)) {
1433 best = ISC_LIST_HEAD(find->list);
1434 curr = ISC_LIST_NEXT(best, publink);
1435 while (curr != NULL) {
1436 if (curr->srtt < best->srtt)
1437 best = curr;
1438 curr = ISC_LIST_NEXT(curr, publink);
1440 ISC_LIST_UNLINK(find->list, best, publink);
1441 ISC_LIST_APPEND(sorted, best, publink);
1443 find->list = sorted;
1446 static void
1447 sort_finds(fetchctx_t *fctx) {
1448 dns_adbfind_t *best, *curr;
1449 dns_adbfindlist_t sorted;
1450 dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
1453 * Lame N^2 bubble sort.
1456 ISC_LIST_INIT(sorted);
1457 while (!ISC_LIST_EMPTY(fctx->finds)) {
1458 best = ISC_LIST_HEAD(fctx->finds);
1459 bestaddrinfo = ISC_LIST_HEAD(best->list);
1460 INSIST(bestaddrinfo != NULL);
1461 curr = ISC_LIST_NEXT(best, publink);
1462 while (curr != NULL) {
1463 addrinfo = ISC_LIST_HEAD(curr->list);
1464 INSIST(addrinfo != NULL);
1465 if (addrinfo->srtt < bestaddrinfo->srtt) {
1466 best = curr;
1467 bestaddrinfo = addrinfo;
1469 curr = ISC_LIST_NEXT(curr, publink);
1471 ISC_LIST_UNLINK(fctx->finds, best, publink);
1472 ISC_LIST_APPEND(sorted, best, publink);
1474 fctx->finds = sorted;
1477 static isc_result_t
1478 fctx_getaddresses(fetchctx_t *fctx) {
1479 dns_rdata_t rdata = DNS_RDATA_INIT;
1480 isc_result_t result;
1481 dns_resolver_t *res;
1482 isc_stdtime_t now;
1483 dns_adbfind_t *find;
1484 unsigned int stdoptions, options;
1485 isc_sockaddr_t *sa;
1486 dns_adbaddrinfo_t *ai;
1487 isc_boolean_t pruned, all_bad;
1488 dns_rdata_ns_t ns;
1490 FCTXTRACE("getaddresses");
1493 * Don't pound on remote servers. (Failsafe!)
1495 fctx->restarts++;
1496 if (fctx->restarts > 10) {
1497 FCTXTRACE("too many restarts");
1498 return (DNS_R_SERVFAIL);
1501 res = fctx->res;
1502 pruned = ISC_FALSE;
1503 stdoptions = 0; /* Keep compiler happy. */
1506 * Forwarders.
1509 INSIST(ISC_LIST_EMPTY(fctx->forwaddrs));
1512 * If this fctx has forwarders, use them; otherwise use any
1513 * selective forwarders specified in the view; otherwise use the
1514 * resolver's forwarders (if any).
1516 sa = ISC_LIST_HEAD(fctx->forwarders);
1517 if (sa == NULL) {
1518 dns_forwarders_t *forwarders = NULL;
1519 result = dns_fwdtable_find(fctx->res->view->fwdtable,
1520 &fctx->name, &forwarders);
1521 if (result == ISC_R_SUCCESS) {
1522 sa = ISC_LIST_HEAD(forwarders->addrs);
1523 fctx->fwdpolicy = forwarders->fwdpolicy;
1527 while (sa != NULL) {
1528 ai = NULL;
1529 result = dns_adb_findaddrinfo(fctx->adb,
1530 sa, &ai, 0); /* XXXMLG */
1531 if (result == ISC_R_SUCCESS) {
1532 ai->flags |= FCTX_ADDRINFO_FORWARDER;
1533 ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
1535 sa = ISC_LIST_NEXT(sa, link);
1539 * If the forwarding policy is "only", we don't need the addresses
1540 * of the nameservers.
1542 if (fctx->fwdpolicy == dns_fwdpolicy_only)
1543 goto out;
1546 * Normal nameservers.
1549 stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
1550 if (fctx->restarts == 1) {
1552 * To avoid sending out a flood of queries likely to
1553 * result in NXRRSET, we suppress fetches for address
1554 * families we don't have the first time through,
1555 * provided that we have addresses in some family we
1556 * can use.
1558 * We don't want to set this option all the time, since
1559 * if fctx->restarts > 1, we've clearly been having trouble
1560 * with the addresses we had, so getting more could help.
1562 stdoptions |= DNS_ADBFIND_AVOIDFETCHES;
1564 if (res->dispatchv4 != NULL)
1565 stdoptions |= DNS_ADBFIND_INET;
1566 if (res->dispatchv6 != NULL)
1567 stdoptions |= DNS_ADBFIND_INET6;
1568 isc_stdtime_get(&now);
1570 restart:
1571 INSIST(ISC_LIST_EMPTY(fctx->finds));
1573 result = dns_rdataset_first(&fctx->nameservers);
1574 while (result == ISC_R_SUCCESS) {
1575 dns_rdataset_current(&fctx->nameservers, &rdata);
1577 * Extract the name from the NS record.
1579 result = dns_rdata_tostruct(&rdata, &ns, NULL);
1580 if (result != ISC_R_SUCCESS) {
1581 dns_rdataset_next(&fctx->nameservers);
1582 continue;
1584 options = stdoptions;
1586 * If this name is a subdomain of the query domain, tell
1587 * the ADB to start looking using zone/hint data. This keeps
1588 * us from getting stuck if the nameserver is beneath the
1589 * zone cut and we don't know its address (e.g. because the
1590 * A record has expired).
1592 if (dns_name_issubdomain(&ns.name, &fctx->domain))
1593 options |= DNS_ADBFIND_STARTATZONE;
1594 options |= DNS_ADBFIND_GLUEOK;
1595 options |= DNS_ADBFIND_HINTOK;
1598 * See what we know about this address.
1600 find = NULL;
1601 result = dns_adb_createfind(fctx->adb,
1602 res->buckets[fctx->bucketnum].task,
1603 fctx_finddone, fctx, &ns.name,
1604 &fctx->domain, options, now, NULL,
1605 res->view->dstport, &find);
1606 if (result != ISC_R_SUCCESS) {
1607 if (result == DNS_R_ALIAS) {
1609 * XXXRTH Follow the CNAME/DNAME chain?
1611 dns_adb_destroyfind(&find);
1613 } else if (!ISC_LIST_EMPTY(find->list)) {
1615 * We have at least some of the addresses for the
1616 * name.
1618 INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
1619 sort_adbfind(find);
1620 ISC_LIST_APPEND(fctx->finds, find, publink);
1621 } else {
1623 * We don't know any of the addresses for this
1624 * name.
1626 if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
1628 * We're looking for them and will get an
1629 * event about it later.
1631 fctx->pending++;
1632 } else {
1634 * And ADB isn't going to send us any events
1635 * either. This find loses.
1637 if ((find->options & DNS_ADBFIND_LAMEPRUNED)
1638 != 0) {
1640 * The ADB pruned lame servers for
1641 * this name. Remember that in case
1642 * we get desperate later on.
1644 pruned = ISC_TRUE;
1646 dns_adb_destroyfind(&find);
1649 dns_rdata_reset(&rdata);
1650 dns_rdata_freestruct(&ns);
1651 result = dns_rdataset_next(&fctx->nameservers);
1653 if (result != ISC_R_NOMORE)
1654 return (result);
1656 out:
1658 * Mark all known bad servers.
1660 all_bad = mark_bad(fctx);
1663 * How are we doing?
1665 if (all_bad) {
1667 * We've got no addresses.
1669 if (fctx->pending > 0) {
1671 * We're fetching the addresses, but don't have any
1672 * yet. Tell the caller to wait for an answer.
1674 result = DNS_R_WAIT;
1675 } else if (pruned) {
1677 * Some addresses were removed by lame pruning.
1678 * Turn pruning off and try again.
1680 FCTXTRACE("restarting with returnlame");
1681 INSIST((stdoptions & DNS_ADBFIND_RETURNLAME) == 0);
1682 stdoptions |= DNS_ADBFIND_RETURNLAME;
1683 pruned = ISC_FALSE;
1684 fctx_cleanupfinds(fctx);
1685 goto restart;
1686 } else {
1688 * We've lost completely. We don't know any
1689 * addresses, and the ADB has told us it can't get
1690 * them.
1692 FCTXTRACE("no addresses");
1693 result = ISC_R_FAILURE;
1695 } else {
1697 * We've found some addresses. We might still be looking
1698 * for more addresses.
1701 * XXXRTH We could sort the forwaddrs here if the caller
1702 * wants to use the forwaddrs in "best order" as
1703 * opposed to "fixed order".
1705 sort_finds(fctx);
1706 result = ISC_R_SUCCESS;
1709 return (result);
1712 static inline void
1713 possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr)
1715 isc_netaddr_t na;
1716 char buf[ISC_NETADDR_FORMATSIZE];
1717 isc_sockaddr_t *sa;
1718 isc_boolean_t aborted = ISC_FALSE;
1719 isc_boolean_t bogus;
1720 dns_acl_t *blackhole;
1721 isc_netaddr_t ipaddr;
1722 dns_peer_t *peer = NULL;
1723 dns_resolver_t *res;
1724 const char *msg = NULL;
1726 sa = &addr->sockaddr;
1728 res = fctx->res;
1729 isc_netaddr_fromsockaddr(&ipaddr, sa);
1730 blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr);
1731 (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer);
1733 if (blackhole != NULL) {
1734 int match;
1736 if (dns_acl_match(&ipaddr, NULL, blackhole,
1737 &res->view->aclenv,
1738 &match, NULL) == ISC_R_SUCCESS &&
1739 match > 0)
1740 aborted = ISC_TRUE;
1743 if (peer != NULL &&
1744 dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS &&
1745 bogus)
1746 aborted = ISC_TRUE;
1748 if (aborted) {
1749 addr->flags |= FCTX_ADDRINFO_MARK;
1750 msg = "ignoring blackholed / bogus server: ";
1751 } else if (sa->type.sa.sa_family != AF_INET6) {
1752 return;
1753 } else if (isc_sockaddr_ismulticast(sa)) {
1754 addr->flags |= FCTX_ADDRINFO_MARK;
1755 msg = "ignoring multicast address: ";
1756 } else if (isc_sockaddr_isexperimental(sa)) {
1757 addr->flags |= FCTX_ADDRINFO_MARK;
1758 msg = "ignoring experimental address: ";
1759 } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) {
1760 addr->flags |= FCTX_ADDRINFO_MARK;
1761 msg = "ignoring IPv6 mapped IPV4 address: ";
1762 } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) {
1763 addr->flags |= FCTX_ADDRINFO_MARK;
1764 msg = "ignoring IPv6 compatibility IPV4 address: ";
1765 } else
1766 return;
1768 if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3)))
1769 return;
1771 isc_netaddr_fromsockaddr(&na, sa);
1772 isc_netaddr_format(&na, buf, sizeof buf);
1773 FCTXTRACE2(msg, buf);
1776 static inline dns_adbaddrinfo_t *
1777 fctx_nextaddress(fetchctx_t *fctx) {
1778 dns_adbfind_t *find, *start;
1779 dns_adbaddrinfo_t *addrinfo;
1782 * Return the next untried address, if any.
1786 * Find the first unmarked forwarder (if any).
1788 for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
1789 addrinfo != NULL;
1790 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1791 possibly_mark(fctx, addrinfo);
1792 if (UNMARKED(addrinfo)) {
1793 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1794 fctx->find = NULL;
1795 return (addrinfo);
1800 * No forwarders. Move to the next find.
1802 find = fctx->find;
1803 if (find == NULL)
1804 find = ISC_LIST_HEAD(fctx->finds);
1805 else {
1806 find = ISC_LIST_NEXT(find, publink);
1807 if (find == NULL)
1808 find = ISC_LIST_HEAD(fctx->finds);
1812 * Find the first unmarked addrinfo.
1814 addrinfo = NULL;
1815 if (find != NULL) {
1816 start = find;
1817 do {
1818 for (addrinfo = ISC_LIST_HEAD(find->list);
1819 addrinfo != NULL;
1820 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1821 possibly_mark(fctx, addrinfo);
1822 if (UNMARKED(addrinfo)) {
1823 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1824 break;
1827 if (addrinfo != NULL)
1828 break;
1829 find = ISC_LIST_NEXT(find, publink);
1830 if (find == NULL)
1831 find = ISC_LIST_HEAD(fctx->finds);
1832 } while (find != start);
1835 fctx->find = find;
1837 return (addrinfo);
1840 static void
1841 fctx_try(fetchctx_t *fctx) {
1842 isc_result_t result;
1843 dns_adbaddrinfo_t *addrinfo;
1845 FCTXTRACE("try");
1847 REQUIRE(!ADDRWAIT(fctx));
1849 addrinfo = fctx_nextaddress(fctx);
1850 if (addrinfo == NULL) {
1852 * We have no more addresses. Start over.
1854 fctx_cancelqueries(fctx, ISC_TRUE);
1855 fctx_cleanupfinds(fctx);
1856 fctx_cleanupforwaddrs(fctx);
1857 result = fctx_getaddresses(fctx);
1858 if (result == DNS_R_WAIT) {
1860 * Sleep waiting for addresses.
1862 FCTXTRACE("addrwait");
1863 fctx->attributes |= FCTX_ATTR_ADDRWAIT;
1864 return;
1865 } else if (result != ISC_R_SUCCESS) {
1867 * Something bad happened.
1869 fctx_done(fctx, result);
1870 return;
1873 addrinfo = fctx_nextaddress(fctx);
1875 * While we may have addresses from the ADB, they
1876 * might be bad ones. In this case, return SERVFAIL.
1878 if (addrinfo == NULL) {
1879 fctx_done(fctx, DNS_R_SERVFAIL);
1880 return;
1884 result = fctx_query(fctx, addrinfo, fctx->options);
1885 if (result != ISC_R_SUCCESS)
1886 fctx_done(fctx, result);
1889 static isc_boolean_t
1890 fctx_destroy(fetchctx_t *fctx) {
1891 dns_resolver_t *res;
1892 unsigned int bucketnum;
1893 isc_sockaddr_t *sa, *next_sa;
1896 * Caller must be holding the bucket lock.
1899 REQUIRE(VALID_FCTX(fctx));
1900 REQUIRE(fctx->state == fetchstate_done ||
1901 fctx->state == fetchstate_init);
1902 REQUIRE(ISC_LIST_EMPTY(fctx->events));
1903 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
1904 REQUIRE(ISC_LIST_EMPTY(fctx->finds));
1905 REQUIRE(fctx->pending == 0);
1906 REQUIRE(ISC_LIST_EMPTY(fctx->validators));
1907 REQUIRE(fctx->references == 0);
1909 FCTXTRACE("destroy");
1911 res = fctx->res;
1912 bucketnum = fctx->bucketnum;
1914 ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
1917 * Free bad.
1919 for (sa = ISC_LIST_HEAD(fctx->bad);
1920 sa != NULL;
1921 sa = next_sa) {
1922 next_sa = ISC_LIST_NEXT(sa, link);
1923 ISC_LIST_UNLINK(fctx->bad, sa, link);
1924 isc_mem_put(res->mctx, sa, sizeof *sa);
1927 isc_timer_detach(&fctx->timer);
1928 dns_message_destroy(&fctx->rmessage);
1929 dns_message_destroy(&fctx->qmessage);
1930 if (dns_name_countlabels(&fctx->domain) > 0)
1931 dns_name_free(&fctx->domain, res->mctx);
1932 if (dns_rdataset_isassociated(&fctx->nameservers))
1933 dns_rdataset_disassociate(&fctx->nameservers);
1934 dns_name_free(&fctx->name, res->mctx);
1935 dns_db_detach(&fctx->cache);
1936 dns_adb_detach(&fctx->adb);
1937 isc_mem_put(res->mctx, fctx, sizeof *fctx);
1939 if (res->buckets[bucketnum].exiting &&
1940 ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
1941 return (ISC_TRUE);
1943 return (ISC_FALSE);
1947 * Fetch event handlers.
1950 static void
1951 fctx_timeout(isc_task_t *task, isc_event_t *event) {
1952 fetchctx_t *fctx = event->ev_arg;
1954 REQUIRE(VALID_FCTX(fctx));
1956 UNUSED(task);
1958 FCTXTRACE("timeout");
1960 if (event->ev_type == ISC_TIMEREVENT_LIFE) {
1961 fctx_done(fctx, ISC_R_TIMEDOUT);
1962 } else {
1963 fctx->timeouts++;
1965 * We could cancel the running queries here, or we could let
1966 * them keep going. Right now we choose the latter...
1968 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1970 * Our timer has triggered. Reestablish the fctx lifetime
1971 * timer.
1973 fctx_starttimer(fctx);
1975 * Keep trying.
1977 fctx_try(fctx);
1980 isc_event_free(&event);
1983 static void
1984 fctx_shutdown(fetchctx_t *fctx) {
1985 isc_event_t *cevent;
1988 * Start the shutdown process for fctx, if it isn't already underway.
1991 FCTXTRACE("shutdown");
1994 * The caller must be holding the appropriate bucket lock.
1997 if (fctx->want_shutdown)
1998 return;
2000 fctx->want_shutdown = ISC_TRUE;
2003 * Unless we're still initializing (in which case the
2004 * control event is still outstanding), we need to post
2005 * the control event to tell the fetch we want it to
2006 * exit.
2008 if (fctx->state != fetchstate_init) {
2009 cevent = &fctx->control_event;
2010 isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
2011 &cevent);
2015 static void
2016 fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
2017 fetchctx_t *fctx = event->ev_arg;
2018 isc_boolean_t bucket_empty = ISC_FALSE;
2019 dns_resolver_t *res;
2020 unsigned int bucketnum;
2021 dns_validator_t *validator;
2023 REQUIRE(VALID_FCTX(fctx));
2025 UNUSED(task);
2027 res = fctx->res;
2028 bucketnum = fctx->bucketnum;
2030 FCTXTRACE("doshutdown");
2033 * An fctx that is shutting down is no longer in ADDRWAIT mode.
2035 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
2038 * Cancel all pending validators. Note that this must be done
2039 * without the bucket lock held, since that could cause deadlock.
2041 validator = ISC_LIST_HEAD(fctx->validators);
2042 while (validator != NULL) {
2043 dns_validator_cancel(validator);
2044 validator = ISC_LIST_NEXT(validator, link);
2048 * Shut down anything that is still running on behalf of this
2049 * fetch. To avoid deadlock with the ADB, we must do this
2050 * before we lock the bucket lock.
2052 fctx_stopeverything(fctx, ISC_FALSE);
2054 LOCK(&res->buckets[bucketnum].lock);
2056 fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
2058 INSIST(fctx->state == fetchstate_active ||
2059 fctx->state == fetchstate_done);
2060 INSIST(fctx->want_shutdown);
2062 if (fctx->state != fetchstate_done) {
2063 fctx->state = fetchstate_done;
2064 fctx_sendevents(fctx, ISC_R_CANCELED);
2067 if (fctx->references == 0 && fctx->pending == 0 &&
2068 ISC_LIST_EMPTY(fctx->validators))
2069 bucket_empty = fctx_destroy(fctx);
2071 UNLOCK(&res->buckets[bucketnum].lock);
2073 if (bucket_empty)
2074 empty_bucket(res);
2077 static void
2078 fctx_start(isc_task_t *task, isc_event_t *event) {
2079 fetchctx_t *fctx = event->ev_arg;
2080 isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE;
2081 dns_resolver_t *res;
2082 unsigned int bucketnum;
2084 REQUIRE(VALID_FCTX(fctx));
2086 UNUSED(task);
2088 res = fctx->res;
2089 bucketnum = fctx->bucketnum;
2091 FCTXTRACE("start");
2093 LOCK(&res->buckets[bucketnum].lock);
2095 INSIST(fctx->state == fetchstate_init);
2096 if (fctx->want_shutdown) {
2098 * We haven't started this fctx yet, and we've been requested
2099 * to shut it down.
2101 fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
2102 fctx->state = fetchstate_done;
2103 fctx_sendevents(fctx, ISC_R_CANCELED);
2105 * Since we haven't started, we INSIST that we have no
2106 * pending ADB finds and no pending validations.
2108 INSIST(fctx->pending == 0);
2109 INSIST(ISC_LIST_EMPTY(fctx->validators));
2110 if (fctx->references == 0) {
2112 * It's now safe to destroy this fctx.
2114 bucket_empty = fctx_destroy(fctx);
2116 done = ISC_TRUE;
2117 } else {
2119 * Normal fctx startup.
2121 fctx->state = fetchstate_active;
2123 * Reset the control event for later use in shutting down
2124 * the fctx.
2126 ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
2127 DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx,
2128 NULL, NULL, NULL);
2131 UNLOCK(&res->buckets[bucketnum].lock);
2133 if (!done) {
2135 * All is well. Start working on the fetch.
2137 fctx_starttimer(fctx);
2138 fctx_try(fctx);
2139 } else if (bucket_empty)
2140 empty_bucket(res);
2144 * Fetch Creation, Joining, and Cancelation.
2147 static inline isc_result_t
2148 fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_taskaction_t action,
2149 void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
2150 dns_fetch_t *fetch)
2152 isc_task_t *clone;
2153 dns_fetchevent_t *event;
2155 FCTXTRACE("join");
2158 * We store the task we're going to send this event to in the
2159 * sender field. We'll make the fetch the sender when we actually
2160 * send the event.
2162 clone = NULL;
2163 isc_task_attach(task, &clone);
2164 event = (dns_fetchevent_t *)
2165 isc_event_allocate(fctx->res->mctx, clone,
2166 DNS_EVENT_FETCHDONE,
2167 action, arg, sizeof *event);
2168 if (event == NULL) {
2169 isc_task_detach(&clone);
2170 return (ISC_R_NOMEMORY);
2172 event->result = DNS_R_SERVFAIL;
2173 event->qtype = fctx->type;
2174 event->db = NULL;
2175 event->node = NULL;
2176 event->rdataset = rdataset;
2177 event->sigrdataset = sigrdataset;
2178 event->fetch = fetch;
2179 dns_fixedname_init(&event->foundname);
2182 * Make sure that we can store the sigrdataset in the
2183 * first event if it is needed by any of the events.
2185 if (event->sigrdataset != NULL)
2186 ISC_LIST_PREPEND(fctx->events, event, ev_link);
2187 else
2188 ISC_LIST_APPEND(fctx->events, event, ev_link);
2189 fctx->references++;
2191 fetch->magic = DNS_FETCH_MAGIC;
2192 fetch->private = fctx;
2194 return (ISC_R_SUCCESS);
2197 static isc_result_t
2198 fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
2199 dns_name_t *domain, dns_rdataset_t *nameservers,
2200 unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
2202 fetchctx_t *fctx;
2203 isc_result_t result = ISC_R_SUCCESS;
2204 isc_result_t iresult;
2205 isc_interval_t interval;
2206 dns_fixedname_t qdomain;
2207 unsigned int findoptions = 0;
2210 * Caller must be holding the lock for bucket number 'bucketnum'.
2212 REQUIRE(fctxp != NULL && *fctxp == NULL);
2214 fctx = isc_mem_get(res->mctx, sizeof *fctx);
2215 if (fctx == NULL)
2216 return (ISC_R_NOMEMORY);
2217 FCTXTRACE("create");
2218 dns_name_init(&fctx->name, NULL);
2219 result = dns_name_dup(name, res->mctx, &fctx->name);
2220 if (result != ISC_R_SUCCESS)
2221 goto cleanup_fetch;
2222 dns_name_init(&fctx->domain, NULL);
2223 dns_rdataset_init(&fctx->nameservers);
2225 fctx->type = type;
2226 fctx->options = options;
2228 * Note! We do not attach to the task. We are relying on the
2229 * resolver to ensure that this task doesn't go away while we are
2230 * using it.
2232 fctx->res = res;
2233 fctx->references = 0;
2234 fctx->bucketnum = bucketnum;
2235 fctx->state = fetchstate_init;
2236 fctx->want_shutdown = ISC_FALSE;
2237 fctx->cloned = ISC_FALSE;
2238 ISC_LIST_INIT(fctx->queries);
2239 ISC_LIST_INIT(fctx->finds);
2240 ISC_LIST_INIT(fctx->forwaddrs);
2241 ISC_LIST_INIT(fctx->forwarders);
2242 fctx->fwdpolicy = dns_fwdpolicy_none;
2243 ISC_LIST_INIT(fctx->bad);
2244 ISC_LIST_INIT(fctx->validators);
2245 fctx->find = NULL;
2246 fctx->pending = 0;
2247 fctx->restarts = 0;
2248 fctx->timeouts = 0;
2249 if (dns_name_requiresedns(name))
2250 fctx->attributes = FCTX_ATTR_NEEDEDNS0;
2251 else
2252 fctx->attributes = 0;
2254 if (domain == NULL) {
2255 dns_forwarders_t *forwarders = NULL;
2256 result = dns_fwdtable_find(fctx->res->view->fwdtable,
2257 &fctx->name, &forwarders);
2258 if (result == ISC_R_SUCCESS)
2259 fctx->fwdpolicy = forwarders->fwdpolicy;
2261 if (fctx->fwdpolicy != dns_fwdpolicy_only) {
2263 * The caller didn't supply a query domain and
2264 * nameservers, and we're not in forward-only mode,
2265 * so find the best nameservers to use.
2267 if (type == dns_rdatatype_key)
2268 findoptions |= DNS_DBFIND_NOEXACT;
2269 dns_fixedname_init(&qdomain);
2270 result = dns_view_findzonecut(res->view, name,
2271 dns_fixedname_name(&qdomain), 0,
2272 findoptions, ISC_TRUE,
2273 &fctx->nameservers,
2274 NULL);
2275 if (result != ISC_R_SUCCESS)
2276 goto cleanup_name;
2277 result = dns_name_dup(dns_fixedname_name(&qdomain),
2278 res->mctx, &fctx->domain);
2279 if (result != ISC_R_SUCCESS) {
2280 dns_rdataset_disassociate(&fctx->nameservers);
2281 goto cleanup_name;
2283 } else {
2285 * We're in forward-only mode. Set the query domain
2286 * to ".".
2288 result = dns_name_dup(dns_rootname, res->mctx,
2289 &fctx->domain);
2290 if (result != ISC_R_SUCCESS)
2291 goto cleanup_name;
2293 } else {
2294 result = dns_name_dup(domain, res->mctx, &fctx->domain);
2295 if (result != ISC_R_SUCCESS)
2296 goto cleanup_name;
2297 dns_rdataset_clone(nameservers, &fctx->nameservers);
2300 INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
2302 fctx->qmessage = NULL;
2303 result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTRENDER,
2304 &fctx->qmessage);
2306 if (result != ISC_R_SUCCESS)
2307 goto cleanup_domain;
2309 fctx->rmessage = NULL;
2310 result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTPARSE,
2311 &fctx->rmessage);
2313 if (result != ISC_R_SUCCESS)
2314 goto cleanup_qmessage;
2317 * Compute an expiration time for the entire fetch.
2319 isc_interval_set(&interval, 30, 0); /* XXXRTH constant */
2320 iresult = isc_time_nowplusinterval(&fctx->expires, &interval);
2321 if (iresult != ISC_R_SUCCESS) {
2322 UNEXPECTED_ERROR(__FILE__, __LINE__,
2323 "isc_time_nowplusinterval: %s",
2324 isc_result_totext(iresult));
2325 result = ISC_R_UNEXPECTED;
2326 goto cleanup_rmessage;
2330 * Default retry interval initialization. We set the interval now
2331 * mostly so it won't be uninitialized. It will be set to the
2332 * correct value before a query is issued.
2334 isc_interval_set(&fctx->interval, 2, 0);
2337 * Create an inactive timer. It will be made active when the fetch
2338 * is actually started.
2340 fctx->timer = NULL;
2341 iresult = isc_timer_create(res->timermgr, isc_timertype_inactive,
2342 NULL, NULL,
2343 res->buckets[bucketnum].task, fctx_timeout,
2344 fctx, &fctx->timer);
2345 if (iresult != ISC_R_SUCCESS) {
2346 UNEXPECTED_ERROR(__FILE__, __LINE__,
2347 "isc_timer_create: %s",
2348 isc_result_totext(iresult));
2349 result = ISC_R_UNEXPECTED;
2350 goto cleanup_rmessage;
2354 * Attach to the view's cache and adb.
2356 fctx->cache = NULL;
2357 dns_db_attach(res->view->cachedb, &fctx->cache);
2358 fctx->adb = NULL;
2359 dns_adb_attach(res->view->adb, &fctx->adb);
2361 ISC_LIST_INIT(fctx->events);
2362 ISC_LINK_INIT(fctx, link);
2363 fctx->magic = FCTX_MAGIC;
2365 ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
2367 *fctxp = fctx;
2369 return (ISC_R_SUCCESS);
2371 cleanup_rmessage:
2372 dns_message_destroy(&fctx->rmessage);
2374 cleanup_qmessage:
2375 dns_message_destroy(&fctx->qmessage);
2377 cleanup_domain:
2378 if (dns_name_countlabels(&fctx->domain) > 0)
2379 dns_name_free(&fctx->domain, res->mctx);
2380 if (dns_rdataset_isassociated(&fctx->nameservers))
2381 dns_rdataset_disassociate(&fctx->nameservers);
2383 cleanup_name:
2384 dns_name_free(&fctx->name, res->mctx);
2386 cleanup_fetch:
2387 isc_mem_put(res->mctx, fctx, sizeof *fctx);
2389 return (result);
2393 * Handle Responses
2395 static inline isc_boolean_t
2396 is_lame(fetchctx_t *fctx) {
2397 dns_message_t *message = fctx->rmessage;
2398 dns_name_t *name;
2399 dns_rdataset_t *rdataset;
2400 isc_result_t result;
2402 if (message->rcode != dns_rcode_noerror &&
2403 message->rcode != dns_rcode_nxdomain)
2404 return (ISC_FALSE);
2406 if (message->counts[DNS_SECTION_ANSWER] != 0)
2407 return (ISC_FALSE);
2409 if (message->counts[DNS_SECTION_AUTHORITY] == 0)
2410 return (ISC_FALSE);
2412 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
2413 while (result == ISC_R_SUCCESS) {
2414 name = NULL;
2415 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
2416 for (rdataset = ISC_LIST_HEAD(name->list);
2417 rdataset != NULL;
2418 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2419 dns_namereln_t namereln;
2420 int order;
2421 unsigned int labels, bits;
2422 if (rdataset->type != dns_rdatatype_ns)
2423 continue;
2424 namereln = dns_name_fullcompare(name, &fctx->domain,
2425 &order, &labels, &bits);
2426 if (namereln == dns_namereln_equal &&
2427 (message->flags & DNS_MESSAGEFLAG_AA) != 0)
2428 return (ISC_FALSE);
2429 if (namereln == dns_namereln_subdomain)
2430 return (ISC_FALSE);
2431 return (ISC_TRUE);
2433 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
2436 return (ISC_FALSE);
2439 static inline void
2440 log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) {
2441 char namebuf[DNS_NAME_FORMATSIZE];
2442 char domainbuf[DNS_NAME_FORMATSIZE];
2443 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2445 dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
2446 dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
2447 isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf));
2448 isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
2449 DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
2450 "lame server resolving '%s' (in '%s'?): %s",
2451 namebuf, domainbuf, addrbuf);
2454 static inline isc_result_t
2455 same_question(fetchctx_t *fctx) {
2456 isc_result_t result;
2457 dns_message_t *message = fctx->rmessage;
2458 dns_name_t *name;
2459 dns_rdataset_t *rdataset;
2462 * Caller must be holding the fctx lock.
2466 * XXXRTH Currently we support only one question.
2468 if (message->counts[DNS_SECTION_QUESTION] != 1)
2469 return (DNS_R_FORMERR);
2471 result = dns_message_firstname(message, DNS_SECTION_QUESTION);
2472 if (result != ISC_R_SUCCESS)
2473 return (result);
2474 name = NULL;
2475 dns_message_currentname(message, DNS_SECTION_QUESTION, &name);
2476 rdataset = ISC_LIST_HEAD(name->list);
2477 INSIST(rdataset != NULL);
2478 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
2479 if (fctx->type != rdataset->type ||
2480 fctx->res->rdclass != rdataset->rdclass ||
2481 !dns_name_equal(&fctx->name, name))
2482 return (DNS_R_FORMERR);
2484 return (ISC_R_SUCCESS);
2487 static void
2488 clone_results(fetchctx_t *fctx) {
2489 dns_fetchevent_t *event, *hevent;
2490 isc_result_t result;
2491 dns_name_t *name, *hname;
2494 * Set up any other events to have the same data as the first
2495 * event.
2497 * Caller must be holding the appropriate lock.
2500 fctx->cloned = ISC_TRUE;
2501 hevent = ISC_LIST_HEAD(fctx->events);
2502 if (hevent == NULL)
2503 return;
2504 hname = dns_fixedname_name(&hevent->foundname);
2505 for (event = ISC_LIST_NEXT(hevent, ev_link);
2506 event != NULL;
2507 event = ISC_LIST_NEXT(event, ev_link)) {
2508 name = dns_fixedname_name(&event->foundname);
2509 result = dns_name_copy(hname, name, NULL);
2510 if (result != ISC_R_SUCCESS)
2511 event->result = result;
2512 else
2513 event->result = hevent->result;
2514 dns_db_attach(hevent->db, &event->db);
2515 dns_db_attachnode(hevent->db, hevent->node, &event->node);
2516 INSIST(hevent->rdataset != NULL);
2517 INSIST(event->rdataset != NULL);
2518 if (dns_rdataset_isassociated(hevent->rdataset))
2519 dns_rdataset_clone(hevent->rdataset, event->rdataset);
2520 INSIST(! (hevent->sigrdataset == NULL &&
2521 event->sigrdataset != NULL));
2522 if (hevent->sigrdataset != NULL &&
2523 dns_rdataset_isassociated(hevent->sigrdataset) &&
2524 event->sigrdataset != NULL)
2525 dns_rdataset_clone(hevent->sigrdataset,
2526 event->sigrdataset);
2530 #define CACHE(r) (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0)
2531 #define ANSWER(r) (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0)
2532 #define ANSWERSIG(r) (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0)
2533 #define EXTERNAL(r) (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0)
2534 #define CHAINING(r) (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0)
2535 #define CHASE(r) (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0)
2539 * Destroy '*fctx' if it is ready to be destroyed (i.e., if it has
2540 * no references and is no longer waiting for any events). If this
2541 * was the last fctx in the resolver, destroy the resolver.
2543 * Requires:
2544 * '*fctx' is shutting down.
2546 static void
2547 maybe_destroy(fetchctx_t *fctx) {
2548 unsigned int bucketnum;
2549 isc_boolean_t bucket_empty = ISC_FALSE;
2550 dns_resolver_t *res = fctx->res;
2552 REQUIRE(SHUTTINGDOWN(fctx));
2554 if (fctx->pending != 0 || !ISC_LIST_EMPTY(fctx->validators))
2555 return;
2557 bucketnum = fctx->bucketnum;
2558 LOCK(&res->buckets[bucketnum].lock);
2559 if (fctx->references == 0)
2560 bucket_empty = fctx_destroy(fctx);
2561 UNLOCK(&res->buckets[bucketnum].lock);
2563 if (bucket_empty)
2564 empty_bucket(res);
2568 * The validator has finished.
2570 static void
2571 validated(isc_task_t *task, isc_event_t *event) {
2572 isc_result_t result = ISC_R_SUCCESS;
2573 isc_result_t eresult = ISC_R_SUCCESS;
2574 isc_stdtime_t now;
2575 fetchctx_t *fctx;
2576 dns_validatorevent_t *vevent;
2577 dns_fetchevent_t *hevent;
2578 dns_rdataset_t *ardataset = NULL;
2579 dns_rdataset_t *asigrdataset = NULL;
2580 dns_dbnode_t *node = NULL;
2581 isc_boolean_t negative;
2582 isc_boolean_t chaining;
2583 isc_boolean_t sentresponse;
2584 isc_uint32_t ttl;
2586 UNUSED(task); /* for now */
2588 REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE);
2589 fctx = event->ev_arg;
2590 REQUIRE(VALID_FCTX(fctx));
2591 REQUIRE(!ISC_LIST_EMPTY(fctx->validators));
2593 vevent = (dns_validatorevent_t *)event;
2595 FCTXTRACE("received validation completion event");
2597 ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
2600 * Destroy the validator early so that we can
2601 * destroy the fctx if necessary.
2603 dns_validator_destroy(&vevent->validator);
2605 negative = ISC_TF(vevent->rdataset == NULL);
2607 sentresponse = ISC_TF((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0);
2610 * If shutting down, ignore the results. Check to see if we're
2611 * done waiting for validator completions and ADB pending events; if
2612 * so, destroy the fctx.
2614 if (SHUTTINGDOWN(fctx) && !sentresponse ) {
2615 maybe_destroy(fctx);
2616 goto cleanup_event;
2620 * If chaining, we need to make sure that the right result code is
2621 * returned, and that the rdatasets are bound.
2623 if (vevent->result == ISC_R_SUCCESS &&
2624 !negative &&
2625 vevent->rdataset != NULL &&
2626 CHAINING(vevent->rdataset))
2628 if (vevent->rdataset->type == dns_rdatatype_cname)
2629 eresult = DNS_R_CNAME;
2630 else {
2631 INSIST(vevent->rdataset->type == dns_rdatatype_dname);
2632 eresult = DNS_R_DNAME;
2634 chaining = ISC_TRUE;
2635 } else
2636 chaining = ISC_FALSE;
2639 * Either we're not shutting down, or we are shutting down but want
2640 * to cache the result anyway (if this was a validation started by
2641 * a query with cd set)
2644 hevent = ISC_LIST_HEAD(fctx->events);
2645 if (hevent != NULL) {
2646 if (!negative && !chaining &&
2647 (fctx->type == dns_rdatatype_any ||
2648 fctx->type == dns_rdatatype_sig)) {
2650 * Don't bind rdatasets; the caller
2651 * will iterate the node.
2653 } else {
2654 ardataset = hevent->rdataset;
2655 asigrdataset = hevent->sigrdataset;
2659 if (vevent->result != ISC_R_SUCCESS) {
2660 FCTXTRACE("validation failed");
2661 if (vevent->rdataset != NULL) {
2662 result = dns_db_findnode(fctx->cache, vevent->name,
2663 ISC_TRUE, &node);
2664 if (result != ISC_R_SUCCESS)
2665 goto noanswer_response;
2666 (void)dns_db_deleterdataset(fctx->cache, node, NULL,
2667 vevent->type, 0);
2668 if (vevent->sigrdataset != NULL)
2669 (void)dns_db_deleterdataset(fctx->cache,
2670 node, NULL,
2671 dns_rdatatype_sig,
2672 vevent->type);
2674 result = vevent->result;
2675 goto noanswer_response;
2678 isc_stdtime_get(&now);
2680 if (negative) {
2681 dns_rdatatype_t covers;
2682 FCTXTRACE("nonexistence validation OK");
2684 if (fctx->rmessage->rcode == dns_rcode_nxdomain)
2685 covers = dns_rdatatype_any;
2686 else
2687 covers = fctx->type;
2689 result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE,
2690 &node);
2691 if (result != ISC_R_SUCCESS)
2692 goto noanswer_response;
2695 * If we are asking for a SOA record set the cache time
2696 * to zero to facilitate locating the containing zone of
2697 * a arbitary zone.
2699 ttl = fctx->res->view->maxncachettl;
2700 if (fctx->type == dns_rdatatype_soa &&
2701 covers == dns_rdatatype_any)
2702 ttl = 0;
2704 result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
2705 covers, now, ttl,
2706 ardataset, &eresult);
2707 if (result != ISC_R_SUCCESS)
2708 goto noanswer_response;
2710 goto answer_response;
2713 FCTXTRACE("validation OK");
2716 * The data was already cached as pending data.
2717 * Re-cache it as secure and bind the cached
2718 * rdatasets to the first event on the fetch
2719 * event list.
2721 result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node);
2722 if (result != ISC_R_SUCCESS)
2723 goto noanswer_response;
2725 result = dns_db_addrdataset(fctx->cache, node, NULL, now,
2726 vevent->rdataset, 0, ardataset);
2727 if (result != ISC_R_SUCCESS &&
2728 result != DNS_R_UNCHANGED)
2729 goto noanswer_response;
2730 if (vevent->sigrdataset != NULL) {
2731 result = dns_db_addrdataset(fctx->cache, node, NULL, now,
2732 vevent->sigrdataset, 0,
2733 asigrdataset);
2734 if (result != ISC_R_SUCCESS &&
2735 result != DNS_R_UNCHANGED)
2736 goto noanswer_response;
2739 if (sentresponse) {
2741 * If we only deferred the destroy because we wanted to cache
2742 * the data, destroy now.
2744 if (SHUTTINGDOWN(fctx))
2745 maybe_destroy(fctx);
2747 goto cleanup_event;
2750 if (!ISC_LIST_EMPTY(fctx->validators)) {
2751 INSIST(!negative);
2752 INSIST(fctx->type == dns_rdatatype_any ||
2753 fctx->type == dns_rdatatype_sig);
2755 * Don't send a response yet - we have
2756 * more rdatasets that still need to
2757 * be validated.
2759 goto cleanup_event;
2762 result = ISC_R_SUCCESS;
2764 answer_response:
2766 * Respond with an answer, positive or negative,
2767 * as opposed to an error. 'node' must be non-NULL.
2770 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
2772 if (hevent != NULL) {
2773 hevent->result = eresult;
2774 dns_name_copy(vevent->name,
2775 dns_fixedname_name(&hevent->foundname), NULL);
2776 dns_db_attach(fctx->cache, &hevent->db);
2777 hevent->node = node;
2778 node = NULL;
2779 clone_results(fctx);
2782 noanswer_response:
2783 if (node != NULL)
2784 dns_db_detachnode(fctx->cache, &node);
2786 fctx_done(fctx, result);
2788 cleanup_event:
2789 isc_event_free(&event);
2792 static inline isc_result_t
2793 cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
2794 dns_rdataset_t *rdataset, *sigrdataset;
2795 dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset;
2796 dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL;
2797 dns_dbnode_t *node, **anodep;
2798 dns_db_t **adbp;
2799 dns_name_t *aname;
2800 dns_resolver_t *res;
2801 isc_boolean_t need_validation, secure_domain, have_answer;
2802 isc_result_t result, eresult;
2803 dns_fetchevent_t *event;
2804 unsigned int options;
2805 isc_task_t *task;
2806 dns_validator_t *validator;
2809 * The appropriate bucket lock must be held.
2812 res = fctx->res;
2813 need_validation = ISC_FALSE;
2814 secure_domain = ISC_FALSE;
2815 have_answer = ISC_FALSE;
2816 eresult = ISC_R_SUCCESS;
2817 task = res->buckets[fctx->bucketnum].task;
2820 * Is DNSSEC validation required for this name?
2822 result = dns_keytable_issecuredomain(res->view->secroots, name,
2823 &secure_domain);
2824 if (result != ISC_R_SUCCESS)
2825 return (result);
2827 if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
2828 need_validation = ISC_FALSE;
2829 else
2830 need_validation = secure_domain;
2832 adbp = NULL;
2833 aname = NULL;
2834 anodep = NULL;
2835 ardataset = NULL;
2836 asigrdataset = NULL;
2837 event = NULL;
2838 if ((name->attributes & DNS_NAMEATTR_ANSWER) != 0 &&
2839 !need_validation) {
2840 have_answer = ISC_TRUE;
2841 event = ISC_LIST_HEAD(fctx->events);
2842 if (event != NULL) {
2843 adbp = &event->db;
2844 aname = dns_fixedname_name(&event->foundname);
2845 result = dns_name_copy(name, aname, NULL);
2846 if (result != ISC_R_SUCCESS)
2847 return (result);
2848 anodep = &event->node;
2850 * If this is an ANY or SIG query, we're not going
2851 * to return any rdatasets, unless we encountered
2852 * a CNAME or DNAME as "the answer". In this case,
2853 * we're going to return DNS_R_CNAME or DNS_R_DNAME
2854 * and we must set up the rdatasets.
2856 if ((fctx->type != dns_rdatatype_any &&
2857 fctx->type != dns_rdatatype_sig) ||
2858 (name->attributes & DNS_NAMEATTR_CHAINING) != 0) {
2859 ardataset = event->rdataset;
2860 asigrdataset = event->sigrdataset;
2866 * Find or create the cache node.
2868 node = NULL;
2869 result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
2870 if (result != ISC_R_SUCCESS)
2871 return (result);
2874 * Cache or validate each cacheable rdataset.
2876 for (rdataset = ISC_LIST_HEAD(name->list);
2877 rdataset != NULL;
2878 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2879 if (!CACHE(rdataset))
2880 continue;
2883 * Enforce the configure maximum cache TTL.
2885 if (rdataset->ttl > res->view->maxcachettl)
2886 rdataset->ttl = res->view->maxcachettl;
2889 * If this rrset is in a secure domain, do DNSSEC validation
2890 * for it, unless it is glue.
2892 if (secure_domain && rdataset->trust != dns_trust_glue) {
2894 * SIGs are validated as part of validating the
2895 * type they cover.
2897 if (rdataset->type == dns_rdatatype_sig)
2898 continue;
2900 * Find the SIG for this rdataset, if we have it.
2902 for (sigrdataset = ISC_LIST_HEAD(name->list);
2903 sigrdataset != NULL;
2904 sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
2905 if (sigrdataset->type == dns_rdatatype_sig &&
2906 sigrdataset->covers == rdataset->type)
2907 break;
2909 if (sigrdataset == NULL) {
2910 if (!ANSWER(rdataset) && need_validation) {
2912 * Ignore non-answer rdatasets that
2913 * are missing signatures.
2915 continue;
2920 * Normalize the rdataset and sigrdataset TTLs.
2922 if (sigrdataset != NULL) {
2923 rdataset->ttl = ISC_MIN(rdataset->ttl,
2924 sigrdataset->ttl);
2925 sigrdataset->ttl = rdataset->ttl;
2929 * Cache this rdataset/sigrdataset pair as
2930 * pending data.
2932 rdataset->trust = dns_trust_pending;
2933 if (sigrdataset != NULL)
2934 sigrdataset->trust = dns_trust_pending;
2935 if (!need_validation)
2936 addedrdataset = ardataset;
2937 else
2938 addedrdataset = NULL;
2939 result = dns_db_addrdataset(fctx->cache, node, NULL,
2940 now, rdataset, 0,
2941 addedrdataset);
2942 if (result == DNS_R_UNCHANGED)
2943 result = ISC_R_SUCCESS;
2944 if (result != ISC_R_SUCCESS)
2945 break;
2946 if (sigrdataset != NULL) {
2947 if (!need_validation)
2948 addedrdataset = asigrdataset;
2949 else
2950 addedrdataset = NULL;
2951 result = dns_db_addrdataset(fctx->cache,
2952 node, NULL, now,
2953 sigrdataset, 0,
2954 addedrdataset);
2955 if (result == DNS_R_UNCHANGED)
2956 result = ISC_R_SUCCESS;
2957 if (result != ISC_R_SUCCESS)
2958 break;
2959 } else if (!ANSWER(rdataset))
2960 continue;
2962 if (ANSWER(rdataset) && need_validation) {
2963 if (fctx->type != dns_rdatatype_any &&
2964 fctx->type != dns_rdatatype_sig) {
2966 * This is The Answer. We will
2967 * validate it, but first we cache
2968 * the rest of the response - it may
2969 * contain useful keys.
2971 INSIST(valrdataset == NULL &&
2972 valsigrdataset == NULL);
2973 valrdataset = rdataset;
2974 valsigrdataset = sigrdataset;
2975 } else {
2977 * This is one of (potentially)
2978 * multiple answers to an ANY
2979 * or SIG query. To keep things
2980 * simple, we just start the
2981 * validator right away rather
2982 * than caching first and
2983 * having to remember which
2984 * rdatasets needed validation.
2986 validator = NULL;
2987 result = dns_validator_create(
2988 res->view,
2989 name,
2990 rdataset->type,
2991 rdataset,
2992 sigrdataset,
2993 fctx->rmessage,
2995 task,
2996 validated,
2997 fctx,
2998 &validator);
2999 if (result == ISC_R_SUCCESS)
3000 ISC_LIST_APPEND(
3001 fctx->validators,
3002 validator, link);
3005 } else if (!EXTERNAL(rdataset)) {
3007 * It's OK to cache this rdataset now.
3009 if (ANSWER(rdataset))
3010 addedrdataset = ardataset;
3011 else if (ANSWERSIG(rdataset))
3012 addedrdataset = asigrdataset;
3013 else
3014 addedrdataset = NULL;
3015 if (CHAINING(rdataset)) {
3016 if (rdataset->type == dns_rdatatype_cname)
3017 eresult = DNS_R_CNAME;
3018 else {
3019 INSIST(rdataset->type ==
3020 dns_rdatatype_dname);
3021 eresult = DNS_R_DNAME;
3024 if (rdataset->trust == dns_trust_glue &&
3025 (rdataset->type == dns_rdatatype_ns ||
3026 (rdataset->type == dns_rdatatype_sig &&
3027 rdataset->covers == dns_rdatatype_ns))) {
3029 * If the trust level is 'dns_trust_glue'
3030 * then we are adding data from a referral
3031 * we got while executing the search algorithm.
3032 * New referral data always takes precedence
3033 * over the existing cache contents.
3035 options = DNS_DBADD_FORCE;
3036 } else
3037 options = 0;
3039 * Now we can add the rdataset.
3041 result = dns_db_addrdataset(fctx->cache,
3042 node, NULL, now,
3043 rdataset,
3044 options,
3045 addedrdataset);
3046 if (result == DNS_R_UNCHANGED) {
3047 if (ANSWER(rdataset) &&
3048 ardataset != NULL &&
3049 ardataset->type == 0) {
3051 * The answer in the cache is better
3052 * than the answer we found, and is
3053 * a negative cache entry, so we
3054 * must set eresult appropriately.
3056 if (NXDOMAIN(ardataset))
3057 eresult =
3058 DNS_R_NCACHENXDOMAIN;
3059 else
3060 eresult =
3061 DNS_R_NCACHENXRRSET;
3063 result = ISC_R_SUCCESS;
3064 } else if (result != ISC_R_SUCCESS)
3065 break;
3069 if (valrdataset != NULL) {
3070 validator = NULL;
3071 result = dns_validator_create(res->view,
3072 name,
3073 fctx->type,
3074 valrdataset,
3075 valsigrdataset,
3076 fctx->rmessage,
3078 task,
3079 validated,
3080 fctx,
3081 &validator);
3082 if (result == ISC_R_SUCCESS)
3083 ISC_LIST_APPEND(fctx->validators, validator, link);
3086 if (result == ISC_R_SUCCESS && have_answer) {
3087 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3088 if (event != NULL) {
3089 event->result = eresult;
3090 dns_db_attach(fctx->cache, adbp);
3091 *anodep = node;
3092 node = NULL;
3093 clone_results(fctx);
3097 if (node != NULL)
3098 dns_db_detachnode(fctx->cache, &node);
3100 return (result);
3103 static inline isc_result_t
3104 cache_message(fetchctx_t *fctx, isc_stdtime_t now) {
3105 isc_result_t result;
3106 dns_section_t section;
3107 dns_name_t *name;
3109 FCTXTRACE("cache_message");
3111 fctx->attributes &= ~FCTX_ATTR_WANTCACHE;
3113 LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3115 for (section = DNS_SECTION_ANSWER;
3116 section <= DNS_SECTION_ADDITIONAL;
3117 section++) {
3118 result = dns_message_firstname(fctx->rmessage, section);
3119 while (result == ISC_R_SUCCESS) {
3120 name = NULL;
3121 dns_message_currentname(fctx->rmessage, section,
3122 &name);
3123 if ((name->attributes & DNS_NAMEATTR_CACHE) != 0) {
3124 result = cache_name(fctx, name, now);
3125 if (result != ISC_R_SUCCESS)
3126 break;
3128 result = dns_message_nextname(fctx->rmessage, section);
3130 if (result != ISC_R_NOMORE)
3131 break;
3133 if (result == ISC_R_NOMORE)
3134 result = ISC_R_SUCCESS;
3136 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3138 return (result);
3142 * Do what dns_ncache_add() does, and then compute an appropriate eresult.
3144 static isc_result_t
3145 ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
3146 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
3147 dns_rdataset_t *ardataset,
3148 isc_result_t *eresultp)
3150 isc_result_t result;
3151 result = dns_ncache_add(message, cache, node, covers, now,
3152 maxttl, ardataset);
3153 if (result == DNS_R_UNCHANGED) {
3155 * The data in the cache is better than the negative cache
3156 * entry we're trying to add.
3158 if (ardataset != NULL && ardataset->type == 0) {
3160 * The cache data is also a negative cache
3161 * entry.
3163 if (NXDOMAIN(ardataset))
3164 *eresultp = DNS_R_NCACHENXDOMAIN;
3165 else
3166 *eresultp = DNS_R_NCACHENXRRSET;
3167 result = ISC_R_SUCCESS;
3168 } else {
3170 * Either we don't care about the nature of the
3171 * cache rdataset (because no fetch is interested
3172 * in the outcome), or the cache rdataset is not
3173 * a negative cache entry. Whichever case it is,
3174 * we can return success.
3176 * XXXRTH There's a CNAME/DNAME problem here.
3178 *eresultp = ISC_R_SUCCESS;
3179 result = ISC_R_SUCCESS;
3181 } else if (result == ISC_R_SUCCESS) {
3182 if (NXDOMAIN(ardataset))
3183 *eresultp = DNS_R_NCACHENXDOMAIN;
3184 else
3185 *eresultp = DNS_R_NCACHENXRRSET;
3188 return (result);
3191 static inline isc_result_t
3192 ncache_message(fetchctx_t *fctx, dns_rdatatype_t covers, isc_stdtime_t now) {
3193 isc_result_t result, eresult;
3194 dns_name_t *name;
3195 dns_resolver_t *res;
3196 dns_db_t **adbp;
3197 dns_dbnode_t *node, **anodep;
3198 dns_rdataset_t *ardataset;
3199 isc_boolean_t need_validation, secure_domain;
3200 dns_name_t *aname;
3201 dns_fetchevent_t *event;
3202 isc_uint32_t ttl;
3204 FCTXTRACE("ncache_message");
3206 fctx->attributes &= ~FCTX_ATTR_WANTNCACHE;
3208 res = fctx->res;
3209 need_validation = ISC_FALSE;
3210 secure_domain = ISC_FALSE;
3211 eresult = ISC_R_SUCCESS;
3212 name = &fctx->name;
3213 node = NULL;
3216 * Is DNSSEC validation required for this name?
3218 result = dns_keytable_issecuredomain(res->view->secroots, name,
3219 &secure_domain);
3220 if (result != ISC_R_SUCCESS)
3221 return (result);
3223 if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
3224 need_validation = ISC_FALSE;
3225 else
3226 need_validation = secure_domain;
3228 if (secure_domain) {
3230 * Mark all rdatasets as pending.
3232 dns_rdataset_t *trdataset;
3233 dns_name_t *tname;
3235 result = dns_message_firstname(fctx->rmessage,
3236 DNS_SECTION_AUTHORITY);
3237 while (result == ISC_R_SUCCESS) {
3238 tname = NULL;
3239 dns_message_currentname(fctx->rmessage,
3240 DNS_SECTION_AUTHORITY,
3241 &tname);
3242 for (trdataset = ISC_LIST_HEAD(tname->list);
3243 trdataset != NULL;
3244 trdataset = ISC_LIST_NEXT(trdataset, link))
3245 trdataset->trust = dns_trust_pending;
3246 result = dns_message_nextname(fctx->rmessage,
3247 DNS_SECTION_AUTHORITY);
3249 if (result != ISC_R_NOMORE)
3250 return (result);
3254 if (need_validation) {
3256 * Do negative response validation.
3258 dns_validator_t *validator = NULL;
3259 isc_task_t *task = res->buckets[fctx->bucketnum].task;
3261 result = dns_validator_create(res->view, name, fctx->type,
3262 NULL, NULL,
3263 fctx->rmessage, 0, task,
3264 validated, fctx,
3265 &validator);
3266 if (result != ISC_R_SUCCESS)
3267 return (result);
3268 ISC_LIST_APPEND(fctx->validators, validator, link);
3270 * If validation is necessary, return now. Otherwise continue
3271 * to process the message, letting the validation complete
3272 * in its own good time.
3274 return (ISC_R_SUCCESS);
3277 LOCK(&res->buckets[fctx->bucketnum].lock);
3279 adbp = NULL;
3280 aname = NULL;
3281 anodep = NULL;
3282 ardataset = NULL;
3283 if (!HAVE_ANSWER(fctx)) {
3284 event = ISC_LIST_HEAD(fctx->events);
3285 if (event != NULL) {
3286 adbp = &event->db;
3287 aname = dns_fixedname_name(&event->foundname);
3288 result = dns_name_copy(name, aname, NULL);
3289 if (result != ISC_R_SUCCESS)
3290 goto unlock;
3291 anodep = &event->node;
3292 ardataset = event->rdataset;
3294 } else
3295 event = NULL;
3297 result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
3298 if (result != ISC_R_SUCCESS)
3299 goto unlock;
3302 * If we are asking for a SOA record set the cache time
3303 * to zero to facilitate locating the containing zone of
3304 * a arbitary zone.
3306 ttl = fctx->res->view->maxncachettl;
3307 if (fctx->type == dns_rdatatype_soa &&
3308 covers == dns_rdatatype_any)
3309 ttl = 0;
3311 result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
3312 covers, now, ttl, ardataset, &eresult);
3313 if (result != ISC_R_SUCCESS)
3314 goto unlock;
3316 if (!HAVE_ANSWER(fctx)) {
3317 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3318 if (event != NULL) {
3319 event->result = eresult;
3320 dns_db_attach(fctx->cache, adbp);
3321 *anodep = node;
3322 node = NULL;
3323 clone_results(fctx);
3327 unlock:
3328 UNLOCK(&res->buckets[fctx->bucketnum].lock);
3330 if (node != NULL)
3331 dns_db_detachnode(fctx->cache, &node);
3333 return (result);
3336 static inline void
3337 mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
3338 isc_boolean_t external, isc_boolean_t gluing)
3340 name->attributes |= DNS_NAMEATTR_CACHE;
3341 if (gluing) {
3342 rdataset->trust = dns_trust_glue;
3344 * Glue with 0 TTL causes problems. We force the TTL to
3345 * 1 second to prevent this.
3347 if (rdataset->ttl == 0)
3348 rdataset->ttl = 1;
3349 } else
3350 rdataset->trust = dns_trust_additional;
3352 * Avoid infinite loops by only marking new rdatasets.
3354 if (!CACHE(rdataset)) {
3355 name->attributes |= DNS_NAMEATTR_CHASE;
3356 rdataset->attributes |= DNS_RDATASETATTR_CHASE;
3358 rdataset->attributes |= DNS_RDATASETATTR_CACHE;
3359 if (external)
3360 rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
3363 static isc_result_t
3364 check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
3365 fetchctx_t *fctx = arg;
3366 isc_result_t result;
3367 dns_name_t *name;
3368 dns_rdataset_t *rdataset;
3369 isc_boolean_t external;
3370 dns_rdatatype_t rtype;
3371 isc_boolean_t gluing;
3373 REQUIRE(VALID_FCTX(fctx));
3375 if (GLUING(fctx))
3376 gluing = ISC_TRUE;
3377 else
3378 gluing = ISC_FALSE;
3379 name = NULL;
3380 result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
3381 addname, dns_rdatatype_any, 0, &name,
3382 NULL);
3383 if (result == ISC_R_SUCCESS) {
3384 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
3385 for (rdataset = ISC_LIST_HEAD(name->list);
3386 rdataset != NULL;
3387 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3388 if (rdataset->type == dns_rdatatype_sig)
3389 rtype = rdataset->covers;
3390 else
3391 rtype = rdataset->type;
3392 if ((type == dns_rdatatype_a &&
3393 (rtype == dns_rdatatype_a ||
3394 rtype == dns_rdatatype_aaaa ||
3395 rtype == dns_rdatatype_a6)) ||
3396 type == rtype)
3397 mark_related(name, rdataset, external,
3398 gluing);
3402 return (ISC_R_SUCCESS);
3405 static void
3406 chase_additional(fetchctx_t *fctx) {
3407 isc_boolean_t rescan;
3408 dns_section_t section = DNS_SECTION_ADDITIONAL;
3409 isc_result_t result;
3411 again:
3412 rescan = ISC_FALSE;
3414 for (result = dns_message_firstname(fctx->rmessage, section);
3415 result == ISC_R_SUCCESS;
3416 result = dns_message_nextname(fctx->rmessage, section)) {
3417 dns_name_t *name = NULL;
3418 dns_rdataset_t *rdataset;
3419 dns_message_currentname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
3420 &name);
3421 if ((name->attributes & DNS_NAMEATTR_CHASE) == 0)
3422 continue;
3423 name->attributes &= ~DNS_NAMEATTR_CHASE;
3424 for (rdataset = ISC_LIST_HEAD(name->list);
3425 rdataset != NULL;
3426 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3427 if (CHASE(rdataset)) {
3428 rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
3429 (void)dns_rdataset_additionaldata(rdataset,
3430 check_related,
3431 fctx);
3432 rescan = ISC_TRUE;
3436 if (rescan)
3437 goto again;
3440 static inline isc_result_t
3441 cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) {
3442 isc_result_t result;
3443 dns_rdata_t rdata = DNS_RDATA_INIT;
3444 dns_rdata_cname_t cname;
3446 result = dns_rdataset_first(rdataset);
3447 if (result != ISC_R_SUCCESS)
3448 return (result);
3449 dns_rdataset_current(rdataset, &rdata);
3450 result = dns_rdata_tostruct(&rdata, &cname, NULL);
3451 if (result != ISC_R_SUCCESS)
3452 return (result);
3453 dns_name_init(tname, NULL);
3454 dns_name_clone(&cname.cname, tname);
3455 dns_rdata_freestruct(&cname);
3457 return (ISC_R_SUCCESS);
3460 static inline isc_result_t
3461 dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
3462 dns_fixedname_t *fixeddname)
3464 isc_result_t result;
3465 dns_rdata_t rdata = DNS_RDATA_INIT;
3466 unsigned int nlabels, nbits;
3467 int order;
3468 dns_namereln_t namereln;
3469 dns_rdata_dname_t dname;
3470 dns_fixedname_t prefix;
3473 * Get the target name of the DNAME.
3476 result = dns_rdataset_first(rdataset);
3477 if (result != ISC_R_SUCCESS)
3478 return (result);
3479 dns_rdataset_current(rdataset, &rdata);
3480 result = dns_rdata_tostruct(&rdata, &dname, NULL);
3481 if (result != ISC_R_SUCCESS)
3482 return (result);
3485 * Get the prefix of qname.
3487 namereln = dns_name_fullcompare(qname, oname, &order, &nlabels,
3488 &nbits);
3489 if (namereln != dns_namereln_subdomain) {
3490 dns_rdata_freestruct(&dname);
3491 return (DNS_R_FORMERR);
3493 dns_fixedname_init(&prefix);
3494 result = dns_name_split(qname, nlabels, nbits,
3495 dns_fixedname_name(&prefix), NULL);
3496 if (result != ISC_R_SUCCESS) {
3497 dns_rdata_freestruct(&dname);
3498 return (result);
3500 dns_fixedname_init(fixeddname);
3501 result = dns_name_concatenate(dns_fixedname_name(&prefix),
3502 &dname.dname,
3503 dns_fixedname_name(fixeddname), NULL);
3504 dns_rdata_freestruct(&dname);
3505 return (result);
3508 static isc_result_t
3509 noanswer_response(fetchctx_t *fctx, dns_name_t *oqname) {
3510 isc_result_t result;
3511 dns_message_t *message;
3512 dns_name_t *name, *qname, *ns_name, *soa_name;
3513 dns_rdataset_t *rdataset, *ns_rdataset;
3514 isc_boolean_t done, aa, negative_response;
3515 dns_rdatatype_t type;
3517 FCTXTRACE("noanswer_response");
3519 message = fctx->rmessage;
3522 * Setup qname.
3524 if (oqname == NULL) {
3526 * We have a normal, non-chained negative response or
3527 * referral.
3529 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
3530 aa = ISC_TRUE;
3531 else
3532 aa = ISC_FALSE;
3533 qname = &fctx->name;
3534 } else {
3536 * We're being invoked by answer_response() after it has
3537 * followed a CNAME/DNAME chain.
3539 qname = oqname;
3540 aa = ISC_FALSE;
3542 * If the current qname is not a subdomain of the query
3543 * domain, there's no point in looking at the authority
3544 * section without doing DNSSEC validation.
3546 * Until we do that validation, we'll just return success
3547 * in this case.
3549 if (!dns_name_issubdomain(qname, &fctx->domain))
3550 return (ISC_R_SUCCESS);
3554 * We have to figure out if this is a negative response, or a
3555 * referral.
3559 * Sometimes we can tell if its a negative response by looking at
3560 * the message header.
3562 negative_response = ISC_FALSE;
3563 if (message->rcode == dns_rcode_nxdomain ||
3564 (message->counts[DNS_SECTION_ANSWER] == 0 &&
3565 message->counts[DNS_SECTION_AUTHORITY] == 0))
3566 negative_response = ISC_TRUE;
3569 * Process the authority section.
3571 done = ISC_FALSE;
3572 ns_name = NULL;
3573 ns_rdataset = NULL;
3574 soa_name = NULL;
3575 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
3576 while (!done && result == ISC_R_SUCCESS) {
3577 name = NULL;
3578 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
3579 if (dns_name_issubdomain(name, &fctx->domain)) {
3580 for (rdataset = ISC_LIST_HEAD(name->list);
3581 rdataset != NULL;
3582 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3583 type = rdataset->type;
3584 if (type == dns_rdatatype_sig)
3585 type = rdataset->covers;
3586 if (type == dns_rdatatype_ns) {
3588 * NS or SIG NS.
3590 * Only one set of NS RRs is allowed.
3592 if (rdataset->type ==
3593 dns_rdatatype_ns) {
3594 if (ns_name != NULL &&
3595 name != ns_name)
3596 return (DNS_R_FORMERR);
3597 ns_name = name;
3599 name->attributes |=
3600 DNS_NAMEATTR_CACHE;
3601 rdataset->attributes |=
3602 DNS_RDATASETATTR_CACHE;
3603 rdataset->trust = dns_trust_glue;
3604 ns_rdataset = rdataset;
3607 for (rdataset = ISC_LIST_HEAD(name->list);
3608 rdataset != NULL;
3609 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3610 type = rdataset->type;
3611 if (type == dns_rdatatype_sig)
3612 type = rdataset->covers;
3613 if (type == dns_rdatatype_soa ||
3614 type == dns_rdatatype_nxt) {
3616 * SOA, SIG SOA, NXT, or SIG NXT.
3618 * Only one SOA is allowed.
3620 if (rdataset->type ==
3621 dns_rdatatype_soa) {
3622 if (soa_name != NULL &&
3623 name != soa_name)
3624 return (DNS_R_FORMERR);
3625 soa_name = name;
3627 if (ns_name == NULL) {
3628 negative_response = ISC_TRUE;
3629 name->attributes |=
3630 DNS_NAMEATTR_NCACHE;
3631 rdataset->attributes |=
3632 DNS_RDATASETATTR_NCACHE;
3633 } else {
3634 name->attributes |=
3635 DNS_NAMEATTR_CACHE;
3636 rdataset->attributes |=
3637 DNS_RDATASETATTR_CACHE;
3639 if (aa)
3640 rdataset->trust =
3641 dns_trust_authauthority;
3642 else
3643 rdataset->trust =
3644 dns_trust_additional;
3646 * No additional data needs to be
3647 * marked.
3652 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
3653 if (result == ISC_R_NOMORE)
3654 break;
3655 else if (result != ISC_R_SUCCESS)
3656 return (result);
3660 * Did we find anything?
3662 if (!negative_response && ns_name == NULL) {
3664 * Nope.
3666 if (oqname != NULL) {
3668 * We've already got a partial CNAME/DNAME chain,
3669 * and haven't found else anything useful here, but
3670 * no error has occurred since we have an answer.
3672 return (ISC_R_SUCCESS);
3673 } else {
3675 * The responder is insane.
3677 return (DNS_R_FORMERR);
3682 * If we found both NS and SOA, they should be the same name.
3684 if (ns_name != NULL && soa_name != NULL && ns_name != soa_name)
3685 return (DNS_R_FORMERR);
3688 * Do we have a referral? (We only want to follow a referral if
3689 * we're not following a chain.)
3691 if (!negative_response && ns_name != NULL && oqname == NULL) {
3693 * We already know ns_name is a subdomain of fctx->domain.
3694 * If ns_name is equal to fctx->domain, we're not making
3695 * progress. We return DNS_R_FORMERR so that we'll keep
3696 * keep trying other servers.
3698 if (dns_name_equal(ns_name, &fctx->domain))
3699 return (DNS_R_FORMERR);
3702 * If the referral name is not a parent of the query
3703 * name, consider the responder insane.
3705 if (! dns_name_issubdomain(&fctx->name, ns_name)) {
3706 FCTXTRACE("referral to non-parent");
3707 return (DNS_R_FORMERR);
3711 * Mark any additional data related to this rdataset.
3712 * It's important that we do this before we change the
3713 * query domain.
3715 INSIST(ns_rdataset != NULL);
3716 fctx->attributes |= FCTX_ATTR_GLUING;
3717 (void)dns_rdataset_additionaldata(ns_rdataset, check_related,
3718 fctx);
3719 fctx->attributes &= ~FCTX_ATTR_GLUING;
3721 * NS rdatasets with 0 TTL cause problems.
3722 * dns_view_findzonecut() will not find them when we
3723 * try to follow the referral, and we'll SERVFAIL
3724 * because the best nameservers are now above QDOMAIN.
3725 * We force the TTL to 1 second to prevent this.
3727 if (ns_rdataset->ttl == 0)
3728 ns_rdataset->ttl = 1;
3730 * Set the current query domain to the referral name.
3732 * XXXRTH We should check if we're in forward-only mode, and
3733 * if so we should bail out.
3735 INSIST(dns_name_countlabels(&fctx->domain) > 0);
3736 dns_name_free(&fctx->domain, fctx->res->mctx);
3737 if (dns_rdataset_isassociated(&fctx->nameservers))
3738 dns_rdataset_disassociate(&fctx->nameservers);
3739 dns_name_init(&fctx->domain, NULL);
3740 result = dns_name_dup(ns_name, fctx->res->mctx, &fctx->domain);
3741 if (result != ISC_R_SUCCESS)
3742 return (result);
3743 fctx->attributes |= FCTX_ATTR_WANTCACHE;
3744 return (DNS_R_DELEGATION);
3748 * Since we're not doing a referral, we don't want to cache any
3749 * NS RRs we may have found.
3751 if (ns_name != NULL)
3752 ns_name->attributes &= ~DNS_NAMEATTR_CACHE;
3754 if (negative_response && oqname == NULL)
3755 fctx->attributes |= FCTX_ATTR_WANTNCACHE;
3757 return (ISC_R_SUCCESS);
3760 static isc_result_t
3761 answer_response(fetchctx_t *fctx) {
3762 isc_result_t result;
3763 dns_message_t *message;
3764 dns_name_t *name, *qname, tname;
3765 dns_rdataset_t *rdataset;
3766 isc_boolean_t done, external, chaining, aa, found, want_chaining;
3767 isc_boolean_t have_answer, found_cname, found_type, wanted_chaining;
3768 unsigned int aflag;
3769 dns_rdatatype_t type;
3770 dns_fixedname_t dname, fqname;
3772 FCTXTRACE("answer_response");
3774 message = fctx->rmessage;
3777 * Examine the answer section, marking those rdatasets which are
3778 * part of the answer and should be cached.
3781 done = ISC_FALSE;
3782 found_cname = ISC_FALSE;
3783 found_type = ISC_FALSE;
3784 chaining = ISC_FALSE;
3785 have_answer = ISC_FALSE;
3786 want_chaining = ISC_FALSE;
3787 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
3788 aa = ISC_TRUE;
3789 else
3790 aa = ISC_FALSE;
3791 qname = &fctx->name;
3792 type = fctx->type;
3793 result = dns_message_firstname(message, DNS_SECTION_ANSWER);
3794 while (!done && result == ISC_R_SUCCESS) {
3795 name = NULL;
3796 dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
3797 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
3798 if (dns_name_equal(name, qname)) {
3799 wanted_chaining = ISC_FALSE;
3800 for (rdataset = ISC_LIST_HEAD(name->list);
3801 rdataset != NULL;
3802 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3803 found = ISC_FALSE;
3804 want_chaining = ISC_FALSE;
3805 aflag = 0;
3806 if (rdataset->type == type && !found_cname) {
3808 * We've found an ordinary answer.
3810 found = ISC_TRUE;
3811 found_type = ISC_TRUE;
3812 done = ISC_TRUE;
3813 aflag = DNS_RDATASETATTR_ANSWER;
3814 } else if (type == dns_rdatatype_any) {
3816 * We've found an answer matching
3817 * an ANY query. There may be
3818 * more.
3820 found = ISC_TRUE;
3821 aflag = DNS_RDATASETATTR_ANSWER;
3822 } else if (rdataset->type == dns_rdatatype_sig
3823 && rdataset->covers == type
3824 && !found_cname) {
3826 * We've found a signature that
3827 * covers the type we're looking for.
3829 found = ISC_TRUE;
3830 found_type = ISC_TRUE;
3831 aflag = DNS_RDATASETATTR_ANSWERSIG;
3832 } else if (rdataset->type ==
3833 dns_rdatatype_cname
3834 && !found_type) {
3836 * We're looking for something else,
3837 * but we found a CNAME.
3839 * Getting a CNAME response for some
3840 * query types is an error.
3842 if (type == dns_rdatatype_sig ||
3843 type == dns_rdatatype_key ||
3844 type == dns_rdatatype_nxt)
3845 return (DNS_R_FORMERR);
3846 found = ISC_TRUE;
3847 found_cname = ISC_TRUE;
3848 want_chaining = ISC_TRUE;
3849 aflag = DNS_RDATASETATTR_ANSWER;
3850 result = cname_target(rdataset,
3851 &tname);
3852 if (result != ISC_R_SUCCESS)
3853 return (result);
3854 } else if (rdataset->type == dns_rdatatype_sig
3855 && rdataset->covers ==
3856 dns_rdatatype_cname
3857 && !found_type) {
3859 * We're looking for something else,
3860 * but we found a SIG CNAME.
3862 found = ISC_TRUE;
3863 found_cname = ISC_TRUE;
3864 aflag = DNS_RDATASETATTR_ANSWERSIG;
3867 if (found) {
3869 * We've found an answer to our
3870 * question.
3872 name->attributes |=
3873 DNS_NAMEATTR_CACHE;
3874 rdataset->attributes |=
3875 DNS_RDATASETATTR_CACHE;
3876 rdataset->trust = dns_trust_answer;
3877 if (!chaining) {
3879 * This data is "the" answer
3880 * to our question only if
3881 * we're not chaining (i.e.
3882 * if we haven't followed
3883 * a CNAME or DNAME).
3885 INSIST(!external);
3886 if (aflag ==
3887 DNS_RDATASETATTR_ANSWER)
3888 have_answer = ISC_TRUE;
3889 name->attributes |=
3890 DNS_NAMEATTR_ANSWER;
3891 rdataset->attributes |= aflag;
3892 if (aa)
3893 rdataset->trust =
3894 dns_trust_authanswer;
3895 } else if (external) {
3897 * This data is outside of
3898 * our query domain, and
3899 * may only be cached if it
3900 * comes from a secure zone
3901 * and validates.
3903 rdataset->attributes |=
3904 DNS_RDATASETATTR_EXTERNAL;
3908 * Mark any additional data related
3909 * to this rdataset.
3911 (void)dns_rdataset_additionaldata(
3912 rdataset,
3913 check_related,
3914 fctx);
3917 * CNAME chaining.
3919 if (want_chaining) {
3920 wanted_chaining = ISC_TRUE;
3921 name->attributes |=
3922 DNS_NAMEATTR_CHAINING;
3923 rdataset->attributes |=
3924 DNS_RDATASETATTR_CHAINING;
3925 qname = &tname;
3929 * We could add an "else" clause here and
3930 * log that we're ignoring this rdataset.
3934 * If wanted_chaining is true, we've done
3935 * some chaining as the result of processing
3936 * this node, and thus we need to set
3937 * chaining to true.
3939 * We don't set chaining inside of the
3940 * rdataset loop because doing that would
3941 * cause us to ignore the signatures of
3942 * CNAMEs.
3944 if (wanted_chaining)
3945 chaining = ISC_TRUE;
3946 } else {
3948 * Look for a DNAME (or its SIG). Anything else is
3949 * ignored.
3951 wanted_chaining = ISC_FALSE;
3952 for (rdataset = ISC_LIST_HEAD(name->list);
3953 rdataset != NULL;
3954 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3955 isc_boolean_t found_dname = ISC_FALSE;
3956 found = ISC_FALSE;
3957 aflag = 0;
3958 if (rdataset->type == dns_rdatatype_dname) {
3960 * We're looking for something else,
3961 * but we found a DNAME.
3963 * If we're not chaining, then the
3964 * DNAME should not be external.
3966 if (!chaining && external)
3967 return (DNS_R_FORMERR);
3968 found = ISC_TRUE;
3969 want_chaining = ISC_TRUE;
3970 aflag = DNS_RDATASETATTR_ANSWER;
3971 result = dname_target(rdataset,
3972 qname, name,
3973 &dname);
3974 if (result == ISC_R_NOSPACE) {
3976 * We can't construct the
3977 * DNAME target. Do not
3978 * try to continue.
3980 want_chaining = ISC_FALSE;
3981 } else if (result != ISC_R_SUCCESS)
3982 return (result);
3983 else
3984 found_dname = ISC_TRUE;
3985 } else if (rdataset->type == dns_rdatatype_sig
3986 && rdataset->covers ==
3987 dns_rdatatype_dname) {
3989 * We've found a signature that
3990 * covers the DNAME.
3992 found = ISC_TRUE;
3993 aflag = DNS_RDATASETATTR_ANSWERSIG;
3996 if (found) {
3998 * We've found an answer to our
3999 * question.
4001 name->attributes |=
4002 DNS_NAMEATTR_CACHE;
4003 rdataset->attributes |=
4004 DNS_RDATASETATTR_CACHE;
4005 rdataset->trust = dns_trust_answer;
4006 if (!chaining) {
4008 * This data is "the" answer
4009 * to our question only if
4010 * we're not chaining.
4012 INSIST(!external);
4013 if (aflag ==
4014 DNS_RDATASETATTR_ANSWER)
4015 have_answer = ISC_TRUE;
4016 name->attributes |=
4017 DNS_NAMEATTR_ANSWER;
4018 rdataset->attributes |= aflag;
4019 if (aa)
4020 rdataset->trust =
4021 dns_trust_authanswer;
4022 } else if (external) {
4023 rdataset->attributes |=
4024 DNS_RDATASETATTR_EXTERNAL;
4028 * DNAME chaining.
4030 if (found_dname) {
4032 * Copy the the dname into the
4033 * qname fixed name.
4035 * Although we check for
4036 * failure of the copy
4037 * operation, in practice it
4038 * should never fail since
4039 * we already know that the
4040 * result fits in a fixedname.
4042 dns_fixedname_init(&fqname);
4043 result = dns_name_copy(
4044 dns_fixedname_name(&dname),
4045 dns_fixedname_name(&fqname),
4046 NULL);
4047 if (result != ISC_R_SUCCESS)
4048 return (result);
4049 wanted_chaining = ISC_TRUE;
4050 name->attributes |=
4051 DNS_NAMEATTR_CHAINING;
4052 rdataset->attributes |=
4053 DNS_RDATASETATTR_CHAINING;
4054 qname = dns_fixedname_name(
4055 &fqname);
4059 if (wanted_chaining)
4060 chaining = ISC_TRUE;
4062 result = dns_message_nextname(message, DNS_SECTION_ANSWER);
4064 if (result == ISC_R_NOMORE)
4065 result = ISC_R_SUCCESS;
4066 if (result != ISC_R_SUCCESS)
4067 return (result);
4070 * We should have found an answer.
4072 if (!have_answer)
4073 return (DNS_R_FORMERR);
4076 * This response is now potentially cacheable.
4078 fctx->attributes |= FCTX_ATTR_WANTCACHE;
4081 * Did chaining end before we got the final answer?
4083 if (chaining) {
4085 * Yes. This may be a negative reply, so hand off
4086 * authority section processing to the noanswer code.
4087 * If it isn't a noanswer response, no harm will be
4088 * done.
4090 return (noanswer_response(fctx, qname));
4094 * We didn't end with an incomplete chain, so the rcode should be
4095 * "no error".
4097 if (message->rcode != dns_rcode_noerror)
4098 return (DNS_R_FORMERR);
4101 * Examine the authority section (if there is one).
4103 * We expect there to be only one owner name for all the rdatasets
4104 * in this section, and we expect that it is not external.
4106 done = ISC_FALSE;
4107 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
4108 while (!done && result == ISC_R_SUCCESS) {
4109 name = NULL;
4110 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
4111 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
4112 if (!external) {
4114 * We expect to find NS or SIG NS rdatasets, and
4115 * nothing else.
4117 for (rdataset = ISC_LIST_HEAD(name->list);
4118 rdataset != NULL;
4119 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4120 if (rdataset->type == dns_rdatatype_ns ||
4121 (rdataset->type == dns_rdatatype_sig &&
4122 rdataset->covers == dns_rdatatype_ns)) {
4123 name->attributes |=
4124 DNS_NAMEATTR_CACHE;
4125 rdataset->attributes |=
4126 DNS_RDATASETATTR_CACHE;
4127 if (aa && !chaining)
4128 rdataset->trust =
4129 dns_trust_authauthority;
4130 else
4131 rdataset->trust =
4132 dns_trust_additional;
4135 * Mark any additional data related
4136 * to this rdataset.
4138 (void)dns_rdataset_additionaldata(
4139 rdataset,
4140 check_related,
4141 fctx);
4145 * Since we've found a non-external name in the
4146 * authority section, we should stop looking, even
4147 * if we didn't find any NS or SIG NS.
4149 done = ISC_TRUE;
4151 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
4153 if (result == ISC_R_NOMORE)
4154 result = ISC_R_SUCCESS;
4156 return (result);
4159 static void
4160 resquery_response(isc_task_t *task, isc_event_t *event) {
4161 isc_result_t result;
4162 resquery_t *query = event->ev_arg;
4163 dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
4164 isc_boolean_t keep_trying, broken_server, get_nameservers, resend;
4165 isc_boolean_t truncated;
4166 dns_message_t *message;
4167 fetchctx_t *fctx;
4168 dns_name_t *fname;
4169 dns_fixedname_t foundname;
4170 isc_stdtime_t now;
4171 isc_time_t tnow, *finish;
4172 dns_adbaddrinfo_t *addrinfo;
4173 unsigned int options;
4175 REQUIRE(VALID_QUERY(query));
4176 fctx = query->fctx;
4177 options = query->options;
4178 REQUIRE(VALID_FCTX(fctx));
4179 REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
4181 UNUSED(task);
4182 QTRACE("response");
4184 (void)isc_timer_touch(fctx->timer);
4186 keep_trying = ISC_FALSE;
4187 broken_server = ISC_FALSE;
4188 get_nameservers = ISC_FALSE;
4189 resend = ISC_FALSE;
4190 truncated = ISC_FALSE;
4191 finish = NULL;
4193 if (fctx->res->exiting) {
4194 result = ISC_R_SHUTTINGDOWN;
4195 goto done;
4198 fctx->timeouts = 0;
4201 * XXXRTH We should really get the current time just once. We
4202 * need a routine to convert from an isc_time_t to an
4203 * isc_stdtime_t.
4205 result = isc_time_now(&tnow);
4206 if (result != ISC_R_SUCCESS)
4207 goto done;
4208 finish = &tnow;
4209 isc_stdtime_get(&now);
4212 * Did the dispatcher have a problem?
4214 if (devent->result != ISC_R_SUCCESS) {
4215 if (devent->result == ISC_R_EOF &&
4216 (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
4218 * The problem might be that they
4219 * don't understand EDNS0. Turn it
4220 * off and try again.
4222 options |= DNS_FETCHOPT_NOEDNS0;
4223 resend = ISC_TRUE;
4225 * Remember that they don't like EDNS0.
4227 dns_adb_changeflags(fctx->adb,
4228 query->addrinfo,
4229 DNS_FETCHOPT_NOEDNS0,
4230 DNS_FETCHOPT_NOEDNS0);
4231 } else {
4233 * There's no hope for this query.
4235 keep_trying = ISC_TRUE;
4237 goto done;
4240 message = fctx->rmessage;
4242 if (query->tsig != NULL) {
4243 result = dns_message_setquerytsig(message, query->tsig);
4244 if (result != ISC_R_SUCCESS)
4245 goto done;
4248 if (query->tsigkey) {
4249 result = dns_message_settsigkey(message, query->tsigkey);
4250 if (result != ISC_R_SUCCESS)
4251 goto done;
4254 result = dns_message_parse(message, &devent->buffer, 0);
4255 if (result != ISC_R_SUCCESS) {
4256 switch (result) {
4257 case ISC_R_UNEXPECTEDEND:
4258 if (!message->question_ok ||
4259 (message->flags & DNS_MESSAGEFLAG_TC) == 0 ||
4260 (options & DNS_FETCHOPT_TCP) != 0) {
4262 * Either the message ended prematurely,
4263 * and/or wasn't marked as being truncated,
4264 * and/or this is a response to a query we
4265 * sent over TCP. In all of these cases,
4266 * something is wrong with the remote
4267 * server and we don't want to retry using
4268 * TCP.
4270 if ((query->options & DNS_FETCHOPT_NOEDNS0)
4271 == 0) {
4273 * The problem might be that they
4274 * don't understand EDNS0. Turn it
4275 * off and try again.
4277 options |= DNS_FETCHOPT_NOEDNS0;
4278 resend = ISC_TRUE;
4280 * Remember that they don't like EDNS0.
4282 dns_adb_changeflags(
4283 fctx->adb,
4284 query->addrinfo,
4285 DNS_FETCHOPT_NOEDNS0,
4286 DNS_FETCHOPT_NOEDNS0);
4287 } else {
4288 broken_server = ISC_TRUE;
4289 keep_trying = ISC_TRUE;
4291 goto done;
4294 * We defer retrying via TCP for a bit so we can
4295 * check out this message further.
4297 truncated = ISC_TRUE;
4298 break;
4299 case DNS_R_FORMERR:
4300 if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
4302 * The problem might be that they
4303 * don't understand EDNS0. Turn it
4304 * off and try again.
4306 options |= DNS_FETCHOPT_NOEDNS0;
4307 resend = ISC_TRUE;
4309 * Remember that they don't like EDNS0.
4311 dns_adb_changeflags(fctx->adb,
4312 query->addrinfo,
4313 DNS_FETCHOPT_NOEDNS0,
4314 DNS_FETCHOPT_NOEDNS0);
4315 } else {
4316 broken_server = ISC_TRUE;
4317 keep_trying = ISC_TRUE;
4319 goto done;
4320 default:
4322 * Something bad has happened.
4324 goto done;
4329 * If the message is signed, check the signature. If not, this
4330 * returns success anyway.
4332 result = dns_message_checksig(message, fctx->res->view);
4333 if (result != ISC_R_SUCCESS)
4334 goto done;
4337 * The dispatcher should ensure we only get responses with QR set.
4339 INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0);
4341 * INSIST() that the message comes from the place we sent it to,
4342 * since the dispatch code should ensure this.
4344 * INSIST() that the message id is correct (this should also be
4345 * ensured by the dispatch code).
4350 * Deal with truncated responses by retrying using TCP.
4352 if ((message->flags & DNS_MESSAGEFLAG_TC) != 0)
4353 truncated = ISC_TRUE;
4355 if (truncated) {
4356 if ((options & DNS_FETCHOPT_TCP) != 0) {
4357 broken_server = ISC_TRUE;
4358 keep_trying = ISC_TRUE;
4359 } else {
4360 options |= DNS_FETCHOPT_TCP;
4361 resend = ISC_TRUE;
4363 goto done;
4367 * Is it a query response?
4369 if (message->opcode != dns_opcode_query) {
4370 /* XXXRTH Log */
4371 broken_server = ISC_TRUE;
4372 keep_trying = ISC_TRUE;
4373 goto done;
4377 * Is the remote server broken, or does it dislike us?
4379 if (message->rcode != dns_rcode_noerror &&
4380 message->rcode != dns_rcode_nxdomain) {
4381 if ((message->rcode == dns_rcode_formerr ||
4382 message->rcode == dns_rcode_notimp ||
4383 message->rcode == dns_rcode_servfail) &&
4384 (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
4386 * It's very likely they don't like EDNS0.
4388 * XXXRTH We should check if the question
4389 * we're asking requires EDNS0, and
4390 * if so, we should bail out.
4392 options |= DNS_FETCHOPT_NOEDNS0;
4393 resend = ISC_TRUE;
4395 * Remember that they don't like EDNS0.
4397 if (message->rcode != dns_rcode_servfail)
4398 dns_adb_changeflags(fctx->adb, query->addrinfo,
4399 DNS_FETCHOPT_NOEDNS0,
4400 DNS_FETCHOPT_NOEDNS0);
4401 } else if (message->rcode == dns_rcode_formerr) {
4402 if (ISFORWARDER(query->addrinfo)) {
4404 * This forwarder doesn't understand us,
4405 * but other forwarders might. Keep trying.
4407 broken_server = ISC_TRUE;
4408 keep_trying = ISC_TRUE;
4409 } else {
4411 * The server doesn't understand us. Since
4412 * all servers for a zone need similar
4413 * capabilities, we assume that we will get
4414 * FORMERR from all servers, and thus we
4415 * cannot make any more progress with this
4416 * fetch.
4418 result = DNS_R_FORMERR;
4420 } else if (message->rcode == dns_rcode_yxdomain) {
4422 * DNAME mapping failed because the new name
4423 * was too long. There's no chance of success
4424 * for this fetch.
4426 result = DNS_R_YXDOMAIN;
4427 } else {
4429 * XXXRTH log.
4431 broken_server = ISC_TRUE;
4432 keep_trying = ISC_TRUE;
4434 goto done;
4438 * Is the question the same as the one we asked?
4440 result = same_question(fctx);
4441 if (result != ISC_R_SUCCESS) {
4442 /* XXXRTH Log */
4443 if (result == DNS_R_FORMERR)
4444 keep_trying = ISC_TRUE;
4445 goto done;
4449 * Is the server lame?
4451 if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) &&
4452 is_lame(fctx)) {
4453 log_lame(fctx, query->addrinfo);
4454 dns_adb_marklame(fctx->adb, query->addrinfo,
4455 &fctx->domain, now + fctx->res->lame_ttl);
4456 broken_server = ISC_TRUE;
4457 keep_trying = ISC_TRUE;
4458 goto done;
4462 * Enforce delegations only zones like NET and COM.
4464 if (!ISFORWARDER(query->addrinfo) &&
4465 dns_view_isdelegationonly(fctx->res->view, &fctx->domain) &&
4466 !dns_name_equal(&fctx->domain, &fctx->name) &&
4467 fix_mustbedelegationornxdomain(message, fctx)) {
4468 char namebuf[DNS_NAME_FORMATSIZE];
4469 char domainbuf[DNS_NAME_FORMATSIZE];
4470 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
4471 char classbuf[64];
4472 char typebuf[64];
4474 dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
4475 dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
4476 dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
4477 dns_rdataclass_format(fctx->res->rdclass, classbuf,
4478 sizeof(classbuf));
4479 isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
4480 sizeof(addrbuf));
4482 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY,
4483 DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
4484 "enforced delegation-only for '%s' (%s/%s/%s) "
4485 "from %s",
4486 domainbuf, namebuf, typebuf, classbuf, addrbuf);
4490 * Did we get any answers?
4492 if (message->counts[DNS_SECTION_ANSWER] > 0 &&
4493 (message->rcode == dns_rcode_noerror ||
4494 message->rcode == dns_rcode_nxdomain)) {
4496 * We've got answers.
4498 result = answer_response(fctx);
4499 if (result != ISC_R_SUCCESS) {
4500 if (result == DNS_R_FORMERR)
4501 keep_trying = ISC_TRUE;
4502 goto done;
4504 } else if (message->counts[DNS_SECTION_AUTHORITY] > 0 ||
4505 message->rcode == dns_rcode_noerror ||
4506 message->rcode == dns_rcode_nxdomain) {
4508 * NXDOMAIN, NXRDATASET, or referral.
4510 result = noanswer_response(fctx, NULL);
4511 if (result == DNS_R_DELEGATION) {
4513 * We don't have the answer, but we know a better
4514 * place to look.
4516 get_nameservers = ISC_TRUE;
4517 keep_trying = ISC_TRUE;
4519 * We have a new set of name servers, and it
4520 * has not experienced any restarts yet.
4522 fctx->restarts = 0;
4523 result = ISC_R_SUCCESS;
4524 } else if (result != ISC_R_SUCCESS) {
4526 * Something has gone wrong.
4528 if (result == DNS_R_FORMERR)
4529 keep_trying = ISC_TRUE;
4530 goto done;
4532 } else {
4534 * The server is insane.
4536 /* XXXRTH Log */
4537 broken_server = ISC_TRUE;
4538 keep_trying = ISC_TRUE;
4539 goto done;
4543 * Follow A6 and other additional section data chains.
4545 chase_additional(fctx);
4548 * Cache the cacheable parts of the message. This may also cause
4549 * work to be queued to the DNSSEC validator.
4551 if (WANTCACHE(fctx)) {
4552 result = cache_message(fctx, now);
4553 if (result != ISC_R_SUCCESS)
4554 goto done;
4558 * Ncache the negatively cacheable parts of the message. This may
4559 * also cause work to be queued to the DNSSEC validator.
4561 if (WANTNCACHE(fctx)) {
4562 dns_rdatatype_t covers;
4563 if (message->rcode == dns_rcode_nxdomain)
4564 covers = dns_rdatatype_any;
4565 else
4566 covers = fctx->type;
4569 * Cache any negative cache entries in the message.
4571 result = ncache_message(fctx, covers, now);
4574 done:
4576 * Remember the query's addrinfo, in case we need to mark the
4577 * server as broken.
4579 addrinfo = query->addrinfo;
4582 * Cancel the query.
4584 * XXXRTH Don't cancel the query if waiting for validation?
4586 fctx_cancelquery(&query, &devent, finish, ISC_FALSE);
4588 if (keep_trying) {
4589 if (result == DNS_R_FORMERR)
4590 broken_server = ISC_TRUE;
4591 if (broken_server) {
4593 * Add this server to the list of bad servers for
4594 * this fctx.
4596 add_bad(fctx, &addrinfo->sockaddr);
4599 if (get_nameservers) {
4600 dns_name_t *name;
4601 dns_fixedname_init(&foundname);
4602 fname = dns_fixedname_name(&foundname);
4603 if (result != ISC_R_SUCCESS) {
4604 fctx_done(fctx, DNS_R_SERVFAIL);
4605 return;
4607 if ((options & DNS_FETCHOPT_UNSHARED) == 0)
4608 name = &fctx->name;
4609 else
4610 name = &fctx->domain;
4611 result = dns_view_findzonecut(fctx->res->view,
4612 name, fname,
4613 now, 0, ISC_TRUE,
4614 &fctx->nameservers,
4615 NULL);
4616 if (result != ISC_R_SUCCESS) {
4617 FCTXTRACE("couldn't find a zonecut");
4618 fctx_done(fctx, DNS_R_SERVFAIL);
4619 return;
4621 if (!dns_name_issubdomain(fname, &fctx->domain)) {
4623 * The best nameservers are now above our
4624 * QDOMAIN.
4626 FCTXTRACE("nameservers now above QDOMAIN");
4627 fctx_done(fctx, DNS_R_SERVFAIL);
4628 return;
4630 dns_name_free(&fctx->domain, fctx->res->mctx);
4631 dns_name_init(&fctx->domain, NULL);
4632 result = dns_name_dup(fname, fctx->res->mctx,
4633 &fctx->domain);
4634 if (result != ISC_R_SUCCESS) {
4635 fctx_done(fctx, DNS_R_SERVFAIL);
4636 return;
4638 fctx_cancelqueries(fctx, ISC_TRUE);
4639 fctx_cleanupfinds(fctx);
4640 fctx_cleanupforwaddrs(fctx);
4643 * Try again.
4645 fctx_try(fctx);
4646 } else if (resend) {
4648 * Resend (probably with changed options).
4650 FCTXTRACE("resend");
4651 result = fctx_query(fctx, addrinfo, options);
4652 if (result != ISC_R_SUCCESS)
4653 fctx_done(fctx, result);
4654 } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) {
4656 * All has gone well so far, but we are waiting for the
4657 * DNSSEC validator to validate the answer.
4659 FCTXTRACE("wait for validator");
4660 fctx_cancelqueries(fctx, ISC_TRUE);
4662 * We must not retransmit while the validator is working;
4663 * it has references to the current rmessage.
4665 result = fctx_stopidletimer(fctx);
4666 if (result != ISC_R_SUCCESS)
4667 fctx_done(fctx, result);
4668 } else {
4670 * We're done.
4672 fctx_done(fctx, result);
4677 /***
4678 *** Resolver Methods
4679 ***/
4681 static void
4682 destroy(dns_resolver_t *res) {
4683 unsigned int i;
4685 REQUIRE(res->references == 0);
4686 REQUIRE(!res->priming);
4687 REQUIRE(res->primefetch == NULL);
4689 RTRACE("destroy");
4691 DESTROYLOCK(&res->primelock);
4692 DESTROYLOCK(&res->lock);
4693 for (i = 0; i < res->nbuckets; i++) {
4694 INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
4695 isc_task_shutdown(res->buckets[i].task);
4696 isc_task_detach(&res->buckets[i].task);
4697 DESTROYLOCK(&res->buckets[i].lock);
4699 isc_mem_put(res->mctx, res->buckets,
4700 res->nbuckets * sizeof (fctxbucket_t));
4701 if (res->dispatchv4 != NULL)
4702 dns_dispatch_detach(&res->dispatchv4);
4703 if (res->dispatchv6 != NULL)
4704 dns_dispatch_detach(&res->dispatchv6);
4705 res->magic = 0;
4706 isc_mem_put(res->mctx, res, sizeof *res);
4709 static void
4710 send_shutdown_events(dns_resolver_t *res) {
4711 isc_event_t *event, *next_event;
4712 isc_task_t *etask;
4715 * Caller must be holding the resolver lock.
4718 for (event = ISC_LIST_HEAD(res->whenshutdown);
4719 event != NULL;
4720 event = next_event) {
4721 next_event = ISC_LIST_NEXT(event, ev_link);
4722 ISC_LIST_UNLINK(res->whenshutdown, event, ev_link);
4723 etask = event->ev_sender;
4724 event->ev_sender = res;
4725 isc_task_sendanddetach(&etask, &event);
4729 static void
4730 empty_bucket(dns_resolver_t *res) {
4731 RTRACE("empty_bucket");
4733 LOCK(&res->lock);
4735 INSIST(res->activebuckets > 0);
4736 res->activebuckets--;
4737 if (res->activebuckets == 0)
4738 send_shutdown_events(res);
4740 UNLOCK(&res->lock);
4743 isc_result_t
4744 dns_resolver_create(dns_view_t *view,
4745 isc_taskmgr_t *taskmgr, unsigned int ntasks,
4746 isc_socketmgr_t *socketmgr,
4747 isc_timermgr_t *timermgr,
4748 unsigned int options,
4749 dns_dispatchmgr_t *dispatchmgr,
4750 dns_dispatch_t *dispatchv4,
4751 dns_dispatch_t *dispatchv6,
4752 dns_resolver_t **resp)
4754 dns_resolver_t *res;
4755 isc_result_t result = ISC_R_SUCCESS;
4756 unsigned int i, buckets_created = 0;
4757 char name[16];
4760 * Create a resolver.
4763 REQUIRE(DNS_VIEW_VALID(view));
4764 REQUIRE(ntasks > 0);
4765 REQUIRE(resp != NULL && *resp == NULL);
4766 REQUIRE(dispatchmgr != NULL);
4767 REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL);
4769 res = isc_mem_get(view->mctx, sizeof *res);
4770 if (res == NULL)
4771 return (ISC_R_NOMEMORY);
4772 RTRACE("create");
4773 res->mctx = view->mctx;
4774 res->rdclass = view->rdclass;
4775 res->socketmgr = socketmgr;
4776 res->timermgr = timermgr;
4777 res->taskmgr = taskmgr;
4778 res->dispatchmgr = dispatchmgr;
4779 res->view = view;
4780 res->options = options;
4781 res->lame_ttl = 0;
4783 res->nbuckets = ntasks;
4784 res->activebuckets = ntasks;
4785 res->buckets = isc_mem_get(view->mctx,
4786 ntasks * sizeof (fctxbucket_t));
4787 if (res->buckets == NULL) {
4788 result = ISC_R_NOMEMORY;
4789 goto cleanup_res;
4791 for (i = 0; i < ntasks; i++) {
4792 result = isc_mutex_init(&res->buckets[i].lock);
4793 if (result != ISC_R_SUCCESS)
4794 goto cleanup_buckets;
4795 res->buckets[i].task = NULL;
4796 result = isc_task_create(taskmgr, 0, &res->buckets[i].task);
4797 if (result != ISC_R_SUCCESS) {
4798 DESTROYLOCK(&res->buckets[i].lock);
4799 goto cleanup_buckets;
4801 sprintf(name, "res%u", i);
4802 isc_task_setname(res->buckets[i].task, name, res);
4803 ISC_LIST_INIT(res->buckets[i].fctxs);
4804 res->buckets[i].exiting = ISC_FALSE;
4805 buckets_created++;
4808 res->dispatchv4 = NULL;
4809 if (dispatchv4 != NULL)
4810 dns_dispatch_attach(dispatchv4, &res->dispatchv4);
4811 res->dispatchv6 = NULL;
4812 if (dispatchv6 != NULL)
4813 dns_dispatch_attach(dispatchv6, &res->dispatchv6);
4815 res->references = 1;
4816 res->exiting = ISC_FALSE;
4817 res->frozen = ISC_FALSE;
4818 ISC_LIST_INIT(res->whenshutdown);
4819 res->priming = ISC_FALSE;
4820 res->primefetch = NULL;
4822 result = isc_mutex_init(&res->lock);
4823 if (result != ISC_R_SUCCESS)
4824 goto cleanup_dispatches;
4826 result = isc_mutex_init(&res->primelock);
4827 if (result != ISC_R_SUCCESS)
4828 goto cleanup_lock;
4830 res->magic = RES_MAGIC;
4832 *resp = res;
4834 return (ISC_R_SUCCESS);
4836 cleanup_lock:
4837 DESTROYLOCK(&res->lock);
4839 cleanup_dispatches:
4840 if (res->dispatchv6 != NULL)
4841 dns_dispatch_detach(&res->dispatchv6);
4842 if (res->dispatchv4 != NULL)
4843 dns_dispatch_detach(&res->dispatchv4);
4845 cleanup_buckets:
4846 for (i = 0; i < buckets_created; i++) {
4847 DESTROYLOCK(&res->buckets[i].lock);
4848 isc_task_shutdown(res->buckets[i].task);
4849 isc_task_detach(&res->buckets[i].task);
4851 isc_mem_put(view->mctx, res->buckets,
4852 res->nbuckets * sizeof (fctxbucket_t));
4854 cleanup_res:
4855 isc_mem_put(view->mctx, res, sizeof *res);
4857 return (result);
4860 static void
4861 prime_done(isc_task_t *task, isc_event_t *event) {
4862 dns_resolver_t *res;
4863 dns_fetchevent_t *fevent;
4864 dns_fetch_t *fetch;
4866 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
4867 fevent = (dns_fetchevent_t *)event;
4868 res = event->ev_arg;
4869 REQUIRE(VALID_RESOLVER(res));
4871 UNUSED(task);
4873 LOCK(&res->lock);
4875 INSIST(res->priming);
4876 res->priming = ISC_FALSE;
4877 LOCK(&res->primelock);
4878 fetch = res->primefetch;
4879 res->primefetch = NULL;
4880 UNLOCK(&res->primelock);
4882 UNLOCK(&res->lock);
4884 if (fevent->node != NULL)
4885 dns_db_detachnode(fevent->db, &fevent->node);
4886 if (fevent->db != NULL)
4887 dns_db_detach(&fevent->db);
4888 if (dns_rdataset_isassociated(fevent->rdataset))
4889 dns_rdataset_disassociate(fevent->rdataset);
4890 INSIST(fevent->sigrdataset == NULL);
4892 isc_mem_put(res->mctx, fevent->rdataset, sizeof *fevent->rdataset);
4894 isc_event_free(&event);
4895 dns_resolver_destroyfetch(&fetch);
4898 void
4899 dns_resolver_prime(dns_resolver_t *res) {
4900 isc_boolean_t want_priming = ISC_FALSE;
4901 dns_rdataset_t *rdataset;
4902 isc_result_t result;
4904 REQUIRE(VALID_RESOLVER(res));
4905 REQUIRE(res->frozen);
4907 RTRACE("dns_resolver_prime");
4909 LOCK(&res->lock);
4911 if (!res->exiting && !res->priming) {
4912 INSIST(res->primefetch == NULL);
4913 res->priming = ISC_TRUE;
4914 want_priming = ISC_TRUE;
4917 UNLOCK(&res->lock);
4919 if (want_priming) {
4921 * To avoid any possible recursive locking problems, we
4922 * start the priming fetch like any other fetch, and holding
4923 * no resolver locks. No one else will try to start it
4924 * because we're the ones who set res->priming to true.
4925 * Any other callers of dns_resolver_prime() while we're
4926 * running will see that res->priming is already true and
4927 * do nothing.
4929 RTRACE("priming");
4930 rdataset = isc_mem_get(res->mctx, sizeof *rdataset);
4931 if (rdataset == NULL) {
4932 LOCK(&res->lock);
4933 INSIST(res->priming);
4934 INSIST(res->primefetch == NULL);
4935 res->priming = ISC_FALSE;
4936 UNLOCK(&res->lock);
4937 return;
4939 dns_rdataset_init(rdataset);
4940 LOCK(&res->primelock);
4941 result = dns_resolver_createfetch(res, dns_rootname,
4942 dns_rdatatype_ns,
4943 NULL, NULL, NULL, 0,
4944 res->buckets[0].task,
4945 prime_done,
4946 res, rdataset, NULL,
4947 &res->primefetch);
4948 UNLOCK(&res->primelock);
4949 if (result != ISC_R_SUCCESS) {
4950 LOCK(&res->lock);
4951 INSIST(res->priming);
4952 res->priming = ISC_FALSE;
4953 UNLOCK(&res->lock);
4958 void
4959 dns_resolver_freeze(dns_resolver_t *res) {
4962 * Freeze resolver.
4965 REQUIRE(VALID_RESOLVER(res));
4966 REQUIRE(!res->frozen);
4968 res->frozen = ISC_TRUE;
4971 void
4972 dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) {
4973 REQUIRE(VALID_RESOLVER(source));
4974 REQUIRE(targetp != NULL && *targetp == NULL);
4976 RRTRACE(source, "attach");
4977 LOCK(&source->lock);
4978 REQUIRE(!source->exiting);
4980 INSIST(source->references > 0);
4981 source->references++;
4982 INSIST(source->references != 0);
4983 UNLOCK(&source->lock);
4985 *targetp = source;
4988 void
4989 dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
4990 isc_event_t **eventp)
4992 isc_task_t *clone;
4993 isc_event_t *event;
4995 REQUIRE(VALID_RESOLVER(res));
4996 REQUIRE(eventp != NULL);
4998 event = *eventp;
4999 *eventp = NULL;
5001 LOCK(&res->lock);
5003 if (res->exiting && res->activebuckets == 0) {
5005 * We're already shutdown. Send the event.
5007 event->ev_sender = res;
5008 isc_task_send(task, &event);
5009 } else {
5010 clone = NULL;
5011 isc_task_attach(task, &clone);
5012 event->ev_sender = clone;
5013 ISC_LIST_APPEND(res->whenshutdown, event, ev_link);
5016 UNLOCK(&res->lock);
5019 void
5020 dns_resolver_shutdown(dns_resolver_t *res) {
5021 unsigned int i;
5022 fetchctx_t *fctx;
5023 isc_socket_t *sock;
5025 REQUIRE(VALID_RESOLVER(res));
5027 RTRACE("shutdown");
5029 LOCK(&res->lock);
5031 if (!res->exiting) {
5032 RTRACE("exiting");
5033 res->exiting = ISC_TRUE;
5035 for (i = 0; i < res->nbuckets; i++) {
5036 LOCK(&res->buckets[i].lock);
5037 for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
5038 fctx != NULL;
5039 fctx = ISC_LIST_NEXT(fctx, link))
5040 fctx_shutdown(fctx);
5041 if (res->dispatchv4 != NULL) {
5042 sock = dns_dispatch_getsocket(res->dispatchv4);
5043 isc_socket_cancel(sock, res->buckets[i].task,
5044 ISC_SOCKCANCEL_ALL);
5046 if (res->dispatchv6 != NULL) {
5047 sock = dns_dispatch_getsocket(res->dispatchv6);
5048 isc_socket_cancel(sock, res->buckets[i].task,
5049 ISC_SOCKCANCEL_ALL);
5051 res->buckets[i].exiting = ISC_TRUE;
5052 if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
5053 INSIST(res->activebuckets > 0);
5054 res->activebuckets--;
5056 UNLOCK(&res->buckets[i].lock);
5058 if (res->activebuckets == 0)
5059 send_shutdown_events(res);
5062 UNLOCK(&res->lock);
5065 void
5066 dns_resolver_detach(dns_resolver_t **resp) {
5067 dns_resolver_t *res;
5068 isc_boolean_t need_destroy = ISC_FALSE;
5070 REQUIRE(resp != NULL);
5071 res = *resp;
5072 REQUIRE(VALID_RESOLVER(res));
5074 RTRACE("detach");
5076 LOCK(&res->lock);
5078 INSIST(res->references > 0);
5079 res->references--;
5080 if (res->references == 0) {
5081 INSIST(res->exiting && res->activebuckets == 0);
5082 need_destroy = ISC_TRUE;
5085 UNLOCK(&res->lock);
5087 if (need_destroy)
5088 destroy(res);
5090 *resp = NULL;
5093 static inline isc_boolean_t
5094 fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
5095 unsigned int options)
5097 if (fctx->type != type || fctx->options != options)
5098 return (ISC_FALSE);
5099 return (dns_name_equal(&fctx->name, name));
5102 static inline void
5103 log_fetch(dns_name_t *name, dns_rdatatype_t type) {
5104 char namebuf[DNS_NAME_FORMATSIZE];
5105 char typebuf[DNS_RDATATYPE_FORMATSIZE];
5106 int level = ISC_LOG_DEBUG(1);
5108 if (! isc_log_wouldlog(dns_lctx, level))
5109 return;
5111 dns_name_format(name, namebuf, sizeof(namebuf));
5112 dns_rdatatype_format(type, typebuf, sizeof(typebuf));
5114 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
5115 DNS_LOGMODULE_RESOLVER, level,
5116 "createfetch: %s %s", namebuf, typebuf);
5119 isc_result_t
5120 dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
5121 dns_rdatatype_t type,
5122 dns_name_t *domain, dns_rdataset_t *nameservers,
5123 dns_forwarders_t *forwarders,
5124 unsigned int options, isc_task_t *task,
5125 isc_taskaction_t action, void *arg,
5126 dns_rdataset_t *rdataset,
5127 dns_rdataset_t *sigrdataset,
5128 dns_fetch_t **fetchp)
5130 dns_fetch_t *fetch;
5131 fetchctx_t *fctx = NULL;
5132 isc_result_t result;
5133 unsigned int bucketnum;
5134 isc_boolean_t new_fctx = ISC_FALSE;
5135 isc_event_t *event;
5137 UNUSED(forwarders);
5139 REQUIRE(VALID_RESOLVER(res));
5140 REQUIRE(res->frozen);
5141 /* XXXRTH Check for meta type */
5142 if (domain != NULL) {
5143 REQUIRE(DNS_RDATASET_VALID(nameservers));
5144 REQUIRE(nameservers->type == dns_rdatatype_ns);
5145 } else
5146 REQUIRE(nameservers == NULL);
5147 REQUIRE(forwarders == NULL);
5148 REQUIRE(!dns_rdataset_isassociated(rdataset));
5149 REQUIRE(sigrdataset == NULL ||
5150 !dns_rdataset_isassociated(sigrdataset));
5151 REQUIRE(fetchp != NULL && *fetchp == NULL);
5153 log_fetch(name, type);
5156 * XXXRTH use a mempool?
5158 fetch = isc_mem_get(res->mctx, sizeof *fetch);
5159 if (fetch == NULL)
5160 return (ISC_R_NOMEMORY);
5162 bucketnum = dns_name_hash(name, ISC_FALSE) % res->nbuckets;
5164 LOCK(&res->buckets[bucketnum].lock);
5166 if (res->buckets[bucketnum].exiting) {
5167 result = ISC_R_SHUTTINGDOWN;
5168 goto unlock;
5171 if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
5172 for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
5173 fctx != NULL;
5174 fctx = ISC_LIST_NEXT(fctx, link)) {
5175 if (fctx_match(fctx, name, type, options))
5176 break;
5181 * If we didn't have a fetch, would attach to a done fetch, this
5182 * fetch has already cloned its results, or if the fetch has gone
5183 * "idle" (no one was interested in it), we need to start a new
5184 * fetch instead of joining with the existing one.
5186 if (fctx == NULL ||
5187 fctx->state == fetchstate_done ||
5188 fctx->cloned ||
5189 ISC_LIST_EMPTY(fctx->events)) {
5190 fctx = NULL;
5191 result = fctx_create(res, name, type, domain, nameservers,
5192 options, bucketnum, &fctx);
5193 if (result != ISC_R_SUCCESS)
5194 goto unlock;
5195 new_fctx = ISC_TRUE;
5198 result = fctx_join(fctx, task, action, arg,
5199 rdataset, sigrdataset, fetch);
5200 if (new_fctx) {
5201 if (result == ISC_R_SUCCESS) {
5203 * Launch this fctx.
5205 event = &fctx->control_event;
5206 ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
5207 DNS_EVENT_FETCHCONTROL,
5208 fctx_start, fctx, NULL,
5209 NULL, NULL);
5210 isc_task_send(res->buckets[bucketnum].task, &event);
5211 } else {
5213 * We don't care about the result of fctx_destroy()
5214 * since we know we're not exiting.
5216 (void)fctx_destroy(fctx);
5220 unlock:
5221 UNLOCK(&res->buckets[bucketnum].lock);
5223 if (result == ISC_R_SUCCESS) {
5224 FTRACE("created");
5225 *fetchp = fetch;
5226 } else
5227 isc_mem_put(res->mctx, fetch, sizeof *fetch);
5229 return (result);
5232 void
5233 dns_resolver_cancelfetch(dns_fetch_t *fetch) {
5234 fetchctx_t *fctx;
5235 dns_resolver_t *res;
5236 dns_fetchevent_t *event, *next_event;
5237 isc_task_t *etask;
5239 REQUIRE(DNS_FETCH_VALID(fetch));
5240 fctx = fetch->private;
5241 REQUIRE(VALID_FCTX(fctx));
5242 res = fctx->res;
5244 FTRACE("cancelfetch");
5246 LOCK(&res->buckets[fctx->bucketnum].lock);
5249 * Find the completion event for this fetch (as opposed
5250 * to those for other fetches that have joined the same
5251 * fctx) and send it with result = ISC_R_CANCELED.
5253 event = NULL;
5254 if (fctx->state != fetchstate_done) {
5255 for (event = ISC_LIST_HEAD(fctx->events);
5256 event != NULL;
5257 event = next_event) {
5258 next_event = ISC_LIST_NEXT(event, ev_link);
5259 if (event->fetch == fetch) {
5260 ISC_LIST_UNLINK(fctx->events, event, ev_link);
5261 break;
5265 if (event != NULL) {
5266 etask = event->ev_sender;
5267 event->ev_sender = fctx;
5268 event->result = ISC_R_CANCELED;
5269 isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event));
5272 * The fctx continues running even if no fetches remain;
5273 * the answer is still cached.
5276 UNLOCK(&res->buckets[fctx->bucketnum].lock);
5279 void
5280 dns_resolver_destroyfetch(dns_fetch_t **fetchp) {
5281 dns_fetch_t *fetch;
5282 dns_resolver_t *res;
5283 dns_fetchevent_t *event, *next_event;
5284 fetchctx_t *fctx;
5285 unsigned int bucketnum;
5286 isc_boolean_t bucket_empty = ISC_FALSE;
5288 REQUIRE(fetchp != NULL);
5289 fetch = *fetchp;
5290 REQUIRE(DNS_FETCH_VALID(fetch));
5291 fctx = fetch->private;
5292 REQUIRE(VALID_FCTX(fctx));
5293 res = fctx->res;
5295 FTRACE("destroyfetch");
5297 bucketnum = fctx->bucketnum;
5298 LOCK(&res->buckets[bucketnum].lock);
5301 * Sanity check: the caller should have gotten its event before
5302 * trying to destroy the fetch.
5304 event = NULL;
5305 if (fctx->state != fetchstate_done) {
5306 for (event = ISC_LIST_HEAD(fctx->events);
5307 event != NULL;
5308 event = next_event) {
5309 next_event = ISC_LIST_NEXT(event, ev_link);
5310 RUNTIME_CHECK(event->fetch != fetch);
5314 INSIST(fctx->references > 0);
5315 fctx->references--;
5316 if (fctx->references == 0) {
5318 * No one cares about the result of this fetch anymore.
5320 if (fctx->pending == 0 && ISC_LIST_EMPTY(fctx->validators) &&
5321 SHUTTINGDOWN(fctx)) {
5323 * This fctx is already shutdown; we were just
5324 * waiting for the last reference to go away.
5326 bucket_empty = fctx_destroy(fctx);
5327 } else {
5329 * Initiate shutdown.
5331 fctx_shutdown(fctx);
5335 UNLOCK(&res->buckets[bucketnum].lock);
5337 isc_mem_put(res->mctx, fetch, sizeof *fetch);
5338 *fetchp = NULL;
5340 if (bucket_empty)
5341 empty_bucket(res);
5344 dns_dispatchmgr_t *
5345 dns_resolver_dispatchmgr(dns_resolver_t *resolver) {
5346 REQUIRE(VALID_RESOLVER(resolver));
5347 return (resolver->dispatchmgr);
5350 dns_dispatch_t *
5351 dns_resolver_dispatchv4(dns_resolver_t *resolver) {
5352 REQUIRE(VALID_RESOLVER(resolver));
5353 return (resolver->dispatchv4);
5356 dns_dispatch_t *
5357 dns_resolver_dispatchv6(dns_resolver_t *resolver) {
5358 REQUIRE(VALID_RESOLVER(resolver));
5359 return (resolver->dispatchv6);
5362 isc_socketmgr_t *
5363 dns_resolver_socketmgr(dns_resolver_t *resolver) {
5364 REQUIRE(VALID_RESOLVER(resolver));
5365 return (resolver->socketmgr);
5368 isc_taskmgr_t *
5369 dns_resolver_taskmgr(dns_resolver_t *resolver) {
5370 REQUIRE(VALID_RESOLVER(resolver));
5371 return (resolver->taskmgr);
5374 isc_uint32_t
5375 dns_resolver_getlamettl(dns_resolver_t *resolver) {
5376 REQUIRE(VALID_RESOLVER(resolver));
5377 return (resolver->lame_ttl);
5380 void
5381 dns_resolver_setlamettl(dns_resolver_t *resolver, isc_uint32_t lame_ttl) {
5382 REQUIRE(VALID_RESOLVER(resolver));
5383 resolver->lame_ttl = lame_ttl;