]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/dns/resolver.c
This commit was generated by cvs2svn to compensate for changes in r161751,
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / dns / resolver.c
1 /*
2  * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: resolver.c,v 1.218.2.18.4.56 2005/10/14 01:38:48 marka Exp $ */
19
20 #include <config.h>
21
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>
27
28 #include <dns/acl.h>
29 #include <dns/adb.h>
30 #include <dns/db.h>
31 #include <dns/dispatch.h>
32 #include <dns/events.h>
33 #include <dns/forward.h>
34 #include <dns/keytable.h>
35 #include <dns/log.h>
36 #include <dns/message.h>
37 #include <dns/ncache.h>
38 #include <dns/opcode.h>
39 #include <dns/peer.h>
40 #include <dns/rbt.h>
41 #include <dns/rcode.h>
42 #include <dns/rdata.h>
43 #include <dns/rdataclass.h>
44 #include <dns/rdatalist.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/rdatatype.h>
48 #include <dns/resolver.h>
49 #include <dns/result.h>
50 #include <dns/tsig.h>
51 #include <dns/validator.h>
52
53 #define DNS_RESOLVER_TRACE
54 #ifdef DNS_RESOLVER_TRACE
55 #define RTRACE(m)       isc_log_write(dns_lctx, \
56                                       DNS_LOGCATEGORY_RESOLVER, \
57                                       DNS_LOGMODULE_RESOLVER, \
58                                       ISC_LOG_DEBUG(3), \
59                                       "res %p: %s", res, (m))
60 #define RRTRACE(r, m)   isc_log_write(dns_lctx, \
61                                       DNS_LOGCATEGORY_RESOLVER, \
62                                       DNS_LOGMODULE_RESOLVER, \
63                                       ISC_LOG_DEBUG(3), \
64                                       "res %p: %s", (r), (m))
65 #define FCTXTRACE(m)    isc_log_write(dns_lctx, \
66                                       DNS_LOGCATEGORY_RESOLVER, \
67                                       DNS_LOGMODULE_RESOLVER, \
68                                       ISC_LOG_DEBUG(3), \
69                                       "fctx %p(%s'): %s", fctx, fctx->info, (m))
70 #define FCTXTRACE2(m1, m2) \
71                         isc_log_write(dns_lctx, \
72                                       DNS_LOGCATEGORY_RESOLVER, \
73                                       DNS_LOGMODULE_RESOLVER, \
74                                       ISC_LOG_DEBUG(3), \
75                                       "fctx %p(%s): %s %s", \
76                                       fctx, fctx->info, (m1), (m2))
77 #define FTRACE(m)       isc_log_write(dns_lctx, \
78                                       DNS_LOGCATEGORY_RESOLVER, \
79                                       DNS_LOGMODULE_RESOLVER, \
80                                       ISC_LOG_DEBUG(3), \
81                                       "fetch %p (fctx %p(%s)): %s", \
82                                       fetch, fetch->private, \
83                                       fetch->private->info, (m))
84 #define QTRACE(m)       isc_log_write(dns_lctx, \
85                                       DNS_LOGCATEGORY_RESOLVER, \
86                                       DNS_LOGMODULE_RESOLVER, \
87                                       ISC_LOG_DEBUG(3), \
88                                       "resquery %p (fctx %p(%s)): %s", \
89                                       query, query->fctx, \
90                                       query->fctx->info, (m))
91 #else
92 #define RTRACE(m)
93 #define RRTRACE(r, m)
94 #define FCTXTRACE(m)
95 #define FTRACE(m)
96 #define QTRACE(m)
97 #endif
98
99 /*
100  * Maximum EDNS0 input packet size.
101  */
102 #define RECV_BUFFER_SIZE                4096            /* XXXRTH  Constant. */
103
104 /*
105  * This defines the maximum number of timeouts we will permit before we
106  * disable EDNS0 on the query.
107  */
108 #define MAX_EDNS0_TIMEOUTS      3
109
110 typedef struct fetchctx fetchctx_t;
111
112 typedef struct query {
113         /* Locked by task event serialization. */
114         unsigned int                    magic;
115         fetchctx_t *                    fctx;
116         isc_mem_t *                     mctx;
117         dns_dispatchmgr_t *             dispatchmgr;
118         dns_dispatch_t *                dispatch;
119         dns_adbaddrinfo_t *             addrinfo;
120         isc_socket_t *                  tcpsocket;
121         isc_time_t                      start;
122         dns_messageid_t                 id;
123         dns_dispentry_t *               dispentry;
124         ISC_LINK(struct query)          link;
125         isc_buffer_t                    buffer;
126         isc_buffer_t                    *tsig;
127         dns_tsigkey_t                   *tsigkey;
128         unsigned int                    options;
129         unsigned int                    attributes;
130         unsigned int                    sends;
131         unsigned int                    connects;
132         unsigned char                   data[512];
133 } resquery_t;
134
135 #define QUERY_MAGIC                     ISC_MAGIC('Q', '!', '!', '!')
136 #define VALID_QUERY(query)              ISC_MAGIC_VALID(query, QUERY_MAGIC)
137
138 #define RESQUERY_ATTR_CANCELED          0x02
139
140 #define RESQUERY_CONNECTING(q)          ((q)->connects > 0)
141 #define RESQUERY_CANCELED(q)            (((q)->attributes & \
142                                           RESQUERY_ATTR_CANCELED) != 0)
143 #define RESQUERY_SENDING(q)             ((q)->sends > 0)
144
145 typedef enum {
146         fetchstate_init = 0,            /* Start event has not run yet. */
147         fetchstate_active,
148         fetchstate_done                 /* FETCHDONE events posted. */
149 } fetchstate;
150
151 struct fetchctx {
152         /* Not locked. */
153         unsigned int                    magic;
154         dns_resolver_t *                res;
155         dns_name_t                      name;
156         dns_rdatatype_t                 type;
157         unsigned int                    options;
158         unsigned int                    bucketnum;
159         char *                          info;
160         /* Locked by appropriate bucket lock. */
161         fetchstate                      state;
162         isc_boolean_t                   want_shutdown;
163         isc_boolean_t                   cloned;
164         unsigned int                    references;
165         isc_event_t                     control_event;
166         ISC_LINK(struct fetchctx)       link;
167         ISC_LIST(dns_fetchevent_t)      events;
168         /* Locked by task event serialization. */
169         dns_name_t                      domain;
170         dns_rdataset_t                  nameservers;
171         unsigned int                    attributes;
172         isc_timer_t *                   timer;
173         isc_time_t                      expires;
174         isc_interval_t                  interval;
175         dns_message_t *                 qmessage;
176         dns_message_t *                 rmessage;
177         ISC_LIST(resquery_t)            queries;
178         dns_adbfindlist_t               finds;
179         dns_adbfind_t *                 find;
180         dns_adbfindlist_t               altfinds;
181         dns_adbfind_t *                 altfind;
182         dns_adbaddrinfolist_t           forwaddrs;
183         dns_adbaddrinfolist_t           altaddrs;
184         isc_sockaddrlist_t              forwarders;
185         dns_fwdpolicy_t                 fwdpolicy;
186         isc_sockaddrlist_t              bad;
187         ISC_LIST(dns_validator_t)       validators;
188         dns_db_t *                      cache;
189         dns_adb_t *                     adb;
190
191         /*
192          * The number of events we're waiting for.
193          */
194         unsigned int                    pending;
195
196         /*
197          * The number of times we've "restarted" the current
198          * nameserver set.  This acts as a failsafe to prevent
199          * us from pounding constantly on a particular set of
200          * servers that, for whatever reason, are not giving
201          * us useful responses, but are responding in such a
202          * way that they are not marked "bad".
203          */
204         unsigned int                    restarts;
205
206         /*
207          * The number of timeouts that have occurred since we 
208          * last successfully received a response packet.  This
209          * is used for EDNS0 black hole detection.
210          */
211         unsigned int                    timeouts;
212         /*
213          * Look aside state for DS lookups.
214          */
215         dns_name_t                      nsname; 
216         dns_fetch_t *                   nsfetch;
217         dns_rdataset_t                  nsrrset;
218 };
219
220 #define FCTX_MAGIC                      ISC_MAGIC('F', '!', '!', '!')
221 #define VALID_FCTX(fctx)                ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
222
223 #define FCTX_ATTR_HAVEANSWER            0x0001
224 #define FCTX_ATTR_GLUING                0x0002
225 #define FCTX_ATTR_ADDRWAIT              0x0004
226 #define FCTX_ATTR_SHUTTINGDOWN          0x0008
227 #define FCTX_ATTR_WANTCACHE             0x0010
228 #define FCTX_ATTR_WANTNCACHE            0x0020
229 #define FCTX_ATTR_NEEDEDNS0             0x0040
230 #define FCTX_ATTR_TRIEDFIND             0x0080
231 #define FCTX_ATTR_TRIEDALT              0x0100
232
233 #define HAVE_ANSWER(f)          (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
234                                  0)
235 #define GLUING(f)               (((f)->attributes & FCTX_ATTR_GLUING) != \
236                                  0)
237 #define ADDRWAIT(f)             (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
238                                  0)
239 #define SHUTTINGDOWN(f)         (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
240                                  != 0)
241 #define WANTCACHE(f)            (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
242 #define WANTNCACHE(f)           (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
243 #define NEEDEDNS0(f)            (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
244 #define TRIEDFIND(f)            (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
245 #define TRIEDALT(f)             (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
246
247 typedef struct {
248         dns_adbaddrinfo_t *             addrinfo;
249         fetchctx_t *                    fctx;
250 } dns_valarg_t;
251
252 struct dns_fetch {
253         unsigned int                    magic;
254         fetchctx_t *                    private;
255 };
256
257 #define DNS_FETCH_MAGIC                 ISC_MAGIC('F', 't', 'c', 'h')
258 #define DNS_FETCH_VALID(fetch)          ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
259
260 typedef struct fctxbucket {
261         isc_task_t *                    task;
262         isc_mutex_t                     lock;
263         ISC_LIST(fetchctx_t)            fctxs;
264         isc_boolean_t                   exiting;
265 } fctxbucket_t;
266
267 typedef struct alternate {
268         isc_boolean_t                   isaddress;
269         union   {
270                 isc_sockaddr_t          addr;
271                 struct {
272                         dns_name_t      name;
273                         in_port_t       port;
274                 } _n;
275         } _u;
276         ISC_LINK(struct alternate)      link;
277 } alternate_t;
278
279 struct dns_resolver {
280         /* Unlocked. */
281         unsigned int                    magic;
282         isc_mem_t *                     mctx;
283         isc_mutex_t                     lock;
284         isc_mutex_t                     nlock;  
285         isc_mutex_t                     primelock;      
286         dns_rdataclass_t                rdclass;
287         isc_socketmgr_t *               socketmgr;
288         isc_timermgr_t *                timermgr;
289         isc_taskmgr_t *                 taskmgr;
290         dns_view_t *                    view;
291         isc_boolean_t                   frozen;
292         unsigned int                    options;
293         dns_dispatchmgr_t *             dispatchmgr;
294         dns_dispatch_t *                dispatchv4;
295         dns_dispatch_t *                dispatchv6;
296         unsigned int                    nbuckets;
297         fctxbucket_t *                  buckets;
298         isc_uint32_t                    lame_ttl;
299         ISC_LIST(alternate_t)           alternates;
300         isc_uint16_t                    udpsize;
301 #if USE_ALGLOCK
302         isc_rwlock_t                    alglock;
303 #endif
304         dns_rbt_t *                     algorithms;
305 #if USE_MBSLOCK
306         isc_rwlock_t                    mbslock;
307 #endif
308         dns_rbt_t *                     mustbesecure;
309         /* Locked by lock. */
310         unsigned int                    references;
311         isc_boolean_t                   exiting;
312         isc_eventlist_t                 whenshutdown;
313         unsigned int                    activebuckets;
314         isc_boolean_t                   priming;
315         /* Locked by primelock. */
316         dns_fetch_t *                   primefetch;
317         /* Locked by nlock. */
318         unsigned int                    nfctx;
319 };
320
321 #define RES_MAGIC                       ISC_MAGIC('R', 'e', 's', '!')
322 #define VALID_RESOLVER(res)             ISC_MAGIC_VALID(res, RES_MAGIC)
323
324 /*
325  * Private addrinfo flags.  These must not conflict with DNS_FETCHOPT_NOEDNS0,
326  * which we also use as an addrinfo flag.
327  */
328 #define FCTX_ADDRINFO_MARK              0x0001
329 #define FCTX_ADDRINFO_FORWARDER         0x1000
330 #define UNMARKED(a)                     (((a)->flags & FCTX_ADDRINFO_MARK) \
331                                          == 0)
332 #define ISFORWARDER(a)                  (((a)->flags & \
333                                          FCTX_ADDRINFO_FORWARDER) != 0)
334
335 #define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
336
337 static void destroy(dns_resolver_t *res);
338 static void empty_bucket(dns_resolver_t *res);
339 static isc_result_t resquery_send(resquery_t *query);
340 static void resquery_response(isc_task_t *task, isc_event_t *event);
341 static void resquery_connected(isc_task_t *task, isc_event_t *event);
342 static void fctx_try(fetchctx_t *fctx);
343 static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
344 static isc_result_t ncache_adderesult(dns_message_t *message,
345                                       dns_db_t *cache, dns_dbnode_t *node,
346                                       dns_rdatatype_t covers,
347                                       isc_stdtime_t now, dns_ttl_t maxttl,
348                                       dns_rdataset_t *ardataset,
349                                       isc_result_t *eresultp);
350 static void validated(isc_task_t *task, isc_event_t *event); 
351
352 static isc_result_t
353 valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
354           dns_rdatatype_t type, dns_rdataset_t *rdataset,
355           dns_rdataset_t *sigrdataset, unsigned int valoptions,
356           isc_task_t *task)
357 {
358         dns_validator_t *validator = NULL;
359         dns_valarg_t *valarg;
360         isc_result_t result;
361
362         valarg = isc_mem_get(fctx->res->mctx, sizeof(*valarg));
363         if (valarg == NULL)
364                 return (ISC_R_NOMEMORY);
365
366         valarg->fctx = fctx;
367         valarg->addrinfo = addrinfo;
368
369         result = dns_validator_create(fctx->res->view, name, type, rdataset,
370                                       sigrdataset, fctx->rmessage,
371                                       valoptions, task, validated, valarg,
372                                       &validator);
373         if (result == ISC_R_SUCCESS)
374                 ISC_LIST_APPEND(fctx->validators, validator, link);
375         else
376                 isc_mem_put(fctx->res->mctx, valarg, sizeof(*valarg));
377         return (result);
378 }
379
380 static isc_boolean_t
381 fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
382         dns_name_t *name;
383         dns_name_t *domain = &fctx->domain;
384         dns_rdataset_t *rdataset;
385         dns_rdatatype_t type;
386         isc_result_t result;
387         isc_boolean_t keep_auth = ISC_FALSE;
388
389         if (message->rcode == dns_rcode_nxdomain)
390                 return (ISC_FALSE);
391
392         /*
393          * Look for BIND 8 style delegations.
394          * Also look for answers to ANY queries where the duplicate NS RRset
395          * may have been stripped from the authority section.
396          */
397         if (message->counts[DNS_SECTION_ANSWER] != 0 &&
398             (fctx->type == dns_rdatatype_ns ||
399              fctx->type == dns_rdatatype_any)) {
400                 result = dns_message_firstname(message, DNS_SECTION_ANSWER);
401                 while (result == ISC_R_SUCCESS) {
402                         name = NULL;
403                         dns_message_currentname(message, DNS_SECTION_ANSWER,
404                                                 &name);
405                         for (rdataset = ISC_LIST_HEAD(name->list);
406                              rdataset != NULL;
407                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
408                                 type = rdataset->type;
409                                 if (type != dns_rdatatype_ns)
410                                         continue;
411                                 if (dns_name_issubdomain(name, domain))
412                                         return (ISC_FALSE);
413                         }
414                         result = dns_message_nextname(message,
415                                                       DNS_SECTION_ANSWER);
416                 }
417         }
418
419         /* Look for referral. */
420         if (message->counts[DNS_SECTION_AUTHORITY] == 0)
421                 goto munge;
422
423         result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
424         while (result == ISC_R_SUCCESS) {
425                 name = NULL;
426                 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
427                 for (rdataset = ISC_LIST_HEAD(name->list);
428                      rdataset != NULL;
429                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
430                         type = rdataset->type;
431                         if (type == dns_rdatatype_soa &&
432                             dns_name_equal(name, domain))
433                                 keep_auth = ISC_TRUE;
434                         if (type != dns_rdatatype_ns &&
435                             type != dns_rdatatype_soa)
436                                 continue;
437                         if (dns_name_equal(name, domain))
438                                 goto munge;
439                         if (dns_name_issubdomain(name, domain))
440                                 return (ISC_FALSE);
441                 }
442                 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
443         }
444
445  munge:
446         message->rcode = dns_rcode_nxdomain;
447         message->counts[DNS_SECTION_ANSWER] = 0;
448         if (!keep_auth)
449                 message->counts[DNS_SECTION_AUTHORITY] = 0;
450         message->counts[DNS_SECTION_ADDITIONAL] = 0;
451         return (ISC_TRUE);
452 }
453
454 static inline isc_result_t
455 fctx_starttimer(fetchctx_t *fctx) {
456         /*
457          * Start the lifetime timer for fctx.
458          *
459          * This is also used for stopping the idle timer; in that
460          * case we must purge events already posted to ensure that
461          * no further idle events are delivered.
462          */
463         return (isc_timer_reset(fctx->timer, isc_timertype_once,
464                                 &fctx->expires, NULL,
465                                 ISC_TRUE));
466 }
467
468 static inline void
469 fctx_stoptimer(fetchctx_t *fctx) {
470         isc_result_t result;
471
472         /*
473          * We don't return a result if resetting the timer to inactive fails
474          * since there's nothing to be done about it.  Resetting to inactive
475          * should never fail anyway, since the code as currently written
476          * cannot fail in that case.
477          */
478         result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
479                                   NULL, NULL, ISC_TRUE);
480         if (result != ISC_R_SUCCESS) {
481                 UNEXPECTED_ERROR(__FILE__, __LINE__,
482                                  "isc_timer_reset(): %s",
483                                  isc_result_totext(result));
484         }
485 }
486
487
488 static inline isc_result_t
489 fctx_startidletimer(fetchctx_t *fctx) {
490         /*
491          * Start the idle timer for fctx.  The lifetime timer continues
492          * to be in effect.
493          */
494         return (isc_timer_reset(fctx->timer, isc_timertype_once,
495                                 &fctx->expires, &fctx->interval,
496                                 ISC_FALSE));
497 }
498
499 /*
500  * Stopping the idle timer is equivalent to calling fctx_starttimer(), but
501  * we use fctx_stopidletimer for readability in the code below.
502  */
503 #define fctx_stopidletimer      fctx_starttimer
504
505
506 static inline void
507 resquery_destroy(resquery_t **queryp) {
508         resquery_t *query;
509
510         REQUIRE(queryp != NULL);
511         query = *queryp;
512         REQUIRE(!ISC_LINK_LINKED(query, link));
513
514         INSIST(query->tcpsocket == NULL);
515
516         query->magic = 0;
517         isc_mem_put(query->mctx, query, sizeof(*query));
518         *queryp = NULL;
519 }
520
521 static void
522 fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
523                  isc_time_t *finish, isc_boolean_t no_response)
524 {
525         fetchctx_t *fctx;
526         resquery_t *query;
527         unsigned int rtt;
528         unsigned int factor;
529         dns_adbfind_t *find;
530         dns_adbaddrinfo_t *addrinfo;
531
532         query = *queryp;
533         fctx = query->fctx;
534
535         FCTXTRACE("cancelquery");
536
537         REQUIRE(!RESQUERY_CANCELED(query));
538
539         query->attributes |= RESQUERY_ATTR_CANCELED;
540
541         /*
542          * Should we update the RTT?
543          */
544         if (finish != NULL || no_response) {
545                 if (finish != NULL) {
546                         /*
547                          * We have both the start and finish times for this
548                          * packet, so we can compute a real RTT.
549                          */
550                         rtt = (unsigned int)isc_time_microdiff(finish,
551                                                                &query->start);
552                         factor = DNS_ADB_RTTADJDEFAULT;
553                 } else {
554                         /*
555                          * We don't have an RTT for this query.  Maybe the
556                          * packet was lost, or maybe this server is very
557                          * slow.  We don't know.  Increase the RTT.
558                          */
559                         INSIST(no_response);
560                         rtt = query->addrinfo->srtt +
561                                 (200000 * fctx->restarts);
562                         if (rtt > 10000000)
563                                 rtt = 10000000;
564                         /*
565                          * Replace the current RTT with our value.
566                          */
567                         factor = DNS_ADB_RTTADJREPLACE;
568                 }
569                 dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
570         }
571
572         /*
573          * Age RTTs of servers not tried.
574          */
575         factor = DNS_ADB_RTTADJAGE;
576         if (finish != NULL)
577                 for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
578                      addrinfo != NULL;
579                      addrinfo = ISC_LIST_NEXT(addrinfo, publink))
580                         if (UNMARKED(addrinfo))
581                                 dns_adb_adjustsrtt(fctx->adb, addrinfo,
582                                                    0, factor);
583
584         if (finish != NULL && TRIEDFIND(fctx))
585                 for (find = ISC_LIST_HEAD(fctx->finds);
586                      find != NULL;
587                      find = ISC_LIST_NEXT(find, publink))
588                         for (addrinfo = ISC_LIST_HEAD(find->list);
589                              addrinfo != NULL;
590                              addrinfo = ISC_LIST_NEXT(addrinfo, publink))
591                                 if (UNMARKED(addrinfo))
592                                         dns_adb_adjustsrtt(fctx->adb, addrinfo,
593                                                            0, factor);
594
595         if (finish != NULL && TRIEDALT(fctx)) {
596                 for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
597                      addrinfo != NULL;
598                      addrinfo = ISC_LIST_NEXT(addrinfo, publink))
599                         if (UNMARKED(addrinfo))
600                                 dns_adb_adjustsrtt(fctx->adb, addrinfo,
601                                                    0, factor);
602                 for (find = ISC_LIST_HEAD(fctx->altfinds);
603                      find != NULL;
604                      find = ISC_LIST_NEXT(find, publink))
605                         for (addrinfo = ISC_LIST_HEAD(find->list);
606                              addrinfo != NULL;
607                              addrinfo = ISC_LIST_NEXT(addrinfo, publink))
608                                 if (UNMARKED(addrinfo))
609                                         dns_adb_adjustsrtt(fctx->adb, addrinfo,
610                                                            0, factor);
611         }
612
613         if (query->dispentry != NULL)
614                 dns_dispatch_removeresponse(&query->dispentry, deventp);
615
616         ISC_LIST_UNLINK(fctx->queries, query, link);
617
618         if (query->tsig != NULL)
619                 isc_buffer_free(&query->tsig);
620
621         if (query->tsigkey != NULL)
622                 dns_tsigkey_detach(&query->tsigkey);
623
624         /*
625          * Check for any outstanding socket events.  If they exist, cancel
626          * them and let the event handlers finish the cleanup.  The resolver
627          * only needs to worry about managing the connect and send events;
628          * the dispatcher manages the recv events.
629          */
630         if (RESQUERY_CONNECTING(query))
631                 /*
632                  * Cancel the connect.
633                  */
634                 isc_socket_cancel(query->tcpsocket, NULL,
635                                   ISC_SOCKCANCEL_CONNECT);
636         else if (RESQUERY_SENDING(query))
637                 /*
638                  * Cancel the pending send.
639                  */
640                 isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
641                                   NULL, ISC_SOCKCANCEL_SEND);
642
643         if (query->dispatch != NULL)
644                 dns_dispatch_detach(&query->dispatch);
645
646         if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
647                 /*
648                  * It's safe to destroy the query now.
649                  */
650                 resquery_destroy(&query);
651 }
652
653 static void
654 fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
655         resquery_t *query, *next_query;
656
657         FCTXTRACE("cancelqueries");
658
659         for (query = ISC_LIST_HEAD(fctx->queries);
660              query != NULL;
661              query = next_query) {
662                 next_query = ISC_LIST_NEXT(query, link);
663                 fctx_cancelquery(&query, NULL, NULL, no_response);
664         }
665 }
666
667 static void
668 fctx_cleanupfinds(fetchctx_t *fctx) {
669         dns_adbfind_t *find, *next_find;
670
671         REQUIRE(ISC_LIST_EMPTY(fctx->queries));
672
673         for (find = ISC_LIST_HEAD(fctx->finds);
674              find != NULL;
675              find = next_find) {
676                 next_find = ISC_LIST_NEXT(find, publink);
677                 ISC_LIST_UNLINK(fctx->finds, find, publink);
678                 dns_adb_destroyfind(&find);
679         }
680         fctx->find = NULL;
681 }
682
683 static void
684 fctx_cleanupaltfinds(fetchctx_t *fctx) {
685         dns_adbfind_t *find, *next_find;
686
687         REQUIRE(ISC_LIST_EMPTY(fctx->queries));
688
689         for (find = ISC_LIST_HEAD(fctx->altfinds);
690              find != NULL;
691              find = next_find) {
692                 next_find = ISC_LIST_NEXT(find, publink);
693                 ISC_LIST_UNLINK(fctx->altfinds, find, publink);
694                 dns_adb_destroyfind(&find);
695         }
696         fctx->altfind = NULL;
697 }
698
699 static void
700 fctx_cleanupforwaddrs(fetchctx_t *fctx) {
701         dns_adbaddrinfo_t *addr, *next_addr;
702
703         REQUIRE(ISC_LIST_EMPTY(fctx->queries));
704
705         for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
706              addr != NULL;
707              addr = next_addr) {
708                 next_addr = ISC_LIST_NEXT(addr, publink);
709                 ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
710                 dns_adb_freeaddrinfo(fctx->adb, &addr);
711         }
712 }
713
714 static void
715 fctx_cleanupaltaddrs(fetchctx_t *fctx) {
716         dns_adbaddrinfo_t *addr, *next_addr;
717
718         REQUIRE(ISC_LIST_EMPTY(fctx->queries));
719
720         for (addr = ISC_LIST_HEAD(fctx->altaddrs);
721              addr != NULL;
722              addr = next_addr) {
723                 next_addr = ISC_LIST_NEXT(addr, publink);
724                 ISC_LIST_UNLINK(fctx->altaddrs, addr, publink);
725                 dns_adb_freeaddrinfo(fctx->adb, &addr);
726         }
727 }
728
729 static inline void
730 fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
731         FCTXTRACE("stopeverything");
732         fctx_cancelqueries(fctx, no_response);
733         fctx_cleanupfinds(fctx);
734         fctx_cleanupaltfinds(fctx);
735         fctx_cleanupforwaddrs(fctx);
736         fctx_cleanupaltaddrs(fctx);
737         fctx_stoptimer(fctx);
738 }
739
740 static inline void
741 fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
742         dns_fetchevent_t *event, *next_event;
743         isc_task_t *task;
744
745         /*
746          * Caller must be holding the appropriate bucket lock.
747          */
748         REQUIRE(fctx->state == fetchstate_done);
749
750         FCTXTRACE("sendevents");
751
752         for (event = ISC_LIST_HEAD(fctx->events);
753              event != NULL;
754              event = next_event) {
755                 next_event = ISC_LIST_NEXT(event, ev_link);
756                 ISC_LIST_UNLINK(fctx->events, event, ev_link);
757                 task = event->ev_sender;
758                 event->ev_sender = fctx;
759                 if (!HAVE_ANSWER(fctx))
760                         event->result = result;
761
762                 INSIST(result != ISC_R_SUCCESS ||
763                        dns_rdataset_isassociated(event->rdataset) ||
764                        fctx->type == dns_rdatatype_any ||
765                        fctx->type == dns_rdatatype_rrsig);
766
767                 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
768         }
769 }
770
771 static void
772 fctx_done(fetchctx_t *fctx, isc_result_t result) {
773         dns_resolver_t *res;
774         isc_boolean_t no_response;
775
776         FCTXTRACE("done");
777
778         res = fctx->res;
779
780         if (result == ISC_R_SUCCESS)
781                 no_response = ISC_TRUE;
782         else
783                 no_response = ISC_FALSE;
784         fctx_stopeverything(fctx, no_response);
785
786         LOCK(&res->buckets[fctx->bucketnum].lock);
787
788         fctx->state = fetchstate_done;
789         fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
790         fctx_sendevents(fctx, result);
791
792         UNLOCK(&res->buckets[fctx->bucketnum].lock);
793 }
794
795 static void
796 resquery_senddone(isc_task_t *task, isc_event_t *event) {
797         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
798         resquery_t *query = event->ev_arg;
799         isc_boolean_t retry = ISC_FALSE;
800         isc_result_t result;
801         fetchctx_t *fctx;
802
803         REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
804
805         QTRACE("senddone");
806
807         /*
808          * XXXRTH
809          *
810          * Currently we don't wait for the senddone event before retrying
811          * a query.  This means that if we get really behind, we may end
812          * up doing extra work!
813          */
814
815         UNUSED(task);
816
817         INSIST(RESQUERY_SENDING(query));
818
819         query->sends--;
820         fctx = query->fctx;
821
822         if (RESQUERY_CANCELED(query)) {
823                 if (query->sends == 0) {
824                         /*
825                          * This query was canceled while the
826                          * isc_socket_sendto() was in progress.
827                          */
828                         if (query->tcpsocket != NULL)
829                                 isc_socket_detach(&query->tcpsocket);
830                         resquery_destroy(&query);
831                 }
832         } else 
833                 switch (sevent->result) {
834                 case ISC_R_SUCCESS:
835                         break;
836
837                 case ISC_R_HOSTUNREACH:
838                 case ISC_R_NETUNREACH:
839                 case ISC_R_NOPERM:
840                 case ISC_R_ADDRNOTAVAIL:
841                 case ISC_R_CONNREFUSED:
842
843                         /*
844                          * No route to remote.
845                          */
846                         fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
847                         retry = ISC_TRUE;
848                         break;
849
850                 default:
851                         fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
852                         break;
853                 }
854
855         isc_event_free(&event);
856
857         if (retry) {
858                 /*
859                  * Behave as if the idle timer has expired.  For TCP
860                  * this may not actually reflect the latest timer.
861                  */
862                 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
863                 result = fctx_stopidletimer(fctx);
864                 if (result != ISC_R_SUCCESS)
865                         fctx_done(fctx, result);
866                 else
867                         fctx_try(fctx);
868         }
869 }
870
871 static inline isc_result_t
872 fctx_addopt(dns_message_t *message, dns_resolver_t *res) {
873         dns_rdataset_t *rdataset;
874         dns_rdatalist_t *rdatalist;
875         dns_rdata_t *rdata;
876         isc_result_t result;
877
878         rdatalist = NULL;
879         result = dns_message_gettemprdatalist(message, &rdatalist);
880         if (result != ISC_R_SUCCESS)
881                 return (result);
882         rdata = NULL;
883         result = dns_message_gettemprdata(message, &rdata);
884         if (result != ISC_R_SUCCESS)
885                 return (result);
886         rdataset = NULL;
887         result = dns_message_gettemprdataset(message, &rdataset);
888         if (result != ISC_R_SUCCESS)
889                 return (result);
890         dns_rdataset_init(rdataset);
891
892         rdatalist->type = dns_rdatatype_opt;
893         rdatalist->covers = 0;
894
895         /*
896          * Set Maximum UDP buffer size.
897          */
898         rdatalist->rdclass = res->udpsize;
899
900         /*
901          * Set EXTENDED-RCODE, VERSION, and Z to 0, and the DO bit to 1.
902          */
903         rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO;
904
905         /*
906          * No EDNS options.
907          */
908         rdata->data = NULL;
909         rdata->length = 0;
910         rdata->rdclass = rdatalist->rdclass;
911         rdata->type = rdatalist->type;
912         rdata->flags = 0;
913
914         ISC_LIST_INIT(rdatalist->rdata);
915         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
916         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
917
918         return (dns_message_setopt(message, rdataset));
919 }
920
921 static inline void
922 fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
923         unsigned int seconds;
924
925         /*
926          * We retry every 2 seconds the first two times through the address
927          * list, and then we do exponential back-off.
928          */
929         if (fctx->restarts < 3)
930                 seconds = 2;
931         else
932                 seconds = (2 << (fctx->restarts - 1));
933
934         /*
935          * Double the round-trip time and convert to seconds.
936          */
937         rtt /= 500000;
938
939         /*
940          * Always wait for at least the doubled round-trip time.
941          */
942         if (seconds < rtt)
943                 seconds = rtt;
944
945         /*
946          * But don't ever wait for more than 30 seconds.
947          */
948         if (seconds > 30)
949                 seconds = 30;
950
951         isc_interval_set(&fctx->interval, seconds, 0);
952 }
953
954 static isc_result_t
955 fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
956            unsigned int options)
957 {
958         dns_resolver_t *res;
959         isc_task_t *task;
960         isc_result_t result;
961         resquery_t *query;
962
963         FCTXTRACE("query");
964
965         res = fctx->res;
966         task = res->buckets[fctx->bucketnum].task;
967
968         fctx_setretryinterval(fctx, addrinfo->srtt);
969         result = fctx_startidletimer(fctx);
970         if (result != ISC_R_SUCCESS)
971                 return (result);
972
973         dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
974
975         query = isc_mem_get(res->mctx, sizeof(*query));
976         if (query == NULL) {
977                 result = ISC_R_NOMEMORY;
978                 goto stop_idle_timer;
979         }
980         query->mctx = res->mctx;
981         query->options = options;
982         query->attributes = 0;
983         query->sends = 0;
984         query->connects = 0;
985         /*
986          * Note that the caller MUST guarantee that 'addrinfo' will remain
987          * valid until this query is canceled.
988          */
989         query->addrinfo = addrinfo;
990         TIME_NOW(&query->start);
991
992         /*
993          * If this is a TCP query, then we need to make a socket and
994          * a dispatch for it here.  Otherwise we use the resolver's
995          * shared dispatch.
996          */
997         query->dispatchmgr = res->dispatchmgr;
998         query->dispatch = NULL;
999         query->tcpsocket = NULL;
1000         if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1001                 isc_sockaddr_t addr;
1002                 int pf;
1003
1004                 pf = isc_sockaddr_pf(&addrinfo->sockaddr);
1005
1006                 switch (pf) {
1007                 case PF_INET:
1008                         result = dns_dispatch_getlocaladdress(res->dispatchv4,
1009                                                               &addr);
1010                         break;
1011                 case PF_INET6:
1012                         result = dns_dispatch_getlocaladdress(res->dispatchv6,
1013                                                               &addr);
1014                         break;
1015                 default:
1016                         result = ISC_R_NOTIMPLEMENTED;
1017                         break;
1018                 }
1019                 if (result != ISC_R_SUCCESS)
1020                         goto cleanup_query;
1021
1022                 isc_sockaddr_setport(&addr, 0);
1023
1024                 result = isc_socket_create(res->socketmgr, pf,
1025                                            isc_sockettype_tcp,
1026                                            &query->tcpsocket);
1027                 if (result != ISC_R_SUCCESS)
1028                         goto cleanup_query;
1029
1030                 result = isc_socket_bind(query->tcpsocket, &addr);
1031                 if (result != ISC_R_SUCCESS)
1032                         goto cleanup_socket;
1033
1034                 /*
1035                  * A dispatch will be created once the connect succeeds.
1036                  */
1037         } else {
1038                 switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
1039                 case PF_INET:
1040                         dns_dispatch_attach(res->dispatchv4, &query->dispatch);
1041                         break;
1042                 case PF_INET6:
1043                         dns_dispatch_attach(res->dispatchv6, &query->dispatch);
1044                         break;
1045                 default:
1046                         result = ISC_R_NOTIMPLEMENTED;
1047                         goto cleanup_query;
1048                 }
1049                 /*
1050                  * We should always have a valid dispatcher here.  If we
1051                  * don't support a protocol family, then its dispatcher
1052                  * will be NULL, but we shouldn't be finding addresses for
1053                  * protocol types we don't support, so the dispatcher
1054                  * we found should never be NULL.
1055                  */
1056                 INSIST(query->dispatch != NULL);
1057         }
1058
1059         query->dispentry = NULL;
1060         query->fctx = fctx;
1061         query->tsig = NULL;
1062         query->tsigkey = NULL;
1063         ISC_LINK_INIT(query, link);
1064         query->magic = QUERY_MAGIC;
1065
1066         if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1067                 /*
1068                  * Connect to the remote server.
1069                  *
1070                  * XXXRTH  Should we attach to the socket?
1071                  */
1072                 result = isc_socket_connect(query->tcpsocket,
1073                                             &addrinfo->sockaddr, task,
1074                                             resquery_connected, query);
1075                 if (result != ISC_R_SUCCESS)
1076                         goto cleanup_socket;
1077                 query->connects++;
1078                 QTRACE("connecting via TCP");
1079         } else {
1080                 result = resquery_send(query);
1081                 if (result != ISC_R_SUCCESS)
1082                         goto cleanup_dispatch;
1083         }
1084
1085         ISC_LIST_APPEND(fctx->queries, query, link);
1086
1087         return (ISC_R_SUCCESS);
1088
1089  cleanup_socket:
1090         isc_socket_detach(&query->tcpsocket);
1091
1092  cleanup_dispatch:
1093         if (query->dispatch != NULL)
1094                 dns_dispatch_detach(&query->dispatch);
1095
1096  cleanup_query:
1097         query->magic = 0;
1098         isc_mem_put(res->mctx, query, sizeof(*query));
1099
1100  stop_idle_timer:
1101         RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS);
1102
1103         return (result);
1104 }
1105
1106 static isc_result_t
1107 resquery_send(resquery_t *query) {
1108         fetchctx_t *fctx;
1109         isc_result_t result;
1110         dns_name_t *qname = NULL;
1111         dns_rdataset_t *qrdataset = NULL;
1112         isc_region_t r;
1113         dns_resolver_t *res;
1114         isc_task_t *task;
1115         isc_socket_t *socket;
1116         isc_buffer_t tcpbuffer;
1117         isc_sockaddr_t *address;
1118         isc_buffer_t *buffer;
1119         isc_netaddr_t ipaddr;
1120         dns_tsigkey_t *tsigkey = NULL;
1121         dns_peer_t *peer = NULL;
1122         isc_boolean_t useedns;
1123         dns_compress_t cctx;
1124         isc_boolean_t cleanup_cctx = ISC_FALSE;
1125         isc_boolean_t secure_domain;
1126
1127         fctx = query->fctx;
1128         QTRACE("send");
1129
1130         res = fctx->res;
1131         task = res->buckets[fctx->bucketnum].task;
1132         address = NULL;
1133
1134         if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1135                 /*
1136                  * Reserve space for the TCP message length.
1137                  */
1138                 isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data));
1139                 isc_buffer_init(&query->buffer, query->data + 2,
1140                                 sizeof(query->data) - 2);
1141                 buffer = &tcpbuffer;
1142         } else {
1143                 isc_buffer_init(&query->buffer, query->data,
1144                                 sizeof(query->data));
1145                 buffer = &query->buffer;
1146         }
1147
1148         result = dns_message_gettempname(fctx->qmessage, &qname);
1149         if (result != ISC_R_SUCCESS)
1150                 goto cleanup_temps;
1151         result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
1152         if (result != ISC_R_SUCCESS)
1153                 goto cleanup_temps;
1154
1155         /*
1156          * Get a query id from the dispatch.
1157          */
1158         result = dns_dispatch_addresponse(query->dispatch,
1159                                           &query->addrinfo->sockaddr,
1160                                           task,
1161                                           resquery_response,
1162                                           query,
1163                                           &query->id,
1164                                           &query->dispentry);
1165         if (result != ISC_R_SUCCESS)
1166                 goto cleanup_temps;
1167
1168         fctx->qmessage->opcode = dns_opcode_query;
1169
1170         /*
1171          * Set up question.
1172          */
1173         dns_name_init(qname, NULL);
1174         dns_name_clone(&fctx->name, qname);
1175         dns_rdataset_init(qrdataset);
1176         dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
1177         ISC_LIST_APPEND(qname->list, qrdataset, link);
1178         dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
1179         qname = NULL;
1180         qrdataset = NULL;
1181
1182         /*
1183          * Set RD if the client has requested that we do a recursive query,
1184          * or if we're sending to a forwarder.
1185          */
1186         if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||
1187             ISFORWARDER(query->addrinfo))
1188                 fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;
1189
1190         /*
1191          * Set CD if the client says don't validate or the question is
1192          * under a secure entry point.
1193          */
1194         if ((query->options & DNS_FETCHOPT_NOVALIDATE) == 0) {
1195                 result = dns_keytable_issecuredomain(res->view->secroots,
1196                                                      &fctx->name,
1197                                                      &secure_domain);
1198                 if (result != ISC_R_SUCCESS)
1199                         secure_domain = ISC_FALSE;
1200                 if (res->view->dlv != NULL)
1201                         secure_domain = ISC_TRUE;
1202                 if (secure_domain)
1203                         fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
1204         } else
1205                 fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
1206
1207         /*
1208          * We don't have to set opcode because it defaults to query.
1209          */
1210         fctx->qmessage->id = query->id;
1211
1212         /*
1213          * Convert the question to wire format.
1214          */
1215         result = dns_compress_init(&cctx, -1, fctx->res->mctx);
1216         if (result != ISC_R_SUCCESS)
1217                 goto cleanup_message;
1218         cleanup_cctx = ISC_TRUE;
1219
1220         result = dns_message_renderbegin(fctx->qmessage, &cctx,
1221                                          &query->buffer);
1222         if (result != ISC_R_SUCCESS)
1223                 goto cleanup_message;
1224
1225         result = dns_message_rendersection(fctx->qmessage,
1226                                            DNS_SECTION_QUESTION, 0);
1227         if (result != ISC_R_SUCCESS)
1228                 goto cleanup_message;
1229
1230         peer = NULL;
1231         isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr);
1232         (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer);
1233
1234         /*
1235          * The ADB does not know about servers with "edns no".  Check this,
1236          * and then inform the ADB for future use.
1237          */
1238         if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 &&
1239             peer != NULL &&
1240             dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS &&
1241             !useedns)
1242         {
1243                 query->options |= DNS_FETCHOPT_NOEDNS0;
1244                 dns_adb_changeflags(fctx->adb,
1245                                     query->addrinfo,
1246                                     DNS_FETCHOPT_NOEDNS0,
1247                                     DNS_FETCHOPT_NOEDNS0);
1248         }
1249
1250         /*
1251          * Use EDNS0, unless the caller doesn't want it, or we know that
1252          * the remote server doesn't like it.
1253          */
1254         if (fctx->timeouts >= MAX_EDNS0_TIMEOUTS &&
1255             (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
1256                 query->options |= DNS_FETCHOPT_NOEDNS0;
1257                 FCTXTRACE("too many timeouts, disabling EDNS0");
1258         }
1259
1260         if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
1261                 if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
1262                         result = fctx_addopt(fctx->qmessage, res);
1263                         if (result != ISC_R_SUCCESS) {
1264                                 /*
1265                                  * We couldn't add the OPT, but we'll press on.
1266                                  * We're not using EDNS0, so set the NOEDNS0
1267                                  * bit.
1268                                  */
1269                                 query->options |= DNS_FETCHOPT_NOEDNS0;
1270                         }
1271                 } else {
1272                         /*
1273                          * We know this server doesn't like EDNS0, so we
1274                          * won't use it.  Set the NOEDNS0 bit since we're
1275                          * not using EDNS0.
1276                          */
1277                         query->options |= DNS_FETCHOPT_NOEDNS0;
1278                 }
1279         }
1280
1281         /*
1282          * If we need EDNS0 to do this query and aren't using it, we lose.
1283          */
1284         if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) {
1285                 result = DNS_R_SERVFAIL;
1286                 goto cleanup_message;
1287         }
1288
1289         /*
1290          * Add TSIG record tailored to the current recipient.
1291          */
1292         result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey);
1293         if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
1294                 goto cleanup_message;
1295
1296         if (tsigkey != NULL) {
1297                 result = dns_message_settsigkey(fctx->qmessage, tsigkey);
1298                 dns_tsigkey_detach(&tsigkey);
1299                 if (result != ISC_R_SUCCESS)
1300                         goto cleanup_message;
1301         }
1302
1303         result = dns_message_rendersection(fctx->qmessage,
1304                                            DNS_SECTION_ADDITIONAL, 0);
1305         if (result != ISC_R_SUCCESS)
1306                 goto cleanup_message;
1307
1308         result = dns_message_renderend(fctx->qmessage);
1309         if (result != ISC_R_SUCCESS)
1310                 goto cleanup_message;
1311
1312         dns_compress_invalidate(&cctx);
1313         cleanup_cctx = ISC_FALSE;
1314
1315         if (dns_message_gettsigkey(fctx->qmessage) != NULL) {
1316                 dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage),
1317                                    &query->tsigkey);
1318                 result = dns_message_getquerytsig(fctx->qmessage,
1319                                                   fctx->res->mctx,
1320                                                   &query->tsig);
1321                 if (result != ISC_R_SUCCESS)
1322                         goto cleanup_message;
1323         }
1324
1325         /*
1326          * If using TCP, write the length of the message at the beginning
1327          * of the buffer.
1328          */
1329         if ((query->options & DNS_FETCHOPT_TCP) != 0) {
1330                 isc_buffer_usedregion(&query->buffer, &r);
1331                 isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
1332                 isc_buffer_add(&tcpbuffer, r.length);
1333         }
1334
1335         /*
1336          * We're now done with the query message.
1337          */
1338         dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
1339
1340         socket = dns_dispatch_getsocket(query->dispatch);
1341         /*
1342          * Send the query!
1343          */
1344         if ((query->options & DNS_FETCHOPT_TCP) == 0)
1345                 address = &query->addrinfo->sockaddr;
1346         isc_buffer_usedregion(buffer, &r);
1347
1348         /*
1349          * XXXRTH  Make sure we don't send to ourselves!  We should probably
1350          *         prune out these addresses when we get them from the ADB.
1351          */
1352         result = isc_socket_sendto(socket, &r, task, resquery_senddone,
1353                                    query, address, NULL);
1354         if (result != ISC_R_SUCCESS)
1355                 goto cleanup_message;
1356         query->sends++;
1357         QTRACE("sent");
1358
1359         return (ISC_R_SUCCESS);
1360
1361  cleanup_message:
1362         if (cleanup_cctx)
1363                 dns_compress_invalidate(&cctx);
1364
1365         dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
1366
1367         /*
1368          * Stop the dispatcher from listening.
1369          */
1370         dns_dispatch_removeresponse(&query->dispentry, NULL);
1371
1372  cleanup_temps:
1373         if (qname != NULL)
1374                 dns_message_puttempname(fctx->qmessage, &qname);
1375         if (qrdataset != NULL)
1376                 dns_message_puttemprdataset(fctx->qmessage, &qrdataset);
1377
1378         return (result);
1379 }
1380
1381 static void
1382 resquery_connected(isc_task_t *task, isc_event_t *event) {
1383         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1384         resquery_t *query = event->ev_arg;
1385         isc_boolean_t retry = ISC_FALSE;
1386         isc_result_t result;
1387         unsigned int attrs;
1388         fetchctx_t *fctx;
1389
1390         REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1391         REQUIRE(VALID_QUERY(query));
1392
1393         QTRACE("connected");
1394
1395         UNUSED(task);
1396
1397         /*
1398          * XXXRTH
1399          *
1400          * Currently we don't wait for the connect event before retrying
1401          * a query.  This means that if we get really behind, we may end
1402          * up doing extra work!
1403          */
1404
1405         query->connects--;
1406         fctx = query->fctx;
1407
1408         if (RESQUERY_CANCELED(query)) {
1409                 /*
1410                  * This query was canceled while the connect() was in
1411                  * progress.
1412                  */
1413                 isc_socket_detach(&query->tcpsocket);
1414                 resquery_destroy(&query);
1415         } else {
1416                 switch (sevent->result) {
1417                 case ISC_R_SUCCESS:
1418                         /*
1419                          * We are connected.  Create a dispatcher and
1420                          * send the query.
1421                          */
1422                         attrs = 0;
1423                         attrs |= DNS_DISPATCHATTR_TCP;
1424                         attrs |= DNS_DISPATCHATTR_PRIVATE;
1425                         attrs |= DNS_DISPATCHATTR_CONNECTED;
1426                         if (isc_sockaddr_pf(&query->addrinfo->sockaddr) ==
1427                             AF_INET)
1428                                 attrs |= DNS_DISPATCHATTR_IPV4;
1429                         else
1430                                 attrs |= DNS_DISPATCHATTR_IPV6;
1431                         attrs |= DNS_DISPATCHATTR_MAKEQUERY;
1432
1433                         result = dns_dispatch_createtcp(query->dispatchmgr,
1434                                                      query->tcpsocket,
1435                                                      query->fctx->res->taskmgr,
1436                                                      4096, 2, 1, 1, 3, attrs,
1437                                                      &query->dispatch);
1438
1439                         /*
1440                          * Regardless of whether dns_dispatch_create()
1441                          * succeeded or not, we don't need our reference
1442                          * to the socket anymore.
1443                          */
1444                         isc_socket_detach(&query->tcpsocket);
1445
1446                         if (result == ISC_R_SUCCESS)
1447                                 result = resquery_send(query);
1448
1449                         if (result != ISC_R_SUCCESS) {
1450                                 fctx_cancelquery(&query, NULL, NULL,
1451                                                  ISC_FALSE);
1452                                 fctx_done(fctx, result);
1453                         }
1454                         break;
1455
1456                 case ISC_R_NETUNREACH:
1457                 case ISC_R_HOSTUNREACH:
1458                 case ISC_R_CONNREFUSED:
1459                 case ISC_R_NOPERM:
1460                 case ISC_R_ADDRNOTAVAIL:
1461                 case ISC_R_CONNECTIONRESET:
1462                         /*
1463                          * No route to remote.
1464                          */
1465                         isc_socket_detach(&query->tcpsocket);
1466                         fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
1467                         retry = ISC_TRUE;
1468                         break;
1469
1470                 default:
1471                         isc_socket_detach(&query->tcpsocket);
1472                         fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
1473                         break;
1474                 }
1475         }
1476
1477         isc_event_free(&event);
1478         
1479         if (retry) {
1480                 /*
1481                  * Behave as if the idle timer has expired.  For TCP
1482                  * connections this may not actually reflect the latest timer.
1483                  */
1484                 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1485                 result = fctx_stopidletimer(fctx);
1486                 if (result != ISC_R_SUCCESS)
1487                         fctx_done(fctx, result);
1488                 else
1489                         fctx_try(fctx);
1490         }
1491 }
1492
1493 static void
1494 fctx_finddone(isc_task_t *task, isc_event_t *event) {
1495         fetchctx_t *fctx;
1496         dns_adbfind_t *find;
1497         dns_resolver_t *res;
1498         isc_boolean_t want_try = ISC_FALSE;
1499         isc_boolean_t want_done = ISC_FALSE;
1500         isc_boolean_t bucket_empty = ISC_FALSE;
1501         unsigned int bucketnum;
1502
1503         find = event->ev_sender;
1504         fctx = event->ev_arg;
1505         REQUIRE(VALID_FCTX(fctx));
1506         res = fctx->res;
1507
1508         UNUSED(task);
1509
1510         FCTXTRACE("finddone");
1511
1512         INSIST(fctx->pending > 0);
1513         fctx->pending--;
1514
1515         if (ADDRWAIT(fctx)) {
1516                 /*
1517                  * The fetch is waiting for a name to be found.
1518                  */
1519                 INSIST(!SHUTTINGDOWN(fctx));
1520                 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1521                 if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
1522                         want_try = ISC_TRUE;
1523                 else if (fctx->pending == 0) {
1524                         /*
1525                          * We've got nothing else to wait for and don't
1526                          * know the answer.  There's nothing to do but
1527                          * fail the fctx.
1528                          */
1529                         want_done = ISC_TRUE;
1530                 }
1531         } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
1532                    ISC_LIST_EMPTY(fctx->validators)) {
1533                 bucketnum = fctx->bucketnum;
1534                 LOCK(&res->buckets[bucketnum].lock);
1535                 /*
1536                  * Note that we had to wait until we had the lock before
1537                  * looking at fctx->references.
1538                  */
1539                 if (fctx->references == 0)
1540                         bucket_empty = fctx_destroy(fctx);
1541                 UNLOCK(&res->buckets[bucketnum].lock);
1542         }
1543
1544         isc_event_free(&event);
1545         dns_adb_destroyfind(&find);
1546
1547         if (want_try)
1548                 fctx_try(fctx);
1549         else if (want_done)
1550                 fctx_done(fctx, ISC_R_FAILURE);
1551         else if (bucket_empty)
1552                 empty_bucket(res);
1553 }
1554
1555
1556 static inline isc_boolean_t
1557 bad_server(fetchctx_t *fctx, isc_sockaddr_t *address) {
1558         isc_sockaddr_t *sa;
1559
1560         for (sa = ISC_LIST_HEAD(fctx->bad);
1561              sa != NULL;
1562              sa = ISC_LIST_NEXT(sa, link)) {
1563                 if (isc_sockaddr_equal(sa, address))
1564                         return (ISC_TRUE);
1565         }
1566
1567         return (ISC_FALSE);
1568 }
1569
1570 static inline isc_boolean_t
1571 mark_bad(fetchctx_t *fctx) {
1572         dns_adbfind_t *curr;
1573         dns_adbaddrinfo_t *addrinfo;
1574         isc_boolean_t all_bad = ISC_TRUE;
1575
1576         /*
1577          * Mark all known bad servers, so we don't try to talk to them
1578          * again.
1579          */
1580
1581         /*
1582          * Mark any bad nameservers.
1583          */
1584         for (curr = ISC_LIST_HEAD(fctx->finds);
1585              curr != NULL;
1586              curr = ISC_LIST_NEXT(curr, publink)) {
1587                 for (addrinfo = ISC_LIST_HEAD(curr->list);
1588                      addrinfo != NULL;
1589                      addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1590                         if (bad_server(fctx, &addrinfo->sockaddr))
1591                                 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1592                         else
1593                                 all_bad = ISC_FALSE;
1594                 }
1595         }
1596
1597         /*
1598          * Mark any bad forwarders.
1599          */
1600         for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
1601              addrinfo != NULL;
1602              addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1603                 if (bad_server(fctx, &addrinfo->sockaddr))
1604                         addrinfo->flags |= FCTX_ADDRINFO_MARK;
1605                 else
1606                         all_bad = ISC_FALSE;
1607         }
1608
1609         /*
1610          * Mark any bad alternates.
1611          */
1612         for (curr = ISC_LIST_HEAD(fctx->altfinds);
1613              curr != NULL;
1614              curr = ISC_LIST_NEXT(curr, publink)) {
1615                 for (addrinfo = ISC_LIST_HEAD(curr->list);
1616                      addrinfo != NULL;
1617                      addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1618                         if (bad_server(fctx, &addrinfo->sockaddr))
1619                                 addrinfo->flags |= FCTX_ADDRINFO_MARK;
1620                         else
1621                                 all_bad = ISC_FALSE;
1622                 }
1623         }
1624
1625         for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
1626              addrinfo != NULL;
1627              addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
1628                 if (bad_server(fctx, &addrinfo->sockaddr))
1629                         addrinfo->flags |= FCTX_ADDRINFO_MARK;
1630                 else
1631                         all_bad = ISC_FALSE;
1632         }
1633
1634         return (all_bad);
1635 }
1636
1637 static void
1638 add_bad(fetchctx_t *fctx, isc_sockaddr_t *address, isc_result_t reason) {
1639         char namebuf[DNS_NAME_FORMATSIZE];
1640         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1641         char classbuf[64];
1642         char typebuf[64];
1643         char code[64];
1644         isc_buffer_t b;
1645         isc_sockaddr_t *sa;
1646         const char *sep1, *sep2;
1647
1648         if (bad_server(fctx, address)) {
1649                 /*
1650                  * We already know this server is bad.
1651                  */
1652                 return;
1653         }
1654
1655         FCTXTRACE("add_bad");
1656
1657         sa = isc_mem_get(fctx->res->mctx, sizeof(*sa));
1658         if (sa == NULL)
1659                 return;
1660         *sa = *address;
1661         ISC_LIST_INITANDAPPEND(fctx->bad, sa, link);
1662
1663         if (reason == DNS_R_LAME)       /* already logged */
1664                 return;
1665
1666         if (reason == DNS_R_UNEXPECTEDRCODE) {
1667                 isc_buffer_init(&b, code, sizeof(code) - 1);
1668                 dns_rcode_totext(fctx->rmessage->rcode, &b);
1669                 code[isc_buffer_usedlength(&b)] = '\0';
1670                 sep1 = "(";
1671                 sep2 = ") ";
1672         } else if (reason == DNS_R_UNEXPECTEDOPCODE) {
1673                 isc_buffer_init(&b, code, sizeof(code) - 1);
1674                 dns_opcode_totext((dns_opcode_t)fctx->rmessage->opcode, &b);
1675                 code[isc_buffer_usedlength(&b)] = '\0';
1676                 sep1 = "(";
1677                 sep2 = ") ";
1678         } else {
1679                 code[0] = '\0';
1680                 sep1 = "";
1681                 sep2 = "";
1682         }
1683         dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
1684         dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
1685         dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf));
1686         isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
1687         isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
1688                       DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
1689                       "%s %s%s%sresolving '%s/%s/%s': %s",
1690                       dns_result_totext(reason), sep1, code, sep2,
1691                       namebuf, typebuf, classbuf, addrbuf);
1692 }
1693
1694 static void
1695 sort_adbfind(dns_adbfind_t *find) {
1696         dns_adbaddrinfo_t *best, *curr;
1697         dns_adbaddrinfolist_t sorted;
1698
1699         /*
1700          * Lame N^2 bubble sort.
1701          */
1702
1703         ISC_LIST_INIT(sorted);
1704         while (!ISC_LIST_EMPTY(find->list)) {
1705                 best = ISC_LIST_HEAD(find->list);
1706                 curr = ISC_LIST_NEXT(best, publink);
1707                 while (curr != NULL) {
1708                         if (curr->srtt < best->srtt)
1709                                 best = curr;
1710                         curr = ISC_LIST_NEXT(curr, publink);
1711                 }
1712                 ISC_LIST_UNLINK(find->list, best, publink);
1713                 ISC_LIST_APPEND(sorted, best, publink);
1714         }
1715         find->list = sorted;
1716 }
1717
1718 static void
1719 sort_finds(fetchctx_t *fctx) {
1720         dns_adbfind_t *best, *curr;
1721         dns_adbfindlist_t sorted;
1722         dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
1723
1724         /*
1725          * Lame N^2 bubble sort.
1726          */
1727
1728         ISC_LIST_INIT(sorted);
1729         while (!ISC_LIST_EMPTY(fctx->finds)) {
1730                 best = ISC_LIST_HEAD(fctx->finds);
1731                 bestaddrinfo = ISC_LIST_HEAD(best->list);
1732                 INSIST(bestaddrinfo != NULL);
1733                 curr = ISC_LIST_NEXT(best, publink);
1734                 while (curr != NULL) {
1735                         addrinfo = ISC_LIST_HEAD(curr->list);
1736                         INSIST(addrinfo != NULL);
1737                         if (addrinfo->srtt < bestaddrinfo->srtt) {
1738                                 best = curr;
1739                                 bestaddrinfo = addrinfo;
1740                         }
1741                         curr = ISC_LIST_NEXT(curr, publink);
1742                 }
1743                 ISC_LIST_UNLINK(fctx->finds, best, publink);
1744                 ISC_LIST_APPEND(sorted, best, publink);
1745         }
1746         fctx->finds = sorted;
1747
1748         ISC_LIST_INIT(sorted);
1749         while (!ISC_LIST_EMPTY(fctx->altfinds)) {
1750                 best = ISC_LIST_HEAD(fctx->altfinds);
1751                 bestaddrinfo = ISC_LIST_HEAD(best->list);
1752                 INSIST(bestaddrinfo != NULL);
1753                 curr = ISC_LIST_NEXT(best, publink);
1754                 while (curr != NULL) {
1755                         addrinfo = ISC_LIST_HEAD(curr->list);
1756                         INSIST(addrinfo != NULL);
1757                         if (addrinfo->srtt < bestaddrinfo->srtt) {
1758                                 best = curr;
1759                                 bestaddrinfo = addrinfo;
1760                         }
1761                         curr = ISC_LIST_NEXT(curr, publink);
1762                 }
1763                 ISC_LIST_UNLINK(fctx->altfinds, best, publink);
1764                 ISC_LIST_APPEND(sorted, best, publink);
1765         }
1766         fctx->altfinds = sorted;
1767 }
1768
1769 static void
1770 findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
1771          unsigned int options, unsigned int flags, isc_stdtime_t now,
1772          isc_boolean_t *pruned, isc_boolean_t *need_alternate)
1773 {
1774         dns_adbaddrinfo_t *ai;
1775         dns_adbfind_t *find;
1776         dns_resolver_t *res;
1777         isc_boolean_t unshared;
1778         isc_result_t result;
1779
1780         res = fctx->res;
1781         unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0);
1782         /*
1783          * If this name is a subdomain of the query domain, tell
1784          * the ADB to start looking using zone/hint data. This keeps us
1785          * from getting stuck if the nameserver is beneath the zone cut
1786          * and we don't know its address (e.g. because the A record has
1787          * expired).
1788          */
1789         if (dns_name_issubdomain(name, &fctx->domain))
1790                 options |= DNS_ADBFIND_STARTATZONE;
1791         options |= DNS_ADBFIND_GLUEOK;
1792         options |= DNS_ADBFIND_HINTOK;
1793
1794         /*
1795          * See what we know about this address.
1796          */
1797         find = NULL;
1798         result = dns_adb_createfind(fctx->adb,
1799                                     res->buckets[fctx->bucketnum].task,
1800                                     fctx_finddone, fctx, name,
1801                                     &fctx->domain, options, now, NULL,
1802                                     res->view->dstport, &find);
1803         if (result != ISC_R_SUCCESS) {
1804                 if (result == DNS_R_ALIAS) {
1805                         /*
1806                          * XXXRTH  Follow the CNAME/DNAME chain?
1807                          */
1808                         dns_adb_destroyfind(&find);
1809                 }
1810         } else if (!ISC_LIST_EMPTY(find->list)) {
1811                 /*
1812                  * We have at least some of the addresses for the
1813                  * name.
1814                  */
1815                 INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
1816                 sort_adbfind(find);
1817                 if (flags != 0 || port != 0) {
1818                         for (ai = ISC_LIST_HEAD(find->list);
1819                              ai != NULL;
1820                              ai = ISC_LIST_NEXT(ai, publink)) {
1821                                 ai->flags |= flags;
1822                                 if (port != 0)
1823                                         isc_sockaddr_setport(&ai->sockaddr,
1824                                                              port);
1825                         }
1826                 }
1827                 if ((flags & FCTX_ADDRINFO_FORWARDER) != 0)
1828                         ISC_LIST_APPEND(fctx->altfinds, find, publink);
1829                 else
1830                         ISC_LIST_APPEND(fctx->finds, find, publink);
1831         } else {
1832                 /*
1833                  * We don't know any of the addresses for this
1834                  * name.
1835                  */
1836                 if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
1837                         /*
1838                          * We're looking for them and will get an
1839                          * event about it later.
1840                          */
1841                         fctx->pending++;
1842                         /*
1843                          * Bootstrap.
1844                          */
1845                         if (need_alternate != NULL &&
1846                             !*need_alternate && unshared &&
1847                             ((res->dispatchv4 == NULL &&
1848                               find->result_v6 != DNS_R_NXDOMAIN) ||
1849                              (res->dispatchv6 == NULL &&
1850                               find->result_v4 != DNS_R_NXDOMAIN)))
1851                                 *need_alternate = ISC_TRUE;
1852                 } else {
1853                         /*
1854                          * If we know there are no addresses for
1855                          * the family we are using then try to add
1856                          * an alternative server.
1857                          */
1858                         if (need_alternate != NULL && !*need_alternate &&
1859                             ((res->dispatchv4 == NULL &&
1860                               find->result_v6 == DNS_R_NXRRSET) ||
1861                              (res->dispatchv6 == NULL &&
1862                               find->result_v4 == DNS_R_NXRRSET)))
1863                                 *need_alternate = ISC_TRUE;
1864                         /*
1865                          * And ADB isn't going to send us any events
1866                          * either.  This find loses.
1867                          */
1868                         if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) {
1869                                 /*
1870                                  * The ADB pruned lame servers for
1871                                  * this name.  Remember that in case
1872                                  * we get desperate later on.
1873                                  */
1874                                 *pruned = ISC_TRUE;
1875                         }
1876                         dns_adb_destroyfind(&find);
1877                 }
1878         }
1879 }
1880
1881 static isc_result_t
1882 fctx_getaddresses(fetchctx_t *fctx) {
1883         dns_rdata_t rdata = DNS_RDATA_INIT;
1884         isc_result_t result;
1885         dns_resolver_t *res;
1886         isc_stdtime_t now;
1887         unsigned int stdoptions;
1888         isc_sockaddr_t *sa;
1889         dns_adbaddrinfo_t *ai;
1890         isc_boolean_t pruned, all_bad;
1891         dns_rdata_ns_t ns;
1892         isc_boolean_t need_alternate = ISC_FALSE;
1893
1894         FCTXTRACE("getaddresses");
1895
1896         /*
1897          * Don't pound on remote servers.  (Failsafe!)
1898          */
1899         fctx->restarts++;
1900         if (fctx->restarts > 10) {
1901                 FCTXTRACE("too many restarts");
1902                 return (DNS_R_SERVFAIL);
1903         }
1904
1905         res = fctx->res;
1906         pruned = ISC_FALSE;
1907         stdoptions = 0;         /* Keep compiler happy. */
1908
1909         /*
1910          * Forwarders.
1911          */
1912
1913         INSIST(ISC_LIST_EMPTY(fctx->forwaddrs));
1914         INSIST(ISC_LIST_EMPTY(fctx->altaddrs));
1915
1916         /*
1917          * If this fctx has forwarders, use them; otherwise use any
1918          * selective forwarders specified in the view; otherwise use the
1919          * resolver's forwarders (if any).
1920          */
1921         sa = ISC_LIST_HEAD(fctx->forwarders);
1922         if (sa == NULL) {
1923                 dns_forwarders_t *forwarders = NULL;
1924                 dns_name_t *name = &fctx->name;
1925                 dns_name_t suffix;
1926                 unsigned int labels;
1927
1928                 /*
1929                  * DS records are found in the parent server.
1930                  * Strip label to get the correct forwarder (if any).
1931                  */
1932                 if (fctx->type == dns_rdatatype_ds &&
1933                     dns_name_countlabels(name) > 1) {
1934                         dns_name_init(&suffix, NULL);
1935                         labels = dns_name_countlabels(name);
1936                         dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
1937                         name = &suffix;
1938                 }
1939                 result = dns_fwdtable_find(fctx->res->view->fwdtable, name,
1940                                            &forwarders);
1941                 if (result == ISC_R_SUCCESS) {
1942                         sa = ISC_LIST_HEAD(forwarders->addrs);
1943                         fctx->fwdpolicy = forwarders->fwdpolicy;
1944                 }
1945         }
1946
1947         while (sa != NULL) {
1948                 ai = NULL;
1949                 result = dns_adb_findaddrinfo(fctx->adb,
1950                                               sa, &ai, 0);  /* XXXMLG */
1951                 if (result == ISC_R_SUCCESS) {
1952                         dns_adbaddrinfo_t *cur;
1953                         ai->flags |= FCTX_ADDRINFO_FORWARDER;
1954                         cur = ISC_LIST_HEAD(fctx->forwaddrs);
1955                         while (cur != NULL && cur->srtt < ai->srtt)
1956                                 cur = ISC_LIST_NEXT(cur, publink);
1957                         if (cur != NULL)
1958                                 ISC_LIST_INSERTBEFORE(fctx->forwaddrs, cur,
1959                                                       ai, publink);
1960                         else
1961                                 ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
1962                 }
1963                 sa = ISC_LIST_NEXT(sa, link);
1964         }
1965
1966         /*
1967          * If the forwarding policy is "only", we don't need the addresses
1968          * of the nameservers.
1969          */
1970         if (fctx->fwdpolicy == dns_fwdpolicy_only)
1971                 goto out;
1972
1973         /*
1974          * Normal nameservers.
1975          */
1976
1977         stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
1978         if (fctx->restarts == 1) {
1979                 /*
1980                  * To avoid sending out a flood of queries likely to
1981                  * result in NXRRSET, we suppress fetches for address
1982                  * families we don't have the first time through,
1983                  * provided that we have addresses in some family we
1984                  * can use.
1985                  *
1986                  * We don't want to set this option all the time, since
1987                  * if fctx->restarts > 1, we've clearly been having trouble
1988                  * with the addresses we had, so getting more could help.
1989                  */
1990                 stdoptions |= DNS_ADBFIND_AVOIDFETCHES;
1991         }
1992         if (res->dispatchv4 != NULL)
1993                 stdoptions |= DNS_ADBFIND_INET;
1994         if (res->dispatchv6 != NULL)
1995                 stdoptions |= DNS_ADBFIND_INET6;
1996         isc_stdtime_get(&now);
1997
1998  restart:
1999         INSIST(ISC_LIST_EMPTY(fctx->finds));
2000         INSIST(ISC_LIST_EMPTY(fctx->altfinds));
2001
2002         for (result = dns_rdataset_first(&fctx->nameservers);
2003              result == ISC_R_SUCCESS;
2004              result = dns_rdataset_next(&fctx->nameservers))
2005         {
2006                 dns_rdataset_current(&fctx->nameservers, &rdata);
2007                 /*
2008                  * Extract the name from the NS record.
2009                  */
2010                 result = dns_rdata_tostruct(&rdata, &ns, NULL);
2011                 if (result != ISC_R_SUCCESS)
2012                         continue;
2013
2014                 findname(fctx, &ns.name, 0, stdoptions, 0, now,
2015                          &pruned, &need_alternate);
2016                 dns_rdata_reset(&rdata);
2017                 dns_rdata_freestruct(&ns);
2018         }
2019         if (result != ISC_R_NOMORE)
2020                 return (result);
2021
2022         /*
2023          * Do we need to use 6 to 4?
2024          */
2025         if (need_alternate) {
2026                 int family;
2027                 alternate_t *a;
2028                 family = (res->dispatchv6 != NULL) ? AF_INET6 : AF_INET;
2029                 for (a = ISC_LIST_HEAD(fctx->res->alternates);
2030                      a != NULL;
2031                      a = ISC_LIST_NEXT(a, link)) {
2032                         if (!a->isaddress) {
2033                                 findname(fctx, &a->_u._n.name, a->_u._n.port,
2034                                          stdoptions, FCTX_ADDRINFO_FORWARDER,
2035                                          now, &pruned, NULL);
2036                                 continue;
2037                         }
2038                         if (isc_sockaddr_pf(&a->_u.addr) != family)
2039                                 continue;
2040                         ai = NULL;
2041                         result = dns_adb_findaddrinfo(fctx->adb, &a->_u.addr,
2042                                                       &ai, 0);
2043                         if (result == ISC_R_SUCCESS) {
2044                                 dns_adbaddrinfo_t *cur;
2045                                 ai->flags |= FCTX_ADDRINFO_FORWARDER;
2046                                 cur = ISC_LIST_HEAD(fctx->altaddrs);
2047                                 while (cur != NULL && cur->srtt < ai->srtt)
2048                                         cur = ISC_LIST_NEXT(cur, publink);
2049                                 if (cur != NULL)
2050                                         ISC_LIST_INSERTBEFORE(fctx->altaddrs,
2051                                                               cur, ai, publink);
2052                                 else
2053                                         ISC_LIST_APPEND(fctx->altaddrs, ai,
2054                                                         publink);
2055                         }
2056                 }
2057         }
2058
2059  out:
2060         /*
2061          * Mark all known bad servers.
2062          */
2063         all_bad = mark_bad(fctx);
2064
2065         /*
2066          * How are we doing?
2067          */
2068         if (all_bad) {
2069                 /*
2070                  * We've got no addresses.
2071                  */
2072                 if (fctx->pending > 0) {
2073                         /*
2074                          * We're fetching the addresses, but don't have any
2075                          * yet.   Tell the caller to wait for an answer.
2076                          */
2077                         result = DNS_R_WAIT;
2078                 } else if (pruned) {
2079                         /*
2080                          * Some addresses were removed by lame pruning.
2081                          * Turn pruning off and try again.
2082                          */
2083                         FCTXTRACE("restarting with returnlame");
2084                         INSIST((stdoptions & DNS_ADBFIND_RETURNLAME) == 0);
2085                         stdoptions |= DNS_ADBFIND_RETURNLAME;
2086                         pruned = ISC_FALSE;
2087                         fctx_cleanupaltfinds(fctx);
2088                         fctx_cleanupfinds(fctx);
2089                         goto restart;
2090                 } else {
2091                         /*
2092                          * We've lost completely.  We don't know any
2093                          * addresses, and the ADB has told us it can't get
2094                          * them.
2095                          */
2096                         FCTXTRACE("no addresses");
2097                         result = ISC_R_FAILURE;
2098                 }
2099         } else {
2100                 /*
2101                  * We've found some addresses.  We might still be looking
2102                  * for more addresses.
2103                  */
2104                 sort_finds(fctx);
2105                 result = ISC_R_SUCCESS;
2106         }
2107
2108         return (result);
2109 }
2110
2111 static inline void
2112 possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr)
2113 {
2114         isc_netaddr_t na;
2115         char buf[ISC_NETADDR_FORMATSIZE];
2116         isc_sockaddr_t *sa;
2117         isc_boolean_t aborted = ISC_FALSE;
2118         isc_boolean_t bogus;
2119         dns_acl_t *blackhole;
2120         isc_netaddr_t ipaddr;
2121         dns_peer_t *peer = NULL;
2122         dns_resolver_t *res;
2123         const char *msg = NULL;
2124
2125         sa = &addr->sockaddr;
2126
2127         res = fctx->res;
2128         isc_netaddr_fromsockaddr(&ipaddr, sa);
2129         blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr);
2130         (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer);
2131         
2132         if (blackhole != NULL) {
2133                 int match;
2134
2135                 if (dns_acl_match(&ipaddr, NULL, blackhole,
2136                                   &res->view->aclenv,
2137                                   &match, NULL) == ISC_R_SUCCESS &&
2138                     match > 0)
2139                         aborted = ISC_TRUE;
2140         }
2141
2142         if (peer != NULL &&
2143             dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS &&
2144             bogus)
2145                 aborted = ISC_TRUE;
2146
2147         if (aborted) {
2148                 addr->flags |= FCTX_ADDRINFO_MARK;
2149                 msg = "ignoring blackholed / bogus server: ";
2150         } else if (isc_sockaddr_ismulticast(sa)) {
2151                 addr->flags |= FCTX_ADDRINFO_MARK;
2152                 msg = "ignoring multicast address: ";
2153         } else if (isc_sockaddr_isexperimental(sa)) {
2154                 addr->flags |= FCTX_ADDRINFO_MARK;
2155                 msg = "ignoring experimental address: ";
2156         } else if (sa->type.sa.sa_family != AF_INET6) {
2157                 return;
2158         } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) {
2159                 addr->flags |= FCTX_ADDRINFO_MARK;
2160                 msg = "ignoring IPv6 mapped IPV4 address: ";
2161         } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) {
2162                 addr->flags |= FCTX_ADDRINFO_MARK;
2163                 msg = "ignoring IPv6 compatibility IPV4 address: ";
2164         } else
2165                 return;
2166
2167         if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3)))
2168                 return;
2169
2170         isc_netaddr_fromsockaddr(&na, sa);
2171         isc_netaddr_format(&na, buf, sizeof(buf));
2172         FCTXTRACE2(msg, buf);
2173 }
2174
2175 static inline dns_adbaddrinfo_t *
2176 fctx_nextaddress(fetchctx_t *fctx) {
2177         dns_adbfind_t *find, *start;
2178         dns_adbaddrinfo_t *addrinfo;
2179         dns_adbaddrinfo_t *faddrinfo;
2180
2181         /*
2182          * Return the next untried address, if any.
2183          */
2184
2185         /*
2186          * Find the first unmarked forwarder (if any).
2187          */
2188         for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
2189              addrinfo != NULL;
2190              addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2191                 if (!UNMARKED(addrinfo))
2192                         continue;
2193                 possibly_mark(fctx, addrinfo);
2194                 if (UNMARKED(addrinfo)) {
2195                         addrinfo->flags |= FCTX_ADDRINFO_MARK;
2196                         fctx->find = NULL;
2197                         return (addrinfo);
2198                 }
2199         }
2200
2201         /*
2202          * No forwarders.  Move to the next find.
2203          */
2204
2205         fctx->attributes |= FCTX_ATTR_TRIEDFIND;
2206
2207         find = fctx->find;
2208         if (find == NULL)
2209                 find = ISC_LIST_HEAD(fctx->finds);
2210         else {
2211                 find = ISC_LIST_NEXT(find, publink);
2212                 if (find == NULL)
2213                         find = ISC_LIST_HEAD(fctx->finds);
2214         }
2215
2216         /*
2217          * Find the first unmarked addrinfo.
2218          */
2219         addrinfo = NULL;
2220         if (find != NULL) {
2221                 start = find;
2222                 do {
2223                         for (addrinfo = ISC_LIST_HEAD(find->list);
2224                              addrinfo != NULL;
2225                              addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2226                                 if (!UNMARKED(addrinfo))
2227                                         continue;
2228                                 possibly_mark(fctx, addrinfo);
2229                                 if (UNMARKED(addrinfo)) {
2230                                         addrinfo->flags |= FCTX_ADDRINFO_MARK;
2231                                         break;
2232                                 }
2233                         }
2234                         if (addrinfo != NULL)
2235                                 break;
2236                         find = ISC_LIST_NEXT(find, publink);
2237                         if (find == NULL)
2238                                 find = ISC_LIST_HEAD(fctx->finds);
2239                 } while (find != start);
2240         }
2241
2242         fctx->find = find;
2243         if (addrinfo != NULL)
2244                 return (addrinfo);
2245
2246         /*
2247          * No nameservers left.  Try alternates.
2248          */
2249
2250         fctx->attributes |= FCTX_ATTR_TRIEDALT;
2251
2252         find = fctx->altfind;
2253         if (find == NULL)
2254                 find = ISC_LIST_HEAD(fctx->altfinds);
2255         else {
2256                 find = ISC_LIST_NEXT(find, publink);
2257                 if (find == NULL)
2258                         find = ISC_LIST_HEAD(fctx->altfinds);
2259         }
2260
2261         /*
2262          * Find the first unmarked addrinfo.
2263          */
2264         addrinfo = NULL;
2265         if (find != NULL) {
2266                 start = find;
2267                 do {
2268                         for (addrinfo = ISC_LIST_HEAD(find->list);
2269                              addrinfo != NULL;
2270                              addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2271                                 if (!UNMARKED(addrinfo))
2272                                         continue;
2273                                 possibly_mark(fctx, addrinfo);
2274                                 if (UNMARKED(addrinfo)) {
2275                                         addrinfo->flags |= FCTX_ADDRINFO_MARK;
2276                                         break;
2277                                 }
2278                         }
2279                         if (addrinfo != NULL)
2280                                 break;
2281                         find = ISC_LIST_NEXT(find, publink);
2282                         if (find == NULL)
2283                                 find = ISC_LIST_HEAD(fctx->altfinds);
2284                 } while (find != start);
2285         }
2286
2287         faddrinfo = addrinfo;
2288
2289         /*
2290          * See if we have a better alternate server by address.
2291          */
2292
2293         for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
2294              addrinfo != NULL;
2295              addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
2296                 if (!UNMARKED(addrinfo))
2297                         continue;
2298                 possibly_mark(fctx, addrinfo);
2299                 if (UNMARKED(addrinfo) &&
2300                     (faddrinfo == NULL ||
2301                      addrinfo->srtt < faddrinfo->srtt)) {
2302                         if (faddrinfo != NULL)
2303                                 faddrinfo->flags &= ~FCTX_ADDRINFO_MARK;
2304                         addrinfo->flags |= FCTX_ADDRINFO_MARK;
2305                         break;
2306                 }
2307         }
2308
2309         if (addrinfo == NULL) {
2310                 addrinfo = faddrinfo;
2311                 fctx->altfind = find;
2312         }
2313
2314         return (addrinfo);
2315 }
2316
2317 static void
2318 fctx_try(fetchctx_t *fctx) {
2319         isc_result_t result;
2320         dns_adbaddrinfo_t *addrinfo;
2321
2322         FCTXTRACE("try");
2323
2324         REQUIRE(!ADDRWAIT(fctx));
2325
2326         addrinfo = fctx_nextaddress(fctx);
2327         if (addrinfo == NULL) {
2328                 /*
2329                  * We have no more addresses.  Start over.
2330                  */
2331                 fctx_cancelqueries(fctx, ISC_TRUE);
2332                 fctx_cleanupfinds(fctx);
2333                 fctx_cleanupaltfinds(fctx);
2334                 fctx_cleanupforwaddrs(fctx);
2335                 fctx_cleanupaltaddrs(fctx);
2336                 result = fctx_getaddresses(fctx);
2337                 if (result == DNS_R_WAIT) {
2338                         /*
2339                          * Sleep waiting for addresses.
2340                          */
2341                         FCTXTRACE("addrwait");
2342                         fctx->attributes |= FCTX_ATTR_ADDRWAIT;
2343                         return;
2344                 } else if (result != ISC_R_SUCCESS) {
2345                         /*
2346                          * Something bad happened.
2347                          */
2348                         fctx_done(fctx, result);
2349                         return;
2350                 }
2351
2352                 addrinfo = fctx_nextaddress(fctx);
2353                 /*
2354                  * While we may have addresses from the ADB, they
2355                  * might be bad ones.  In this case, return SERVFAIL.
2356                  */
2357                 if (addrinfo == NULL) {
2358                         fctx_done(fctx, DNS_R_SERVFAIL);
2359                         return;
2360                 }
2361         }
2362
2363         result = fctx_query(fctx, addrinfo, fctx->options);
2364         if (result != ISC_R_SUCCESS)
2365                 fctx_done(fctx, result);
2366 }
2367
2368 static isc_boolean_t
2369 fctx_destroy(fetchctx_t *fctx) {
2370         dns_resolver_t *res;
2371         unsigned int bucketnum;
2372         isc_sockaddr_t *sa, *next_sa;
2373
2374         /*
2375          * Caller must be holding the bucket lock.
2376          */
2377
2378         REQUIRE(VALID_FCTX(fctx));
2379         REQUIRE(fctx->state == fetchstate_done ||
2380                 fctx->state == fetchstate_init);
2381         REQUIRE(ISC_LIST_EMPTY(fctx->events));
2382         REQUIRE(ISC_LIST_EMPTY(fctx->queries));
2383         REQUIRE(ISC_LIST_EMPTY(fctx->finds));
2384         REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
2385         REQUIRE(fctx->pending == 0);
2386         REQUIRE(ISC_LIST_EMPTY(fctx->validators));
2387         REQUIRE(fctx->references == 0);
2388
2389         FCTXTRACE("destroy");
2390
2391         res = fctx->res;
2392         bucketnum = fctx->bucketnum;
2393
2394         ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
2395
2396         /*
2397          * Free bad.
2398          */
2399         for (sa = ISC_LIST_HEAD(fctx->bad);
2400              sa != NULL;
2401              sa = next_sa) {
2402                 next_sa = ISC_LIST_NEXT(sa, link);
2403                 ISC_LIST_UNLINK(fctx->bad, sa, link);
2404                 isc_mem_put(res->mctx, sa, sizeof(*sa));
2405         }
2406
2407         isc_timer_detach(&fctx->timer);
2408         dns_message_destroy(&fctx->rmessage);
2409         dns_message_destroy(&fctx->qmessage);
2410         if (dns_name_countlabels(&fctx->domain) > 0)
2411                 dns_name_free(&fctx->domain, res->mctx);
2412         if (dns_rdataset_isassociated(&fctx->nameservers))
2413                 dns_rdataset_disassociate(&fctx->nameservers);
2414         dns_name_free(&fctx->name, res->mctx);
2415         dns_db_detach(&fctx->cache);
2416         dns_adb_detach(&fctx->adb);
2417         isc_mem_free(res->mctx, fctx->info);
2418         isc_mem_put(res->mctx, fctx, sizeof(*fctx));
2419
2420         LOCK(&res->nlock);
2421         res->nfctx--;
2422         UNLOCK(&res->nlock);
2423
2424         if (res->buckets[bucketnum].exiting &&
2425             ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
2426                 return (ISC_TRUE);
2427
2428         return (ISC_FALSE);
2429 }
2430
2431 /*
2432  * Fetch event handlers.
2433  */
2434
2435 static void
2436 fctx_timeout(isc_task_t *task, isc_event_t *event) {
2437         fetchctx_t *fctx = event->ev_arg;
2438
2439         REQUIRE(VALID_FCTX(fctx));
2440
2441         UNUSED(task);
2442
2443         FCTXTRACE("timeout");
2444
2445         if (event->ev_type == ISC_TIMEREVENT_LIFE) {
2446                 fctx_done(fctx, ISC_R_TIMEDOUT);
2447         } else {
2448                 isc_result_t result;
2449
2450                 fctx->timeouts++;
2451                 /*
2452                  * We could cancel the running queries here, or we could let
2453                  * them keep going.  Right now we choose the latter...
2454                  */
2455                 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
2456                 /*
2457                  * Our timer has triggered.  Reestablish the fctx lifetime
2458                  * timer.
2459                  */
2460                 result = fctx_starttimer(fctx);
2461                 if (result != ISC_R_SUCCESS)
2462                         fctx_done(fctx, result);
2463                 else
2464                         /*
2465                          * Keep trying.
2466                          */
2467                         fctx_try(fctx);
2468         }
2469
2470         isc_event_free(&event);
2471 }
2472
2473 static void
2474 fctx_shutdown(fetchctx_t *fctx) {
2475         isc_event_t *cevent;
2476
2477         /*
2478          * Start the shutdown process for fctx, if it isn't already underway.
2479          */
2480
2481         FCTXTRACE("shutdown");
2482
2483         /*
2484          * The caller must be holding the appropriate bucket lock.
2485          */
2486
2487         if (fctx->want_shutdown)
2488                 return;
2489
2490         fctx->want_shutdown = ISC_TRUE;
2491
2492         /*
2493          * Unless we're still initializing (in which case the
2494          * control event is still outstanding), we need to post
2495          * the control event to tell the fetch we want it to
2496          * exit.
2497          */
2498         if (fctx->state != fetchstate_init) {
2499                 cevent = &fctx->control_event;
2500                 isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
2501                               &cevent);
2502         }
2503 }
2504
2505 static void
2506 fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
2507         fetchctx_t *fctx = event->ev_arg;
2508         isc_boolean_t bucket_empty = ISC_FALSE;
2509         dns_resolver_t *res;
2510         unsigned int bucketnum;
2511         dns_validator_t *validator;
2512
2513         REQUIRE(VALID_FCTX(fctx));
2514
2515         UNUSED(task);
2516
2517         res = fctx->res;
2518         bucketnum = fctx->bucketnum;
2519
2520         FCTXTRACE("doshutdown");
2521
2522         /*
2523          * An fctx that is shutting down is no longer in ADDRWAIT mode.
2524          */
2525         fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
2526
2527         /*
2528          * Cancel all pending validators.  Note that this must be done
2529          * without the bucket lock held, since that could cause deadlock.
2530          */
2531         validator = ISC_LIST_HEAD(fctx->validators);
2532         while (validator != NULL) {
2533                 dns_validator_cancel(validator);
2534                 validator = ISC_LIST_NEXT(validator, link);
2535         }
2536         
2537         if (fctx->nsfetch != NULL)
2538                 dns_resolver_cancelfetch(fctx->nsfetch);
2539
2540         /*
2541          * Shut down anything that is still running on behalf of this
2542          * fetch.  To avoid deadlock with the ADB, we must do this
2543          * before we lock the bucket lock.
2544          */
2545         fctx_stopeverything(fctx, ISC_FALSE);
2546
2547         LOCK(&res->buckets[bucketnum].lock);
2548
2549         fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
2550
2551         INSIST(fctx->state == fetchstate_active ||
2552                fctx->state == fetchstate_done);
2553         INSIST(fctx->want_shutdown);
2554
2555         if (fctx->state != fetchstate_done) {
2556                 fctx->state = fetchstate_done;
2557                 fctx_sendevents(fctx, ISC_R_CANCELED);
2558         }
2559
2560         if (fctx->references == 0 && fctx->pending == 0 &&
2561             ISC_LIST_EMPTY(fctx->validators))
2562                 bucket_empty = fctx_destroy(fctx);
2563
2564         UNLOCK(&res->buckets[bucketnum].lock);
2565
2566         if (bucket_empty)
2567                 empty_bucket(res);
2568 }
2569
2570 static void
2571 fctx_start(isc_task_t *task, isc_event_t *event) {
2572         fetchctx_t *fctx = event->ev_arg;
2573         isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE;
2574         dns_resolver_t *res;
2575         unsigned int bucketnum;
2576
2577         REQUIRE(VALID_FCTX(fctx));
2578
2579         UNUSED(task);
2580
2581         res = fctx->res;
2582         bucketnum = fctx->bucketnum;
2583
2584         FCTXTRACE("start");
2585
2586         LOCK(&res->buckets[bucketnum].lock);
2587
2588         INSIST(fctx->state == fetchstate_init);
2589         if (fctx->want_shutdown) {
2590                 /*
2591                  * We haven't started this fctx yet, and we've been requested
2592                  * to shut it down.
2593                  */
2594                 fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
2595                 fctx->state = fetchstate_done;
2596                 fctx_sendevents(fctx, ISC_R_CANCELED);
2597                 /*
2598                  * Since we haven't started, we INSIST that we have no
2599                  * pending ADB finds and no pending validations.
2600                  */
2601                 INSIST(fctx->pending == 0);
2602                 INSIST(ISC_LIST_EMPTY(fctx->validators));
2603                 if (fctx->references == 0) {
2604                         /*
2605                          * It's now safe to destroy this fctx.
2606                          */
2607                         bucket_empty = fctx_destroy(fctx);
2608                 }
2609                 done = ISC_TRUE;
2610         } else {
2611                 /*
2612                  * Normal fctx startup.
2613                  */
2614                 fctx->state = fetchstate_active;
2615                 /*
2616                  * Reset the control event for later use in shutting down
2617                  * the fctx.
2618                  */
2619                 ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
2620                                DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx,
2621                                NULL, NULL, NULL);
2622         }
2623
2624         UNLOCK(&res->buckets[bucketnum].lock);
2625
2626         if (!done) {
2627                 isc_result_t result;
2628
2629                 /*
2630                  * All is well.  Start working on the fetch.
2631                  */
2632                 result = fctx_starttimer(fctx);
2633                 if (result != ISC_R_SUCCESS)
2634                         fctx_done(fctx, result);
2635                 else
2636                         fctx_try(fctx);
2637         } else if (bucket_empty)
2638                 empty_bucket(res);
2639 }
2640
2641 /*
2642  * Fetch Creation, Joining, and Cancelation.
2643  */
2644
2645 static inline isc_result_t
2646 fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_taskaction_t action,
2647           void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
2648           dns_fetch_t *fetch)
2649 {
2650         isc_task_t *clone;
2651         dns_fetchevent_t *event;
2652
2653         FCTXTRACE("join");
2654
2655         /*
2656          * We store the task we're going to send this event to in the
2657          * sender field.  We'll make the fetch the sender when we actually
2658          * send the event.
2659          */
2660         clone = NULL;
2661         isc_task_attach(task, &clone);
2662         event = (dns_fetchevent_t *)
2663                 isc_event_allocate(fctx->res->mctx, clone,
2664                                    DNS_EVENT_FETCHDONE,
2665                                    action, arg, sizeof(*event));
2666         if (event == NULL) {
2667                 isc_task_detach(&clone);
2668                 return (ISC_R_NOMEMORY);
2669         }
2670         event->result = DNS_R_SERVFAIL;
2671         event->qtype = fctx->type;
2672         event->db = NULL;
2673         event->node = NULL;
2674         event->rdataset = rdataset;
2675         event->sigrdataset = sigrdataset;
2676         event->fetch = fetch;
2677         dns_fixedname_init(&event->foundname);
2678
2679         /*
2680          * Make sure that we can store the sigrdataset in the
2681          * first event if it is needed by any of the events.
2682          */
2683         if (event->sigrdataset != NULL)
2684                 ISC_LIST_PREPEND(fctx->events, event, ev_link);
2685         else
2686                 ISC_LIST_APPEND(fctx->events, event, ev_link);
2687         fctx->references++;
2688
2689         fetch->magic = DNS_FETCH_MAGIC;
2690         fetch->private = fctx;
2691
2692         return (ISC_R_SUCCESS);
2693 }
2694
2695 static isc_result_t
2696 fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
2697             dns_name_t *domain, dns_rdataset_t *nameservers,
2698             unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
2699 {
2700         fetchctx_t *fctx;
2701         isc_result_t result;
2702         isc_result_t iresult;
2703         isc_interval_t interval;
2704         dns_fixedname_t fixed;
2705         unsigned int findoptions = 0;
2706         char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
2707         char typebuf[DNS_RDATATYPE_FORMATSIZE];
2708         dns_name_t suffix;
2709
2710         /*
2711          * Caller must be holding the lock for bucket number 'bucketnum'.
2712          */
2713         REQUIRE(fctxp != NULL && *fctxp == NULL);
2714
2715         fctx = isc_mem_get(res->mctx, sizeof(*fctx));
2716         if (fctx == NULL)
2717                 return (ISC_R_NOMEMORY);
2718         dns_name_format(name, buf, sizeof(buf));
2719         dns_rdatatype_format(type, typebuf, sizeof(typebuf));
2720         strcat(buf, "/");       /* checked */
2721         strcat(buf, typebuf);   /* checked */
2722         fctx->info = isc_mem_strdup(res->mctx, buf);
2723         if (fctx->info == NULL) {
2724                 result = ISC_R_NOMEMORY;
2725                 goto cleanup_fetch;
2726         }
2727         FCTXTRACE("create");
2728         dns_name_init(&fctx->name, NULL);
2729         result = dns_name_dup(name, res->mctx, &fctx->name);
2730         if (result != ISC_R_SUCCESS)
2731                 goto cleanup_info;
2732         dns_name_init(&fctx->domain, NULL);
2733         dns_rdataset_init(&fctx->nameservers);
2734
2735         fctx->type = type;
2736         fctx->options = options;
2737         /*
2738          * Note!  We do not attach to the task.  We are relying on the
2739          * resolver to ensure that this task doesn't go away while we are
2740          * using it.
2741          */
2742         fctx->res = res;
2743         fctx->references = 0;
2744         fctx->bucketnum = bucketnum;
2745         fctx->state = fetchstate_init;
2746         fctx->want_shutdown = ISC_FALSE;
2747         fctx->cloned = ISC_FALSE;
2748         ISC_LIST_INIT(fctx->queries);
2749         ISC_LIST_INIT(fctx->finds);
2750         ISC_LIST_INIT(fctx->altfinds);
2751         ISC_LIST_INIT(fctx->forwaddrs);
2752         ISC_LIST_INIT(fctx->altaddrs);
2753         ISC_LIST_INIT(fctx->forwarders);
2754         fctx->fwdpolicy = dns_fwdpolicy_none;
2755         ISC_LIST_INIT(fctx->bad);
2756         ISC_LIST_INIT(fctx->validators);
2757         fctx->find = NULL;
2758         fctx->altfind = NULL;
2759         fctx->pending = 0;
2760         fctx->restarts = 0;
2761         fctx->timeouts = 0;
2762         fctx->attributes = 0;
2763
2764         dns_name_init(&fctx->nsname, NULL);
2765         fctx->nsfetch = NULL;
2766         dns_rdataset_init(&fctx->nsrrset);
2767
2768         if (domain == NULL) {
2769                 dns_forwarders_t *forwarders = NULL;
2770                 unsigned int labels;
2771
2772                 /*
2773                  * DS records are found in the parent server.
2774                  * Strip label to get the correct forwarder (if any).
2775                  */
2776                 if (fctx->type == dns_rdatatype_ds &&
2777                     dns_name_countlabels(name) > 1) {
2778                         dns_name_init(&suffix, NULL);
2779                         labels = dns_name_countlabels(name);
2780                         dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
2781                         name = &suffix;
2782                 }
2783                 dns_fixedname_init(&fixed);
2784                 domain = dns_fixedname_name(&fixed);
2785                 result = dns_fwdtable_find2(fctx->res->view->fwdtable, name,
2786                                             domain, &forwarders);
2787                 if (result == ISC_R_SUCCESS)
2788                         fctx->fwdpolicy = forwarders->fwdpolicy;
2789
2790                 if (fctx->fwdpolicy != dns_fwdpolicy_only) {
2791                         /*
2792                          * The caller didn't supply a query domain and
2793                          * nameservers, and we're not in forward-only mode,
2794                          * so find the best nameservers to use.
2795                          */
2796                         if (dns_rdatatype_atparent(type))
2797                                 findoptions |= DNS_DBFIND_NOEXACT;
2798                         result = dns_view_findzonecut(res->view, name, domain,
2799                                                       0, findoptions, ISC_TRUE,
2800                                                       &fctx->nameservers,
2801                                                       NULL);
2802                         if (result != ISC_R_SUCCESS)
2803                                 goto cleanup_name;
2804                         result = dns_name_dup(domain, res->mctx, &fctx->domain);
2805                         if (result != ISC_R_SUCCESS) {
2806                                 dns_rdataset_disassociate(&fctx->nameservers);
2807                                 goto cleanup_name;
2808                         }
2809                 } else {
2810                         /*
2811                          * We're in forward-only mode.  Set the query domain.
2812                          */
2813                         result = dns_name_dup(domain, res->mctx, &fctx->domain);
2814                         if (result != ISC_R_SUCCESS)
2815                                 goto cleanup_name;
2816                 }
2817         } else {
2818                 result = dns_name_dup(domain, res->mctx, &fctx->domain);
2819                 if (result != ISC_R_SUCCESS)
2820                         goto cleanup_name;
2821                 dns_rdataset_clone(nameservers, &fctx->nameservers);
2822         }
2823
2824         INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
2825
2826         fctx->qmessage = NULL;
2827         result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTRENDER,
2828                                     &fctx->qmessage);
2829
2830         if (result != ISC_R_SUCCESS)
2831                 goto cleanup_domain;
2832
2833         fctx->rmessage = NULL;
2834         result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTPARSE,
2835                                     &fctx->rmessage);
2836
2837         if (result != ISC_R_SUCCESS)
2838                 goto cleanup_qmessage;
2839
2840         /*
2841          * Compute an expiration time for the entire fetch.
2842          */
2843         isc_interval_set(&interval, 30, 0);             /* XXXRTH constant */
2844         iresult = isc_time_nowplusinterval(&fctx->expires, &interval);
2845         if (iresult != ISC_R_SUCCESS) {
2846                 UNEXPECTED_ERROR(__FILE__, __LINE__,
2847                                  "isc_time_nowplusinterval: %s",
2848                                  isc_result_totext(iresult));
2849                 result = ISC_R_UNEXPECTED;
2850                 goto cleanup_rmessage;
2851         }
2852
2853         /*
2854          * Default retry interval initialization.  We set the interval now
2855          * mostly so it won't be uninitialized.  It will be set to the
2856          * correct value before a query is issued.
2857          */
2858         isc_interval_set(&fctx->interval, 2, 0);
2859
2860         /*
2861          * Create an inactive timer.  It will be made active when the fetch
2862          * is actually started.
2863          */
2864         fctx->timer = NULL;
2865         iresult = isc_timer_create(res->timermgr, isc_timertype_inactive,
2866                                    NULL, NULL,
2867                                    res->buckets[bucketnum].task, fctx_timeout,
2868                                    fctx, &fctx->timer);
2869         if (iresult != ISC_R_SUCCESS) {
2870                 UNEXPECTED_ERROR(__FILE__, __LINE__,
2871                                  "isc_timer_create: %s",
2872                                  isc_result_totext(iresult));
2873                 result = ISC_R_UNEXPECTED;
2874                 goto cleanup_rmessage;
2875         }
2876
2877         /*
2878          * Attach to the view's cache and adb.
2879          */
2880         fctx->cache = NULL;
2881         dns_db_attach(res->view->cachedb, &fctx->cache);
2882         fctx->adb = NULL;
2883         dns_adb_attach(res->view->adb, &fctx->adb);
2884
2885         ISC_LIST_INIT(fctx->events);
2886         ISC_LINK_INIT(fctx, link);
2887         fctx->magic = FCTX_MAGIC;
2888
2889         ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
2890
2891         LOCK(&res->nlock);
2892         res->nfctx++;
2893         UNLOCK(&res->nlock);
2894
2895         *fctxp = fctx;
2896
2897         return (ISC_R_SUCCESS);
2898
2899  cleanup_rmessage:
2900         dns_message_destroy(&fctx->rmessage);
2901
2902  cleanup_qmessage:
2903         dns_message_destroy(&fctx->qmessage);
2904
2905  cleanup_domain:
2906         if (dns_name_countlabels(&fctx->domain) > 0)
2907                 dns_name_free(&fctx->domain, res->mctx);
2908         if (dns_rdataset_isassociated(&fctx->nameservers))
2909                 dns_rdataset_disassociate(&fctx->nameservers);
2910
2911  cleanup_name:
2912         dns_name_free(&fctx->name, res->mctx);
2913
2914  cleanup_info:
2915         isc_mem_free(res->mctx, fctx->info);
2916
2917  cleanup_fetch:
2918         isc_mem_put(res->mctx, fctx, sizeof(*fctx));
2919
2920         return (result);
2921 }
2922
2923 /*
2924  * Handle Responses
2925  */
2926 static inline isc_boolean_t
2927 is_lame(fetchctx_t *fctx) {
2928         dns_message_t *message = fctx->rmessage;
2929         dns_name_t *name;
2930         dns_rdataset_t *rdataset;
2931         isc_result_t result;
2932
2933         if (message->rcode != dns_rcode_noerror &&
2934             message->rcode != dns_rcode_nxdomain)
2935                 return (ISC_FALSE);
2936
2937         if (message->counts[DNS_SECTION_ANSWER] != 0)
2938                 return (ISC_FALSE);
2939
2940         if (message->counts[DNS_SECTION_AUTHORITY] == 0)
2941                 return (ISC_FALSE);
2942
2943         result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
2944         while (result == ISC_R_SUCCESS) {
2945                 name = NULL;
2946                 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
2947                 for (rdataset = ISC_LIST_HEAD(name->list);
2948                      rdataset != NULL;
2949                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
2950                         dns_namereln_t namereln;
2951                         int order;
2952                         unsigned int labels;
2953                         if (rdataset->type != dns_rdatatype_ns)
2954                                 continue;
2955                         namereln = dns_name_fullcompare(name, &fctx->domain,
2956                                                         &order, &labels);
2957                         if (namereln == dns_namereln_equal &&
2958                             (message->flags & DNS_MESSAGEFLAG_AA) != 0)
2959                                 return (ISC_FALSE);
2960                         if (namereln == dns_namereln_subdomain)
2961                                 return (ISC_FALSE);
2962                         return (ISC_TRUE);
2963                 }
2964                 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
2965         }
2966
2967         return (ISC_FALSE);
2968 }
2969
2970 static inline void
2971 log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) {
2972         char namebuf[DNS_NAME_FORMATSIZE];
2973         char domainbuf[DNS_NAME_FORMATSIZE];    
2974         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2975         
2976         dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
2977         dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
2978         isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf));
2979         isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
2980                       DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
2981                       "lame server resolving '%s' (in '%s'?): %s",
2982                       namebuf, domainbuf, addrbuf);
2983 }
2984
2985 static inline isc_result_t
2986 same_question(fetchctx_t *fctx) {
2987         isc_result_t result;
2988         dns_message_t *message = fctx->rmessage;
2989         dns_name_t *name;
2990         dns_rdataset_t *rdataset;
2991
2992         /*
2993          * Caller must be holding the fctx lock.
2994          */
2995
2996         /*
2997          * XXXRTH  Currently we support only one question.
2998          */
2999         if (message->counts[DNS_SECTION_QUESTION] != 1)
3000                 return (DNS_R_FORMERR);
3001
3002         result = dns_message_firstname(message, DNS_SECTION_QUESTION);
3003         if (result != ISC_R_SUCCESS)
3004                 return (result);
3005         name = NULL;
3006         dns_message_currentname(message, DNS_SECTION_QUESTION, &name);
3007         rdataset = ISC_LIST_HEAD(name->list);
3008         INSIST(rdataset != NULL);
3009         INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
3010         if (fctx->type != rdataset->type ||
3011             fctx->res->rdclass != rdataset->rdclass ||
3012             !dns_name_equal(&fctx->name, name))
3013                 return (DNS_R_FORMERR);
3014
3015         return (ISC_R_SUCCESS);
3016 }
3017
3018 static void
3019 clone_results(fetchctx_t *fctx) {
3020         dns_fetchevent_t *event, *hevent;
3021         isc_result_t result;
3022         dns_name_t *name, *hname;
3023
3024         FCTXTRACE("clone_results");
3025
3026         /*
3027          * Set up any other events to have the same data as the first
3028          * event.
3029          *
3030          * Caller must be holding the appropriate lock.
3031          */
3032
3033         fctx->cloned = ISC_TRUE;
3034         hevent = ISC_LIST_HEAD(fctx->events);
3035         if (hevent == NULL)
3036                 return;
3037         hname = dns_fixedname_name(&hevent->foundname);
3038         for (event = ISC_LIST_NEXT(hevent, ev_link);
3039              event != NULL;
3040              event = ISC_LIST_NEXT(event, ev_link)) {
3041                 name = dns_fixedname_name(&event->foundname);
3042                 result = dns_name_copy(hname, name, NULL);
3043                 if (result != ISC_R_SUCCESS)
3044                         event->result = result;
3045                 else
3046                         event->result = hevent->result;
3047                 dns_db_attach(hevent->db, &event->db);
3048                 dns_db_attachnode(hevent->db, hevent->node, &event->node);
3049                 INSIST(hevent->rdataset != NULL);
3050                 INSIST(event->rdataset != NULL);
3051                 if (dns_rdataset_isassociated(hevent->rdataset))
3052                         dns_rdataset_clone(hevent->rdataset, event->rdataset);
3053                 INSIST(! (hevent->sigrdataset == NULL &&
3054                           event->sigrdataset != NULL));
3055                 if (hevent->sigrdataset != NULL &&
3056                     dns_rdataset_isassociated(hevent->sigrdataset) &&
3057                     event->sigrdataset != NULL)
3058                         dns_rdataset_clone(hevent->sigrdataset,
3059                                            event->sigrdataset);
3060         }
3061 }
3062
3063 #define CACHE(r)        (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0)
3064 #define ANSWER(r)       (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0)
3065 #define ANSWERSIG(r)    (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0)
3066 #define EXTERNAL(r)     (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0)
3067 #define CHAINING(r)     (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0)
3068 #define CHASE(r)        (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0)
3069 #define CHECKNAMES(r)   (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0)
3070
3071
3072 /*
3073  * Destroy '*fctx' if it is ready to be destroyed (i.e., if it has
3074  * no references and is no longer waiting for any events).  If this
3075  * was the last fctx in the resolver, destroy the resolver.
3076  *
3077  * Requires:
3078  *      '*fctx' is shutting down.
3079  */
3080 static void
3081 maybe_destroy(fetchctx_t *fctx) {
3082         unsigned int bucketnum;
3083         isc_boolean_t bucket_empty = ISC_FALSE;
3084         dns_resolver_t *res = fctx->res;
3085
3086         REQUIRE(SHUTTINGDOWN(fctx));
3087
3088         if (fctx->pending != 0 || !ISC_LIST_EMPTY(fctx->validators))
3089                 return;
3090
3091         bucketnum = fctx->bucketnum;
3092         LOCK(&res->buckets[bucketnum].lock);
3093         if (fctx->references == 0)
3094                 bucket_empty = fctx_destroy(fctx);
3095         UNLOCK(&res->buckets[bucketnum].lock);
3096
3097         if (bucket_empty)
3098                 empty_bucket(res);
3099 }
3100
3101 /*
3102  * The validator has finished.
3103  */
3104 static void
3105 validated(isc_task_t *task, isc_event_t *event) {
3106         isc_result_t result = ISC_R_SUCCESS;
3107         isc_result_t eresult = ISC_R_SUCCESS;
3108         isc_stdtime_t now;
3109         fetchctx_t *fctx;
3110         dns_validatorevent_t *vevent;
3111         dns_fetchevent_t *hevent;
3112         dns_rdataset_t *ardataset = NULL;
3113         dns_rdataset_t *asigrdataset = NULL;
3114         dns_dbnode_t *node = NULL;
3115         isc_boolean_t negative;
3116         isc_boolean_t chaining;
3117         isc_boolean_t sentresponse;
3118         isc_uint32_t ttl;
3119         dns_dbnode_t *nsnode = NULL;
3120         dns_name_t *name;
3121         dns_rdataset_t *rdataset;
3122         dns_rdataset_t *sigrdataset;
3123         dns_valarg_t *valarg;
3124         dns_adbaddrinfo_t *addrinfo;
3125
3126         UNUSED(task); /* for now */
3127
3128         REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE);
3129         valarg = event->ev_arg;
3130         fctx = valarg->fctx;
3131         addrinfo = valarg->addrinfo;
3132         REQUIRE(VALID_FCTX(fctx));
3133         REQUIRE(!ISC_LIST_EMPTY(fctx->validators));
3134
3135         vevent = (dns_validatorevent_t *)event;
3136
3137         FCTXTRACE("received validation completion event");
3138
3139         ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
3140
3141         /*
3142          * Destroy the validator early so that we can
3143          * destroy the fctx if necessary.
3144          */
3145         dns_validator_destroy(&vevent->validator);
3146         isc_mem_put(fctx->res->mctx, valarg, sizeof(*valarg));
3147
3148         negative = ISC_TF(vevent->rdataset == NULL);
3149
3150         sentresponse = ISC_TF((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0);
3151
3152         /*
3153          * If shutting down, ignore the results.  Check to see if we're
3154          * done waiting for validator completions and ADB pending events; if
3155          * so, destroy the fctx.
3156          */
3157         if (SHUTTINGDOWN(fctx) && !sentresponse) {
3158                 maybe_destroy(fctx);
3159                 goto cleanup_event;
3160         }
3161
3162         /*
3163          * If chaining, we need to make sure that the right result code is
3164          * returned, and that the rdatasets are bound.
3165          */
3166         if (vevent->result == ISC_R_SUCCESS &&
3167             !negative &&
3168             vevent->rdataset != NULL &&
3169             CHAINING(vevent->rdataset))
3170         {
3171                 if (vevent->rdataset->type == dns_rdatatype_cname)
3172                         eresult = DNS_R_CNAME;
3173                 else {
3174                         INSIST(vevent->rdataset->type == dns_rdatatype_dname);
3175                         eresult = DNS_R_DNAME;
3176                 }
3177                 chaining = ISC_TRUE;
3178         } else
3179                 chaining = ISC_FALSE;
3180
3181         /*
3182          * Either we're not shutting down, or we are shutting down but want
3183          * to cache the result anyway (if this was a validation started by
3184          * a query with cd set)
3185          */
3186
3187         hevent = ISC_LIST_HEAD(fctx->events);
3188         if (hevent != NULL) {
3189                 if (!negative && !chaining &&
3190                     (fctx->type == dns_rdatatype_any ||
3191                      fctx->type == dns_rdatatype_rrsig)) {
3192                         /*
3193                          * Don't bind rdatasets; the caller
3194                          * will iterate the node.
3195                          */
3196                 } else {
3197                         ardataset = hevent->rdataset;
3198                         asigrdataset = hevent->sigrdataset;
3199                 }
3200         }
3201
3202         if (vevent->result != ISC_R_SUCCESS) {
3203                 FCTXTRACE("validation failed");
3204                 result = ISC_R_NOTFOUND;
3205                 if (vevent->rdataset != NULL)
3206                         result = dns_db_findnode(fctx->cache, vevent->name,
3207                                                  ISC_TRUE, &node);
3208                 if (result == ISC_R_SUCCESS)
3209                         (void)dns_db_deleterdataset(fctx->cache, node, NULL,
3210                                                     vevent->type, 0);
3211                 if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL)
3212                         (void)dns_db_deleterdataset(fctx->cache, node, NULL,
3213                                                     dns_rdatatype_rrsig,
3214                                                     vevent->type);
3215                 if (result == ISC_R_SUCCESS)
3216                         dns_db_detachnode(fctx->cache, &node);
3217                 result = vevent->result;
3218                 add_bad(fctx, &addrinfo->sockaddr, result);
3219                 isc_event_free(&event);
3220                 if (sentresponse)
3221                         fctx_done(fctx, result);
3222                 else
3223                         fctx_try(fctx);
3224                 return;
3225         }
3226
3227         isc_stdtime_get(&now);
3228
3229         if (negative) {
3230                 dns_rdatatype_t covers;
3231                 FCTXTRACE("nonexistence validation OK");
3232
3233                 if (fctx->rmessage->rcode == dns_rcode_nxdomain)
3234                         covers = dns_rdatatype_any;
3235                 else
3236                         covers = fctx->type;
3237
3238                 result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE,
3239                                          &node);
3240                 if (result != ISC_R_SUCCESS)
3241                         goto noanswer_response;
3242
3243                 /*
3244                  * If we are asking for a SOA record set the cache time
3245                  * to zero to facilitate locating the containing zone of
3246                  * a arbitary zone.
3247                  */
3248                 ttl = fctx->res->view->maxncachettl;
3249                 if (fctx->type == dns_rdatatype_soa &&
3250                     covers == dns_rdatatype_any)
3251                         ttl = 0;
3252
3253                 result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
3254                                            covers, now, ttl,
3255                                            ardataset, &eresult);
3256                 if (result != ISC_R_SUCCESS)
3257                         goto noanswer_response;
3258                 goto answer_response;
3259         }
3260
3261         FCTXTRACE("validation OK");
3262
3263         if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) {
3264
3265                 result = dns_rdataset_addnoqname(vevent->rdataset,
3266                                    vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]);
3267                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3268                 vevent->sigrdataset->ttl = vevent->rdataset->ttl;
3269         }
3270
3271         /*
3272          * The data was already cached as pending data.
3273          * Re-cache it as secure and bind the cached
3274          * rdatasets to the first event on the fetch
3275          * event list.
3276          */
3277         result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node);
3278         if (result != ISC_R_SUCCESS)
3279                 goto noanswer_response;
3280
3281         result = dns_db_addrdataset(fctx->cache, node, NULL, now,
3282                                     vevent->rdataset, 0, ardataset);
3283         if (result != ISC_R_SUCCESS &&
3284             result != DNS_R_UNCHANGED)
3285                 goto noanswer_response;
3286         if (vevent->sigrdataset != NULL) {
3287                 result = dns_db_addrdataset(fctx->cache, node, NULL, now,
3288                                             vevent->sigrdataset, 0,
3289                                             asigrdataset);
3290                 if (result != ISC_R_SUCCESS &&
3291                     result != DNS_R_UNCHANGED)
3292                         goto noanswer_response;
3293         }
3294
3295         if (sentresponse) {
3296                 /*
3297                  * If we only deferred the destroy because we wanted to cache
3298                  * the data, destroy now.
3299                  */
3300                 if (SHUTTINGDOWN(fctx))
3301                         maybe_destroy(fctx);
3302
3303                 goto cleanup_event;
3304         }
3305
3306         if (!ISC_LIST_EMPTY(fctx->validators)) {
3307                 INSIST(!negative);
3308                 INSIST(fctx->type == dns_rdatatype_any ||
3309                        fctx->type == dns_rdatatype_rrsig);
3310                 /*
3311                  * Don't send a response yet - we have
3312                  * more rdatasets that still need to
3313                  * be validated.
3314                  */
3315                 goto cleanup_event;
3316         }
3317
3318  answer_response:
3319         /*
3320          * Cache any NS/NSEC records that happened to be validated.
3321          */
3322         result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY);
3323         while (result == ISC_R_SUCCESS) {
3324                 name = NULL;
3325                 dns_message_currentname(fctx->rmessage, DNS_SECTION_AUTHORITY,
3326                                         &name);
3327                 for (rdataset = ISC_LIST_HEAD(name->list);
3328                      rdataset != NULL;
3329                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
3330                         if ((rdataset->type != dns_rdatatype_ns &&
3331                              rdataset->type != dns_rdatatype_nsec) ||
3332                             rdataset->trust != dns_trust_secure)
3333                                 continue;
3334                         for (sigrdataset = ISC_LIST_HEAD(name->list);
3335                              sigrdataset != NULL;
3336                              sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
3337                                 if (sigrdataset->type != dns_rdatatype_rrsig ||
3338                                     sigrdataset->covers != rdataset->type)
3339                                         continue;
3340                                 break;
3341                         }
3342                         if (sigrdataset == NULL ||
3343                             sigrdataset->trust != dns_trust_secure)
3344                                 continue;
3345                         result = dns_db_findnode(fctx->cache, name, ISC_TRUE,
3346                                                  &nsnode);
3347                         if (result != ISC_R_SUCCESS)
3348                                 continue;
3349
3350                         result = dns_db_addrdataset(fctx->cache, nsnode, NULL,
3351                                                     now, rdataset, 0, NULL);
3352                         if (result == ISC_R_SUCCESS)
3353                                 result = dns_db_addrdataset(fctx->cache, nsnode,
3354                                                             NULL, now,
3355                                                             sigrdataset, 0,
3356                                                             NULL);
3357                         dns_db_detachnode(fctx->cache, &nsnode);
3358                 }
3359                 result = dns_message_nextname(fctx->rmessage,
3360                                               DNS_SECTION_AUTHORITY);
3361         }
3362
3363         result = ISC_R_SUCCESS;
3364
3365         /*
3366          * Respond with an answer, positive or negative,
3367          * as opposed to an error.  'node' must be non-NULL.
3368          */
3369
3370         fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3371
3372         if (hevent != NULL) {
3373                 hevent->result = eresult;
3374                 RUNTIME_CHECK(dns_name_copy(vevent->name,
3375                               dns_fixedname_name(&hevent->foundname), NULL)
3376                               == ISC_R_SUCCESS);
3377                 dns_db_attach(fctx->cache, &hevent->db);
3378                 hevent->node = node;
3379                 node = NULL;
3380                 clone_results(fctx);
3381         }
3382
3383  noanswer_response:
3384         if (node != NULL)
3385                 dns_db_detachnode(fctx->cache, &node);
3386
3387         fctx_done(fctx, result);
3388
3389  cleanup_event:
3390         isc_event_free(&event);
3391 }
3392
3393 static inline isc_result_t
3394 cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
3395            isc_stdtime_t now) {
3396         dns_rdataset_t *rdataset, *sigrdataset;
3397         dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset;
3398         dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL;
3399         dns_dbnode_t *node, **anodep;
3400         dns_db_t **adbp;
3401         dns_name_t *aname;
3402         dns_resolver_t *res;
3403         isc_boolean_t need_validation, secure_domain, have_answer;
3404         isc_result_t result, eresult;
3405         dns_fetchevent_t *event;
3406         unsigned int options;
3407         isc_task_t *task;
3408         isc_boolean_t fail;
3409         unsigned int valoptions = 0;
3410
3411         /*
3412          * The appropriate bucket lock must be held.
3413          */
3414
3415         res = fctx->res;
3416         need_validation = ISC_FALSE;
3417         secure_domain = ISC_FALSE;
3418         have_answer = ISC_FALSE;
3419         eresult = ISC_R_SUCCESS;
3420         task = res->buckets[fctx->bucketnum].task;
3421
3422         /*
3423          * Is DNSSEC validation required for this name?
3424          */
3425         result = dns_keytable_issecuredomain(res->view->secroots, name,
3426                                              &secure_domain);
3427         if (result != ISC_R_SUCCESS)
3428                 return (result);
3429
3430         if (!secure_domain && res->view->dlv != NULL) {
3431                 valoptions = DNS_VALIDATOR_DLV;
3432                 secure_domain = ISC_TRUE;
3433         }
3434
3435         if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
3436                 need_validation = ISC_FALSE;
3437         else
3438                 need_validation = secure_domain;
3439
3440         adbp = NULL;
3441         aname = NULL;
3442         anodep = NULL;
3443         ardataset = NULL;
3444         asigrdataset = NULL;
3445         event = NULL;
3446         if ((name->attributes & DNS_NAMEATTR_ANSWER) != 0 &&
3447             !need_validation) {
3448                 have_answer = ISC_TRUE;
3449                 event = ISC_LIST_HEAD(fctx->events);
3450                 if (event != NULL) {
3451                         adbp = &event->db;
3452                         aname = dns_fixedname_name(&event->foundname);
3453                         result = dns_name_copy(name, aname, NULL);
3454                         if (result != ISC_R_SUCCESS)
3455                                 return (result);
3456                         anodep = &event->node;
3457                         /*
3458                          * If this is an ANY or SIG query, we're not going
3459                          * to return any rdatasets, unless we encountered
3460                          * a CNAME or DNAME as "the answer".  In this case,
3461                          * we're going to return DNS_R_CNAME or DNS_R_DNAME
3462                          * and we must set up the rdatasets.
3463                          */
3464                         if ((fctx->type != dns_rdatatype_any &&
3465                             fctx->type != dns_rdatatype_rrsig) ||
3466                             (name->attributes & DNS_NAMEATTR_CHAINING) != 0) {
3467                                 ardataset = event->rdataset;
3468                                 asigrdataset = event->sigrdataset;
3469                         }
3470                 }
3471         }
3472
3473         /*
3474          * Find or create the cache node.
3475          */
3476         node = NULL;
3477         result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
3478         if (result != ISC_R_SUCCESS)
3479                 return (result);
3480
3481         /*
3482          * Cache or validate each cacheable rdataset.
3483          */
3484         fail = ISC_TF((fctx->res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0);
3485         for (rdataset = ISC_LIST_HEAD(name->list);
3486              rdataset != NULL;
3487              rdataset = ISC_LIST_NEXT(rdataset, link)) {
3488                 if (!CACHE(rdataset))
3489                         continue;
3490                 if (CHECKNAMES(rdataset)) {
3491                         char namebuf[DNS_NAME_FORMATSIZE];
3492                         char typebuf[DNS_RDATATYPE_FORMATSIZE];
3493                         char classbuf[DNS_RDATATYPE_FORMATSIZE];
3494
3495                         dns_name_format(name, namebuf, sizeof(namebuf));
3496                         dns_rdatatype_format(rdataset->type, typebuf,
3497                                              sizeof(typebuf));
3498                         dns_rdataclass_format(rdataset->rdclass, classbuf,
3499                                               sizeof(classbuf));
3500                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,  
3501                                       DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
3502                                       "check-names %s %s/%s/%s", 
3503                                       fail ? "failure" : "warning",
3504                                       namebuf, typebuf, classbuf);
3505                         if (fail) {
3506                                 if (ANSWER(rdataset))
3507                                         return (DNS_R_BADNAME);
3508                                 continue;
3509                         }
3510                 }
3511
3512                 /*
3513                  * Enforce the configure maximum cache TTL.
3514                  */
3515                 if (rdataset->ttl > res->view->maxcachettl)
3516                         rdataset->ttl = res->view->maxcachettl;
3517
3518                 /*
3519                  * If this rrset is in a secure domain, do DNSSEC validation
3520                  * for it, unless it is glue.
3521                  */
3522                 if (secure_domain && rdataset->trust != dns_trust_glue) {
3523                         /*
3524                          * SIGs are validated as part of validating the
3525                          * type they cover.
3526                          */
3527                         if (rdataset->type == dns_rdatatype_rrsig)
3528                                 continue;
3529                         /*
3530                          * Find the SIG for this rdataset, if we have it.
3531                          */
3532                         for (sigrdataset = ISC_LIST_HEAD(name->list);
3533                              sigrdataset != NULL;
3534                              sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
3535                                 if (sigrdataset->type == dns_rdatatype_rrsig &&
3536                                     sigrdataset->covers == rdataset->type)
3537                                         break;
3538                         }
3539                         if (sigrdataset == NULL) {
3540                                 if (!ANSWER(rdataset) && need_validation) {
3541                                         /*
3542                                          * Ignore non-answer rdatasets that
3543                                          * are missing signatures.
3544                                          */
3545                                         continue;
3546                                 }
3547                         }
3548
3549                         /*
3550                          * Normalize the rdataset and sigrdataset TTLs.
3551                          */
3552                         if (sigrdataset != NULL) {
3553                                 rdataset->ttl = ISC_MIN(rdataset->ttl,
3554                                                         sigrdataset->ttl);
3555                                 sigrdataset->ttl = rdataset->ttl;
3556                         }
3557
3558                         /*
3559                          * Cache this rdataset/sigrdataset pair as
3560                          * pending data.
3561                          */
3562                         rdataset->trust = dns_trust_pending;
3563                         if (sigrdataset != NULL)
3564                                 sigrdataset->trust = dns_trust_pending;
3565                         if (!need_validation)
3566                                 addedrdataset = ardataset;
3567                         else
3568                                 addedrdataset = NULL;
3569                         result = dns_db_addrdataset(fctx->cache, node, NULL,
3570                                                     now, rdataset, 0,
3571                                                     addedrdataset);
3572                         if (result == DNS_R_UNCHANGED)
3573                                 result = ISC_R_SUCCESS;
3574                         if (result != ISC_R_SUCCESS)
3575                                 break;
3576                         if (sigrdataset != NULL) {
3577                                 if (!need_validation)
3578                                         addedrdataset = asigrdataset;
3579                                 else
3580                                         addedrdataset = NULL;
3581                                 result = dns_db_addrdataset(fctx->cache,
3582                                                             node, NULL, now,
3583                                                             sigrdataset, 0,
3584                                                             addedrdataset);
3585                                 if (result == DNS_R_UNCHANGED)
3586                                         result = ISC_R_SUCCESS;
3587                                 if (result != ISC_R_SUCCESS)
3588                                         break;
3589                         } else if (!ANSWER(rdataset))
3590                                 continue;
3591
3592                         if (ANSWER(rdataset) && need_validation) {
3593                                 if (fctx->type != dns_rdatatype_any &&
3594                                     fctx->type != dns_rdatatype_rrsig) {
3595                                         /*
3596                                          * This is The Answer.  We will
3597                                          * validate it, but first we cache
3598                                          * the rest of the response - it may
3599                                          * contain useful keys.
3600                                          */
3601                                         INSIST(valrdataset == NULL &&
3602                                                valsigrdataset == NULL);
3603                                         valrdataset = rdataset;
3604                                         valsigrdataset = sigrdataset;
3605                                 } else {
3606                                         /*
3607                                          * This is one of (potentially)
3608                                          * multiple answers to an ANY
3609                                          * or SIG query.  To keep things
3610                                          * simple, we just start the
3611                                          * validator right away rather
3612                                          * than caching first and
3613                                          * having to remember which
3614                                          * rdatasets needed validation.
3615                                          */
3616                                         result = valcreate(fctx, addrinfo,
3617                                                            name, rdataset->type,
3618                                                            rdataset,
3619                                                            sigrdataset,
3620                                                            valoptions, task);
3621                                 }
3622                         } else if (CHAINING(rdataset)) {
3623                                 if (rdataset->type == dns_rdatatype_cname)
3624                                         eresult = DNS_R_CNAME;
3625                                 else {
3626                                         INSIST(rdataset->type ==
3627                                                dns_rdatatype_dname);
3628                                         eresult = DNS_R_DNAME;
3629                                 }
3630                         }
3631                 } else if (!EXTERNAL(rdataset)) {
3632                         /*
3633                          * It's OK to cache this rdataset now.
3634                          */
3635                         if (ANSWER(rdataset))
3636                                 addedrdataset = ardataset;
3637                         else if (ANSWERSIG(rdataset))
3638                                 addedrdataset = asigrdataset;
3639                         else
3640                                 addedrdataset = NULL;
3641                         if (CHAINING(rdataset)) {
3642                                 if (rdataset->type == dns_rdatatype_cname)
3643                                         eresult = DNS_R_CNAME;
3644                                 else {
3645                                         INSIST(rdataset->type ==
3646                                                dns_rdatatype_dname);
3647                                         eresult = DNS_R_DNAME;
3648                                 }
3649                         }
3650                         if (rdataset->trust == dns_trust_glue &&
3651                             (rdataset->type == dns_rdatatype_ns ||
3652                              (rdataset->type == dns_rdatatype_rrsig &&
3653                               rdataset->covers == dns_rdatatype_ns))) {
3654                                 /*
3655                                  * If the trust level is 'dns_trust_glue'
3656                                  * then we are adding data from a referral
3657                                  * we got while executing the search algorithm.
3658                                  * New referral data always takes precedence
3659                                  * over the existing cache contents.
3660                                  */
3661                                 options = DNS_DBADD_FORCE;
3662                         } else
3663                                 options = 0;
3664                         /*
3665                          * Now we can add the rdataset.
3666                          */
3667                         result = dns_db_addrdataset(fctx->cache,
3668                                                     node, NULL, now,
3669                                                     rdataset,
3670                                                     options,
3671                                                     addedrdataset);
3672                         if (result == DNS_R_UNCHANGED) {
3673                                 if (ANSWER(rdataset) &&
3674                                     ardataset != NULL &&
3675                                     ardataset->type == 0) {
3676                                         /*
3677                                          * The answer in the cache is better
3678                                          * than the answer we found, and is
3679                                          * a negative cache entry, so we
3680                                          * must set eresult appropriately.
3681                                          */
3682                                          if (NXDOMAIN(ardataset))
3683                                                  eresult =
3684                                                          DNS_R_NCACHENXDOMAIN;
3685                                          else
3686                                                  eresult =
3687                                                          DNS_R_NCACHENXRRSET;
3688                                 }
3689                                 result = ISC_R_SUCCESS;
3690                         } else if (result != ISC_R_SUCCESS)
3691                                 break;
3692                 }
3693         }
3694
3695         if (valrdataset != NULL)
3696                 result = valcreate(fctx, addrinfo, name, fctx->type,
3697                                    valrdataset, valsigrdataset, valoptions,
3698                                     task);
3699
3700         if (result == ISC_R_SUCCESS && have_answer) {
3701                 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3702                 if (event != NULL) {
3703                         event->result = eresult;
3704                         dns_db_attach(fctx->cache, adbp);
3705                         *anodep = node;
3706                         node = NULL;
3707                         clone_results(fctx);
3708                 }
3709         }
3710
3711         if (node != NULL)
3712                 dns_db_detachnode(fctx->cache, &node);
3713
3714         return (result);
3715 }
3716
3717 static inline isc_result_t
3718 cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now)
3719 {
3720         isc_result_t result;
3721         dns_section_t section;
3722         dns_name_t *name;
3723
3724         FCTXTRACE("cache_message");
3725
3726         fctx->attributes &= ~FCTX_ATTR_WANTCACHE;
3727
3728         LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3729
3730         for (section = DNS_SECTION_ANSWER;
3731              section <= DNS_SECTION_ADDITIONAL;
3732              section++) {
3733                 result = dns_message_firstname(fctx->rmessage, section);
3734                 while (result == ISC_R_SUCCESS) {
3735                         name = NULL;
3736                         dns_message_currentname(fctx->rmessage, section,
3737                                                 &name);
3738                         if ((name->attributes & DNS_NAMEATTR_CACHE) != 0) {
3739                                 result = cache_name(fctx, name, addrinfo, now);
3740                                 if (result != ISC_R_SUCCESS)
3741                                         break;
3742                         }
3743                         result = dns_message_nextname(fctx->rmessage, section);
3744                 }
3745                 if (result != ISC_R_NOMORE)
3746                         break;
3747         }
3748         if (result == ISC_R_NOMORE)
3749                 result = ISC_R_SUCCESS;
3750
3751         UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
3752
3753         return (result);
3754 }
3755
3756 /*
3757  * Do what dns_ncache_add() does, and then compute an appropriate eresult.
3758  */
3759 static isc_result_t
3760 ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
3761                   dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
3762                   dns_rdataset_t *ardataset,
3763                   isc_result_t *eresultp)
3764 {
3765         isc_result_t result;
3766         result = dns_ncache_add(message, cache, node, covers, now,
3767                                 maxttl, ardataset);
3768         if (result == DNS_R_UNCHANGED) {
3769                 /*
3770                  * The data in the cache are better than the negative cache
3771                  * entry we're trying to add.
3772                  */
3773                 if (ardataset != NULL && ardataset->type == 0) {
3774                         /*
3775                          * The cache data is also a negative cache
3776                          * entry.
3777                          */
3778                         if (NXDOMAIN(ardataset))
3779                                 *eresultp = DNS_R_NCACHENXDOMAIN;
3780                         else
3781                                 *eresultp = DNS_R_NCACHENXRRSET;
3782                         result = ISC_R_SUCCESS;
3783                 } else {
3784                         /*
3785                          * Either we don't care about the nature of the
3786                          * cache rdataset (because no fetch is interested
3787                          * in the outcome), or the cache rdataset is not
3788                          * a negative cache entry.  Whichever case it is,
3789                          * we can return success.
3790                          *
3791                          * XXXRTH  There's a CNAME/DNAME problem here.
3792                          */
3793                         *eresultp = ISC_R_SUCCESS;
3794                         result = ISC_R_SUCCESS;
3795                 }
3796         } else if (result == ISC_R_SUCCESS) {
3797                 if (NXDOMAIN(ardataset))
3798                         *eresultp = DNS_R_NCACHENXDOMAIN;
3799                 else
3800                         *eresultp = DNS_R_NCACHENXRRSET;
3801         }
3802
3803         return (result);
3804 }
3805
3806 static inline isc_result_t
3807 ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
3808                dns_rdatatype_t covers, isc_stdtime_t now)
3809 {
3810         isc_result_t result, eresult;
3811         dns_name_t *name;
3812         dns_resolver_t *res;
3813         dns_db_t **adbp;
3814         dns_dbnode_t *node, **anodep;
3815         dns_rdataset_t *ardataset;
3816         isc_boolean_t need_validation, secure_domain;
3817         dns_name_t *aname;
3818         dns_fetchevent_t *event;
3819         isc_uint32_t ttl;
3820         unsigned int valoptions = 0;
3821
3822         FCTXTRACE("ncache_message");
3823
3824         fctx->attributes &= ~FCTX_ATTR_WANTNCACHE;
3825
3826         res = fctx->res;
3827         need_validation = ISC_FALSE;
3828         secure_domain = ISC_FALSE;
3829         eresult = ISC_R_SUCCESS;
3830         name = &fctx->name;
3831         node = NULL;
3832
3833         /*
3834          * XXXMPA remove when we follow cnames and adjust the setting
3835          * of FCTX_ATTR_WANTNCACHE in noanswer_response().
3836          */
3837         INSIST(fctx->rmessage->counts[DNS_SECTION_ANSWER] == 0);
3838
3839         /*
3840          * Is DNSSEC validation required for this name?
3841          */
3842         result = dns_keytable_issecuredomain(res->view->secroots, name,
3843                                              &secure_domain);
3844         if (result != ISC_R_SUCCESS)
3845                 return (result);
3846
3847         if (!secure_domain && res->view->dlv != NULL) {
3848                 valoptions = DNS_VALIDATOR_DLV;
3849                 secure_domain = ISC_TRUE;
3850         }
3851
3852         if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
3853                 need_validation = ISC_FALSE;
3854         else
3855                 need_validation = secure_domain;
3856
3857         if (secure_domain) {
3858                 /*
3859                  * Mark all rdatasets as pending.
3860                  */
3861                 dns_rdataset_t *trdataset;
3862                 dns_name_t *tname;
3863
3864                 result = dns_message_firstname(fctx->rmessage,
3865                                                DNS_SECTION_AUTHORITY);
3866                 while (result == ISC_R_SUCCESS) {
3867                         tname = NULL;
3868                         dns_message_currentname(fctx->rmessage,
3869                                                 DNS_SECTION_AUTHORITY,
3870                                                 &tname);
3871                         for (trdataset = ISC_LIST_HEAD(tname->list);
3872                              trdataset != NULL;
3873                              trdataset = ISC_LIST_NEXT(trdataset, link))
3874                                 trdataset->trust = dns_trust_pending;
3875                         result = dns_message_nextname(fctx->rmessage,
3876                                                       DNS_SECTION_AUTHORITY);
3877                 }
3878                 if (result != ISC_R_NOMORE)
3879                         return (result);
3880
3881         }
3882
3883         if (need_validation) {
3884                 /*
3885                  * Do negative response validation.
3886                  */
3887                 result = valcreate(fctx, addrinfo, name, fctx->type,
3888                                    NULL, NULL, valoptions,
3889                                    res->buckets[fctx->bucketnum].task);
3890                 /*
3891                  * If validation is necessary, return now.  Otherwise continue
3892                  * to process the message, letting the validation complete
3893                  * in its own good time.
3894                  */
3895                 return (result);
3896         }
3897
3898         LOCK(&res->buckets[fctx->bucketnum].lock);
3899
3900         adbp = NULL;
3901         aname = NULL;
3902         anodep = NULL;
3903         ardataset = NULL;
3904         if (!HAVE_ANSWER(fctx)) {
3905                 event = ISC_LIST_HEAD(fctx->events);
3906                 if (event != NULL) {
3907                         adbp = &event->db;
3908                         aname = dns_fixedname_name(&event->foundname);
3909                         result = dns_name_copy(name, aname, NULL);
3910                         if (result != ISC_R_SUCCESS)
3911                                 goto unlock;
3912                         anodep = &event->node;
3913                         ardataset = event->rdataset;
3914                 }
3915         } else
3916                 event = NULL;
3917
3918         result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
3919         if (result != ISC_R_SUCCESS)
3920                 goto unlock;
3921
3922         /*
3923          * If we are asking for a SOA record set the cache time
3924          * to zero to facilitate locating the containing zone of
3925          * a arbitary zone.
3926          */
3927         ttl = fctx->res->view->maxncachettl;
3928         if (fctx->type == dns_rdatatype_soa &&
3929             covers == dns_rdatatype_any)
3930                 ttl = 0;
3931
3932         result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
3933                                    covers, now, ttl, ardataset, &eresult);
3934         if (result != ISC_R_SUCCESS)
3935                 goto unlock;
3936
3937         if (!HAVE_ANSWER(fctx)) {
3938                 fctx->attributes |= FCTX_ATTR_HAVEANSWER;
3939                 if (event != NULL) {
3940                         event->result = eresult;
3941                         dns_db_attach(fctx->cache, adbp);
3942                         *anodep = node;
3943                         node = NULL;
3944                         clone_results(fctx);
3945                 }
3946         }
3947
3948  unlock:
3949         UNLOCK(&res->buckets[fctx->bucketnum].lock);
3950
3951         if (node != NULL)
3952                 dns_db_detachnode(fctx->cache, &node);
3953
3954         return (result);
3955 }
3956
3957 static inline void
3958 mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
3959              isc_boolean_t external, isc_boolean_t gluing)
3960 {
3961         name->attributes |= DNS_NAMEATTR_CACHE;
3962         if (gluing) {
3963                 rdataset->trust = dns_trust_glue;
3964                 /*
3965                  * Glue with 0 TTL causes problems.  We force the TTL to
3966                  * 1 second to prevent this.
3967                  */
3968                 if (rdataset->ttl == 0)
3969                         rdataset->ttl = 1;
3970         } else
3971                 rdataset->trust = dns_trust_additional;
3972         /*
3973          * Avoid infinite loops by only marking new rdatasets.
3974          */
3975         if (!CACHE(rdataset)) {
3976                 name->attributes |= DNS_NAMEATTR_CHASE;
3977                 rdataset->attributes |= DNS_RDATASETATTR_CHASE;
3978         }
3979         rdataset->attributes |= DNS_RDATASETATTR_CACHE;
3980         if (external)
3981                 rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
3982 }
3983
3984 static isc_result_t
3985 check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
3986         fetchctx_t *fctx = arg;
3987         isc_result_t result;
3988         dns_name_t *name;
3989         dns_rdataset_t *rdataset;
3990         isc_boolean_t external;
3991         dns_rdatatype_t rtype;
3992         isc_boolean_t gluing;
3993
3994         REQUIRE(VALID_FCTX(fctx));
3995
3996         if (GLUING(fctx))
3997                 gluing = ISC_TRUE;
3998         else
3999                 gluing = ISC_FALSE;
4000         name = NULL;
4001         rdataset = NULL;
4002         result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
4003                                       addname, dns_rdatatype_any, 0, &name,
4004                                       NULL);
4005         if (result == ISC_R_SUCCESS) {
4006                 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
4007                 if (type == dns_rdatatype_a) {
4008                         for (rdataset = ISC_LIST_HEAD(name->list);
4009                              rdataset != NULL;
4010                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
4011                                 if (rdataset->type == dns_rdatatype_rrsig)
4012                                         rtype = rdataset->covers;
4013                                 else
4014                                         rtype = rdataset->type;
4015                                 if (rtype == dns_rdatatype_a ||
4016                                     rtype == dns_rdatatype_aaaa)
4017                                         mark_related(name, rdataset, external,
4018                                                      gluing);
4019                         }
4020                 } else {
4021                         result = dns_message_findtype(name, type, 0,
4022                                                       &rdataset);
4023                         if (result == ISC_R_SUCCESS) {
4024                                 mark_related(name, rdataset, external, gluing);
4025                                 /*
4026                                  * Do we have its SIG too?
4027                                  */
4028                                 rdataset = NULL;
4029                                 result = dns_message_findtype(name,
4030                                                       dns_rdatatype_rrsig,
4031                                                       type, &rdataset);
4032                                 if (result == ISC_R_SUCCESS)
4033                                         mark_related(name, rdataset, external,
4034                                                      gluing);
4035                         }
4036                 }
4037         }
4038
4039         return (ISC_R_SUCCESS);
4040 }
4041
4042 static void
4043 chase_additional(fetchctx_t *fctx) {
4044         isc_boolean_t rescan;
4045         dns_section_t section = DNS_SECTION_ADDITIONAL;
4046         isc_result_t result;
4047
4048  again:
4049         rescan = ISC_FALSE;
4050         
4051         for (result = dns_message_firstname(fctx->rmessage, section);
4052              result == ISC_R_SUCCESS;
4053              result = dns_message_nextname(fctx->rmessage, section)) {
4054                 dns_name_t *name = NULL;
4055                 dns_rdataset_t *rdataset;
4056                 dns_message_currentname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
4057                                         &name);
4058                 if ((name->attributes & DNS_NAMEATTR_CHASE) == 0)
4059                         continue;
4060                 name->attributes &= ~DNS_NAMEATTR_CHASE;
4061                 for (rdataset = ISC_LIST_HEAD(name->list);
4062                      rdataset != NULL;
4063                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
4064                         if (CHASE(rdataset)) {
4065                                 rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
4066                                 (void)dns_rdataset_additionaldata(rdataset,
4067                                                                   check_related,
4068                                                                   fctx);
4069                                 rescan = ISC_TRUE;
4070                         }
4071                 }
4072         }
4073         if (rescan)
4074                 goto again;
4075 }
4076
4077 static inline isc_result_t
4078 cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) {
4079         isc_result_t result;
4080         dns_rdata_t rdata = DNS_RDATA_INIT;
4081         dns_rdata_cname_t cname;
4082
4083         result = dns_rdataset_first(rdataset);
4084         if (result != ISC_R_SUCCESS)
4085                 return (result);
4086         dns_rdataset_current(rdataset, &rdata);
4087         result = dns_rdata_tostruct(&rdata, &cname, NULL);
4088         if (result != ISC_R_SUCCESS)
4089                 return (result);
4090         dns_name_init(tname, NULL);
4091         dns_name_clone(&cname.cname, tname);
4092         dns_rdata_freestruct(&cname);
4093
4094         return (ISC_R_SUCCESS);
4095 }
4096
4097 static inline isc_result_t
4098 dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
4099              dns_fixedname_t *fixeddname)
4100 {
4101         isc_result_t result;
4102         dns_rdata_t rdata = DNS_RDATA_INIT;
4103         unsigned int nlabels;
4104         int order;
4105         dns_namereln_t namereln;
4106         dns_rdata_dname_t dname;
4107         dns_fixedname_t prefix;
4108
4109         /*
4110          * Get the target name of the DNAME.
4111          */
4112
4113         result = dns_rdataset_first(rdataset);
4114         if (result != ISC_R_SUCCESS)
4115                 return (result);
4116         dns_rdataset_current(rdataset, &rdata);
4117         result = dns_rdata_tostruct(&rdata, &dname, NULL);
4118         if (result != ISC_R_SUCCESS)
4119                 return (result);
4120
4121         /*
4122          * Get the prefix of qname.
4123          */
4124         namereln = dns_name_fullcompare(qname, oname, &order, &nlabels);
4125         if (namereln != dns_namereln_subdomain) {
4126                 dns_rdata_freestruct(&dname);
4127                 return (DNS_R_FORMERR);
4128         }
4129         dns_fixedname_init(&prefix);
4130         dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); 
4131         dns_fixedname_init(fixeddname);
4132         result = dns_name_concatenate(dns_fixedname_name(&prefix),
4133                                       &dname.dname,
4134                                       dns_fixedname_name(fixeddname), NULL);
4135         dns_rdata_freestruct(&dname);
4136         return (result);
4137 }
4138
4139 /*
4140  * Handle a no-answer response (NXDOMAIN, NXRRSET, or referral).
4141  * If bind8_ns_resp is ISC_TRUE, this is a suspected BIND 8
4142  * response to an NS query that should be treated as a referral
4143  * even though the NS records occur in the answer section
4144  * rather than the authority section.
4145  */
4146 static isc_result_t
4147 noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
4148                   isc_boolean_t bind8_ns_resp)
4149 {
4150         isc_result_t result;
4151         dns_message_t *message;
4152         dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name;
4153         dns_rdataset_t *rdataset, *ns_rdataset;
4154         isc_boolean_t done, aa, negative_response;
4155         dns_rdatatype_t type;
4156         dns_section_t section =
4157                 bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY;
4158
4159         FCTXTRACE("noanswer_response");
4160
4161         message = fctx->rmessage;
4162
4163         /*
4164          * Setup qname.
4165          */
4166         if (oqname == NULL) {
4167                 /*
4168                  * We have a normal, non-chained negative response or
4169                  * referral.
4170                  */
4171                 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
4172                         aa = ISC_TRUE;
4173                 else
4174                         aa = ISC_FALSE;
4175                 qname = &fctx->name;
4176         } else {
4177                 /*
4178                  * We're being invoked by answer_response() after it has
4179                  * followed a CNAME/DNAME chain.
4180                  */
4181                 qname = oqname;
4182                 aa = ISC_FALSE;
4183                 /*
4184                  * If the current qname is not a subdomain of the query
4185                  * domain, there's no point in looking at the authority
4186                  * section without doing DNSSEC validation.
4187                  *
4188                  * Until we do that validation, we'll just return success
4189                  * in this case.
4190                  */
4191                 if (!dns_name_issubdomain(qname, &fctx->domain))
4192                         return (ISC_R_SUCCESS);
4193         }
4194
4195         /*
4196          * We have to figure out if this is a negative response, or a
4197          * referral.
4198          */
4199
4200         /*
4201          * Sometimes we can tell if its a negative response by looking at
4202          * the message header.
4203          */
4204         negative_response = ISC_FALSE;
4205         if (message->rcode == dns_rcode_nxdomain ||
4206             (message->counts[DNS_SECTION_ANSWER] == 0 &&
4207              message->counts[DNS_SECTION_AUTHORITY] == 0))
4208                 negative_response = ISC_TRUE;
4209
4210         /*
4211          * Process the authority section.
4212          */
4213         done = ISC_FALSE;
4214         ns_name = NULL;
4215         ns_rdataset = NULL;
4216         soa_name = NULL;
4217         ds_name = NULL;
4218         result = dns_message_firstname(message, section);
4219         while (!done && result == ISC_R_SUCCESS) {
4220                 name = NULL;
4221                 dns_message_currentname(message, section, &name);
4222                 if (dns_name_issubdomain(name, &fctx->domain)) {
4223                         /*
4224                          * Look for NS/SOA RRsets first.
4225                          */
4226                         for (rdataset = ISC_LIST_HEAD(name->list);
4227                              rdataset != NULL;
4228                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
4229                                 type = rdataset->type;
4230                                 if (type == dns_rdatatype_rrsig)
4231                                         type = rdataset->covers;
4232                                 if (((type == dns_rdatatype_ns ||
4233                                       type == dns_rdatatype_soa) &&
4234                                      !dns_name_issubdomain(qname, name)))
4235                                         return (DNS_R_FORMERR);
4236                                 if (type == dns_rdatatype_ns) {
4237                                         /*
4238                                          * NS or RRSIG NS.
4239                                          *
4240                                          * Only one set of NS RRs is allowed.
4241                                          */
4242                                         if (rdataset->type ==
4243                                             dns_rdatatype_ns) {
4244                                                 if (ns_name != NULL &&
4245                                                     name != ns_name)
4246                                                         return (DNS_R_FORMERR);
4247                                                 ns_name = name;
4248                                                 ns_rdataset = rdataset;
4249                                         }
4250                                         name->attributes |=
4251                                                 DNS_NAMEATTR_CACHE;
4252                                         rdataset->attributes |=
4253                                                 DNS_RDATASETATTR_CACHE;
4254                                         rdataset->trust = dns_trust_glue;
4255                                 }
4256                                 if (type == dns_rdatatype_soa) {
4257                                         /*
4258                                          * SOA, or RRSIG SOA.
4259                                          *
4260                                          * Only one SOA is allowed.
4261                                          */
4262                                         if (rdataset->type ==
4263                                             dns_rdatatype_soa) {
4264                                                 if (soa_name != NULL &&
4265                                                     name != soa_name)
4266                                                         return (DNS_R_FORMERR);
4267                                                 soa_name = name;
4268                                         }
4269                                         name->attributes |=
4270                                                 DNS_NAMEATTR_NCACHE;
4271                                         rdataset->attributes |=
4272                                                 DNS_RDATASETATTR_NCACHE;
4273                                         if (aa)
4274                                                 rdataset->trust =
4275                                                     dns_trust_authauthority;
4276                                         else
4277                                                 rdataset->trust =
4278                                                         dns_trust_additional;
4279                                 }
4280                         }
4281                         /*
4282                          * A negative response has a SOA record (Type 2) 
4283                          * and a optional NS RRset (Type 1) or it has neither
4284                          * a SOA or a NS RRset (Type 3, handled above) or
4285                          * rcode is NXDOMAIN (handled above) in which case
4286                          * the NS RRset is allowed (Type 4).
4287                          */
4288                         if (soa_name != NULL)
4289                                 negative_response = ISC_TRUE;
4290                         for (rdataset = ISC_LIST_HEAD(name->list);
4291                              rdataset != NULL;
4292                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
4293                                 type = rdataset->type;
4294                                 if (type == dns_rdatatype_rrsig)
4295                                         type = rdataset->covers;
4296                                 if (type == dns_rdatatype_nsec) {
4297                                         /*
4298                                          * NSEC or RRSIG NSEC.
4299                                          */
4300                                         if (negative_response) {
4301                                                 name->attributes |=
4302                                                         DNS_NAMEATTR_NCACHE;
4303                                                 rdataset->attributes |=
4304                                                         DNS_RDATASETATTR_NCACHE;
4305                                         } else {
4306                                                 name->attributes |=
4307                                                         DNS_NAMEATTR_CACHE;
4308                                                 rdataset->attributes |=
4309                                                         DNS_RDATASETATTR_CACHE;
4310                                         }
4311                                         if (aa)
4312                                                 rdataset->trust =
4313                                                     dns_trust_authauthority;
4314                                         else
4315                                                 rdataset->trust =
4316                                                         dns_trust_additional;
4317                                         /*
4318                                          * No additional data needs to be
4319                                          * marked.
4320                                          */
4321                                 } else if (type == dns_rdatatype_ds) {
4322                                         /*
4323                                          * DS or SIG DS.
4324                                          *
4325                                          * These should only be here if
4326                                          * this is a referral, and there
4327                                          * should only be one DS.
4328                                          */
4329                                         if (ns_name == NULL)
4330                                                 return (DNS_R_FORMERR);
4331                                         if (rdataset->type ==
4332                                             dns_rdatatype_ds) {
4333                                                 if (ds_name != NULL &&
4334                                                     name != ds_name)
4335                                                         return (DNS_R_FORMERR);
4336                                                 ds_name = name;
4337                                         }
4338                                         name->attributes |=
4339                                                 DNS_NAMEATTR_CACHE;
4340                                         rdataset->attributes |=
4341                                                 DNS_RDATASETATTR_CACHE;
4342                                         if (aa)
4343                                                 rdataset->trust =
4344                                                     dns_trust_authauthority;
4345                                         else
4346                                                 rdataset->trust =
4347                                                         dns_trust_additional;
4348                                 }
4349                         }
4350                 }
4351                 result = dns_message_nextname(message, section);
4352                 if (result == ISC_R_NOMORE)
4353                         break;
4354                 else if (result != ISC_R_SUCCESS)
4355                         return (result);
4356         }
4357
4358         /*
4359          * Trigger lookups for DNS nameservers.
4360          */
4361         if (negative_response && message->rcode == dns_rcode_noerror &&
4362             fctx->type == dns_rdatatype_ds && soa_name != NULL &&
4363             dns_name_equal(soa_name, qname) &&
4364             !dns_name_equal(qname, dns_rootname))
4365                 return (DNS_R_CHASEDSSERVERS);
4366
4367         /*
4368          * Did we find anything?
4369          */
4370         if (!negative_response && ns_name == NULL) {
4371                 /*
4372                  * Nope.
4373                  */
4374                 if (oqname != NULL) {
4375                         /*
4376                          * We've already got a partial CNAME/DNAME chain,
4377                          * and haven't found else anything useful here, but
4378                          * no error has occurred since we have an answer.
4379                          */
4380                         return (ISC_R_SUCCESS);
4381                 } else {
4382                         /*
4383                          * The responder is insane.
4384                          */
4385                         return (DNS_R_FORMERR);
4386                 }
4387         }
4388
4389         /*
4390          * If we found both NS and SOA, they should be the same name.
4391          */
4392         if (ns_name != NULL && soa_name != NULL && ns_name != soa_name)
4393                 return (DNS_R_FORMERR);
4394
4395         /*
4396          * Do we have a referral?  (We only want to follow a referral if
4397          * we're not following a chain.)
4398          */
4399         if (!negative_response && ns_name != NULL && oqname == NULL) {
4400                 /*
4401                  * We already know ns_name is a subdomain of fctx->domain.
4402                  * If ns_name is equal to fctx->domain, we're not making
4403                  * progress.  We return DNS_R_FORMERR so that we'll keep
4404                  * trying other servers.
4405                  */
4406                 if (dns_name_equal(ns_name, &fctx->domain))
4407                         return (DNS_R_FORMERR);
4408
4409                 /*
4410                  * If the referral name is not a parent of the query
4411                  * name, consider the responder insane.
4412                  */
4413                 if (! dns_name_issubdomain(&fctx->name, ns_name)) {
4414                         FCTXTRACE("referral to non-parent");
4415                         return (DNS_R_FORMERR);
4416                 }
4417
4418                 /*
4419                  * Mark any additional data related to this rdataset.
4420                  * It's important that we do this before we change the
4421                  * query domain.
4422                  */
4423                 INSIST(ns_rdataset != NULL);
4424                 fctx->attributes |= FCTX_ATTR_GLUING;
4425                 (void)dns_rdataset_additionaldata(ns_rdataset, check_related,
4426                                                   fctx);
4427                 fctx->attributes &= ~FCTX_ATTR_GLUING;
4428                 /*
4429                  * NS rdatasets with 0 TTL cause problems.
4430                  * dns_view_findzonecut() will not find them when we
4431                  * try to follow the referral, and we'll SERVFAIL
4432                  * because the best nameservers are now above QDOMAIN.
4433                  * We force the TTL to 1 second to prevent this.
4434                  */
4435                 if (ns_rdataset->ttl == 0)
4436                         ns_rdataset->ttl = 1;
4437                 /*
4438                  * Set the current query domain to the referral name.
4439                  *
4440                  * XXXRTH  We should check if we're in forward-only mode, and
4441                  *         if so we should bail out.
4442                  */
4443                 INSIST(dns_name_countlabels(&fctx->domain) > 0);
4444                 dns_name_free(&fctx->domain, fctx->res->mctx);
4445                 if (dns_rdataset_isassociated(&fctx->nameservers))
4446                         dns_rdataset_disassociate(&fctx->nameservers);
4447                 dns_name_init(&fctx->domain, NULL);
4448                 result = dns_name_dup(ns_name, fctx->res->mctx, &fctx->domain);
4449                 if (result != ISC_R_SUCCESS)
4450                         return (result);
4451                 fctx->attributes |= FCTX_ATTR_WANTCACHE;
4452                 return (DNS_R_DELEGATION);
4453         }
4454
4455         /*
4456          * Since we're not doing a referral, we don't want to cache any
4457          * NS RRs we may have found.
4458          */
4459         if (ns_name != NULL)
4460                 ns_name->attributes &= ~DNS_NAMEATTR_CACHE;
4461
4462         if (negative_response && oqname == NULL)
4463                 fctx->attributes |= FCTX_ATTR_WANTNCACHE;
4464
4465         return (ISC_R_SUCCESS);
4466 }
4467
4468 static isc_result_t
4469 answer_response(fetchctx_t *fctx) {
4470         isc_result_t result;
4471         dns_message_t *message;
4472         dns_name_t *name, *qname, tname;
4473         dns_rdataset_t *rdataset;
4474         isc_boolean_t done, external, chaining, aa, found, want_chaining;
4475         isc_boolean_t have_answer, found_cname, found_type, wanted_chaining;
4476         unsigned int aflag;
4477         dns_rdatatype_t type;
4478         dns_fixedname_t dname, fqname;
4479
4480         FCTXTRACE("answer_response");
4481
4482         message = fctx->rmessage;
4483
4484         /*
4485          * Examine the answer section, marking those rdatasets which are
4486          * part of the answer and should be cached.
4487          */
4488
4489         done = ISC_FALSE;
4490         found_cname = ISC_FALSE;
4491         found_type = ISC_FALSE;
4492         chaining = ISC_FALSE;
4493         have_answer = ISC_FALSE;
4494         want_chaining = ISC_FALSE;
4495         if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
4496                 aa = ISC_TRUE;
4497         else
4498                 aa = ISC_FALSE;
4499         qname = &fctx->name;
4500         type = fctx->type;
4501         result = dns_message_firstname(message, DNS_SECTION_ANSWER);
4502         while (!done && result == ISC_R_SUCCESS) {
4503                 name = NULL;
4504                 dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
4505                 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
4506                 if (dns_name_equal(name, qname)) {
4507                         wanted_chaining = ISC_FALSE;
4508                         for (rdataset = ISC_LIST_HEAD(name->list);
4509                              rdataset != NULL;
4510                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
4511                                 found = ISC_FALSE;
4512                                 want_chaining = ISC_FALSE;
4513                                 aflag = 0;
4514                                 if (rdataset->type == type && !found_cname) {
4515                                         /*
4516                                          * We've found an ordinary answer.
4517                                          */
4518                                         found = ISC_TRUE;
4519                                         found_type = ISC_TRUE;
4520                                         done = ISC_TRUE;
4521                                         aflag = DNS_RDATASETATTR_ANSWER;
4522                                 } else if (type == dns_rdatatype_any) {
4523                                         /*
4524                                          * We've found an answer matching
4525                                          * an ANY query.  There may be
4526                                          * more.
4527                                          */
4528                                         found = ISC_TRUE;
4529                                         aflag = DNS_RDATASETATTR_ANSWER;
4530                                 } else if (rdataset->type == dns_rdatatype_rrsig
4531                                            && rdataset->covers == type
4532                                            && !found_cname) {
4533                                         /*
4534                                          * We've found a signature that
4535                                          * covers the type we're looking for.
4536                                          */
4537                                         found = ISC_TRUE;
4538                                         found_type = ISC_TRUE;
4539                                         aflag = DNS_RDATASETATTR_ANSWERSIG;
4540                                 } else if (rdataset->type ==
4541                                            dns_rdatatype_cname
4542                                            && !found_type) {
4543                                         /*
4544                                          * We're looking for something else,
4545                                          * but we found a CNAME.
4546                                          *
4547                                          * Getting a CNAME response for some
4548                                          * query types is an error.
4549                                          */
4550                                         if (type == dns_rdatatype_rrsig ||
4551                                             type == dns_rdatatype_dnskey ||
4552                                             type == dns_rdatatype_nsec)
4553                                                 return (DNS_R_FORMERR);
4554                                         found = ISC_TRUE;
4555                                         found_cname = ISC_TRUE;
4556                                         want_chaining = ISC_TRUE;
4557                                         aflag = DNS_RDATASETATTR_ANSWER;
4558                                         result = cname_target(rdataset,
4559                                                               &tname);
4560                                         if (result != ISC_R_SUCCESS)
4561                                                 return (result);
4562                                 } else if (rdataset->type == dns_rdatatype_rrsig
4563                                            && rdataset->covers ==
4564                                            dns_rdatatype_cname
4565                                            && !found_type) {
4566                                         /*
4567                                          * We're looking for something else,
4568                                          * but we found a SIG CNAME.
4569                                          */
4570                                         found = ISC_TRUE;
4571                                         found_cname = ISC_TRUE;
4572                                         aflag = DNS_RDATASETATTR_ANSWERSIG;
4573                                 }
4574
4575                                 if (found) {
4576                                         /*
4577                                          * We've found an answer to our
4578                                          * question.
4579                                          */
4580                                         name->attributes |=
4581                                                 DNS_NAMEATTR_CACHE;
4582                                         rdataset->attributes |=
4583                                                 DNS_RDATASETATTR_CACHE;
4584                                         rdataset->trust = dns_trust_answer;
4585                                         if (!chaining) {
4586                                                 /*
4587                                                  * This data is "the" answer
4588                                                  * to our question only if
4589                                                  * we're not chaining (i.e.
4590                                                  * if we haven't followed
4591                                                  * a CNAME or DNAME).
4592                                                  */
4593                                                 INSIST(!external);
4594                                                 if (aflag ==
4595                                                     DNS_RDATASETATTR_ANSWER)
4596                                                         have_answer = ISC_TRUE;
4597                                                 name->attributes |=
4598                                                         DNS_NAMEATTR_ANSWER;
4599                                                 rdataset->attributes |= aflag;
4600                                                 if (aa)
4601                                                         rdataset->trust =
4602                                                           dns_trust_authanswer;
4603                                         } else if (external) {
4604                                                 /*
4605                                                  * This data is outside of
4606                                                  * our query domain, and
4607                                                  * may only be cached if it
4608                                                  * comes from a secure zone
4609                                                  * and validates.
4610                                                  */
4611                                                 rdataset->attributes |=
4612                                                     DNS_RDATASETATTR_EXTERNAL;
4613                                         }
4614
4615                                         /*
4616                                          * Mark any additional data related
4617                                          * to this rdataset.
4618                                          */
4619                                         (void)dns_rdataset_additionaldata(
4620                                                         rdataset,
4621                                                         check_related,
4622                                                         fctx);
4623
4624                                         /*
4625                                          * CNAME chaining.
4626                                          */
4627                                         if (want_chaining) {
4628                                                 wanted_chaining = ISC_TRUE;
4629                                                 name->attributes |=
4630                                                         DNS_NAMEATTR_CHAINING;
4631                                                 rdataset->attributes |=
4632                                                     DNS_RDATASETATTR_CHAINING;
4633                                                 qname = &tname;
4634                                         }
4635                                 }
4636                                 /*
4637                                  * We could add an "else" clause here and
4638                                  * log that we're ignoring this rdataset.
4639                                  */
4640                         }
4641                         /*
4642                          * If wanted_chaining is true, we've done
4643                          * some chaining as the result of processing
4644                          * this node, and thus we need to set
4645                          * chaining to true.
4646                          *
4647                          * We don't set chaining inside of the
4648                          * rdataset loop because doing that would
4649                          * cause us to ignore the signatures of
4650                          * CNAMEs.
4651                          */
4652                         if (wanted_chaining)
4653                                 chaining = ISC_TRUE;
4654                 } else {
4655                         /*
4656                          * Look for a DNAME (or its SIG).  Anything else is
4657                          * ignored.
4658                          */
4659                         wanted_chaining = ISC_FALSE;
4660                         for (rdataset = ISC_LIST_HEAD(name->list);
4661                              rdataset != NULL;
4662                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
4663                                 isc_boolean_t found_dname = ISC_FALSE;
4664                                 found = ISC_FALSE;
4665                                 aflag = 0;
4666                                 if (rdataset->type == dns_rdatatype_dname) {
4667                                         /*
4668                                          * We're looking for something else,
4669                                          * but we found a DNAME.
4670                                          *
4671                                          * If we're not chaining, then the
4672                                          * DNAME should not be external.
4673                                          */
4674                                         if (!chaining && external)
4675                                                 return (DNS_R_FORMERR);
4676                                         found = ISC_TRUE;
4677                                         want_chaining = ISC_TRUE;
4678                                         aflag = DNS_RDATASETATTR_ANSWER;
4679                                         result = dname_target(rdataset,
4680                                                               qname, name,
4681                                                               &dname);
4682                                         if (result == ISC_R_NOSPACE) {
4683                                                 /*
4684                                                  * We can't construct the
4685                                                  * DNAME target.  Do not
4686                                                  * try to continue.
4687                                                  */
4688                                                 want_chaining = ISC_FALSE;
4689                                         } else if (result != ISC_R_SUCCESS)
4690                                                 return (result);
4691                                         else
4692                                                 found_dname = ISC_TRUE;
4693                                 } else if (rdataset->type == dns_rdatatype_rrsig
4694                                            && rdataset->covers ==
4695                                            dns_rdatatype_dname) {
4696                                         /*
4697                                          * We've found a signature that
4698                                          * covers the DNAME.
4699                                          */
4700                                         found = ISC_TRUE;
4701                                         aflag = DNS_RDATASETATTR_ANSWERSIG;
4702                                 }
4703
4704                                 if (found) {
4705                                         /*
4706                                          * We've found an answer to our
4707                                          * question.
4708                                          */
4709                                         name->attributes |=
4710                                                 DNS_NAMEATTR_CACHE;
4711                                         rdataset->attributes |=
4712                                                 DNS_RDATASETATTR_CACHE;
4713                                         rdataset->trust = dns_trust_answer;
4714                                         if (!chaining) {
4715                                                 /*
4716                                                  * This data is "the" answer
4717                                                  * to our question only if
4718                                                  * we're not chaining.
4719                                                  */
4720                                                 INSIST(!external);
4721                                                 if (aflag ==
4722                                                     DNS_RDATASETATTR_ANSWER)
4723                                                         have_answer = ISC_TRUE;
4724                                                 name->attributes |=
4725                                                         DNS_NAMEATTR_ANSWER;
4726                                                 rdataset->attributes |= aflag;
4727                                                 if (aa)
4728                                                         rdataset->trust =
4729                                                           dns_trust_authanswer;
4730                                         } else if (external) {
4731                                                 rdataset->attributes |=
4732                                                     DNS_RDATASETATTR_EXTERNAL;
4733                                         }
4734
4735                                         /*
4736                                          * DNAME chaining.
4737                                          */
4738                                         if (found_dname) {
4739                                                 /*
4740                                                  * Copy the the dname into the
4741                                                  * qname fixed name.
4742                                                  *
4743                                                  * Although we check for
4744                                                  * failure of the copy
4745                                                  * operation, in practice it
4746                                                  * should never fail since
4747                                                  * we already know that the
4748                                                  * result fits in a fixedname.
4749                                                  */
4750                                                 dns_fixedname_init(&fqname);
4751                                                 result = dns_name_copy(
4752                                                   dns_fixedname_name(&dname),
4753                                                   dns_fixedname_name(&fqname),
4754                                                   NULL);
4755                                                 if (result != ISC_R_SUCCESS)
4756                                                         return (result);
4757                                                 wanted_chaining = ISC_TRUE;
4758                                                 name->attributes |=
4759                                                         DNS_NAMEATTR_CHAINING;
4760                                                 rdataset->attributes |=
4761                                                     DNS_RDATASETATTR_CHAINING;
4762                                                 qname = dns_fixedname_name(
4763                                                                    &fqname);
4764                                         }
4765                                 }
4766                         }
4767                         if (wanted_chaining)
4768                                 chaining = ISC_TRUE;
4769                 }
4770                 result = dns_message_nextname(message, DNS_SECTION_ANSWER);
4771         }
4772         if (result == ISC_R_NOMORE)
4773                 result = ISC_R_SUCCESS;
4774         if (result != ISC_R_SUCCESS)
4775                 return (result);
4776
4777         /*
4778          * We should have found an answer.
4779          */
4780         if (!have_answer)
4781                 return (DNS_R_FORMERR);
4782
4783         /*
4784          * This response is now potentially cacheable.
4785          */
4786         fctx->attributes |= FCTX_ATTR_WANTCACHE;
4787
4788         /*
4789          * Did chaining end before we got the final answer?
4790          */
4791         if (chaining) {
4792                 /*
4793                  * Yes.  This may be a negative reply, so hand off
4794                  * authority section processing to the noanswer code.
4795                  * If it isn't a noanswer response, no harm will be
4796                  * done.
4797                  */
4798                 return (noanswer_response(fctx, qname, ISC_FALSE));
4799         }
4800
4801         /*
4802          * We didn't end with an incomplete chain, so the rcode should be
4803          * "no error".
4804          */
4805         if (message->rcode != dns_rcode_noerror)
4806                 return (DNS_R_FORMERR);
4807
4808         /*
4809          * Examine the authority section (if there is one).
4810          *
4811          * We expect there to be only one owner name for all the rdatasets
4812          * in this section, and we expect that it is not external.
4813          */
4814         done = ISC_FALSE;
4815         result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
4816         while (!done && result == ISC_R_SUCCESS) {
4817                 name = NULL;
4818                 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
4819                 external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
4820                 if (!external) {
4821                         /*
4822                          * We expect to find NS or SIG NS rdatasets, and
4823                          * nothing else.
4824                          */
4825                         for (rdataset = ISC_LIST_HEAD(name->list);
4826                              rdataset != NULL;
4827                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
4828                                 if (rdataset->type == dns_rdatatype_ns ||
4829                                     (rdataset->type == dns_rdatatype_rrsig &&
4830                                      rdataset->covers == dns_rdatatype_ns)) {
4831                                         name->attributes |=
4832                                                 DNS_NAMEATTR_CACHE;
4833                                         rdataset->attributes |=
4834                                                 DNS_RDATASETATTR_CACHE;
4835                                         if (aa && !chaining)
4836                                                 rdataset->trust =
4837                                                     dns_trust_authauthority;
4838                                         else
4839                                                 rdataset->trust =
4840                                                     dns_trust_additional;
4841
4842                                         /*
4843                                          * Mark any additional data related
4844                                          * to this rdataset.
4845                                          */
4846                                         (void)dns_rdataset_additionaldata(
4847                                                         rdataset,
4848                                                         check_related,
4849                                                         fctx);
4850                                         done = ISC_TRUE;
4851                                 }
4852                         }
4853                 }
4854                 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
4855         }
4856         if (result == ISC_R_NOMORE)
4857                 result = ISC_R_SUCCESS;
4858
4859         return (result);
4860 }
4861
4862 static void
4863 resume_dslookup(isc_task_t *task, isc_event_t *event) {
4864         dns_fetchevent_t *fevent;
4865         dns_resolver_t *res;
4866         fetchctx_t *fctx;
4867         isc_result_t result;
4868         isc_boolean_t bucket_empty = ISC_FALSE;
4869         isc_boolean_t locked = ISC_FALSE;
4870         unsigned int bucketnum;
4871         dns_rdataset_t nameservers;
4872         dns_fixedname_t fixed;
4873         dns_name_t *domain;
4874
4875         REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
4876         fevent = (dns_fetchevent_t *)event;
4877         fctx = event->ev_arg;
4878         REQUIRE(VALID_FCTX(fctx));
4879         res = fctx->res;
4880
4881         UNUSED(task);
4882         FCTXTRACE("resume_dslookup");
4883
4884         if (fevent->node != NULL)
4885                 dns_db_detachnode(fevent->db, &fevent->node);
4886         if (fevent->db != NULL)
4887                 dns_db_detach(&fevent->db);
4888
4889         dns_rdataset_init(&nameservers);
4890
4891         bucketnum = fctx->bucketnum;
4892         if (fevent->result == ISC_R_CANCELED) {
4893                 dns_resolver_destroyfetch(&fctx->nsfetch);
4894                 fctx_done(fctx, ISC_R_CANCELED);
4895         } else if (fevent->result == ISC_R_SUCCESS) {
4896
4897                 FCTXTRACE("resuming DS lookup");
4898
4899                 dns_resolver_destroyfetch(&fctx->nsfetch);
4900                 if (dns_rdataset_isassociated(&fctx->nameservers))
4901                         dns_rdataset_disassociate(&fctx->nameservers);
4902                 dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
4903                 dns_name_free(&fctx->domain, fctx->res->mctx);
4904                 dns_name_init(&fctx->domain, NULL);
4905                 result = dns_name_dup(&fctx->nsname, fctx->res->mctx,
4906                                       &fctx->domain);
4907                 if (result != ISC_R_SUCCESS) {
4908                         fctx_done(fctx, DNS_R_SERVFAIL);
4909                         goto cleanup;
4910                 }
4911                 /*
4912                  * Try again.
4913                  */
4914                 fctx_try(fctx);
4915         } else {
4916                 unsigned int n;
4917
4918                 /*
4919                  * Retrieve state from fctx->nsfetch before we destroy it.
4920                  */
4921                 dns_fixedname_init(&fixed);
4922                 domain = dns_fixedname_name(&fixed);
4923                 dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL);
4924                 dns_rdataset_clone(&fctx->nsfetch->private->nameservers,
4925                                    &nameservers);
4926                 dns_resolver_destroyfetch(&fctx->nsfetch);
4927                 if (dns_name_equal(&fctx->nsname, domain)) {
4928                         fctx_done(fctx, DNS_R_SERVFAIL);
4929                         goto cleanup;
4930                 }
4931                 n = dns_name_countlabels(&fctx->nsname);
4932                 dns_name_getlabelsequence(&fctx->nsname, 1, n - 1,
4933                                           &fctx->nsname);
4934
4935                 if (dns_rdataset_isassociated(fevent->rdataset))
4936                         dns_rdataset_disassociate(fevent->rdataset);
4937                 FCTXTRACE("continuing to look for parent's NS records");
4938                 result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
4939                                                   dns_rdatatype_ns, domain,
4940                                                   &nameservers, NULL, 0, task,
4941                                                   resume_dslookup, fctx,
4942                                                   &fctx->nsrrset, NULL,
4943                                                   &fctx->nsfetch);
4944                 if (result != ISC_R_SUCCESS)
4945                         fctx_done(fctx, result);
4946                 else {
4947                         LOCK(&res->buckets[bucketnum].lock);
4948                         locked = ISC_TRUE;
4949                         fctx->references++;
4950                 }
4951         }
4952
4953  cleanup:
4954         if (dns_rdataset_isassociated(&nameservers))
4955                 dns_rdataset_disassociate(&nameservers);
4956         if (dns_rdataset_isassociated(fevent->rdataset))
4957                 dns_rdataset_disassociate(fevent->rdataset);
4958         INSIST(fevent->sigrdataset == NULL);
4959         isc_event_free(&event);
4960         if (!locked)
4961                 LOCK(&res->buckets[bucketnum].lock);
4962         fctx->references--;
4963         if (fctx->references == 0)
4964                 bucket_empty = fctx_destroy(fctx);
4965         UNLOCK(&res->buckets[bucketnum].lock);
4966         if (bucket_empty)
4967                 empty_bucket(res);
4968 }
4969
4970 static inline void
4971 checknamessection(dns_message_t *message, dns_section_t section) {
4972         isc_result_t result;
4973         dns_name_t *name;
4974         dns_rdata_t rdata = DNS_RDATA_INIT;
4975         dns_rdataset_t *rdataset;
4976         
4977         for (result = dns_message_firstname(message, section);
4978              result == ISC_R_SUCCESS;
4979              result = dns_message_nextname(message, section))
4980         {
4981                 name = NULL;
4982                 dns_message_currentname(message, section, &name);
4983                 for (rdataset = ISC_LIST_HEAD(name->list);
4984                      rdataset != NULL;
4985                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
4986                         for (result = dns_rdataset_first(rdataset);
4987                              result == ISC_R_SUCCESS;
4988                              result = dns_rdataset_next(rdataset)) {
4989                                 dns_rdataset_current(rdataset, &rdata);
4990                                 if (!dns_rdata_checkowner(name, rdata.rdclass,
4991                                                           rdata.type,
4992                                                           ISC_FALSE) ||
4993                                     !dns_rdata_checknames(&rdata, name, NULL))
4994                                 {
4995                                         rdataset->attributes |= 
4996                                                 DNS_RDATASETATTR_CHECKNAMES;
4997                                 }
4998                                 dns_rdata_reset(&rdata);
4999                         }
5000                 }
5001         }
5002 }
5003
5004 static void
5005 checknames(dns_message_t *message) {
5006
5007         checknamessection(message, DNS_SECTION_ANSWER);
5008         checknamessection(message, DNS_SECTION_AUTHORITY);
5009         checknamessection(message, DNS_SECTION_ADDITIONAL);
5010 }
5011
5012 static void
5013 log_packet(dns_message_t *message, int level, isc_mem_t *mctx) {
5014         isc_buffer_t buffer;
5015         char *buf = NULL;
5016         int len = 1024;
5017         isc_result_t result;
5018
5019         if (! isc_log_wouldlog(dns_lctx, level))
5020                 return;
5021
5022         /*
5023          * Note that these are multiline debug messages.  We want a newline
5024          * to appear in the log after each message.
5025          */
5026
5027         do {
5028                 buf = isc_mem_get(mctx, len);
5029                 if (buf == NULL)
5030                         break;
5031                 isc_buffer_init(&buffer, buf, len);
5032                 result = dns_message_totext(message, &dns_master_style_debug,
5033                                             0, &buffer);
5034                 if (result == ISC_R_NOSPACE) {
5035                         isc_mem_put(mctx, buf, len);
5036                         len += 1024;
5037                 } else if (result == ISC_R_SUCCESS)
5038                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
5039                                       DNS_LOGMODULE_RESOLVER, level,
5040                                       "received packet:\n%.*s",
5041                                       (int)isc_buffer_usedlength(&buffer),
5042                                       buf);
5043         } while (result == ISC_R_NOSPACE);
5044
5045         if (buf != NULL)
5046                 isc_mem_put(mctx, buf, len);
5047 }
5048
5049 static void
5050 resquery_response(isc_task_t *task, isc_event_t *event) {
5051         isc_result_t result = ISC_R_SUCCESS;
5052         resquery_t *query = event->ev_arg;
5053         dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
5054         isc_boolean_t keep_trying, get_nameservers, resend;
5055         isc_boolean_t truncated;
5056         dns_message_t *message;
5057         fetchctx_t *fctx;
5058         dns_name_t *fname;
5059         dns_fixedname_t foundname;
5060         isc_stdtime_t now;
5061         isc_time_t tnow, *finish;
5062         dns_adbaddrinfo_t *addrinfo;
5063         unsigned int options;
5064         unsigned int findoptions;
5065         isc_result_t broken_server;
5066
5067         REQUIRE(VALID_QUERY(query));
5068         fctx = query->fctx;
5069         options = query->options;
5070         REQUIRE(VALID_FCTX(fctx));
5071         REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
5072
5073         QTRACE("response");
5074
5075         (void)isc_timer_touch(fctx->timer);
5076
5077         keep_trying = ISC_FALSE;
5078         broken_server = ISC_R_SUCCESS;
5079         get_nameservers = ISC_FALSE;
5080         resend = ISC_FALSE;
5081         truncated = ISC_FALSE;
5082         finish = NULL;
5083
5084         if (fctx->res->exiting) {
5085                 result = ISC_R_SHUTTINGDOWN;
5086                 goto done;
5087         }
5088
5089         fctx->timeouts = 0;
5090
5091         /*
5092          * XXXRTH  We should really get the current time just once.  We
5093          *         need a routine to convert from an isc_time_t to an
5094          *         isc_stdtime_t.
5095          */
5096         TIME_NOW(&tnow);
5097         finish = &tnow;
5098         isc_stdtime_get(&now);
5099
5100         /*
5101          * Did the dispatcher have a problem?
5102          */
5103         if (devent->result != ISC_R_SUCCESS) {
5104                 if (devent->result == ISC_R_EOF &&
5105                     (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
5106                         /*
5107                          * The problem might be that they
5108                          * don't understand EDNS0.  Turn it
5109                          * off and try again.
5110                          */
5111                         options |= DNS_FETCHOPT_NOEDNS0;
5112                         resend = ISC_TRUE;
5113                         /*
5114                          * Remember that they don't like EDNS0.
5115                          */
5116                         dns_adb_changeflags(fctx->adb,
5117                                             query->addrinfo,
5118                                             DNS_FETCHOPT_NOEDNS0,
5119                                             DNS_FETCHOPT_NOEDNS0);
5120                 } else {
5121                         /*
5122                          * There's no hope for this query.
5123                          */
5124                         keep_trying = ISC_TRUE;
5125                 }
5126                 goto done;
5127         }
5128
5129         message = fctx->rmessage;
5130
5131         if (query->tsig != NULL) {
5132                 result = dns_message_setquerytsig(message, query->tsig);
5133                 if (result != ISC_R_SUCCESS)
5134                         goto done;
5135         }
5136
5137         if (query->tsigkey) {
5138                 result = dns_message_settsigkey(message, query->tsigkey);
5139                 if (result != ISC_R_SUCCESS)
5140                         goto done;
5141         }
5142
5143         result = dns_message_parse(message, &devent->buffer, 0);
5144         if (result != ISC_R_SUCCESS) {
5145                 switch (result) {
5146                 case ISC_R_UNEXPECTEDEND:
5147                         if (!message->question_ok ||
5148                             (message->flags & DNS_MESSAGEFLAG_TC) == 0 ||
5149                             (options & DNS_FETCHOPT_TCP) != 0) {
5150                                 /*
5151                                  * Either the message ended prematurely,
5152                                  * and/or wasn't marked as being truncated,
5153                                  * and/or this is a response to a query we
5154                                  * sent over TCP.  In all of these cases,
5155                                  * something is wrong with the remote
5156                                  * server and we don't want to retry using
5157                                  * TCP.
5158                                  */
5159                                 if ((query->options & DNS_FETCHOPT_NOEDNS0)
5160                                     == 0) {
5161                                         /*
5162                                          * The problem might be that they
5163                                          * don't understand EDNS0.  Turn it
5164                                          * off and try again.
5165                                          */
5166                                         options |= DNS_FETCHOPT_NOEDNS0;
5167                                         resend = ISC_TRUE;
5168                                         /*
5169                                          * Remember that they don't like EDNS0.
5170                                          */
5171                                         dns_adb_changeflags(
5172                                                         fctx->adb,
5173                                                         query->addrinfo,
5174                                                         DNS_FETCHOPT_NOEDNS0,
5175                                                         DNS_FETCHOPT_NOEDNS0);
5176                                 } else {
5177                                         broken_server = result;
5178                                         keep_trying = ISC_TRUE;
5179                                 }
5180                                 goto done;
5181                         }
5182                         /*
5183                          * We defer retrying via TCP for a bit so we can
5184                          * check out this message further.
5185                          */
5186                         truncated = ISC_TRUE;
5187                         break;
5188                 case DNS_R_FORMERR:
5189                         if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
5190                                 /*
5191                                  * The problem might be that they
5192                                  * don't understand EDNS0.  Turn it
5193                                  * off and try again.
5194                                  */
5195                                 options |= DNS_FETCHOPT_NOEDNS0;
5196                                 resend = ISC_TRUE;
5197                                 /*
5198                                  * Remember that they don't like EDNS0.
5199                                  */
5200                                 dns_adb_changeflags(fctx->adb,
5201                                                     query->addrinfo,
5202                                                     DNS_FETCHOPT_NOEDNS0,
5203                                                     DNS_FETCHOPT_NOEDNS0);
5204                         } else {
5205                                 broken_server = DNS_R_UNEXPECTEDRCODE;
5206                                 keep_trying = ISC_TRUE;
5207                         }
5208                         goto done;
5209                 default:
5210                         /*
5211                          * Something bad has happened.
5212                          */
5213                         goto done;
5214                 }
5215         }
5216
5217         /*
5218          * Log the incoming packet.
5219          */
5220         log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx);
5221
5222         /*
5223          * If the message is signed, check the signature.  If not, this
5224          * returns success anyway.
5225          */
5226         result = dns_message_checksig(message, fctx->res->view);
5227         if (result != ISC_R_SUCCESS)
5228                 goto done;
5229
5230         /*
5231          * The dispatcher should ensure we only get responses with QR set.
5232          */
5233         INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0);
5234         /*
5235          * INSIST() that the message comes from the place we sent it to,
5236          * since the dispatch code should ensure this.
5237          *
5238          * INSIST() that the message id is correct (this should also be
5239          * ensured by the dispatch code).
5240          */
5241
5242
5243         /*
5244          * Deal with truncated responses by retrying using TCP.
5245          */
5246         if ((message->flags & DNS_MESSAGEFLAG_TC) != 0)
5247                 truncated = ISC_TRUE;
5248
5249         if (truncated) {
5250                 if ((options & DNS_FETCHOPT_TCP) != 0) {
5251                         broken_server = DNS_R_TRUNCATEDTCP;
5252                         keep_trying = ISC_TRUE;
5253                 } else {
5254                         options |= DNS_FETCHOPT_TCP;
5255                         resend = ISC_TRUE;
5256                 }
5257                 goto done;
5258         }
5259
5260         /*
5261          * Is it a query response?
5262          */
5263         if (message->opcode != dns_opcode_query) {
5264                 /* XXXRTH Log */
5265                 broken_server = DNS_R_UNEXPECTEDOPCODE;
5266                 keep_trying = ISC_TRUE;
5267                 goto done;
5268         }
5269
5270         /*
5271          * Is the remote server broken, or does it dislike us?
5272          */
5273         if (message->rcode != dns_rcode_noerror &&
5274             message->rcode != dns_rcode_nxdomain) {
5275                 if ((message->rcode == dns_rcode_formerr ||
5276                      message->rcode == dns_rcode_notimp ||
5277                      message->rcode == dns_rcode_servfail) &&
5278                     (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
5279                         /*
5280                          * It's very likely they don't like EDNS0.
5281                          *
5282                          * XXXRTH  We should check if the question
5283                          *         we're asking requires EDNS0, and
5284                          *         if so, we should bail out.
5285                          */
5286                         options |= DNS_FETCHOPT_NOEDNS0;
5287                         resend = ISC_TRUE;
5288                         /*
5289                          * Remember that they don't like EDNS0.
5290                          */
5291                         if (message->rcode != dns_rcode_servfail)
5292                                 dns_adb_changeflags(fctx->adb, query->addrinfo,
5293                                                     DNS_FETCHOPT_NOEDNS0,
5294                                                     DNS_FETCHOPT_NOEDNS0);
5295                 } else if (message->rcode == dns_rcode_formerr) {
5296                         if (ISFORWARDER(query->addrinfo)) {
5297                                 /*
5298                                  * This forwarder doesn't understand us,
5299                                  * but other forwarders might.  Keep trying.
5300                                  */
5301                                 broken_server = DNS_R_REMOTEFORMERR;
5302                                 keep_trying = ISC_TRUE;
5303                         } else {
5304                                 /*
5305                                  * The server doesn't understand us.  Since
5306                                  * all servers for a zone need similar
5307                                  * capabilities, we assume that we will get
5308                                  * FORMERR from all servers, and thus we
5309                                  * cannot make any more progress with this
5310                                  * fetch.
5311                                  */
5312                                 result = DNS_R_FORMERR;
5313                         }
5314                 } else if (message->rcode == dns_rcode_yxdomain) {
5315                         /*
5316                          * DNAME mapping failed because the new name
5317                          * was too long.  There's no chance of success
5318                          * for this fetch.
5319                          */
5320                         result = DNS_R_YXDOMAIN;
5321                 } else {
5322                         /*
5323                          * XXXRTH log.
5324                          */
5325                         broken_server = DNS_R_UNEXPECTEDRCODE;
5326                         INSIST(broken_server != ISC_R_SUCCESS);
5327                         keep_trying = ISC_TRUE;
5328                 }
5329                 goto done;
5330         }
5331
5332         /*
5333          * Is the question the same as the one we asked?
5334          */
5335         result = same_question(fctx);
5336         if (result != ISC_R_SUCCESS) {
5337                 /* XXXRTH Log */
5338                 if (result == DNS_R_FORMERR)
5339                         keep_trying = ISC_TRUE;
5340                 goto done;
5341         }
5342
5343         /*
5344          * Is the server lame?
5345          */
5346         if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) &&
5347             is_lame(fctx)) {
5348                 log_lame(fctx, query->addrinfo);
5349                 result = dns_adb_marklame(fctx->adb, query->addrinfo,
5350                                           &fctx->domain,
5351                                           now + fctx->res->lame_ttl);
5352                 if (result != ISC_R_SUCCESS)
5353                         isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
5354                                       DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
5355                                       "could not mark server as lame: %s",
5356                                       isc_result_totext(result));
5357                 broken_server = DNS_R_LAME;
5358                 keep_trying = ISC_TRUE;
5359                 goto done;
5360         }
5361
5362         /*
5363          * Enforce delegations only zones like NET and COM.
5364          */
5365         if (!ISFORWARDER(query->addrinfo) &&
5366             dns_view_isdelegationonly(fctx->res->view, &fctx->domain) &&
5367             !dns_name_equal(&fctx->domain, &fctx->name) &&
5368             fix_mustbedelegationornxdomain(message, fctx)) {
5369                 char namebuf[DNS_NAME_FORMATSIZE];
5370                 char domainbuf[DNS_NAME_FORMATSIZE];
5371                 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
5372                 char classbuf[64];
5373                 char typebuf[64];
5374
5375                 dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
5376                 dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
5377                 dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
5378                 dns_rdataclass_format(fctx->res->rdclass, classbuf,
5379                                       sizeof(classbuf));
5380                 isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
5381                                     sizeof(addrbuf));
5382
5383                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY,
5384                              DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
5385                              "enforced delegation-only for '%s' (%s/%s/%s) "
5386                              "from %s",
5387                              domainbuf, namebuf, typebuf, classbuf, addrbuf);
5388         }
5389
5390         if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0)
5391                 checknames(message);
5392
5393         /*
5394          * Clear cache bits.
5395          */
5396         fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE);
5397
5398         /*
5399          * Did we get any answers?
5400          */
5401         if (message->counts[DNS_SECTION_ANSWER] > 0 &&
5402             (message->rcode == dns_rcode_noerror ||
5403              message->rcode == dns_rcode_nxdomain)) {
5404                 /*
5405                  * We've got answers.  However, if we sent
5406                  * a BIND 8 server an NS query, it may have
5407                  * incorrectly responded with a non-authoritative
5408                  * answer instead of a referral.  Since this
5409                  * answer lacks the SIGs necessary to do DNSSEC
5410                  * validation, we must invoke the following special
5411                  * kludge to treat it as a referral.
5412                  */
5413                 if (fctx->type == dns_rdatatype_ns &&
5414                     (message->flags & DNS_MESSAGEFLAG_AA) == 0 &&
5415                     !ISFORWARDER(query->addrinfo))
5416                 {
5417                         result = noanswer_response(fctx, NULL, ISC_TRUE);
5418                         if (result != DNS_R_DELEGATION) {
5419                                 /*
5420                                  * The answer section must have contained
5421                                  * something other than the NS records
5422                                  * we asked for.  Since AA is not set
5423                                  * and the server is not a forwarder,
5424                                  * it is technically lame and it's easier
5425                                  * to treat it as such than to figure out
5426                                  * some more elaborate course of action.
5427                                  */
5428                                 broken_server = DNS_R_LAME;
5429                                 keep_trying = ISC_TRUE;
5430                                 goto done;
5431                         }
5432                         goto force_referral;
5433                 }
5434                 result = answer_response(fctx);
5435                 if (result != ISC_R_SUCCESS) {
5436                         if (result == DNS_R_FORMERR)
5437                                 keep_trying = ISC_TRUE;
5438                         goto done;
5439                 }
5440         } else if (message->counts[DNS_SECTION_AUTHORITY] > 0 ||
5441                    message->rcode == dns_rcode_noerror ||
5442                    message->rcode == dns_rcode_nxdomain) {
5443                 /*
5444                  * NXDOMAIN, NXRDATASET, or referral.
5445                  */
5446                 result = noanswer_response(fctx, NULL, ISC_FALSE);
5447                 if (result == DNS_R_CHASEDSSERVERS) {
5448                 } else if (result == DNS_R_DELEGATION) {
5449                 force_referral:
5450                         /*
5451                          * We don't have the answer, but we know a better
5452                          * place to look.
5453                          */
5454                         get_nameservers = ISC_TRUE;
5455                         keep_trying = ISC_TRUE;
5456                         /*
5457                          * We have a new set of name servers, and it
5458                          * has not experienced any restarts yet.
5459                          */
5460                         fctx->restarts = 0;
5461                         result = ISC_R_SUCCESS;
5462                 } else if (result != ISC_R_SUCCESS) {
5463                         /*
5464                          * Something has gone wrong.
5465                          */
5466                         if (result == DNS_R_FORMERR)
5467                                 keep_trying = ISC_TRUE;
5468                         goto done;
5469                 }
5470         } else {
5471                 /*
5472                  * The server is insane.
5473                  */
5474                 /* XXXRTH Log */
5475                 broken_server = DNS_R_UNEXPECTEDRCODE;
5476                 keep_trying = ISC_TRUE;
5477                 goto done;
5478         }
5479
5480         /*
5481          * Follow additional section data chains.
5482          */
5483         chase_additional(fctx);
5484
5485         /*
5486          * Cache the cacheable parts of the message.  This may also cause
5487          * work to be queued to the DNSSEC validator.
5488          */
5489         if (WANTCACHE(fctx)) {
5490                 result = cache_message(fctx, query->addrinfo, now);
5491                 if (result != ISC_R_SUCCESS)
5492                         goto done;
5493         }
5494
5495         /*
5496          * Ncache the negatively cacheable parts of the message.  This may
5497          * also cause work to be queued to the DNSSEC validator.
5498          */
5499         if (WANTNCACHE(fctx)) {
5500                 dns_rdatatype_t covers;
5501                 if (message->rcode == dns_rcode_nxdomain)
5502                         covers = dns_rdatatype_any;
5503                 else
5504                         covers = fctx->type;
5505
5506                 /*
5507                  * Cache any negative cache entries in the message.
5508                  */
5509                 result = ncache_message(fctx, query->addrinfo, covers, now);
5510         }
5511
5512  done:
5513         /*
5514          * Remember the query's addrinfo, in case we need to mark the
5515          * server as broken.
5516          */
5517         addrinfo = query->addrinfo;
5518
5519         /*
5520          * Cancel the query.
5521          *
5522          * XXXRTH  Don't cancel the query if waiting for validation?
5523          */
5524         fctx_cancelquery(&query, &devent, finish, ISC_FALSE);
5525
5526         if (keep_trying) {
5527                 if (result == DNS_R_FORMERR)
5528                         broken_server = DNS_R_FORMERR;
5529                 if (broken_server != ISC_R_SUCCESS) {
5530                         /*
5531                          * Add this server to the list of bad servers for
5532                          * this fctx.
5533                          */
5534                         add_bad(fctx, &addrinfo->sockaddr, broken_server);
5535                 }
5536
5537                 if (get_nameservers) {
5538                         dns_name_t *name;
5539                         dns_fixedname_init(&foundname);
5540                         fname = dns_fixedname_name(&foundname);
5541                         if (result != ISC_R_SUCCESS) {
5542                                 fctx_done(fctx, DNS_R_SERVFAIL);
5543                                 return;
5544                         }
5545                         findoptions = 0;
5546                         if (dns_rdatatype_atparent(fctx->type))
5547                                 findoptions |= DNS_DBFIND_NOEXACT;
5548                         if ((options & DNS_FETCHOPT_UNSHARED) == 0)
5549                                 name = &fctx->name;
5550                         else
5551                                 name = &fctx->domain;
5552                         result = dns_view_findzonecut(fctx->res->view,
5553                                                       name, fname,
5554                                                       now, findoptions,
5555                                                       ISC_TRUE,
5556                                                       &fctx->nameservers,
5557                                                       NULL);
5558                         if (result != ISC_R_SUCCESS) {
5559                                 FCTXTRACE("couldn't find a zonecut");
5560                                 fctx_done(fctx, DNS_R_SERVFAIL);
5561                                 return;
5562                         }
5563                         if (!dns_name_issubdomain(fname, &fctx->domain)) {
5564                                 /*
5565                                  * The best nameservers are now above our
5566                                  * QDOMAIN.
5567                                  */
5568                                 FCTXTRACE("nameservers now above QDOMAIN");
5569                                 fctx_done(fctx, DNS_R_SERVFAIL);
5570                                 return;
5571                         }
5572                         dns_name_free(&fctx->domain, fctx->res->mctx);
5573                         dns_name_init(&fctx->domain, NULL);
5574                         result = dns_name_dup(fname, fctx->res->mctx,
5575                                               &fctx->domain);
5576                         if (result != ISC_R_SUCCESS) {
5577                                 fctx_done(fctx, DNS_R_SERVFAIL);
5578                                 return;
5579                         }
5580                         fctx_cancelqueries(fctx, ISC_TRUE);
5581                         fctx_cleanupfinds(fctx);
5582                         fctx_cleanupaltfinds(fctx);
5583                         fctx_cleanupforwaddrs(fctx);
5584                         fctx_cleanupaltaddrs(fctx);
5585                 }
5586                 /*
5587                  * Try again.
5588                  */
5589                 fctx_try(fctx);
5590         } else if (resend) {
5591                 /*
5592                  * Resend (probably with changed options).
5593                  */
5594                 FCTXTRACE("resend");
5595                 result = fctx_query(fctx, addrinfo, options);
5596                 if (result != ISC_R_SUCCESS)
5597                         fctx_done(fctx, result);
5598         } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) {
5599                 /*
5600                  * All has gone well so far, but we are waiting for the
5601                  * DNSSEC validator to validate the answer.
5602                  */
5603                 FCTXTRACE("wait for validator");
5604                 fctx_cancelqueries(fctx, ISC_TRUE);
5605                 /*
5606                  * We must not retransmit while the validator is working;
5607                  * it has references to the current rmessage.
5608                  */
5609                 result = fctx_stopidletimer(fctx);
5610                 if (result != ISC_R_SUCCESS)
5611                         fctx_done(fctx, result);
5612         } else if (result == DNS_R_CHASEDSSERVERS) {
5613                 unsigned int n;
5614                 add_bad(fctx, &addrinfo->sockaddr, result);
5615                 fctx_cancelqueries(fctx, ISC_TRUE);
5616                 fctx_cleanupfinds(fctx);
5617                 fctx_cleanupforwaddrs(fctx);
5618
5619                 n = dns_name_countlabels(&fctx->name);
5620                 dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname);
5621
5622                 FCTXTRACE("suspending DS lookup to find parent's NS records");
5623
5624                 result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
5625                                                   dns_rdatatype_ns,
5626                                                   NULL, NULL, NULL, 0, task,
5627                                                   resume_dslookup, fctx,
5628                                                   &fctx->nsrrset, NULL,
5629                                                   &fctx->nsfetch);
5630                 if (result != ISC_R_SUCCESS)
5631                         fctx_done(fctx, result);
5632                 LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
5633                 fctx->references++;
5634                 UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
5635                 result = fctx_stopidletimer(fctx);
5636                 if (result != ISC_R_SUCCESS)
5637                         fctx_done(fctx, result);
5638         } else {
5639                 /*
5640                  * We're done.
5641                  */
5642                 fctx_done(fctx, result);
5643         }
5644 }
5645
5646
5647 /***
5648  *** Resolver Methods
5649  ***/
5650
5651 static void
5652 destroy(dns_resolver_t *res) {
5653         unsigned int i;
5654         alternate_t *a;
5655
5656         REQUIRE(res->references == 0);
5657         REQUIRE(!res->priming);
5658         REQUIRE(res->primefetch == NULL);
5659
5660         RTRACE("destroy");
5661
5662         INSIST(res->nfctx == 0);
5663
5664         DESTROYLOCK(&res->primelock);
5665         DESTROYLOCK(&res->nlock);
5666         DESTROYLOCK(&res->lock);
5667         for (i = 0; i < res->nbuckets; i++) {
5668                 INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
5669                 isc_task_shutdown(res->buckets[i].task);
5670                 isc_task_detach(&res->buckets[i].task);
5671                 DESTROYLOCK(&res->buckets[i].lock);
5672         }
5673         isc_mem_put(res->mctx, res->buckets,
5674                     res->nbuckets * sizeof(fctxbucket_t));
5675         if (res->dispatchv4 != NULL)
5676                 dns_dispatch_detach(&res->dispatchv4);
5677         if (res->dispatchv6 != NULL)
5678                 dns_dispatch_detach(&res->dispatchv6);
5679         while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) {
5680                 ISC_LIST_UNLINK(res->alternates, a, link);
5681                 if (!a->isaddress)
5682                         dns_name_free(&a->_u._n.name, res->mctx);
5683                 isc_mem_put(res->mctx, a, sizeof(*a));
5684         }
5685         dns_resolver_reset_algorithms(res);
5686         dns_resolver_resetmustbesecure(res);
5687 #if USE_ALGLOCK
5688         isc_rwlock_destroy(&res->alglock);
5689 #endif
5690 #if USE_MBSLOCK
5691         isc_rwlock_destroy(&res->mbslock);
5692 #endif
5693         res->magic = 0;
5694         isc_mem_put(res->mctx, res, sizeof(*res));
5695 }
5696
5697 static void
5698 send_shutdown_events(dns_resolver_t *res) {
5699         isc_event_t *event, *next_event;
5700         isc_task_t *etask;
5701
5702         /*
5703          * Caller must be holding the resolver lock.
5704          */
5705
5706         for (event = ISC_LIST_HEAD(res->whenshutdown);
5707              event != NULL;
5708              event = next_event) {
5709                 next_event = ISC_LIST_NEXT(event, ev_link);
5710                 ISC_LIST_UNLINK(res->whenshutdown, event, ev_link);
5711                 etask = event->ev_sender;
5712                 event->ev_sender = res;
5713                 isc_task_sendanddetach(&etask, &event);
5714         }
5715 }
5716
5717 static void
5718 empty_bucket(dns_resolver_t *res) {
5719         RTRACE("empty_bucket");
5720
5721         LOCK(&res->lock);
5722
5723         INSIST(res->activebuckets > 0);
5724         res->activebuckets--;
5725         if (res->activebuckets == 0)
5726                 send_shutdown_events(res);
5727
5728         UNLOCK(&res->lock);
5729 }
5730
5731 isc_result_t
5732 dns_resolver_create(dns_view_t *view,
5733                     isc_taskmgr_t *taskmgr, unsigned int ntasks,
5734                     isc_socketmgr_t *socketmgr,
5735                     isc_timermgr_t *timermgr,
5736                     unsigned int options,
5737                     dns_dispatchmgr_t *dispatchmgr,
5738                     dns_dispatch_t *dispatchv4,
5739                     dns_dispatch_t *dispatchv6,
5740                     dns_resolver_t **resp)
5741 {
5742         dns_resolver_t *res;
5743         isc_result_t result = ISC_R_SUCCESS;
5744         unsigned int i, buckets_created = 0;
5745         char name[16];
5746
5747         /*
5748          * Create a resolver.
5749          */
5750
5751         REQUIRE(DNS_VIEW_VALID(view));
5752         REQUIRE(ntasks > 0);
5753         REQUIRE(resp != NULL && *resp == NULL);
5754         REQUIRE(dispatchmgr != NULL);
5755         REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL);
5756
5757         res = isc_mem_get(view->mctx, sizeof(*res));
5758         if (res == NULL)
5759                 return (ISC_R_NOMEMORY);
5760         RTRACE("create");
5761         res->mctx = view->mctx;
5762         res->rdclass = view->rdclass;
5763         res->socketmgr = socketmgr;
5764         res->timermgr = timermgr;
5765         res->taskmgr = taskmgr;
5766         res->dispatchmgr = dispatchmgr;
5767         res->view = view;
5768         res->options = options;
5769         res->lame_ttl = 0;
5770         ISC_LIST_INIT(res->alternates);
5771         res->udpsize = RECV_BUFFER_SIZE;
5772         res->algorithms = NULL;
5773         res->mustbesecure = NULL;
5774
5775         res->nbuckets = ntasks;
5776         res->activebuckets = ntasks;
5777         res->buckets = isc_mem_get(view->mctx,
5778                                    ntasks * sizeof(fctxbucket_t));
5779         if (res->buckets == NULL) {
5780                 result = ISC_R_NOMEMORY;
5781                 goto cleanup_res;
5782         }
5783         for (i = 0; i < ntasks; i++) {
5784                 result = isc_mutex_init(&res->buckets[i].lock);
5785                 if (result != ISC_R_SUCCESS)
5786                         goto cleanup_buckets;
5787                 res->buckets[i].task = NULL;
5788                 result = isc_task_create(taskmgr, 0, &res->buckets[i].task);
5789                 if (result != ISC_R_SUCCESS) {
5790                         DESTROYLOCK(&res->buckets[i].lock);
5791                         goto cleanup_buckets;
5792                 }
5793                 snprintf(name, sizeof(name), "res%u", i);
5794                 isc_task_setname(res->buckets[i].task, name, res);
5795                 ISC_LIST_INIT(res->buckets[i].fctxs);
5796                 res->buckets[i].exiting = ISC_FALSE;
5797                 buckets_created++;
5798         }
5799
5800         res->dispatchv4 = NULL;
5801         if (dispatchv4 != NULL)
5802                 dns_dispatch_attach(dispatchv4, &res->dispatchv4);
5803         res->dispatchv6 = NULL;
5804         if (dispatchv6 != NULL)
5805                 dns_dispatch_attach(dispatchv6, &res->dispatchv6);
5806
5807         res->references = 1;
5808         res->exiting = ISC_FALSE;
5809         res->frozen = ISC_FALSE;
5810         ISC_LIST_INIT(res->whenshutdown);
5811         res->priming = ISC_FALSE;
5812         res->primefetch = NULL;
5813         res->nfctx = 0;
5814
5815         result = isc_mutex_init(&res->lock);
5816         if (result != ISC_R_SUCCESS)
5817                 goto cleanup_dispatches;
5818
5819         result = isc_mutex_init(&res->nlock);
5820         if (result != ISC_R_SUCCESS)
5821                 goto cleanup_lock;
5822
5823         result = isc_mutex_init(&res->primelock);
5824         if (result != ISC_R_SUCCESS)
5825                 goto cleanup_nlock;
5826
5827 #if USE_ALGLOCK
5828         result = isc_rwlock_init(&res->alglock, 0, 0);
5829         if (result != ISC_R_SUCCESS)
5830                 goto cleanup_primelock;
5831 #endif
5832 #if USE_MBSLOCK
5833         result = isc_rwlock_init(&res->mbslock, 0, 0);
5834         if (result != ISC_R_SUCCESS)
5835                 goto cleanup_alglock;
5836 #endif
5837
5838         res->magic = RES_MAGIC;
5839
5840         *resp = res;
5841
5842         return (ISC_R_SUCCESS);
5843
5844 #if USE_MBSLOCK
5845  cleanup_alglock:
5846 #if USE_ALGLOCK
5847         isc_rwlock_destroy(&res->alglock);
5848 #endif
5849 #endif
5850 #if USE_ALGLOCK || USE_MBSLOCK
5851  cleanup_primelock:
5852         DESTROYLOCK(&res->primelock);
5853 #endif
5854
5855  cleanup_nlock:
5856         DESTROYLOCK(&res->nlock);
5857
5858  cleanup_lock:
5859         DESTROYLOCK(&res->lock);
5860
5861  cleanup_dispatches:
5862         if (res->dispatchv6 != NULL)
5863                 dns_dispatch_detach(&res->dispatchv6);
5864         if (res->dispatchv4 != NULL)
5865                 dns_dispatch_detach(&res->dispatchv4);
5866
5867  cleanup_buckets:
5868         for (i = 0; i < buckets_created; i++) {
5869                 DESTROYLOCK(&res->buckets[i].lock);
5870                 isc_task_shutdown(res->buckets[i].task);
5871                 isc_task_detach(&res->buckets[i].task);
5872         }
5873         isc_mem_put(view->mctx, res->buckets,
5874                     res->nbuckets * sizeof(fctxbucket_t));
5875
5876  cleanup_res:
5877         isc_mem_put(view->mctx, res, sizeof(*res));
5878
5879         return (result);
5880 }
5881
5882 static void
5883 prime_done(isc_task_t *task, isc_event_t *event) {
5884         dns_resolver_t *res;
5885         dns_fetchevent_t *fevent;
5886         dns_fetch_t *fetch;
5887
5888         REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
5889         fevent = (dns_fetchevent_t *)event;
5890         res = event->ev_arg;
5891         REQUIRE(VALID_RESOLVER(res));
5892
5893         UNUSED(task);
5894
5895         LOCK(&res->lock);
5896
5897         INSIST(res->priming);
5898         res->priming = ISC_FALSE;
5899         LOCK(&res->primelock);
5900         fetch = res->primefetch;
5901         res->primefetch = NULL;
5902         UNLOCK(&res->primelock);
5903
5904         UNLOCK(&res->lock);
5905
5906         if (fevent->node != NULL)
5907                 dns_db_detachnode(fevent->db, &fevent->node);
5908         if (fevent->db != NULL)
5909                 dns_db_detach(&fevent->db);
5910         if (dns_rdataset_isassociated(fevent->rdataset))
5911                 dns_rdataset_disassociate(fevent->rdataset);
5912         INSIST(fevent->sigrdataset == NULL);
5913
5914         isc_mem_put(res->mctx, fevent->rdataset, sizeof(*fevent->rdataset));
5915
5916         isc_event_free(&event);
5917         dns_resolver_destroyfetch(&fetch);
5918 }
5919
5920 void
5921 dns_resolver_prime(dns_resolver_t *res) {
5922         isc_boolean_t want_priming = ISC_FALSE;
5923         dns_rdataset_t *rdataset;
5924         isc_result_t result;
5925
5926         REQUIRE(VALID_RESOLVER(res));
5927         REQUIRE(res->frozen);
5928
5929         RTRACE("dns_resolver_prime");
5930
5931         LOCK(&res->lock);
5932
5933         if (!res->exiting && !res->priming) {
5934                 INSIST(res->primefetch == NULL);
5935                 res->priming = ISC_TRUE;
5936                 want_priming = ISC_TRUE;
5937         }
5938
5939         UNLOCK(&res->lock);
5940
5941         if (want_priming) {
5942                 /*
5943                  * To avoid any possible recursive locking problems, we
5944                  * start the priming fetch like any other fetch, and holding
5945                  * no resolver locks.  No one else will try to start it
5946                  * because we're the ones who set res->priming to true.
5947                  * Any other callers of dns_resolver_prime() while we're
5948                  * running will see that res->priming is already true and
5949                  * do nothing.
5950                  */
5951                 RTRACE("priming");
5952                 rdataset = isc_mem_get(res->mctx, sizeof(*rdataset));
5953                 if (rdataset == NULL) {
5954                         LOCK(&res->lock);
5955                         INSIST(res->priming);
5956                         INSIST(res->primefetch == NULL);
5957                         res->priming = ISC_FALSE;
5958                         UNLOCK(&res->lock);
5959                         return;
5960                 }
5961                 dns_rdataset_init(rdataset);
5962                 LOCK(&res->primelock);
5963                 result = dns_resolver_createfetch(res, dns_rootname,
5964                                                   dns_rdatatype_ns,
5965                                                   NULL, NULL, NULL, 0,
5966                                                   res->buckets[0].task,
5967                                                   prime_done,
5968                                                   res, rdataset, NULL,
5969                                                   &res->primefetch);
5970                 UNLOCK(&res->primelock);
5971                 if (result != ISC_R_SUCCESS) {
5972                         LOCK(&res->lock);
5973                         INSIST(res->priming);
5974                         res->priming = ISC_FALSE;
5975                         UNLOCK(&res->lock);
5976                 }
5977         }
5978 }
5979
5980 void
5981 dns_resolver_freeze(dns_resolver_t *res) {
5982
5983         /*
5984          * Freeze resolver.
5985          */
5986
5987         REQUIRE(VALID_RESOLVER(res));
5988         REQUIRE(!res->frozen);
5989
5990         res->frozen = ISC_TRUE;
5991 }
5992
5993 void
5994 dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) {
5995         REQUIRE(VALID_RESOLVER(source));
5996         REQUIRE(targetp != NULL && *targetp == NULL);
5997
5998         RRTRACE(source, "attach");
5999         LOCK(&source->lock);
6000         REQUIRE(!source->exiting);
6001
6002         INSIST(source->references > 0);
6003         source->references++;
6004         INSIST(source->references != 0);
6005         UNLOCK(&source->lock);
6006
6007         *targetp = source;
6008 }
6009
6010 void
6011 dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
6012                           isc_event_t **eventp)
6013 {
6014         isc_task_t *clone;
6015         isc_event_t *event;
6016
6017         REQUIRE(VALID_RESOLVER(res));
6018         REQUIRE(eventp != NULL);
6019
6020         event = *eventp;
6021         *eventp = NULL;
6022
6023         LOCK(&res->lock);
6024
6025         if (res->exiting && res->activebuckets == 0) {
6026                 /*
6027                  * We're already shutdown.  Send the event.
6028                  */
6029                 event->ev_sender = res;
6030                 isc_task_send(task, &event);
6031         } else {
6032                 clone = NULL;
6033                 isc_task_attach(task, &clone);
6034                 event->ev_sender = clone;
6035                 ISC_LIST_APPEND(res->whenshutdown, event, ev_link);
6036         }
6037
6038         UNLOCK(&res->lock);
6039 }
6040
6041 void
6042 dns_resolver_shutdown(dns_resolver_t *res) {
6043         unsigned int i;
6044         fetchctx_t *fctx;
6045         isc_socket_t *sock;
6046
6047         REQUIRE(VALID_RESOLVER(res));
6048
6049         RTRACE("shutdown");
6050
6051         LOCK(&res->lock);
6052
6053         if (!res->exiting) {
6054                 RTRACE("exiting");
6055                 res->exiting = ISC_TRUE;
6056
6057                 for (i = 0; i < res->nbuckets; i++) {
6058                         LOCK(&res->buckets[i].lock);
6059                         for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
6060                              fctx != NULL;
6061                              fctx = ISC_LIST_NEXT(fctx, link))
6062                                 fctx_shutdown(fctx);
6063                         if (res->dispatchv4 != NULL) {
6064                                 sock = dns_dispatch_getsocket(res->dispatchv4);
6065                                 isc_socket_cancel(sock, res->buckets[i].task,
6066                                                   ISC_SOCKCANCEL_ALL);
6067                         }
6068                         if (res->dispatchv6 != NULL) {
6069                                 sock = dns_dispatch_getsocket(res->dispatchv6);
6070                                 isc_socket_cancel(sock, res->buckets[i].task,
6071                                                   ISC_SOCKCANCEL_ALL);
6072                         }
6073                         res->buckets[i].exiting = ISC_TRUE;
6074                         if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
6075                                 INSIST(res->activebuckets > 0);
6076                                 res->activebuckets--;
6077                         }
6078                         UNLOCK(&res->buckets[i].lock);
6079                 }
6080                 if (res->activebuckets == 0)
6081                         send_shutdown_events(res);
6082         }
6083
6084         UNLOCK(&res->lock);
6085 }
6086
6087 void
6088 dns_resolver_detach(dns_resolver_t **resp) {
6089         dns_resolver_t *res;
6090         isc_boolean_t need_destroy = ISC_FALSE;
6091
6092         REQUIRE(resp != NULL);
6093         res = *resp;
6094         REQUIRE(VALID_RESOLVER(res));
6095
6096         RTRACE("detach");
6097
6098         LOCK(&res->lock);
6099
6100         INSIST(res->references > 0);
6101         res->references--;
6102         if (res->references == 0) {
6103                 INSIST(res->exiting && res->activebuckets == 0);
6104                 need_destroy = ISC_TRUE;
6105         }
6106
6107         UNLOCK(&res->lock);
6108
6109         if (need_destroy)
6110                 destroy(res);
6111
6112         *resp = NULL;
6113 }
6114
6115 static inline isc_boolean_t
6116 fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
6117            unsigned int options)
6118 {
6119         if (fctx->type != type || fctx->options != options)
6120                 return (ISC_FALSE);
6121         return (dns_name_equal(&fctx->name, name));
6122 }
6123
6124 static inline void
6125 log_fetch(dns_name_t *name, dns_rdatatype_t type) {
6126         char namebuf[DNS_NAME_FORMATSIZE];
6127         char typebuf[DNS_RDATATYPE_FORMATSIZE];
6128         int level = ISC_LOG_DEBUG(1);
6129
6130         if (! isc_log_wouldlog(dns_lctx, level))
6131                 return;
6132
6133         dns_name_format(name, namebuf, sizeof(namebuf));
6134         dns_rdatatype_format(type, typebuf, sizeof(typebuf));
6135
6136         isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
6137                       DNS_LOGMODULE_RESOLVER, level,
6138                       "createfetch: %s %s", namebuf, typebuf);
6139 }
6140
6141 isc_result_t
6142 dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
6143                          dns_rdatatype_t type,
6144                          dns_name_t *domain, dns_rdataset_t *nameservers,
6145                          dns_forwarders_t *forwarders,
6146                          unsigned int options, isc_task_t *task,
6147                          isc_taskaction_t action, void *arg,
6148                          dns_rdataset_t *rdataset,
6149                          dns_rdataset_t *sigrdataset,
6150                          dns_fetch_t **fetchp)
6151 {
6152         dns_fetch_t *fetch;
6153         fetchctx_t *fctx = NULL;
6154         isc_result_t result;
6155         unsigned int bucketnum;
6156         isc_boolean_t new_fctx = ISC_FALSE;
6157         isc_event_t *event;
6158
6159         UNUSED(forwarders);
6160
6161         REQUIRE(VALID_RESOLVER(res));
6162         REQUIRE(res->frozen);
6163         /* XXXRTH  Check for meta type */
6164         if (domain != NULL) {
6165                 REQUIRE(DNS_RDATASET_VALID(nameservers));
6166                 REQUIRE(nameservers->type == dns_rdatatype_ns);
6167         } else
6168                 REQUIRE(nameservers == NULL);
6169         REQUIRE(forwarders == NULL);
6170         REQUIRE(!dns_rdataset_isassociated(rdataset));
6171         REQUIRE(sigrdataset == NULL ||
6172                 !dns_rdataset_isassociated(sigrdataset));
6173         REQUIRE(fetchp != NULL && *fetchp == NULL);
6174
6175         log_fetch(name, type);
6176
6177         /*
6178          * XXXRTH  use a mempool?
6179          */
6180         fetch = isc_mem_get(res->mctx, sizeof(*fetch));
6181         if (fetch == NULL)
6182                 return (ISC_R_NOMEMORY);
6183
6184         bucketnum = dns_name_hash(name, ISC_FALSE) % res->nbuckets;
6185
6186         LOCK(&res->buckets[bucketnum].lock);
6187
6188         if (res->buckets[bucketnum].exiting) {
6189                 result = ISC_R_SHUTTINGDOWN;
6190                 goto unlock;
6191         }
6192
6193         if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
6194                 for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
6195                      fctx != NULL;
6196                      fctx = ISC_LIST_NEXT(fctx, link)) {
6197                         if (fctx_match(fctx, name, type, options))
6198                                 break;
6199                 }
6200         }
6201
6202         /*
6203          * If we didn't have a fetch, would attach to a done fetch, this
6204          * fetch has already cloned its results, or if the fetch has gone
6205          * "idle" (no one was interested in it), we need to start a new
6206          * fetch instead of joining with the existing one.
6207          */
6208         if (fctx == NULL ||
6209             fctx->state == fetchstate_done ||
6210             fctx->cloned ||
6211             ISC_LIST_EMPTY(fctx->events)) {
6212                 fctx = NULL;
6213                 result = fctx_create(res, name, type, domain, nameservers,
6214                                      options, bucketnum, &fctx);
6215                 if (result != ISC_R_SUCCESS)
6216                         goto unlock;
6217                 new_fctx = ISC_TRUE;
6218         }
6219
6220         result = fctx_join(fctx, task, action, arg,
6221                            rdataset, sigrdataset, fetch);
6222         if (new_fctx) {
6223                 if (result == ISC_R_SUCCESS) {
6224                         /*
6225                          * Launch this fctx.
6226                          */
6227                         event = &fctx->control_event;
6228                         ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
6229                                        DNS_EVENT_FETCHCONTROL,
6230                                        fctx_start, fctx, NULL,
6231                                        NULL, NULL);
6232                         isc_task_send(res->buckets[bucketnum].task, &event);
6233                 } else {
6234                         /*
6235                          * We don't care about the result of fctx_destroy()
6236                          * since we know we're not exiting.
6237                          */
6238                         (void)fctx_destroy(fctx);
6239                 }
6240         }
6241
6242  unlock:
6243         UNLOCK(&res->buckets[bucketnum].lock);
6244
6245         if (result == ISC_R_SUCCESS) {
6246                 FTRACE("created");
6247                 *fetchp = fetch;
6248         } else
6249                 isc_mem_put(res->mctx, fetch, sizeof(*fetch));
6250
6251         return (result);
6252 }
6253
6254 void
6255 dns_resolver_cancelfetch(dns_fetch_t *fetch) {
6256         fetchctx_t *fctx;
6257         dns_resolver_t *res;
6258         dns_fetchevent_t *event, *next_event;
6259         isc_task_t *etask;
6260
6261         REQUIRE(DNS_FETCH_VALID(fetch));
6262         fctx = fetch->private;
6263         REQUIRE(VALID_FCTX(fctx));
6264         res = fctx->res;
6265
6266         FTRACE("cancelfetch");
6267
6268         LOCK(&res->buckets[fctx->bucketnum].lock);
6269
6270         /*
6271          * Find the completion event for this fetch (as opposed
6272          * to those for other fetches that have joined the same
6273          * fctx) and send it with result = ISC_R_CANCELED.
6274          */
6275         event = NULL;
6276         if (fctx->state != fetchstate_done) {
6277                 for (event = ISC_LIST_HEAD(fctx->events);
6278                      event != NULL;
6279                      event = next_event) {
6280                         next_event = ISC_LIST_NEXT(event, ev_link);
6281                         if (event->fetch == fetch) {
6282                                 ISC_LIST_UNLINK(fctx->events, event, ev_link);
6283                                 break;
6284                         }
6285                 }
6286         }
6287         if (event != NULL) {
6288                 etask = event->ev_sender;
6289                 event->ev_sender = fctx;
6290                 event->result = ISC_R_CANCELED;
6291                 isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event));
6292         }
6293         /*
6294          * The fctx continues running even if no fetches remain;
6295          * the answer is still cached.
6296          */
6297
6298         UNLOCK(&res->buckets[fctx->bucketnum].lock);
6299 }
6300
6301 void
6302 dns_resolver_destroyfetch(dns_fetch_t **fetchp) {
6303         dns_fetch_t *fetch;
6304         dns_resolver_t *res;
6305         dns_fetchevent_t *event, *next_event;
6306         fetchctx_t *fctx;
6307         unsigned int bucketnum;
6308         isc_boolean_t bucket_empty = ISC_FALSE;
6309
6310         REQUIRE(fetchp != NULL);
6311         fetch = *fetchp;
6312         REQUIRE(DNS_FETCH_VALID(fetch));
6313         fctx = fetch->private;
6314         REQUIRE(VALID_FCTX(fctx));
6315         res = fctx->res;
6316
6317         FTRACE("destroyfetch");
6318
6319         bucketnum = fctx->bucketnum;
6320         LOCK(&res->buckets[bucketnum].lock);
6321
6322         /*
6323          * Sanity check: the caller should have gotten its event before
6324          * trying to destroy the fetch.
6325          */
6326         event = NULL;
6327         if (fctx->state != fetchstate_done) {
6328                 for (event = ISC_LIST_HEAD(fctx->events);
6329                      event != NULL;
6330                      event = next_event) {
6331                         next_event = ISC_LIST_NEXT(event, ev_link);
6332                         RUNTIME_CHECK(event->fetch != fetch);
6333                 }
6334         }
6335
6336         INSIST(fctx->references > 0);
6337         fctx->references--;
6338         if (fctx->references == 0) {
6339                 /*
6340                  * No one cares about the result of this fetch anymore.
6341                  */
6342                 if (fctx->pending == 0 && ISC_LIST_EMPTY(fctx->validators) &&
6343                     SHUTTINGDOWN(fctx)) {
6344                         /*
6345                          * This fctx is already shutdown; we were just
6346                          * waiting for the last reference to go away.
6347                          */
6348                         bucket_empty = fctx_destroy(fctx);
6349                 } else {
6350                         /*
6351                          * Initiate shutdown.
6352                          */
6353                         fctx_shutdown(fctx);
6354                 }
6355         }
6356
6357         UNLOCK(&res->buckets[bucketnum].lock);
6358
6359         isc_mem_put(res->mctx, fetch, sizeof(*fetch));
6360         *fetchp = NULL;
6361
6362         if (bucket_empty)
6363                 empty_bucket(res);
6364 }
6365
6366 dns_dispatchmgr_t *
6367 dns_resolver_dispatchmgr(dns_resolver_t *resolver) {
6368         REQUIRE(VALID_RESOLVER(resolver));
6369         return (resolver->dispatchmgr);
6370 }
6371
6372 dns_dispatch_t *
6373 dns_resolver_dispatchv4(dns_resolver_t *resolver) {
6374         REQUIRE(VALID_RESOLVER(resolver));
6375         return (resolver->dispatchv4);
6376 }
6377
6378 dns_dispatch_t *
6379 dns_resolver_dispatchv6(dns_resolver_t *resolver) {
6380         REQUIRE(VALID_RESOLVER(resolver));
6381         return (resolver->dispatchv6);
6382 }
6383
6384 isc_socketmgr_t *
6385 dns_resolver_socketmgr(dns_resolver_t *resolver) {
6386         REQUIRE(VALID_RESOLVER(resolver));
6387         return (resolver->socketmgr);
6388 }
6389
6390 isc_taskmgr_t *
6391 dns_resolver_taskmgr(dns_resolver_t *resolver) {
6392         REQUIRE(VALID_RESOLVER(resolver));
6393         return (resolver->taskmgr);
6394 }
6395
6396 isc_uint32_t
6397 dns_resolver_getlamettl(dns_resolver_t *resolver) {
6398         REQUIRE(VALID_RESOLVER(resolver));
6399         return (resolver->lame_ttl);
6400 }
6401
6402 void
6403 dns_resolver_setlamettl(dns_resolver_t *resolver, isc_uint32_t lame_ttl) {
6404         REQUIRE(VALID_RESOLVER(resolver));
6405         resolver->lame_ttl = lame_ttl;
6406 }
6407
6408 unsigned int
6409 dns_resolver_nrunning(dns_resolver_t *resolver) {
6410         unsigned int n;
6411         LOCK(&resolver->nlock);
6412         n = resolver->nfctx;
6413         UNLOCK(&resolver->nlock);
6414         return (n);
6415 }
6416
6417 isc_result_t
6418 dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt,
6419                           dns_name_t *name, in_port_t port) {
6420         alternate_t *a;
6421         isc_result_t result;
6422
6423         REQUIRE(VALID_RESOLVER(resolver));
6424         REQUIRE(!resolver->frozen);
6425         REQUIRE((alt == NULL) ^ (name == NULL));
6426
6427         a = isc_mem_get(resolver->mctx, sizeof(*a));
6428         if (a == NULL)
6429                 return (ISC_R_NOMEMORY);
6430         if (alt != NULL) {
6431                 a->isaddress = ISC_TRUE;
6432                 a->_u.addr = *alt;
6433         } else {
6434                 a->isaddress = ISC_FALSE;
6435                 a->_u._n.port = port;
6436                 dns_name_init(&a->_u._n.name, NULL);
6437                 result = dns_name_dup(name, resolver->mctx, &a->_u._n.name);
6438                 if (result != ISC_R_SUCCESS) {
6439                         isc_mem_put(resolver->mctx, a, sizeof(*a));
6440                         return (result);
6441                 }
6442         }
6443         ISC_LINK_INIT(a, link);
6444         ISC_LIST_APPEND(resolver->alternates, a, link);
6445
6446         return (ISC_R_SUCCESS);
6447 }
6448
6449 void
6450 dns_resolver_setudpsize(dns_resolver_t *resolver, isc_uint16_t udpsize) {
6451         REQUIRE(VALID_RESOLVER(resolver));
6452         resolver->udpsize = udpsize;
6453 }
6454
6455 isc_uint16_t
6456 dns_resolver_getudpsize(dns_resolver_t *resolver) {
6457         REQUIRE(VALID_RESOLVER(resolver));
6458         return (resolver->udpsize);
6459 }
6460
6461 static void
6462 free_algorithm(void *node, void *arg) {
6463         unsigned char *algorithms = node;
6464         isc_mem_t *mctx = arg;
6465
6466         isc_mem_put(mctx, algorithms, *algorithms);
6467 }
6468  
6469 void
6470 dns_resolver_reset_algorithms(dns_resolver_t *resolver) {
6471
6472         REQUIRE(VALID_RESOLVER(resolver));
6473
6474 #if USE_ALGLOCK
6475         RWLOCK(&resolver->alglock, isc_rwlocktype_write);
6476 #endif
6477         if (resolver->algorithms != NULL)
6478                 dns_rbt_destroy(&resolver->algorithms);
6479 #if USE_ALGLOCK
6480         RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
6481 #endif
6482 }
6483
6484 isc_result_t
6485 dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
6486                                unsigned int alg)
6487 {
6488         unsigned int len, mask;
6489         unsigned char *new;
6490         unsigned char *algorithms;
6491         isc_result_t result;
6492         dns_rbtnode_t *node = NULL;
6493
6494         REQUIRE(VALID_RESOLVER(resolver));
6495         if (alg > 255)
6496                 return (ISC_R_RANGE);
6497
6498 #if USE_ALGLOCK
6499         RWLOCK(&resolver->alglock, isc_rwlocktype_write);
6500 #endif
6501         if (resolver->algorithms == NULL) {
6502                 result = dns_rbt_create(resolver->mctx, free_algorithm,
6503                                         resolver->mctx, &resolver->algorithms);
6504                 if (result != ISC_R_SUCCESS)
6505                         goto cleanup;
6506         }
6507
6508         len = alg/8 + 2;
6509         mask = 1 << (alg%8);
6510
6511         result = dns_rbt_addnode(resolver->algorithms, name, &node);
6512         
6513         if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
6514                 algorithms = node->data;
6515                 if (algorithms == NULL || len > *algorithms) {
6516                         new = isc_mem_get(resolver->mctx, len);
6517                         if (new == NULL) {
6518                                 result = ISC_R_NOMEMORY;
6519                                 goto cleanup;
6520                         }
6521                         memset(new, 0, len);
6522                         if (algorithms != NULL)
6523                                 memcpy(new, algorithms, *algorithms);
6524                         new[len-1] |= mask;
6525                         *new = len;
6526                         node->data = new;
6527                         if (algorithms != NULL)
6528                                 isc_mem_put(resolver->mctx, algorithms, 
6529                                             *algorithms);
6530                 } else
6531                         algorithms[len-1] |= mask;
6532         }
6533         result = ISC_R_SUCCESS;
6534  cleanup:
6535 #if USE_ALGLOCK
6536         RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
6537 #endif
6538         return (result);
6539 }
6540
6541 isc_boolean_t
6542 dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name,
6543                                  unsigned int alg)
6544 {
6545         unsigned int len, mask;
6546         unsigned char *algorithms;
6547         void *data = NULL;
6548         isc_result_t result;
6549         isc_boolean_t found = ISC_FALSE;
6550
6551         REQUIRE(VALID_RESOLVER(resolver));
6552
6553 #if USE_ALGLOCK
6554         RWLOCK(&resolver->alglock, isc_rwlocktype_read);
6555 #endif
6556         if (resolver->algorithms == NULL)
6557                 goto unlock;
6558         result = dns_rbt_findname(resolver->algorithms, name, 0, NULL, &data);
6559         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
6560                 len = alg/8 + 2;
6561                 mask = 1 << (alg%8);
6562                 algorithms = data;
6563                 if (len <= *algorithms && (algorithms[len-1] & mask) != 0)
6564                         found = ISC_TRUE;
6565         }
6566  unlock:
6567 #if USE_ALGLOCK
6568         RWUNLOCK(&resolver->alglock, isc_rwlocktype_read);
6569 #endif
6570         if (found)
6571                 return (ISC_FALSE);
6572         return (dst_algorithm_supported(alg));
6573 }
6574
6575 void
6576 dns_resolver_resetmustbesecure(dns_resolver_t *resolver) {
6577
6578         REQUIRE(VALID_RESOLVER(resolver));
6579
6580 #if USE_MBSLOCK
6581         RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
6582 #endif
6583         if (resolver->mustbesecure != NULL)
6584                 dns_rbt_destroy(&resolver->mustbesecure);
6585 #if USE_MBSLOCK
6586         RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
6587 #endif
6588 }
6589  
6590 static isc_boolean_t yes = ISC_TRUE, no = ISC_FALSE;
6591
6592 isc_result_t
6593 dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name,
6594                              isc_boolean_t value)
6595 {
6596         isc_result_t result;
6597
6598         REQUIRE(VALID_RESOLVER(resolver));
6599
6600 #if USE_MBSLOCK
6601         RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
6602 #endif
6603         if (resolver->mustbesecure == NULL) {
6604                 result = dns_rbt_create(resolver->mctx, NULL, NULL,
6605                                         &resolver->mustbesecure);
6606                 if (result != ISC_R_SUCCESS)
6607                         goto cleanup;
6608         }
6609         result = dns_rbt_addname(resolver->mustbesecure, name, 
6610                                  value ? &yes : &no);
6611  cleanup:
6612 #if USE_MBSLOCK
6613         RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
6614 #endif
6615         return (result);
6616 }
6617
6618 isc_boolean_t
6619 dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name) {
6620         void *data = NULL;
6621         isc_boolean_t value = ISC_FALSE;
6622         isc_result_t result;
6623
6624         REQUIRE(VALID_RESOLVER(resolver));
6625
6626 #if USE_MBSLOCK
6627         RWLOCK(&resolver->mbslock, isc_rwlocktype_read);
6628 #endif
6629         if (resolver->mustbesecure == NULL)
6630                 goto unlock;
6631         result = dns_rbt_findname(resolver->mustbesecure, name, 0, NULL, &data);
6632         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
6633                 value = *(isc_boolean_t*)data;
6634  unlock:
6635 #if USE_MBSLOCK
6636         RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read);
6637 #endif
6638         return (value);
6639 }