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