]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - contrib/bind9/bin/named/query.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / contrib / bind9 / bin / named / query.c
1 /*
2  * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or 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: query.c,v 1.313.20.7 2009/03/13 01:38:51 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <isc/hex.h>
27 #include <isc/mem.h>
28 #include <isc/stats.h>
29 #include <isc/util.h>
30
31 #include <dns/adb.h>
32 #include <dns/byaddr.h>
33 #include <dns/db.h>
34 #ifdef DLZ
35 #include <dns/dlz.h>
36 #endif
37 #include <dns/dnssec.h>
38 #include <dns/events.h>
39 #include <dns/message.h>
40 #include <dns/ncache.h>
41 #include <dns/nsec3.h>
42 #include <dns/order.h>
43 #include <dns/rdata.h>
44 #include <dns/rdataclass.h>
45 #include <dns/rdatalist.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatasetiter.h>
48 #include <dns/rdatastruct.h>
49 #include <dns/rdatatype.h>
50 #include <dns/resolver.h>
51 #include <dns/result.h>
52 #include <dns/stats.h>
53 #include <dns/tkey.h>
54 #include <dns/view.h>
55 #include <dns/zone.h>
56 #include <dns/zt.h>
57
58 #include <named/client.h>
59 #include <named/log.h>
60 #include <named/server.h>
61 #include <named/sortlist.h>
62 #include <named/xfrout.h>
63
64 /*% Partial answer? */
65 #define PARTIALANSWER(c)        (((c)->query.attributes & \
66                                   NS_QUERYATTR_PARTIALANSWER) != 0)
67 /*% Use Cache? */
68 #define USECACHE(c)             (((c)->query.attributes & \
69                                   NS_QUERYATTR_CACHEOK) != 0)
70 /*% Recursion OK? */
71 #define RECURSIONOK(c)          (((c)->query.attributes & \
72                                   NS_QUERYATTR_RECURSIONOK) != 0)
73 /*% Recursing? */
74 #define RECURSING(c)            (((c)->query.attributes & \
75                                   NS_QUERYATTR_RECURSING) != 0)
76 /*% Cache glue ok? */
77 #define CACHEGLUEOK(c)          (((c)->query.attributes & \
78                                   NS_QUERYATTR_CACHEGLUEOK) != 0)
79 /*% Want Recursion? */
80 #define WANTRECURSION(c)        (((c)->query.attributes & \
81                                   NS_QUERYATTR_WANTRECURSION) != 0)
82 /*% Want DNSSEC? */
83 #define WANTDNSSEC(c)           (((c)->attributes & \
84                                   NS_CLIENTATTR_WANTDNSSEC) != 0)
85 /*% No authority? */
86 #define NOAUTHORITY(c)          (((c)->query.attributes & \
87                                   NS_QUERYATTR_NOAUTHORITY) != 0)
88 /*% No additional? */
89 #define NOADDITIONAL(c)         (((c)->query.attributes & \
90                                   NS_QUERYATTR_NOADDITIONAL) != 0)
91 /*% Secure? */
92 #define SECURE(c)               (((c)->query.attributes & \
93                                   NS_QUERYATTR_SECURE) != 0)
94
95 /*% No QNAME Proof? */
96 #define NOQNAME(r)              (((r)->attributes & \
97                                   DNS_RDATASETATTR_NOQNAME) != 0)
98
99 #if 0
100 #define CTRACE(m)       isc_log_write(ns_g_lctx, \
101                                       NS_LOGCATEGORY_CLIENT, \
102                                       NS_LOGMODULE_QUERY, \
103                                       ISC_LOG_DEBUG(3), \
104                                       "client %p: %s", client, (m))
105 #define QTRACE(m)       isc_log_write(ns_g_lctx, \
106                                       NS_LOGCATEGORY_GENERAL, \
107                                       NS_LOGMODULE_QUERY, \
108                                       ISC_LOG_DEBUG(3), \
109                                       "query %p: %s", query, (m))
110 #else
111 #define CTRACE(m) ((void)m)
112 #define QTRACE(m) ((void)m)
113 #endif
114
115 #define DNS_GETDB_NOEXACT 0x01U
116 #define DNS_GETDB_NOLOG 0x02U
117 #define DNS_GETDB_PARTIAL 0x04U
118
119 typedef struct client_additionalctx {
120         ns_client_t *client;
121         dns_rdataset_t *rdataset;
122 } client_additionalctx_t;
123
124 static isc_result_t
125 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
126
127 static isc_boolean_t
128 validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
129          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
130
131 static void
132 query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
133                        dns_dbversion_t *version, ns_client_t *client,
134                        dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
135                        dns_name_t *fname, isc_boolean_t exact,
136                        dns_name_t *found);
137
138 static inline void
139 log_queryerror(ns_client_t *client, isc_result_t result, int line, int level);
140
141 /*%
142  * Increment query statistics counters.
143  */
144 static inline void
145 inc_stats(ns_client_t *client, isc_statscounter_t counter) {
146         dns_zone_t *zone = client->query.authzone;
147
148         isc_stats_increment(ns_g_server->nsstats, counter);
149
150         if (zone != NULL) {
151                 isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
152                 if (zonestats != NULL)
153                         isc_stats_increment(zonestats, counter);
154         }
155 }
156
157 static void
158 query_send(ns_client_t *client) {
159         isc_statscounter_t counter;
160         if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0)
161                 inc_stats(client, dns_nsstatscounter_nonauthans);
162         else
163                 inc_stats(client, dns_nsstatscounter_authans);
164         if (client->message->rcode == dns_rcode_noerror) {
165                 if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) {
166                         if (client->query.isreferral) {
167                                 counter = dns_nsstatscounter_referral;
168                         } else {
169                                 counter = dns_nsstatscounter_nxrrset;
170                         }
171                 } else {
172                         counter = dns_nsstatscounter_success;
173                 }
174         } else if (client->message->rcode == dns_rcode_nxdomain) {
175                 counter = dns_nsstatscounter_nxdomain;
176         } else {
177                 /* We end up here in case of YXDOMAIN, and maybe others */
178                 counter = dns_nsstatscounter_failure;
179         }
180         inc_stats(client, counter);
181         ns_client_send(client);
182 }
183
184 static void
185 query_error(ns_client_t *client, isc_result_t result, int line) {
186         int loglevel = ISC_LOG_DEBUG(3);
187
188         switch (result) {
189         case DNS_R_SERVFAIL:
190                 loglevel = ISC_LOG_DEBUG(1);
191                 inc_stats(client, dns_nsstatscounter_servfail);
192                 break;
193         case DNS_R_FORMERR:
194                 inc_stats(client, dns_nsstatscounter_formerr);
195                 break;
196         default:
197                 inc_stats(client, dns_nsstatscounter_failure);
198                 break;
199         }
200
201         log_queryerror(client, result, line, loglevel);
202
203         ns_client_error(client, result);
204 }
205
206 static void
207 query_next(ns_client_t *client, isc_result_t result) {
208         if (result == DNS_R_DUPLICATE)
209                 inc_stats(client, dns_nsstatscounter_duplicate);
210         else if (result == DNS_R_DROP)
211                 inc_stats(client, dns_nsstatscounter_dropped);
212         else
213                 inc_stats(client, dns_nsstatscounter_failure);
214         ns_client_next(client, result);
215 }
216
217 static inline void
218 query_freefreeversions(ns_client_t *client, isc_boolean_t everything) {
219         ns_dbversion_t *dbversion, *dbversion_next;
220         unsigned int i;
221
222         for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
223              dbversion != NULL;
224              dbversion = dbversion_next, i++)
225         {
226                 dbversion_next = ISC_LIST_NEXT(dbversion, link);
227                 /*
228                  * If we're not freeing everything, we keep the first three
229                  * dbversions structures around.
230                  */
231                 if (i > 3 || everything) {
232                         ISC_LIST_UNLINK(client->query.freeversions, dbversion,
233                                         link);
234                         isc_mem_put(client->mctx, dbversion,
235                                     sizeof(*dbversion));
236                 }
237         }
238 }
239
240 void
241 ns_query_cancel(ns_client_t *client) {
242         LOCK(&client->query.fetchlock);
243         if (client->query.fetch != NULL) {
244                 dns_resolver_cancelfetch(client->query.fetch);
245
246                 client->query.fetch = NULL;
247         }
248         UNLOCK(&client->query.fetchlock);
249 }
250
251 static inline void
252 query_reset(ns_client_t *client, isc_boolean_t everything) {
253         isc_buffer_t *dbuf, *dbuf_next;
254         ns_dbversion_t *dbversion, *dbversion_next;
255
256         /*%
257          * Reset the query state of a client to its default state.
258          */
259
260         /*
261          * Cancel the fetch if it's running.
262          */
263         ns_query_cancel(client);
264
265         /*
266          * Cleanup any active versions.
267          */
268         for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
269              dbversion != NULL;
270              dbversion = dbversion_next) {
271                 dbversion_next = ISC_LIST_NEXT(dbversion, link);
272                 dns_db_closeversion(dbversion->db, &dbversion->version,
273                                     ISC_FALSE);
274                 dns_db_detach(&dbversion->db);
275                 ISC_LIST_INITANDAPPEND(client->query.freeversions,
276                                       dbversion, link);
277         }
278         ISC_LIST_INIT(client->query.activeversions);
279
280         if (client->query.authdb != NULL)
281                 dns_db_detach(&client->query.authdb);
282         if (client->query.authzone != NULL)
283                 dns_zone_detach(&client->query.authzone);
284
285         query_freefreeversions(client, everything);
286
287         for (dbuf = ISC_LIST_HEAD(client->query.namebufs);
288              dbuf != NULL;
289              dbuf = dbuf_next) {
290                 dbuf_next = ISC_LIST_NEXT(dbuf, link);
291                 if (dbuf_next != NULL || everything) {
292                         ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
293                         isc_buffer_free(&dbuf);
294                 }
295         }
296
297         if (client->query.restarts > 0) {
298                 /*
299                  * client->query.qname was dynamically allocated.
300                  */
301                 dns_message_puttempname(client->message,
302                                         &client->query.qname);
303         }
304         client->query.qname = NULL;
305         client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
306                                     NS_QUERYATTR_CACHEOK |
307                                     NS_QUERYATTR_SECURE);
308         client->query.restarts = 0;
309         client->query.timerset = ISC_FALSE;
310         client->query.origqname = NULL;
311         client->query.qname = NULL;
312         client->query.dboptions = 0;
313         client->query.fetchoptions = 0;
314         client->query.gluedb = NULL;
315         client->query.authdbset = ISC_FALSE;
316         client->query.isreferral = ISC_FALSE;
317 }
318
319 static void
320 query_next_callback(ns_client_t *client) {
321         query_reset(client, ISC_FALSE);
322 }
323
324 void
325 ns_query_free(ns_client_t *client) {
326         query_reset(client, ISC_TRUE);
327 }
328
329 static inline isc_result_t
330 query_newnamebuf(ns_client_t *client) {
331         isc_buffer_t *dbuf;
332         isc_result_t result;
333
334         CTRACE("query_newnamebuf");
335         /*%
336          * Allocate a name buffer.
337          */
338
339         dbuf = NULL;
340         result = isc_buffer_allocate(client->mctx, &dbuf, 1024);
341         if (result != ISC_R_SUCCESS) {
342                 CTRACE("query_newnamebuf: isc_buffer_allocate failed: done");
343                 return (result);
344         }
345         ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
346
347         CTRACE("query_newnamebuf: done");
348         return (ISC_R_SUCCESS);
349 }
350
351 static inline isc_buffer_t *
352 query_getnamebuf(ns_client_t *client) {
353         isc_buffer_t *dbuf;
354         isc_result_t result;
355         isc_region_t r;
356
357         CTRACE("query_getnamebuf");
358         /*%
359          * Return a name buffer with space for a maximal name, allocating
360          * a new one if necessary.
361          */
362
363         if (ISC_LIST_EMPTY(client->query.namebufs)) {
364                 result = query_newnamebuf(client);
365                 if (result != ISC_R_SUCCESS) {
366                     CTRACE("query_getnamebuf: query_newnamebuf failed: done");
367                         return (NULL);
368                 }
369         }
370
371         dbuf = ISC_LIST_TAIL(client->query.namebufs);
372         INSIST(dbuf != NULL);
373         isc_buffer_availableregion(dbuf, &r);
374         if (r.length < 255) {
375                 result = query_newnamebuf(client);
376                 if (result != ISC_R_SUCCESS) {
377                     CTRACE("query_getnamebuf: query_newnamebuf failed: done");
378                         return (NULL);
379
380                 }
381                 dbuf = ISC_LIST_TAIL(client->query.namebufs);
382                 isc_buffer_availableregion(dbuf, &r);
383                 INSIST(r.length >= 255);
384         }
385         CTRACE("query_getnamebuf: done");
386         return (dbuf);
387 }
388
389 static inline void
390 query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
391         isc_region_t r;
392
393         CTRACE("query_keepname");
394         /*%
395          * 'name' is using space in 'dbuf', but 'dbuf' has not yet been
396          * adjusted to take account of that.  We do the adjustment.
397          */
398
399         REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0);
400
401         dns_name_toregion(name, &r);
402         isc_buffer_add(dbuf, r.length);
403         dns_name_setbuffer(name, NULL);
404         client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
405 }
406
407 static inline void
408 query_releasename(ns_client_t *client, dns_name_t **namep) {
409         dns_name_t *name = *namep;
410
411         /*%
412          * 'name' is no longer needed.  Return it to our pool of temporary
413          * names.  If it is using a name buffer, relinquish its exclusive
414          * rights on the buffer.
415          */
416
417         CTRACE("query_releasename");
418         if (dns_name_hasbuffer(name)) {
419                 INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED)
420                        != 0);
421                 client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
422         }
423         dns_message_puttempname(client->message, namep);
424         CTRACE("query_releasename: done");
425 }
426
427 static inline dns_name_t *
428 query_newname(ns_client_t *client, isc_buffer_t *dbuf,
429               isc_buffer_t *nbuf)
430 {
431         dns_name_t *name;
432         isc_region_t r;
433         isc_result_t result;
434
435         REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
436
437         CTRACE("query_newname");
438         name = NULL;
439         result = dns_message_gettempname(client->message, &name);
440         if (result != ISC_R_SUCCESS) {
441                 CTRACE("query_newname: dns_message_gettempname failed: done");
442                 return (NULL);
443         }
444         isc_buffer_availableregion(dbuf, &r);
445         isc_buffer_init(nbuf, r.base, r.length);
446         dns_name_init(name, NULL);
447         dns_name_setbuffer(name, nbuf);
448         client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED;
449
450         CTRACE("query_newname: done");
451         return (name);
452 }
453
454 static inline dns_rdataset_t *
455 query_newrdataset(ns_client_t *client) {
456         dns_rdataset_t *rdataset;
457         isc_result_t result;
458
459         CTRACE("query_newrdataset");
460         rdataset = NULL;
461         result = dns_message_gettemprdataset(client->message, &rdataset);
462         if (result != ISC_R_SUCCESS) {
463           CTRACE("query_newrdataset: "
464                  "dns_message_gettemprdataset failed: done");
465                 return (NULL);
466         }
467         dns_rdataset_init(rdataset);
468
469         CTRACE("query_newrdataset: done");
470         return (rdataset);
471 }
472
473 static inline void
474 query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
475         dns_rdataset_t *rdataset = *rdatasetp;
476
477         CTRACE("query_putrdataset");
478         if (rdataset != NULL) {
479                 if (dns_rdataset_isassociated(rdataset))
480                         dns_rdataset_disassociate(rdataset);
481                 dns_message_puttemprdataset(client->message, rdatasetp);
482         }
483         CTRACE("query_putrdataset: done");
484 }
485
486
487 static inline isc_result_t
488 query_newdbversion(ns_client_t *client, unsigned int n) {
489         unsigned int i;
490         ns_dbversion_t *dbversion;
491
492         for (i = 0; i < n; i++) {
493                 dbversion = isc_mem_get(client->mctx, sizeof(*dbversion));
494                 if (dbversion != NULL) {
495                         dbversion->db = NULL;
496                         dbversion->version = NULL;
497                         ISC_LIST_INITANDAPPEND(client->query.freeversions,
498                                               dbversion, link);
499                 } else {
500                         /*
501                          * We only return ISC_R_NOMEMORY if we couldn't
502                          * allocate anything.
503                          */
504                         if (i == 0)
505                                 return (ISC_R_NOMEMORY);
506                         else
507                                 return (ISC_R_SUCCESS);
508                 }
509         }
510
511         return (ISC_R_SUCCESS);
512 }
513
514 static inline ns_dbversion_t *
515 query_getdbversion(ns_client_t *client) {
516         isc_result_t result;
517         ns_dbversion_t *dbversion;
518
519         if (ISC_LIST_EMPTY(client->query.freeversions)) {
520                 result = query_newdbversion(client, 1);
521                 if (result != ISC_R_SUCCESS)
522                         return (NULL);
523         }
524         dbversion = ISC_LIST_HEAD(client->query.freeversions);
525         INSIST(dbversion != NULL);
526         ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
527
528         return (dbversion);
529 }
530
531 isc_result_t
532 ns_query_init(ns_client_t *client) {
533         isc_result_t result;
534
535         ISC_LIST_INIT(client->query.namebufs);
536         ISC_LIST_INIT(client->query.activeversions);
537         ISC_LIST_INIT(client->query.freeversions);
538         client->query.restarts = 0;
539         client->query.timerset = ISC_FALSE;
540         client->query.qname = NULL;
541         result = isc_mutex_init(&client->query.fetchlock);
542         if (result != ISC_R_SUCCESS)
543                 return (result);
544         client->query.fetch = NULL;
545         client->query.authdb = NULL;
546         client->query.authzone = NULL;
547         client->query.authdbset = ISC_FALSE;
548         client->query.isreferral = ISC_FALSE;
549         query_reset(client, ISC_FALSE);
550         result = query_newdbversion(client, 3);
551         if (result != ISC_R_SUCCESS) {
552                 DESTROYLOCK(&client->query.fetchlock);
553                 return (result);
554         }
555         result = query_newnamebuf(client);
556         if (result != ISC_R_SUCCESS)
557                 query_freefreeversions(client, ISC_TRUE);
558
559         return (result);
560 }
561
562 static inline ns_dbversion_t *
563 query_findversion(ns_client_t *client, dns_db_t *db,
564                   isc_boolean_t *newzonep)
565 {
566         ns_dbversion_t *dbversion;
567
568         /*%
569          * We may already have done a query related to this
570          * database.  If so, we must be sure to make subsequent
571          * queries from the same version.
572          */
573         for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
574              dbversion != NULL;
575              dbversion = ISC_LIST_NEXT(dbversion, link)) {
576                 if (dbversion->db == db)
577                         break;
578         }
579
580         if (dbversion == NULL) {
581                 /*
582                  * This is a new zone for this query.  Add it to
583                  * the active list.
584                  */
585                 dbversion = query_getdbversion(client);
586                 if (dbversion == NULL)
587                         return (NULL);
588                 dns_db_attach(db, &dbversion->db);
589                 dns_db_currentversion(db, &dbversion->version);
590                 dbversion->queryok = ISC_FALSE;
591                 ISC_LIST_APPEND(client->query.activeversions,
592                                 dbversion, link);
593                 *newzonep = ISC_TRUE;
594         } else
595                 *newzonep = ISC_FALSE;
596
597         return (dbversion);
598 }
599
600 static inline isc_result_t
601 query_validatezonedb(ns_client_t *client, dns_name_t *name,
602                      dns_rdatatype_t qtype, unsigned int options,
603                      dns_zone_t *zone, dns_db_t *db,
604                      dns_dbversion_t **versionp)
605 {
606         isc_result_t result;
607         isc_boolean_t check_acl, new_zone;
608         dns_acl_t *queryacl;
609         ns_dbversion_t *dbversion;
610
611         REQUIRE(zone != NULL);
612         REQUIRE(db != NULL);
613
614         /*
615          * This limits our searching to the zone where the first name
616          * (the query target) was looked for.  This prevents following
617          * CNAMES or DNAMES into other zones and prevents returning
618          * additional data from other zones.
619          */
620         if (!client->view->additionalfromauth &&
621             client->query.authdbset &&
622             db != client->query.authdb)
623                 goto refuse;
624
625         /*
626          * If the zone has an ACL, we'll check it, otherwise
627          * we use the view's "allow-query" ACL.  Each ACL is only checked
628          * once per query.
629          *
630          * Also, get the database version to use.
631          */
632
633         check_acl = ISC_TRUE;   /* Keep compiler happy. */
634         queryacl = NULL;
635
636         /*
637          * Get the current version of this database.
638          */
639         dbversion = query_findversion(client, db, &new_zone);
640         if (dbversion == NULL) {
641                 result = DNS_R_SERVFAIL;
642                 goto fail;
643         }
644         if (new_zone) {
645                 check_acl = ISC_TRUE;
646         } else if (!dbversion->queryok) {
647                 goto refuse;
648         } else {
649                 check_acl = ISC_FALSE;
650         }
651
652         queryacl = dns_zone_getqueryacl(zone);
653         if (queryacl == NULL) {
654                 queryacl = client->view->queryacl;
655                 if ((client->query.attributes &
656                      NS_QUERYATTR_QUERYOKVALID) != 0) {
657                         /*
658                          * We've evaluated the view's queryacl already.  If
659                          * NS_QUERYATTR_QUERYOK is set, then the client is
660                          * allowed to make queries, otherwise the query should
661                          * be refused.
662                          */
663                         check_acl = ISC_FALSE;
664                         if ((client->query.attributes &
665                              NS_QUERYATTR_QUERYOK) == 0)
666                                 goto refuse;
667                 } else {
668                         /*
669                          * We haven't evaluated the view's queryacl yet.
670                          */
671                         check_acl = ISC_TRUE;
672                 }
673         }
674
675         if (check_acl) {
676                 isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
677
678                 result = ns_client_checkaclsilent(client, NULL, queryacl,
679                                                   ISC_TRUE);
680                 if (log) {
681                         char msg[NS_CLIENT_ACLMSGSIZE("query")];
682                         if (result == ISC_R_SUCCESS) {
683                                 if (isc_log_wouldlog(ns_g_lctx,
684                                                      ISC_LOG_DEBUG(3)))
685                                 {
686                                         ns_client_aclmsg("query", name, qtype,
687                                                          client->view->rdclass,
688                                                          msg, sizeof(msg));
689                                         ns_client_log(client,
690                                                       DNS_LOGCATEGORY_SECURITY,
691                                                       NS_LOGMODULE_QUERY,
692                                                       ISC_LOG_DEBUG(3),
693                                                       "%s approved", msg);
694                                 }
695                         } else {
696                                 ns_client_aclmsg("query", name, qtype,
697                                                  client->view->rdclass,
698                                                  msg, sizeof(msg));
699                                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
700                                               NS_LOGMODULE_QUERY, ISC_LOG_INFO,
701                                               "%s denied", msg);
702                         }
703                 }
704
705                 if (queryacl == client->view->queryacl) {
706                         if (result == ISC_R_SUCCESS) {
707                                 /*
708                                  * We were allowed by the default
709                                  * "allow-query" ACL.  Remember this so we
710                                  * don't have to check again.
711                                  */
712                                 client->query.attributes |=
713                                         NS_QUERYATTR_QUERYOK;
714                         }
715                         /*
716                          * We've now evaluated the view's query ACL, and
717                          * the NS_QUERYATTR_QUERYOK attribute is now valid.
718                          */
719                         client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
720                 }
721
722                 if (result != ISC_R_SUCCESS)
723                         goto refuse;
724         }
725
726         /* Approved. */
727
728         /*
729          * Remember the result of the ACL check so we
730          * don't have to check again.
731          */
732         dbversion->queryok = ISC_TRUE;
733
734         /* Transfer ownership, if necessary. */
735         if (versionp != NULL)
736                 *versionp = dbversion->version;
737
738         return (ISC_R_SUCCESS);
739
740  refuse:
741         return (DNS_R_REFUSED);
742
743  fail:
744         return (result);
745 }
746
747 static inline isc_result_t
748 query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
749                 unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
750                 dns_dbversion_t **versionp)
751 {
752         isc_result_t result;
753         unsigned int ztoptions;
754         dns_zone_t *zone = NULL;
755         dns_db_t *db = NULL;
756         isc_boolean_t partial = ISC_FALSE;
757
758         REQUIRE(zonep != NULL && *zonep == NULL);
759         REQUIRE(dbp != NULL && *dbp == NULL);
760
761         /*%
762          * Find a zone database to answer the query.
763          */
764         ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
765                 DNS_ZTFIND_NOEXACT : 0;
766
767         result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
768                              &zone);
769         if (result == DNS_R_PARTIALMATCH)
770                 partial = ISC_TRUE;
771         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
772                 result = dns_zone_getdb(zone, &db);
773
774         if (result != ISC_R_SUCCESS)
775                 goto fail;
776
777         result = query_validatezonedb(client, name, qtype, options, zone, db,
778                                       versionp);
779
780         if (result != ISC_R_SUCCESS)
781                 goto fail;
782
783         /* Transfer ownership. */
784         *zonep = zone;
785         *dbp = db;
786
787         if (partial && (options & DNS_GETDB_PARTIAL) != 0)
788                 return (DNS_R_PARTIALMATCH);
789         return (ISC_R_SUCCESS);
790
791  fail:
792         if (zone != NULL)
793                 dns_zone_detach(&zone);
794         if (db != NULL)
795                 dns_db_detach(&db);
796
797         return (result);
798 }
799
800 static inline isc_result_t
801 query_getcachedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
802                  dns_db_t **dbp, unsigned int options)
803 {
804         isc_result_t result;
805         isc_boolean_t check_acl;
806         dns_db_t *db = NULL;
807
808         REQUIRE(dbp != NULL && *dbp == NULL);
809
810         /*%
811          * Find a cache database to answer the query.
812          * This may fail with DNS_R_REFUSED if the client
813          * is not allowed to use the cache.
814          */
815
816         if (!USECACHE(client))
817                 return (DNS_R_REFUSED);
818         dns_db_attach(client->view->cachedb, &db);
819
820         if ((client->query.attributes &
821              NS_QUERYATTR_QUERYOKVALID) != 0) {
822                 /*
823                  * We've evaluated the view's queryacl already.  If
824                  * NS_QUERYATTR_QUERYOK is set, then the client is
825                  * allowed to make queries, otherwise the query should
826                  * be refused.
827                  */
828                 check_acl = ISC_FALSE;
829                 if ((client->query.attributes &
830                      NS_QUERYATTR_QUERYOK) == 0)
831                         goto refuse;
832         } else {
833                 /*
834                  * We haven't evaluated the view's queryacl yet.
835                  */
836                 check_acl = ISC_TRUE;
837         }
838
839         if (check_acl) {
840                 isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
841                 char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
842
843                 result = ns_client_checkaclsilent(client, NULL,
844                                                   client->view->queryacl,
845                                                   ISC_TRUE);
846                 if (result == ISC_R_SUCCESS) {
847                         /*
848                          * We were allowed by the default
849                          * "allow-query" ACL.  Remember this so we
850                          * don't have to check again.
851                          */
852                         client->query.attributes |=
853                                 NS_QUERYATTR_QUERYOK;
854                         if (log && isc_log_wouldlog(ns_g_lctx,
855                                                      ISC_LOG_DEBUG(3)))
856                         {
857                                 ns_client_aclmsg("query (cache)", name, qtype,
858                                                  client->view->rdclass,
859                                                  msg, sizeof(msg));
860                                 ns_client_log(client,
861                                               DNS_LOGCATEGORY_SECURITY,
862                                               NS_LOGMODULE_QUERY,
863                                               ISC_LOG_DEBUG(3),
864                                               "%s approved", msg);
865                         }
866                 } else if (log) {
867                         ns_client_aclmsg("query (cache)", name, qtype,
868                                          client->view->rdclass, msg,
869                                          sizeof(msg));
870                         ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
871                                       NS_LOGMODULE_QUERY, ISC_LOG_INFO,
872                                       "%s denied", msg);
873                 }
874                 /*
875                  * We've now evaluated the view's query ACL, and
876                  * the NS_QUERYATTR_QUERYOK attribute is now valid.
877                  */
878                 client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
879
880                 if (result != ISC_R_SUCCESS)
881                         goto refuse;
882         }
883
884         /* Approved. */
885
886         /* Transfer ownership. */
887         *dbp = db;
888
889         return (ISC_R_SUCCESS);
890
891  refuse:
892         result = DNS_R_REFUSED;
893
894         if (db != NULL)
895                 dns_db_detach(&db);
896
897         return (result);
898 }
899
900
901 static inline isc_result_t
902 query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
903             unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
904             dns_dbversion_t **versionp, isc_boolean_t *is_zonep)
905 {
906         isc_result_t result;
907
908 #ifdef DLZ
909         isc_result_t tresult;
910         unsigned int namelabels;
911         unsigned int zonelabels;
912         dns_zone_t *zone = NULL;
913         dns_db_t *tdbp;
914
915         REQUIRE(zonep != NULL && *zonep == NULL);
916
917         tdbp = NULL;
918
919         /* Calculate how many labels are in name. */
920         namelabels = dns_name_countlabels(name);
921         zonelabels = 0;
922
923         /* Try to find name in bind's standard database. */
924         result = query_getzonedb(client, name, qtype, options, &zone,
925                                  dbp, versionp);
926
927         /* See how many labels are in the zone's name.    */
928         if (result == ISC_R_SUCCESS && zone != NULL)
929                 zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
930         /*
931          * If # zone labels < # name labels, try to find an even better match
932          * Only try if a DLZ driver is loaded for this view
933          */
934         if (zonelabels < namelabels && client->view->dlzdatabase != NULL) {
935                 tresult = dns_dlzfindzone(client->view, name,
936                                           zonelabels, &tdbp);
937                  /* If we successful, we found a better match. */
938                 if (tresult == ISC_R_SUCCESS) {
939                         /*
940                          * If the previous search returned a zone, detach it.
941                          */
942                         if (zone != NULL)
943                                 dns_zone_detach(&zone);
944
945                         /*
946                          * If the previous search returned a database,
947                          * detach it.
948                          */
949                         if (*dbp != NULL)
950                                 dns_db_detach(dbp);
951
952                         /*
953                          * If the previous search returned a version, clear it.
954                          */
955                         *versionp = NULL;
956
957                         /*
958                          * Get our database version.
959                          */
960                         dns_db_currentversion(tdbp, versionp);
961
962                         /*
963                          * Be sure to return our database.
964                          */
965                         *dbp = tdbp;
966
967                         /*
968                          * We return a null zone, No stats for DLZ zones.
969                          */
970                         zone = NULL;
971                         result = tresult;
972                 }
973         }
974 #else
975         result = query_getzonedb(client, name, qtype, options,
976                                  zonep, dbp, versionp);
977 #endif
978
979         /* If successful, Transfer ownership of zone. */
980         if (result == ISC_R_SUCCESS) {
981 #ifdef DLZ
982                 *zonep = zone;
983 #endif
984                 /*
985                  * If neither attempt above succeeded, return the cache instead
986                  */
987                 *is_zonep = ISC_TRUE;
988         } else if (result == ISC_R_NOTFOUND) {
989                 result = query_getcachedb(client, name, qtype, dbp, options);
990                 *is_zonep = ISC_FALSE;
991         }
992         return (result);
993 }
994
995 static inline isc_boolean_t
996 query_isduplicate(ns_client_t *client, dns_name_t *name,
997                   dns_rdatatype_t type, dns_name_t **mnamep)
998 {
999         dns_section_t section;
1000         dns_name_t *mname = NULL;
1001         isc_result_t result;
1002
1003         CTRACE("query_isduplicate");
1004
1005         for (section = DNS_SECTION_ANSWER;
1006              section <= DNS_SECTION_ADDITIONAL;
1007              section++) {
1008                 result = dns_message_findname(client->message, section,
1009                                               name, type, 0, &mname, NULL);
1010                 if (result == ISC_R_SUCCESS) {
1011                         /*
1012                          * We've already got this RRset in the response.
1013                          */
1014                         CTRACE("query_isduplicate: true: done");
1015                         return (ISC_TRUE);
1016                 } else if (result == DNS_R_NXRRSET) {
1017                         /*
1018                          * The name exists, but the rdataset does not.
1019                          */
1020                         if (section == DNS_SECTION_ADDITIONAL)
1021                                 break;
1022                 } else
1023                         RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
1024                 mname = NULL;
1025         }
1026
1027         /*
1028          * If the dns_name_t we're looking up is already in the message,
1029          * we don't want to trigger the caller's name replacement logic.
1030          */
1031         if (name == mname)
1032                 mname = NULL;
1033
1034         *mnamep = mname;
1035
1036         CTRACE("query_isduplicate: false: done");
1037         return (ISC_FALSE);
1038 }
1039
1040 static isc_result_t
1041 query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
1042         ns_client_t *client = arg;
1043         isc_result_t result, eresult;
1044         dns_dbnode_t *node;
1045         dns_db_t *db;
1046         dns_name_t *fname, *mname;
1047         dns_rdataset_t *rdataset, *sigrdataset, *trdataset;
1048         isc_buffer_t *dbuf;
1049         isc_buffer_t b;
1050         dns_dbversion_t *version;
1051         isc_boolean_t added_something, need_addname;
1052         dns_zone_t *zone;
1053         dns_rdatatype_t type;
1054
1055         REQUIRE(NS_CLIENT_VALID(client));
1056         REQUIRE(qtype != dns_rdatatype_any);
1057
1058         if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype))
1059                 return (ISC_R_SUCCESS);
1060
1061         CTRACE("query_addadditional");
1062
1063         /*
1064          * Initialization.
1065          */
1066         eresult = ISC_R_SUCCESS;
1067         fname = NULL;
1068         rdataset = NULL;
1069         sigrdataset = NULL;
1070         trdataset = NULL;
1071         db = NULL;
1072         version = NULL;
1073         node = NULL;
1074         added_something = ISC_FALSE;
1075         need_addname = ISC_FALSE;
1076         zone = NULL;
1077
1078         /*
1079          * We treat type A additional section processing as if it
1080          * were "any address type" additional section processing.
1081          * To avoid multiple lookups, we do an 'any' database
1082          * lookup and iterate over the node.
1083          */
1084         if (qtype == dns_rdatatype_a)
1085                 type = dns_rdatatype_any;
1086         else
1087                 type = qtype;
1088
1089         /*
1090          * Get some resources.
1091          */
1092         dbuf = query_getnamebuf(client);
1093         if (dbuf == NULL)
1094                 goto cleanup;
1095         fname = query_newname(client, dbuf, &b);
1096         rdataset = query_newrdataset(client);
1097         if (fname == NULL || rdataset == NULL)
1098                 goto cleanup;
1099         if (WANTDNSSEC(client)) {
1100                 sigrdataset = query_newrdataset(client);
1101                 if (sigrdataset == NULL)
1102                         goto cleanup;
1103         }
1104
1105         /*
1106          * Look for a zone database that might contain authoritative
1107          * additional data.
1108          */
1109         result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
1110                                  &zone, &db, &version);
1111         if (result != ISC_R_SUCCESS)
1112                 goto try_cache;
1113
1114         CTRACE("query_addadditional: db_find");
1115
1116         /*
1117          * Since we are looking for authoritative data, we do not set
1118          * the GLUEOK flag.  Glue will be looked for later, but not
1119          * necessarily in the same database.
1120          */
1121         node = NULL;
1122         result = dns_db_find(db, name, version, type, client->query.dboptions,
1123                              client->now, &node, fname, rdataset,
1124                              sigrdataset);
1125         if (result == ISC_R_SUCCESS) {
1126                 if (sigrdataset != NULL && !dns_db_issecure(db) &&
1127                     dns_rdataset_isassociated(sigrdataset))
1128                         dns_rdataset_disassociate(sigrdataset);
1129                 goto found;
1130         }
1131
1132         if (dns_rdataset_isassociated(rdataset))
1133                 dns_rdataset_disassociate(rdataset);
1134         if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset))
1135                 dns_rdataset_disassociate(sigrdataset);
1136         if (node != NULL)
1137                 dns_db_detachnode(db, &node);
1138         version = NULL;
1139         dns_db_detach(&db);
1140
1141         /*
1142          * No authoritative data was found.  The cache is our next best bet.
1143          */
1144
1145  try_cache:
1146         result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
1147         if (result != ISC_R_SUCCESS)
1148                 /*
1149                  * Most likely the client isn't allowed to query the cache.
1150                  */
1151                 goto try_glue;
1152         /*
1153          * Attempt to validate glue.
1154          */
1155         if (sigrdataset == NULL) {
1156                 sigrdataset = query_newrdataset(client);
1157                 if (sigrdataset == NULL)
1158                         goto cleanup;
1159         }
1160         result = dns_db_find(db, name, version, type,
1161                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1162                              client->now, &node, fname, rdataset,
1163                              sigrdataset);
1164         if (result == DNS_R_GLUE &&
1165             validate(client, db, fname, rdataset, sigrdataset))
1166                 result = ISC_R_SUCCESS;
1167         if (!WANTDNSSEC(client))
1168                 query_putrdataset(client, &sigrdataset);
1169         if (result == ISC_R_SUCCESS)
1170                 goto found;
1171
1172         if (dns_rdataset_isassociated(rdataset))
1173                 dns_rdataset_disassociate(rdataset);
1174         if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset))
1175                 dns_rdataset_disassociate(sigrdataset);
1176         if (node != NULL)
1177                 dns_db_detachnode(db, &node);
1178         dns_db_detach(&db);
1179
1180  try_glue:
1181         /*
1182          * No cached data was found.  Glue is our last chance.
1183          * RFC1035 sayeth:
1184          *
1185          *      NS records cause both the usual additional section
1186          *      processing to locate a type A record, and, when used
1187          *      in a referral, a special search of the zone in which
1188          *      they reside for glue information.
1189          *
1190          * This is the "special search".  Note that we must search
1191          * the zone where the NS record resides, not the zone it
1192          * points to, and that we only do the search in the delegation
1193          * case (identified by client->query.gluedb being set).
1194          */
1195
1196         if (client->query.gluedb == NULL)
1197                 goto cleanup;
1198
1199         /*
1200          * Don't poison caches using the bailiwick protection model.
1201          */
1202         if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
1203                 goto cleanup;
1204
1205         dns_db_attach(client->query.gluedb, &db);
1206         result = dns_db_find(db, name, version, type,
1207                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1208                              client->now, &node, fname, rdataset,
1209                              sigrdataset);
1210         if (!(result == ISC_R_SUCCESS ||
1211               result == DNS_R_ZONECUT ||
1212               result == DNS_R_GLUE))
1213                 goto cleanup;
1214
1215  found:
1216         /*
1217          * We have found a potential additional data rdataset, or
1218          * at least a node to iterate over.
1219          */
1220         query_keepname(client, fname, dbuf);
1221
1222         /*
1223          * If we have an rdataset, add it to the additional data
1224          * section.
1225          */
1226         mname = NULL;
1227         if (dns_rdataset_isassociated(rdataset) &&
1228             !query_isduplicate(client, fname, type, &mname)) {
1229                 if (mname != NULL) {
1230                         query_releasename(client, &fname);
1231                         fname = mname;
1232                 } else
1233                         need_addname = ISC_TRUE;
1234                 ISC_LIST_APPEND(fname->list, rdataset, link);
1235                 trdataset = rdataset;
1236                 rdataset = NULL;
1237                 added_something = ISC_TRUE;
1238                 /*
1239                  * Note: we only add SIGs if we've added the type they cover,
1240                  * so we do not need to check if the SIG rdataset is already
1241                  * in the response.
1242                  */
1243                 if (sigrdataset != NULL &&
1244                     dns_rdataset_isassociated(sigrdataset))
1245                 {
1246                         ISC_LIST_APPEND(fname->list, sigrdataset, link);
1247                         sigrdataset = NULL;
1248                 }
1249         }
1250
1251         if (qtype == dns_rdatatype_a) {
1252                 /*
1253                  * We now go looking for A and AAAA records, along with
1254                  * their signatures.
1255                  *
1256                  * XXXRTH  This code could be more efficient.
1257                  */
1258                 if (rdataset != NULL) {
1259                         if (dns_rdataset_isassociated(rdataset))
1260                                 dns_rdataset_disassociate(rdataset);
1261                 } else {
1262                         rdataset = query_newrdataset(client);
1263                         if (rdataset == NULL)
1264                                 goto addname;
1265                 }
1266                 if (sigrdataset != NULL) {
1267                         if (dns_rdataset_isassociated(sigrdataset))
1268                                 dns_rdataset_disassociate(sigrdataset);
1269                 } else if (WANTDNSSEC(client)) {
1270                         sigrdataset = query_newrdataset(client);
1271                         if (sigrdataset == NULL)
1272                                 goto addname;
1273                 }
1274                 result = dns_db_findrdataset(db, node, version,
1275                                              dns_rdatatype_a, 0,
1276                                              client->now, rdataset,
1277                                              sigrdataset);
1278                 if (result == DNS_R_NCACHENXDOMAIN)
1279                         goto addname;
1280                 if (result == DNS_R_NCACHENXRRSET) {
1281                         dns_rdataset_disassociate(rdataset);
1282                         /*
1283                          * Negative cache entries don't have sigrdatasets.
1284                          */
1285                         INSIST(sigrdataset == NULL ||
1286                                ! dns_rdataset_isassociated(sigrdataset));
1287                 }
1288                 if (result == ISC_R_SUCCESS) {
1289                         mname = NULL;
1290                         if (!query_isduplicate(client, fname,
1291                                                dns_rdatatype_a, &mname)) {
1292                                 if (mname != NULL) {
1293                                         query_releasename(client, &fname);
1294                                         fname = mname;
1295                                 } else
1296                                         need_addname = ISC_TRUE;
1297                                 ISC_LIST_APPEND(fname->list, rdataset, link);
1298                                 added_something = ISC_TRUE;
1299                                 if (sigrdataset != NULL &&
1300                                     dns_rdataset_isassociated(sigrdataset))
1301                                 {
1302                                         ISC_LIST_APPEND(fname->list,
1303                                                         sigrdataset, link);
1304                                         sigrdataset =
1305                                                 query_newrdataset(client);
1306                                 }
1307                                 rdataset = query_newrdataset(client);
1308                                 if (rdataset == NULL)
1309                                         goto addname;
1310                                 if (WANTDNSSEC(client) && sigrdataset == NULL)
1311                                         goto addname;
1312                         } else {
1313                                 dns_rdataset_disassociate(rdataset);
1314                                 if (sigrdataset != NULL &&
1315                                     dns_rdataset_isassociated(sigrdataset))
1316                                         dns_rdataset_disassociate(sigrdataset);
1317                         }
1318                 }
1319                 result = dns_db_findrdataset(db, node, version,
1320                                              dns_rdatatype_aaaa, 0,
1321                                              client->now, rdataset,
1322                                              sigrdataset);
1323                 if (result == DNS_R_NCACHENXDOMAIN)
1324                         goto addname;
1325                 if (result == DNS_R_NCACHENXRRSET) {
1326                         dns_rdataset_disassociate(rdataset);
1327                         INSIST(sigrdataset == NULL ||
1328                                ! dns_rdataset_isassociated(sigrdataset));
1329                 }
1330                 if (result == ISC_R_SUCCESS) {
1331                         mname = NULL;
1332                         if (!query_isduplicate(client, fname,
1333                                                dns_rdatatype_aaaa, &mname)) {
1334                                 if (mname != NULL) {
1335                                         query_releasename(client, &fname);
1336                                         fname = mname;
1337                                 } else
1338                                         need_addname = ISC_TRUE;
1339                                 ISC_LIST_APPEND(fname->list, rdataset, link);
1340                                 added_something = ISC_TRUE;
1341                                 if (sigrdataset != NULL &&
1342                                     dns_rdataset_isassociated(sigrdataset))
1343                                 {
1344                                         ISC_LIST_APPEND(fname->list,
1345                                                         sigrdataset, link);
1346                                         sigrdataset = NULL;
1347                                 }
1348                                 rdataset = NULL;
1349                         }
1350                 }
1351         }
1352
1353  addname:
1354         CTRACE("query_addadditional: addname");
1355         /*
1356          * If we haven't added anything, then we're done.
1357          */
1358         if (!added_something)
1359                 goto cleanup;
1360
1361         /*
1362          * We may have added our rdatasets to an existing name, if so, then
1363          * need_addname will be ISC_FALSE.  Whether we used an existing name
1364          * or a new one, we must set fname to NULL to prevent cleanup.
1365          */
1366         if (need_addname)
1367                 dns_message_addname(client->message, fname,
1368                                     DNS_SECTION_ADDITIONAL);
1369         fname = NULL;
1370
1371         /*
1372          * In a few cases, we want to add additional data for additional
1373          * data.  It's simpler to just deal with special cases here than
1374          * to try to create a general purpose mechanism and allow the
1375          * rdata implementations to do it themselves.
1376          *
1377          * This involves recursion, but the depth is limited.  The
1378          * most complex case is adding a SRV rdataset, which involves
1379          * recursing to add address records, which in turn can cause
1380          * recursion to add KEYs.
1381          */
1382         if (type == dns_rdatatype_srv && trdataset != NULL) {
1383                 /*
1384                  * If we're adding SRV records to the additional data
1385                  * section, it's helpful if we add the SRV additional data
1386                  * as well.
1387                  */
1388                 eresult = dns_rdataset_additionaldata(trdataset,
1389                                                       query_addadditional,
1390                                                       client);
1391         }
1392
1393  cleanup:
1394         CTRACE("query_addadditional: cleanup");
1395         query_putrdataset(client, &rdataset);
1396         if (sigrdataset != NULL)
1397                 query_putrdataset(client, &sigrdataset);
1398         if (fname != NULL)
1399                 query_releasename(client, &fname);
1400         if (node != NULL)
1401                 dns_db_detachnode(db, &node);
1402         if (db != NULL)
1403                 dns_db_detach(&db);
1404         if (zone != NULL)
1405                 dns_zone_detach(&zone);
1406
1407         CTRACE("query_addadditional: done");
1408         return (eresult);
1409 }
1410
1411 static inline void
1412 query_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base,
1413                    dns_rdatasetadditional_t additionaltype,
1414                    dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp,
1415                    dns_dbversion_t **versionp, dns_dbnode_t **nodep,
1416                    dns_name_t *fname)
1417 {
1418         dns_rdataset_t *rdataset;
1419
1420         while  ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
1421                 ISC_LIST_UNLINK(fname->list, rdataset, link);
1422                 query_putrdataset(client, &rdataset);
1423         }
1424         if (*versionp != NULL)
1425                 dns_db_closeversion(*dbp, versionp, ISC_FALSE);
1426         if (*nodep != NULL)
1427                 dns_db_detachnode(*dbp, nodep);
1428         if (*dbp != NULL)
1429                 dns_db_detach(dbp);
1430         if (*zonep != NULL)
1431                 dns_zone_detach(zonep);
1432         (void)dns_rdataset_putadditional(client->view->acache, rdataset_base,
1433                                          additionaltype, type);
1434 }
1435
1436 static inline isc_result_t
1437 query_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0,
1438                    dns_dbversion_t *version)
1439 {
1440         isc_result_t result = ISC_R_SUCCESS;
1441         dns_dbversion_t *version_current = NULL;
1442         dns_db_t *db_current = db0;
1443
1444         if (db_current == NULL) {
1445                 result = dns_zone_getdb(zone, &db_current);
1446                 if (result != ISC_R_SUCCESS)
1447                         return (result);
1448         }
1449         dns_db_currentversion(db_current, &version_current);
1450         if (db_current != db || version_current != version) {
1451                 result = ISC_R_FAILURE;
1452                 goto cleanup;
1453         }
1454
1455  cleanup:
1456         dns_db_closeversion(db_current, &version_current, ISC_FALSE);
1457         if (db0 == NULL && db_current != NULL)
1458                 dns_db_detach(&db_current);
1459
1460         return (result);
1461 }
1462
1463 static isc_result_t
1464 query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
1465         client_additionalctx_t *additionalctx = arg;
1466         dns_rdataset_t *rdataset_base;
1467         ns_client_t *client;
1468         isc_result_t result, eresult;
1469         dns_dbnode_t *node, *cnode;
1470         dns_db_t *db, *cdb;
1471         dns_name_t *fname, *mname0, cfname;
1472         dns_rdataset_t *rdataset, *sigrdataset;
1473         dns_rdataset_t *crdataset, *crdataset_next;
1474         isc_buffer_t *dbuf;
1475         isc_buffer_t b;
1476         dns_dbversion_t *version, *cversion;
1477         isc_boolean_t added_something, need_addname, needadditionalcache;
1478         isc_boolean_t need_sigrrset;
1479         dns_zone_t *zone;
1480         dns_rdatatype_t type;
1481         dns_rdatasetadditional_t additionaltype;
1482
1483         if (qtype != dns_rdatatype_a) {
1484                 /*
1485                  * This function is optimized for "address" types.  For other
1486                  * types, use a generic routine.
1487                  * XXX: ideally, this function should be generic enough.
1488                  */
1489                 return (query_addadditional(additionalctx->client,
1490                                             name, qtype));
1491         }
1492
1493         /*
1494          * Initialization.
1495          */
1496         rdataset_base = additionalctx->rdataset;
1497         client = additionalctx->client;
1498         REQUIRE(NS_CLIENT_VALID(client));
1499         eresult = ISC_R_SUCCESS;
1500         fname = NULL;
1501         rdataset = NULL;
1502         sigrdataset = NULL;
1503         db = NULL;
1504         cdb = NULL;
1505         version = NULL;
1506         cversion = NULL;
1507         node = NULL;
1508         cnode = NULL;
1509         added_something = ISC_FALSE;
1510         need_addname = ISC_FALSE;
1511         zone = NULL;
1512         needadditionalcache = ISC_FALSE;
1513         additionaltype = dns_rdatasetadditional_fromauth;
1514         dns_name_init(&cfname, NULL);
1515
1516         CTRACE("query_addadditional2");
1517
1518         /*
1519          * We treat type A additional section processing as if it
1520          * were "any address type" additional section processing.
1521          * To avoid multiple lookups, we do an 'any' database
1522          * lookup and iterate over the node.
1523          * XXXJT: this approach can cause a suboptimal result when the cache
1524          * DB only has partial address types and the glue DB has remaining
1525          * ones.
1526          */
1527         type = dns_rdatatype_any;
1528
1529         /*
1530          * Get some resources.
1531          */
1532         dbuf = query_getnamebuf(client);
1533         if (dbuf == NULL)
1534                 goto cleanup;
1535         fname = query_newname(client, dbuf, &b);
1536         if (fname == NULL)
1537                 goto cleanup;
1538         dns_name_setbuffer(&cfname, &b); /* share the buffer */
1539
1540         /* Check additional cache */
1541         result = dns_rdataset_getadditional(rdataset_base, additionaltype,
1542                                             type, client->view->acache, &zone,
1543                                             &cdb, &cversion, &cnode, &cfname,
1544                                             client->message, client->now);
1545         if (result != ISC_R_SUCCESS)
1546                 goto findauthdb;
1547         if (zone == NULL) {
1548                 CTRACE("query_addadditional2: auth zone not found");
1549                 goto try_cache;
1550         }
1551
1552         /* Is the cached DB up-to-date? */
1553         result = query_iscachevalid(zone, cdb, NULL, cversion);
1554         if (result != ISC_R_SUCCESS) {
1555                 CTRACE("query_addadditional2: old auth additional cache");
1556                 query_discardcache(client, rdataset_base, additionaltype,
1557                                    type, &zone, &cdb, &cversion, &cnode,
1558                                    &cfname);
1559                 goto findauthdb;
1560         }
1561
1562         if (cnode == NULL) {
1563                 /*
1564                  * We have a negative cache.  We don't have to check the zone
1565                  * ACL, since the result (not using this zone) would be same
1566                  * regardless of the result.
1567                  */
1568                 CTRACE("query_addadditional2: negative auth additional cache");
1569                 dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1570                 dns_db_detach(&cdb);
1571                 dns_zone_detach(&zone);
1572                 goto try_cache;
1573         }
1574
1575         result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG,
1576                                       zone, cdb, NULL);
1577         if (result != ISC_R_SUCCESS) {
1578                 query_discardcache(client, rdataset_base, additionaltype,
1579                                    type, &zone, &cdb, &cversion, &cnode,
1580                                    &cfname);
1581                 goto try_cache;
1582         }
1583
1584         /* We've got an active cache. */
1585         CTRACE("query_addadditional2: auth additional cache");
1586         dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1587         db = cdb;
1588         node = cnode;
1589         dns_name_clone(&cfname, fname);
1590         query_keepname(client, fname, dbuf);
1591         goto foundcache;
1592
1593         /*
1594          * Look for a zone database that might contain authoritative
1595          * additional data.
1596          */
1597  findauthdb:
1598         result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
1599                                  &zone, &db, &version);
1600         if (result != ISC_R_SUCCESS) {
1601                 /* Cache the negative result */
1602                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1603                                                  type, client->view->acache,
1604                                                  NULL, NULL, NULL, NULL,
1605                                                  NULL);
1606                 goto try_cache;
1607         }
1608
1609         CTRACE("query_addadditional2: db_find");
1610
1611         /*
1612          * Since we are looking for authoritative data, we do not set
1613          * the GLUEOK flag.  Glue will be looked for later, but not
1614          * necessarily in the same database.
1615          */
1616         node = NULL;
1617         result = dns_db_find(db, name, version, type, client->query.dboptions,
1618                              client->now, &node, fname, NULL, NULL);
1619         if (result == ISC_R_SUCCESS)
1620                 goto found;
1621
1622         /* Cache the negative result */
1623         (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1624                                          type, client->view->acache, zone, db,
1625                                          version, NULL, fname);
1626
1627         if (node != NULL)
1628                 dns_db_detachnode(db, &node);
1629         version = NULL;
1630         dns_db_detach(&db);
1631
1632         /*
1633          * No authoritative data was found.  The cache is our next best bet.
1634          */
1635
1636  try_cache:
1637         additionaltype = dns_rdatasetadditional_fromcache;
1638         result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
1639         if (result != ISC_R_SUCCESS)
1640                 /*
1641                  * Most likely the client isn't allowed to query the cache.
1642                  */
1643                 goto try_glue;
1644
1645         result = dns_db_find(db, name, version, type,
1646                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1647                              client->now, &node, fname, NULL, NULL);
1648         if (result == ISC_R_SUCCESS)
1649                 goto found;
1650
1651         if (node != NULL)
1652                 dns_db_detachnode(db, &node);
1653         dns_db_detach(&db);
1654
1655  try_glue:
1656         /*
1657          * No cached data was found.  Glue is our last chance.
1658          * RFC1035 sayeth:
1659          *
1660          *      NS records cause both the usual additional section
1661          *      processing to locate a type A record, and, when used
1662          *      in a referral, a special search of the zone in which
1663          *      they reside for glue information.
1664          *
1665          * This is the "special search".  Note that we must search
1666          * the zone where the NS record resides, not the zone it
1667          * points to, and that we only do the search in the delegation
1668          * case (identified by client->query.gluedb being set).
1669          */
1670         if (client->query.gluedb == NULL)
1671                 goto cleanup;
1672
1673         /*
1674          * Don't poison caches using the bailiwick protection model.
1675          */
1676         if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
1677                 goto cleanup;
1678
1679         /* Check additional cache */
1680         additionaltype = dns_rdatasetadditional_fromglue;
1681         result = dns_rdataset_getadditional(rdataset_base, additionaltype,
1682                                             type, client->view->acache, NULL,
1683                                             &cdb, &cversion, &cnode, &cfname,
1684                                             client->message, client->now);
1685         if (result != ISC_R_SUCCESS)
1686                 goto findglue;
1687
1688         result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion);
1689         if (result != ISC_R_SUCCESS) {
1690                 CTRACE("query_addadditional2: old glue additional cache");
1691                 query_discardcache(client, rdataset_base, additionaltype,
1692                                    type, &zone, &cdb, &cversion, &cnode,
1693                                    &cfname);
1694                 goto findglue;
1695         }
1696
1697         if (cnode == NULL) {
1698                 /* We have a negative cache. */
1699                 CTRACE("query_addadditional2: negative glue additional cache");
1700                 dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1701                 dns_db_detach(&cdb);
1702                 goto cleanup;
1703         }
1704
1705         /* Cache hit. */
1706         CTRACE("query_addadditional2: glue additional cache");
1707         dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1708         db = cdb;
1709         node = cnode;
1710         dns_name_clone(&cfname, fname);
1711         query_keepname(client, fname, dbuf);
1712         goto foundcache;
1713
1714  findglue:
1715         dns_db_attach(client->query.gluedb, &db);
1716         result = dns_db_find(db, name, version, type,
1717                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1718                              client->now, &node, fname, NULL, NULL);
1719         if (!(result == ISC_R_SUCCESS ||
1720               result == DNS_R_ZONECUT ||
1721               result == DNS_R_GLUE)) {
1722                 /* cache the negative result */
1723                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1724                                                  type, client->view->acache,
1725                                                  NULL, db, version, NULL,
1726                                                  fname);
1727                 goto cleanup;
1728         }
1729
1730  found:
1731         /*
1732          * We have found a DB node to iterate over from a DB.
1733          * We are going to look for address RRsets (i.e., A and AAAA) in the DB
1734          * node we've just found.  We'll then store the complete information
1735          * in the additional data cache.
1736          */
1737         dns_name_clone(fname, &cfname);
1738         query_keepname(client, fname, dbuf);
1739         needadditionalcache = ISC_TRUE;
1740
1741         rdataset = query_newrdataset(client);
1742         if (rdataset == NULL)
1743                 goto cleanup;
1744
1745         sigrdataset = query_newrdataset(client);
1746         if (sigrdataset == NULL)
1747                 goto cleanup;
1748
1749         /*
1750          * Find A RRset with sig RRset.  Even if we don't find a sig RRset
1751          * for a client using DNSSEC, we'll continue the process to make a
1752          * complete list to be cached.  However, we need to cancel the
1753          * caching when something unexpected happens, in order to avoid
1754          * caching incomplete information.
1755          */
1756         result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0,
1757                                      client->now, rdataset, sigrdataset);
1758         /*
1759          * If we can't promote glue/pending from the cache to secure
1760          * then drop it.
1761          */
1762         if (result == ISC_R_SUCCESS &&
1763             additionaltype == dns_rdatasetadditional_fromcache &&
1764             (rdataset->trust == dns_trust_pending ||
1765              rdataset->trust == dns_trust_glue) &&
1766             !validate(client, db, fname, rdataset, sigrdataset)) {
1767                 dns_rdataset_disassociate(rdataset);
1768                 if (dns_rdataset_isassociated(sigrdataset))
1769                         dns_rdataset_disassociate(sigrdataset);
1770                 result = ISC_R_NOTFOUND;
1771         }
1772         if (result == DNS_R_NCACHENXDOMAIN)
1773                 goto setcache;
1774         if (result == DNS_R_NCACHENXRRSET) {
1775                 dns_rdataset_disassociate(rdataset);
1776                 /*
1777                  * Negative cache entries don't have sigrdatasets.
1778                  */
1779                 INSIST(! dns_rdataset_isassociated(sigrdataset));
1780         }
1781         if (result == ISC_R_SUCCESS) {
1782                 /* Remember the result as a cache */
1783                 ISC_LIST_APPEND(cfname.list, rdataset, link);
1784                 if (dns_rdataset_isassociated(sigrdataset)) {
1785                         ISC_LIST_APPEND(cfname.list, sigrdataset, link);
1786                         sigrdataset = query_newrdataset(client);
1787                 }
1788                 rdataset = query_newrdataset(client);
1789                 if (sigrdataset == NULL || rdataset == NULL) {
1790                         /* do not cache incomplete information */
1791                         goto foundcache;
1792                 }
1793         }
1794
1795         /* Find AAAA RRset with sig RRset */
1796         result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa,
1797                                      0, client->now, rdataset, sigrdataset);
1798         /*
1799          * If we can't promote glue/pending from the cache to secure
1800          * then drop it.
1801          */
1802         if (result == ISC_R_SUCCESS &&
1803             additionaltype == dns_rdatasetadditional_fromcache &&
1804             (rdataset->trust == dns_trust_pending ||
1805              rdataset->trust == dns_trust_glue) &&
1806             !validate(client, db, fname, rdataset, sigrdataset)) {
1807                 dns_rdataset_disassociate(rdataset);
1808                 if (dns_rdataset_isassociated(sigrdataset))
1809                         dns_rdataset_disassociate(sigrdataset);
1810                 result = ISC_R_NOTFOUND;
1811         }
1812         if (result == ISC_R_SUCCESS) {
1813                 ISC_LIST_APPEND(cfname.list, rdataset, link);
1814                 rdataset = NULL;
1815                 if (dns_rdataset_isassociated(sigrdataset)) {
1816                         ISC_LIST_APPEND(cfname.list, sigrdataset, link);
1817                         sigrdataset = NULL;
1818                 }
1819         }
1820
1821  setcache:
1822         /*
1823          * Set the new result in the cache if required.  We do not support
1824          * caching additional data from a cache DB.
1825          */
1826         if (needadditionalcache == ISC_TRUE &&
1827             (additionaltype == dns_rdatasetadditional_fromauth ||
1828              additionaltype == dns_rdatasetadditional_fromglue)) {
1829                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1830                                                  type, client->view->acache,
1831                                                  zone, db, version, node,
1832                                                  &cfname);
1833         }
1834
1835  foundcache:
1836         need_sigrrset = ISC_FALSE;
1837         mname0 = NULL;
1838         for (crdataset = ISC_LIST_HEAD(cfname.list);
1839              crdataset != NULL;
1840              crdataset = crdataset_next) {
1841                 dns_name_t *mname;
1842
1843                 crdataset_next = ISC_LIST_NEXT(crdataset, link);
1844
1845                 mname = NULL;
1846                 if (crdataset->type == dns_rdatatype_a ||
1847                     crdataset->type == dns_rdatatype_aaaa) {
1848                         if (!query_isduplicate(client, fname, crdataset->type,
1849                                                &mname)) {
1850                                 if (mname != NULL) {
1851                                         /*
1852                                          * A different type of this name is
1853                                          * already stored in the additional
1854                                          * section.  We'll reuse the name.
1855                                          * Note that this should happen at most
1856                                          * once.  Otherwise, fname->link could
1857                                          * leak below.
1858                                          */
1859                                         INSIST(mname0 == NULL);
1860
1861                                         query_releasename(client, &fname);
1862                                         fname = mname;
1863                                         mname0 = mname;
1864                                 } else
1865                                         need_addname = ISC_TRUE;
1866                                 ISC_LIST_UNLINK(cfname.list, crdataset, link);
1867                                 ISC_LIST_APPEND(fname->list, crdataset, link);
1868                                 added_something = ISC_TRUE;
1869                                 need_sigrrset = ISC_TRUE;
1870                         } else
1871                                 need_sigrrset = ISC_FALSE;
1872                 } else if (crdataset->type == dns_rdatatype_rrsig &&
1873                            need_sigrrset && WANTDNSSEC(client)) {
1874                         ISC_LIST_UNLINK(cfname.list, crdataset, link);
1875                         ISC_LIST_APPEND(fname->list, crdataset, link);
1876                         added_something = ISC_TRUE; /* just in case */
1877                         need_sigrrset = ISC_FALSE;
1878                 }
1879         }
1880
1881         CTRACE("query_addadditional2: addname");
1882
1883         /*
1884          * If we haven't added anything, then we're done.
1885          */
1886         if (!added_something)
1887                 goto cleanup;
1888
1889         /*
1890          * We may have added our rdatasets to an existing name, if so, then
1891          * need_addname will be ISC_FALSE.  Whether we used an existing name
1892          * or a new one, we must set fname to NULL to prevent cleanup.
1893          */
1894         if (need_addname)
1895                 dns_message_addname(client->message, fname,
1896                                     DNS_SECTION_ADDITIONAL);
1897         fname = NULL;
1898
1899  cleanup:
1900         CTRACE("query_addadditional2: cleanup");
1901
1902         if (rdataset != NULL)
1903                 query_putrdataset(client, &rdataset);
1904         if (sigrdataset != NULL)
1905                 query_putrdataset(client, &sigrdataset);
1906         while  ((crdataset = ISC_LIST_HEAD(cfname.list)) != NULL) {
1907                 ISC_LIST_UNLINK(cfname.list, crdataset, link);
1908                 query_putrdataset(client, &crdataset);
1909         }
1910         if (fname != NULL)
1911                 query_releasename(client, &fname);
1912         if (node != NULL)
1913                 dns_db_detachnode(db, &node);
1914         if (db != NULL)
1915                 dns_db_detach(&db);
1916         if (zone != NULL)
1917                 dns_zone_detach(&zone);
1918
1919         CTRACE("query_addadditional2: done");
1920         return (eresult);
1921 }
1922
1923 static inline void
1924 query_addrdataset(ns_client_t *client, dns_name_t *fname,
1925                   dns_rdataset_t *rdataset)
1926 {
1927         client_additionalctx_t additionalctx;
1928
1929         /*
1930          * Add 'rdataset' and any pertinent additional data to
1931          * 'fname', a name in the response message for 'client'.
1932          */
1933
1934         CTRACE("query_addrdataset");
1935
1936         ISC_LIST_APPEND(fname->list, rdataset, link);
1937
1938         if (client->view->order != NULL)
1939                 rdataset->attributes |= dns_order_find(client->view->order,
1940                                                        fname, rdataset->type,
1941                                                        rdataset->rdclass);
1942         rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
1943
1944         if (NOADDITIONAL(client))
1945                 return;
1946
1947         /*
1948          * Add additional data.
1949          *
1950          * We don't care if dns_rdataset_additionaldata() fails.
1951          */
1952         additionalctx.client = client;
1953         additionalctx.rdataset = rdataset;
1954         (void)dns_rdataset_additionaldata(rdataset, query_addadditional2,
1955                                           &additionalctx);
1956         CTRACE("query_addrdataset: done");
1957 }
1958
1959 static void
1960 query_addrrset(ns_client_t *client, dns_name_t **namep,
1961                dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
1962                isc_buffer_t *dbuf, dns_section_t section)
1963 {
1964         dns_name_t *name, *mname;
1965         dns_rdataset_t *rdataset, *mrdataset, *sigrdataset;
1966         isc_result_t result;
1967
1968         /*%
1969          * To the current response for 'client', add the answer RRset
1970          * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
1971          * owner name '*namep', to section 'section', unless they are
1972          * already there.  Also add any pertinent additional data.
1973          *
1974          * If 'dbuf' is not NULL, then '*namep' is the name whose data is
1975          * stored in 'dbuf'.  In this case, query_addrrset() guarantees that
1976          * when it returns the name will either have been kept or released.
1977          */
1978         CTRACE("query_addrrset");
1979         name = *namep;
1980         rdataset = *rdatasetp;
1981         if (sigrdatasetp != NULL)
1982                 sigrdataset = *sigrdatasetp;
1983         else
1984                 sigrdataset = NULL;
1985         mname = NULL;
1986         mrdataset = NULL;
1987         result = dns_message_findname(client->message, section,
1988                                       name, rdataset->type, rdataset->covers,
1989                                       &mname, &mrdataset);
1990         if (result == ISC_R_SUCCESS) {
1991                 /*
1992                  * We've already got an RRset of the given name and type.
1993                  * There's nothing else to do;
1994                  */
1995                 CTRACE("query_addrrset: dns_message_findname succeeded: done");
1996                 if (dbuf != NULL)
1997                         query_releasename(client, namep);
1998                 return;
1999         } else if (result == DNS_R_NXDOMAIN) {
2000                 /*
2001                  * The name doesn't exist.
2002                  */
2003                 if (dbuf != NULL)
2004                         query_keepname(client, name, dbuf);
2005                 dns_message_addname(client->message, name, section);
2006                 *namep = NULL;
2007                 mname = name;
2008         } else {
2009                 RUNTIME_CHECK(result == DNS_R_NXRRSET);
2010                 if (dbuf != NULL)
2011                         query_releasename(client, namep);
2012         }
2013
2014         if (rdataset->trust != dns_trust_secure &&
2015             (section == DNS_SECTION_ANSWER ||
2016              section == DNS_SECTION_AUTHORITY))
2017                 client->query.attributes &= ~NS_QUERYATTR_SECURE;
2018         /*
2019          * Note: we only add SIGs if we've added the type they cover, so
2020          * we do not need to check if the SIG rdataset is already in the
2021          * response.
2022          */
2023         query_addrdataset(client, mname, rdataset);
2024         *rdatasetp = NULL;
2025         if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
2026                 /*
2027                  * We have a signature.  Add it to the response.
2028                  */
2029                 ISC_LIST_APPEND(mname->list, sigrdataset, link);
2030                 *sigrdatasetp = NULL;
2031         }
2032         CTRACE("query_addrrset: done");
2033 }
2034
2035 static inline isc_result_t
2036 query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
2037              isc_boolean_t zero_ttl)
2038 {
2039         dns_name_t *name;
2040         dns_dbnode_t *node;
2041         isc_result_t result, eresult;
2042         dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
2043         dns_rdataset_t **sigrdatasetp = NULL;
2044
2045         CTRACE("query_addsoa");
2046         /*
2047          * Initialization.
2048          */
2049         eresult = ISC_R_SUCCESS;
2050         name = NULL;
2051         rdataset = NULL;
2052         node = NULL;
2053
2054         /*
2055          * Get resources and make 'name' be the database origin.
2056          */
2057         result = dns_message_gettempname(client->message, &name);
2058         if (result != ISC_R_SUCCESS)
2059                 return (result);
2060         dns_name_init(name, NULL);
2061         dns_name_clone(dns_db_origin(db), name);
2062         rdataset = query_newrdataset(client);
2063         if (rdataset == NULL) {
2064                 eresult = DNS_R_SERVFAIL;
2065                 goto cleanup;
2066         }
2067         if (WANTDNSSEC(client) && dns_db_issecure(db)) {
2068                 sigrdataset = query_newrdataset(client);
2069                 if (sigrdataset == NULL) {
2070                         eresult = DNS_R_SERVFAIL;
2071                         goto cleanup;
2072                 }
2073         }
2074
2075         /*
2076          * Find the SOA.
2077          */
2078         result = dns_db_getoriginnode(db, &node);
2079         if (result == ISC_R_SUCCESS) {
2080                 result = dns_db_findrdataset(db, node, version,
2081                                              dns_rdatatype_soa,
2082                                              0, client->now, rdataset,
2083                                              sigrdataset);
2084         } else {
2085                 dns_fixedname_t foundname;
2086                 dns_name_t *fname;
2087
2088                 dns_fixedname_init(&foundname);
2089                 fname = dns_fixedname_name(&foundname);
2090
2091                 result = dns_db_find(db, name, version, dns_rdatatype_soa,
2092                                      client->query.dboptions, 0, &node,
2093                                      fname, rdataset, sigrdataset);
2094         }
2095         if (result != ISC_R_SUCCESS) {
2096                 /*
2097                  * This is bad.  We tried to get the SOA RR at the zone top
2098                  * and it didn't work!
2099                  */
2100                 eresult = DNS_R_SERVFAIL;
2101         } else {
2102                 /*
2103                  * Extract the SOA MINIMUM.
2104                  */
2105                 dns_rdata_soa_t soa;
2106                 dns_rdata_t rdata = DNS_RDATA_INIT;
2107                 result = dns_rdataset_first(rdataset);
2108                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2109                 dns_rdataset_current(rdataset, &rdata);
2110                 result = dns_rdata_tostruct(&rdata, &soa, NULL);
2111                 if (result != ISC_R_SUCCESS)
2112                         goto cleanup;
2113
2114                 if (zero_ttl) {
2115                         rdataset->ttl = 0;
2116                         if (sigrdataset != NULL)
2117                                 sigrdataset->ttl = 0;
2118                 }
2119
2120                 /*
2121                  * Add the SOA and its SIG to the response, with the
2122                  * TTLs adjusted per RFC2308 section 3.
2123                  */
2124                 if (rdataset->ttl > soa.minimum)
2125                         rdataset->ttl = soa.minimum;
2126                 if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum)
2127                         sigrdataset->ttl = soa.minimum;
2128
2129                 if (sigrdataset != NULL)
2130                         sigrdatasetp = &sigrdataset;
2131                 else
2132                         sigrdatasetp = NULL;
2133                 query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL,
2134                                DNS_SECTION_AUTHORITY);
2135         }
2136
2137  cleanup:
2138         query_putrdataset(client, &rdataset);
2139         if (sigrdataset != NULL)
2140                 query_putrdataset(client, &sigrdataset);
2141         if (name != NULL)
2142                 query_releasename(client, &name);
2143         if (node != NULL)
2144                 dns_db_detachnode(db, &node);
2145
2146         return (eresult);
2147 }
2148
2149 static inline isc_result_t
2150 query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
2151         dns_name_t *name, *fname;
2152         dns_dbnode_t *node;
2153         isc_result_t result, eresult;
2154         dns_fixedname_t foundname;
2155         dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
2156         dns_rdataset_t **sigrdatasetp = NULL;
2157
2158         CTRACE("query_addns");
2159         /*
2160          * Initialization.
2161          */
2162         eresult = ISC_R_SUCCESS;
2163         name = NULL;
2164         rdataset = NULL;
2165         node = NULL;
2166         dns_fixedname_init(&foundname);
2167         fname = dns_fixedname_name(&foundname);
2168
2169         /*
2170          * Get resources and make 'name' be the database origin.
2171          */
2172         result = dns_message_gettempname(client->message, &name);
2173         if (result != ISC_R_SUCCESS) {
2174                 CTRACE("query_addns: dns_message_gettempname failed: done");
2175                 return (result);
2176         }
2177         dns_name_init(name, NULL);
2178         dns_name_clone(dns_db_origin(db), name);
2179         rdataset = query_newrdataset(client);
2180         if (rdataset == NULL) {
2181                 CTRACE("query_addns: query_newrdataset failed");
2182                 eresult = DNS_R_SERVFAIL;
2183                 goto cleanup;
2184         }
2185         if (WANTDNSSEC(client) && dns_db_issecure(db)) {
2186                 sigrdataset = query_newrdataset(client);
2187                 if (sigrdataset == NULL) {
2188                         CTRACE("query_addns: query_newrdataset failed");
2189                         eresult = DNS_R_SERVFAIL;
2190                         goto cleanup;
2191                 }
2192         }
2193
2194         /*
2195          * Find the NS rdataset.
2196          */
2197         result = dns_db_getoriginnode(db, &node);
2198         if (result == ISC_R_SUCCESS) {
2199                 result = dns_db_findrdataset(db, node, version,
2200                                              dns_rdatatype_ns,
2201                                              0, client->now, rdataset,
2202                                              sigrdataset);
2203         } else {
2204                 CTRACE("query_addns: calling dns_db_find");
2205                 result = dns_db_find(db, name, NULL, dns_rdatatype_ns,
2206                                      client->query.dboptions, 0, &node,
2207                                      fname, rdataset, sigrdataset);
2208                 CTRACE("query_addns: dns_db_find complete");
2209         }
2210         if (result != ISC_R_SUCCESS) {
2211                 CTRACE("query_addns: "
2212                        "dns_db_findrdataset or dns_db_find failed");
2213                 /*
2214                  * This is bad.  We tried to get the NS rdataset at the zone
2215                  * top and it didn't work!
2216                  */
2217                 eresult = DNS_R_SERVFAIL;
2218         } else {
2219                 if (sigrdataset != NULL)
2220                         sigrdatasetp = &sigrdataset;
2221                 else
2222                         sigrdatasetp = NULL;
2223                 query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL,
2224                                DNS_SECTION_AUTHORITY);
2225         }
2226
2227  cleanup:
2228         CTRACE("query_addns: cleanup");
2229         query_putrdataset(client, &rdataset);
2230         if (sigrdataset != NULL)
2231                 query_putrdataset(client, &sigrdataset);
2232         if (name != NULL)
2233                 query_releasename(client, &name);
2234         if (node != NULL)
2235                 dns_db_detachnode(db, &node);
2236
2237         CTRACE("query_addns: done");
2238         return (eresult);
2239 }
2240
2241 static inline isc_result_t
2242 query_addcnamelike(ns_client_t *client, dns_name_t *qname, dns_name_t *tname,
2243                    dns_trust_t trust, dns_name_t **anamep, dns_rdatatype_t type)
2244 {
2245         dns_rdataset_t *rdataset;
2246         dns_rdatalist_t *rdatalist;
2247         dns_rdata_t *rdata;
2248         isc_result_t result;
2249         isc_region_t r;
2250
2251         /*
2252          * We assume the name data referred to by tname won't go away.
2253          */
2254
2255         REQUIRE(anamep != NULL);
2256
2257         rdatalist = NULL;
2258         result = dns_message_gettemprdatalist(client->message, &rdatalist);
2259         if (result != ISC_R_SUCCESS)
2260                 return (result);
2261         rdata = NULL;
2262         result = dns_message_gettemprdata(client->message, &rdata);
2263         if (result != ISC_R_SUCCESS)
2264                 return (result);
2265         rdataset = NULL;
2266         result = dns_message_gettemprdataset(client->message, &rdataset);
2267         if (result != ISC_R_SUCCESS)
2268                 return (result);
2269         dns_rdataset_init(rdataset);
2270         result = dns_name_dup(qname, client->mctx, *anamep);
2271         if (result != ISC_R_SUCCESS) {
2272                 dns_message_puttemprdataset(client->message, &rdataset);
2273                 return (result);
2274         }
2275
2276         rdatalist->type = type;
2277         rdatalist->covers = 0;
2278         rdatalist->rdclass = client->message->rdclass;
2279         rdatalist->ttl = 0;
2280
2281         dns_name_toregion(tname, &r);
2282         rdata->data = r.base;
2283         rdata->length = r.length;
2284         rdata->rdclass = client->message->rdclass;
2285         rdata->type = type;
2286
2287         ISC_LIST_INIT(rdatalist->rdata);
2288         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2289         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset)
2290                       == ISC_R_SUCCESS);
2291         rdataset->trust = trust;
2292
2293         query_addrrset(client, anamep, &rdataset, NULL, NULL,
2294                        DNS_SECTION_ANSWER);
2295
2296         if (rdataset != NULL) {
2297                 if (dns_rdataset_isassociated(rdataset))
2298                         dns_rdataset_disassociate(rdataset);
2299                 dns_message_puttemprdataset(client->message, &rdataset);
2300         }
2301
2302         return (ISC_R_SUCCESS);
2303 }
2304
2305 /*
2306  * Mark the RRsets as secure.  Update the cache (db) to reflect the
2307  * change in trust level.
2308  */
2309 static void
2310 mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2311             isc_uint32_t ttl, dns_rdataset_t *rdataset,
2312             dns_rdataset_t *sigrdataset)
2313 {
2314         isc_result_t result;
2315         dns_dbnode_t *node = NULL;
2316
2317         rdataset->trust = dns_trust_secure;
2318         sigrdataset->trust = dns_trust_secure;
2319
2320         /*
2321          * Save the updated secure state.  Ignore failures.
2322          */
2323         result = dns_db_findnode(db, name, ISC_TRUE, &node);
2324         if (result != ISC_R_SUCCESS)
2325                 return;
2326         /*
2327          * Bound the validated ttls then minimise.
2328          */
2329         if (sigrdataset->ttl > ttl)
2330                 sigrdataset->ttl = ttl;
2331         if (rdataset->ttl > ttl)
2332                 rdataset->ttl = ttl;
2333         if (rdataset->ttl > sigrdataset->ttl)
2334                 rdataset->ttl = sigrdataset->ttl;
2335         else
2336                 sigrdataset->ttl = rdataset->ttl;
2337
2338         (void)dns_db_addrdataset(db, node, NULL, client->now, rdataset,
2339                                  0, NULL);
2340         (void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset,
2341                                  0, NULL);
2342         dns_db_detachnode(db, &node);
2343 }
2344
2345 /*
2346  * Find the secure key that corresponds to rrsig.
2347  * Note: 'keyrdataset' maintains state between successive calls,
2348  * there may be multiple keys with the same keyid.
2349  * Return ISC_FALSE if we have exhausted all the possible keys.
2350  */
2351 static isc_boolean_t
2352 get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
2353         dns_rdataset_t *keyrdataset, dst_key_t **keyp)
2354 {
2355         isc_result_t result;
2356         dns_dbnode_t *node = NULL;
2357         isc_boolean_t secure = ISC_FALSE;
2358
2359         if (!dns_rdataset_isassociated(keyrdataset)) {
2360                 result = dns_db_findnode(db, &rrsig->signer, ISC_FALSE, &node);
2361                 if (result != ISC_R_SUCCESS)
2362                         return (ISC_FALSE);
2363
2364                 result = dns_db_findrdataset(db, node, NULL,
2365                                              dns_rdatatype_dnskey, 0,
2366                                              client->now, keyrdataset, NULL);
2367                 dns_db_detachnode(db, &node);
2368                 if (result != ISC_R_SUCCESS)
2369                         return (ISC_FALSE);
2370
2371                 if (keyrdataset->trust != dns_trust_secure)
2372                         return (ISC_FALSE);
2373
2374                 result = dns_rdataset_first(keyrdataset);
2375         } else
2376                 result = dns_rdataset_next(keyrdataset);
2377
2378         for ( ; result == ISC_R_SUCCESS;
2379              result = dns_rdataset_next(keyrdataset)) {
2380                 dns_rdata_t rdata = DNS_RDATA_INIT;
2381                 isc_buffer_t b;
2382
2383                 dns_rdataset_current(keyrdataset, &rdata);
2384                 isc_buffer_init(&b, rdata.data, rdata.length);
2385                 isc_buffer_add(&b, rdata.length);
2386                 result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
2387                                          client->mctx, keyp);
2388                 if (result != ISC_R_SUCCESS)
2389                         continue;
2390                 if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
2391                     rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
2392                     dst_key_iszonekey(*keyp)) {
2393                         secure = ISC_TRUE;
2394                         break;
2395                 }
2396                 dst_key_free(keyp);
2397         }
2398         return (secure);
2399 }
2400
2401 static isc_boolean_t
2402 verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
2403        dns_rdata_t *rdata, isc_mem_t *mctx, isc_boolean_t acceptexpired)
2404 {
2405         isc_result_t result;
2406         dns_fixedname_t fixed;
2407         isc_boolean_t ignore = ISC_FALSE;
2408
2409         dns_fixedname_init(&fixed);
2410
2411 again:
2412         result = dns_dnssec_verify2(name, rdataset, key, ignore, mctx,
2413                                     rdata, NULL);
2414         if (result == DNS_R_SIGEXPIRED && acceptexpired) {
2415                 ignore = ISC_TRUE;
2416                 goto again;
2417         }
2418         if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD)
2419                 return (ISC_TRUE);
2420         return (ISC_FALSE);
2421 }
2422
2423 /*
2424  * Validate the rdataset if possible with available records.
2425  */
2426 static isc_boolean_t
2427 validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2428          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
2429 {
2430         isc_result_t result;
2431         dns_rdata_t rdata = DNS_RDATA_INIT;
2432         dns_rdata_rrsig_t rrsig;
2433         dst_key_t *key = NULL;
2434         dns_rdataset_t keyrdataset;
2435
2436         if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
2437                 return (ISC_FALSE);
2438
2439         for (result = dns_rdataset_first(sigrdataset);
2440              result == ISC_R_SUCCESS;
2441              result = dns_rdataset_next(sigrdataset)) {
2442
2443                 dns_rdata_reset(&rdata);
2444                 dns_rdataset_current(sigrdataset, &rdata);
2445                 result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
2446                 if (result != ISC_R_SUCCESS)
2447                         return (ISC_FALSE);
2448                 if (!dns_resolver_algorithm_supported(client->view->resolver,
2449                                                       name, rrsig.algorithm))
2450                         continue;
2451                 if (!dns_name_issubdomain(name, &rrsig.signer))
2452                         continue;
2453                 dns_rdataset_init(&keyrdataset);
2454                 do {
2455                         if (!get_key(client, db, &rrsig, &keyrdataset, &key))
2456                                 break;
2457                         if (verify(key, name, rdataset, &rdata, client->mctx,
2458                                    client->view->acceptexpired)) {
2459                                 dst_key_free(&key);
2460                                 dns_rdataset_disassociate(&keyrdataset);
2461                                 mark_secure(client, db, name,
2462                                             rrsig.originalttl,
2463                                             rdataset, sigrdataset);
2464                                 return (ISC_TRUE);
2465                         }
2466                         dst_key_free(&key);
2467                 } while (1);
2468                 if (dns_rdataset_isassociated(&keyrdataset))
2469                         dns_rdataset_disassociate(&keyrdataset);
2470         }
2471         return (ISC_FALSE);
2472 }
2473
2474 static void
2475 query_addbestns(ns_client_t *client) {
2476         dns_db_t *db, *zdb;
2477         dns_dbnode_t *node;
2478         dns_name_t *fname, *zfname;
2479         dns_rdataset_t *rdataset, *sigrdataset, *zrdataset, *zsigrdataset;
2480         isc_boolean_t is_zone, use_zone;
2481         isc_buffer_t *dbuf;
2482         isc_result_t result;
2483         dns_dbversion_t *version;
2484         dns_zone_t *zone;
2485         isc_buffer_t b;
2486
2487         CTRACE("query_addbestns");
2488         fname = NULL;
2489         zfname = NULL;
2490         rdataset = NULL;
2491         zrdataset = NULL;
2492         sigrdataset = NULL;
2493         zsigrdataset = NULL;
2494         node = NULL;
2495         db = NULL;
2496         zdb = NULL;
2497         version = NULL;
2498         zone = NULL;
2499         is_zone = ISC_FALSE;
2500         use_zone = ISC_FALSE;
2501
2502         /*
2503          * Find the right database.
2504          */
2505         result = query_getdb(client, client->query.qname, dns_rdatatype_ns, 0,
2506                              &zone, &db, &version, &is_zone);
2507         if (result != ISC_R_SUCCESS)
2508                 goto cleanup;
2509
2510  db_find:
2511         /*
2512          * We'll need some resources...
2513          */
2514         dbuf = query_getnamebuf(client);
2515         if (dbuf == NULL)
2516                 goto cleanup;
2517         fname = query_newname(client, dbuf, &b);
2518         rdataset = query_newrdataset(client);
2519         if (fname == NULL || rdataset == NULL)
2520                 goto cleanup;
2521         /*
2522          * Get the RRSIGs if the client requested them or if we may
2523          * need to validate answers from the cache.
2524          */
2525         if (WANTDNSSEC(client) || !is_zone) {
2526                 sigrdataset = query_newrdataset(client);
2527                 if (sigrdataset == NULL)
2528                         goto cleanup;
2529         }
2530
2531         /*
2532          * Now look for the zonecut.
2533          */
2534         if (is_zone) {
2535                 result = dns_db_find(db, client->query.qname, version,
2536                                      dns_rdatatype_ns, client->query.dboptions,
2537                                      client->now, &node, fname,
2538                                      rdataset, sigrdataset);
2539                 if (result != DNS_R_DELEGATION)
2540                         goto cleanup;
2541                 if (USECACHE(client)) {
2542                         query_keepname(client, fname, dbuf);
2543                         zdb = db;
2544                         zfname = fname;
2545                         fname = NULL;
2546                         zrdataset = rdataset;
2547                         rdataset = NULL;
2548                         zsigrdataset = sigrdataset;
2549                         sigrdataset = NULL;
2550                         dns_db_detachnode(db, &node);
2551                         version = NULL;
2552                         db = NULL;
2553                         dns_db_attach(client->view->cachedb, &db);
2554                         is_zone = ISC_FALSE;
2555                         goto db_find;
2556                 }
2557         } else {
2558                 result = dns_db_findzonecut(db, client->query.qname,
2559                                             client->query.dboptions,
2560                                             client->now, &node, fname,
2561                                             rdataset, sigrdataset);
2562                 if (result == ISC_R_SUCCESS) {
2563                         if (zfname != NULL &&
2564                             !dns_name_issubdomain(fname, zfname)) {
2565                                 /*
2566                                  * We found a zonecut in the cache, but our
2567                                  * zone delegation is better.
2568                                  */
2569                                 use_zone = ISC_TRUE;
2570                         }
2571                 } else if (result == ISC_R_NOTFOUND && zfname != NULL) {
2572                         /*
2573                          * We didn't find anything in the cache, but we
2574                          * have a zone delegation, so use it.
2575                          */
2576                         use_zone = ISC_TRUE;
2577                 } else
2578                         goto cleanup;
2579         }
2580
2581         if (use_zone) {
2582                 query_releasename(client, &fname);
2583                 fname = zfname;
2584                 zfname = NULL;
2585                 /*
2586                  * We've already done query_keepname() on
2587                  * zfname, so we must set dbuf to NULL to
2588                  * prevent query_addrrset() from trying to
2589                  * call query_keepname() again.
2590                  */
2591                 dbuf = NULL;
2592                 query_putrdataset(client, &rdataset);
2593                 if (sigrdataset != NULL)
2594                         query_putrdataset(client, &sigrdataset);
2595                 rdataset = zrdataset;
2596                 zrdataset = NULL;
2597                 sigrdataset = zsigrdataset;
2598                 zsigrdataset = NULL;
2599         }
2600
2601         /*
2602          * Attempt to validate RRsets that are pending or that are glue.
2603          */
2604         if ((rdataset->trust == dns_trust_pending ||
2605              (sigrdataset != NULL && sigrdataset->trust == dns_trust_pending))
2606             && !validate(client, db, fname, rdataset, sigrdataset) &&
2607             (client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0)
2608                 goto cleanup;
2609
2610         if ((rdataset->trust == dns_trust_glue ||
2611              (sigrdataset != NULL && sigrdataset->trust == dns_trust_glue)) &&
2612             !validate(client, db, fname, rdataset, sigrdataset) &&
2613             SECURE(client) && WANTDNSSEC(client))
2614                 goto cleanup;
2615
2616         /*
2617          * If the client doesn't want DNSSEC we can discard the sigrdataset
2618          * now.
2619          */
2620         if (!WANTDNSSEC(client))
2621                 query_putrdataset(client, &sigrdataset);
2622         query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2623                        DNS_SECTION_AUTHORITY);
2624
2625  cleanup:
2626         if (rdataset != NULL)
2627                 query_putrdataset(client, &rdataset);
2628         if (sigrdataset != NULL)
2629                 query_putrdataset(client, &sigrdataset);
2630         if (fname != NULL)
2631                 query_releasename(client, &fname);
2632         if (node != NULL)
2633                 dns_db_detachnode(db, &node);
2634         if (db != NULL)
2635                 dns_db_detach(&db);
2636         if (zone != NULL)
2637                 dns_zone_detach(&zone);
2638         if (zdb != NULL) {
2639                 query_putrdataset(client, &zrdataset);
2640                 if (zsigrdataset != NULL)
2641                         query_putrdataset(client, &zsigrdataset);
2642                 if (zfname != NULL)
2643                         query_releasename(client, &zfname);
2644                 dns_db_detach(&zdb);
2645         }
2646 }
2647
2648 static void
2649 fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) {
2650         if (*rdataset == NULL)
2651                 *rdataset = query_newrdataset(client);
2652         else  if (dns_rdataset_isassociated(*rdataset))
2653                 dns_rdataset_disassociate(*rdataset);
2654 }
2655
2656 static void
2657 fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf,
2658          isc_buffer_t *nbuf)
2659 {
2660         if (*fname == NULL) {
2661                 *dbuf = query_getnamebuf(client);
2662                 if (*dbuf == NULL)
2663                         return;
2664                 *fname = query_newname(client, *dbuf, nbuf);
2665         }
2666 }
2667
2668 static void
2669 query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node,
2670             dns_dbversion_t *version, dns_name_t *name)
2671 {
2672         dns_fixedname_t fixed;
2673         dns_name_t *fname = NULL;
2674         dns_name_t *rname;
2675         dns_rdataset_t *rdataset, *sigrdataset;
2676         isc_buffer_t *dbuf, b;
2677         isc_result_t result;
2678         unsigned int count;
2679
2680         CTRACE("query_addds");
2681         rname = NULL;
2682         rdataset = NULL;
2683         sigrdataset = NULL;
2684
2685         /*
2686          * We'll need some resources...
2687          */
2688         rdataset = query_newrdataset(client);
2689         sigrdataset = query_newrdataset(client);
2690         if (rdataset == NULL || sigrdataset == NULL)
2691                 goto cleanup;
2692
2693         /*
2694          * Look for the DS record, which may or may not be present.
2695          */
2696         result = dns_db_findrdataset(db, node, version, dns_rdatatype_ds, 0,
2697                                      client->now, rdataset, sigrdataset);
2698         /*
2699          * If we didn't find it, look for an NSEC.
2700          */
2701         if (result == ISC_R_NOTFOUND)
2702                 result = dns_db_findrdataset(db, node, version,
2703                                              dns_rdatatype_nsec, 0, client->now,
2704                                              rdataset, sigrdataset);
2705         if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
2706                 goto addnsec3;
2707         if (!dns_rdataset_isassociated(rdataset) ||
2708             !dns_rdataset_isassociated(sigrdataset))
2709                 goto addnsec3;
2710
2711         /*
2712          * We've already added the NS record, so if the name's not there,
2713          * we have other problems.  Use this name rather than calling
2714          * query_addrrset().
2715          */
2716         result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
2717         if (result != ISC_R_SUCCESS)
2718                 goto cleanup;
2719
2720         rname = NULL;
2721         dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
2722                                 &rname);
2723         result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
2724         if (result != ISC_R_SUCCESS)
2725                 goto cleanup;
2726
2727         ISC_LIST_APPEND(rname->list, rdataset, link);
2728         ISC_LIST_APPEND(rname->list, sigrdataset, link);
2729         rdataset = NULL;
2730         sigrdataset = NULL;
2731         return;
2732
2733    addnsec3:
2734         if (dns_db_iscache(db))
2735                 goto cleanup;
2736         /*
2737          * Add the NSEC3 which proves the DS does not exist.
2738          */
2739         dbuf = query_getnamebuf(client);
2740         if (dbuf == NULL)
2741                 goto cleanup;
2742         fname = query_newname(client, dbuf, &b);
2743         dns_fixedname_init(&fixed);
2744         if (dns_rdataset_isassociated(rdataset))
2745                 dns_rdataset_disassociate(rdataset);
2746         if (dns_rdataset_isassociated(sigrdataset))
2747                 dns_rdataset_disassociate(sigrdataset);
2748         query_findclosestnsec3(name, db, version, client, rdataset,
2749                                sigrdataset, fname, ISC_TRUE,
2750                                dns_fixedname_name(&fixed));
2751         if (!dns_rdataset_isassociated(rdataset))
2752                 goto cleanup;
2753         query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2754                        DNS_SECTION_AUTHORITY);
2755         /*
2756          * Did we find the closest provable encloser instead?
2757          * If so add the nearest to the closest provable encloser.
2758          */
2759         if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
2760                 count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
2761                 dns_name_getlabelsequence(name,
2762                                           dns_name_countlabels(name) - count,
2763                                           count, dns_fixedname_name(&fixed));
2764                 fixfname(client, &fname, &dbuf, &b);
2765                 fixrdataset(client, &rdataset);
2766                 fixrdataset(client, &sigrdataset);
2767                 if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2768                                 goto cleanup;
2769                 query_findclosestnsec3(dns_fixedname_name(&fixed), db, version,
2770                                        client, rdataset, sigrdataset, fname,
2771                                        ISC_FALSE, NULL);
2772                 if (!dns_rdataset_isassociated(rdataset))
2773                         goto cleanup;
2774                 query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2775                                DNS_SECTION_AUTHORITY);
2776         }
2777
2778  cleanup:
2779         if (rdataset != NULL)
2780                 query_putrdataset(client, &rdataset);
2781         if (sigrdataset != NULL)
2782                 query_putrdataset(client, &sigrdataset);
2783         if (fname != NULL)
2784                 query_releasename(client, &fname);
2785 }
2786
2787 static void
2788 query_addwildcardproof(ns_client_t *client, dns_db_t *db,
2789                        dns_dbversion_t *version, dns_name_t *name,
2790                        isc_boolean_t ispositive)
2791 {
2792         isc_buffer_t *dbuf, b;
2793         dns_name_t *fname;
2794         dns_rdataset_t *rdataset, *sigrdataset;
2795         dns_fixedname_t wfixed;
2796         dns_name_t *wname;
2797         dns_dbnode_t *node;
2798         unsigned int options;
2799         unsigned int olabels, nlabels, labels;
2800         isc_result_t result;
2801         dns_rdata_t rdata = DNS_RDATA_INIT;
2802         dns_rdata_nsec_t nsec;
2803         isc_boolean_t have_wname;
2804         int order;
2805         dns_fixedname_t cfixed;
2806         dns_name_t *cname;
2807
2808         CTRACE("query_addwildcardproof");
2809         fname = NULL;
2810         rdataset = NULL;
2811         sigrdataset = NULL;
2812         node = NULL;
2813
2814         /*
2815          * Get the NOQNAME proof then if !ispositive
2816          * get the NOWILDCARD proof.
2817          *
2818          * DNS_DBFIND_NOWILD finds the NSEC records that covers the
2819          * name ignoring any wildcard.  From the owner and next names
2820          * of this record you can compute which wildcard (if it exists)
2821          * will match by finding the longest common suffix of the
2822          * owner name and next names with the qname and prefixing that
2823          * with the wildcard label.
2824          *
2825          * e.g.
2826          *   Given:
2827          *      example SOA
2828          *      example NSEC b.example
2829          *      b.example A
2830          *      b.example NSEC a.d.example
2831          *      a.d.example A
2832          *      a.d.example NSEC g.f.example
2833          *      g.f.example A
2834          *      g.f.example NSEC z.i.example
2835          *      z.i.example A
2836          *      z.i.example NSEC example
2837          *
2838          *   QNAME:
2839          *   a.example -> example NSEC b.example
2840          *      owner common example
2841          *      next common example
2842          *      wild *.example
2843          *   d.b.example -> b.example NSEC a.d.example
2844          *      owner common b.example
2845          *      next common example
2846          *      wild *.b.example
2847          *   a.f.example -> a.d.example NSEC g.f.example
2848          *      owner common example
2849          *      next common f.example
2850          *      wild *.f.example
2851          *  j.example -> z.i.example NSEC example
2852          *      owner common example
2853          *      next common example
2854          *      wild *.f.example
2855          */
2856         options = client->query.dboptions | DNS_DBFIND_NOWILD;
2857         dns_fixedname_init(&wfixed);
2858         wname = dns_fixedname_name(&wfixed);
2859  again:
2860         have_wname = ISC_FALSE;
2861         /*
2862          * We'll need some resources...
2863          */
2864         dbuf = query_getnamebuf(client);
2865         if (dbuf == NULL)
2866                 goto cleanup;
2867         fname = query_newname(client, dbuf, &b);
2868         rdataset = query_newrdataset(client);
2869         sigrdataset = query_newrdataset(client);
2870         if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2871                 goto cleanup;
2872
2873         result = dns_db_find(db, name, version, dns_rdatatype_nsec, options,
2874                              0, &node, fname, rdataset, sigrdataset);
2875         if (node != NULL)
2876                 dns_db_detachnode(db, &node);
2877
2878         if (!dns_rdataset_isassociated(rdataset)) {
2879                 /*
2880                  * No NSEC proof available, return NSEC3 proofs instead.
2881                  */
2882                 dns_fixedname_init(&cfixed);
2883                 cname = dns_fixedname_name(&cfixed);
2884                 /*
2885                  * Find the closest encloser.
2886                  */
2887                 dns_name_copy(name, cname, NULL);
2888                 while (result == DNS_R_NXDOMAIN) {
2889                         labels = dns_name_countlabels(cname) - 1;
2890                         dns_name_split(cname, labels, NULL, cname);
2891                         result = dns_db_find(db, cname, version,
2892                                              dns_rdatatype_nsec,
2893                                              options, 0, NULL, fname,
2894                                              NULL, NULL);
2895                 }
2896                 /*
2897                  * Add closest (provable) encloser NSEC3.
2898                  */
2899                 query_findclosestnsec3(cname, db, NULL, client, rdataset,
2900                                        sigrdataset, fname, ISC_TRUE, cname);
2901                 if (!dns_rdataset_isassociated(rdataset))
2902                         goto cleanup;
2903                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2904                                dbuf, DNS_SECTION_AUTHORITY);
2905
2906                 /*
2907                  * Replace resources which were consumed by query_addrrset.
2908                  */
2909                 if (fname == NULL) {
2910                         dbuf = query_getnamebuf(client);
2911                         if (dbuf == NULL)
2912                                 goto cleanup;
2913                         fname = query_newname(client, dbuf, &b);
2914                 }
2915
2916                 if (rdataset == NULL)
2917                         rdataset = query_newrdataset(client);
2918                 else if (dns_rdataset_isassociated(rdataset))
2919                         dns_rdataset_disassociate(rdataset);
2920
2921                 if (sigrdataset == NULL)
2922                         sigrdataset = query_newrdataset(client);
2923                 else if (dns_rdataset_isassociated(sigrdataset))
2924                         dns_rdataset_disassociate(sigrdataset);
2925
2926                 if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2927                         goto cleanup;
2928                 /*
2929                  * Add no qname proof.
2930                  */
2931                 labels = dns_name_countlabels(cname) + 1;
2932                 if (dns_name_countlabels(name) == labels)
2933                         dns_name_copy(name, wname, NULL);
2934                 else
2935                         dns_name_split(name, labels, NULL, wname);
2936
2937                 query_findclosestnsec3(wname, db, NULL, client, rdataset,
2938                                        sigrdataset, fname, ISC_FALSE, NULL);
2939                 if (!dns_rdataset_isassociated(rdataset))
2940                         goto cleanup;
2941                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2942                                dbuf, DNS_SECTION_AUTHORITY);
2943
2944                 if (ispositive)
2945                         goto cleanup;
2946
2947                 /*
2948                  * Replace resources which were consumed by query_addrrset.
2949                  */
2950                 if (fname == NULL) {
2951                         dbuf = query_getnamebuf(client);
2952                         if (dbuf == NULL)
2953                                 goto cleanup;
2954                         fname = query_newname(client, dbuf, &b);
2955                 }
2956
2957                 if (rdataset == NULL)
2958                         rdataset = query_newrdataset(client);
2959                 else if (dns_rdataset_isassociated(rdataset))
2960                         dns_rdataset_disassociate(rdataset);
2961
2962                 if (sigrdataset == NULL)
2963                         sigrdataset = query_newrdataset(client);
2964                 else if (dns_rdataset_isassociated(sigrdataset))
2965                         dns_rdataset_disassociate(sigrdataset);
2966
2967                 if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2968                         goto cleanup;
2969                 /*
2970                  * Add the no wildcard proof.
2971                  */
2972                 result = dns_name_concatenate(dns_wildcardname,
2973                                               cname, wname, NULL);
2974                 if (result != ISC_R_SUCCESS)
2975                         goto cleanup;
2976
2977                 query_findclosestnsec3(wname, db, NULL, client, rdataset,
2978                                        sigrdataset, fname, ISC_FALSE, NULL);
2979                 if (!dns_rdataset_isassociated(rdataset))
2980                         goto cleanup;
2981                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2982                                dbuf, DNS_SECTION_AUTHORITY);
2983
2984                 goto cleanup;
2985         } else if (result == DNS_R_NXDOMAIN) {
2986                 if (!ispositive)
2987                         result = dns_rdataset_first(rdataset);
2988                 if (result == ISC_R_SUCCESS) {
2989                         dns_rdataset_current(rdataset, &rdata);
2990                         result = dns_rdata_tostruct(&rdata, &nsec, NULL);
2991                 }
2992                 if (result == ISC_R_SUCCESS) {
2993                         (void)dns_name_fullcompare(name, fname, &order,
2994                                                    &olabels);
2995                         (void)dns_name_fullcompare(name, &nsec.next, &order,
2996                                                    &nlabels);
2997                         /*
2998                          * Check for a pathological condition created when
2999                          * serving some malformed signed zones and bail out.
3000                          */
3001                         if (dns_name_countlabels(name) == nlabels)
3002                                 goto cleanup;
3003
3004                         if (olabels > nlabels)
3005                                 dns_name_split(name, olabels, NULL, wname);
3006                         else
3007                                 dns_name_split(name, nlabels, NULL, wname);
3008                         result = dns_name_concatenate(dns_wildcardname,
3009                                                       wname, wname, NULL);
3010                         if (result == ISC_R_SUCCESS)
3011                                 have_wname = ISC_TRUE;
3012                         dns_rdata_freestruct(&nsec);
3013                 }
3014                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
3015                                dbuf, DNS_SECTION_AUTHORITY);
3016         }
3017         if (rdataset != NULL)
3018                 query_putrdataset(client, &rdataset);
3019         if (sigrdataset != NULL)
3020                 query_putrdataset(client, &sigrdataset);
3021         if (fname != NULL)
3022                 query_releasename(client, &fname);
3023         if (have_wname) {
3024                 ispositive = ISC_TRUE;  /* prevent loop */
3025                 if (!dns_name_equal(name, wname)) {
3026                         name = wname;
3027                         goto again;
3028                 }
3029         }
3030  cleanup:
3031         if (rdataset != NULL)
3032                 query_putrdataset(client, &rdataset);
3033         if (sigrdataset != NULL)
3034                 query_putrdataset(client, &sigrdataset);
3035         if (fname != NULL)
3036                 query_releasename(client, &fname);
3037 }
3038
3039 static void
3040 query_addnxrrsetnsec(ns_client_t *client, dns_db_t *db,
3041                      dns_dbversion_t *version, dns_name_t **namep,
3042                      dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp)
3043 {
3044         dns_name_t *name;
3045         dns_rdataset_t *sigrdataset;
3046         dns_rdata_t sigrdata;
3047         dns_rdata_rrsig_t sig;
3048         unsigned int labels;
3049         isc_buffer_t *dbuf, b;
3050         dns_name_t *fname;
3051         isc_result_t result;
3052
3053         name = *namep;
3054         if ((name->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
3055                 query_addrrset(client, namep, rdatasetp, sigrdatasetp,
3056                                NULL, DNS_SECTION_AUTHORITY);
3057                 return;
3058         }
3059
3060         if (sigrdatasetp == NULL)
3061                 return;
3062
3063         sigrdataset = *sigrdatasetp;
3064         if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
3065                 return;
3066         result = dns_rdataset_first(sigrdataset);
3067         if (result != ISC_R_SUCCESS)
3068                 return;
3069         dns_rdata_init(&sigrdata);
3070         dns_rdataset_current(sigrdataset, &sigrdata);
3071         result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
3072         if (result != ISC_R_SUCCESS)
3073                 return;
3074
3075         labels = dns_name_countlabels(name);
3076         if ((unsigned int)sig.labels + 1 >= labels)
3077                 return;
3078
3079         /* XXX */
3080         query_addwildcardproof(client, db, version, client->query.qname,
3081                                ISC_TRUE);
3082
3083         /*
3084          * We'll need some resources...
3085          */
3086         dbuf = query_getnamebuf(client);
3087         if (dbuf == NULL)
3088                 return;
3089         fname = query_newname(client, dbuf, &b);
3090         if (fname == NULL)
3091                 return;
3092         dns_name_split(name, sig.labels + 1, NULL, fname);
3093         /* This will succeed, since we've stripped labels. */
3094         RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
3095                                            NULL) == ISC_R_SUCCESS);
3096         query_addrrset(client, &fname, rdatasetp, sigrdatasetp,
3097                        dbuf, DNS_SECTION_AUTHORITY);
3098 }
3099
3100 static void
3101 query_resume(isc_task_t *task, isc_event_t *event) {
3102         dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
3103         dns_fetch_t *fetch;
3104         ns_client_t *client;
3105         isc_boolean_t fetch_canceled, client_shuttingdown;
3106         isc_result_t result;
3107         isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_EERRORS;
3108         int errorloglevel;
3109
3110         /*
3111          * Resume a query after recursion.
3112          */
3113
3114         UNUSED(task);
3115
3116         REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
3117         client = devent->ev_arg;
3118         REQUIRE(NS_CLIENT_VALID(client));
3119         REQUIRE(task == client->task);
3120         REQUIRE(RECURSING(client));
3121
3122         LOCK(&client->query.fetchlock);
3123         if (client->query.fetch != NULL) {
3124                 /*
3125                  * This is the fetch we've been waiting for.
3126                  */
3127                 INSIST(devent->fetch == client->query.fetch);
3128                 client->query.fetch = NULL;
3129                 fetch_canceled = ISC_FALSE;
3130                 /*
3131                  * Update client->now.
3132                  */
3133                 isc_stdtime_get(&client->now);
3134         } else {
3135                 /*
3136                  * This is a fetch completion event for a canceled fetch.
3137                  * Clean up and don't resume the find.
3138                  */
3139                 fetch_canceled = ISC_TRUE;
3140         }
3141         UNLOCK(&client->query.fetchlock);
3142         INSIST(client->query.fetch == NULL);
3143
3144         client->query.attributes &= ~NS_QUERYATTR_RECURSING;
3145         fetch = devent->fetch;
3146         devent->fetch = NULL;
3147
3148         /*
3149          * If this client is shutting down, or this transaction
3150          * has timed out, do not resume the find.
3151          */
3152         client_shuttingdown = ns_client_shuttingdown(client);
3153         if (fetch_canceled || client_shuttingdown) {
3154                 if (devent->node != NULL)
3155                         dns_db_detachnode(devent->db, &devent->node);
3156                 if (devent->db != NULL)
3157                         dns_db_detach(&devent->db);
3158                 query_putrdataset(client, &devent->rdataset);
3159                 if (devent->sigrdataset != NULL)
3160                         query_putrdataset(client, &devent->sigrdataset);
3161                 isc_event_free(&event);
3162                 if (fetch_canceled)
3163                         query_error(client, DNS_R_SERVFAIL, __LINE__);
3164                 else
3165                         query_next(client, ISC_R_CANCELED);
3166                 /*
3167                  * This may destroy the client.
3168                  */
3169                 ns_client_detach(&client);
3170         } else {
3171                 result = query_find(client, devent, 0);
3172                 if (result != ISC_R_SUCCESS) {
3173                         if (result == DNS_R_SERVFAIL)
3174                                 errorloglevel = ISC_LOG_DEBUG(2);
3175                         else
3176                                 errorloglevel = ISC_LOG_DEBUG(4);
3177                         if (isc_log_wouldlog(ns_g_lctx, errorloglevel)) {
3178                                 dns_resolver_logfetch(fetch, ns_g_lctx,
3179                                                       logcategory,
3180                                                       NS_LOGMODULE_QUERY,
3181                                                       errorloglevel, ISC_FALSE);
3182                         }
3183                 }
3184         }
3185
3186         dns_resolver_destroyfetch(&fetch);
3187 }
3188
3189 static isc_result_t
3190 query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
3191               dns_rdataset_t *nameservers, isc_boolean_t resuming)
3192 {
3193         isc_result_t result;
3194         dns_rdataset_t *rdataset, *sigrdataset;
3195         isc_sockaddr_t *peeraddr;
3196
3197         if (!resuming)
3198                 inc_stats(client, dns_nsstatscounter_recursion);
3199
3200         /*
3201          * We are about to recurse, which means that this client will
3202          * be unavailable for serving new requests for an indeterminate
3203          * amount of time.  If this client is currently responsible
3204          * for handling incoming queries, set up a new client
3205          * object to handle them while we are waiting for a
3206          * response.  There is no need to replace TCP clients
3207          * because those have already been replaced when the
3208          * connection was accepted (if allowed by the TCP quota).
3209          */
3210         if (client->recursionquota == NULL) {
3211                 result = isc_quota_attach(&ns_g_server->recursionquota,
3212                                           &client->recursionquota);
3213                 if  (result == ISC_R_SOFTQUOTA) {
3214                         static isc_stdtime_t last = 0;
3215                         isc_stdtime_t now;
3216                         isc_stdtime_get(&now);
3217                         if (now != last) {
3218                                 last = now;
3219                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3220                                               NS_LOGMODULE_QUERY,
3221                                               ISC_LOG_WARNING,
3222                                               "recursive-clients soft limit "
3223                                               "exceeded, aborting oldest query");
3224                         }
3225                         ns_client_killoldestquery(client);
3226                         result = ISC_R_SUCCESS;
3227                 } else if (result == ISC_R_QUOTA) {
3228                         static isc_stdtime_t last = 0;
3229                         isc_stdtime_t now;
3230                         isc_stdtime_get(&now);
3231                         if (now != last) {
3232                                 last = now;
3233                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3234                                               NS_LOGMODULE_QUERY,
3235                                               ISC_LOG_WARNING,
3236                                               "no more recursive clients: %s",
3237                                               isc_result_totext(result));
3238                         }
3239                         ns_client_killoldestquery(client);
3240                 }
3241                 if (result == ISC_R_SUCCESS && !client->mortal &&
3242                     (client->attributes & NS_CLIENTATTR_TCP) == 0) {
3243                         result = ns_client_replace(client);
3244                         if (result != ISC_R_SUCCESS) {
3245                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3246                                               NS_LOGMODULE_QUERY,
3247                                               ISC_LOG_WARNING,
3248                                               "ns_client_replace() failed: %s",
3249                                               isc_result_totext(result));
3250                                 isc_quota_detach(&client->recursionquota);
3251                         }
3252                 }
3253                 if (result != ISC_R_SUCCESS)
3254                         return (result);
3255                 ns_client_recursing(client);
3256         }
3257
3258         /*
3259          * Invoke the resolver.
3260          */
3261         REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
3262         REQUIRE(client->query.fetch == NULL);
3263
3264         rdataset = query_newrdataset(client);
3265         if (rdataset == NULL)
3266                 return (ISC_R_NOMEMORY);
3267         if (WANTDNSSEC(client)) {
3268                 sigrdataset = query_newrdataset(client);
3269                 if (sigrdataset == NULL) {
3270                         query_putrdataset(client, &rdataset);
3271                         return (ISC_R_NOMEMORY);
3272                 }
3273         } else
3274                 sigrdataset = NULL;
3275
3276         if (client->query.timerset == ISC_FALSE)
3277                 ns_client_settimeout(client, 60);
3278         if ((client->attributes & NS_CLIENTATTR_TCP) == 0)
3279                 peeraddr = &client->peeraddr;
3280         else
3281                 peeraddr = NULL;
3282         result = dns_resolver_createfetch2(client->view->resolver,
3283                                            client->query.qname,
3284                                            qtype, qdomain, nameservers,
3285                                            NULL, peeraddr, client->message->id,
3286                                            client->query.fetchoptions,
3287                                            client->task,
3288                                            query_resume, client,
3289                                            rdataset, sigrdataset,
3290                                            &client->query.fetch);
3291
3292         if (result == ISC_R_SUCCESS) {
3293                 /*
3294                  * Record that we're waiting for an event.  A client which
3295                  * is shutting down will not be destroyed until all the
3296                  * events have been received.
3297                  */
3298         } else {
3299                 query_putrdataset(client, &rdataset);
3300                 if (sigrdataset != NULL)
3301                         query_putrdataset(client, &sigrdataset);
3302         }
3303
3304         return (result);
3305 }
3306
3307 #define MAX_RESTARTS 16
3308
3309 #define QUERY_ERROR(r) \
3310 do { \
3311         eresult = r; \
3312         want_restart = ISC_FALSE; \
3313         line = __LINE__; \
3314 } while (0)
3315
3316 /*
3317  * Extract a network address from the RDATA of an A or AAAA
3318  * record.
3319  *
3320  * Returns:
3321  *      ISC_R_SUCCESS
3322  *      ISC_R_NOTIMPLEMENTED    The rdata is not a known address type.
3323  */
3324 static isc_result_t
3325 rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
3326         struct in_addr ina;
3327         struct in6_addr in6a;
3328
3329         switch (rdata->type) {
3330         case dns_rdatatype_a:
3331                 INSIST(rdata->length == 4);
3332                 memcpy(&ina.s_addr, rdata->data, 4);
3333                 isc_netaddr_fromin(netaddr, &ina);
3334                 return (ISC_R_SUCCESS);
3335         case dns_rdatatype_aaaa:
3336                 INSIST(rdata->length == 16);
3337                 memcpy(in6a.s6_addr, rdata->data, 16);
3338                 isc_netaddr_fromin6(netaddr, &in6a);
3339                 return (ISC_R_SUCCESS);
3340         default:
3341                 return (ISC_R_NOTIMPLEMENTED);
3342         }
3343 }
3344
3345 /*
3346  * Find the sort order of 'rdata' in the topology-like
3347  * ACL forming the second element in a 2-element top-level
3348  * sortlist statement.
3349  */
3350 static int
3351 query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
3352         isc_netaddr_t netaddr;
3353
3354         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3355                 return (INT_MAX);
3356         return (ns_sortlist_addrorder2(&netaddr, arg));
3357 }
3358
3359 /*
3360  * Find the sort order of 'rdata' in the matching element
3361  * of a 1-element top-level sortlist statement.
3362  */
3363 static int
3364 query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
3365         isc_netaddr_t netaddr;
3366
3367         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3368                 return (INT_MAX);
3369         return (ns_sortlist_addrorder1(&netaddr, arg));
3370 }
3371
3372 /*
3373  * Find the sortlist statement that applies to 'client' and set up
3374  * the sortlist info in in client->message appropriately.
3375  */
3376 static void
3377 setup_query_sortlist(ns_client_t *client) {
3378         isc_netaddr_t netaddr;
3379         dns_rdatasetorderfunc_t order = NULL;
3380         const void *order_arg = NULL;
3381
3382         isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
3383         switch (ns_sortlist_setup(client->view->sortlist,
3384                                &netaddr, &order_arg)) {
3385         case NS_SORTLISTTYPE_1ELEMENT:
3386                 order = query_sortlist_order_1element;
3387                 break;
3388         case NS_SORTLISTTYPE_2ELEMENT:
3389                 order = query_sortlist_order_2element;
3390                 break;
3391         case NS_SORTLISTTYPE_NONE:
3392                 order = NULL;
3393                 break;
3394         default:
3395                 INSIST(0);
3396                 break;
3397         }
3398         dns_message_setsortorder(client->message, order, order_arg);
3399 }
3400
3401 static void
3402 query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) {
3403         isc_buffer_t *dbuf, b;
3404         dns_name_t *fname;
3405         dns_rdataset_t *neg, *negsig;
3406         isc_result_t result = ISC_R_NOMEMORY;
3407
3408         CTRACE("query_addnoqnameproof");
3409
3410         fname = NULL;
3411         neg = NULL;
3412         negsig = NULL;
3413
3414         dbuf = query_getnamebuf(client);
3415         if (dbuf == NULL)
3416                 goto cleanup;
3417         fname = query_newname(client, dbuf, &b);
3418         neg = query_newrdataset(client);
3419         negsig = query_newrdataset(client);
3420         if (fname == NULL || neg == NULL || negsig == NULL)
3421                 goto cleanup;
3422
3423         result = dns_rdataset_getnoqname(rdataset, fname, neg, negsig);
3424         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3425
3426         query_addrrset(client, &fname, &neg, &negsig, dbuf,
3427                        DNS_SECTION_AUTHORITY);
3428
3429         if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) == 0)
3430                 goto cleanup;
3431
3432         if (fname == NULL) {
3433                 dbuf = query_getnamebuf(client);
3434                 if (dbuf == NULL)
3435                         goto cleanup;
3436                 fname = query_newname(client, dbuf, &b);
3437         }
3438         if (neg == NULL)
3439                 neg = query_newrdataset(client);
3440         else if (dns_rdataset_isassociated(neg))
3441                 dns_rdataset_disassociate(neg);
3442         if (negsig == NULL)
3443                 negsig = query_newrdataset(client);
3444         else if (dns_rdataset_isassociated(negsig))
3445                 dns_rdataset_disassociate(negsig);
3446         if (fname == NULL || neg == NULL || negsig == NULL)
3447                 goto cleanup;
3448         result = dns_rdataset_getclosest(rdataset, fname, neg, negsig);
3449         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3450
3451         query_addrrset(client, &fname, &neg, &negsig, dbuf,
3452                        DNS_SECTION_AUTHORITY);
3453
3454  cleanup:
3455         if (neg != NULL)
3456                 query_putrdataset(client, &neg);
3457         if (negsig != NULL)
3458                 query_putrdataset(client, &negsig);
3459         if (fname != NULL)
3460                 query_releasename(client, &fname);
3461 }
3462
3463 static inline void
3464 answer_in_glue(ns_client_t *client, dns_rdatatype_t qtype) {
3465         dns_name_t *name;
3466         dns_message_t *msg;
3467         dns_section_t section = DNS_SECTION_ADDITIONAL;
3468         dns_rdataset_t *rdataset = NULL;
3469
3470         msg = client->message;
3471         for (name = ISC_LIST_HEAD(msg->sections[section]);
3472              name != NULL;
3473              name = ISC_LIST_NEXT(name, link))
3474                 if (dns_name_equal(name, client->query.qname)) {
3475                         for (rdataset = ISC_LIST_HEAD(name->list);
3476                              rdataset != NULL;
3477                              rdataset = ISC_LIST_NEXT(rdataset, link))
3478                                 if (rdataset->type == qtype)
3479                                         break;
3480                         break;
3481                 }
3482         if (rdataset != NULL) {
3483                 ISC_LIST_UNLINK(msg->sections[section], name, link);
3484                 ISC_LIST_PREPEND(msg->sections[section], name, link);
3485                 ISC_LIST_UNLINK(name->list, rdataset, link);
3486                 ISC_LIST_PREPEND(name->list, rdataset, link);
3487                 rdataset->attributes |= DNS_RDATASETATTR_REQUIREDGLUE;
3488         }
3489 }
3490
3491 #define NS_NAME_INIT(A,B) \
3492          { \
3493                 DNS_NAME_MAGIC, \
3494                 A, sizeof(A), sizeof(B), \
3495                 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \
3496                 B, NULL, { (void *)-1, (void *)-1}, \
3497                 {NULL, NULL} \
3498         }
3499
3500 static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
3501 static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
3502 static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
3503
3504 static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
3505
3506 static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
3507 static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
3508 static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
3509 static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
3510 static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
3511 static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
3512 static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
3513 static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
3514 static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
3515 static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
3516 static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
3517 static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
3518 static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
3519 static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
3520 static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
3521 static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
3522
3523 static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
3524
3525 static dns_name_t rfc1918names[] = {
3526         NS_NAME_INIT(inaddr10, inaddr10_offsets),
3527         NS_NAME_INIT(inaddr16172, inaddr172_offsets),
3528         NS_NAME_INIT(inaddr17172, inaddr172_offsets),
3529         NS_NAME_INIT(inaddr18172, inaddr172_offsets),
3530         NS_NAME_INIT(inaddr19172, inaddr172_offsets),
3531         NS_NAME_INIT(inaddr20172, inaddr172_offsets),
3532         NS_NAME_INIT(inaddr21172, inaddr172_offsets),
3533         NS_NAME_INIT(inaddr22172, inaddr172_offsets),
3534         NS_NAME_INIT(inaddr23172, inaddr172_offsets),
3535         NS_NAME_INIT(inaddr24172, inaddr172_offsets),
3536         NS_NAME_INIT(inaddr25172, inaddr172_offsets),
3537         NS_NAME_INIT(inaddr26172, inaddr172_offsets),
3538         NS_NAME_INIT(inaddr27172, inaddr172_offsets),
3539         NS_NAME_INIT(inaddr28172, inaddr172_offsets),
3540         NS_NAME_INIT(inaddr29172, inaddr172_offsets),
3541         NS_NAME_INIT(inaddr30172, inaddr172_offsets),
3542         NS_NAME_INIT(inaddr31172, inaddr172_offsets),
3543         NS_NAME_INIT(inaddr168192, inaddr192_offsets)
3544 };
3545
3546
3547 static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
3548 static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org";
3549
3550 static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
3551 static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
3552
3553 static dns_name_t prisoner = NS_NAME_INIT(prisoner_data, prisoner_offsets);
3554 static dns_name_t hostmaster = NS_NAME_INIT(hostmaster_data, hostmaster_offsets);
3555
3556 static void
3557 warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
3558         unsigned int i;
3559         dns_rdata_t rdata = DNS_RDATA_INIT;
3560         dns_rdata_soa_t soa;
3561         dns_rdataset_t found;
3562         isc_result_t result;
3563
3564         for (i = 0; i < (sizeof(rfc1918names)/sizeof(*rfc1918names)); i++) {
3565                 if (dns_name_issubdomain(fname, &rfc1918names[i])) {
3566                         dns_rdataset_init(&found);
3567                         result = dns_ncache_getrdataset(rdataset,
3568                                                         &rfc1918names[i],
3569                                                         dns_rdatatype_soa,
3570                                                         &found);
3571                         if (result != ISC_R_SUCCESS)
3572                                 return;
3573
3574                         result = dns_rdataset_first(&found);
3575                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3576                         dns_rdataset_current(&found, &rdata);
3577                         result = dns_rdata_tostruct(&rdata, &soa, NULL);
3578                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3579                         if (dns_name_equal(&soa.origin, &prisoner) &&
3580                             dns_name_equal(&soa.contact, &hostmaster)) {
3581                                 char buf[DNS_NAME_FORMATSIZE];
3582                                 dns_name_format(fname, buf, sizeof(buf));
3583                                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3584                                               NS_LOGMODULE_QUERY,
3585                                               ISC_LOG_WARNING,
3586                                               "RFC 1918 response from "
3587                                               "Internet for %s", buf);
3588                         }
3589                         dns_rdataset_disassociate(&found);
3590                         return;
3591                 }
3592         }
3593 }
3594
3595 static void
3596 query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
3597                        dns_dbversion_t *version, ns_client_t *client,
3598                        dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
3599                        dns_name_t *fname, isc_boolean_t exact,
3600                        dns_name_t *found)
3601 {
3602         unsigned char salt[256];
3603         size_t salt_length = sizeof(salt);
3604         isc_uint16_t iterations;
3605         isc_result_t result;
3606         unsigned int dboptions;
3607         dns_fixedname_t fixed;
3608         dns_hash_t hash;
3609         dns_name_t name;
3610         int order;
3611         unsigned int count;
3612         dns_rdata_nsec3_t nsec3;
3613         dns_rdata_t rdata = DNS_RDATA_INIT;
3614         isc_boolean_t optout;
3615
3616         salt_length = sizeof(salt);
3617         result = dns_db_getnsec3parameters(db, version, &hash, NULL,
3618                                            &iterations, salt, &salt_length);
3619         if (result != ISC_R_SUCCESS)
3620                 return;
3621
3622         dns_name_init(&name, NULL);
3623         dns_name_clone(qname, &name);
3624
3625         /*
3626          * Map unknown algorithm to known value.
3627          */
3628         if (hash == DNS_NSEC3_UNKNOWNALG)
3629                 hash = 1;
3630
3631  again:
3632         dns_fixedname_init(&fixed);
3633         result = dns_nsec3_hashname(&fixed, NULL, NULL, &name,
3634                                     dns_db_origin(db), hash,
3635                                     iterations, salt, salt_length);
3636         if (result != ISC_R_SUCCESS)
3637                 return;
3638
3639         dboptions = client->query.dboptions | DNS_DBFIND_FORCENSEC3;
3640         result = dns_db_find(db, dns_fixedname_name(&fixed), version,
3641                              dns_rdatatype_nsec3, dboptions, client->now,
3642                              NULL, fname, rdataset, sigrdataset);
3643
3644         if (result == DNS_R_NXDOMAIN) {
3645                 if (!dns_rdataset_isassociated(rdataset)) {
3646                         return;
3647                 }
3648                 result = dns_rdataset_first(rdataset);
3649                 INSIST(result == ISC_R_SUCCESS);
3650                 dns_rdataset_current(rdataset, &rdata);
3651                 dns_rdata_tostruct(&rdata, &nsec3, NULL);
3652                 dns_rdata_reset(&rdata);
3653                 optout = ISC_TF((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
3654                 if (found != NULL && optout &&
3655                     dns_name_fullcompare(&name, dns_db_origin(db), &order,
3656                                          &count) == dns_namereln_subdomain) {
3657                         dns_rdataset_disassociate(rdataset);
3658                         if (dns_rdataset_isassociated(sigrdataset))
3659                                 dns_rdataset_disassociate(sigrdataset);
3660                         count = dns_name_countlabels(&name) - 1;
3661                         dns_name_getlabelsequence(&name, 1, count, &name);
3662                         ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
3663                                       NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3),
3664                                       "looking for closest provable encloser");
3665                         goto again;
3666                 }
3667                 if (exact)
3668                         ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
3669                                       NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
3670                                       "expected a exact match NSEC3, got "
3671                                       "a covering record");
3672
3673         } else if (result != ISC_R_SUCCESS) {
3674                 return;
3675         } else if (!exact)
3676                 ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
3677                               NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
3678                               "expected covering NSEC3, got an exact match");
3679         if (found != NULL)
3680                 dns_name_copy(&name, found, NULL);
3681         return;
3682 }
3683
3684 /*
3685  * Do the bulk of query processing for the current query of 'client'.
3686  * If 'event' is non-NULL, we are returning from recursion and 'qtype'
3687  * is ignored.  Otherwise, 'qtype' is the query type.
3688  */
3689 static isc_result_t
3690 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
3691 {
3692         dns_db_t *db, *zdb;
3693         dns_dbnode_t *node;
3694         dns_rdatatype_t type;
3695         dns_name_t *fname, *zfname, *tname, *prefix;
3696         dns_rdataset_t *rdataset, *trdataset;
3697         dns_rdataset_t *sigrdataset, *zrdataset, *zsigrdataset;
3698         dns_rdataset_t **sigrdatasetp;
3699         dns_rdata_t rdata = DNS_RDATA_INIT;
3700         dns_rdatasetiter_t *rdsiter;
3701         isc_boolean_t want_restart, authoritative, is_zone, need_wildcardproof;
3702         unsigned int n, nlabels;
3703         dns_namereln_t namereln;
3704         int order;
3705         isc_buffer_t *dbuf;
3706         isc_buffer_t b;
3707         isc_result_t result, eresult;
3708         dns_fixedname_t fixed;
3709         dns_fixedname_t wildcardname;
3710         dns_dbversion_t *version, *zversion;
3711         dns_zone_t *zone;
3712         dns_rdata_cname_t cname;
3713         dns_rdata_dname_t dname;
3714         unsigned int options;
3715         isc_boolean_t empty_wild;
3716         dns_rdataset_t *noqname;
3717         isc_boolean_t resuming;
3718         int line = -1;
3719
3720         CTRACE("query_find");
3721
3722         /*
3723          * One-time initialization.
3724          *
3725          * It's especially important to initialize anything that the cleanup
3726          * code might cleanup.
3727          */
3728
3729         eresult = ISC_R_SUCCESS;
3730         fname = NULL;
3731         zfname = NULL;
3732         rdataset = NULL;
3733         zrdataset = NULL;
3734         sigrdataset = NULL;
3735         zsigrdataset = NULL;
3736         zversion = NULL;
3737         node = NULL;
3738         db = NULL;
3739         zdb = NULL;
3740         version = NULL;
3741         zone = NULL;
3742         need_wildcardproof = ISC_FALSE;
3743         empty_wild = ISC_FALSE;
3744         options = 0;
3745         resuming = ISC_FALSE;
3746         is_zone = ISC_FALSE;
3747
3748         if (event != NULL) {
3749                 /*
3750                  * We're returning from recursion.  Restore the query context
3751                  * and resume.
3752                  */
3753
3754                 want_restart = ISC_FALSE;
3755                 authoritative = ISC_FALSE;
3756
3757                 qtype = event->qtype;
3758                 if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3759                         type = dns_rdatatype_any;
3760                 else
3761                         type = qtype;
3762                 db = event->db;
3763                 node = event->node;
3764                 rdataset = event->rdataset;
3765                 sigrdataset = event->sigrdataset;
3766
3767                 /*
3768                  * We'll need some resources...
3769                  */
3770                 dbuf = query_getnamebuf(client);
3771                 if (dbuf == NULL) {
3772                         QUERY_ERROR(DNS_R_SERVFAIL);
3773                         goto cleanup;
3774                 }
3775                 fname = query_newname(client, dbuf, &b);
3776                 if (fname == NULL) {
3777                         QUERY_ERROR(DNS_R_SERVFAIL);
3778                         goto cleanup;
3779                 }
3780                 tname = dns_fixedname_name(&event->foundname);
3781                 result = dns_name_copy(tname, fname, NULL);
3782                 if (result != ISC_R_SUCCESS) {
3783                         QUERY_ERROR(DNS_R_SERVFAIL);
3784                         goto cleanup;
3785                 }
3786
3787                 result = event->result;
3788                 resuming = ISC_TRUE;
3789
3790                 goto resume;
3791         }
3792
3793         /*
3794          * Not returning from recursion.
3795          */
3796
3797         /*
3798          * If it's a SIG query, we'll iterate the node.
3799          */
3800         if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3801                 type = dns_rdatatype_any;
3802         else
3803                 type = qtype;
3804
3805  restart:
3806         CTRACE("query_find: restart");
3807         want_restart = ISC_FALSE;
3808         authoritative = ISC_FALSE;
3809         version = NULL;
3810         need_wildcardproof = ISC_FALSE;
3811
3812         if (client->view->checknames &&
3813             !dns_rdata_checkowner(client->query.qname,
3814                                   client->message->rdclass,
3815                                   qtype, ISC_FALSE)) {
3816                 char namebuf[DNS_NAME_FORMATSIZE];
3817                 char typename[DNS_RDATATYPE_FORMATSIZE];
3818                 char classname[DNS_RDATACLASS_FORMATSIZE];
3819
3820                 dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
3821                 dns_rdatatype_format(qtype, typename, sizeof(typename));
3822                 dns_rdataclass_format(client->message->rdclass, classname,
3823                                       sizeof(classname));
3824                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3825                               NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
3826                               "check-names failure %s/%s/%s", namebuf,
3827                               typename, classname);
3828                 QUERY_ERROR(DNS_R_REFUSED);
3829                 goto cleanup;
3830         }
3831
3832         /*
3833          * First we must find the right database.
3834          */
3835         options &= DNS_GETDB_NOLOG; /* Preserve DNS_GETDB_NOLOG. */
3836         if (dns_rdatatype_atparent(qtype) &&
3837             !dns_name_equal(client->query.qname, dns_rootname))
3838                 options |= DNS_GETDB_NOEXACT;
3839         result = query_getdb(client, client->query.qname, qtype, options,
3840                              &zone, &db, &version, &is_zone);
3841         if ((result != ISC_R_SUCCESS || !is_zone) && !RECURSIONOK(client) &&
3842             (options & DNS_GETDB_NOEXACT) != 0 && qtype == dns_rdatatype_ds) {
3843                 /*
3844                  * Look to see if we are authoritative for the
3845                  * child zone if the query type is DS.
3846                  */
3847                 dns_db_t *tdb = NULL;
3848                 dns_zone_t *tzone = NULL;
3849                 dns_dbversion_t *tversion = NULL;
3850                 isc_result_t tresult;
3851
3852                 tresult = query_getzonedb(client, client->query.qname, qtype,
3853                                          DNS_GETDB_PARTIAL, &tzone, &tdb,
3854                                          &tversion);
3855                 if (tresult == ISC_R_SUCCESS) {
3856                         options &= ~DNS_GETDB_NOEXACT;
3857                         query_putrdataset(client, &rdataset);
3858                         if (db != NULL)
3859                                 dns_db_detach(&db);
3860                         if (zone != NULL)
3861                                 dns_zone_detach(&zone);
3862                         version = tversion;
3863                         db = tdb;
3864                         zone = tzone;
3865                         is_zone = ISC_TRUE;
3866                         result = ISC_R_SUCCESS;
3867                 } else {
3868                         if (tdb != NULL)
3869                                 dns_db_detach(&tdb);
3870                         if (tzone != NULL)
3871                                 dns_zone_detach(&tzone);
3872                 }
3873         }
3874         if (result != ISC_R_SUCCESS) {
3875                 if (result == DNS_R_REFUSED) {
3876                         if (WANTRECURSION(client)) {
3877                                 inc_stats(client,
3878                                           dns_nsstatscounter_recurserej);
3879                         } else
3880                                 inc_stats(client, dns_nsstatscounter_authrej);
3881                         if (!PARTIALANSWER(client))
3882                                 QUERY_ERROR(DNS_R_REFUSED);
3883                 } else
3884                         QUERY_ERROR(DNS_R_SERVFAIL);
3885                 goto cleanup;
3886         }
3887
3888         if (is_zone)
3889                 authoritative = ISC_TRUE;
3890
3891         if (event == NULL && client->query.restarts == 0) {
3892                 if (is_zone) {
3893 #ifdef DLZ
3894                         if (zone != NULL) {
3895                                 /*
3896                                  * if is_zone = true, zone = NULL then this is
3897                                  * a DLZ zone.  Don't attempt to attach zone.
3898                                  */
3899 #endif
3900                                 dns_zone_attach(zone, &client->query.authzone);
3901 #ifdef DLZ
3902                         }
3903 #endif
3904                         dns_db_attach(db, &client->query.authdb);
3905                 }
3906                 client->query.authdbset = ISC_TRUE;
3907         }
3908
3909  db_find:
3910         CTRACE("query_find: db_find");
3911         /*
3912          * We'll need some resources...
3913          */
3914         dbuf = query_getnamebuf(client);
3915         if (dbuf == NULL) {
3916                 QUERY_ERROR(DNS_R_SERVFAIL);
3917                 goto cleanup;
3918         }
3919         fname = query_newname(client, dbuf, &b);
3920         rdataset = query_newrdataset(client);
3921         if (fname == NULL || rdataset == NULL) {
3922                 QUERY_ERROR(DNS_R_SERVFAIL);
3923                 goto cleanup;
3924         }
3925         if (WANTDNSSEC(client) && (!is_zone || dns_db_issecure(db))) {
3926                 sigrdataset = query_newrdataset(client);
3927                 if (sigrdataset == NULL) {
3928                         QUERY_ERROR(DNS_R_SERVFAIL);
3929                         goto cleanup;
3930                 }
3931         }
3932
3933         /*
3934          * Now look for an answer in the database.
3935          */
3936         result = dns_db_find(db, client->query.qname, version, type,
3937                              client->query.dboptions, client->now,
3938                              &node, fname, rdataset, sigrdataset);
3939
3940  resume:
3941         CTRACE("query_find: resume");
3942         switch (result) {
3943         case ISC_R_SUCCESS:
3944                 /*
3945                  * This case is handled in the main line below.
3946                  */
3947                 break;
3948         case DNS_R_GLUE:
3949         case DNS_R_ZONECUT:
3950                 /*
3951                  * These cases are handled in the main line below.
3952                  */
3953                 INSIST(is_zone);
3954                 authoritative = ISC_FALSE;
3955                 break;
3956         case ISC_R_NOTFOUND:
3957                 /*
3958                  * The cache doesn't even have the root NS.  Get them from
3959                  * the hints DB.
3960                  */
3961                 INSIST(!is_zone);
3962                 if (db != NULL)
3963                         dns_db_detach(&db);
3964
3965                 if (client->view->hints == NULL) {
3966                         /* We have no hints. */
3967                         result = ISC_R_FAILURE;
3968                 } else {
3969                         dns_db_attach(client->view->hints, &db);
3970                         result = dns_db_find(db, dns_rootname,
3971                                              NULL, dns_rdatatype_ns,
3972                                              0, client->now, &node, fname,
3973                                              rdataset, sigrdataset);
3974                 }
3975                 if (result != ISC_R_SUCCESS) {
3976                         /*
3977                          * Nonsensical root hints may require cleanup.
3978                          */
3979                         if (dns_rdataset_isassociated(rdataset))
3980                                 dns_rdataset_disassociate(rdataset);
3981                         if (sigrdataset != NULL &&
3982                             dns_rdataset_isassociated(sigrdataset))
3983                                 dns_rdataset_disassociate(sigrdataset);
3984                         if (node != NULL)
3985                                 dns_db_detachnode(db, &node);
3986
3987                         /*
3988                          * We don't have any root server hints, but
3989                          * we may have working forwarders, so try to
3990                          * recurse anyway.
3991                          */
3992                         if (RECURSIONOK(client)) {
3993                                 result = query_recurse(client, qtype,
3994                                                        NULL, NULL, resuming);
3995                                 if (result == ISC_R_SUCCESS)
3996                                         client->query.attributes |=
3997                                                 NS_QUERYATTR_RECURSING;
3998                                 else if (result == DNS_R_DUPLICATE ||
3999                                          result == DNS_R_DROP) {
4000                                         /* Duplicate query. */
4001                                         QUERY_ERROR(result);
4002                                 } else {
4003                                         /* Unable to recurse. */
4004                                         QUERY_ERROR(DNS_R_SERVFAIL);
4005                                 }
4006                                 goto cleanup;
4007                         } else {
4008                                 /* Unable to give root server referral. */
4009                                 QUERY_ERROR(DNS_R_SERVFAIL);
4010                                 goto cleanup;
4011                         }
4012                 }
4013                 /*
4014                  * XXXRTH  We should trigger root server priming here.
4015                  */
4016                 /* FALLTHROUGH */
4017         case DNS_R_DELEGATION:
4018                 authoritative = ISC_FALSE;
4019                 if (is_zone) {
4020                         /*
4021                          * Look to see if we are authoritative for the
4022                          * child zone if the query type is DS.
4023                          */
4024                         if (!RECURSIONOK(client) &&
4025                             (options & DNS_GETDB_NOEXACT) != 0 &&
4026                             qtype == dns_rdatatype_ds) {
4027                                 dns_db_t *tdb = NULL;
4028                                 dns_zone_t *tzone = NULL;
4029                                 dns_dbversion_t *tversion = NULL;
4030                                 result = query_getzonedb(client,
4031                                                          client->query.qname,
4032                                                          qtype,
4033                                                          DNS_GETDB_PARTIAL,
4034                                                          &tzone, &tdb,
4035                                                          &tversion);
4036                                 if (result == ISC_R_SUCCESS) {
4037                                         options &= ~DNS_GETDB_NOEXACT;
4038                                         query_putrdataset(client, &rdataset);
4039                                         if (sigrdataset != NULL)
4040                                                 query_putrdataset(client,
4041                                                                   &sigrdataset);
4042                                         if (fname != NULL)
4043                                                 query_releasename(client,
4044                                                                   &fname);
4045                                         if (node != NULL)
4046                                                 dns_db_detachnode(db, &node);
4047                                         if (db != NULL)
4048                                                 dns_db_detach(&db);
4049                                         if (zone != NULL)
4050                                                 dns_zone_detach(&zone);
4051                                         version = tversion;
4052                                         db = tdb;
4053                                         zone = tzone;
4054                                         authoritative = ISC_TRUE;
4055                                         goto db_find;
4056                                 }
4057                                 if (tdb != NULL)
4058                                         dns_db_detach(&tdb);
4059                                 if (tzone != NULL)
4060                                         dns_zone_detach(&tzone);
4061                         }
4062                         /*
4063                          * We're authoritative for an ancestor of QNAME.
4064                          */
4065                         if (!USECACHE(client) || !RECURSIONOK(client)) {
4066                                 dns_fixedname_t fixed;
4067
4068                                 dns_fixedname_init(&fixed);
4069                                 dns_name_copy(fname,
4070                                               dns_fixedname_name(&fixed), NULL);
4071
4072                                 /*
4073                                  * If we don't have a cache, this is the best
4074                                  * answer.
4075                                  *
4076                                  * If the client is making a nonrecursive
4077                                  * query we always give out the authoritative
4078                                  * delegation.  This way even if we get
4079                                  * junk in our cache, we won't fail in our
4080                                  * role as the delegating authority if another
4081                                  * nameserver asks us about a delegated
4082                                  * subzone.
4083                                  *
4084                                  * We enable the retrieval of glue for this
4085                                  * database by setting client->query.gluedb.
4086                                  */
4087                                 client->query.gluedb = db;
4088                                 client->query.isreferral = ISC_TRUE;
4089                                 /*
4090                                  * We must ensure NOADDITIONAL is off,
4091                                  * because the generation of
4092                                  * additional data is required in
4093                                  * delegations.
4094                                  */
4095                                 client->query.attributes &=
4096                                         ~NS_QUERYATTR_NOADDITIONAL;
4097                                 if (sigrdataset != NULL)
4098                                         sigrdatasetp = &sigrdataset;
4099                                 else
4100                                         sigrdatasetp = NULL;
4101                                 query_addrrset(client, &fname,
4102                                                &rdataset, sigrdatasetp,
4103                                                dbuf, DNS_SECTION_AUTHORITY);
4104                                 client->query.gluedb = NULL;
4105                                 if (WANTDNSSEC(client))
4106                                         query_addds(client, db, node, version,
4107                                                    dns_fixedname_name(&fixed));
4108                         } else {
4109                                 /*
4110                                  * We might have a better answer or delegation
4111                                  * in the cache.  We'll remember the current
4112                                  * values of fname, rdataset, and sigrdataset.
4113                                  * We'll then go looking for QNAME in the
4114                                  * cache.  If we find something better, we'll
4115                                  * use it instead.
4116                                  */
4117                                 query_keepname(client, fname, dbuf);
4118                                 zdb = db;
4119                                 zfname = fname;
4120                                 fname = NULL;
4121                                 zrdataset = rdataset;
4122                                 rdataset = NULL;
4123                                 zsigrdataset = sigrdataset;
4124                                 sigrdataset = NULL;
4125                                 dns_db_detachnode(db, &node);
4126                                 zversion = version;
4127                                 version = NULL;
4128                                 db = NULL;
4129                                 dns_db_attach(client->view->cachedb, &db);
4130                                 is_zone = ISC_FALSE;
4131                                 goto db_find;
4132                         }
4133                 } else {
4134                         if (zfname != NULL &&
4135                             !dns_name_issubdomain(fname, zfname)) {
4136                                 /*
4137                                  * We've already got a delegation from
4138                                  * authoritative data, and it is better
4139                                  * than what we found in the cache.  Use
4140                                  * it instead of the cache delegation.
4141                                  */
4142                                 query_releasename(client, &fname);
4143                                 fname = zfname;
4144                                 zfname = NULL;
4145                                 /*
4146                                  * We've already done query_keepname() on
4147                                  * zfname, so we must set dbuf to NULL to
4148                                  * prevent query_addrrset() from trying to
4149                                  * call query_keepname() again.
4150                                  */
4151                                 dbuf = NULL;
4152                                 query_putrdataset(client, &rdataset);
4153                                 if (sigrdataset != NULL)
4154                                         query_putrdataset(client,
4155                                                           &sigrdataset);
4156                                 rdataset = zrdataset;
4157                                 zrdataset = NULL;
4158                                 sigrdataset = zsigrdataset;
4159                                 zsigrdataset = NULL;
4160                                 version = zversion;
4161                                 zversion = NULL;
4162                                 /*
4163                                  * We don't clean up zdb here because we
4164                                  * may still need it.  It will get cleaned
4165                                  * up by the main cleanup code.
4166                                  */
4167                         }
4168
4169                         if (RECURSIONOK(client)) {
4170                                 /*
4171                                  * Recurse!
4172                                  */
4173                                 if (dns_rdatatype_atparent(type))
4174                                         result = query_recurse(client, qtype,
4175                                                                NULL, NULL,
4176                                                                resuming);
4177                                 else
4178                                         result = query_recurse(client, qtype,
4179                                                                fname, rdataset,
4180                                                                resuming);
4181                                 if (result == ISC_R_SUCCESS)
4182                                         client->query.attributes |=
4183                                                 NS_QUERYATTR_RECURSING;
4184                                 else if (result == DNS_R_DUPLICATE ||
4185                                          result == DNS_R_DROP)
4186                                         QUERY_ERROR(result);
4187                                 else
4188                                         QUERY_ERROR(DNS_R_SERVFAIL);
4189                         } else {
4190                                 dns_fixedname_t fixed;
4191
4192                                 dns_fixedname_init(&fixed);
4193                                 dns_name_copy(fname,
4194                                               dns_fixedname_name(&fixed), NULL);
4195                                 /*
4196                                  * This is the best answer.
4197                                  */
4198                                 client->query.attributes |=
4199                                         NS_QUERYATTR_CACHEGLUEOK;
4200                                 client->query.gluedb = zdb;
4201                                 client->query.isreferral = ISC_TRUE;
4202                                 /*
4203                                  * We must ensure NOADDITIONAL is off,
4204                                  * because the generation of
4205                                  * additional data is required in
4206                                  * delegations.
4207                                  */
4208                                 client->query.attributes &=
4209                                         ~NS_QUERYATTR_NOADDITIONAL;
4210                                 if (sigrdataset != NULL)
4211                                         sigrdatasetp = &sigrdataset;
4212                                 else
4213                                         sigrdatasetp = NULL;
4214                                 query_addrrset(client, &fname,
4215                                                &rdataset, sigrdatasetp,
4216                                                dbuf, DNS_SECTION_AUTHORITY);
4217                                 client->query.gluedb = NULL;
4218                                 client->query.attributes &=
4219                                         ~NS_QUERYATTR_CACHEGLUEOK;
4220                                 if (WANTDNSSEC(client))
4221                                         query_addds(client, db, node, version,
4222                                                    dns_fixedname_name(&fixed));
4223                         }
4224                 }
4225                 goto cleanup;
4226         case DNS_R_EMPTYNAME:
4227                 result = DNS_R_NXRRSET;
4228                 /* FALLTHROUGH */
4229         case DNS_R_NXRRSET:
4230                 INSIST(is_zone);
4231                 /*
4232                  * Look for a NSEC3 record if we don't have a NSEC record.
4233                  */
4234                 if (!dns_rdataset_isassociated(rdataset) &&
4235                      WANTDNSSEC(client)) {
4236                         if ((fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
4237                                 dns_name_t *found;
4238                                 dns_name_t *qname;
4239
4240                                 dns_fixedname_init(&fixed);
4241                                 found = dns_fixedname_name(&fixed);
4242                                 qname = client->query.qname;
4243
4244                                 query_findclosestnsec3(qname, db, version,
4245                                                        client, rdataset,
4246                                                        sigrdataset, fname,
4247                                                        ISC_TRUE, found);
4248                                 /*
4249                                  * Did we find the closest provable encloser
4250                                  * instead? If so add the nearest to the
4251                                  * closest provable encloser.
4252                                  */
4253                                 if (found &&
4254                                     dns_rdataset_isassociated(rdataset) &&
4255                                     !dns_name_equal(qname, found))
4256                                 {
4257                                         unsigned int count;
4258                                         unsigned int skip;
4259
4260                                         /*
4261                                          * Add the closest provable encloser.
4262                                          */
4263                                         query_addrrset(client, &fname,
4264                                                        &rdataset, &sigrdataset,
4265                                                        dbuf,
4266                                                        DNS_SECTION_AUTHORITY);
4267
4268                                         count = dns_name_countlabels(found)
4269                                                          + 1;
4270                                         skip = dns_name_countlabels(qname) -
4271                                                          count;
4272                                         dns_name_getlabelsequence(qname, skip,
4273                                                                   count,
4274                                                                   found);
4275
4276                                         fixfname(client, &fname, &dbuf, &b);
4277                                         fixrdataset(client, &rdataset);
4278                                         fixrdataset(client, &sigrdataset);
4279                                         if (fname == NULL ||
4280                                             rdataset == NULL ||
4281                                             sigrdataset == NULL) {
4282                                                 QUERY_ERROR(DNS_R_SERVFAIL);
4283                                                 goto cleanup;
4284                                         }
4285                                         /*
4286                                          * 'nearest' doesn't exist so
4287                                          * 'exist' is set to ISC_FALSE.
4288                                          */
4289                                         query_findclosestnsec3(found, db,
4290                                                                version,
4291                                                                client,
4292                                                                rdataset,
4293                                                                sigrdataset,
4294                                                                fname,
4295                                                                ISC_FALSE,
4296                                                                NULL);
4297                                 }
4298                         } else {
4299                                 query_releasename(client, &fname);
4300                                 query_addwildcardproof(client, db, version,
4301                                                        client->query.qname,
4302                                                        ISC_FALSE);
4303                         }
4304                 }
4305                 if (dns_rdataset_isassociated(rdataset)) {
4306                         /*
4307                          * If we've got a NSEC record, we need to save the
4308                          * name now because we're going call query_addsoa()
4309                          * below, and it needs to use the name buffer.
4310                          */
4311                         query_keepname(client, fname, dbuf);
4312                 } else if (fname != NULL) {
4313                         /*
4314                          * We're not going to use fname, and need to release
4315                          * our hold on the name buffer so query_addsoa()
4316                          * may use it.
4317                          */
4318                         query_releasename(client, &fname);
4319                 }
4320                 /*
4321                  * Add SOA.
4322                  */
4323                 result = query_addsoa(client, db, version, ISC_FALSE);
4324                 if (result != ISC_R_SUCCESS) {
4325                         QUERY_ERROR(result);
4326                         goto cleanup;
4327                 }
4328                 /*
4329                  * Add NSEC record if we found one.
4330                  */
4331                 if (WANTDNSSEC(client)) {
4332                         if (dns_rdataset_isassociated(rdataset))
4333                                 query_addnxrrsetnsec(client, db, version,
4334                                                      &fname, &rdataset,
4335                                                      &sigrdataset);
4336                 }
4337                 goto cleanup;
4338
4339         case DNS_R_EMPTYWILD:
4340                 empty_wild = ISC_TRUE;
4341                 /* FALLTHROUGH */
4342
4343         case DNS_R_NXDOMAIN:
4344                 INSIST(is_zone);
4345                 if (dns_rdataset_isassociated(rdataset)) {
4346                         /*
4347                          * If we've got a NSEC record, we need to save the
4348                          * name now because we're going call query_addsoa()
4349                          * below, and it needs to use the name buffer.
4350                          */
4351                         query_keepname(client, fname, dbuf);
4352                 } else if (fname != NULL) {
4353                         /*
4354                          * We're not going to use fname, and need to release
4355                          * our hold on the name buffer so query_addsoa()
4356                          * may use it.
4357                          */
4358                         query_releasename(client, &fname);
4359                 }
4360                 /*
4361                  * Add SOA.  If the query was for a SOA record force the
4362                  * ttl to zero so that it is possible for clients to find
4363                  * the containing zone of an arbitrary name with a stub
4364                  * resolver and not have it cached.
4365                  */
4366                 if (qtype == dns_rdatatype_soa &&
4367 #ifdef DLZ
4368                     zone != NULL &&
4369 #endif
4370                     dns_zone_getzeronosoattl(zone))
4371                         result = query_addsoa(client, db, version, ISC_TRUE);
4372                 else
4373                         result = query_addsoa(client, db, version, ISC_FALSE);
4374                 if (result != ISC_R_SUCCESS) {
4375                         QUERY_ERROR(result);
4376                         goto cleanup;
4377                 }
4378
4379                 if (WANTDNSSEC(client)) {
4380                         /*
4381                          * Add NSEC record if we found one.
4382                          */
4383                         if (dns_rdataset_isassociated(rdataset))
4384                                 query_addrrset(client, &fname, &rdataset,
4385                                                &sigrdataset,
4386                                                NULL, DNS_SECTION_AUTHORITY);
4387                         query_addwildcardproof(client, db, version,
4388                                                client->query.qname, ISC_FALSE);
4389                 }
4390
4391                 /*
4392                  * Set message rcode.
4393                  */
4394                 if (empty_wild)
4395                         client->message->rcode = dns_rcode_noerror;
4396                 else
4397                         client->message->rcode = dns_rcode_nxdomain;
4398                 goto cleanup;
4399
4400         case DNS_R_NCACHENXDOMAIN:
4401         case DNS_R_NCACHENXRRSET:
4402                 INSIST(!is_zone);
4403                 authoritative = ISC_FALSE;
4404                 /*
4405                  * Set message rcode, if required.
4406                  */
4407                 if (result == DNS_R_NCACHENXDOMAIN)
4408                         client->message->rcode = dns_rcode_nxdomain;
4409                 /*
4410                  * Look for RFC 1918 leakage from Internet.
4411                  */
4412                 if (result == DNS_R_NCACHENXDOMAIN &&
4413                     qtype == dns_rdatatype_ptr &&
4414                     client->message->rdclass == dns_rdataclass_in &&
4415                     dns_name_countlabels(fname) == 7)
4416                         warn_rfc1918(client, fname, rdataset);
4417                 /*
4418                  * We don't call query_addrrset() because we don't need any
4419                  * of its extra features (and things would probably break!).
4420                  */
4421                 query_keepname(client, fname, dbuf);
4422                 dns_message_addname(client->message, fname,
4423                                     DNS_SECTION_AUTHORITY);
4424                 ISC_LIST_APPEND(fname->list, rdataset, link);
4425                 fname = NULL;
4426                 rdataset = NULL;
4427                 goto cleanup;
4428
4429         case DNS_R_CNAME:
4430                 /*
4431                  * Keep a copy of the rdataset.  We have to do this because
4432                  * query_addrrset may clear 'rdataset' (to prevent the
4433                  * cleanup code from cleaning it up).
4434                  */
4435                 trdataset = rdataset;
4436                 /*
4437                  * Add the CNAME to the answer section.
4438                  */
4439                 if (sigrdataset != NULL)
4440                         sigrdatasetp = &sigrdataset;
4441                 else
4442                         sigrdatasetp = NULL;
4443                 if (WANTDNSSEC(client) &&
4444                     (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4445                 {
4446                         dns_fixedname_init(&wildcardname);
4447                         dns_name_copy(fname, dns_fixedname_name(&wildcardname),
4448                                       NULL);
4449                         need_wildcardproof = ISC_TRUE;
4450                 }
4451                 if (NOQNAME(rdataset) && WANTDNSSEC(client))
4452                         noqname = rdataset;
4453                 else
4454                         noqname = NULL;
4455                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4456                                DNS_SECTION_ANSWER);
4457                 if (noqname != NULL)
4458                         query_addnoqnameproof(client, noqname);
4459                 /*
4460                  * We set the PARTIALANSWER attribute so that if anything goes
4461                  * wrong later on, we'll return what we've got so far.
4462                  */
4463                 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
4464                 /*
4465                  * Reset qname to be the target name of the CNAME and restart
4466                  * the query.
4467                  */
4468                 tname = NULL;
4469                 result = dns_message_gettempname(client->message, &tname);
4470                 if (result != ISC_R_SUCCESS)
4471                         goto cleanup;
4472                 result = dns_rdataset_first(trdataset);
4473                 if (result != ISC_R_SUCCESS) {
4474                         dns_message_puttempname(client->message, &tname);
4475                         goto cleanup;
4476                 }
4477                 dns_rdataset_current(trdataset, &rdata);
4478                 result = dns_rdata_tostruct(&rdata, &cname, NULL);
4479                 dns_rdata_reset(&rdata);
4480                 if (result != ISC_R_SUCCESS) {
4481                         dns_message_puttempname(client->message, &tname);
4482                         goto cleanup;
4483                 }
4484                 dns_name_init(tname, NULL);
4485                 result = dns_name_dup(&cname.cname, client->mctx, tname);
4486                 if (result != ISC_R_SUCCESS) {
4487                         dns_message_puttempname(client->message, &tname);
4488                         dns_rdata_freestruct(&cname);
4489                         goto cleanup;
4490                 }
4491                 dns_rdata_freestruct(&cname);
4492                 ns_client_qnamereplace(client, tname);
4493                 want_restart = ISC_TRUE;
4494                 if (!WANTRECURSION(client))
4495                         options |= DNS_GETDB_NOLOG;
4496                 goto addauth;
4497         case DNS_R_DNAME:
4498                 /*
4499                  * Compare the current qname to the found name.  We need
4500                  * to know how many labels and bits are in common because
4501                  * we're going to have to split qname later on.
4502                  */
4503                 namereln = dns_name_fullcompare(client->query.qname, fname,
4504                                                 &order, &nlabels);
4505                 INSIST(namereln == dns_namereln_subdomain);
4506                 /*
4507                  * Keep a copy of the rdataset.  We have to do this because
4508                  * query_addrrset may clear 'rdataset' (to prevent the
4509                  * cleanup code from cleaning it up).
4510                  */
4511                 trdataset = rdataset;
4512                 /*
4513                  * Add the DNAME to the answer section.
4514                  */
4515                 if (sigrdataset != NULL)
4516                         sigrdatasetp = &sigrdataset;
4517                 else
4518                         sigrdatasetp = NULL;
4519                 if (WANTDNSSEC(client) &&
4520                     (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4521                 {
4522                         dns_fixedname_init(&wildcardname);
4523                         dns_name_copy(fname, dns_fixedname_name(&wildcardname),
4524                                       NULL);
4525                         need_wildcardproof = ISC_TRUE;
4526                 }
4527                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4528                                DNS_SECTION_ANSWER);
4529                 /*
4530                  * We set the PARTIALANSWER attribute so that if anything goes
4531                  * wrong later on, we'll return what we've got so far.
4532                  */
4533                 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
4534                 /*
4535                  * Get the target name of the DNAME.
4536                  */
4537                 tname = NULL;
4538                 result = dns_message_gettempname(client->message, &tname);
4539                 if (result != ISC_R_SUCCESS)
4540                         goto cleanup;
4541                 result = dns_rdataset_first(trdataset);
4542                 if (result != ISC_R_SUCCESS) {
4543                         dns_message_puttempname(client->message, &tname);
4544                         goto cleanup;
4545                 }
4546                 dns_rdataset_current(trdataset, &rdata);
4547                 result = dns_rdata_tostruct(&rdata, &dname, NULL);
4548                 dns_rdata_reset(&rdata);
4549                 if (result != ISC_R_SUCCESS) {
4550                         dns_message_puttempname(client->message, &tname);
4551                         goto cleanup;
4552                 }
4553                 dns_name_init(tname, NULL);
4554                 dns_name_clone(&dname.dname, tname);
4555                 dns_rdata_freestruct(&dname);
4556                 /*
4557                  * Construct the new qname.
4558                  */
4559                 dns_fixedname_init(&fixed);
4560                 prefix = dns_fixedname_name(&fixed);
4561                 dns_name_split(client->query.qname, nlabels, prefix, NULL);
4562                 INSIST(fname == NULL);
4563                 dbuf = query_getnamebuf(client);
4564                 if (dbuf == NULL) {
4565                         dns_message_puttempname(client->message, &tname);
4566                         goto cleanup;
4567                 }
4568                 fname = query_newname(client, dbuf, &b);
4569                 if (fname == NULL) {
4570                         dns_message_puttempname(client->message, &tname);
4571                         goto cleanup;
4572                 }
4573                 result = dns_name_concatenate(prefix, tname, fname, NULL);
4574                 if (result != ISC_R_SUCCESS) {
4575                         dns_message_puttempname(client->message, &tname);
4576                         if (result == ISC_R_NOSPACE) {
4577                                 /*
4578                                  * RFC2672, section 4.1, subsection 3c says
4579                                  * we should return YXDOMAIN if the constructed
4580                                  * name would be too long.
4581                                  */
4582                                 client->message->rcode = dns_rcode_yxdomain;
4583                         }
4584                         goto cleanup;
4585                 }
4586                 query_keepname(client, fname, dbuf);
4587                 /*
4588                  * Synthesize a CNAME for this DNAME.
4589                  *
4590                  * We want to synthesize a CNAME since if we don't
4591                  * then older software that doesn't understand DNAME
4592                  * will not chain like it should.
4593                  *
4594                  * We do not try to synthesize a signature because we hope
4595                  * that security aware servers will understand DNAME.  Also,
4596                  * even if we had an online key, making a signature
4597                  * on-the-fly is costly, and not really legitimate anyway
4598                  * since the synthesized CNAME is NOT in the zone.
4599                  */
4600                 dns_name_init(tname, NULL);
4601                 (void)query_addcnamelike(client, client->query.qname, fname,
4602                                          trdataset->trust, &tname,
4603                                          dns_rdatatype_cname);
4604                 if (tname != NULL)
4605                         dns_message_puttempname(client->message, &tname);
4606                 /*
4607                  * Switch to the new qname and restart.
4608                  */
4609                 ns_client_qnamereplace(client, fname);
4610                 fname = NULL;
4611                 want_restart = ISC_TRUE;
4612                 if (!WANTRECURSION(client))
4613                         options |= DNS_GETDB_NOLOG;
4614                 goto addauth;
4615         default:
4616                 /*
4617                  * Something has gone wrong.
4618                  */
4619                 QUERY_ERROR(DNS_R_SERVFAIL);
4620                 goto cleanup;
4621         }
4622
4623         if (WANTDNSSEC(client) &&
4624             (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4625         {
4626                 dns_fixedname_init(&wildcardname);
4627                 dns_name_copy(fname, dns_fixedname_name(&wildcardname), NULL);
4628                 need_wildcardproof = ISC_TRUE;
4629         }
4630
4631         if (type == dns_rdatatype_any) {
4632                 /*
4633                  * XXXRTH  Need to handle zonecuts with special case
4634                  * code.
4635                  */
4636                 n = 0;
4637                 rdsiter = NULL;
4638                 result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
4639                 if (result != ISC_R_SUCCESS) {
4640                         QUERY_ERROR(DNS_R_SERVFAIL);
4641                         goto cleanup;
4642                 }
4643                 /*
4644                  * Calling query_addrrset() with a non-NULL dbuf is going
4645                  * to either keep or release the name.  We don't want it to
4646                  * release fname, since we may have to call query_addrrset()
4647                  * more than once.  That means we have to call query_keepname()
4648                  * now, and pass a NULL dbuf to query_addrrset().
4649                  *
4650                  * If we do a query_addrrset() below, we must set fname to
4651                  * NULL before leaving this block, otherwise we might try to
4652                  * cleanup fname even though we're using it!
4653                  */
4654                 query_keepname(client, fname, dbuf);
4655                 tname = fname;
4656                 result = dns_rdatasetiter_first(rdsiter);
4657                 while (result == ISC_R_SUCCESS) {
4658                         dns_rdatasetiter_current(rdsiter, rdataset);
4659                         if (is_zone && qtype == dns_rdatatype_any &&
4660                             !dns_db_issecure(db) &&
4661                             dns_rdatatype_isdnssec(rdataset->type)) {
4662                                 /*
4663                                  * The zone is transitioning from insecure
4664                                  * to secure. Hide the dnssec records from
4665                                  * ANY queries.
4666                                  */
4667                                 dns_rdataset_disassociate(rdataset);
4668                         } else if ((qtype == dns_rdatatype_any ||
4669                              rdataset->type == qtype) && rdataset->type != 0) {
4670                                 if (NOQNAME(rdataset) && WANTDNSSEC(client))
4671                                         noqname = rdataset;
4672                                 else
4673                                         noqname = NULL;
4674                                 query_addrrset(client,
4675                                                fname != NULL ? &fname : &tname,
4676                                                &rdataset, NULL,
4677                                                NULL, DNS_SECTION_ANSWER);
4678                                 if (noqname != NULL)
4679                                         query_addnoqnameproof(client, noqname);
4680                                 n++;
4681                                 INSIST(tname != NULL);
4682                                 /*
4683                                  * rdataset is non-NULL only in certain
4684                                  * pathological cases involving DNAMEs.
4685                                  */
4686                                 if (rdataset != NULL)
4687                                         query_putrdataset(client, &rdataset);
4688                                 rdataset = query_newrdataset(client);
4689                                 if (rdataset == NULL)
4690                                         break;
4691                         } else {
4692                                 /*
4693                                  * We're not interested in this rdataset.
4694                                  */
4695                                 dns_rdataset_disassociate(rdataset);
4696                         }
4697                         result = dns_rdatasetiter_next(rdsiter);
4698                 }
4699
4700                 if (fname != NULL)
4701                         dns_message_puttempname(client->message, &fname);
4702
4703                 if (n == 0 && is_zone) {
4704                         /*
4705                          * We didn't match any rdatasets.
4706                          */
4707                         if (qtype == dns_rdatatype_rrsig &&
4708                             result == ISC_R_NOMORE) {
4709                                 /*
4710                                  * XXXRTH  If this is a secure zone and we
4711                                  * didn't find any SIGs, we should generate
4712                                  * an error unless we were searching for
4713                                  * glue.  Ugh.
4714                                  */
4715                                 if (!is_zone) {
4716                                         authoritative = ISC_FALSE;
4717                                         dns_rdatasetiter_destroy(&rdsiter);
4718                                         if (RECURSIONOK(client)) {
4719                                                 result = query_recurse(client,
4720                                                                        qtype,
4721                                                                        NULL,
4722                                                                        NULL,
4723                                                                        resuming);
4724                                                 if (result == ISC_R_SUCCESS)
4725                                                     client->query.attributes |=
4726                                                         NS_QUERYATTR_RECURSING;
4727                                                 else
4728                                                     QUERY_ERROR(DNS_R_SERVFAIL);                                        }
4729                                         goto addauth;
4730                                 }
4731                                 /*
4732                                  * We were searching for SIG records in
4733                                  * a nonsecure zone.  Send a "no error,
4734                                  * no data" response.
4735                                  */
4736                                 /*
4737                                  * Add SOA.
4738                                  */
4739                                 result = query_addsoa(client, db, version,
4740                                                       ISC_FALSE);
4741                                 if (result == ISC_R_SUCCESS)
4742                                         result = ISC_R_NOMORE;
4743                         } else {
4744                                 /*
4745                                  * Something went wrong.
4746                                  */
4747                                 result = DNS_R_SERVFAIL;
4748                         }
4749                 }
4750                 dns_rdatasetiter_destroy(&rdsiter);
4751                 if (result != ISC_R_NOMORE) {
4752                         QUERY_ERROR(DNS_R_SERVFAIL);
4753                         goto cleanup;
4754                 }
4755         } else {
4756                 /*
4757                  * This is the "normal" case -- an ordinary question to which
4758                  * we know the answer.
4759                  */
4760                 if (sigrdataset != NULL)
4761                         sigrdatasetp = &sigrdataset;
4762                 else
4763                         sigrdatasetp = NULL;
4764                 if (NOQNAME(rdataset) && WANTDNSSEC(client))
4765                         noqname = rdataset;
4766                 else
4767                         noqname = NULL;
4768                 /*
4769                  * BIND 8 priming queries need the additional section.
4770                  */
4771                 if (is_zone && qtype == dns_rdatatype_ns &&
4772                     dns_name_equal(client->query.qname, dns_rootname))
4773                         client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
4774
4775                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4776                                DNS_SECTION_ANSWER);
4777                 if (noqname != NULL)
4778                         query_addnoqnameproof(client, noqname);
4779                 /*
4780                  * We shouldn't ever fail to add 'rdataset'
4781                  * because it's already in the answer.
4782                  */
4783                 INSIST(rdataset == NULL);
4784         }
4785
4786  addauth:
4787         CTRACE("query_find: addauth");
4788         /*
4789          * Add NS records to the authority section (if we haven't already
4790          * added them to the answer section).
4791          */
4792         if (!want_restart && !NOAUTHORITY(client)) {
4793                 if (is_zone) {
4794                         if (!((qtype == dns_rdatatype_ns ||
4795                                qtype == dns_rdatatype_any) &&
4796                               dns_name_equal(client->query.qname,
4797                                              dns_db_origin(db))))
4798                                 (void)query_addns(client, db, version);
4799                 } else if (qtype != dns_rdatatype_ns) {
4800                         if (fname != NULL)
4801                                 query_releasename(client, &fname);
4802                         query_addbestns(client);
4803                 }
4804         }
4805
4806         /*
4807          * Add NSEC records to the authority section if they're needed for
4808          * DNSSEC wildcard proofs.
4809          */
4810         if (need_wildcardproof && dns_db_issecure(db))
4811                 query_addwildcardproof(client, db, version,
4812                                        dns_fixedname_name(&wildcardname),
4813                                        ISC_TRUE);
4814  cleanup:
4815         CTRACE("query_find: cleanup");
4816         /*
4817          * General cleanup.
4818          */
4819         if (rdataset != NULL)
4820                 query_putrdataset(client, &rdataset);
4821         if (sigrdataset != NULL)
4822                 query_putrdataset(client, &sigrdataset);
4823         if (fname != NULL)
4824                 query_releasename(client, &fname);
4825         if (node != NULL)
4826                 dns_db_detachnode(db, &node);
4827         if (db != NULL)
4828                 dns_db_detach(&db);
4829         if (zone != NULL)
4830                 dns_zone_detach(&zone);
4831         if (zdb != NULL) {
4832                 query_putrdataset(client, &zrdataset);
4833                 if (zsigrdataset != NULL)
4834                         query_putrdataset(client, &zsigrdataset);
4835                 if (zfname != NULL)
4836                         query_releasename(client, &zfname);
4837                 dns_db_detach(&zdb);
4838         }
4839         if (event != NULL)
4840                 isc_event_free(ISC_EVENT_PTR(&event));
4841
4842         /*
4843          * AA bit.
4844          */
4845         if (client->query.restarts == 0 && !authoritative) {
4846                 /*
4847                  * We're not authoritative, so we must ensure the AA bit
4848                  * isn't set.
4849                  */
4850                 client->message->flags &= ~DNS_MESSAGEFLAG_AA;
4851         }
4852
4853         /*
4854          * Restart the query?
4855          */
4856         if (want_restart && client->query.restarts < MAX_RESTARTS) {
4857                 client->query.restarts++;
4858                 goto restart;
4859         }
4860
4861         if (eresult != ISC_R_SUCCESS &&
4862             (!PARTIALANSWER(client) || WANTRECURSION(client))) {
4863                 if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) {
4864                         /*
4865                          * This was a duplicate query that we are
4866                          * recursing on.  Don't send a response now.
4867                          * The original query will still cause a response.
4868                          */
4869                         query_next(client, eresult);
4870                 } else {
4871                         /*
4872                          * If we don't have any answer to give the client,
4873                          * or if the client requested recursion and thus wanted
4874                          * the complete answer, send an error response.
4875                          */
4876                         INSIST(line >= 0);
4877                         query_error(client, eresult, line);
4878                 }
4879                 ns_client_detach(&client);
4880         } else if (!RECURSING(client)) {
4881                 /*
4882                  * We are done.  Set up sortlist data for the message
4883                  * rendering code, make a final tweak to the AA bit if the
4884                  * auth-nxdomain config option says so, then render and
4885                  * send the response.
4886                  */
4887                 setup_query_sortlist(client);
4888
4889                 /*
4890                  * If this is a referral and the answer to the question
4891                  * is in the glue sort it to the start of the additional
4892                  * section.
4893                  */
4894                 if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) &&
4895                     client->message->rcode == dns_rcode_noerror &&
4896                     (qtype == dns_rdatatype_a || qtype == dns_rdatatype_aaaa))
4897                         answer_in_glue(client, qtype);
4898
4899                 if (client->message->rcode == dns_rcode_nxdomain &&
4900                     client->view->auth_nxdomain == ISC_TRUE)
4901                         client->message->flags |= DNS_MESSAGEFLAG_AA;
4902
4903                 /*
4904                  * If the response is somehow unexpected for the client and this
4905                  * is a result of recursion, return an error to the caller
4906                  * to indicate it may need to be logged.
4907                  */
4908                 if (resuming &&
4909                     (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) ||
4910                      client->message->rcode != dns_rcode_noerror))
4911                         eresult = ISC_R_FAILURE;
4912
4913                 query_send(client);
4914                 ns_client_detach(&client);
4915         }
4916         CTRACE("query_find: done");
4917
4918         return (eresult);
4919 }
4920
4921 static inline void
4922 log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) {
4923         char namebuf[DNS_NAME_FORMATSIZE];
4924         char typename[DNS_RDATATYPE_FORMATSIZE];
4925         char classname[DNS_RDATACLASS_FORMATSIZE];
4926         dns_rdataset_t *rdataset;
4927         int level = ISC_LOG_INFO;
4928
4929         if (! isc_log_wouldlog(ns_g_lctx, level))
4930                 return;
4931
4932         rdataset = ISC_LIST_HEAD(client->query.qname->list);
4933         INSIST(rdataset != NULL);
4934         dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
4935         dns_rdataclass_format(rdataset->rdclass, classname, sizeof(classname));
4936         dns_rdatatype_format(rdataset->type, typename, sizeof(typename));
4937
4938         ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
4939                       level, "query: %s %s %s %s%s%s%s%s", namebuf, classname,
4940                       typename, WANTRECURSION(client) ? "+" : "-",
4941                       (client->signer != NULL) ? "S": "",
4942                       (client->opt != NULL) ? "E" : "",
4943                       ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) ? "D" : "",
4944                       ((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : "");
4945 }
4946
4947 static inline void
4948 log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) {
4949         char namebuf[DNS_NAME_FORMATSIZE];
4950         char typename[DNS_RDATATYPE_FORMATSIZE];
4951         char classname[DNS_RDATACLASS_FORMATSIZE];
4952         const char *namep, *typep, *classp, *sep1, *sep2;
4953         dns_rdataset_t *rdataset;
4954
4955         if (!isc_log_wouldlog(ns_g_lctx, level))
4956                 return;
4957
4958         namep = typep = classp = sep1 = sep2 = "";
4959
4960         /*
4961          * Query errors can happen for various reasons.  In some cases we cannot
4962          * even assume the query contains a valid question section, so we should
4963          * expect exceptional cases.
4964          */
4965         if (client->query.origqname != NULL) {
4966                 dns_name_format(client->query.origqname, namebuf,
4967                                 sizeof(namebuf));
4968                 namep = namebuf;
4969                 sep1 = " for ";
4970
4971                 rdataset = ISC_LIST_HEAD(client->query.origqname->list);
4972                 if (rdataset != NULL) {
4973                         dns_rdataclass_format(rdataset->rdclass, classname,
4974                                               sizeof(classname));
4975                         classp = classname;
4976                         dns_rdatatype_format(rdataset->type, typename,
4977                                              sizeof(typename));
4978                         typep = typename;
4979                         sep2 = "/";
4980                 }
4981         }
4982
4983         ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, NS_LOGMODULE_QUERY,
4984                       level, "query failed (%s)%s%s%s%s%s%s at %s:%d",
4985                       isc_result_totext(result), sep1, namep, sep2,
4986                       classp, sep2, typep, __FILE__, line);
4987 }
4988
4989 void
4990 ns_query_start(ns_client_t *client) {
4991         isc_result_t result;
4992         dns_message_t *message = client->message;
4993         dns_rdataset_t *rdataset;
4994         ns_client_t *qclient;
4995         dns_rdatatype_t qtype;
4996         unsigned int saved_extflags = client->extflags;
4997         unsigned int saved_flags = client->message->flags;
4998         isc_boolean_t want_ad;
4999
5000         CTRACE("ns_query_start");
5001
5002         /*
5003          * Test only.
5004          */
5005         if (ns_g_clienttest && (client->attributes & NS_CLIENTATTR_TCP) == 0)
5006                 RUNTIME_CHECK(ns_client_replace(client) == ISC_R_SUCCESS);
5007
5008         /*
5009          * Ensure that appropriate cleanups occur.
5010          */
5011         client->next = query_next_callback;
5012
5013         /*
5014          * Behave as if we don't support DNSSEC if not enabled.
5015          */
5016         if (!client->view->enablednssec) {
5017                 message->flags &= ~DNS_MESSAGEFLAG_CD;
5018                 client->extflags &= ~DNS_MESSAGEEXTFLAG_DO;
5019                 if (client->opt != NULL)
5020                         client->opt->ttl &= ~DNS_MESSAGEEXTFLAG_DO;
5021         }
5022
5023         if ((message->flags & DNS_MESSAGEFLAG_RD) != 0)
5024                 client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
5025
5026         if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0)
5027                 client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
5028
5029         if (client->view->minimalresponses)
5030                 client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
5031                                              NS_QUERYATTR_NOADDITIONAL);
5032
5033         if ((client->view->cachedb == NULL)
5034             || (!client->view->additionalfromcache)) {
5035                 /*
5036                  * We don't have a cache.  Turn off cache support and
5037                  * recursion.
5038                  */
5039                 client->query.attributes &=
5040                         ~(NS_QUERYATTR_RECURSIONOK|NS_QUERYATTR_CACHEOK);
5041         } else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
5042                    (message->flags & DNS_MESSAGEFLAG_RD) == 0) {
5043                 /*
5044                  * If the client isn't allowed to recurse (due to
5045                  * "recursion no", the allow-recursion ACL, or the
5046                  * lack of a resolver in this view), or if it
5047                  * doesn't want recursion, turn recursion off.
5048                  */
5049                 client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
5050         }
5051
5052         /*
5053          * Get the question name.
5054          */
5055         result = dns_message_firstname(message, DNS_SECTION_QUESTION);
5056         if (result != ISC_R_SUCCESS) {
5057                 query_error(client, result, __LINE__);
5058                 return;
5059         }
5060         dns_message_currentname(message, DNS_SECTION_QUESTION,
5061                                 &client->query.qname);
5062         client->query.origqname = client->query.qname;
5063         result = dns_message_nextname(message, DNS_SECTION_QUESTION);
5064         if (result != ISC_R_NOMORE) {
5065                 if (result == ISC_R_SUCCESS) {
5066                         /*
5067                          * There's more than one QNAME in the question
5068                          * section.
5069                          */
5070                         query_error(client, DNS_R_FORMERR, __LINE__);
5071                 } else
5072                         query_error(client, result, __LINE__);
5073                 return;
5074         }
5075
5076         if (ns_g_server->log_queries)
5077                 log_query(client, saved_flags, saved_extflags);
5078
5079         /*
5080          * Check for multiple question queries, since edns1 is dead.
5081          */
5082         if (message->counts[DNS_SECTION_QUESTION] > 1) {
5083                 query_error(client, DNS_R_FORMERR, __LINE__);
5084                 return;
5085         }
5086
5087         /*
5088          * Check for meta-queries like IXFR and AXFR.
5089          */
5090         rdataset = ISC_LIST_HEAD(client->query.qname->list);
5091         INSIST(rdataset != NULL);
5092         qtype = rdataset->type;
5093         dns_rdatatypestats_increment(ns_g_server->rcvquerystats, qtype);
5094         if (dns_rdatatype_ismeta(qtype)) {
5095                 switch (qtype) {
5096                 case dns_rdatatype_any:
5097                         break; /* Let query_find handle it. */
5098                 case dns_rdatatype_ixfr:
5099                 case dns_rdatatype_axfr:
5100                         ns_xfr_start(client, rdataset->type);
5101                         return;
5102                 case dns_rdatatype_maila:
5103                 case dns_rdatatype_mailb:
5104                         query_error(client, DNS_R_NOTIMP, __LINE__);
5105                         return;
5106                 case dns_rdatatype_tkey:
5107                         result = dns_tkey_processquery(client->message,
5108                                                 ns_g_server->tkeyctx,
5109                                                 client->view->dynamickeys);
5110                         if (result == ISC_R_SUCCESS)
5111                                 query_send(client);
5112                         else
5113                                 query_error(client, result, __LINE__);
5114                         return;
5115                 default: /* TSIG, etc. */
5116                         query_error(client, DNS_R_FORMERR, __LINE__);
5117                         return;
5118                 }
5119         }
5120
5121         /*
5122          * Turn on minimal response for DNSKEY queries.
5123          */
5124         if (qtype == dns_rdatatype_dnskey)
5125                 client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
5126                                              NS_QUERYATTR_NOADDITIONAL);
5127
5128         /*
5129          * If the client has requested that DNSSEC checking be disabled,
5130          * allow lookups to return pending data and instruct the resolver
5131          * to return data before validation has completed.
5132          *
5133          * We don't need to set DNS_DBFIND_PENDINGOK when validation is
5134          * disabled as there will be no pending data.
5135          */
5136         if (message->flags & DNS_MESSAGEFLAG_CD ||
5137             qtype == dns_rdatatype_rrsig)
5138         {
5139                 client->query.dboptions |= DNS_DBFIND_PENDINGOK;
5140                 client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
5141         } else if (!client->view->enablevalidation)
5142                 client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
5143
5144         /*
5145          * Allow glue NS records to be added to the authority section
5146          * if the answer is secure.
5147          */
5148         if (message->flags & DNS_MESSAGEFLAG_CD)
5149                 client->query.attributes &= ~NS_QUERYATTR_SECURE;
5150
5151         /*
5152          * Set 'want_ad' if the client has set AD in the query.
5153          * This allows AD to be returned on queries without DO set.
5154          */
5155         if ((message->flags & DNS_MESSAGEFLAG_AD) != 0)
5156                 want_ad = ISC_TRUE;
5157         else
5158                 want_ad = ISC_FALSE;
5159
5160         /*
5161          * This is an ordinary query.
5162          */
5163         result = dns_message_reply(message, ISC_TRUE);
5164         if (result != ISC_R_SUCCESS) {
5165                 query_next(client, result);
5166                 return;
5167         }
5168
5169         /*
5170          * Assume authoritative response until it is known to be
5171          * otherwise.
5172          */
5173         message->flags |= DNS_MESSAGEFLAG_AA;
5174
5175         /*
5176          * Set AD.  We must clear it if we add non-validated data to a
5177          * response.
5178          */
5179         if (WANTDNSSEC(client) || want_ad)
5180                 message->flags |= DNS_MESSAGEFLAG_AD;
5181
5182         qclient = NULL;
5183         ns_client_attach(client, &qclient);
5184         (void)query_find(qclient, NULL, qtype);
5185 }