Import bind-9.3.4
[dragonfly.git] / contrib / bind-9.3 / lib / dns / resolver.c
bloba56fecfd3ce1ca9926995c49aeedddda488e0fad
1 /*
2 * Copyright (C) 2004-2006 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.18.4.64.4.2 2007/01/11 05:05:10 marka Exp $ */
20 #include <config.h>
22 #include <isc/print.h>
23 #include <isc/string.h>
24 #include <isc/task.h>
25 #include <isc/timer.h>
26 #include <isc/util.h>
28 #include <dns/acl.h>
29 #include <dns/adb.h>
30 #include <dns/cache.h>
31 #include <dns/db.h>
32 #include <dns/dispatch.h>
33 #include <dns/ds.h>
34 #include <dns/events.h>
35 #include <dns/forward.h>
36 #include <dns/keytable.h>
37 #include <dns/log.h>
38 #include <dns/message.h>
39 #include <dns/ncache.h>
40 #include <dns/opcode.h>
41 #include <dns/peer.h>
42 #include <dns/rbt.h>
43 #include <dns/rcode.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataclass.h>
46 #include <dns/rdatalist.h>
47 #include <dns/rdataset.h>
48 #include <dns/rdatastruct.h>
49 #include <dns/rdatatype.h>
50 #include <dns/resolver.h>
51 #include <dns/result.h>
52 #include <dns/rootns.h>
53 #include <dns/tsig.h>
54 #include <dns/validator.h>
56 #define DNS_RESOLVER_TRACE
57 #ifdef DNS_RESOLVER_TRACE
58 #define RTRACE(m) isc_log_write(dns_lctx, \
59 DNS_LOGCATEGORY_RESOLVER, \
60 DNS_LOGMODULE_RESOLVER, \
61 ISC_LOG_DEBUG(3), \
62 "res %p: %s", res, (m))
63 #define RRTRACE(r, m) isc_log_write(dns_lctx, \
64 DNS_LOGCATEGORY_RESOLVER, \
65 DNS_LOGMODULE_RESOLVER, \
66 ISC_LOG_DEBUG(3), \
67 "res %p: %s", (r), (m))
68 #define FCTXTRACE(m) isc_log_write(dns_lctx, \
69 DNS_LOGCATEGORY_RESOLVER, \
70 DNS_LOGMODULE_RESOLVER, \
71 ISC_LOG_DEBUG(3), \
72 "fctx %p(%s'): %s", fctx, fctx->info, (m))
73 #define FCTXTRACE2(m1, m2) \
74 isc_log_write(dns_lctx, \
75 DNS_LOGCATEGORY_RESOLVER, \
76 DNS_LOGMODULE_RESOLVER, \
77 ISC_LOG_DEBUG(3), \
78 "fctx %p(%s): %s %s", \
79 fctx, fctx->info, (m1), (m2))
80 #define FTRACE(m) isc_log_write(dns_lctx, \
81 DNS_LOGCATEGORY_RESOLVER, \
82 DNS_LOGMODULE_RESOLVER, \
83 ISC_LOG_DEBUG(3), \
84 "fetch %p (fctx %p(%s)): %s", \
85 fetch, fetch->private, \
86 fetch->private->info, (m))
87 #define QTRACE(m) isc_log_write(dns_lctx, \
88 DNS_LOGCATEGORY_RESOLVER, \
89 DNS_LOGMODULE_RESOLVER, \
90 ISC_LOG_DEBUG(3), \
91 "resquery %p (fctx %p(%s)): %s", \
92 query, query->fctx, \
93 query->fctx->info, (m))
94 #else
95 #define RTRACE(m)
96 #define RRTRACE(r, m)
97 #define FCTXTRACE(m)
98 #define FTRACE(m)
99 #define QTRACE(m)
100 #endif
103 * Maximum EDNS0 input packet size.
105 #define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */
108 * This defines the maximum number of timeouts we will permit before we
109 * disable EDNS0 on the query.
111 #define MAX_EDNS0_TIMEOUTS 3
113 typedef struct fetchctx fetchctx_t;
115 typedef struct query {
116 /* Locked by task event serialization. */
117 unsigned int magic;
118 fetchctx_t * fctx;
119 isc_mem_t * mctx;
120 dns_dispatchmgr_t * dispatchmgr;
121 dns_dispatch_t * dispatch;
122 dns_adbaddrinfo_t * addrinfo;
123 isc_socket_t * tcpsocket;
124 isc_time_t start;
125 dns_messageid_t id;
126 dns_dispentry_t * dispentry;
127 ISC_LINK(struct query) link;
128 isc_buffer_t buffer;
129 isc_buffer_t *tsig;
130 dns_tsigkey_t *tsigkey;
131 unsigned int options;
132 unsigned int attributes;
133 unsigned int sends;
134 unsigned int connects;
135 unsigned char data[512];
136 } resquery_t;
138 #define QUERY_MAGIC ISC_MAGIC('Q', '!', '!', '!')
139 #define VALID_QUERY(query) ISC_MAGIC_VALID(query, QUERY_MAGIC)
141 #define RESQUERY_ATTR_CANCELED 0x02
143 #define RESQUERY_CONNECTING(q) ((q)->connects > 0)
144 #define RESQUERY_CANCELED(q) (((q)->attributes & \
145 RESQUERY_ATTR_CANCELED) != 0)
146 #define RESQUERY_SENDING(q) ((q)->sends > 0)
148 typedef enum {
149 fetchstate_init = 0, /* Start event has not run yet. */
150 fetchstate_active,
151 fetchstate_done /* FETCHDONE events posted. */
152 } fetchstate;
154 struct fetchctx {
155 /* Not locked. */
156 unsigned int magic;
157 dns_resolver_t * res;
158 dns_name_t name;
159 dns_rdatatype_t type;
160 unsigned int options;
161 unsigned int bucketnum;
162 char * info;
163 /* Locked by appropriate bucket lock. */
164 fetchstate state;
165 isc_boolean_t want_shutdown;
166 isc_boolean_t cloned;
167 unsigned int references;
168 isc_event_t control_event;
169 ISC_LINK(struct fetchctx) link;
170 ISC_LIST(dns_fetchevent_t) events;
171 /* Locked by task event serialization. */
172 dns_name_t domain;
173 dns_rdataset_t nameservers;
174 unsigned int attributes;
175 isc_timer_t * timer;
176 isc_time_t expires;
177 isc_interval_t interval;
178 dns_message_t * qmessage;
179 dns_message_t * rmessage;
180 ISC_LIST(resquery_t) queries;
181 dns_adbfindlist_t finds;
182 dns_adbfind_t * find;
183 dns_adbfindlist_t altfinds;
184 dns_adbfind_t * altfind;
185 dns_adbaddrinfolist_t forwaddrs;
186 dns_adbaddrinfolist_t altaddrs;
187 isc_sockaddrlist_t forwarders;
188 dns_fwdpolicy_t fwdpolicy;
189 isc_sockaddrlist_t bad;
190 ISC_LIST(dns_validator_t) validators;
191 dns_db_t * cache;
192 dns_adb_t * adb;
195 * The number of events we're waiting for.
197 unsigned int pending;
200 * The number of times we've "restarted" the current
201 * nameserver set. This acts as a failsafe to prevent
202 * us from pounding constantly on a particular set of
203 * servers that, for whatever reason, are not giving
204 * us useful responses, but are responding in such a
205 * way that they are not marked "bad".
207 unsigned int restarts;
210 * The number of timeouts that have occurred since we
211 * last successfully received a response packet. This
212 * is used for EDNS0 black hole detection.
214 unsigned int timeouts;
216 * Look aside state for DS lookups.
218 dns_name_t nsname;
219 dns_fetch_t * nsfetch;
220 dns_rdataset_t nsrrset;
223 * Number of queries that reference this context.
225 unsigned int nqueries;
228 #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
229 #define VALID_FCTX(fctx) ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
231 #define FCTX_ATTR_HAVEANSWER 0x0001
232 #define FCTX_ATTR_GLUING 0x0002
233 #define FCTX_ATTR_ADDRWAIT 0x0004
234 #define FCTX_ATTR_SHUTTINGDOWN 0x0008
235 #define FCTX_ATTR_WANTCACHE 0x0010
236 #define FCTX_ATTR_WANTNCACHE 0x0020
237 #define FCTX_ATTR_NEEDEDNS0 0x0040
238 #define FCTX_ATTR_TRIEDFIND 0x0080
239 #define FCTX_ATTR_TRIEDALT 0x0100
241 #define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
243 #define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \
245 #define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
247 #define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
248 != 0)
249 #define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
250 #define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
251 #define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
252 #define TRIEDFIND(f) (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
253 #define TRIEDALT(f) (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
255 typedef struct {
256 dns_adbaddrinfo_t * addrinfo;
257 fetchctx_t * fctx;
258 } dns_valarg_t;
260 struct dns_fetch {
261 unsigned int magic;
262 fetchctx_t * private;
265 #define DNS_FETCH_MAGIC ISC_MAGIC('F', 't', 'c', 'h')
266 #define DNS_FETCH_VALID(fetch) ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
268 typedef struct fctxbucket {
269 isc_task_t * task;
270 isc_mutex_t lock;
271 ISC_LIST(fetchctx_t) fctxs;
272 isc_boolean_t exiting;
273 } fctxbucket_t;
275 typedef struct alternate {
276 isc_boolean_t isaddress;
277 union {
278 isc_sockaddr_t addr;
279 struct {
280 dns_name_t name;
281 in_port_t port;
282 } _n;
283 } _u;
284 ISC_LINK(struct alternate) link;
285 } alternate_t;
287 struct dns_resolver {
288 /* Unlocked. */
289 unsigned int magic;
290 isc_mem_t * mctx;
291 isc_mutex_t lock;
292 isc_mutex_t nlock;
293 isc_mutex_t primelock;
294 dns_rdataclass_t rdclass;
295 isc_socketmgr_t * socketmgr;
296 isc_timermgr_t * timermgr;
297 isc_taskmgr_t * taskmgr;
298 dns_view_t * view;
299 isc_boolean_t frozen;
300 unsigned int options;
301 dns_dispatchmgr_t * dispatchmgr;
302 dns_dispatch_t * dispatchv4;
303 dns_dispatch_t * dispatchv6;
304 unsigned int nbuckets;
305 fctxbucket_t * buckets;
306 isc_uint32_t lame_ttl;
307 ISC_LIST(alternate_t) alternates;
308 isc_uint16_t udpsize;
309 #if USE_ALGLOCK
310 isc_rwlock_t alglock;
311 #endif
312 dns_rbt_t * algorithms;
313 #if USE_MBSLOCK
314 isc_rwlock_t mbslock;
315 #endif
316 dns_rbt_t * mustbesecure;
317 /* Locked by lock. */
318 unsigned int references;
319 isc_boolean_t exiting;
320 isc_eventlist_t whenshutdown;
321 unsigned int activebuckets;
322 isc_boolean_t priming;
323 /* Locked by primelock. */
324 dns_fetch_t * primefetch;
325 /* Locked by nlock. */
326 unsigned int nfctx;
329 #define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!')
330 #define VALID_RESOLVER(res) ISC_MAGIC_VALID(res, RES_MAGIC)
333 * Private addrinfo flags. These must not conflict with DNS_FETCHOPT_NOEDNS0,
334 * which we also use as an addrinfo flag.
336 #define FCTX_ADDRINFO_MARK 0x0001
337 #define FCTX_ADDRINFO_FORWARDER 0x1000
338 #define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \
339 == 0)
340 #define ISFORWARDER(a) (((a)->flags & \
341 FCTX_ADDRINFO_FORWARDER) != 0)
343 #define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
345 static void destroy(dns_resolver_t *res);
346 static void empty_bucket(dns_resolver_t *res);
347 static isc_result_t resquery_send(resquery_t *query);
348 static void resquery_response(isc_task_t *task, isc_event_t *event);
349 static void resquery_connected(isc_task_t *task, isc_event_t *event);
350 static void fctx_try(fetchctx_t *fctx);
351 static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
352 static isc_result_t ncache_adderesult(dns_message_t *message,
353 dns_db_t *cache, dns_dbnode_t *node,
354 dns_rdatatype_t covers,
355 isc_stdtime_t now, dns_ttl_t maxttl,
356 dns_rdataset_t *ardataset,
357 isc_result_t *eresultp);
358 static void validated(isc_task_t *task, isc_event_t *event);
359 static void maybe_destroy(fetchctx_t *fctx);
361 static isc_result_t
362 valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
363 dns_rdatatype_t type, dns_rdataset_t *rdataset,
364 dns_rdataset_t *sigrdataset, unsigned int valoptions,
365 isc_task_t *task)
367 dns_validator_t *validator = NULL;
368 dns_valarg_t *valarg;
369 isc_result_t result;
371 valarg = isc_mem_get(fctx->res->mctx, sizeof(*valarg));
372 if (valarg == NULL)
373 return (ISC_R_NOMEMORY);
375 valarg->fctx = fctx;
376 valarg->addrinfo = addrinfo;
378 if (!ISC_LIST_EMPTY(fctx->validators))
379 INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0);
381 result = dns_validator_create(fctx->res->view, name, type, rdataset,
382 sigrdataset, fctx->rmessage,
383 valoptions, task, validated, valarg,
384 &validator);
385 if (result == ISC_R_SUCCESS)
386 ISC_LIST_APPEND(fctx->validators, validator, link);
387 else
388 isc_mem_put(fctx->res->mctx, valarg, sizeof(*valarg));
389 return (result);
392 static isc_boolean_t
393 fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
394 dns_name_t *name;
395 dns_name_t *domain = &fctx->domain;
396 dns_rdataset_t *rdataset;
397 dns_rdatatype_t type;
398 isc_result_t result;
399 isc_boolean_t keep_auth = ISC_FALSE;
401 if (message->rcode == dns_rcode_nxdomain)
402 return (ISC_FALSE);
405 * Look for BIND 8 style delegations.
406 * Also look for answers to ANY queries where the duplicate NS RRset
407 * may have been stripped from the authority section.
409 if (message->counts[DNS_SECTION_ANSWER] != 0 &&
410 (fctx->type == dns_rdatatype_ns ||
411 fctx->type == dns_rdatatype_any)) {
412 result = dns_message_firstname(message, DNS_SECTION_ANSWER);
413 while (result == ISC_R_SUCCESS) {
414 name = NULL;
415 dns_message_currentname(message, DNS_SECTION_ANSWER,
416 &name);
417 for (rdataset = ISC_LIST_HEAD(name->list);
418 rdataset != NULL;
419 rdataset = ISC_LIST_NEXT(rdataset, link)) {
420 type = rdataset->type;
421 if (type != dns_rdatatype_ns)
422 continue;
423 if (dns_name_issubdomain(name, domain))
424 return (ISC_FALSE);
426 result = dns_message_nextname(message,
427 DNS_SECTION_ANSWER);
431 /* Look for referral. */
432 if (message->counts[DNS_SECTION_AUTHORITY] == 0)
433 goto munge;
435 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
436 while (result == ISC_R_SUCCESS) {
437 name = NULL;
438 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
439 for (rdataset = ISC_LIST_HEAD(name->list);
440 rdataset != NULL;
441 rdataset = ISC_LIST_NEXT(rdataset, link)) {
442 type = rdataset->type;
443 if (type == dns_rdatatype_soa &&
444 dns_name_equal(name, domain))
445 keep_auth = ISC_TRUE;
446 if (type != dns_rdatatype_ns &&
447 type != dns_rdatatype_soa)
448 continue;
449 if (dns_name_equal(name, domain))
450 goto munge;
451 if (dns_name_issubdomain(name, domain))
452 return (ISC_FALSE);
454 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
457 munge:
458 message->rcode = dns_rcode_nxdomain;
459 message->counts[DNS_SECTION_ANSWER] = 0;
460 if (!keep_auth)
461 message->counts[DNS_SECTION_AUTHORITY] = 0;
462 message->counts[DNS_SECTION_ADDITIONAL] = 0;
463 return (ISC_TRUE);
466 static inline isc_result_t
467 fctx_starttimer(fetchctx_t *fctx) {
469 * Start the lifetime timer for fctx.
471 * This is also used for stopping the idle timer; in that
472 * case we must purge events already posted to ensure that
473 * no further idle events are delivered.
475 return (isc_timer_reset(fctx->timer, isc_timertype_once,
476 &fctx->expires, NULL, ISC_TRUE));
479 static inline void
480 fctx_stoptimer(fetchctx_t *fctx) {
481 isc_result_t result;
484 * We don't return a result if resetting the timer to inactive fails
485 * since there's nothing to be done about it. Resetting to inactive
486 * should never fail anyway, since the code as currently written
487 * cannot fail in that case.
489 result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
490 NULL, NULL, ISC_TRUE);
491 if (result != ISC_R_SUCCESS) {
492 UNEXPECTED_ERROR(__FILE__, __LINE__,
493 "isc_timer_reset(): %s",
494 isc_result_totext(result));
499 static inline isc_result_t
500 fctx_startidletimer(fetchctx_t *fctx) {
502 * Start the idle timer for fctx. The lifetime timer continues
503 * to be in effect.
505 return (isc_timer_reset(fctx->timer, isc_timertype_once,
506 &fctx->expires, &fctx->interval,
507 ISC_FALSE));
511 * Stopping the idle timer is equivalent to calling fctx_starttimer(), but
512 * we use fctx_stopidletimer for readability in the code below.
514 #define fctx_stopidletimer fctx_starttimer
517 static inline void
518 resquery_destroy(resquery_t **queryp) {
519 resquery_t *query;
521 REQUIRE(queryp != NULL);
522 query = *queryp;
523 REQUIRE(!ISC_LINK_LINKED(query, link));
525 INSIST(query->tcpsocket == NULL);
527 query->fctx->nqueries--;
528 if (SHUTTINGDOWN(query->fctx))
529 maybe_destroy(query->fctx); /* Locks bucket. */
530 query->magic = 0;
531 isc_mem_put(query->mctx, query, sizeof(*query));
532 *queryp = NULL;
535 static void
536 fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
537 isc_time_t *finish, isc_boolean_t no_response)
539 fetchctx_t *fctx;
540 resquery_t *query;
541 unsigned int rtt;
542 unsigned int factor;
543 dns_adbfind_t *find;
544 dns_adbaddrinfo_t *addrinfo;
546 query = *queryp;
547 fctx = query->fctx;
549 FCTXTRACE("cancelquery");
551 REQUIRE(!RESQUERY_CANCELED(query));
553 query->attributes |= RESQUERY_ATTR_CANCELED;
556 * Should we update the RTT?
558 if (finish != NULL || no_response) {
559 if (finish != NULL) {
561 * We have both the start and finish times for this
562 * packet, so we can compute a real RTT.
564 rtt = (unsigned int)isc_time_microdiff(finish,
565 &query->start);
566 factor = DNS_ADB_RTTADJDEFAULT;
567 } else {
569 * We don't have an RTT for this query. Maybe the
570 * packet was lost, or maybe this server is very
571 * slow. We don't know. Increase the RTT.
573 INSIST(no_response);
574 rtt = query->addrinfo->srtt +
575 (200000 * fctx->restarts);
576 if (rtt > 10000000)
577 rtt = 10000000;
579 * Replace the current RTT with our value.
581 factor = DNS_ADB_RTTADJREPLACE;
583 dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
587 * Age RTTs of servers not tried.
589 factor = DNS_ADB_RTTADJAGE;
590 if (finish != NULL)
591 for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
592 addrinfo != NULL;
593 addrinfo = ISC_LIST_NEXT(addrinfo, publink))
594 if (UNMARKED(addrinfo))
595 dns_adb_adjustsrtt(fctx->adb, addrinfo,
596 0, factor);
598 if (finish != NULL && TRIEDFIND(fctx))
599 for (find = ISC_LIST_HEAD(fctx->finds);
600 find != NULL;
601 find = ISC_LIST_NEXT(find, publink))
602 for (addrinfo = ISC_LIST_HEAD(find->list);
603 addrinfo != NULL;
604 addrinfo = ISC_LIST_NEXT(addrinfo, publink))
605 if (UNMARKED(addrinfo))
606 dns_adb_adjustsrtt(fctx->adb, addrinfo,
607 0, factor);
609 if (finish != NULL && TRIEDALT(fctx)) {
610 for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
611 addrinfo != NULL;
612 addrinfo = ISC_LIST_NEXT(addrinfo, publink))
613 if (UNMARKED(addrinfo))
614 dns_adb_adjustsrtt(fctx->adb, addrinfo,
615 0, factor);
616 for (find = ISC_LIST_HEAD(fctx->altfinds);
617 find != NULL;
618 find = ISC_LIST_NEXT(find, publink))
619 for (addrinfo = ISC_LIST_HEAD(find->list);
620 addrinfo != NULL;
621 addrinfo = ISC_LIST_NEXT(addrinfo, publink))
622 if (UNMARKED(addrinfo))
623 dns_adb_adjustsrtt(fctx->adb, addrinfo,
624 0, factor);
627 if (query->dispentry != NULL)
628 dns_dispatch_removeresponse(&query->dispentry, deventp);
630 ISC_LIST_UNLINK(fctx->queries, query, link);
632 if (query->tsig != NULL)
633 isc_buffer_free(&query->tsig);
635 if (query->tsigkey != NULL)
636 dns_tsigkey_detach(&query->tsigkey);
639 * Check for any outstanding socket events. If they exist, cancel
640 * them and let the event handlers finish the cleanup. The resolver
641 * only needs to worry about managing the connect and send events;
642 * the dispatcher manages the recv events.
644 if (RESQUERY_CONNECTING(query))
646 * Cancel the connect.
648 isc_socket_cancel(query->tcpsocket, NULL,
649 ISC_SOCKCANCEL_CONNECT);
650 else if (RESQUERY_SENDING(query))
652 * Cancel the pending send.
654 isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
655 NULL, ISC_SOCKCANCEL_SEND);
657 if (query->dispatch != NULL)
658 dns_dispatch_detach(&query->dispatch);
660 if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
662 * It's safe to destroy the query now.
664 resquery_destroy(&query);
667 static void
668 fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
669 resquery_t *query, *next_query;
671 FCTXTRACE("cancelqueries");
673 for (query = ISC_LIST_HEAD(fctx->queries);
674 query != NULL;
675 query = next_query) {
676 next_query = ISC_LIST_NEXT(query, link);
677 fctx_cancelquery(&query, NULL, NULL, no_response);
681 static void
682 fctx_cleanupfinds(fetchctx_t *fctx) {
683 dns_adbfind_t *find, *next_find;
685 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
687 for (find = ISC_LIST_HEAD(fctx->finds);
688 find != NULL;
689 find = next_find) {
690 next_find = ISC_LIST_NEXT(find, publink);
691 ISC_LIST_UNLINK(fctx->finds, find, publink);
692 dns_adb_destroyfind(&find);
694 fctx->find = NULL;
697 static void
698 fctx_cleanupaltfinds(fetchctx_t *fctx) {
699 dns_adbfind_t *find, *next_find;
701 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
703 for (find = ISC_LIST_HEAD(fctx->altfinds);
704 find != NULL;
705 find = next_find) {
706 next_find = ISC_LIST_NEXT(find, publink);
707 ISC_LIST_UNLINK(fctx->altfinds, find, publink);
708 dns_adb_destroyfind(&find);
710 fctx->altfind = NULL;
713 static void
714 fctx_cleanupforwaddrs(fetchctx_t *fctx) {
715 dns_adbaddrinfo_t *addr, *next_addr;
717 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
719 for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
720 addr != NULL;
721 addr = next_addr) {
722 next_addr = ISC_LIST_NEXT(addr, publink);
723 ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
724 dns_adb_freeaddrinfo(fctx->adb, &addr);
728 static void
729 fctx_cleanupaltaddrs(fetchctx_t *fctx) {
730 dns_adbaddrinfo_t *addr, *next_addr;
732 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
734 for (addr = ISC_LIST_HEAD(fctx->altaddrs);
735 addr != NULL;
736 addr = next_addr) {
737 next_addr = ISC_LIST_NEXT(addr, publink);
738 ISC_LIST_UNLINK(fctx->altaddrs, addr, publink);
739 dns_adb_freeaddrinfo(fctx->adb, &addr);
743 static inline void
744 fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
745 FCTXTRACE("stopeverything");
746 fctx_cancelqueries(fctx, no_response);
747 fctx_cleanupfinds(fctx);
748 fctx_cleanupaltfinds(fctx);
749 fctx_cleanupforwaddrs(fctx);
750 fctx_cleanupaltaddrs(fctx);
751 fctx_stoptimer(fctx);
754 static inline void
755 fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
756 dns_fetchevent_t *event, *next_event;
757 isc_task_t *task;
760 * Caller must be holding the appropriate bucket lock.
762 REQUIRE(fctx->state == fetchstate_done);
764 FCTXTRACE("sendevents");
766 for (event = ISC_LIST_HEAD(fctx->events);
767 event != NULL;
768 event = next_event) {
769 next_event = ISC_LIST_NEXT(event, ev_link);
770 ISC_LIST_UNLINK(fctx->events, event, ev_link);
771 task = event->ev_sender;
772 event->ev_sender = fctx;
773 if (!HAVE_ANSWER(fctx))
774 event->result = result;
776 INSIST(result != ISC_R_SUCCESS ||
777 dns_rdataset_isassociated(event->rdataset) ||
778 fctx->type == dns_rdatatype_any ||
779 fctx->type == dns_rdatatype_rrsig ||
780 fctx->type == dns_rdatatype_sig);
782 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
786 static void
787 fctx_done(fetchctx_t *fctx, isc_result_t result) {
788 dns_resolver_t *res;
789 isc_boolean_t no_response;
791 FCTXTRACE("done");
793 res = fctx->res;
795 if (result == ISC_R_SUCCESS)
796 no_response = ISC_TRUE;
797 else
798 no_response = ISC_FALSE;
799 fctx_stopeverything(fctx, no_response);
801 LOCK(&res->buckets[fctx->bucketnum].lock);
803 fctx->state = fetchstate_done;
804 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
805 fctx_sendevents(fctx, result);
807 UNLOCK(&res->buckets[fctx->bucketnum].lock);
810 static void
811 resquery_senddone(isc_task_t *task, isc_event_t *event) {
812 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
813 resquery_t *query = event->ev_arg;
814 isc_boolean_t retry = ISC_FALSE;
815 isc_result_t result;
816 fetchctx_t *fctx;
818 REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
820 QTRACE("senddone");
823 * XXXRTH
825 * Currently we don't wait for the senddone event before retrying
826 * a query. This means that if we get really behind, we may end
827 * up doing extra work!
830 UNUSED(task);
832 INSIST(RESQUERY_SENDING(query));
834 query->sends--;
835 fctx = query->fctx;
837 if (RESQUERY_CANCELED(query)) {
838 if (query->sends == 0) {
840 * This query was canceled while the
841 * isc_socket_sendto() was in progress.
843 if (query->tcpsocket != NULL)
844 isc_socket_detach(&query->tcpsocket);
845 resquery_destroy(&query);
847 } else
848 switch (sevent->result) {
849 case ISC_R_SUCCESS:
850 break;
852 case ISC_R_HOSTUNREACH:
853 case ISC_R_NETUNREACH:
854 case ISC_R_NOPERM:
855 case ISC_R_ADDRNOTAVAIL:
856 case ISC_R_CONNREFUSED:
859 * No route to remote.
861 fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
862 retry = ISC_TRUE;
863 break;
865 default:
866 fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
867 break;
870 isc_event_free(&event);
872 if (retry) {
874 * Behave as if the idle timer has expired. For TCP
875 * this may not actually reflect the latest timer.
877 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
878 result = fctx_stopidletimer(fctx);
879 if (result != ISC_R_SUCCESS)
880 fctx_done(fctx, result);
881 else
882 fctx_try(fctx);
886 static inline isc_result_t
887 fctx_addopt(dns_message_t *message, dns_resolver_t *res) {
888 dns_rdataset_t *rdataset;
889 dns_rdatalist_t *rdatalist;
890 dns_rdata_t *rdata;
891 isc_result_t result;
893 rdatalist = NULL;
894 result = dns_message_gettemprdatalist(message, &rdatalist);
895 if (result != ISC_R_SUCCESS)
896 return (result);
897 rdata = NULL;
898 result = dns_message_gettemprdata(message, &rdata);
899 if (result != ISC_R_SUCCESS)
900 return (result);
901 rdataset = NULL;
902 result = dns_message_gettemprdataset(message, &rdataset);
903 if (result != ISC_R_SUCCESS)
904 return (result);
905 dns_rdataset_init(rdataset);
907 rdatalist->type = dns_rdatatype_opt;
908 rdatalist->covers = 0;
911 * Set Maximum UDP buffer size.
913 rdatalist->rdclass = res->udpsize;
916 * Set EXTENDED-RCODE, VERSION, and Z to 0, and the DO bit to 1.
918 rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO;
921 * No EDNS options.
923 rdata->data = NULL;
924 rdata->length = 0;
925 rdata->rdclass = rdatalist->rdclass;
926 rdata->type = rdatalist->type;
927 rdata->flags = 0;
929 ISC_LIST_INIT(rdatalist->rdata);
930 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
931 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
933 return (dns_message_setopt(message, rdataset));
936 static inline void
937 fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
938 unsigned int seconds;
941 * We retry every 2 seconds the first two times through the address
942 * list, and then we do exponential back-off.
944 if (fctx->restarts < 3)
945 seconds = 2;
946 else
947 seconds = (2 << (fctx->restarts - 1));
950 * Double the round-trip time and convert to seconds.
952 rtt /= 500000;
955 * Always wait for at least the doubled round-trip time.
957 if (seconds < rtt)
958 seconds = rtt;
961 * But don't ever wait for more than 30 seconds.
963 if (seconds > 30)
964 seconds = 30;
966 isc_interval_set(&fctx->interval, seconds, 0);
969 static isc_result_t
970 fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
971 unsigned int options)
973 dns_resolver_t *res;
974 isc_task_t *task;
975 isc_result_t result;
976 resquery_t *query;
978 FCTXTRACE("query");
980 res = fctx->res;
981 task = res->buckets[fctx->bucketnum].task;
983 fctx_setretryinterval(fctx, addrinfo->srtt);
984 result = fctx_startidletimer(fctx);
985 if (result != ISC_R_SUCCESS)
986 return (result);
988 INSIST(ISC_LIST_EMPTY(fctx->validators));
990 dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
992 query = isc_mem_get(res->mctx, sizeof(*query));
993 if (query == NULL) {
994 result = ISC_R_NOMEMORY;
995 goto stop_idle_timer;
997 query->mctx = res->mctx;
998 query->options = options;
999 query->attributes = 0;
1000 query->sends = 0;
1001 query->connects = 0;
1003 * Note that the caller MUST guarantee that 'addrinfo' will remain
1004 * valid until this query is canceled.
1006 query->addrinfo = addrinfo;
1007 TIME_NOW(&query->start);
1010 * If this is a TCP query, then we need to make a socket and
1011 * a dispatch for it here. Otherwise we use the resolver's
1012 * shared dispatch.
1014 query->dispatchmgr = res->dispatchmgr;
1015 query->dispatch = NULL;
1016 query->tcpsocket = NULL;
1017 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1018 isc_sockaddr_t addr;
1019 int pf;
1021 pf = isc_sockaddr_pf(&addrinfo->sockaddr);
1023 switch (pf) {
1024 case PF_INET:
1025 result = dns_dispatch_getlocaladdress(res->dispatchv4,
1026 &addr);
1027 break;
1028 case PF_INET6:
1029 result = dns_dispatch_getlocaladdress(res->dispatchv6,
1030 &addr);
1031 break;
1032 default:
1033 result = ISC_R_NOTIMPLEMENTED;
1034 break;
1036 if (result != ISC_R_SUCCESS)
1037 goto cleanup_query;
1039 isc_sockaddr_setport(&addr, 0);
1041 result = isc_socket_create(res->socketmgr, pf,
1042 isc_sockettype_tcp,
1043 &query->tcpsocket);
1044 if (result != ISC_R_SUCCESS)
1045 goto cleanup_query;
1047 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
1048 result = isc_socket_bind(query->tcpsocket, &addr);
1049 if (result != ISC_R_SUCCESS)
1050 goto cleanup_socket;
1051 #endif
1054 * A dispatch will be created once the connect succeeds.
1056 } else {
1057 switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
1058 case PF_INET:
1059 dns_dispatch_attach(res->dispatchv4, &query->dispatch);
1060 break;
1061 case PF_INET6:
1062 dns_dispatch_attach(res->dispatchv6, &query->dispatch);
1063 break;
1064 default:
1065 result = ISC_R_NOTIMPLEMENTED;
1066 goto cleanup_query;
1069 * We should always have a valid dispatcher here. If we
1070 * don't support a protocol family, then its dispatcher
1071 * will be NULL, but we shouldn't be finding addresses for
1072 * protocol types we don't support, so the dispatcher
1073 * we found should never be NULL.
1075 INSIST(query->dispatch != NULL);
1078 query->dispentry = NULL;
1079 query->fctx = fctx;
1080 query->tsig = NULL;
1081 query->tsigkey = NULL;
1082 ISC_LINK_INIT(query, link);
1083 query->magic = QUERY_MAGIC;
1085 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1087 * Connect to the remote server.
1089 * XXXRTH Should we attach to the socket?
1091 result = isc_socket_connect(query->tcpsocket,
1092 &addrinfo->sockaddr, task,
1093 resquery_connected, query);
1094 if (result != ISC_R_SUCCESS)
1095 goto cleanup_socket;
1096 query->connects++;
1097 QTRACE("connecting via TCP");
1098 } else {
1099 result = resquery_send(query);
1100 if (result != ISC_R_SUCCESS)
1101 goto cleanup_dispatch;
1104 ISC_LIST_APPEND(fctx->queries, query, link);
1105 query->fctx->nqueries++;
1107 return (ISC_R_SUCCESS);
1109 cleanup_socket:
1110 isc_socket_detach(&query->tcpsocket);
1112 cleanup_dispatch:
1113 if (query->dispatch != NULL)
1114 dns_dispatch_detach(&query->dispatch);
1116 cleanup_query:
1117 query->magic = 0;
1118 isc_mem_put(res->mctx, query, sizeof(*query));
1120 stop_idle_timer:
1121 RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS);
1123 return (result);
1126 static isc_result_t
1127 resquery_send(resquery_t *query) {
1128 fetchctx_t *fctx;
1129 isc_result_t result;
1130 dns_name_t *qname = NULL;
1131 dns_rdataset_t *qrdataset = NULL;
1132 isc_region_t r;
1133 dns_resolver_t *res;
1134 isc_task_t *task;
1135 isc_socket_t *socket;
1136 isc_buffer_t tcpbuffer;
1137 isc_sockaddr_t *address;
1138 isc_buffer_t *buffer;
1139 isc_netaddr_t ipaddr;
1140 dns_tsigkey_t *tsigkey = NULL;
1141 dns_peer_t *peer = NULL;
1142 isc_boolean_t useedns;
1143 dns_compress_t cctx;
1144 isc_boolean_t cleanup_cctx = ISC_FALSE;
1145 isc_boolean_t secure_domain;
1147 fctx = query->fctx;
1148 QTRACE("send");
1150 res = fctx->res;
1151 task = res->buckets[fctx->bucketnum].task;
1152 address = NULL;
1154 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1156 * Reserve space for the TCP message length.
1158 isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data));
1159 isc_buffer_init(&query->buffer, query->data + 2,
1160 sizeof(query->data) - 2);
1161 buffer = &tcpbuffer;
1162 } else {
1163 isc_buffer_init(&query->buffer, query->data,
1164 sizeof(query->data));
1165 buffer = &query->buffer;
1168 result = dns_message_gettempname(fctx->qmessage, &qname);
1169 if (result != ISC_R_SUCCESS)
1170 goto cleanup_temps;
1171 result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
1172 if (result != ISC_R_SUCCESS)
1173 goto cleanup_temps;
1176 * Get a query id from the dispatch.
1178 result = dns_dispatch_addresponse(query->dispatch,
1179 &query->addrinfo->sockaddr,
1180 task,
1181 resquery_response,
1182 query,
1183 &query->id,
1184 &query->dispentry);
1185 if (result != ISC_R_SUCCESS)
1186 goto cleanup_temps;
1188 fctx->qmessage->opcode = dns_opcode_query;
1191 * Set up question.
1193 dns_name_init(qname, NULL);
1194 dns_name_clone(&fctx->name, qname);
1195 dns_rdataset_init(qrdataset);
1196 dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
1197 ISC_LIST_APPEND(qname->list, qrdataset, link);
1198 dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
1199 qname = NULL;
1200 qrdataset = NULL;
1203 * Set RD if the client has requested that we do a recursive query,
1204 * or if we're sending to a forwarder.
1206 if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||
1207 ISFORWARDER(query->addrinfo))
1208 fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;
1211 * Set CD if the client says don't validate or the question is
1212 * under a secure entry point.
1214 if ((query->options & DNS_FETCHOPT_NOVALIDATE) == 0) {
1215 result = dns_keytable_issecuredomain(res->view->secroots,
1216 &fctx->name,
1217 &secure_domain);
1218 if (result != ISC_R_SUCCESS)
1219 secure_domain = ISC_FALSE;
1220 if (res->view->dlv != NULL)
1221 secure_domain = ISC_TRUE;
1222 if (secure_domain)
1223 fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
1224 } else
1225 fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
1228 * We don't have to set opcode because it defaults to query.
1230 fctx->qmessage->id = query->id;
1233 * Convert the question to wire format.
1235 result = dns_compress_init(&cctx, -1, fctx->res->mctx);
1236 if (result != ISC_R_SUCCESS)
1237 goto cleanup_message;
1238 cleanup_cctx = ISC_TRUE;
1240 result = dns_message_renderbegin(fctx->qmessage, &cctx,
1241 &query->buffer);
1242 if (result != ISC_R_SUCCESS)
1243 goto cleanup_message;
1245 result = dns_message_rendersection(fctx->qmessage,
1246 DNS_SECTION_QUESTION, 0);
1247 if (result != ISC_R_SUCCESS)
1248 goto cleanup_message;
1250 peer = NULL;
1251 isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr);
1252 (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer);
1255 * The ADB does not know about servers with "edns no". Check this,
1256 * and then inform the ADB for future use.
1258 if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 &&
1259 peer != NULL &&
1260 dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS &&
1261 !useedns)
1263 query->options |= DNS_FETCHOPT_NOEDNS0;
1264 dns_adb_changeflags(fctx->adb,
1265 query->addrinfo,
1266 DNS_FETCHOPT_NOEDNS0,
1267 DNS_FETCHOPT_NOEDNS0);
1271 * Use EDNS0, unless the caller doesn't want it, or we know that
1272 * the remote server doesn't like it.
1274 if (fctx->timeouts >= MAX_EDNS0_TIMEOUTS &&
1275 (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
1276 query->options |= DNS_FETCHOPT_NOEDNS0;
1277 FCTXTRACE("too many timeouts, disabling EDNS0");
1280 if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
1281 if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
1282 result = fctx_addopt(fctx->qmessage, res);
1283 if (result != ISC_R_SUCCESS) {
1285 * We couldn't add the OPT, but we'll press on.
1286 * We're not using EDNS0, so set the NOEDNS0
1287 * bit.
1289 query->options |= DNS_FETCHOPT_NOEDNS0;
1291 } else {
1293 * We know this server doesn't like EDNS0, so we
1294 * won't use it. Set the NOEDNS0 bit since we're
1295 * not using EDNS0.
1297 query->options |= DNS_FETCHOPT_NOEDNS0;
1302 * If we need EDNS0 to do this query and aren't using it, we lose.
1304 if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) {
1305 result = DNS_R_SERVFAIL;
1306 goto cleanup_message;
1310 * Clear CD if EDNS is not in use.
1312 if ((query->options & DNS_FETCHOPT_NOEDNS0) != 0)
1313 fctx->qmessage->flags &= ~DNS_MESSAGEFLAG_CD;
1316 * Add TSIG record tailored to the current recipient.
1318 result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey);
1319 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
1320 goto cleanup_message;
1322 if (tsigkey != NULL) {
1323 result = dns_message_settsigkey(fctx->qmessage, tsigkey);
1324 dns_tsigkey_detach(&tsigkey);
1325 if (result != ISC_R_SUCCESS)
1326 goto cleanup_message;
1329 result = dns_message_rendersection(fctx->qmessage,
1330 DNS_SECTION_ADDITIONAL, 0);
1331 if (result != ISC_R_SUCCESS)
1332 goto cleanup_message;
1334 result = dns_message_renderend(fctx->qmessage);
1335 if (result != ISC_R_SUCCESS)
1336 goto cleanup_message;
1338 dns_compress_invalidate(&cctx);
1339 cleanup_cctx = ISC_FALSE;
1341 if (dns_message_gettsigkey(fctx->qmessage) != NULL) {
1342 dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage),
1343 &query->tsigkey);
1344 result = dns_message_getquerytsig(fctx->qmessage,
1345 fctx->res->mctx,
1346 &query->tsig);
1347 if (result != ISC_R_SUCCESS)
1348 goto cleanup_message;
1352 * If using TCP, write the length of the message at the beginning
1353 * of the buffer.
1355 if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1356 isc_buffer_usedregion(&query->buffer, &r);
1357 isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
1358 isc_buffer_add(&tcpbuffer, r.length);
1362 * We're now done with the query message.
1364 dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
1366 socket = dns_dispatch_getsocket(query->dispatch);
1368 * Send the query!
1370 if ((query->options & DNS_FETCHOPT_TCP) == 0)
1371 address = &query->addrinfo->sockaddr;
1372 isc_buffer_usedregion(buffer, &r);
1375 * XXXRTH Make sure we don't send to ourselves! We should probably
1376 * prune out these addresses when we get them from the ADB.
1378 result = isc_socket_sendto(socket, &r, task, resquery_senddone,
1379 query, address, NULL);
1380 if (result != ISC_R_SUCCESS)
1381 goto cleanup_message;
1382 query->sends++;
1383 QTRACE("sent");
1385 return (ISC_R_SUCCESS);
1387 cleanup_message:
1388 if (cleanup_cctx)
1389 dns_compress_invalidate(&cctx);
1391 dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
1394 * Stop the dispatcher from listening.
1396 dns_dispatch_removeresponse(&query->dispentry, NULL);
1398 cleanup_temps:
1399 if (qname != NULL)
1400 dns_message_puttempname(fctx->qmessage, &qname);
1401 if (qrdataset != NULL)
1402 dns_message_puttemprdataset(fctx->qmessage, &qrdataset);
1404 return (result);
1407 static void
1408 resquery_connected(isc_task_t *task, isc_event_t *event) {
1409 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1410 resquery_t *query = event->ev_arg;
1411 isc_boolean_t retry = ISC_FALSE;
1412 isc_result_t result;
1413 unsigned int attrs;
1414 fetchctx_t *fctx;
1416 REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1417 REQUIRE(VALID_QUERY(query));
1419 QTRACE("connected");
1421 UNUSED(task);
1424 * XXXRTH
1426 * Currently we don't wait for the connect event before retrying
1427 * a query. This means that if we get really behind, we may end
1428 * up doing extra work!
1431 query->connects--;
1432 fctx = query->fctx;
1434 if (RESQUERY_CANCELED(query)) {
1436 * This query was canceled while the connect() was in
1437 * progress.
1439 isc_socket_detach(&query->tcpsocket);
1440 resquery_destroy(&query);
1441 } else {
1442 switch (sevent->result) {
1443 case ISC_R_SUCCESS:
1445 * We are connected. Create a dispatcher and
1446 * send the query.
1448 attrs = 0;
1449 attrs |= DNS_DISPATCHATTR_TCP;
1450 attrs |= DNS_DISPATCHATTR_PRIVATE;
1451 attrs |= DNS_DISPATCHATTR_CONNECTED;
1452 if (isc_sockaddr_pf(&query->addrinfo->sockaddr) ==
1453 AF_INET)
1454 attrs |= DNS_DISPATCHATTR_IPV4;
1455 else
1456 attrs |= DNS_DISPATCHATTR_IPV6;
1457 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
1459 result = dns_dispatch_createtcp(query->dispatchmgr,
1460 query->tcpsocket,
1461 query->fctx->res->taskmgr,
1462 4096, 2, 1, 1, 3, attrs,
1463 &query->dispatch);
1466 * Regardless of whether dns_dispatch_create()
1467 * succeeded or not, we don't need our reference
1468 * to the socket anymore.
1470 isc_socket_detach(&query->tcpsocket);
1472 if (result == ISC_R_SUCCESS)
1473 result = resquery_send(query);
1475 if (result != ISC_R_SUCCESS) {
1476 fctx_cancelquery(&query, NULL, NULL,
1477 ISC_FALSE);
1478 fctx_done(fctx, result);
1480 break;
1482 case ISC_R_NETUNREACH:
1483 case ISC_R_HOSTUNREACH:
1484 case ISC_R_CONNREFUSED:
1485 case ISC_R_NOPERM:
1486 case ISC_R_ADDRNOTAVAIL:
1487 case ISC_R_CONNECTIONRESET:
1489 * No route to remote.
1491 isc_socket_detach(&query->tcpsocket);
1492 fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
1493 retry = ISC_TRUE;
1494 break;
1496 default:
1497 isc_socket_detach(&query->tcpsocket);
1498 fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
1499 break;
1503 isc_event_free(&event);
1505 if (retry) {
1507 * Behave as if the idle timer has expired. For TCP
1508 * connections this may not actually reflect the latest timer.
1510 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1511 result = fctx_stopidletimer(fctx);
1512 if (result != ISC_R_SUCCESS)
1513 fctx_done(fctx, result);
1514 else
1515 fctx_try(fctx);
1519 static void
1520 fctx_finddone(isc_task_t *task, isc_event_t *event) {
1521 fetchctx_t *fctx;
1522 dns_adbfind_t *find;
1523 dns_resolver_t *res;
1524 isc_boolean_t want_try = ISC_FALSE;
1525 isc_boolean_t want_done = ISC_FALSE;
1526 isc_boolean_t bucket_empty = ISC_FALSE;
1527 unsigned int bucketnum;
1529 find = event->ev_sender;
1530 fctx = event->ev_arg;
1531 REQUIRE(VALID_FCTX(fctx));
1532 res = fctx->res;
1534 UNUSED(task);
1536 FCTXTRACE("finddone");
1538 INSIST(fctx->pending > 0);
1539 fctx->pending--;
1541 if (ADDRWAIT(fctx)) {
1543 * The fetch is waiting for a name to be found.
1545 INSIST(!SHUTTINGDOWN(fctx));
1546 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1547 if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
1548 want_try = ISC_TRUE;
1549 else if (fctx->pending == 0) {
1551 * We've got nothing else to wait for and don't
1552 * know the answer. There's nothing to do but
1553 * fail the fctx.
1555 want_done = ISC_TRUE;
1557 } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
1558 fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
1559 bucketnum = fctx->bucketnum;
1560 LOCK(&res->buckets[bucketnum].lock);
1562 * Note that we had to wait until we had the lock before
1563 * looking at fctx->references.
1565 if (fctx->references == 0)
1566 bucket_empty = fctx_destroy(fctx);
1567 UNLOCK(&res->buckets[bucketnum].lock);
1570 isc_event_free(&event);
1571 dns_adb_destroyfind(&find);
1573 if (want_try)
1574 fctx_try(fctx);
1575 else if (want_done)
1576 fctx_done(fctx, ISC_R_FAILURE);
1577 else if (bucket_empty)
1578 empty_bucket(res);
1582 static inline isc_boolean_t
1583 bad_server(fetchctx_t *fctx, isc_sockaddr_t *address) {
1584 isc_sockaddr_t *sa;
1586 for (sa = ISC_LIST_HEAD(fctx->bad);
1587 sa != NULL;
1588 sa = ISC_LIST_NEXT(sa, link)) {
1589 if (isc_sockaddr_equal(sa, address))
1590 return (ISC_TRUE);
1593 return (ISC_FALSE);
1596 static inline isc_boolean_t
1597 mark_bad(fetchctx_t *fctx) {
1598 dns_adbfind_t *curr;
1599 dns_adbaddrinfo_t *addrinfo;
1600 isc_boolean_t all_bad = ISC_TRUE;
1603 * Mark all known bad servers, so we don't try to talk to them
1604 * again.
1608 * Mark any bad nameservers.
1610 for (curr = ISC_LIST_HEAD(fctx->finds);
1611 curr != NULL;
1612 curr = ISC_LIST_NEXT(curr, publink)) {
1613 for (addrinfo = ISC_LIST_HEAD(curr->list);
1614 addrinfo != NULL;
1615 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1616 if (bad_server(fctx, &addrinfo->sockaddr))
1617 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1618 else
1619 all_bad = ISC_FALSE;
1624 * Mark any bad forwarders.
1626 for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
1627 addrinfo != NULL;
1628 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1629 if (bad_server(fctx, &addrinfo->sockaddr))
1630 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1631 else
1632 all_bad = ISC_FALSE;
1636 * Mark any bad alternates.
1638 for (curr = ISC_LIST_HEAD(fctx->altfinds);
1639 curr != NULL;
1640 curr = ISC_LIST_NEXT(curr, publink)) {
1641 for (addrinfo = ISC_LIST_HEAD(curr->list);
1642 addrinfo != NULL;
1643 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1644 if (bad_server(fctx, &addrinfo->sockaddr))
1645 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1646 else
1647 all_bad = ISC_FALSE;
1651 for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
1652 addrinfo != NULL;
1653 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1654 if (bad_server(fctx, &addrinfo->sockaddr))
1655 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1656 else
1657 all_bad = ISC_FALSE;
1660 return (all_bad);
1663 static void
1664 add_bad(fetchctx_t *fctx, isc_sockaddr_t *address, isc_result_t reason) {
1665 char namebuf[DNS_NAME_FORMATSIZE];
1666 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1667 char classbuf[64];
1668 char typebuf[64];
1669 char code[64];
1670 isc_buffer_t b;
1671 isc_sockaddr_t *sa;
1672 const char *sep1, *sep2;
1674 if (bad_server(fctx, address)) {
1676 * We already know this server is bad.
1678 return;
1681 FCTXTRACE("add_bad");
1683 sa = isc_mem_get(fctx->res->mctx, sizeof(*sa));
1684 if (sa == NULL)
1685 return;
1686 *sa = *address;
1687 ISC_LIST_INITANDAPPEND(fctx->bad, sa, link);
1689 if (reason == DNS_R_LAME) /* already logged */
1690 return;
1692 if (reason == DNS_R_UNEXPECTEDRCODE) {
1693 isc_buffer_init(&b, code, sizeof(code) - 1);
1694 dns_rcode_totext(fctx->rmessage->rcode, &b);
1695 code[isc_buffer_usedlength(&b)] = '\0';
1696 sep1 = "(";
1697 sep2 = ") ";
1698 } else if (reason == DNS_R_UNEXPECTEDOPCODE) {
1699 isc_buffer_init(&b, code, sizeof(code) - 1);
1700 dns_opcode_totext((dns_opcode_t)fctx->rmessage->opcode, &b);
1701 code[isc_buffer_usedlength(&b)] = '\0';
1702 sep1 = "(";
1703 sep2 = ") ";
1704 } else {
1705 code[0] = '\0';
1706 sep1 = "";
1707 sep2 = "";
1709 dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
1710 dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
1711 dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf));
1712 isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
1713 isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
1714 DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
1715 "%s %s%s%sresolving '%s/%s/%s': %s",
1716 dns_result_totext(reason), sep1, code, sep2,
1717 namebuf, typebuf, classbuf, addrbuf);
1720 static void
1721 sort_adbfind(dns_adbfind_t *find) {
1722 dns_adbaddrinfo_t *best, *curr;
1723 dns_adbaddrinfolist_t sorted;
1726 * Lame N^2 bubble sort.
1729 ISC_LIST_INIT(sorted);
1730 while (!ISC_LIST_EMPTY(find->list)) {
1731 best = ISC_LIST_HEAD(find->list);
1732 curr = ISC_LIST_NEXT(best, publink);
1733 while (curr != NULL) {
1734 if (curr->srtt < best->srtt)
1735 best = curr;
1736 curr = ISC_LIST_NEXT(curr, publink);
1738 ISC_LIST_UNLINK(find->list, best, publink);
1739 ISC_LIST_APPEND(sorted, best, publink);
1741 find->list = sorted;
1744 static void
1745 sort_finds(fetchctx_t *fctx) {
1746 dns_adbfind_t *best, *curr;
1747 dns_adbfindlist_t sorted;
1748 dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
1751 * Lame N^2 bubble sort.
1754 ISC_LIST_INIT(sorted);
1755 while (!ISC_LIST_EMPTY(fctx->finds)) {
1756 best = ISC_LIST_HEAD(fctx->finds);
1757 bestaddrinfo = ISC_LIST_HEAD(best->list);
1758 INSIST(bestaddrinfo != NULL);
1759 curr = ISC_LIST_NEXT(best, publink);
1760 while (curr != NULL) {
1761 addrinfo = ISC_LIST_HEAD(curr->list);
1762 INSIST(addrinfo != NULL);
1763 if (addrinfo->srtt < bestaddrinfo->srtt) {
1764 best = curr;
1765 bestaddrinfo = addrinfo;
1767 curr = ISC_LIST_NEXT(curr, publink);
1769 ISC_LIST_UNLINK(fctx->finds, best, publink);
1770 ISC_LIST_APPEND(sorted, best, publink);
1772 fctx->finds = sorted;
1774 ISC_LIST_INIT(sorted);
1775 while (!ISC_LIST_EMPTY(fctx->altfinds)) {
1776 best = ISC_LIST_HEAD(fctx->altfinds);
1777 bestaddrinfo = ISC_LIST_HEAD(best->list);
1778 INSIST(bestaddrinfo != NULL);
1779 curr = ISC_LIST_NEXT(best, publink);
1780 while (curr != NULL) {
1781 addrinfo = ISC_LIST_HEAD(curr->list);
1782 INSIST(addrinfo != NULL);
1783 if (addrinfo->srtt < bestaddrinfo->srtt) {
1784 best = curr;
1785 bestaddrinfo = addrinfo;
1787 curr = ISC_LIST_NEXT(curr, publink);
1789 ISC_LIST_UNLINK(fctx->altfinds, best, publink);
1790 ISC_LIST_APPEND(sorted, best, publink);
1792 fctx->altfinds = sorted;
1795 static void
1796 findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
1797 unsigned int options, unsigned int flags, isc_stdtime_t now,
1798 isc_boolean_t *pruned, isc_boolean_t *need_alternate)
1800 dns_adbaddrinfo_t *ai;
1801 dns_adbfind_t *find;
1802 dns_resolver_t *res;
1803 isc_boolean_t unshared;
1804 isc_result_t result;
1806 res = fctx->res;
1807 unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0);
1809 * If this name is a subdomain of the query domain, tell
1810 * the ADB to start looking using zone/hint data. This keeps us
1811 * from getting stuck if the nameserver is beneath the zone cut
1812 * and we don't know its address (e.g. because the A record has
1813 * expired).
1815 if (dns_name_issubdomain(name, &fctx->domain))
1816 options |= DNS_ADBFIND_STARTATZONE;
1817 options |= DNS_ADBFIND_GLUEOK;
1818 options |= DNS_ADBFIND_HINTOK;
1821 * See what we know about this address.
1823 find = NULL;
1824 result = dns_adb_createfind(fctx->adb,
1825 res->buckets[fctx->bucketnum].task,
1826 fctx_finddone, fctx, name,
1827 &fctx->domain, options, now, NULL,
1828 res->view->dstport, &find);
1829 if (result != ISC_R_SUCCESS) {
1830 if (result == DNS_R_ALIAS) {
1832 * XXXRTH Follow the CNAME/DNAME chain?
1834 dns_adb_destroyfind(&find);
1836 } else if (!ISC_LIST_EMPTY(find->list)) {
1838 * We have at least some of the addresses for the
1839 * name.
1841 INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
1842 sort_adbfind(find);
1843 if (flags != 0 || port != 0) {
1844 for (ai = ISC_LIST_HEAD(find->list);
1845 ai != NULL;
1846 ai = ISC_LIST_NEXT(ai, publink)) {
1847 ai->flags |= flags;
1848 if (port != 0)
1849 isc_sockaddr_setport(&ai->sockaddr,
1850 port);
1853 if ((flags & FCTX_ADDRINFO_FORWARDER) != 0)
1854 ISC_LIST_APPEND(fctx->altfinds, find, publink);
1855 else
1856 ISC_LIST_APPEND(fctx->finds, find, publink);
1857 } else {
1859 * We don't know any of the addresses for this
1860 * name.
1862 if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
1864 * We're looking for them and will get an
1865 * event about it later.
1867 fctx->pending++;
1869 * Bootstrap.
1871 if (need_alternate != NULL &&
1872 !*need_alternate && unshared &&
1873 ((res->dispatchv4 == NULL &&
1874 find->result_v6 != DNS_R_NXDOMAIN) ||
1875 (res->dispatchv6 == NULL &&
1876 find->result_v4 != DNS_R_NXDOMAIN)))
1877 *need_alternate = ISC_TRUE;
1878 } else {
1880 * If we know there are no addresses for
1881 * the family we are using then try to add
1882 * an alternative server.
1884 if (need_alternate != NULL && !*need_alternate &&
1885 ((res->dispatchv4 == NULL &&
1886 find->result_v6 == DNS_R_NXRRSET) ||
1887 (res->dispatchv6 == NULL &&
1888 find->result_v4 == DNS_R_NXRRSET)))
1889 *need_alternate = ISC_TRUE;
1891 * And ADB isn't going to send us any events
1892 * either. This find loses.
1894 if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) {
1896 * The ADB pruned lame servers for
1897 * this name. Remember that in case
1898 * we get desperate later on.
1900 *pruned = ISC_TRUE;
1902 dns_adb_destroyfind(&find);
1907 static isc_result_t
1908 fctx_getaddresses(fetchctx_t *fctx) {
1909 dns_rdata_t rdata = DNS_RDATA_INIT;
1910 isc_result_t result;
1911 dns_resolver_t *res;
1912 isc_stdtime_t now;
1913 unsigned int stdoptions;
1914 isc_sockaddr_t *sa;
1915 dns_adbaddrinfo_t *ai;
1916 isc_boolean_t pruned, all_bad;
1917 dns_rdata_ns_t ns;
1918 isc_boolean_t need_alternate = ISC_FALSE;
1920 FCTXTRACE("getaddresses");
1923 * Don't pound on remote servers. (Failsafe!)
1925 fctx->restarts++;
1926 if (fctx->restarts > 10) {
1927 FCTXTRACE("too many restarts");
1928 return (DNS_R_SERVFAIL);
1931 res = fctx->res;
1932 pruned = ISC_FALSE;
1933 stdoptions = 0; /* Keep compiler happy. */
1936 * Forwarders.
1939 INSIST(ISC_LIST_EMPTY(fctx->forwaddrs));
1940 INSIST(ISC_LIST_EMPTY(fctx->altaddrs));
1943 * If this fctx has forwarders, use them; otherwise use any
1944 * selective forwarders specified in the view; otherwise use the
1945 * resolver's forwarders (if any).
1947 sa = ISC_LIST_HEAD(fctx->forwarders);
1948 if (sa == NULL) {
1949 dns_forwarders_t *forwarders = NULL;
1950 dns_name_t *name = &fctx->name;
1951 dns_name_t suffix;
1952 unsigned int labels;
1955 * DS records are found in the parent server.
1956 * Strip label to get the correct forwarder (if any).
1958 if (fctx->type == dns_rdatatype_ds &&
1959 dns_name_countlabels(name) > 1) {
1960 dns_name_init(&suffix, NULL);
1961 labels = dns_name_countlabels(name);
1962 dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
1963 name = &suffix;
1965 result = dns_fwdtable_find(fctx->res->view->fwdtable, name,
1966 &forwarders);
1967 if (result == ISC_R_SUCCESS) {
1968 sa = ISC_LIST_HEAD(forwarders->addrs);
1969 fctx->fwdpolicy = forwarders->fwdpolicy;
1973 while (sa != NULL) {
1974 ai = NULL;
1975 result = dns_adb_findaddrinfo(fctx->adb,
1976 sa, &ai, 0); /* XXXMLG */
1977 if (result == ISC_R_SUCCESS) {
1978 dns_adbaddrinfo_t *cur;
1979 ai->flags |= FCTX_ADDRINFO_FORWARDER;
1980 cur = ISC_LIST_HEAD(fctx->forwaddrs);
1981 while (cur != NULL && cur->srtt < ai->srtt)
1982 cur = ISC_LIST_NEXT(cur, publink);
1983 if (cur != NULL)
1984 ISC_LIST_INSERTBEFORE(fctx->forwaddrs, cur,
1985 ai, publink);
1986 else
1987 ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
1989 sa = ISC_LIST_NEXT(sa, link);
1993 * If the forwarding policy is "only", we don't need the addresses
1994 * of the nameservers.
1996 if (fctx->fwdpolicy == dns_fwdpolicy_only)
1997 goto out;
2000 * Normal nameservers.
2003 stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
2004 if (fctx->restarts == 1) {
2006 * To avoid sending out a flood of queries likely to
2007 * result in NXRRSET, we suppress fetches for address
2008 * families we don't have the first time through,
2009 * provided that we have addresses in some family we
2010 * can use.
2012 * We don't want to set this option all the time, since
2013 * if fctx->restarts > 1, we've clearly been having trouble
2014 * with the addresses we had, so getting more could help.
2016 stdoptions |= DNS_ADBFIND_AVOIDFETCHES;
2018 if (res->dispatchv4 != NULL)
2019 stdoptions |= DNS_ADBFIND_INET;
2020 if (res->dispatchv6 != NULL)
2021 stdoptions |= DNS_ADBFIND_INET6;
2022 isc_stdtime_get(&now);
2024 restart:
2025 INSIST(ISC_LIST_EMPTY(fctx->finds));
2026 INSIST(ISC_LIST_EMPTY(fctx->altfinds));
2028 for (result = dns_rdataset_first(&fctx->nameservers);
2029 result == ISC_R_SUCCESS;
2030 result = dns_rdataset_next(&fctx->nameservers))
2032 dns_rdataset_current(&fctx->nameservers, &rdata);
2034 * Extract the name from the NS record.
2036 result = dns_rdata_tostruct(&rdata, &ns, NULL);
2037 if (result != ISC_R_SUCCESS)
2038 continue;
2040 findname(fctx, &ns.name, 0, stdoptions, 0, now,
2041 &pruned, &need_alternate);
2042 dns_rdata_reset(&rdata);
2043 dns_rdata_freestruct(&ns);
2045 if (result != ISC_R_NOMORE)
2046 return (result);
2049 * Do we need to use 6 to 4?
2051 if (need_alternate) {
2052 int family;
2053 alternate_t *a;
2054 family = (res->dispatchv6 != NULL) ? AF_INET6 : AF_INET;
2055 for (a = ISC_LIST_HEAD(fctx->res->alternates);
2056 a != NULL;
2057 a = ISC_LIST_NEXT(a, link)) {
2058 if (!a->isaddress) {
2059 findname(fctx, &a->_u._n.name, a->_u._n.port,
2060 stdoptions, FCTX_ADDRINFO_FORWARDER,
2061 now, &pruned, NULL);
2062 continue;
2064 if (isc_sockaddr_pf(&a->_u.addr) != family)
2065 continue;
2066 ai = NULL;
2067 result = dns_adb_findaddrinfo(fctx->adb, &a->_u.addr,
2068 &ai, 0);
2069 if (result == ISC_R_SUCCESS) {
2070 dns_adbaddrinfo_t *cur;
2071 ai->flags |= FCTX_ADDRINFO_FORWARDER;
2072 cur = ISC_LIST_HEAD(fctx->altaddrs);
2073 while (cur != NULL && cur->srtt < ai->srtt)
2074 cur = ISC_LIST_NEXT(cur, publink);
2075 if (cur != NULL)
2076 ISC_LIST_INSERTBEFORE(fctx->altaddrs,
2077 cur, ai, publink);
2078 else
2079 ISC_LIST_APPEND(fctx->altaddrs, ai,
2080 publink);
2085 out:
2087 * Mark all known bad servers.
2089 all_bad = mark_bad(fctx);
2092 * How are we doing?
2094 if (all_bad) {
2096 * We've got no addresses.
2098 if (fctx->pending > 0) {
2100 * We're fetching the addresses, but don't have any
2101 * yet. Tell the caller to wait for an answer.
2103 result = DNS_R_WAIT;
2104 } else if (pruned) {
2106 * Some addresses were removed by lame pruning.
2107 * Turn pruning off and try again.
2109 FCTXTRACE("restarting with returnlame");
2110 INSIST((stdoptions & DNS_ADBFIND_RETURNLAME) == 0);
2111 stdoptions |= DNS_ADBFIND_RETURNLAME;
2112 pruned = ISC_FALSE;
2113 fctx_cleanupaltfinds(fctx);
2114 fctx_cleanupfinds(fctx);
2115 goto restart;
2116 } else {
2118 * We've lost completely. We don't know any
2119 * addresses, and the ADB has told us it can't get
2120 * them.
2122 FCTXTRACE("no addresses");
2123 result = ISC_R_FAILURE;
2125 } else {
2127 * We've found some addresses. We might still be looking
2128 * for more addresses.
2130 sort_finds(fctx);
2131 result = ISC_R_SUCCESS;
2134 return (result);
2137 static inline void
2138 possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr)
2140 isc_netaddr_t na;
2141 char buf[ISC_NETADDR_FORMATSIZE];
2142 isc_sockaddr_t *sa;
2143 isc_boolean_t aborted = ISC_FALSE;
2144 isc_boolean_t bogus;
2145 dns_acl_t *blackhole;
2146 isc_netaddr_t ipaddr;
2147 dns_peer_t *peer = NULL;
2148 dns_resolver_t *res;
2149 const char *msg = NULL;
2151 sa = &addr->sockaddr;
2153 res = fctx->res;
2154 isc_netaddr_fromsockaddr(&ipaddr, sa);
2155 blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr);
2156 (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer);
2158 if (blackhole != NULL) {
2159 int match;
2161 if (dns_acl_match(&ipaddr, NULL, blackhole,
2162 &res->view->aclenv,
2163 &match, NULL) == ISC_R_SUCCESS &&
2164 match > 0)
2165 aborted = ISC_TRUE;
2168 if (peer != NULL &&
2169 dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS &&
2170 bogus)
2171 aborted = ISC_TRUE;
2173 if (aborted) {
2174 addr->flags |= FCTX_ADDRINFO_MARK;
2175 msg = "ignoring blackholed / bogus server: ";
2176 } else if (isc_sockaddr_ismulticast(sa)) {
2177 addr->flags |= FCTX_ADDRINFO_MARK;
2178 msg = "ignoring multicast address: ";
2179 } else if (isc_sockaddr_isexperimental(sa)) {
2180 addr->flags |= FCTX_ADDRINFO_MARK;
2181 msg = "ignoring experimental address: ";
2182 } else if (sa->type.sa.sa_family != AF_INET6) {
2183 return;
2184 } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) {
2185 addr->flags |= FCTX_ADDRINFO_MARK;
2186 msg = "ignoring IPv6 mapped IPV4 address: ";
2187 } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) {
2188 addr->flags |= FCTX_ADDRINFO_MARK;
2189 msg = "ignoring IPv6 compatibility IPV4 address: ";
2190 } else
2191 return;
2193 if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3)))
2194 return;
2196 isc_netaddr_fromsockaddr(&na, sa);
2197 isc_netaddr_format(&na, buf, sizeof(buf));
2198 FCTXTRACE2(msg, buf);
2201 static inline dns_adbaddrinfo_t *
2202 fctx_nextaddress(fetchctx_t *fctx) {
2203 dns_adbfind_t *find, *start;
2204 dns_adbaddrinfo_t *addrinfo;
2205 dns_adbaddrinfo_t *faddrinfo;
2208 * Return the next untried address, if any.
2212 * Find the first unmarked forwarder (if any).
2214 for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
2215 addrinfo != NULL;
2216 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2217 if (!UNMARKED(addrinfo))
2218 continue;
2219 possibly_mark(fctx, addrinfo);
2220 if (UNMARKED(addrinfo)) {
2221 addrinfo->flags |= FCTX_ADDRINFO_MARK;
2222 fctx->find = NULL;
2223 return (addrinfo);
2228 * No forwarders. Move to the next find.
2231 fctx->attributes |= FCTX_ATTR_TRIEDFIND;
2233 find = fctx->find;
2234 if (find == NULL)
2235 find = ISC_LIST_HEAD(fctx->finds);
2236 else {
2237 find = ISC_LIST_NEXT(find, publink);
2238 if (find == NULL)
2239 find = ISC_LIST_HEAD(fctx->finds);
2243 * Find the first unmarked addrinfo.
2245 addrinfo = NULL;
2246 if (find != NULL) {
2247 start = find;
2248 do {
2249 for (addrinfo = ISC_LIST_HEAD(find->list);
2250 addrinfo != NULL;
2251 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2252 if (!UNMARKED(addrinfo))
2253 continue;
2254 possibly_mark(fctx, addrinfo);
2255 if (UNMARKED(addrinfo)) {
2256 addrinfo->flags |= FCTX_ADDRINFO_MARK;
2257 break;
2260 if (addrinfo != NULL)
2261 break;
2262 find = ISC_LIST_NEXT(find, publink);
2263 if (find == NULL)
2264 find = ISC_LIST_HEAD(fctx->finds);
2265 } while (find != start);
2268 fctx->find = find;
2269 if (addrinfo != NULL)
2270 return (addrinfo);
2273 * No nameservers left. Try alternates.
2276 fctx->attributes |= FCTX_ATTR_TRIEDALT;
2278 find = fctx->altfind;
2279 if (find == NULL)
2280 find = ISC_LIST_HEAD(fctx->altfinds);
2281 else {
2282 find = ISC_LIST_NEXT(find, publink);
2283 if (find == NULL)
2284 find = ISC_LIST_HEAD(fctx->altfinds);
2288 * Find the first unmarked addrinfo.
2290 addrinfo = NULL;
2291 if (find != NULL) {
2292 start = find;
2293 do {
2294 for (addrinfo = ISC_LIST_HEAD(find->list);
2295 addrinfo != NULL;
2296 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2297 if (!UNMARKED(addrinfo))
2298 continue;
2299 possibly_mark(fctx, addrinfo);
2300 if (UNMARKED(addrinfo)) {
2301 addrinfo->flags |= FCTX_ADDRINFO_MARK;
2302 break;
2305 if (addrinfo != NULL)
2306 break;
2307 find = ISC_LIST_NEXT(find, publink);
2308 if (find == NULL)
2309 find = ISC_LIST_HEAD(fctx->altfinds);
2310 } while (find != start);
2313 faddrinfo = addrinfo;
2316 * See if we have a better alternate server by address.
2319 for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
2320 addrinfo != NULL;
2321 addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2322 if (!UNMARKED(addrinfo))
2323 continue;
2324 possibly_mark(fctx, addrinfo);
2325 if (UNMARKED(addrinfo) &&
2326 (faddrinfo == NULL ||
2327 addrinfo->srtt < faddrinfo->srtt)) {
2328 if (faddrinfo != NULL)
2329 faddrinfo->flags &= ~FCTX_ADDRINFO_MARK;
2330 addrinfo->flags |= FCTX_ADDRINFO_MARK;
2331 break;
2335 if (addrinfo == NULL) {
2336 addrinfo = faddrinfo;
2337 fctx->altfind = find;
2340 return (addrinfo);
2343 static void
2344 fctx_try(fetchctx_t *fctx) {
2345 isc_result_t result;
2346 dns_adbaddrinfo_t *addrinfo;
2348 FCTXTRACE("try");
2350 REQUIRE(!ADDRWAIT(fctx));
2352 addrinfo = fctx_nextaddress(fctx);
2353 if (addrinfo == NULL) {
2355 * We have no more addresses. Start over.
2357 fctx_cancelqueries(fctx, ISC_TRUE);
2358 fctx_cleanupfinds(fctx);
2359 fctx_cleanupaltfinds(fctx);
2360 fctx_cleanupforwaddrs(fctx);
2361 fctx_cleanupaltaddrs(fctx);
2362 result = fctx_getaddresses(fctx);
2363 if (result == DNS_R_WAIT) {
2365 * Sleep waiting for addresses.
2367 FCTXTRACE("addrwait");
2368 fctx->attributes |= FCTX_ATTR_ADDRWAIT;
2369 return;
2370 } else if (result != ISC_R_SUCCESS) {
2372 * Something bad happened.
2374 fctx_done(fctx, result);
2375 return;
2378 addrinfo = fctx_nextaddress(fctx);
2380 * While we may have addresses from the ADB, they
2381 * might be bad ones. In this case, return SERVFAIL.
2383 if (addrinfo == NULL) {
2384 fctx_done(fctx, DNS_R_SERVFAIL);
2385 return;
2389 result = fctx_query(fctx, addrinfo, fctx->options);
2390 if (result != ISC_R_SUCCESS)
2391 fctx_done(fctx, result);
2394 static isc_boolean_t
2395 fctx_destroy(fetchctx_t *fctx) {
2396 dns_resolver_t *res;
2397 unsigned int bucketnum;
2398 isc_sockaddr_t *sa, *next_sa;
2401 * Caller must be holding the bucket lock.
2404 REQUIRE(VALID_FCTX(fctx));
2405 REQUIRE(fctx->state == fetchstate_done ||
2406 fctx->state == fetchstate_init);
2407 REQUIRE(ISC_LIST_EMPTY(fctx->events));
2408 REQUIRE(ISC_LIST_EMPTY(fctx->queries));
2409 REQUIRE(ISC_LIST_EMPTY(fctx->finds));
2410 REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
2411 REQUIRE(fctx->pending == 0);
2412 REQUIRE(fctx->references == 0);
2413 REQUIRE(ISC_LIST_EMPTY(fctx->validators));
2415 FCTXTRACE("destroy");
2417 res = fctx->res;
2418 bucketnum = fctx->bucketnum;
2420 ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
2423 * Free bad.
2425 for (sa = ISC_LIST_HEAD(fctx->bad);
2426 sa != NULL;
2427 sa = next_sa) {
2428 next_sa = ISC_LIST_NEXT(sa, link);
2429 ISC_LIST_UNLINK(fctx->bad, sa, link);
2430 isc_mem_put(res->mctx, sa, sizeof(*sa));
2433 isc_timer_detach(&fctx->timer);
2434 dns_message_destroy(&fctx->rmessage);
2435 dns_message_destroy(&fctx->qmessage);
2436 if (dns_name_countlabels(&fctx->domain) > 0)
2437 dns_name_free(&fctx->domain, res->mctx);
2438 if (dns_rdataset_isassociated(&fctx->nameservers))
2439 dns_rdataset_disassociate(&fctx->nameservers);
2440 dns_name_free(&fctx->name, res->mctx);
2441 dns_db_detach(&fctx->cache);
2442 dns_adb_detach(&fctx->adb);
2443 isc_mem_free(res->mctx, fctx->info);
2444 isc_mem_put(res->mctx, fctx, sizeof(*fctx));
2446 LOCK(&res->nlock);
2447 res->nfctx--;
2448 UNLOCK(&res->nlock);
2450 if (res->buckets[bucketnum].exiting &&
2451 ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
2452 return (ISC_TRUE);
2454 return (ISC_FALSE);
2458 * Fetch event handlers.
2461 static void
2462 fctx_timeout(isc_task_t *task, isc_event_t *event) {
2463 fetchctx_t *fctx = event->ev_arg;
2465 REQUIRE(VALID_FCTX(fctx));
2467 UNUSED(task);
2469 FCTXTRACE("timeout");
2471 if (event->ev_type == ISC_TIMEREVENT_LIFE) {
2472 fctx_done(fctx, ISC_R_TIMEDOUT);
2473 } else {
2474 isc_result_t result;
2476 fctx->timeouts++;
2478 * We could cancel the running queries here, or we could let
2479 * them keep going. Right now we choose the latter...
2481 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
2483 * Our timer has triggered. Reestablish the fctx lifetime
2484 * timer.
2486 result = fctx_starttimer(fctx);
2487 if (result != ISC_R_SUCCESS)
2488 fctx_done(fctx, result);
2489 else
2491 * Keep trying.
2493 fctx_try(fctx);
2496 isc_event_free(&event);
2499 static void
2500 fctx_shutdown(fetchctx_t *fctx) {
2501 isc_event_t *cevent;
2504 * Start the shutdown process for fctx, if it isn't already underway.
2507 FCTXTRACE("shutdown");
2510 * The caller must be holding the appropriate bucket lock.
2513 if (fctx->want_shutdown)
2514 return;
2516 fctx->want_shutdown = ISC_TRUE;
2519 * Unless we're still initializing (in which case the
2520 * control event is still outstanding), we need to post
2521 * the control event to tell the fetch we want it to
2522 * exit.
2524 if (fctx->state != fetchstate_init) {
2525 cevent = &fctx->control_event;
2526 isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
2527 &cevent);
2531 static void
2532 fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
2533 fetchctx_t *fctx = event->ev_arg;
2534 isc_boolean_t bucket_empty = ISC_FALSE;
2535 dns_resolver_t *res;
2536 unsigned int bucketnum;
2537 dns_validator_t *validator;
2539 REQUIRE(VALID_FCTX(fctx));
2541 UNUSED(task);
2543 res = fctx->res;
2544 bucketnum = fctx->bucketnum;
2546 FCTXTRACE("doshutdown");
2549 * An fctx that is shutting down is no longer in ADDRWAIT mode.
2551 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
2554 * Cancel all pending validators. Note that this must be done
2555 * without the bucket lock held, since that could cause deadlock.
2557 validator = ISC_LIST_HEAD(fctx->validators);
2558 while (validator != NULL) {
2559 dns_validator_cancel(validator);
2560 validator = ISC_LIST_NEXT(validator, link);
2563 if (fctx->nsfetch != NULL)
2564 dns_resolver_cancelfetch(fctx->nsfetch);
2567 * Shut down anything that is still running on behalf of this
2568 * fetch. To avoid deadlock with the ADB, we must do this
2569 * before we lock the bucket lock.
2571 fctx_stopeverything(fctx, ISC_FALSE);
2573 LOCK(&res->buckets[bucketnum].lock);
2575 fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
2577 INSIST(fctx->state == fetchstate_active ||
2578 fctx->state == fetchstate_done);
2579 INSIST(fctx->want_shutdown);
2581 if (fctx->state != fetchstate_done) {
2582 fctx->state = fetchstate_done;
2583 fctx_sendevents(fctx, ISC_R_CANCELED);
2586 if (fctx->references == 0 && fctx->pending == 0 &&
2587 fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators))
2588 bucket_empty = fctx_destroy(fctx);
2590 UNLOCK(&res->buckets[bucketnum].lock);
2592 if (bucket_empty)
2593 empty_bucket(res);
2596 static void
2597 fctx_start(isc_task_t *task, isc_event_t *event) {
2598 fetchctx_t *fctx = event->ev_arg;
2599 isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE;
2600 dns_resolver_t *res;
2601 unsigned int bucketnum;
2603 REQUIRE(VALID_FCTX(fctx));
2605 UNUSED(task);
2607 res = fctx->res;
2608 bucketnum = fctx->bucketnum;
2610 FCTXTRACE("start");
2612 LOCK(&res->buckets[bucketnum].lock);
2614 INSIST(fctx->state == fetchstate_init);
2615 if (fctx->want_shutdown) {
2617 * We haven't started this fctx yet, and we've been requested
2618 * to shut it down.
2620 fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
2621 fctx->state = fetchstate_done;
2622 fctx_sendevents(fctx, ISC_R_CANCELED);
2624 * Since we haven't started, we INSIST that we have no
2625 * pending ADB finds and no pending validations.
2627 INSIST(fctx->pending == 0);
2628 INSIST(fctx->nqueries == 0);
2629 INSIST(ISC_LIST_EMPTY(fctx->validators));
2630 if (fctx->references == 0) {
2632 * It's now safe to destroy this fctx.
2634 bucket_empty = fctx_destroy(fctx);
2636 done = ISC_TRUE;
2637 } else {
2639 * Normal fctx startup.
2641 fctx->state = fetchstate_active;
2643 * Reset the control event for later use in shutting down
2644 * the fctx.
2646 ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
2647 DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx,
2648 NULL, NULL, NULL);
2651 UNLOCK(&res->buckets[bucketnum].lock);
2653 if (!done) {
2654 isc_result_t result;
2657 * All is well. Start working on the fetch.
2659 result = fctx_starttimer(fctx);
2660 if (result != ISC_R_SUCCESS)
2661 fctx_done(fctx, result);
2662 else
2663 fctx_try(fctx);
2664 } else if (bucket_empty)
2665 empty_bucket(res);
2669 * Fetch Creation, Joining, and Cancelation.
2672 static inline isc_result_t
2673 fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_taskaction_t action,
2674 void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
2675 dns_fetch_t *fetch)
2677 isc_task_t *clone;
2678 dns_fetchevent_t *event;
2680 FCTXTRACE("join");
2683 * We store the task we're going to send this event to in the
2684 * sender field. We'll make the fetch the sender when we actually
2685 * send the event.
2687 clone = NULL;
2688 isc_task_attach(task, &clone);
2689 event = (dns_fetchevent_t *)
2690 isc_event_allocate(fctx->res->mctx, clone,
2691 DNS_EVENT_FETCHDONE,
2692 action, arg, sizeof(*event));
2693 if (event == NULL) {
2694 isc_task_detach(&clone);
2695 return (ISC_R_NOMEMORY);
2697 event->result = DNS_R_SERVFAIL;
2698 event->qtype = fctx->type;
2699 event->db = NULL;
2700 event->node = NULL;
2701 event->rdataset = rdataset;
2702 event->sigrdataset = sigrdataset;
2703 event->fetch = fetch;
2704 dns_fixedname_init(&event->foundname);
2707 * Make sure that we can store the sigrdataset in the
2708 * first event if it is needed by any of the events.
2710 if (event->sigrdataset != NULL)
2711 ISC_LIST_PREPEND(fctx->events, event, ev_link);
2712 else
2713 ISC_LIST_APPEND(fctx->events, event, ev_link);
2714 fctx->references++;
2716 fetch->magic = DNS_FETCH_MAGIC;
2717 fetch->private = fctx;
2719 return (ISC_R_SUCCESS);
2722 static isc_result_t
2723 fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
2724 dns_name_t *domain, dns_rdataset_t *nameservers,
2725 unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
2727 fetchctx_t *fctx;
2728 isc_result_t result;
2729 isc_result_t iresult;
2730 isc_interval_t interval;
2731 dns_fixedname_t fixed;
2732 unsigned int findoptions = 0;
2733 char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
2734 char typebuf[DNS_RDATATYPE_FORMATSIZE];
2735 dns_name_t suffix;
2738 * Caller must be holding the lock for bucket number 'bucketnum'.
2740 REQUIRE(fctxp != NULL && *fctxp == NULL);
2742 fctx = isc_mem_get(res->mctx, sizeof(*fctx));
2743 if (fctx == NULL)
2744 return (ISC_R_NOMEMORY);
2745 dns_name_format(name, buf, sizeof(buf));
2746 dns_rdatatype_format(type, typebuf, sizeof(typebuf));
2747 strcat(buf, "/"); /* checked */
2748 strcat(buf, typebuf); /* checked */
2749 fctx->info = isc_mem_strdup(res->mctx, buf);
2750 if (fctx->info == NULL) {
2751 result = ISC_R_NOMEMORY;
2752 goto cleanup_fetch;
2754 FCTXTRACE("create");
2755 dns_name_init(&fctx->name, NULL);
2756 result = dns_name_dup(name, res->mctx, &fctx->name);
2757 if (result != ISC_R_SUCCESS)
2758 goto cleanup_info;
2759 dns_name_init(&fctx->domain, NULL);
2760 dns_rdataset_init(&fctx->nameservers);
2762 fctx->type = type;
2763 fctx->options = options;
2765 * Note! We do not attach to the task. We are relying on the
2766 * resolver to ensure that this task doesn't go away while we are
2767 * using it.
2769 fctx->res = res;
2770 fctx->references = 0;
2771 fctx->bucketnum = bucketnum;
2772 fctx->state = fetchstate_init;
2773 fctx->want_shutdown = ISC_FALSE;
2774 fctx->cloned = ISC_FALSE;
2775 ISC_LIST_INIT(fctx->queries);
2776 ISC_LIST_INIT(fctx->finds);
2777 ISC_LIST_INIT(fctx->altfinds);
2778 ISC_LIST_INIT(fctx->forwaddrs);
2779 ISC_LIST_INIT(fctx->altaddrs);
2780 ISC_LIST_INIT(fctx->forwarders);
2781 fctx->fwdpolicy = dns_fwdpolicy_none;
2782 ISC_LIST_INIT(fctx->bad);
2783 ISC_LIST_INIT(fctx->validators);
2784 fctx->find = NULL;
2785 fctx->altfind = NULL;
2786 fctx->pending = 0;
2787 fctx->restarts = 0;
2788 fctx->timeouts = 0;
2789 fctx->attributes = 0;
2790 fctx->nqueries = 0;
2792 dns_name_init(&fctx->nsname, NULL);
2793 fctx->nsfetch = NULL;
2794 dns_rdataset_init(&fctx->nsrrset);
2796 if (domain == NULL) {
2797 dns_forwarders_t *forwarders = NULL;
2798 unsigned int labels;
2801 * DS records are found in the parent server.
2802 * Strip label to get the correct forwarder (if any).
2804 if (fctx->type == dns_rdatatype_ds &&
2805 dns_name_countlabels(name) > 1) {
2806 dns_name_init(&suffix, NULL);
2807 labels = dns_name_countlabels(name);
2808 dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
2809 name = &suffix;
2811 dns_fixedname_init(&fixed);
2812 domain = dns_fixedname_name(&fixed);
2813 result = dns_fwdtable_find2(fctx->res->view->fwdtable, name,
2814 domain, &forwarders);
2815 if (result == ISC_R_SUCCESS)
2816 fctx->fwdpolicy = forwarders->fwdpolicy;
2818 if (fctx->fwdpolicy != dns_fwdpolicy_only) {
2820 * The caller didn't supply a query domain and
2821 * nameservers, and we're not in forward-only mode,
2822 * so find the best nameservers to use.
2824 if (dns_rdatatype_atparent(type))
2825 findoptions |= DNS_DBFIND_NOEXACT;
2826 result = dns_view_findzonecut(res->view, name, domain,
2827 0, findoptions, ISC_TRUE,
2828 &fctx->nameservers,
2829 NULL);
2830 if (result != ISC_R_SUCCESS)
2831 goto cleanup_name;
2832 result = dns_name_dup(domain, res->mctx, &fctx->domain);
2833 if (result != ISC_R_SUCCESS) {
2834 dns_rdataset_disassociate(&fctx->nameservers);
2835 goto cleanup_name;
2837 } else {
2839 * We're in forward-only mode. Set the query domain.
2841 result = dns_name_dup(domain, res->mctx, &fctx->domain);
2842 if (result != ISC_R_SUCCESS)
2843 goto cleanup_name;
2845 } else {
2846 result = dns_name_dup(domain, res->mctx, &fctx->domain);
2847 if (result != ISC_R_SUCCESS)
2848 goto cleanup_name;
2849 dns_rdataset_clone(nameservers, &fctx->nameservers);
2852 INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
2854 fctx->qmessage = NULL;
2855 result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTRENDER,
2856 &fctx->qmessage);
2858 if (result != ISC_R_SUCCESS)
2859 goto cleanup_domain;
2861 fctx->rmessage = NULL;
2862 result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTPARSE,
2863 &fctx->rmessage);
2865 if (result != ISC_R_SUCCESS)
2866 goto cleanup_qmessage;
2869 * Compute an expiration time for the entire fetch.
2871 isc_interval_set(&interval, 30, 0); /* XXXRTH constant */
2872 iresult = isc_time_nowplusinterval(&fctx->expires, &interval);
2873 if (iresult != ISC_R_SUCCESS) {
2874 UNEXPECTED_ERROR(__FILE__, __LINE__,
2875 "isc_time_nowplusinterval: %s",
2876 isc_result_totext(iresult));
2877 result = ISC_R_UNEXPECTED;
2878 goto cleanup_rmessage;
2882 * Default retry interval initialization. We set the interval now
2883 * mostly so it won't be uninitialized. It will be set to the
2884 * correct value before a query is issued.
2886 isc_interval_set(&fctx->interval, 2, 0);
2889 * Create an inactive timer. It will be made active when the fetch
2890 * is actually started.
2892 fctx->timer = NULL;
2893 iresult = isc_timer_create(res->timermgr, isc_timertype_inactive,
2894 NULL, NULL,
2895 res->buckets[bucketnum].task, fctx_timeout,
2896 fctx, &fctx->timer);
2897 if (iresult != ISC_R_SUCCESS) {
2898 UNEXPECTED_ERROR(__FILE__, __LINE__,
2899 "isc_timer_create: %s",
2900 isc_result_totext(iresult));
2901 result = ISC_R_UNEXPECTED;
2902 goto cleanup_rmessage;
2906 * Attach to the view's cache and adb.
2908 fctx->cache = NULL;
2909 dns_db_attach(res->view->cachedb, &fctx->cache);
2910 fctx->adb = NULL;
2911 dns_adb_attach(res->view->adb, &fctx->adb);
2913 ISC_LIST_INIT(fctx->events);
2914 ISC_LINK_INIT(fctx, link);
2915 fctx->magic = FCTX_MAGIC;
2917 ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
2919 LOCK(&res->nlock);
2920 res->nfctx++;
2921 UNLOCK(&res->nlock);
2923 *fctxp = fctx;
2925 return (ISC_R_SUCCESS);
2927 cleanup_rmessage:
2928 dns_message_destroy(&fctx->rmessage);
2930 cleanup_qmessage:
2931 dns_message_destroy(&fctx->qmessage);
2933 cleanup_domain:
2934 if (dns_name_countlabels(&fctx->domain) > 0)
2935 dns_name_free(&fctx->domain, res->mctx);
2936 if (dns_rdataset_isassociated(&fctx->nameservers))
2937 dns_rdataset_disassociate(&fctx->nameservers);
2939 cleanup_name:
2940 dns_name_free(&fctx->name, res->mctx);
2942 cleanup_info:
2943 isc_mem_free(res->mctx, fctx->info);
2945 cleanup_fetch:
2946 isc_mem_put(res->mctx, fctx, sizeof(*fctx));
2948 return (result);
2952 * Handle Responses
2954 static inline isc_boolean_t
2955 is_lame(fetchctx_t *fctx) {
2956 dns_message_t *message = fctx->rmessage;
2957 dns_name_t *name;
2958 dns_rdataset_t *rdataset;
2959 isc_result_t result;
2961 if (message->rcode != dns_rcode_noerror &&
2962 message->rcode != dns_rcode_nxdomain)
2963 return (ISC_FALSE);
2965 if (message->counts[DNS_SECTION_ANSWER] != 0)
2966 return (ISC_FALSE);
2968 if (message->counts[DNS_SECTION_AUTHORITY] == 0)
2969 return (ISC_FALSE);
2971 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
2972 while (result == ISC_R_SUCCESS) {
2973 name = NULL;
2974 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
2975 for (rdataset = ISC_LIST_HEAD(name->list);
2976 rdataset != NULL;
2977 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2978 dns_namereln_t namereln;
2979 int order;
2980 unsigned int labels;
2981 if (rdataset->type != dns_rdatatype_ns)
2982 continue;
2983 namereln = dns_name_fullcompare(name, &fctx->domain,
2984 &order, &labels);
2985 if (namereln == dns_namereln_equal &&
2986 (message->flags & DNS_MESSAGEFLAG_AA) != 0)
2987 return (ISC_FALSE);
2988 if (namereln == dns_namereln_subdomain)
2989 return (ISC_FALSE);
2990 return (ISC_TRUE);
2992 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
2995 return (ISC_FALSE);
2998 static inline void
2999 log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) {
3000 char namebuf[DNS_NAME_FORMATSIZE];
3001 char domainbuf[DNS_NAME_FORMATSIZE];
3002 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
3004 dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
3005 dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
3006 isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf));
3007 isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
3008 DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
3009 "lame server resolving '%s' (in '%s'?): %s",
3010 namebuf, domainbuf, addrbuf);
3013 static inline isc_result_t
3014 same_question(fetchctx_t *fctx) {
3015 isc_result_t result;
3016 dns_message_t *message = fctx->rmessage;
3017 dns_name_t *name;
3018 dns_rdataset_t *rdataset;
3021 * Caller must be holding the fctx lock.
3025 * XXXRTH Currently we support only one question.
3027 if (message->counts[DNS_SECTION_QUESTION] != 1)
3028 return (DNS_R_FORMERR);
3030 result = dns_message_firstname(message, DNS_SECTION_QUESTION);
3031 if (result != ISC_R_SUCCESS)
3032 return (result);
3033 name = NULL;
3034 dns_message_currentname(message, DNS_SECTION_QUESTION, &name);
3035 rdataset = ISC_LIST_HEAD(name->list);
3036 INSIST(rdataset != NULL);
3037 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
3038 if (fctx->type != rdataset->type ||
3039 fctx->res->rdclass != rdataset->rdclass ||
3040 !dns_name_equal(&fctx->name, name))
3041 return (DNS_R_FORMERR);
3043 return (ISC_R_SUCCESS);
3046 static void
3047 clone_results(fetchctx_t *fctx) {
3048 dns_fetchevent_t *event, *hevent;
3049 isc_result_t result;
3050 dns_name_t *name, *hname;
3052 FCTXTRACE("clone_results");
3055 * Set up any other events to have the same data as the first
3056 * event.
3058 * Caller must be holding the appropriate lock.
3061 fctx->cloned = ISC_TRUE;
3062 hevent = ISC_LIST_HEAD(fctx->events);
3063 if (hevent == NULL)
3064 return;
3065 hname = dns_fixedname_name(&hevent->foundname);
3066 for (event = ISC_LIST_NEXT(hevent, ev_link);
3067 event != NULL;
3068 event = ISC_LIST_NEXT(event, ev_link)) {
3069 name = dns_fixedname_name(&event->foundname);
3070 result = dns_name_copy(hname, name, NULL);
3071 if (result != ISC_R_SUCCESS)
3072 event->result = result;
3073 else
3074 event->result = hevent->result;
3075 dns_db_attach(hevent->db, &event->db);
3076 dns_db_attachnode(hevent->db, hevent->node, &event->node);
3077 INSIST(hevent->rdataset != NULL);
3078 INSIST(event->rdataset != NULL);
3079 if (dns_rdataset_isassociated(hevent->rdataset))
3080 dns_rdataset_clone(hevent->rdataset, event->rdataset);
3081 INSIST(! (hevent->sigrdataset == NULL &&
3082 event->sigrdataset != NULL));
3083 if (hevent->sigrdataset != NULL &&
3084 dns_rdataset_isassociated(hevent->sigrdataset) &&
3085 event->sigrdataset != NULL)
3086 dns_rdataset_clone(hevent->sigrdataset,
3087 event->sigrdataset);
3091 #define CACHE(r) (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0)
3092 #define ANSWER(r) (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0)
3093 #define ANSWERSIG(r) (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0)
3094 #define EXTERNAL(r) (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0)
3095 #define CHAINING(r) (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0)
3096 #define CHASE(r) (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0)
3097 #define CHECKNAMES(r) (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0)
3101 * Destroy '*fctx' if it is ready to be destroyed (i.e., if it has
3102 * no references and is no longer waiting for any events). If this
3103 * was the last fctx in the resolver, destroy the resolver.
3105 * Requires:
3106 * '*fctx' is shutting down.
3108 static void
3109 maybe_destroy(fetchctx_t *fctx) {
3110 unsigned int bucketnum;
3111 isc_boolean_t bucket_empty = ISC_FALSE;
3112 dns_resolver_t *res = fctx->res;
3113 dns_validator_t *validator;
3115 REQUIRE(SHUTTINGDOWN(fctx));
3117 if (fctx->pending != 0 || fctx->nqueries != 0)
3118 return;
3120 for (validator = ISC_LIST_HEAD(fctx->validators);
3121 validator != NULL;
3122 validator = ISC_LIST_HEAD(fctx->validators)) {
3123 ISC_LIST_UNLINK(fctx->validators, validator, link);
3124 dns_validator_cancel(validator);
3125 dns_validator_destroy(&validator);
3128 bucketnum = fctx->bucketnum;
3129 LOCK(&res->buckets[bucketnum].lock);
3130 if (fctx->references == 0)
3131 bucket_empty = fctx_destroy(fctx);
3132 UNLOCK(&res->buckets[bucketnum].lock);
3134 if (bucket_empty)
3135 empty_bucket(res);
3139 * The validator has finished.
3141 static void
3142 validated(isc_task_t *task, isc_event_t *event) {
3143 isc_result_t result = ISC_R_SUCCESS;
3144 isc_result_t eresult = ISC_R_SUCCESS;
3145 isc_stdtime_t now;
3146 fetchctx_t *fctx;
3147 dns_validatorevent_t *vevent;
3148 dns_fetchevent_t *hevent;
3149 dns_rdataset_t *ardataset = NULL;
3150 dns_rdataset_t *asigrdataset = NULL;
3151 dns_dbnode_t *node = NULL;
3152 isc_boolean_t negative;
3153 isc_boolean_t chaining;
3154 isc_boolean_t sentresponse;
3155 isc_uint32_t ttl;
3156 dns_dbnode_t *nsnode = NULL;
3157 dns_name_t *name;
3158 dns_rdataset_t *rdataset;
3159 dns_rdataset_t *sigrdataset;
3160 dns_valarg_t *valarg;
3161 dns_adbaddrinfo_t *addrinfo;
3163 UNUSED(task); /* for now */
3165 REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE);
3166 valarg = event->ev_arg;
3167 fctx = valarg->fctx;
3168 addrinfo = valarg->addrinfo;
3169 REQUIRE(VALID_FCTX(fctx));
3170 REQUIRE(!ISC_LIST_EMPTY(fctx->validators));
3172 vevent = (dns_validatorevent_t *)event;
3174 FCTXTRACE("received validation completion event");
3176 ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
3179 * Destroy the validator early so that we can
3180 * destroy the fctx if necessary.
3182 dns_validator_destroy(&vevent->validator);
3183 isc_mem_put(fctx->res->mctx, valarg, sizeof(*valarg));
3185 negative = ISC_TF(vevent->rdataset == NULL);
3187 sentresponse = ISC_TF((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0);
3190 * If shutting down, ignore the results. Check to see if we're
3191 * done waiting for validator completions and ADB pending events; if
3192 * so, destroy the fctx.
3194 if (SHUTTINGDOWN(fctx) && !sentresponse) {
3195 maybe_destroy(fctx); /* Locks bucket. */
3196 goto cleanup_event;
3199 LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3202 * If chaining, we need to make sure that the right result code is
3203 * returned, and that the rdatasets are bound.
3205 if (vevent->result == ISC_R_SUCCESS &&
3206 !negative &&
3207 vevent->rdataset != NULL &&
3208 CHAINING(vevent->rdataset))
3210 if (vevent->rdataset->type == dns_rdatatype_cname)
3211 eresult = DNS_R_CNAME;
3212 else {
3213 INSIST(vevent->rdataset->type == dns_rdatatype_dname);
3214 eresult = DNS_R_DNAME;
3216 chaining = ISC_TRUE;
3217 } else
3218 chaining = ISC_FALSE;
3221 * Either we're not shutting down, or we are shutting down but want
3222 * to cache the result anyway (if this was a validation started by
3223 * a query with cd set)
3226 hevent = ISC_LIST_HEAD(fctx->events);
3227 if (hevent != NULL) {
3228 if (!negative && !chaining &&
3229 (fctx->type == dns_rdatatype_any ||
3230 fctx->type == dns_rdatatype_rrsig ||
3231 fctx->type == dns_rdatatype_sig)) {
3233 * Don't bind rdatasets; the caller
3234 * will iterate the node.
3236 } else {
3237 ardataset = hevent->rdataset;
3238 asigrdataset = hevent->sigrdataset;
3242 if (vevent->result != ISC_R_SUCCESS) {
3243 FCTXTRACE("validation failed");
3244 result = ISC_R_NOTFOUND;
3245 if (vevent->rdataset != NULL)
3246 result = dns_db_findnode(fctx->cache, vevent->name,
3247 ISC_TRUE, &node);
3248 if (result == ISC_R_SUCCESS)
3249 (void)dns_db_deleterdataset(fctx->cache, node, NULL,
3250 vevent->type, 0);
3251 if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL)
3252 (void)dns_db_deleterdataset(fctx->cache, node, NULL,
3253 dns_rdatatype_rrsig,
3254 vevent->type);
3255 if (result == ISC_R_SUCCESS)
3256 dns_db_detachnode(fctx->cache, &node);
3257 result = vevent->result;
3258 add_bad(fctx, &addrinfo->sockaddr, result);
3259 isc_event_free(&event);
3260 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3261 if (!ISC_LIST_EMPTY(fctx->validators))
3262 dns_validator_send(ISC_LIST_HEAD(fctx->validators));
3263 else if (sentresponse)
3264 fctx_done(fctx, result); /* Locks bucket. */
3265 else
3266 fctx_try(fctx); /* Locks bucket. */
3267 return;
3270 isc_stdtime_get(&now);
3272 if (negative) {
3273 dns_rdatatype_t covers;
3274 FCTXTRACE("nonexistence validation OK");
3276 if (fctx->rmessage->rcode == dns_rcode_nxdomain)
3277 covers = dns_rdatatype_any;
3278 else
3279 covers = fctx->type;
3281 result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE,
3282 &node);
3283 if (result != ISC_R_SUCCESS)
3284 goto noanswer_response;
3287 * If we are asking for a SOA record set the cache time
3288 * to zero to facilitate locating the containing zone of
3289 * a arbitary zone.
3291 ttl = fctx->res->view->maxncachettl;
3292 if (fctx->type == dns_rdatatype_soa &&
3293 covers == dns_rdatatype_any)
3294 ttl = 0;
3296 result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
3297 covers, now, ttl,
3298 ardataset, &eresult);
3299 if (result != ISC_R_SUCCESS)
3300 goto noanswer_response;
3301 goto answer_response;
3304 FCTXTRACE("validation OK");
3306 if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) {
3308 result = dns_rdataset_addnoqname(vevent->rdataset,
3309 vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]);
3310 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3311 INSIST(vevent->sigrdataset != NULL);
3312 vevent->sigrdataset->ttl = vevent->rdataset->ttl;
3316 * The data was already cached as pending data.
3317 * Re-cache it as secure and bind the cached
3318 * rdatasets to the first event on the fetch
3319 * event list.
3321 result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node);
3322 if (result != ISC_R_SUCCESS)
3323 goto noanswer_response;
3325 result = dns_db_addrdataset(fctx->cache, node, NULL, now,
3326 vevent->rdataset, 0, ardataset);
3327 if (result != ISC_R_SUCCESS &&
3328 result != DNS_R_UNCHANGED)
3329 goto noanswer_response;
3330 if (vevent->sigrdataset != NULL) {
3331 result = dns_db_addrdataset(fctx->cache, node, NULL, now,
3332 vevent->sigrdataset, 0,
3333 asigrdataset);
3334 if (result != ISC_R_SUCCESS &&
3335 result != DNS_R_UNCHANGED)
3336 goto noanswer_response;
3339 if (sentresponse) {
3341 * If we only deferred the destroy because we wanted to cache
3342 * the data, destroy now.
3344 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3345 if (SHUTTINGDOWN(fctx))
3346 maybe_destroy(fctx); /* Locks bucket. */
3347 goto cleanup_event;
3350 if (!ISC_LIST_EMPTY(fctx->validators)) {
3351 INSIST(!negative);
3352 INSIST(fctx->type == dns_rdatatype_any ||
3353 fctx->type == dns_rdatatype_rrsig ||
3354 fctx->type == dns_rdatatype_sig);
3356 * Don't send a response yet - we have
3357 * more rdatasets that still need to
3358 * be validated.
3360 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3361 dns_validator_send(ISC_LIST_HEAD(fctx->validators));
3362 goto cleanup_event;
3365 answer_response:
3367 * Cache any NS/NSEC records that happened to be validated.
3369 result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY);
3370 while (result == ISC_R_SUCCESS) {
3371 name = NULL;
3372 dns_message_currentname(fctx->rmessage, DNS_SECTION_AUTHORITY,
3373 &name);
3374 for (rdataset = ISC_LIST_HEAD(name->list);
3375 rdataset != NULL;
3376 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3377 if ((rdataset->type != dns_rdatatype_ns &&
3378 rdataset->type != dns_rdatatype_nsec) ||
3379 rdataset->trust != dns_trust_secure)
3380 continue;
3381 for (sigrdataset = ISC_LIST_HEAD(name->list);
3382 sigrdataset != NULL;
3383 sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
3384 if (sigrdataset->type != dns_rdatatype_rrsig ||
3385 sigrdataset->covers != rdataset->type)
3386 continue;
3387 break;
3389 if (sigrdataset == NULL ||
3390 sigrdataset->trust != dns_trust_secure)
3391 continue;
3392 result = dns_db_findnode(fctx->cache, name, ISC_TRUE,
3393 &nsnode);
3394 if (result != ISC_R_SUCCESS)
3395 continue;
3397 result = dns_db_addrdataset(fctx->cache, nsnode, NULL,
3398 now, rdataset, 0, NULL);
3399 if (result == ISC_R_SUCCESS)
3400 result = dns_db_addrdataset(fctx->cache, nsnode,
3401 NULL, now,
3402 sigrdataset, 0,
3403 NULL);
3404 dns_db_detachnode(fctx->cache, &nsnode);
3406 result = dns_message_nextname(fctx->rmessage,
3407 DNS_SECTION_AUTHORITY);
3410 result = ISC_R_SUCCESS;
3413 * Respond with an answer, positive or negative,
3414 * as opposed to an error. 'node' must be non-NULL.
3417 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3419 if (hevent != NULL) {
3420 hevent->result = eresult;
3421 RUNTIME_CHECK(dns_name_copy(vevent->name,
3422 dns_fixedname_name(&hevent->foundname), NULL)
3423 == ISC_R_SUCCESS);
3424 dns_db_attach(fctx->cache, &hevent->db);
3425 hevent->node = node;
3426 node = NULL;
3427 clone_results(fctx);
3430 noanswer_response:
3431 if (node != NULL)
3432 dns_db_detachnode(fctx->cache, &node);
3434 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3436 fctx_done(fctx, result); /* Locks bucket. */
3438 cleanup_event:
3439 isc_event_free(&event);
3442 static inline isc_result_t
3443 cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
3444 isc_stdtime_t now) {
3445 dns_rdataset_t *rdataset, *sigrdataset;
3446 dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset;
3447 dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL;
3448 dns_dbnode_t *node, **anodep;
3449 dns_db_t **adbp;
3450 dns_name_t *aname;
3451 dns_resolver_t *res;
3452 isc_boolean_t need_validation, secure_domain, have_answer;
3453 isc_result_t result, eresult;
3454 dns_fetchevent_t *event;
3455 unsigned int options;
3456 isc_task_t *task;
3457 isc_boolean_t fail;
3458 unsigned int valoptions = 0;
3461 * The appropriate bucket lock must be held.
3464 res = fctx->res;
3465 need_validation = ISC_FALSE;
3466 secure_domain = ISC_FALSE;
3467 have_answer = ISC_FALSE;
3468 eresult = ISC_R_SUCCESS;
3469 task = res->buckets[fctx->bucketnum].task;
3472 * Is DNSSEC validation required for this name?
3474 result = dns_keytable_issecuredomain(res->view->secroots, name,
3475 &secure_domain);
3476 if (result != ISC_R_SUCCESS)
3477 return (result);
3479 if (!secure_domain && res->view->dlv != NULL) {
3480 valoptions = DNS_VALIDATOR_DLV;
3481 secure_domain = ISC_TRUE;
3484 if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
3485 need_validation = ISC_FALSE;
3486 else
3487 need_validation = secure_domain;
3489 adbp = NULL;
3490 aname = NULL;
3491 anodep = NULL;
3492 ardataset = NULL;
3493 asigrdataset = NULL;
3494 event = NULL;
3495 if ((name->attributes & DNS_NAMEATTR_ANSWER) != 0 &&
3496 !need_validation) {
3497 have_answer = ISC_TRUE;
3498 event = ISC_LIST_HEAD(fctx->events);
3499 if (event != NULL) {
3500 adbp = &event->db;
3501 aname = dns_fixedname_name(&event->foundname);
3502 result = dns_name_copy(name, aname, NULL);
3503 if (result != ISC_R_SUCCESS)
3504 return (result);
3505 anodep = &event->node;
3507 * If this is an ANY, SIG or RRSIG query, we're not
3508 * going to return any rdatasets, unless we encountered
3509 * a CNAME or DNAME as "the answer". In this case,
3510 * we're going to return DNS_R_CNAME or DNS_R_DNAME
3511 * and we must set up the rdatasets.
3513 if ((fctx->type != dns_rdatatype_any &&
3514 fctx->type != dns_rdatatype_rrsig &&
3515 fctx->type != dns_rdatatype_sig) ||
3516 (name->attributes & DNS_NAMEATTR_CHAINING) != 0) {
3517 ardataset = event->rdataset;
3518 asigrdataset = event->sigrdataset;
3524 * Find or create the cache node.
3526 node = NULL;
3527 result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
3528 if (result != ISC_R_SUCCESS)
3529 return (result);
3532 * Cache or validate each cacheable rdataset.
3534 fail = ISC_TF((fctx->res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0);
3535 for (rdataset = ISC_LIST_HEAD(name->list);
3536 rdataset != NULL;
3537 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3538 if (!CACHE(rdataset))
3539 continue;
3540 if (CHECKNAMES(rdataset)) {
3541 char namebuf[DNS_NAME_FORMATSIZE];
3542 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3543 char classbuf[DNS_RDATATYPE_FORMATSIZE];
3545 dns_name_format(name, namebuf, sizeof(namebuf));
3546 dns_rdatatype_format(rdataset->type, typebuf,
3547 sizeof(typebuf));
3548 dns_rdataclass_format(rdataset->rdclass, classbuf,
3549 sizeof(classbuf));
3550 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
3551 DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
3552 "check-names %s %s/%s/%s",
3553 fail ? "failure" : "warning",
3554 namebuf, typebuf, classbuf);
3555 if (fail) {
3556 if (ANSWER(rdataset))
3557 return (DNS_R_BADNAME);
3558 continue;
3563 * Enforce the configure maximum cache TTL.
3565 if (rdataset->ttl > res->view->maxcachettl)
3566 rdataset->ttl = res->view->maxcachettl;
3569 * If this rrset is in a secure domain, do DNSSEC validation
3570 * for it, unless it is glue.
3572 if (secure_domain && rdataset->trust != dns_trust_glue) {
3574 * RRSIGs are validated as part of validating the
3575 * type they cover.
3577 if (rdataset->type == dns_rdatatype_rrsig)
3578 continue;
3580 * Find the SIG for this rdataset, if we have it.
3582 for (sigrdataset = ISC_LIST_HEAD(name->list);
3583 sigrdataset != NULL;
3584 sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
3585 if (sigrdataset->type == dns_rdatatype_rrsig &&
3586 sigrdataset->covers == rdataset->type)
3587 break;
3589 if (sigrdataset == NULL) {
3590 if (!ANSWER(rdataset) && need_validation) {
3592 * Ignore non-answer rdatasets that
3593 * are missing signatures.
3595 continue;
3600 * Normalize the rdataset and sigrdataset TTLs.
3602 if (sigrdataset != NULL) {
3603 rdataset->ttl = ISC_MIN(rdataset->ttl,
3604 sigrdataset->ttl);
3605 sigrdataset->ttl = rdataset->ttl;
3609 * Cache this rdataset/sigrdataset pair as
3610 * pending data.
3612 rdataset->trust = dns_trust_pending;
3613 if (sigrdataset != NULL)
3614 sigrdataset->trust = dns_trust_pending;
3615 if (!need_validation)
3616 addedrdataset = ardataset;
3617 else
3618 addedrdataset = NULL;
3619 result = dns_db_addrdataset(fctx->cache, node, NULL,
3620 now, rdataset, 0,
3621 addedrdataset);
3622 if (result == DNS_R_UNCHANGED)
3623 result = ISC_R_SUCCESS;
3624 if (result != ISC_R_SUCCESS)
3625 break;
3626 if (sigrdataset != NULL) {
3627 if (!need_validation)
3628 addedrdataset = asigrdataset;
3629 else
3630 addedrdataset = NULL;
3631 result = dns_db_addrdataset(fctx->cache,
3632 node, NULL, now,
3633 sigrdataset, 0,
3634 addedrdataset);
3635 if (result == DNS_R_UNCHANGED)
3636 result = ISC_R_SUCCESS;
3637 if (result != ISC_R_SUCCESS)
3638 break;
3639 } else if (!ANSWER(rdataset))
3640 continue;
3642 if (ANSWER(rdataset) && need_validation) {
3643 if (fctx->type != dns_rdatatype_any &&
3644 fctx->type != dns_rdatatype_rrsig &&
3645 fctx->type != dns_rdatatype_sig) {
3647 * This is The Answer. We will
3648 * validate it, but first we cache
3649 * the rest of the response - it may
3650 * contain useful keys.
3652 INSIST(valrdataset == NULL &&
3653 valsigrdataset == NULL);
3654 valrdataset = rdataset;
3655 valsigrdataset = sigrdataset;
3656 } else {
3658 * This is one of (potentially)
3659 * multiple answers to an ANY
3660 * or SIG query. To keep things
3661 * simple, we just start the
3662 * validator right away rather
3663 * than caching first and
3664 * having to remember which
3665 * rdatasets needed validation.
3667 result = valcreate(fctx, addrinfo,
3668 name, rdataset->type,
3669 rdataset,
3670 sigrdataset,
3671 valoptions, task);
3673 * Defer any further validations.
3674 * This prevents multiple validators
3675 * from manipulating fctx->rmessage
3676 * simultaniously.
3678 valoptions |= DNS_VALIDATOR_DEFER;
3680 } else if (CHAINING(rdataset)) {
3681 if (rdataset->type == dns_rdatatype_cname)
3682 eresult = DNS_R_CNAME;
3683 else {
3684 INSIST(rdataset->type ==
3685 dns_rdatatype_dname);
3686 eresult = DNS_R_DNAME;
3689 } else if (!EXTERNAL(rdataset)) {
3691 * It's OK to cache this rdataset now.
3693 if (ANSWER(rdataset))
3694 addedrdataset = ardataset;
3695 else if (ANSWERSIG(rdataset))
3696 addedrdataset = asigrdataset;
3697 else
3698 addedrdataset = NULL;
3699 if (CHAINING(rdataset)) {
3700 if (rdataset->type == dns_rdatatype_cname)
3701 eresult = DNS_R_CNAME;
3702 else {
3703 INSIST(rdataset->type ==
3704 dns_rdatatype_dname);
3705 eresult = DNS_R_DNAME;
3708 if (rdataset->trust == dns_trust_glue &&
3709 (rdataset->type == dns_rdatatype_ns ||
3710 (rdataset->type == dns_rdatatype_rrsig &&
3711 rdataset->covers == dns_rdatatype_ns))) {
3713 * If the trust level is 'dns_trust_glue'
3714 * then we are adding data from a referral
3715 * we got while executing the search algorithm.
3716 * New referral data always takes precedence
3717 * over the existing cache contents.
3719 options = DNS_DBADD_FORCE;
3720 } else
3721 options = 0;
3723 * Now we can add the rdataset.
3725 result = dns_db_addrdataset(fctx->cache,
3726 node, NULL, now,
3727 rdataset,
3728 options,
3729 addedrdataset);
3730 if (result == DNS_R_UNCHANGED) {
3731 if (ANSWER(rdataset) &&
3732 ardataset != NULL &&
3733 ardataset->type == 0) {
3735 * The answer in the cache is better
3736 * than the answer we found, and is
3737 * a negative cache entry, so we
3738 * must set eresult appropriately.
3740 if (NXDOMAIN(ardataset))
3741 eresult =
3742 DNS_R_NCACHENXDOMAIN;
3743 else
3744 eresult =
3745 DNS_R_NCACHENXRRSET;
3747 result = ISC_R_SUCCESS;
3748 } else if (result != ISC_R_SUCCESS)
3749 break;
3753 if (valrdataset != NULL)
3754 result = valcreate(fctx, addrinfo, name, fctx->type,
3755 valrdataset, valsigrdataset, valoptions,
3756 task);
3758 if (result == ISC_R_SUCCESS && have_answer) {
3759 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3760 if (event != NULL) {
3761 event->result = eresult;
3762 dns_db_attach(fctx->cache, adbp);
3763 *anodep = node;
3764 node = NULL;
3765 clone_results(fctx);
3769 if (node != NULL)
3770 dns_db_detachnode(fctx->cache, &node);
3772 return (result);
3775 static inline isc_result_t
3776 cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now)
3778 isc_result_t result;
3779 dns_section_t section;
3780 dns_name_t *name;
3782 FCTXTRACE("cache_message");
3784 fctx->attributes &= ~FCTX_ATTR_WANTCACHE;
3786 LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3788 for (section = DNS_SECTION_ANSWER;
3789 section <= DNS_SECTION_ADDITIONAL;
3790 section++) {
3791 result = dns_message_firstname(fctx->rmessage, section);
3792 while (result == ISC_R_SUCCESS) {
3793 name = NULL;
3794 dns_message_currentname(fctx->rmessage, section,
3795 &name);
3796 if ((name->attributes & DNS_NAMEATTR_CACHE) != 0) {
3797 result = cache_name(fctx, name, addrinfo, now);
3798 if (result != ISC_R_SUCCESS)
3799 break;
3801 result = dns_message_nextname(fctx->rmessage, section);
3803 if (result != ISC_R_NOMORE)
3804 break;
3806 if (result == ISC_R_NOMORE)
3807 result = ISC_R_SUCCESS;
3809 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3811 return (result);
3815 * Do what dns_ncache_add() does, and then compute an appropriate eresult.
3817 static isc_result_t
3818 ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
3819 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
3820 dns_rdataset_t *ardataset,
3821 isc_result_t *eresultp)
3823 isc_result_t result;
3824 dns_rdataset_t rdataset;
3826 if (ardataset == NULL) {
3827 dns_rdataset_init(&rdataset);
3828 ardataset = &rdataset;
3830 result = dns_ncache_add(message, cache, node, covers, now,
3831 maxttl, ardataset);
3832 if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
3834 * If the cache now contains a negative entry and we
3835 * care about whether it is DNS_R_NCACHENXDOMAIN or
3836 * DNS_R_NCACHENXRRSET then extract it.
3838 if (ardataset->type == 0) {
3840 * The cache data is a negative cache entry.
3842 if (NXDOMAIN(ardataset))
3843 *eresultp = DNS_R_NCACHENXDOMAIN;
3844 else
3845 *eresultp = DNS_R_NCACHENXRRSET;
3846 } else {
3848 * Either we don't care about the nature of the
3849 * cache rdataset (because no fetch is interested
3850 * in the outcome), or the cache rdataset is not
3851 * a negative cache entry. Whichever case it is,
3852 * we can return success.
3854 * XXXRTH There's a CNAME/DNAME problem here.
3856 *eresultp = ISC_R_SUCCESS;
3858 result = ISC_R_SUCCESS;
3860 if (ardataset == &rdataset && dns_rdataset_isassociated(ardataset))
3861 dns_rdataset_disassociate(ardataset);
3863 return (result);
3866 static inline isc_result_t
3867 ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
3868 dns_rdatatype_t covers, isc_stdtime_t now)
3870 isc_result_t result, eresult;
3871 dns_name_t *name;
3872 dns_resolver_t *res;
3873 dns_db_t **adbp;
3874 dns_dbnode_t *node, **anodep;
3875 dns_rdataset_t *ardataset;
3876 isc_boolean_t need_validation, secure_domain;
3877 dns_name_t *aname;
3878 dns_fetchevent_t *event;
3879 isc_uint32_t ttl;
3880 unsigned int valoptions = 0;
3882 FCTXTRACE("ncache_message");
3884 fctx->attributes &= ~FCTX_ATTR_WANTNCACHE;
3886 res = fctx->res;
3887 need_validation = ISC_FALSE;
3888 secure_domain = ISC_FALSE;
3889 eresult = ISC_R_SUCCESS;
3890 name = &fctx->name;
3891 node = NULL;
3894 * XXXMPA remove when we follow cnames and adjust the setting
3895 * of FCTX_ATTR_WANTNCACHE in noanswer_response().
3897 INSIST(fctx->rmessage->counts[DNS_SECTION_ANSWER] == 0);
3900 * Is DNSSEC validation required for this name?
3902 result = dns_keytable_issecuredomain(res->view->secroots, name,
3903 &secure_domain);
3904 if (result != ISC_R_SUCCESS)
3905 return (result);
3907 if (!secure_domain && res->view->dlv != NULL) {
3908 valoptions = DNS_VALIDATOR_DLV;
3909 secure_domain = ISC_TRUE;
3912 if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
3913 need_validation = ISC_FALSE;
3914 else
3915 need_validation = secure_domain;
3917 if (secure_domain) {
3919 * Mark all rdatasets as pending.
3921 dns_rdataset_t *trdataset;
3922 dns_name_t *tname;
3924 result = dns_message_firstname(fctx->rmessage,
3925 DNS_SECTION_AUTHORITY);
3926 while (result == ISC_R_SUCCESS) {
3927 tname = NULL;
3928 dns_message_currentname(fctx->rmessage,
3929 DNS_SECTION_AUTHORITY,
3930 &tname);
3931 for (trdataset = ISC_LIST_HEAD(tname->list);
3932 trdataset != NULL;
3933 trdataset = ISC_LIST_NEXT(trdataset, link))
3934 trdataset->trust = dns_trust_pending;
3935 result = dns_message_nextname(fctx->rmessage,
3936 DNS_SECTION_AUTHORITY);
3938 if (result != ISC_R_NOMORE)
3939 return (result);
3943 if (need_validation) {
3945 * Do negative response validation.
3947 result = valcreate(fctx, addrinfo, name, fctx->type,
3948 NULL, NULL, valoptions,
3949 res->buckets[fctx->bucketnum].task);
3951 * If validation is necessary, return now. Otherwise continue
3952 * to process the message, letting the validation complete
3953 * in its own good time.
3955 return (result);
3958 LOCK(&res->buckets[fctx->bucketnum].lock);
3960 adbp = NULL;
3961 aname = NULL;
3962 anodep = NULL;
3963 ardataset = NULL;
3964 if (!HAVE_ANSWER(fctx)) {
3965 event = ISC_LIST_HEAD(fctx->events);
3966 if (event != NULL) {
3967 adbp = &event->db;
3968 aname = dns_fixedname_name(&event->foundname);
3969 result = dns_name_copy(name, aname, NULL);
3970 if (result != ISC_R_SUCCESS)
3971 goto unlock;
3972 anodep = &event->node;
3973 ardataset = event->rdataset;
3975 } else
3976 event = NULL;
3978 result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
3979 if (result != ISC_R_SUCCESS)
3980 goto unlock;
3983 * If we are asking for a SOA record set the cache time
3984 * to zero to facilitate locating the containing zone of
3985 * a arbitary zone.
3987 ttl = fctx->res->view->maxncachettl;
3988 if (fctx->type == dns_rdatatype_soa &&
3989 covers == dns_rdatatype_any)
3990 ttl = 0;
3992 result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
3993 covers, now, ttl, ardataset, &eresult);
3994 if (result != ISC_R_SUCCESS)
3995 goto unlock;
3997 if (!HAVE_ANSWER(fctx)) {
3998 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3999 if (event != NULL) {
4000 event->result = eresult;
4001 dns_db_attach(fctx->cache, adbp);
4002 *anodep = node;
4003 node = NULL;
4004 clone_results(fctx);
4008 unlock:
4009 UNLOCK(&res->buckets[fctx->bucketnum].lock);
4011 if (node != NULL)
4012 dns_db_detachnode(fctx->cache, &node);
4014 return (result);
4017 static inline void
4018 mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
4019 isc_boolean_t external, isc_boolean_t gluing)
4021 name->attributes |= DNS_NAMEATTR_CACHE;
4022 if (gluing) {
4023 rdataset->trust = dns_trust_glue;
4025 * Glue with 0 TTL causes problems. We force the TTL to
4026 * 1 second to prevent this.
4028 if (rdataset->ttl == 0)
4029 rdataset->ttl = 1;
4030 } else
4031 rdataset->trust = dns_trust_additional;
4033 * Avoid infinite loops by only marking new rdatasets.
4035 if (!CACHE(rdataset)) {
4036 name->attributes |= DNS_NAMEATTR_CHASE;
4037 rdataset->attributes |= DNS_RDATASETATTR_CHASE;
4039 rdataset->attributes |= DNS_RDATASETATTR_CACHE;
4040 if (external)
4041 rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
4044 static isc_result_t
4045 check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
4046 fetchctx_t *fctx = arg;
4047 isc_result_t result;
4048 dns_name_t *name;
4049 dns_rdataset_t *rdataset;
4050 isc_boolean_t external;
4051 dns_rdatatype_t rtype;
4052 isc_boolean_t gluing;
4054 REQUIRE(VALID_FCTX(fctx));
4056 if (GLUING(fctx))
4057 gluing = ISC_TRUE;
4058 else
4059 gluing = ISC_FALSE;
4060 name = NULL;
4061 rdataset = NULL;
4062 result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
4063 addname, dns_rdatatype_any, 0, &name,
4064 NULL);
4065 if (result == ISC_R_SUCCESS) {
4066 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
4067 if (type == dns_rdatatype_a) {
4068 for (rdataset = ISC_LIST_HEAD(name->list);
4069 rdataset != NULL;
4070 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4071 if (rdataset->type == dns_rdatatype_rrsig)
4072 rtype = rdataset->covers;
4073 else
4074 rtype = rdataset->type;
4075 if (rtype == dns_rdatatype_a ||
4076 rtype == dns_rdatatype_aaaa)
4077 mark_related(name, rdataset, external,
4078 gluing);
4080 } else {
4081 result = dns_message_findtype(name, type, 0,
4082 &rdataset);
4083 if (result == ISC_R_SUCCESS) {
4084 mark_related(name, rdataset, external, gluing);
4086 * Do we have its SIG too?
4088 rdataset = NULL;
4089 result = dns_message_findtype(name,
4090 dns_rdatatype_rrsig,
4091 type, &rdataset);
4092 if (result == ISC_R_SUCCESS)
4093 mark_related(name, rdataset, external,
4094 gluing);
4099 return (ISC_R_SUCCESS);
4102 static void
4103 chase_additional(fetchctx_t *fctx) {
4104 isc_boolean_t rescan;
4105 dns_section_t section = DNS_SECTION_ADDITIONAL;
4106 isc_result_t result;
4108 again:
4109 rescan = ISC_FALSE;
4111 for (result = dns_message_firstname(fctx->rmessage, section);
4112 result == ISC_R_SUCCESS;
4113 result = dns_message_nextname(fctx->rmessage, section)) {
4114 dns_name_t *name = NULL;
4115 dns_rdataset_t *rdataset;
4116 dns_message_currentname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
4117 &name);
4118 if ((name->attributes & DNS_NAMEATTR_CHASE) == 0)
4119 continue;
4120 name->attributes &= ~DNS_NAMEATTR_CHASE;
4121 for (rdataset = ISC_LIST_HEAD(name->list);
4122 rdataset != NULL;
4123 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4124 if (CHASE(rdataset)) {
4125 rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
4126 (void)dns_rdataset_additionaldata(rdataset,
4127 check_related,
4128 fctx);
4129 rescan = ISC_TRUE;
4133 if (rescan)
4134 goto again;
4137 static inline isc_result_t
4138 cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) {
4139 isc_result_t result;
4140 dns_rdata_t rdata = DNS_RDATA_INIT;
4141 dns_rdata_cname_t cname;
4143 result = dns_rdataset_first(rdataset);
4144 if (result != ISC_R_SUCCESS)
4145 return (result);
4146 dns_rdataset_current(rdataset, &rdata);
4147 result = dns_rdata_tostruct(&rdata, &cname, NULL);
4148 if (result != ISC_R_SUCCESS)
4149 return (result);
4150 dns_name_init(tname, NULL);
4151 dns_name_clone(&cname.cname, tname);
4152 dns_rdata_freestruct(&cname);
4154 return (ISC_R_SUCCESS);
4157 static inline isc_result_t
4158 dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
4159 dns_fixedname_t *fixeddname)
4161 isc_result_t result;
4162 dns_rdata_t rdata = DNS_RDATA_INIT;
4163 unsigned int nlabels;
4164 int order;
4165 dns_namereln_t namereln;
4166 dns_rdata_dname_t dname;
4167 dns_fixedname_t prefix;
4170 * Get the target name of the DNAME.
4173 result = dns_rdataset_first(rdataset);
4174 if (result != ISC_R_SUCCESS)
4175 return (result);
4176 dns_rdataset_current(rdataset, &rdata);
4177 result = dns_rdata_tostruct(&rdata, &dname, NULL);
4178 if (result != ISC_R_SUCCESS)
4179 return (result);
4182 * Get the prefix of qname.
4184 namereln = dns_name_fullcompare(qname, oname, &order, &nlabels);
4185 if (namereln != dns_namereln_subdomain) {
4186 dns_rdata_freestruct(&dname);
4187 return (DNS_R_FORMERR);
4189 dns_fixedname_init(&prefix);
4190 dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL);
4191 dns_fixedname_init(fixeddname);
4192 result = dns_name_concatenate(dns_fixedname_name(&prefix),
4193 &dname.dname,
4194 dns_fixedname_name(fixeddname), NULL);
4195 dns_rdata_freestruct(&dname);
4196 return (result);
4200 * Handle a no-answer response (NXDOMAIN, NXRRSET, or referral).
4201 * If bind8_ns_resp is ISC_TRUE, this is a suspected BIND 8
4202 * response to an NS query that should be treated as a referral
4203 * even though the NS records occur in the answer section
4204 * rather than the authority section.
4206 static isc_result_t
4207 noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
4208 isc_boolean_t bind8_ns_resp)
4210 isc_result_t result;
4211 dns_message_t *message;
4212 dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name;
4213 dns_rdataset_t *rdataset, *ns_rdataset;
4214 isc_boolean_t done, aa, negative_response;
4215 dns_rdatatype_t type;
4216 dns_section_t section =
4217 bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY;
4219 FCTXTRACE("noanswer_response");
4221 message = fctx->rmessage;
4224 * Setup qname.
4226 if (oqname == NULL) {
4228 * We have a normal, non-chained negative response or
4229 * referral.
4231 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
4232 aa = ISC_TRUE;
4233 else
4234 aa = ISC_FALSE;
4235 qname = &fctx->name;
4236 } else {
4238 * We're being invoked by answer_response() after it has
4239 * followed a CNAME/DNAME chain.
4241 qname = oqname;
4242 aa = ISC_FALSE;
4244 * If the current qname is not a subdomain of the query
4245 * domain, there's no point in looking at the authority
4246 * section without doing DNSSEC validation.
4248 * Until we do that validation, we'll just return success
4249 * in this case.
4251 if (!dns_name_issubdomain(qname, &fctx->domain))
4252 return (ISC_R_SUCCESS);
4256 * We have to figure out if this is a negative response, or a
4257 * referral.
4261 * Sometimes we can tell if its a negative response by looking at
4262 * the message header.
4264 negative_response = ISC_FALSE;
4265 if (message->rcode == dns_rcode_nxdomain ||
4266 (message->counts[DNS_SECTION_ANSWER] == 0 &&
4267 message->counts[DNS_SECTION_AUTHORITY] == 0))
4268 negative_response = ISC_TRUE;
4271 * Process the authority section.
4273 done = ISC_FALSE;
4274 ns_name = NULL;
4275 ns_rdataset = NULL;
4276 soa_name = NULL;
4277 ds_name = NULL;
4278 result = dns_message_firstname(message, section);
4279 while (!done && result == ISC_R_SUCCESS) {
4280 name = NULL;
4281 dns_message_currentname(message, section, &name);
4282 if (dns_name_issubdomain(name, &fctx->domain)) {
4284 * Look for NS/SOA RRsets first.
4286 for (rdataset = ISC_LIST_HEAD(name->list);
4287 rdataset != NULL;
4288 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4289 type = rdataset->type;
4290 if (type == dns_rdatatype_rrsig)
4291 type = rdataset->covers;
4292 if (((type == dns_rdatatype_ns ||
4293 type == dns_rdatatype_soa) &&
4294 !dns_name_issubdomain(qname, name)))
4295 return (DNS_R_FORMERR);
4296 if (type == dns_rdatatype_ns) {
4298 * NS or RRSIG NS.
4300 * Only one set of NS RRs is allowed.
4302 if (rdataset->type ==
4303 dns_rdatatype_ns) {
4304 if (ns_name != NULL &&
4305 name != ns_name)
4306 return (DNS_R_FORMERR);
4307 ns_name = name;
4308 ns_rdataset = rdataset;
4310 name->attributes |=
4311 DNS_NAMEATTR_CACHE;
4312 rdataset->attributes |=
4313 DNS_RDATASETATTR_CACHE;
4314 rdataset->trust = dns_trust_glue;
4316 if (type == dns_rdatatype_soa) {
4318 * SOA, or RRSIG SOA.
4320 * Only one SOA is allowed.
4322 if (rdataset->type ==
4323 dns_rdatatype_soa) {
4324 if (soa_name != NULL &&
4325 name != soa_name)
4326 return (DNS_R_FORMERR);
4327 soa_name = name;
4329 name->attributes |=
4330 DNS_NAMEATTR_NCACHE;
4331 rdataset->attributes |=
4332 DNS_RDATASETATTR_NCACHE;
4333 if (aa)
4334 rdataset->trust =
4335 dns_trust_authauthority;
4336 else
4337 rdataset->trust =
4338 dns_trust_additional;
4342 * A negative response has a SOA record (Type 2)
4343 * and a optional NS RRset (Type 1) or it has neither
4344 * a SOA or a NS RRset (Type 3, handled above) or
4345 * rcode is NXDOMAIN (handled above) in which case
4346 * the NS RRset is allowed (Type 4).
4348 if (soa_name != NULL)
4349 negative_response = ISC_TRUE;
4350 for (rdataset = ISC_LIST_HEAD(name->list);
4351 rdataset != NULL;
4352 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4353 type = rdataset->type;
4354 if (type == dns_rdatatype_rrsig)
4355 type = rdataset->covers;
4356 if (type == dns_rdatatype_nsec) {
4358 * NSEC or RRSIG NSEC.
4360 if (negative_response) {
4361 name->attributes |=
4362 DNS_NAMEATTR_NCACHE;
4363 rdataset->attributes |=
4364 DNS_RDATASETATTR_NCACHE;
4365 } else {
4366 name->attributes |=
4367 DNS_NAMEATTR_CACHE;
4368 rdataset->attributes |=
4369 DNS_RDATASETATTR_CACHE;
4371 if (aa)
4372 rdataset->trust =
4373 dns_trust_authauthority;
4374 else
4375 rdataset->trust =
4376 dns_trust_additional;
4378 * No additional data needs to be
4379 * marked.
4381 } else if (type == dns_rdatatype_ds) {
4383 * DS or SIG DS.
4385 * These should only be here if
4386 * this is a referral, and there
4387 * should only be one DS.
4389 if (ns_name == NULL)
4390 return (DNS_R_FORMERR);
4391 if (rdataset->type ==
4392 dns_rdatatype_ds) {
4393 if (ds_name != NULL &&
4394 name != ds_name)
4395 return (DNS_R_FORMERR);
4396 ds_name = name;
4398 name->attributes |=
4399 DNS_NAMEATTR_CACHE;
4400 rdataset->attributes |=
4401 DNS_RDATASETATTR_CACHE;
4402 if (aa)
4403 rdataset->trust =
4404 dns_trust_authauthority;
4405 else
4406 rdataset->trust =
4407 dns_trust_additional;
4411 result = dns_message_nextname(message, section);
4412 if (result == ISC_R_NOMORE)
4413 break;
4414 else if (result != ISC_R_SUCCESS)
4415 return (result);
4419 * Trigger lookups for DNS nameservers.
4421 if (negative_response && message->rcode == dns_rcode_noerror &&
4422 fctx->type == dns_rdatatype_ds && soa_name != NULL &&
4423 dns_name_equal(soa_name, qname) &&
4424 !dns_name_equal(qname, dns_rootname))
4425 return (DNS_R_CHASEDSSERVERS);
4428 * Did we find anything?
4430 if (!negative_response && ns_name == NULL) {
4432 * Nope.
4434 if (oqname != NULL) {
4436 * We've already got a partial CNAME/DNAME chain,
4437 * and haven't found else anything useful here, but
4438 * no error has occurred since we have an answer.
4440 return (ISC_R_SUCCESS);
4441 } else {
4443 * The responder is insane.
4445 return (DNS_R_FORMERR);
4450 * If we found both NS and SOA, they should be the same name.
4452 if (ns_name != NULL && soa_name != NULL && ns_name != soa_name)
4453 return (DNS_R_FORMERR);
4456 * Do we have a referral? (We only want to follow a referral if
4457 * we're not following a chain.)
4459 if (!negative_response && ns_name != NULL && oqname == NULL) {
4461 * We already know ns_name is a subdomain of fctx->domain.
4462 * If ns_name is equal to fctx->domain, we're not making
4463 * progress. We return DNS_R_FORMERR so that we'll keep
4464 * trying other servers.
4466 if (dns_name_equal(ns_name, &fctx->domain))
4467 return (DNS_R_FORMERR);
4470 * If the referral name is not a parent of the query
4471 * name, consider the responder insane.
4473 if (! dns_name_issubdomain(&fctx->name, ns_name)) {
4474 FCTXTRACE("referral to non-parent");
4475 return (DNS_R_FORMERR);
4479 * Mark any additional data related to this rdataset.
4480 * It's important that we do this before we change the
4481 * query domain.
4483 INSIST(ns_rdataset != NULL);
4484 fctx->attributes |= FCTX_ATTR_GLUING;
4485 (void)dns_rdataset_additionaldata(ns_rdataset, check_related,
4486 fctx);
4487 fctx->attributes &= ~FCTX_ATTR_GLUING;
4489 * NS rdatasets with 0 TTL cause problems.
4490 * dns_view_findzonecut() will not find them when we
4491 * try to follow the referral, and we'll SERVFAIL
4492 * because the best nameservers are now above QDOMAIN.
4493 * We force the TTL to 1 second to prevent this.
4495 if (ns_rdataset->ttl == 0)
4496 ns_rdataset->ttl = 1;
4498 * Set the current query domain to the referral name.
4500 * XXXRTH We should check if we're in forward-only mode, and
4501 * if so we should bail out.
4503 INSIST(dns_name_countlabels(&fctx->domain) > 0);
4504 dns_name_free(&fctx->domain, fctx->res->mctx);
4505 if (dns_rdataset_isassociated(&fctx->nameservers))
4506 dns_rdataset_disassociate(&fctx->nameservers);
4507 dns_name_init(&fctx->domain, NULL);
4508 result = dns_name_dup(ns_name, fctx->res->mctx, &fctx->domain);
4509 if (result != ISC_R_SUCCESS)
4510 return (result);
4511 fctx->attributes |= FCTX_ATTR_WANTCACHE;
4512 return (DNS_R_DELEGATION);
4516 * Since we're not doing a referral, we don't want to cache any
4517 * NS RRs we may have found.
4519 if (ns_name != NULL)
4520 ns_name->attributes &= ~DNS_NAMEATTR_CACHE;
4522 if (negative_response && oqname == NULL)
4523 fctx->attributes |= FCTX_ATTR_WANTNCACHE;
4525 return (ISC_R_SUCCESS);
4528 static isc_result_t
4529 answer_response(fetchctx_t *fctx) {
4530 isc_result_t result;
4531 dns_message_t *message;
4532 dns_name_t *name, *qname, tname;
4533 dns_rdataset_t *rdataset;
4534 isc_boolean_t done, external, chaining, aa, found, want_chaining;
4535 isc_boolean_t have_answer, found_cname, found_type, wanted_chaining;
4536 unsigned int aflag;
4537 dns_rdatatype_t type;
4538 dns_fixedname_t dname, fqname;
4540 FCTXTRACE("answer_response");
4542 message = fctx->rmessage;
4545 * Examine the answer section, marking those rdatasets which are
4546 * part of the answer and should be cached.
4549 done = ISC_FALSE;
4550 found_cname = ISC_FALSE;
4551 found_type = ISC_FALSE;
4552 chaining = ISC_FALSE;
4553 have_answer = ISC_FALSE;
4554 want_chaining = ISC_FALSE;
4555 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
4556 aa = ISC_TRUE;
4557 else
4558 aa = ISC_FALSE;
4559 qname = &fctx->name;
4560 type = fctx->type;
4561 result = dns_message_firstname(message, DNS_SECTION_ANSWER);
4562 while (!done && result == ISC_R_SUCCESS) {
4563 name = NULL;
4564 dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
4565 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
4566 if (dns_name_equal(name, qname)) {
4567 wanted_chaining = ISC_FALSE;
4568 for (rdataset = ISC_LIST_HEAD(name->list);
4569 rdataset != NULL;
4570 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4571 found = ISC_FALSE;
4572 want_chaining = ISC_FALSE;
4573 aflag = 0;
4574 if (rdataset->type == type && !found_cname) {
4576 * We've found an ordinary answer.
4578 found = ISC_TRUE;
4579 found_type = ISC_TRUE;
4580 done = ISC_TRUE;
4581 aflag = DNS_RDATASETATTR_ANSWER;
4582 } else if (type == dns_rdatatype_any) {
4584 * We've found an answer matching
4585 * an ANY query. There may be
4586 * more.
4588 found = ISC_TRUE;
4589 aflag = DNS_RDATASETATTR_ANSWER;
4590 } else if (rdataset->type == dns_rdatatype_rrsig
4591 && rdataset->covers == type
4592 && !found_cname) {
4594 * We've found a signature that
4595 * covers the type we're looking for.
4597 found = ISC_TRUE;
4598 found_type = ISC_TRUE;
4599 aflag = DNS_RDATASETATTR_ANSWERSIG;
4600 } else if (rdataset->type ==
4601 dns_rdatatype_cname
4602 && !found_type) {
4604 * We're looking for something else,
4605 * but we found a CNAME.
4607 * Getting a CNAME response for some
4608 * query types is an error.
4610 if (type == dns_rdatatype_rrsig ||
4611 type == dns_rdatatype_dnskey ||
4612 type == dns_rdatatype_nsec)
4613 return (DNS_R_FORMERR);
4614 found = ISC_TRUE;
4615 found_cname = ISC_TRUE;
4616 want_chaining = ISC_TRUE;
4617 aflag = DNS_RDATASETATTR_ANSWER;
4618 result = cname_target(rdataset,
4619 &tname);
4620 if (result != ISC_R_SUCCESS)
4621 return (result);
4622 } else if (rdataset->type == dns_rdatatype_rrsig
4623 && rdataset->covers ==
4624 dns_rdatatype_cname
4625 && !found_type) {
4627 * We're looking for something else,
4628 * but we found a SIG CNAME.
4630 found = ISC_TRUE;
4631 found_cname = ISC_TRUE;
4632 aflag = DNS_RDATASETATTR_ANSWERSIG;
4635 if (found) {
4637 * We've found an answer to our
4638 * question.
4640 name->attributes |=
4641 DNS_NAMEATTR_CACHE;
4642 rdataset->attributes |=
4643 DNS_RDATASETATTR_CACHE;
4644 rdataset->trust = dns_trust_answer;
4645 if (!chaining) {
4647 * This data is "the" answer
4648 * to our question only if
4649 * we're not chaining (i.e.
4650 * if we haven't followed
4651 * a CNAME or DNAME).
4653 INSIST(!external);
4654 if (aflag ==
4655 DNS_RDATASETATTR_ANSWER)
4656 have_answer = ISC_TRUE;
4657 name->attributes |=
4658 DNS_NAMEATTR_ANSWER;
4659 rdataset->attributes |= aflag;
4660 if (aa)
4661 rdataset->trust =
4662 dns_trust_authanswer;
4663 } else if (external) {
4665 * This data is outside of
4666 * our query domain, and
4667 * may only be cached if it
4668 * comes from a secure zone
4669 * and validates.
4671 rdataset->attributes |=
4672 DNS_RDATASETATTR_EXTERNAL;
4676 * Mark any additional data related
4677 * to this rdataset.
4679 (void)dns_rdataset_additionaldata(
4680 rdataset,
4681 check_related,
4682 fctx);
4685 * CNAME chaining.
4687 if (want_chaining) {
4688 wanted_chaining = ISC_TRUE;
4689 name->attributes |=
4690 DNS_NAMEATTR_CHAINING;
4691 rdataset->attributes |=
4692 DNS_RDATASETATTR_CHAINING;
4693 qname = &tname;
4697 * We could add an "else" clause here and
4698 * log that we're ignoring this rdataset.
4702 * If wanted_chaining is true, we've done
4703 * some chaining as the result of processing
4704 * this node, and thus we need to set
4705 * chaining to true.
4707 * We don't set chaining inside of the
4708 * rdataset loop because doing that would
4709 * cause us to ignore the signatures of
4710 * CNAMEs.
4712 if (wanted_chaining)
4713 chaining = ISC_TRUE;
4714 } else {
4716 * Look for a DNAME (or its SIG). Anything else is
4717 * ignored.
4719 wanted_chaining = ISC_FALSE;
4720 for (rdataset = ISC_LIST_HEAD(name->list);
4721 rdataset != NULL;
4722 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4723 isc_boolean_t found_dname = ISC_FALSE;
4724 found = ISC_FALSE;
4725 aflag = 0;
4726 if (rdataset->type == dns_rdatatype_dname) {
4728 * We're looking for something else,
4729 * but we found a DNAME.
4731 * If we're not chaining, then the
4732 * DNAME should not be external.
4734 if (!chaining && external)
4735 return (DNS_R_FORMERR);
4736 found = ISC_TRUE;
4737 want_chaining = ISC_TRUE;
4738 aflag = DNS_RDATASETATTR_ANSWER;
4739 result = dname_target(rdataset,
4740 qname, name,
4741 &dname);
4742 if (result == ISC_R_NOSPACE) {
4744 * We can't construct the
4745 * DNAME target. Do not
4746 * try to continue.
4748 want_chaining = ISC_FALSE;
4749 } else if (result != ISC_R_SUCCESS)
4750 return (result);
4751 else
4752 found_dname = ISC_TRUE;
4753 } else if (rdataset->type == dns_rdatatype_rrsig
4754 && rdataset->covers ==
4755 dns_rdatatype_dname) {
4757 * We've found a signature that
4758 * covers the DNAME.
4760 found = ISC_TRUE;
4761 aflag = DNS_RDATASETATTR_ANSWERSIG;
4764 if (found) {
4766 * We've found an answer to our
4767 * question.
4769 name->attributes |=
4770 DNS_NAMEATTR_CACHE;
4771 rdataset->attributes |=
4772 DNS_RDATASETATTR_CACHE;
4773 rdataset->trust = dns_trust_answer;
4774 if (!chaining) {
4776 * This data is "the" answer
4777 * to our question only if
4778 * we're not chaining.
4780 INSIST(!external);
4781 if (aflag ==
4782 DNS_RDATASETATTR_ANSWER)
4783 have_answer = ISC_TRUE;
4784 name->attributes |=
4785 DNS_NAMEATTR_ANSWER;
4786 rdataset->attributes |= aflag;
4787 if (aa)
4788 rdataset->trust =
4789 dns_trust_authanswer;
4790 } else if (external) {
4791 rdataset->attributes |=
4792 DNS_RDATASETATTR_EXTERNAL;
4796 * DNAME chaining.
4798 if (found_dname) {
4800 * Copy the the dname into the
4801 * qname fixed name.
4803 * Although we check for
4804 * failure of the copy
4805 * operation, in practice it
4806 * should never fail since
4807 * we already know that the
4808 * result fits in a fixedname.
4810 dns_fixedname_init(&fqname);
4811 result = dns_name_copy(
4812 dns_fixedname_name(&dname),
4813 dns_fixedname_name(&fqname),
4814 NULL);
4815 if (result != ISC_R_SUCCESS)
4816 return (result);
4817 wanted_chaining = ISC_TRUE;
4818 name->attributes |=
4819 DNS_NAMEATTR_CHAINING;
4820 rdataset->attributes |=
4821 DNS_RDATASETATTR_CHAINING;
4822 qname = dns_fixedname_name(
4823 &fqname);
4827 if (wanted_chaining)
4828 chaining = ISC_TRUE;
4830 result = dns_message_nextname(message, DNS_SECTION_ANSWER);
4832 if (result == ISC_R_NOMORE)
4833 result = ISC_R_SUCCESS;
4834 if (result != ISC_R_SUCCESS)
4835 return (result);
4838 * We should have found an answer.
4840 if (!have_answer)
4841 return (DNS_R_FORMERR);
4844 * This response is now potentially cacheable.
4846 fctx->attributes |= FCTX_ATTR_WANTCACHE;
4849 * Did chaining end before we got the final answer?
4851 if (chaining) {
4853 * Yes. This may be a negative reply, so hand off
4854 * authority section processing to the noanswer code.
4855 * If it isn't a noanswer response, no harm will be
4856 * done.
4858 return (noanswer_response(fctx, qname, ISC_FALSE));
4862 * We didn't end with an incomplete chain, so the rcode should be
4863 * "no error".
4865 if (message->rcode != dns_rcode_noerror)
4866 return (DNS_R_FORMERR);
4869 * Examine the authority section (if there is one).
4871 * We expect there to be only one owner name for all the rdatasets
4872 * in this section, and we expect that it is not external.
4874 done = ISC_FALSE;
4875 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
4876 while (!done && result == ISC_R_SUCCESS) {
4877 name = NULL;
4878 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
4879 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
4880 if (!external) {
4882 * We expect to find NS or SIG NS rdatasets, and
4883 * nothing else.
4885 for (rdataset = ISC_LIST_HEAD(name->list);
4886 rdataset != NULL;
4887 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4888 if (rdataset->type == dns_rdatatype_ns ||
4889 (rdataset->type == dns_rdatatype_rrsig &&
4890 rdataset->covers == dns_rdatatype_ns)) {
4891 name->attributes |=
4892 DNS_NAMEATTR_CACHE;
4893 rdataset->attributes |=
4894 DNS_RDATASETATTR_CACHE;
4895 if (aa && !chaining)
4896 rdataset->trust =
4897 dns_trust_authauthority;
4898 else
4899 rdataset->trust =
4900 dns_trust_additional;
4903 * Mark any additional data related
4904 * to this rdataset.
4906 (void)dns_rdataset_additionaldata(
4907 rdataset,
4908 check_related,
4909 fctx);
4910 done = ISC_TRUE;
4914 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
4916 if (result == ISC_R_NOMORE)
4917 result = ISC_R_SUCCESS;
4919 return (result);
4922 static void
4923 resume_dslookup(isc_task_t *task, isc_event_t *event) {
4924 dns_fetchevent_t *fevent;
4925 dns_resolver_t *res;
4926 fetchctx_t *fctx;
4927 isc_result_t result;
4928 isc_boolean_t bucket_empty = ISC_FALSE;
4929 isc_boolean_t locked = ISC_FALSE;
4930 unsigned int bucketnum;
4931 dns_rdataset_t nameservers;
4932 dns_fixedname_t fixed;
4933 dns_name_t *domain;
4935 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
4936 fevent = (dns_fetchevent_t *)event;
4937 fctx = event->ev_arg;
4938 REQUIRE(VALID_FCTX(fctx));
4939 res = fctx->res;
4941 UNUSED(task);
4942 FCTXTRACE("resume_dslookup");
4944 if (fevent->node != NULL)
4945 dns_db_detachnode(fevent->db, &fevent->node);
4946 if (fevent->db != NULL)
4947 dns_db_detach(&fevent->db);
4949 dns_rdataset_init(&nameservers);
4951 bucketnum = fctx->bucketnum;
4952 if (fevent->result == ISC_R_CANCELED) {
4953 dns_resolver_destroyfetch(&fctx->nsfetch);
4954 fctx_done(fctx, ISC_R_CANCELED);
4955 } else if (fevent->result == ISC_R_SUCCESS) {
4957 FCTXTRACE("resuming DS lookup");
4959 dns_resolver_destroyfetch(&fctx->nsfetch);
4960 if (dns_rdataset_isassociated(&fctx->nameservers))
4961 dns_rdataset_disassociate(&fctx->nameservers);
4962 dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
4963 dns_name_free(&fctx->domain, fctx->res->mctx);
4964 dns_name_init(&fctx->domain, NULL);
4965 result = dns_name_dup(&fctx->nsname, fctx->res->mctx,
4966 &fctx->domain);
4967 if (result != ISC_R_SUCCESS) {
4968 fctx_done(fctx, DNS_R_SERVFAIL);
4969 goto cleanup;
4972 * Try again.
4974 fctx_try(fctx);
4975 } else {
4976 unsigned int n;
4977 dns_rdataset_t *nsrdataset = NULL;
4980 * Retrieve state from fctx->nsfetch before we destroy it.
4982 dns_fixedname_init(&fixed);
4983 domain = dns_fixedname_name(&fixed);
4984 dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL);
4985 if (dns_name_equal(&fctx->nsname, domain)) {
4986 fctx_done(fctx, DNS_R_SERVFAIL);
4987 dns_resolver_destroyfetch(&fctx->nsfetch);
4988 goto cleanup;
4990 if (dns_rdataset_isassociated(
4991 &fctx->nsfetch->private->nameservers)) {
4992 dns_rdataset_clone(
4993 &fctx->nsfetch->private->nameservers,
4994 &nameservers);
4995 nsrdataset = &nameservers;
4996 } else
4997 domain = NULL;
4998 dns_resolver_destroyfetch(&fctx->nsfetch);
4999 n = dns_name_countlabels(&fctx->nsname);
5000 dns_name_getlabelsequence(&fctx->nsname, 1, n - 1,
5001 &fctx->nsname);
5003 if (dns_rdataset_isassociated(fevent->rdataset))
5004 dns_rdataset_disassociate(fevent->rdataset);
5005 FCTXTRACE("continuing to look for parent's NS records");
5006 result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
5007 dns_rdatatype_ns, domain,
5008 nsrdataset, NULL, 0, task,
5009 resume_dslookup, fctx,
5010 &fctx->nsrrset, NULL,
5011 &fctx->nsfetch);
5012 if (result != ISC_R_SUCCESS)
5013 fctx_done(fctx, result);
5014 else {
5015 LOCK(&res->buckets[bucketnum].lock);
5016 locked = ISC_TRUE;
5017 fctx->references++;
5021 cleanup:
5022 if (dns_rdataset_isassociated(&nameservers))
5023 dns_rdataset_disassociate(&nameservers);
5024 if (dns_rdataset_isassociated(fevent->rdataset))
5025 dns_rdataset_disassociate(fevent->rdataset);
5026 INSIST(fevent->sigrdataset == NULL);
5027 isc_event_free(&event);
5028 if (!locked)
5029 LOCK(&res->buckets[bucketnum].lock);
5030 fctx->references--;
5031 if (fctx->references == 0)
5032 bucket_empty = fctx_destroy(fctx);
5033 UNLOCK(&res->buckets[bucketnum].lock);
5034 if (bucket_empty)
5035 empty_bucket(res);
5038 static inline void
5039 checknamessection(dns_message_t *message, dns_section_t section) {
5040 isc_result_t result;
5041 dns_name_t *name;
5042 dns_rdata_t rdata = DNS_RDATA_INIT;
5043 dns_rdataset_t *rdataset;
5045 for (result = dns_message_firstname(message, section);
5046 result == ISC_R_SUCCESS;
5047 result = dns_message_nextname(message, section))
5049 name = NULL;
5050 dns_message_currentname(message, section, &name);
5051 for (rdataset = ISC_LIST_HEAD(name->list);
5052 rdataset != NULL;
5053 rdataset = ISC_LIST_NEXT(rdataset, link)) {
5054 for (result = dns_rdataset_first(rdataset);
5055 result == ISC_R_SUCCESS;
5056 result = dns_rdataset_next(rdataset)) {
5057 dns_rdataset_current(rdataset, &rdata);
5058 if (!dns_rdata_checkowner(name, rdata.rdclass,
5059 rdata.type,
5060 ISC_FALSE) ||
5061 !dns_rdata_checknames(&rdata, name, NULL))
5063 rdataset->attributes |=
5064 DNS_RDATASETATTR_CHECKNAMES;
5066 dns_rdata_reset(&rdata);
5072 static void
5073 checknames(dns_message_t *message) {
5075 checknamessection(message, DNS_SECTION_ANSWER);
5076 checknamessection(message, DNS_SECTION_AUTHORITY);
5077 checknamessection(message, DNS_SECTION_ADDITIONAL);
5080 static void
5081 log_packet(dns_message_t *message, int level, isc_mem_t *mctx) {
5082 isc_buffer_t buffer;
5083 char *buf = NULL;
5084 int len = 1024;
5085 isc_result_t result;
5087 if (! isc_log_wouldlog(dns_lctx, level))
5088 return;
5091 * Note that these are multiline debug messages. We want a newline
5092 * to appear in the log after each message.
5095 do {
5096 buf = isc_mem_get(mctx, len);
5097 if (buf == NULL)
5098 break;
5099 isc_buffer_init(&buffer, buf, len);
5100 result = dns_message_totext(message, &dns_master_style_debug,
5101 0, &buffer);
5102 if (result == ISC_R_NOSPACE) {
5103 isc_mem_put(mctx, buf, len);
5104 len += 1024;
5105 } else if (result == ISC_R_SUCCESS)
5106 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
5107 DNS_LOGMODULE_RESOLVER, level,
5108 "received packet:\n%.*s",
5109 (int)isc_buffer_usedlength(&buffer),
5110 buf);
5111 } while (result == ISC_R_NOSPACE);
5113 if (buf != NULL)
5114 isc_mem_put(mctx, buf, len);
5117 static void
5118 resquery_response(isc_task_t *task, isc_event_t *event) {
5119 isc_result_t result = ISC_R_SUCCESS;
5120 resquery_t *query = event->ev_arg;
5121 dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
5122 isc_boolean_t keep_trying, get_nameservers, resend;
5123 isc_boolean_t truncated;
5124 dns_message_t *message;
5125 fetchctx_t *fctx;
5126 dns_name_t *fname;
5127 dns_fixedname_t foundname;
5128 isc_stdtime_t now;
5129 isc_time_t tnow, *finish;
5130 dns_adbaddrinfo_t *addrinfo;
5131 unsigned int options;
5132 unsigned int findoptions;
5133 isc_result_t broken_server;
5135 REQUIRE(VALID_QUERY(query));
5136 fctx = query->fctx;
5137 options = query->options;
5138 REQUIRE(VALID_FCTX(fctx));
5139 REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
5141 QTRACE("response");
5143 (void)isc_timer_touch(fctx->timer);
5145 keep_trying = ISC_FALSE;
5146 broken_server = ISC_R_SUCCESS;
5147 get_nameservers = ISC_FALSE;
5148 resend = ISC_FALSE;
5149 truncated = ISC_FALSE;
5150 finish = NULL;
5152 if (fctx->res->exiting) {
5153 result = ISC_R_SHUTTINGDOWN;
5154 goto done;
5157 fctx->timeouts = 0;
5160 * XXXRTH We should really get the current time just once. We
5161 * need a routine to convert from an isc_time_t to an
5162 * isc_stdtime_t.
5164 TIME_NOW(&tnow);
5165 finish = &tnow;
5166 isc_stdtime_get(&now);
5169 * Did the dispatcher have a problem?
5171 if (devent->result != ISC_R_SUCCESS) {
5172 if (devent->result == ISC_R_EOF &&
5173 (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
5175 * The problem might be that they
5176 * don't understand EDNS0. Turn it
5177 * off and try again.
5179 options |= DNS_FETCHOPT_NOEDNS0;
5180 resend = ISC_TRUE;
5182 * Remember that they don't like EDNS0.
5184 dns_adb_changeflags(fctx->adb,
5185 query->addrinfo,
5186 DNS_FETCHOPT_NOEDNS0,
5187 DNS_FETCHOPT_NOEDNS0);
5188 } else {
5190 * There's no hope for this query.
5192 keep_trying = ISC_TRUE;
5194 goto done;
5197 message = fctx->rmessage;
5199 if (query->tsig != NULL) {
5200 result = dns_message_setquerytsig(message, query->tsig);
5201 if (result != ISC_R_SUCCESS)
5202 goto done;
5205 if (query->tsigkey) {
5206 result = dns_message_settsigkey(message, query->tsigkey);
5207 if (result != ISC_R_SUCCESS)
5208 goto done;
5211 result = dns_message_parse(message, &devent->buffer, 0);
5212 if (result != ISC_R_SUCCESS) {
5213 switch (result) {
5214 case ISC_R_UNEXPECTEDEND:
5215 if (!message->question_ok ||
5216 (message->flags & DNS_MESSAGEFLAG_TC) == 0 ||
5217 (options & DNS_FETCHOPT_TCP) != 0) {
5219 * Either the message ended prematurely,
5220 * and/or wasn't marked as being truncated,
5221 * and/or this is a response to a query we
5222 * sent over TCP. In all of these cases,
5223 * something is wrong with the remote
5224 * server and we don't want to retry using
5225 * TCP.
5227 if ((query->options & DNS_FETCHOPT_NOEDNS0)
5228 == 0) {
5230 * The problem might be that they
5231 * don't understand EDNS0. Turn it
5232 * off and try again.
5234 options |= DNS_FETCHOPT_NOEDNS0;
5235 resend = ISC_TRUE;
5237 * Remember that they don't like EDNS0.
5239 dns_adb_changeflags(
5240 fctx->adb,
5241 query->addrinfo,
5242 DNS_FETCHOPT_NOEDNS0,
5243 DNS_FETCHOPT_NOEDNS0);
5244 } else {
5245 broken_server = result;
5246 keep_trying = ISC_TRUE;
5248 goto done;
5251 * We defer retrying via TCP for a bit so we can
5252 * check out this message further.
5254 truncated = ISC_TRUE;
5255 break;
5256 case DNS_R_FORMERR:
5257 if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
5259 * The problem might be that they
5260 * don't understand EDNS0. Turn it
5261 * off and try again.
5263 options |= DNS_FETCHOPT_NOEDNS0;
5264 resend = ISC_TRUE;
5266 * Remember that they don't like EDNS0.
5268 dns_adb_changeflags(fctx->adb,
5269 query->addrinfo,
5270 DNS_FETCHOPT_NOEDNS0,
5271 DNS_FETCHOPT_NOEDNS0);
5272 } else {
5273 broken_server = DNS_R_UNEXPECTEDRCODE;
5274 keep_trying = ISC_TRUE;
5276 goto done;
5277 default:
5279 * Something bad has happened.
5281 goto done;
5286 * Log the incoming packet.
5288 log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx);
5291 * If the message is signed, check the signature. If not, this
5292 * returns success anyway.
5294 result = dns_message_checksig(message, fctx->res->view);
5295 if (result != ISC_R_SUCCESS)
5296 goto done;
5299 * The dispatcher should ensure we only get responses with QR set.
5301 INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0);
5303 * INSIST() that the message comes from the place we sent it to,
5304 * since the dispatch code should ensure this.
5306 * INSIST() that the message id is correct (this should also be
5307 * ensured by the dispatch code).
5312 * Deal with truncated responses by retrying using TCP.
5314 if ((message->flags & DNS_MESSAGEFLAG_TC) != 0)
5315 truncated = ISC_TRUE;
5317 if (truncated) {
5318 if ((options & DNS_FETCHOPT_TCP) != 0) {
5319 broken_server = DNS_R_TRUNCATEDTCP;
5320 keep_trying = ISC_TRUE;
5321 } else {
5322 options |= DNS_FETCHOPT_TCP;
5323 resend = ISC_TRUE;
5325 goto done;
5329 * Is it a query response?
5331 if (message->opcode != dns_opcode_query) {
5332 /* XXXRTH Log */
5333 broken_server = DNS_R_UNEXPECTEDOPCODE;
5334 keep_trying = ISC_TRUE;
5335 goto done;
5339 * Is the remote server broken, or does it dislike us?
5341 if (message->rcode != dns_rcode_noerror &&
5342 message->rcode != dns_rcode_nxdomain) {
5343 if ((message->rcode == dns_rcode_formerr ||
5344 message->rcode == dns_rcode_notimp ||
5345 message->rcode == dns_rcode_servfail) &&
5346 (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
5348 * It's very likely they don't like EDNS0.
5350 * XXXRTH We should check if the question
5351 * we're asking requires EDNS0, and
5352 * if so, we should bail out.
5354 options |= DNS_FETCHOPT_NOEDNS0;
5355 resend = ISC_TRUE;
5357 * Remember that they don't like EDNS0.
5359 if (message->rcode != dns_rcode_servfail)
5360 dns_adb_changeflags(fctx->adb, query->addrinfo,
5361 DNS_FETCHOPT_NOEDNS0,
5362 DNS_FETCHOPT_NOEDNS0);
5363 } else if (message->rcode == dns_rcode_formerr) {
5364 if (ISFORWARDER(query->addrinfo)) {
5366 * This forwarder doesn't understand us,
5367 * but other forwarders might. Keep trying.
5369 broken_server = DNS_R_REMOTEFORMERR;
5370 keep_trying = ISC_TRUE;
5371 } else {
5373 * The server doesn't understand us. Since
5374 * all servers for a zone need similar
5375 * capabilities, we assume that we will get
5376 * FORMERR from all servers, and thus we
5377 * cannot make any more progress with this
5378 * fetch.
5380 result = DNS_R_FORMERR;
5382 } else if (message->rcode == dns_rcode_yxdomain) {
5384 * DNAME mapping failed because the new name
5385 * was too long. There's no chance of success
5386 * for this fetch.
5388 result = DNS_R_YXDOMAIN;
5389 } else {
5391 * XXXRTH log.
5393 broken_server = DNS_R_UNEXPECTEDRCODE;
5394 INSIST(broken_server != ISC_R_SUCCESS);
5395 keep_trying = ISC_TRUE;
5397 goto done;
5401 * Is the question the same as the one we asked?
5403 result = same_question(fctx);
5404 if (result != ISC_R_SUCCESS) {
5405 /* XXXRTH Log */
5406 if (result == DNS_R_FORMERR)
5407 keep_trying = ISC_TRUE;
5408 goto done;
5412 * Is the server lame?
5414 if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) &&
5415 is_lame(fctx)) {
5416 log_lame(fctx, query->addrinfo);
5417 result = dns_adb_marklame(fctx->adb, query->addrinfo,
5418 &fctx->domain,
5419 now + fctx->res->lame_ttl);
5420 if (result != ISC_R_SUCCESS)
5421 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
5422 DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
5423 "could not mark server as lame: %s",
5424 isc_result_totext(result));
5425 broken_server = DNS_R_LAME;
5426 keep_trying = ISC_TRUE;
5427 goto done;
5431 * Enforce delegations only zones like NET and COM.
5433 if (!ISFORWARDER(query->addrinfo) &&
5434 dns_view_isdelegationonly(fctx->res->view, &fctx->domain) &&
5435 !dns_name_equal(&fctx->domain, &fctx->name) &&
5436 fix_mustbedelegationornxdomain(message, fctx)) {
5437 char namebuf[DNS_NAME_FORMATSIZE];
5438 char domainbuf[DNS_NAME_FORMATSIZE];
5439 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
5440 char classbuf[64];
5441 char typebuf[64];
5443 dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
5444 dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
5445 dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
5446 dns_rdataclass_format(fctx->res->rdclass, classbuf,
5447 sizeof(classbuf));
5448 isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
5449 sizeof(addrbuf));
5451 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY,
5452 DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
5453 "enforced delegation-only for '%s' (%s/%s/%s) "
5454 "from %s",
5455 domainbuf, namebuf, typebuf, classbuf, addrbuf);
5458 if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0)
5459 checknames(message);
5462 * Clear cache bits.
5464 fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE);
5467 * Did we get any answers?
5469 if (message->counts[DNS_SECTION_ANSWER] > 0 &&
5470 (message->rcode == dns_rcode_noerror ||
5471 message->rcode == dns_rcode_nxdomain)) {
5473 * We've got answers. However, if we sent
5474 * a BIND 8 server an NS query, it may have
5475 * incorrectly responded with a non-authoritative
5476 * answer instead of a referral. Since this
5477 * answer lacks the SIGs necessary to do DNSSEC
5478 * validation, we must invoke the following special
5479 * kludge to treat it as a referral.
5481 if (fctx->type == dns_rdatatype_ns &&
5482 (message->flags & DNS_MESSAGEFLAG_AA) == 0 &&
5483 !ISFORWARDER(query->addrinfo))
5485 result = noanswer_response(fctx, NULL, ISC_TRUE);
5486 if (result != DNS_R_DELEGATION) {
5488 * The answer section must have contained
5489 * something other than the NS records
5490 * we asked for. Since AA is not set
5491 * and the server is not a forwarder,
5492 * it is technically lame and it's easier
5493 * to treat it as such than to figure out
5494 * some more elaborate course of action.
5496 broken_server = DNS_R_LAME;
5497 keep_trying = ISC_TRUE;
5498 goto done;
5500 goto force_referral;
5502 result = answer_response(fctx);
5503 if (result != ISC_R_SUCCESS) {
5504 if (result == DNS_R_FORMERR)
5505 keep_trying = ISC_TRUE;
5506 goto done;
5508 } else if (message->counts[DNS_SECTION_AUTHORITY] > 0 ||
5509 message->rcode == dns_rcode_noerror ||
5510 message->rcode == dns_rcode_nxdomain) {
5512 * NXDOMAIN, NXRDATASET, or referral.
5514 result = noanswer_response(fctx, NULL, ISC_FALSE);
5515 if (result == DNS_R_CHASEDSSERVERS) {
5516 } else if (result == DNS_R_DELEGATION) {
5517 force_referral:
5519 * We don't have the answer, but we know a better
5520 * place to look.
5522 get_nameservers = ISC_TRUE;
5523 keep_trying = ISC_TRUE;
5525 * We have a new set of name servers, and it
5526 * has not experienced any restarts yet.
5528 fctx->restarts = 0;
5529 result = ISC_R_SUCCESS;
5530 } else if (result != ISC_R_SUCCESS) {
5532 * Something has gone wrong.
5534 if (result == DNS_R_FORMERR)
5535 keep_trying = ISC_TRUE;
5536 goto done;
5538 } else {
5540 * The server is insane.
5542 /* XXXRTH Log */
5543 broken_server = DNS_R_UNEXPECTEDRCODE;
5544 keep_trying = ISC_TRUE;
5545 goto done;
5549 * Follow additional section data chains.
5551 chase_additional(fctx);
5554 * Cache the cacheable parts of the message. This may also cause
5555 * work to be queued to the DNSSEC validator.
5557 if (WANTCACHE(fctx)) {
5558 result = cache_message(fctx, query->addrinfo, now);
5559 if (result != ISC_R_SUCCESS)
5560 goto done;
5564 * Ncache the negatively cacheable parts of the message. This may
5565 * also cause work to be queued to the DNSSEC validator.
5567 if (WANTNCACHE(fctx)) {
5568 dns_rdatatype_t covers;
5569 if (message->rcode == dns_rcode_nxdomain)
5570 covers = dns_rdatatype_any;
5571 else
5572 covers = fctx->type;
5575 * Cache any negative cache entries in the message.
5577 result = ncache_message(fctx, query->addrinfo, covers, now);
5580 done:
5582 * Remember the query's addrinfo, in case we need to mark the
5583 * server as broken.
5585 addrinfo = query->addrinfo;
5588 * Cancel the query.
5590 * XXXRTH Don't cancel the query if waiting for validation?
5592 fctx_cancelquery(&query, &devent, finish, ISC_FALSE);
5594 if (keep_trying) {
5595 if (result == DNS_R_FORMERR)
5596 broken_server = DNS_R_FORMERR;
5597 if (broken_server != ISC_R_SUCCESS) {
5599 * Add this server to the list of bad servers for
5600 * this fctx.
5602 add_bad(fctx, &addrinfo->sockaddr, broken_server);
5605 if (get_nameservers) {
5606 dns_name_t *name;
5607 dns_fixedname_init(&foundname);
5608 fname = dns_fixedname_name(&foundname);
5609 if (result != ISC_R_SUCCESS) {
5610 fctx_done(fctx, DNS_R_SERVFAIL);
5611 return;
5613 findoptions = 0;
5614 if (dns_rdatatype_atparent(fctx->type))
5615 findoptions |= DNS_DBFIND_NOEXACT;
5616 if ((options & DNS_FETCHOPT_UNSHARED) == 0)
5617 name = &fctx->name;
5618 else
5619 name = &fctx->domain;
5620 result = dns_view_findzonecut(fctx->res->view,
5621 name, fname,
5622 now, findoptions,
5623 ISC_TRUE,
5624 &fctx->nameservers,
5625 NULL);
5626 if (result != ISC_R_SUCCESS) {
5627 FCTXTRACE("couldn't find a zonecut");
5628 fctx_done(fctx, DNS_R_SERVFAIL);
5629 return;
5631 if (!dns_name_issubdomain(fname, &fctx->domain)) {
5633 * The best nameservers are now above our
5634 * QDOMAIN.
5636 FCTXTRACE("nameservers now above QDOMAIN");
5637 fctx_done(fctx, DNS_R_SERVFAIL);
5638 return;
5640 dns_name_free(&fctx->domain, fctx->res->mctx);
5641 dns_name_init(&fctx->domain, NULL);
5642 result = dns_name_dup(fname, fctx->res->mctx,
5643 &fctx->domain);
5644 if (result != ISC_R_SUCCESS) {
5645 fctx_done(fctx, DNS_R_SERVFAIL);
5646 return;
5648 fctx_cancelqueries(fctx, ISC_TRUE);
5649 fctx_cleanupfinds(fctx);
5650 fctx_cleanupaltfinds(fctx);
5651 fctx_cleanupforwaddrs(fctx);
5652 fctx_cleanupaltaddrs(fctx);
5655 * Try again.
5657 fctx_try(fctx);
5658 } else if (resend) {
5660 * Resend (probably with changed options).
5662 FCTXTRACE("resend");
5663 result = fctx_query(fctx, addrinfo, options);
5664 if (result != ISC_R_SUCCESS)
5665 fctx_done(fctx, result);
5666 } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) {
5668 * All has gone well so far, but we are waiting for the
5669 * DNSSEC validator to validate the answer.
5671 FCTXTRACE("wait for validator");
5672 fctx_cancelqueries(fctx, ISC_TRUE);
5674 * We must not retransmit while the validator is working;
5675 * it has references to the current rmessage.
5677 result = fctx_stopidletimer(fctx);
5678 if (result != ISC_R_SUCCESS)
5679 fctx_done(fctx, result);
5680 } else if (result == DNS_R_CHASEDSSERVERS) {
5681 unsigned int n;
5682 add_bad(fctx, &addrinfo->sockaddr, result);
5683 fctx_cancelqueries(fctx, ISC_TRUE);
5684 fctx_cleanupfinds(fctx);
5685 fctx_cleanupforwaddrs(fctx);
5687 n = dns_name_countlabels(&fctx->name);
5688 dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname);
5690 FCTXTRACE("suspending DS lookup to find parent's NS records");
5692 result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
5693 dns_rdatatype_ns,
5694 NULL, NULL, NULL, 0, task,
5695 resume_dslookup, fctx,
5696 &fctx->nsrrset, NULL,
5697 &fctx->nsfetch);
5698 if (result != ISC_R_SUCCESS)
5699 fctx_done(fctx, result);
5700 LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
5701 fctx->references++;
5702 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
5703 result = fctx_stopidletimer(fctx);
5704 if (result != ISC_R_SUCCESS)
5705 fctx_done(fctx, result);
5706 } else {
5708 * We're done.
5710 fctx_done(fctx, result);
5715 /***
5716 *** Resolver Methods
5717 ***/
5719 static void
5720 destroy(dns_resolver_t *res) {
5721 unsigned int i;
5722 alternate_t *a;
5724 REQUIRE(res->references == 0);
5725 REQUIRE(!res->priming);
5726 REQUIRE(res->primefetch == NULL);
5728 RTRACE("destroy");
5730 INSIST(res->nfctx == 0);
5732 DESTROYLOCK(&res->primelock);
5733 DESTROYLOCK(&res->nlock);
5734 DESTROYLOCK(&res->lock);
5735 for (i = 0; i < res->nbuckets; i++) {
5736 INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
5737 isc_task_shutdown(res->buckets[i].task);
5738 isc_task_detach(&res->buckets[i].task);
5739 DESTROYLOCK(&res->buckets[i].lock);
5741 isc_mem_put(res->mctx, res->buckets,
5742 res->nbuckets * sizeof(fctxbucket_t));
5743 if (res->dispatchv4 != NULL)
5744 dns_dispatch_detach(&res->dispatchv4);
5745 if (res->dispatchv6 != NULL)
5746 dns_dispatch_detach(&res->dispatchv6);
5747 while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) {
5748 ISC_LIST_UNLINK(res->alternates, a, link);
5749 if (!a->isaddress)
5750 dns_name_free(&a->_u._n.name, res->mctx);
5751 isc_mem_put(res->mctx, a, sizeof(*a));
5753 dns_resolver_reset_algorithms(res);
5754 dns_resolver_resetmustbesecure(res);
5755 #if USE_ALGLOCK
5756 isc_rwlock_destroy(&res->alglock);
5757 #endif
5758 #if USE_MBSLOCK
5759 isc_rwlock_destroy(&res->mbslock);
5760 #endif
5761 res->magic = 0;
5762 isc_mem_put(res->mctx, res, sizeof(*res));
5765 static void
5766 send_shutdown_events(dns_resolver_t *res) {
5767 isc_event_t *event, *next_event;
5768 isc_task_t *etask;
5771 * Caller must be holding the resolver lock.
5774 for (event = ISC_LIST_HEAD(res->whenshutdown);
5775 event != NULL;
5776 event = next_event) {
5777 next_event = ISC_LIST_NEXT(event, ev_link);
5778 ISC_LIST_UNLINK(res->whenshutdown, event, ev_link);
5779 etask = event->ev_sender;
5780 event->ev_sender = res;
5781 isc_task_sendanddetach(&etask, &event);
5785 static void
5786 empty_bucket(dns_resolver_t *res) {
5787 RTRACE("empty_bucket");
5789 LOCK(&res->lock);
5791 INSIST(res->activebuckets > 0);
5792 res->activebuckets--;
5793 if (res->activebuckets == 0)
5794 send_shutdown_events(res);
5796 UNLOCK(&res->lock);
5799 isc_result_t
5800 dns_resolver_create(dns_view_t *view,
5801 isc_taskmgr_t *taskmgr, unsigned int ntasks,
5802 isc_socketmgr_t *socketmgr,
5803 isc_timermgr_t *timermgr,
5804 unsigned int options,
5805 dns_dispatchmgr_t *dispatchmgr,
5806 dns_dispatch_t *dispatchv4,
5807 dns_dispatch_t *dispatchv6,
5808 dns_resolver_t **resp)
5810 dns_resolver_t *res;
5811 isc_result_t result = ISC_R_SUCCESS;
5812 unsigned int i, buckets_created = 0;
5813 char name[16];
5816 * Create a resolver.
5819 REQUIRE(DNS_VIEW_VALID(view));
5820 REQUIRE(ntasks > 0);
5821 REQUIRE(resp != NULL && *resp == NULL);
5822 REQUIRE(dispatchmgr != NULL);
5823 REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL);
5825 res = isc_mem_get(view->mctx, sizeof(*res));
5826 if (res == NULL)
5827 return (ISC_R_NOMEMORY);
5828 RTRACE("create");
5829 res->mctx = view->mctx;
5830 res->rdclass = view->rdclass;
5831 res->socketmgr = socketmgr;
5832 res->timermgr = timermgr;
5833 res->taskmgr = taskmgr;
5834 res->dispatchmgr = dispatchmgr;
5835 res->view = view;
5836 res->options = options;
5837 res->lame_ttl = 0;
5838 ISC_LIST_INIT(res->alternates);
5839 res->udpsize = RECV_BUFFER_SIZE;
5840 res->algorithms = NULL;
5841 res->mustbesecure = NULL;
5843 res->nbuckets = ntasks;
5844 res->activebuckets = ntasks;
5845 res->buckets = isc_mem_get(view->mctx,
5846 ntasks * sizeof(fctxbucket_t));
5847 if (res->buckets == NULL) {
5848 result = ISC_R_NOMEMORY;
5849 goto cleanup_res;
5851 for (i = 0; i < ntasks; i++) {
5852 result = isc_mutex_init(&res->buckets[i].lock);
5853 if (result != ISC_R_SUCCESS)
5854 goto cleanup_buckets;
5855 res->buckets[i].task = NULL;
5856 result = isc_task_create(taskmgr, 0, &res->buckets[i].task);
5857 if (result != ISC_R_SUCCESS) {
5858 DESTROYLOCK(&res->buckets[i].lock);
5859 goto cleanup_buckets;
5861 snprintf(name, sizeof(name), "res%u", i);
5862 isc_task_setname(res->buckets[i].task, name, res);
5863 ISC_LIST_INIT(res->buckets[i].fctxs);
5864 res->buckets[i].exiting = ISC_FALSE;
5865 buckets_created++;
5868 res->dispatchv4 = NULL;
5869 if (dispatchv4 != NULL)
5870 dns_dispatch_attach(dispatchv4, &res->dispatchv4);
5871 res->dispatchv6 = NULL;
5872 if (dispatchv6 != NULL)
5873 dns_dispatch_attach(dispatchv6, &res->dispatchv6);
5875 res->references = 1;
5876 res->exiting = ISC_FALSE;
5877 res->frozen = ISC_FALSE;
5878 ISC_LIST_INIT(res->whenshutdown);
5879 res->priming = ISC_FALSE;
5880 res->primefetch = NULL;
5881 res->nfctx = 0;
5883 result = isc_mutex_init(&res->lock);
5884 if (result != ISC_R_SUCCESS)
5885 goto cleanup_dispatches;
5887 result = isc_mutex_init(&res->nlock);
5888 if (result != ISC_R_SUCCESS)
5889 goto cleanup_lock;
5891 result = isc_mutex_init(&res->primelock);
5892 if (result != ISC_R_SUCCESS)
5893 goto cleanup_nlock;
5895 #if USE_ALGLOCK
5896 result = isc_rwlock_init(&res->alglock, 0, 0);
5897 if (result != ISC_R_SUCCESS)
5898 goto cleanup_primelock;
5899 #endif
5900 #if USE_MBSLOCK
5901 result = isc_rwlock_init(&res->mbslock, 0, 0);
5902 if (result != ISC_R_SUCCESS)
5903 goto cleanup_alglock;
5904 #endif
5906 res->magic = RES_MAGIC;
5908 *resp = res;
5910 return (ISC_R_SUCCESS);
5912 #if USE_MBSLOCK
5913 cleanup_alglock:
5914 #if USE_ALGLOCK
5915 isc_rwlock_destroy(&res->alglock);
5916 #endif
5917 #endif
5918 #if USE_ALGLOCK || USE_MBSLOCK
5919 cleanup_primelock:
5920 DESTROYLOCK(&res->primelock);
5921 #endif
5923 cleanup_nlock:
5924 DESTROYLOCK(&res->nlock);
5926 cleanup_lock:
5927 DESTROYLOCK(&res->lock);
5929 cleanup_dispatches:
5930 if (res->dispatchv6 != NULL)
5931 dns_dispatch_detach(&res->dispatchv6);
5932 if (res->dispatchv4 != NULL)
5933 dns_dispatch_detach(&res->dispatchv4);
5935 cleanup_buckets:
5936 for (i = 0; i < buckets_created; i++) {
5937 DESTROYLOCK(&res->buckets[i].lock);
5938 isc_task_shutdown(res->buckets[i].task);
5939 isc_task_detach(&res->buckets[i].task);
5941 isc_mem_put(view->mctx, res->buckets,
5942 res->nbuckets * sizeof(fctxbucket_t));
5944 cleanup_res:
5945 isc_mem_put(view->mctx, res, sizeof(*res));
5947 return (result);
5950 static void
5951 prime_done(isc_task_t *task, isc_event_t *event) {
5952 dns_resolver_t *res;
5953 dns_fetchevent_t *fevent;
5954 dns_fetch_t *fetch;
5956 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
5957 fevent = (dns_fetchevent_t *)event;
5958 res = event->ev_arg;
5959 REQUIRE(VALID_RESOLVER(res));
5961 UNUSED(task);
5963 LOCK(&res->lock);
5965 INSIST(res->priming);
5966 res->priming = ISC_FALSE;
5967 LOCK(&res->primelock);
5968 fetch = res->primefetch;
5969 res->primefetch = NULL;
5970 UNLOCK(&res->primelock);
5972 UNLOCK(&res->lock);
5974 if (fevent->node != NULL)
5975 dns_db_detachnode(fevent->db, &fevent->node);
5976 if (fevent->db != NULL)
5977 dns_db_detach(&fevent->db);
5978 if (dns_rdataset_isassociated(fevent->rdataset))
5979 dns_rdataset_disassociate(fevent->rdataset);
5980 INSIST(fevent->sigrdataset == NULL);
5982 isc_mem_put(res->mctx, fevent->rdataset, sizeof(*fevent->rdataset));
5984 isc_event_free(&event);
5985 dns_resolver_destroyfetch(&fetch);
5988 void
5989 dns_resolver_prime(dns_resolver_t *res) {
5990 isc_boolean_t want_priming = ISC_FALSE;
5991 dns_rdataset_t *rdataset;
5992 isc_result_t result;
5994 REQUIRE(VALID_RESOLVER(res));
5995 REQUIRE(res->frozen);
5997 RTRACE("dns_resolver_prime");
5999 LOCK(&res->lock);
6001 if (!res->exiting && !res->priming) {
6002 INSIST(res->primefetch == NULL);
6003 res->priming = ISC_TRUE;
6004 want_priming = ISC_TRUE;
6007 UNLOCK(&res->lock);
6009 if (want_priming) {
6011 * To avoid any possible recursive locking problems, we
6012 * start the priming fetch like any other fetch, and holding
6013 * no resolver locks. No one else will try to start it
6014 * because we're the ones who set res->priming to true.
6015 * Any other callers of dns_resolver_prime() while we're
6016 * running will see that res->priming is already true and
6017 * do nothing.
6019 RTRACE("priming");
6020 rdataset = isc_mem_get(res->mctx, sizeof(*rdataset));
6021 if (rdataset == NULL) {
6022 LOCK(&res->lock);
6023 INSIST(res->priming);
6024 INSIST(res->primefetch == NULL);
6025 res->priming = ISC_FALSE;
6026 UNLOCK(&res->lock);
6027 return;
6029 dns_rdataset_init(rdataset);
6030 LOCK(&res->primelock);
6031 result = dns_resolver_createfetch(res, dns_rootname,
6032 dns_rdatatype_ns,
6033 NULL, NULL, NULL, 0,
6034 res->buckets[0].task,
6035 prime_done,
6036 res, rdataset, NULL,
6037 &res->primefetch);
6038 UNLOCK(&res->primelock);
6039 if (result != ISC_R_SUCCESS) {
6040 LOCK(&res->lock);
6041 INSIST(res->priming);
6042 res->priming = ISC_FALSE;
6043 UNLOCK(&res->lock);
6048 void
6049 dns_resolver_freeze(dns_resolver_t *res) {
6052 * Freeze resolver.
6055 REQUIRE(VALID_RESOLVER(res));
6056 REQUIRE(!res->frozen);
6058 res->frozen = ISC_TRUE;
6061 void
6062 dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) {
6063 REQUIRE(VALID_RESOLVER(source));
6064 REQUIRE(targetp != NULL && *targetp == NULL);
6066 RRTRACE(source, "attach");
6067 LOCK(&source->lock);
6068 REQUIRE(!source->exiting);
6070 INSIST(source->references > 0);
6071 source->references++;
6072 INSIST(source->references != 0);
6073 UNLOCK(&source->lock);
6075 *targetp = source;
6078 void
6079 dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
6080 isc_event_t **eventp)
6082 isc_task_t *clone;
6083 isc_event_t *event;
6085 REQUIRE(VALID_RESOLVER(res));
6086 REQUIRE(eventp != NULL);
6088 event = *eventp;
6089 *eventp = NULL;
6091 LOCK(&res->lock);
6093 if (res->exiting && res->activebuckets == 0) {
6095 * We're already shutdown. Send the event.
6097 event->ev_sender = res;
6098 isc_task_send(task, &event);
6099 } else {
6100 clone = NULL;
6101 isc_task_attach(task, &clone);
6102 event->ev_sender = clone;
6103 ISC_LIST_APPEND(res->whenshutdown, event, ev_link);
6106 UNLOCK(&res->lock);
6109 void
6110 dns_resolver_shutdown(dns_resolver_t *res) {
6111 unsigned int i;
6112 fetchctx_t *fctx;
6113 isc_socket_t *sock;
6115 REQUIRE(VALID_RESOLVER(res));
6117 RTRACE("shutdown");
6119 LOCK(&res->lock);
6121 if (!res->exiting) {
6122 RTRACE("exiting");
6123 res->exiting = ISC_TRUE;
6125 for (i = 0; i < res->nbuckets; i++) {
6126 LOCK(&res->buckets[i].lock);
6127 for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
6128 fctx != NULL;
6129 fctx = ISC_LIST_NEXT(fctx, link))
6130 fctx_shutdown(fctx);
6131 if (res->dispatchv4 != NULL) {
6132 sock = dns_dispatch_getsocket(res->dispatchv4);
6133 isc_socket_cancel(sock, res->buckets[i].task,
6134 ISC_SOCKCANCEL_ALL);
6136 if (res->dispatchv6 != NULL) {
6137 sock = dns_dispatch_getsocket(res->dispatchv6);
6138 isc_socket_cancel(sock, res->buckets[i].task,
6139 ISC_SOCKCANCEL_ALL);
6141 res->buckets[i].exiting = ISC_TRUE;
6142 if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
6143 INSIST(res->activebuckets > 0);
6144 res->activebuckets--;
6146 UNLOCK(&res->buckets[i].lock);
6148 if (res->activebuckets == 0)
6149 send_shutdown_events(res);
6152 UNLOCK(&res->lock);
6155 void
6156 dns_resolver_detach(dns_resolver_t **resp) {
6157 dns_resolver_t *res;
6158 isc_boolean_t need_destroy = ISC_FALSE;
6160 REQUIRE(resp != NULL);
6161 res = *resp;
6162 REQUIRE(VALID_RESOLVER(res));
6164 RTRACE("detach");
6166 LOCK(&res->lock);
6168 INSIST(res->references > 0);
6169 res->references--;
6170 if (res->references == 0) {
6171 INSIST(res->exiting && res->activebuckets == 0);
6172 need_destroy = ISC_TRUE;
6175 UNLOCK(&res->lock);
6177 if (need_destroy)
6178 destroy(res);
6180 *resp = NULL;
6183 static inline isc_boolean_t
6184 fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
6185 unsigned int options)
6187 if (fctx->type != type || fctx->options != options)
6188 return (ISC_FALSE);
6189 return (dns_name_equal(&fctx->name, name));
6192 static inline void
6193 log_fetch(dns_name_t *name, dns_rdatatype_t type) {
6194 char namebuf[DNS_NAME_FORMATSIZE];
6195 char typebuf[DNS_RDATATYPE_FORMATSIZE];
6196 int level = ISC_LOG_DEBUG(1);
6198 if (! isc_log_wouldlog(dns_lctx, level))
6199 return;
6201 dns_name_format(name, namebuf, sizeof(namebuf));
6202 dns_rdatatype_format(type, typebuf, sizeof(typebuf));
6204 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
6205 DNS_LOGMODULE_RESOLVER, level,
6206 "createfetch: %s %s", namebuf, typebuf);
6209 isc_result_t
6210 dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
6211 dns_rdatatype_t type,
6212 dns_name_t *domain, dns_rdataset_t *nameservers,
6213 dns_forwarders_t *forwarders,
6214 unsigned int options, isc_task_t *task,
6215 isc_taskaction_t action, void *arg,
6216 dns_rdataset_t *rdataset,
6217 dns_rdataset_t *sigrdataset,
6218 dns_fetch_t **fetchp)
6220 dns_fetch_t *fetch;
6221 fetchctx_t *fctx = NULL;
6222 isc_result_t result;
6223 unsigned int bucketnum;
6224 isc_boolean_t new_fctx = ISC_FALSE;
6225 isc_event_t *event;
6227 UNUSED(forwarders);
6229 REQUIRE(VALID_RESOLVER(res));
6230 REQUIRE(res->frozen);
6231 /* XXXRTH Check for meta type */
6232 if (domain != NULL) {
6233 REQUIRE(DNS_RDATASET_VALID(nameservers));
6234 REQUIRE(nameservers->type == dns_rdatatype_ns);
6235 } else
6236 REQUIRE(nameservers == NULL);
6237 REQUIRE(forwarders == NULL);
6238 REQUIRE(!dns_rdataset_isassociated(rdataset));
6239 REQUIRE(sigrdataset == NULL ||
6240 !dns_rdataset_isassociated(sigrdataset));
6241 REQUIRE(fetchp != NULL && *fetchp == NULL);
6243 log_fetch(name, type);
6246 * XXXRTH use a mempool?
6248 fetch = isc_mem_get(res->mctx, sizeof(*fetch));
6249 if (fetch == NULL)
6250 return (ISC_R_NOMEMORY);
6252 bucketnum = dns_name_hash(name, ISC_FALSE) % res->nbuckets;
6254 LOCK(&res->buckets[bucketnum].lock);
6256 if (res->buckets[bucketnum].exiting) {
6257 result = ISC_R_SHUTTINGDOWN;
6258 goto unlock;
6261 if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
6262 for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
6263 fctx != NULL;
6264 fctx = ISC_LIST_NEXT(fctx, link)) {
6265 if (fctx_match(fctx, name, type, options))
6266 break;
6271 * If we didn't have a fetch, would attach to a done fetch, this
6272 * fetch has already cloned its results, or if the fetch has gone
6273 * "idle" (no one was interested in it), we need to start a new
6274 * fetch instead of joining with the existing one.
6276 if (fctx == NULL ||
6277 fctx->state == fetchstate_done ||
6278 fctx->cloned ||
6279 ISC_LIST_EMPTY(fctx->events)) {
6280 fctx = NULL;
6281 result = fctx_create(res, name, type, domain, nameservers,
6282 options, bucketnum, &fctx);
6283 if (result != ISC_R_SUCCESS)
6284 goto unlock;
6285 new_fctx = ISC_TRUE;
6288 result = fctx_join(fctx, task, action, arg,
6289 rdataset, sigrdataset, fetch);
6290 if (new_fctx) {
6291 if (result == ISC_R_SUCCESS) {
6293 * Launch this fctx.
6295 event = &fctx->control_event;
6296 ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
6297 DNS_EVENT_FETCHCONTROL,
6298 fctx_start, fctx, NULL,
6299 NULL, NULL);
6300 isc_task_send(res->buckets[bucketnum].task, &event);
6301 } else {
6303 * We don't care about the result of fctx_destroy()
6304 * since we know we're not exiting.
6306 (void)fctx_destroy(fctx);
6310 unlock:
6311 UNLOCK(&res->buckets[bucketnum].lock);
6313 if (result == ISC_R_SUCCESS) {
6314 FTRACE("created");
6315 *fetchp = fetch;
6316 } else
6317 isc_mem_put(res->mctx, fetch, sizeof(*fetch));
6319 return (result);
6322 void
6323 dns_resolver_cancelfetch(dns_fetch_t *fetch) {
6324 fetchctx_t *fctx;
6325 dns_resolver_t *res;
6326 dns_fetchevent_t *event, *next_event;
6327 isc_task_t *etask;
6329 REQUIRE(DNS_FETCH_VALID(fetch));
6330 fctx = fetch->private;
6331 REQUIRE(VALID_FCTX(fctx));
6332 res = fctx->res;
6334 FTRACE("cancelfetch");
6336 LOCK(&res->buckets[fctx->bucketnum].lock);
6339 * Find the completion event for this fetch (as opposed
6340 * to those for other fetches that have joined the same
6341 * fctx) and send it with result = ISC_R_CANCELED.
6343 event = NULL;
6344 if (fctx->state != fetchstate_done) {
6345 for (event = ISC_LIST_HEAD(fctx->events);
6346 event != NULL;
6347 event = next_event) {
6348 next_event = ISC_LIST_NEXT(event, ev_link);
6349 if (event->fetch == fetch) {
6350 ISC_LIST_UNLINK(fctx->events, event, ev_link);
6351 break;
6355 if (event != NULL) {
6356 etask = event->ev_sender;
6357 event->ev_sender = fctx;
6358 event->result = ISC_R_CANCELED;
6359 isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event));
6362 * The fctx continues running even if no fetches remain;
6363 * the answer is still cached.
6366 UNLOCK(&res->buckets[fctx->bucketnum].lock);
6369 void
6370 dns_resolver_destroyfetch(dns_fetch_t **fetchp) {
6371 dns_fetch_t *fetch;
6372 dns_resolver_t *res;
6373 dns_fetchevent_t *event, *next_event;
6374 fetchctx_t *fctx;
6375 unsigned int bucketnum;
6376 isc_boolean_t bucket_empty = ISC_FALSE;
6378 REQUIRE(fetchp != NULL);
6379 fetch = *fetchp;
6380 REQUIRE(DNS_FETCH_VALID(fetch));
6381 fctx = fetch->private;
6382 REQUIRE(VALID_FCTX(fctx));
6383 res = fctx->res;
6385 FTRACE("destroyfetch");
6387 bucketnum = fctx->bucketnum;
6388 LOCK(&res->buckets[bucketnum].lock);
6391 * Sanity check: the caller should have gotten its event before
6392 * trying to destroy the fetch.
6394 event = NULL;
6395 if (fctx->state != fetchstate_done) {
6396 for (event = ISC_LIST_HEAD(fctx->events);
6397 event != NULL;
6398 event = next_event) {
6399 next_event = ISC_LIST_NEXT(event, ev_link);
6400 RUNTIME_CHECK(event->fetch != fetch);
6404 INSIST(fctx->references > 0);
6405 fctx->references--;
6406 if (fctx->references == 0) {
6408 * No one cares about the result of this fetch anymore.
6410 if (fctx->pending == 0 && fctx->nqueries == 0 &&
6411 ISC_LIST_EMPTY(fctx->validators) &&
6412 SHUTTINGDOWN(fctx)) {
6414 * This fctx is already shutdown; we were just
6415 * waiting for the last reference to go away.
6417 bucket_empty = fctx_destroy(fctx);
6418 } else {
6420 * Initiate shutdown.
6422 fctx_shutdown(fctx);
6426 UNLOCK(&res->buckets[bucketnum].lock);
6428 isc_mem_put(res->mctx, fetch, sizeof(*fetch));
6429 *fetchp = NULL;
6431 if (bucket_empty)
6432 empty_bucket(res);
6435 dns_dispatchmgr_t *
6436 dns_resolver_dispatchmgr(dns_resolver_t *resolver) {
6437 REQUIRE(VALID_RESOLVER(resolver));
6438 return (resolver->dispatchmgr);
6441 dns_dispatch_t *
6442 dns_resolver_dispatchv4(dns_resolver_t *resolver) {
6443 REQUIRE(VALID_RESOLVER(resolver));
6444 return (resolver->dispatchv4);
6447 dns_dispatch_t *
6448 dns_resolver_dispatchv6(dns_resolver_t *resolver) {
6449 REQUIRE(VALID_RESOLVER(resolver));
6450 return (resolver->dispatchv6);
6453 isc_socketmgr_t *
6454 dns_resolver_socketmgr(dns_resolver_t *resolver) {
6455 REQUIRE(VALID_RESOLVER(resolver));
6456 return (resolver->socketmgr);
6459 isc_taskmgr_t *
6460 dns_resolver_taskmgr(dns_resolver_t *resolver) {
6461 REQUIRE(VALID_RESOLVER(resolver));
6462 return (resolver->taskmgr);
6465 isc_uint32_t
6466 dns_resolver_getlamettl(dns_resolver_t *resolver) {
6467 REQUIRE(VALID_RESOLVER(resolver));
6468 return (resolver->lame_ttl);
6471 void
6472 dns_resolver_setlamettl(dns_resolver_t *resolver, isc_uint32_t lame_ttl) {
6473 REQUIRE(VALID_RESOLVER(resolver));
6474 resolver->lame_ttl = lame_ttl;
6477 unsigned int
6478 dns_resolver_nrunning(dns_resolver_t *resolver) {
6479 unsigned int n;
6480 LOCK(&resolver->nlock);
6481 n = resolver->nfctx;
6482 UNLOCK(&resolver->nlock);
6483 return (n);
6486 isc_result_t
6487 dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt,
6488 dns_name_t *name, in_port_t port) {
6489 alternate_t *a;
6490 isc_result_t result;
6492 REQUIRE(VALID_RESOLVER(resolver));
6493 REQUIRE(!resolver->frozen);
6494 REQUIRE((alt == NULL) ^ (name == NULL));
6496 a = isc_mem_get(resolver->mctx, sizeof(*a));
6497 if (a == NULL)
6498 return (ISC_R_NOMEMORY);
6499 if (alt != NULL) {
6500 a->isaddress = ISC_TRUE;
6501 a->_u.addr = *alt;
6502 } else {
6503 a->isaddress = ISC_FALSE;
6504 a->_u._n.port = port;
6505 dns_name_init(&a->_u._n.name, NULL);
6506 result = dns_name_dup(name, resolver->mctx, &a->_u._n.name);
6507 if (result != ISC_R_SUCCESS) {
6508 isc_mem_put(resolver->mctx, a, sizeof(*a));
6509 return (result);
6512 ISC_LINK_INIT(a, link);
6513 ISC_LIST_APPEND(resolver->alternates, a, link);
6515 return (ISC_R_SUCCESS);
6518 void
6519 dns_resolver_setudpsize(dns_resolver_t *resolver, isc_uint16_t udpsize) {
6520 REQUIRE(VALID_RESOLVER(resolver));
6521 resolver->udpsize = udpsize;
6524 isc_uint16_t
6525 dns_resolver_getudpsize(dns_resolver_t *resolver) {
6526 REQUIRE(VALID_RESOLVER(resolver));
6527 return (resolver->udpsize);
6530 static void
6531 free_algorithm(void *node, void *arg) {
6532 unsigned char *algorithms = node;
6533 isc_mem_t *mctx = arg;
6535 isc_mem_put(mctx, algorithms, *algorithms);
6538 void
6539 dns_resolver_reset_algorithms(dns_resolver_t *resolver) {
6541 REQUIRE(VALID_RESOLVER(resolver));
6543 #if USE_ALGLOCK
6544 RWLOCK(&resolver->alglock, isc_rwlocktype_write);
6545 #endif
6546 if (resolver->algorithms != NULL)
6547 dns_rbt_destroy(&resolver->algorithms);
6548 #if USE_ALGLOCK
6549 RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
6550 #endif
6553 isc_result_t
6554 dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
6555 unsigned int alg)
6557 unsigned int len, mask;
6558 unsigned char *new;
6559 unsigned char *algorithms;
6560 isc_result_t result;
6561 dns_rbtnode_t *node = NULL;
6563 REQUIRE(VALID_RESOLVER(resolver));
6564 if (alg > 255)
6565 return (ISC_R_RANGE);
6567 #if USE_ALGLOCK
6568 RWLOCK(&resolver->alglock, isc_rwlocktype_write);
6569 #endif
6570 if (resolver->algorithms == NULL) {
6571 result = dns_rbt_create(resolver->mctx, free_algorithm,
6572 resolver->mctx, &resolver->algorithms);
6573 if (result != ISC_R_SUCCESS)
6574 goto cleanup;
6577 len = alg/8 + 2;
6578 mask = 1 << (alg%8);
6580 result = dns_rbt_addnode(resolver->algorithms, name, &node);
6582 if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
6583 algorithms = node->data;
6584 if (algorithms == NULL || len > *algorithms) {
6585 new = isc_mem_get(resolver->mctx, len);
6586 if (new == NULL) {
6587 result = ISC_R_NOMEMORY;
6588 goto cleanup;
6590 memset(new, 0, len);
6591 if (algorithms != NULL)
6592 memcpy(new, algorithms, *algorithms);
6593 new[len-1] |= mask;
6594 *new = len;
6595 node->data = new;
6596 if (algorithms != NULL)
6597 isc_mem_put(resolver->mctx, algorithms,
6598 *algorithms);
6599 } else
6600 algorithms[len-1] |= mask;
6602 result = ISC_R_SUCCESS;
6603 cleanup:
6604 #if USE_ALGLOCK
6605 RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
6606 #endif
6607 return (result);
6610 isc_boolean_t
6611 dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name,
6612 unsigned int alg)
6614 unsigned int len, mask;
6615 unsigned char *algorithms;
6616 void *data = NULL;
6617 isc_result_t result;
6618 isc_boolean_t found = ISC_FALSE;
6620 REQUIRE(VALID_RESOLVER(resolver));
6622 #if USE_ALGLOCK
6623 RWLOCK(&resolver->alglock, isc_rwlocktype_read);
6624 #endif
6625 if (resolver->algorithms == NULL)
6626 goto unlock;
6627 result = dns_rbt_findname(resolver->algorithms, name, 0, NULL, &data);
6628 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
6629 len = alg/8 + 2;
6630 mask = 1 << (alg%8);
6631 algorithms = data;
6632 if (len <= *algorithms && (algorithms[len-1] & mask) != 0)
6633 found = ISC_TRUE;
6635 unlock:
6636 #if USE_ALGLOCK
6637 RWUNLOCK(&resolver->alglock, isc_rwlocktype_read);
6638 #endif
6639 if (found)
6640 return (ISC_FALSE);
6641 return (dst_algorithm_supported(alg));
6644 void
6645 dns_resolver_resetmustbesecure(dns_resolver_t *resolver) {
6647 REQUIRE(VALID_RESOLVER(resolver));
6649 #if USE_MBSLOCK
6650 RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
6651 #endif
6652 if (resolver->mustbesecure != NULL)
6653 dns_rbt_destroy(&resolver->mustbesecure);
6654 #if USE_MBSLOCK
6655 RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
6656 #endif
6659 static isc_boolean_t yes = ISC_TRUE, no = ISC_FALSE;
6661 isc_result_t
6662 dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name,
6663 isc_boolean_t value)
6665 isc_result_t result;
6667 REQUIRE(VALID_RESOLVER(resolver));
6669 #if USE_MBSLOCK
6670 RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
6671 #endif
6672 if (resolver->mustbesecure == NULL) {
6673 result = dns_rbt_create(resolver->mctx, NULL, NULL,
6674 &resolver->mustbesecure);
6675 if (result != ISC_R_SUCCESS)
6676 goto cleanup;
6678 result = dns_rbt_addname(resolver->mustbesecure, name,
6679 value ? &yes : &no);
6680 cleanup:
6681 #if USE_MBSLOCK
6682 RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
6683 #endif
6684 return (result);
6687 isc_boolean_t
6688 dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name) {
6689 void *data = NULL;
6690 isc_boolean_t value = ISC_FALSE;
6691 isc_result_t result;
6693 REQUIRE(VALID_RESOLVER(resolver));
6695 #if USE_MBSLOCK
6696 RWLOCK(&resolver->mbslock, isc_rwlocktype_read);
6697 #endif
6698 if (resolver->mustbesecure == NULL)
6699 goto unlock;
6700 result = dns_rbt_findname(resolver->mustbesecure, name, 0, NULL, &data);
6701 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
6702 value = *(isc_boolean_t*)data;
6703 unlock:
6704 #if USE_MBSLOCK
6705 RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read);
6706 #endif
6707 return (value);