]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/bin/named/query.c
Fix a problem whereby a corrupt DNS record can cause named to crash. [11:06]
[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                         if (sigrdataset != NULL &&
1286                             dns_rdataset_isassociated(sigrdataset))
1287                                 dns_rdataset_disassociate(sigrdataset);
1288                 }
1289                 if (result == ISC_R_SUCCESS) {
1290                         mname = NULL;
1291                         if (!query_isduplicate(client, fname,
1292                                                dns_rdatatype_a, &mname)) {
1293                                 if (mname != NULL) {
1294                                         query_releasename(client, &fname);
1295                                         fname = mname;
1296                                 } else
1297                                         need_addname = ISC_TRUE;
1298                                 ISC_LIST_APPEND(fname->list, rdataset, link);
1299                                 added_something = ISC_TRUE;
1300                                 if (sigrdataset != NULL &&
1301                                     dns_rdataset_isassociated(sigrdataset))
1302                                 {
1303                                         ISC_LIST_APPEND(fname->list,
1304                                                         sigrdataset, link);
1305                                         sigrdataset =
1306                                                 query_newrdataset(client);
1307                                 }
1308                                 rdataset = query_newrdataset(client);
1309                                 if (rdataset == NULL)
1310                                         goto addname;
1311                                 if (WANTDNSSEC(client) && sigrdataset == NULL)
1312                                         goto addname;
1313                         } else {
1314                                 dns_rdataset_disassociate(rdataset);
1315                                 if (sigrdataset != NULL &&
1316                                     dns_rdataset_isassociated(sigrdataset))
1317                                         dns_rdataset_disassociate(sigrdataset);
1318                         }
1319                 }
1320                 result = dns_db_findrdataset(db, node, version,
1321                                              dns_rdatatype_aaaa, 0,
1322                                              client->now, rdataset,
1323                                              sigrdataset);
1324                 if (result == DNS_R_NCACHENXDOMAIN)
1325                         goto addname;
1326                 if (result == DNS_R_NCACHENXRRSET) {
1327                         dns_rdataset_disassociate(rdataset);
1328                         if (sigrdataset != NULL &&
1329                             dns_rdataset_isassociated(sigrdataset))
1330                                 dns_rdataset_disassociate(sigrdataset);
1331                 }
1332                 if (result == ISC_R_SUCCESS) {
1333                         mname = NULL;
1334                         if (!query_isduplicate(client, fname,
1335                                                dns_rdatatype_aaaa, &mname)) {
1336                                 if (mname != NULL) {
1337                                         query_releasename(client, &fname);
1338                                         fname = mname;
1339                                 } else
1340                                         need_addname = ISC_TRUE;
1341                                 ISC_LIST_APPEND(fname->list, rdataset, link);
1342                                 added_something = ISC_TRUE;
1343                                 if (sigrdataset != NULL &&
1344                                     dns_rdataset_isassociated(sigrdataset))
1345                                 {
1346                                         ISC_LIST_APPEND(fname->list,
1347                                                         sigrdataset, link);
1348                                         sigrdataset = NULL;
1349                                 }
1350                                 rdataset = NULL;
1351                         }
1352                 }
1353         }
1354
1355  addname:
1356         CTRACE("query_addadditional: addname");
1357         /*
1358          * If we haven't added anything, then we're done.
1359          */
1360         if (!added_something)
1361                 goto cleanup;
1362
1363         /*
1364          * We may have added our rdatasets to an existing name, if so, then
1365          * need_addname will be ISC_FALSE.  Whether we used an existing name
1366          * or a new one, we must set fname to NULL to prevent cleanup.
1367          */
1368         if (need_addname)
1369                 dns_message_addname(client->message, fname,
1370                                     DNS_SECTION_ADDITIONAL);
1371         fname = NULL;
1372
1373         /*
1374          * In a few cases, we want to add additional data for additional
1375          * data.  It's simpler to just deal with special cases here than
1376          * to try to create a general purpose mechanism and allow the
1377          * rdata implementations to do it themselves.
1378          *
1379          * This involves recursion, but the depth is limited.  The
1380          * most complex case is adding a SRV rdataset, which involves
1381          * recursing to add address records, which in turn can cause
1382          * recursion to add KEYs.
1383          */
1384         if (type == dns_rdatatype_srv && trdataset != NULL) {
1385                 /*
1386                  * If we're adding SRV records to the additional data
1387                  * section, it's helpful if we add the SRV additional data
1388                  * as well.
1389                  */
1390                 eresult = dns_rdataset_additionaldata(trdataset,
1391                                                       query_addadditional,
1392                                                       client);
1393         }
1394
1395  cleanup:
1396         CTRACE("query_addadditional: cleanup");
1397         query_putrdataset(client, &rdataset);
1398         if (sigrdataset != NULL)
1399                 query_putrdataset(client, &sigrdataset);
1400         if (fname != NULL)
1401                 query_releasename(client, &fname);
1402         if (node != NULL)
1403                 dns_db_detachnode(db, &node);
1404         if (db != NULL)
1405                 dns_db_detach(&db);
1406         if (zone != NULL)
1407                 dns_zone_detach(&zone);
1408
1409         CTRACE("query_addadditional: done");
1410         return (eresult);
1411 }
1412
1413 static inline void
1414 query_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base,
1415                    dns_rdatasetadditional_t additionaltype,
1416                    dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp,
1417                    dns_dbversion_t **versionp, dns_dbnode_t **nodep,
1418                    dns_name_t *fname)
1419 {
1420         dns_rdataset_t *rdataset;
1421
1422         while  ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
1423                 ISC_LIST_UNLINK(fname->list, rdataset, link);
1424                 query_putrdataset(client, &rdataset);
1425         }
1426         if (*versionp != NULL)
1427                 dns_db_closeversion(*dbp, versionp, ISC_FALSE);
1428         if (*nodep != NULL)
1429                 dns_db_detachnode(*dbp, nodep);
1430         if (*dbp != NULL)
1431                 dns_db_detach(dbp);
1432         if (*zonep != NULL)
1433                 dns_zone_detach(zonep);
1434         (void)dns_rdataset_putadditional(client->view->acache, rdataset_base,
1435                                          additionaltype, type);
1436 }
1437
1438 static inline isc_result_t
1439 query_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0,
1440                    dns_dbversion_t *version)
1441 {
1442         isc_result_t result = ISC_R_SUCCESS;
1443         dns_dbversion_t *version_current = NULL;
1444         dns_db_t *db_current = db0;
1445
1446         if (db_current == NULL) {
1447                 result = dns_zone_getdb(zone, &db_current);
1448                 if (result != ISC_R_SUCCESS)
1449                         return (result);
1450         }
1451         dns_db_currentversion(db_current, &version_current);
1452         if (db_current != db || version_current != version) {
1453                 result = ISC_R_FAILURE;
1454                 goto cleanup;
1455         }
1456
1457  cleanup:
1458         dns_db_closeversion(db_current, &version_current, ISC_FALSE);
1459         if (db0 == NULL && db_current != NULL)
1460                 dns_db_detach(&db_current);
1461
1462         return (result);
1463 }
1464
1465 static isc_result_t
1466 query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
1467         client_additionalctx_t *additionalctx = arg;
1468         dns_rdataset_t *rdataset_base;
1469         ns_client_t *client;
1470         isc_result_t result, eresult;
1471         dns_dbnode_t *node, *cnode;
1472         dns_db_t *db, *cdb;
1473         dns_name_t *fname, *mname0, cfname;
1474         dns_rdataset_t *rdataset, *sigrdataset;
1475         dns_rdataset_t *crdataset, *crdataset_next;
1476         isc_buffer_t *dbuf;
1477         isc_buffer_t b;
1478         dns_dbversion_t *version, *cversion;
1479         isc_boolean_t added_something, need_addname, needadditionalcache;
1480         isc_boolean_t need_sigrrset;
1481         dns_zone_t *zone;
1482         dns_rdatatype_t type;
1483         dns_rdatasetadditional_t additionaltype;
1484
1485         if (qtype != dns_rdatatype_a) {
1486                 /*
1487                  * This function is optimized for "address" types.  For other
1488                  * types, use a generic routine.
1489                  * XXX: ideally, this function should be generic enough.
1490                  */
1491                 return (query_addadditional(additionalctx->client,
1492                                             name, qtype));
1493         }
1494
1495         /*
1496          * Initialization.
1497          */
1498         rdataset_base = additionalctx->rdataset;
1499         client = additionalctx->client;
1500         REQUIRE(NS_CLIENT_VALID(client));
1501         eresult = ISC_R_SUCCESS;
1502         fname = NULL;
1503         rdataset = NULL;
1504         sigrdataset = NULL;
1505         db = NULL;
1506         cdb = NULL;
1507         version = NULL;
1508         cversion = NULL;
1509         node = NULL;
1510         cnode = NULL;
1511         added_something = ISC_FALSE;
1512         need_addname = ISC_FALSE;
1513         zone = NULL;
1514         needadditionalcache = ISC_FALSE;
1515         additionaltype = dns_rdatasetadditional_fromauth;
1516         dns_name_init(&cfname, NULL);
1517
1518         CTRACE("query_addadditional2");
1519
1520         /*
1521          * We treat type A additional section processing as if it
1522          * were "any address type" additional section processing.
1523          * To avoid multiple lookups, we do an 'any' database
1524          * lookup and iterate over the node.
1525          * XXXJT: this approach can cause a suboptimal result when the cache
1526          * DB only has partial address types and the glue DB has remaining
1527          * ones.
1528          */
1529         type = dns_rdatatype_any;
1530
1531         /*
1532          * Get some resources.
1533          */
1534         dbuf = query_getnamebuf(client);
1535         if (dbuf == NULL)
1536                 goto cleanup;
1537         fname = query_newname(client, dbuf, &b);
1538         if (fname == NULL)
1539                 goto cleanup;
1540         dns_name_setbuffer(&cfname, &b); /* share the buffer */
1541
1542         /* Check additional cache */
1543         result = dns_rdataset_getadditional(rdataset_base, additionaltype,
1544                                             type, client->view->acache, &zone,
1545                                             &cdb, &cversion, &cnode, &cfname,
1546                                             client->message, client->now);
1547         if (result != ISC_R_SUCCESS)
1548                 goto findauthdb;
1549         if (zone == NULL) {
1550                 CTRACE("query_addadditional2: auth zone not found");
1551                 goto try_cache;
1552         }
1553
1554         /* Is the cached DB up-to-date? */
1555         result = query_iscachevalid(zone, cdb, NULL, cversion);
1556         if (result != ISC_R_SUCCESS) {
1557                 CTRACE("query_addadditional2: old auth additional cache");
1558                 query_discardcache(client, rdataset_base, additionaltype,
1559                                    type, &zone, &cdb, &cversion, &cnode,
1560                                    &cfname);
1561                 goto findauthdb;
1562         }
1563
1564         if (cnode == NULL) {
1565                 /*
1566                  * We have a negative cache.  We don't have to check the zone
1567                  * ACL, since the result (not using this zone) would be same
1568                  * regardless of the result.
1569                  */
1570                 CTRACE("query_addadditional2: negative auth additional cache");
1571                 dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1572                 dns_db_detach(&cdb);
1573                 dns_zone_detach(&zone);
1574                 goto try_cache;
1575         }
1576
1577         result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG,
1578                                       zone, cdb, NULL);
1579         if (result != ISC_R_SUCCESS) {
1580                 query_discardcache(client, rdataset_base, additionaltype,
1581                                    type, &zone, &cdb, &cversion, &cnode,
1582                                    &cfname);
1583                 goto try_cache;
1584         }
1585
1586         /* We've got an active cache. */
1587         CTRACE("query_addadditional2: auth additional cache");
1588         dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1589         db = cdb;
1590         node = cnode;
1591         dns_name_clone(&cfname, fname);
1592         query_keepname(client, fname, dbuf);
1593         goto foundcache;
1594
1595         /*
1596          * Look for a zone database that might contain authoritative
1597          * additional data.
1598          */
1599  findauthdb:
1600         result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
1601                                  &zone, &db, &version);
1602         if (result != ISC_R_SUCCESS) {
1603                 /* Cache the negative result */
1604                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1605                                                  type, client->view->acache,
1606                                                  NULL, NULL, NULL, NULL,
1607                                                  NULL);
1608                 goto try_cache;
1609         }
1610
1611         CTRACE("query_addadditional2: db_find");
1612
1613         /*
1614          * Since we are looking for authoritative data, we do not set
1615          * the GLUEOK flag.  Glue will be looked for later, but not
1616          * necessarily in the same database.
1617          */
1618         node = NULL;
1619         result = dns_db_find(db, name, version, type, client->query.dboptions,
1620                              client->now, &node, fname, NULL, NULL);
1621         if (result == ISC_R_SUCCESS)
1622                 goto found;
1623
1624         /* Cache the negative result */
1625         (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1626                                          type, client->view->acache, zone, db,
1627                                          version, NULL, fname);
1628
1629         if (node != NULL)
1630                 dns_db_detachnode(db, &node);
1631         version = NULL;
1632         dns_db_detach(&db);
1633
1634         /*
1635          * No authoritative data was found.  The cache is our next best bet.
1636          */
1637
1638  try_cache:
1639         additionaltype = dns_rdatasetadditional_fromcache;
1640         result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
1641         if (result != ISC_R_SUCCESS)
1642                 /*
1643                  * Most likely the client isn't allowed to query the cache.
1644                  */
1645                 goto try_glue;
1646
1647         result = dns_db_find(db, name, version, type,
1648                              client->query.dboptions |
1649                              DNS_DBFIND_GLUEOK | DNS_DBFIND_ADDITIONALOK,
1650                              client->now, &node, fname, NULL, NULL);
1651         if (result == ISC_R_SUCCESS)
1652                 goto found;
1653
1654         if (node != NULL)
1655                 dns_db_detachnode(db, &node);
1656         dns_db_detach(&db);
1657
1658  try_glue:
1659         /*
1660          * No cached data was found.  Glue is our last chance.
1661          * RFC1035 sayeth:
1662          *
1663          *      NS records cause both the usual additional section
1664          *      processing to locate a type A record, and, when used
1665          *      in a referral, a special search of the zone in which
1666          *      they reside for glue information.
1667          *
1668          * This is the "special search".  Note that we must search
1669          * the zone where the NS record resides, not the zone it
1670          * points to, and that we only do the search in the delegation
1671          * case (identified by client->query.gluedb being set).
1672          */
1673         if (client->query.gluedb == NULL)
1674                 goto cleanup;
1675
1676         /*
1677          * Don't poison caches using the bailiwick protection model.
1678          */
1679         if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
1680                 goto cleanup;
1681
1682         /* Check additional cache */
1683         additionaltype = dns_rdatasetadditional_fromglue;
1684         result = dns_rdataset_getadditional(rdataset_base, additionaltype,
1685                                             type, client->view->acache, NULL,
1686                                             &cdb, &cversion, &cnode, &cfname,
1687                                             client->message, client->now);
1688         if (result != ISC_R_SUCCESS)
1689                 goto findglue;
1690
1691         result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion);
1692         if (result != ISC_R_SUCCESS) {
1693                 CTRACE("query_addadditional2: old glue additional cache");
1694                 query_discardcache(client, rdataset_base, additionaltype,
1695                                    type, &zone, &cdb, &cversion, &cnode,
1696                                    &cfname);
1697                 goto findglue;
1698         }
1699
1700         if (cnode == NULL) {
1701                 /* We have a negative cache. */
1702                 CTRACE("query_addadditional2: negative glue additional cache");
1703                 dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1704                 dns_db_detach(&cdb);
1705                 goto cleanup;
1706         }
1707
1708         /* Cache hit. */
1709         CTRACE("query_addadditional2: glue additional cache");
1710         dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1711         db = cdb;
1712         node = cnode;
1713         dns_name_clone(&cfname, fname);
1714         query_keepname(client, fname, dbuf);
1715         goto foundcache;
1716
1717  findglue:
1718         dns_db_attach(client->query.gluedb, &db);
1719         result = dns_db_find(db, name, version, type,
1720                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1721                              client->now, &node, fname, NULL, NULL);
1722         if (!(result == ISC_R_SUCCESS ||
1723               result == DNS_R_ZONECUT ||
1724               result == DNS_R_GLUE)) {
1725                 /* cache the negative result */
1726                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1727                                                  type, client->view->acache,
1728                                                  NULL, db, version, NULL,
1729                                                  fname);
1730                 goto cleanup;
1731         }
1732
1733  found:
1734         /*
1735          * We have found a DB node to iterate over from a DB.
1736          * We are going to look for address RRsets (i.e., A and AAAA) in the DB
1737          * node we've just found.  We'll then store the complete information
1738          * in the additional data cache.
1739          */
1740         dns_name_clone(fname, &cfname);
1741         query_keepname(client, fname, dbuf);
1742         needadditionalcache = ISC_TRUE;
1743
1744         rdataset = query_newrdataset(client);
1745         if (rdataset == NULL)
1746                 goto cleanup;
1747
1748         sigrdataset = query_newrdataset(client);
1749         if (sigrdataset == NULL)
1750                 goto cleanup;
1751
1752         /*
1753          * Find A RRset with sig RRset.  Even if we don't find a sig RRset
1754          * for a client using DNSSEC, we'll continue the process to make a
1755          * complete list to be cached.  However, we need to cancel the
1756          * caching when something unexpected happens, in order to avoid
1757          * caching incomplete information.
1758          */
1759         result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0,
1760                                      client->now, rdataset, sigrdataset);
1761         /*
1762          * If we can't promote glue/pending from the cache to secure
1763          * then drop it.
1764          */
1765         if (result == ISC_R_SUCCESS &&
1766             additionaltype == dns_rdatasetadditional_fromcache &&
1767             (DNS_TRUST_PENDING(rdataset->trust) ||
1768              DNS_TRUST_GLUE(rdataset->trust)) &&
1769             !validate(client, db, fname, rdataset, sigrdataset)) {
1770                 dns_rdataset_disassociate(rdataset);
1771                 if (dns_rdataset_isassociated(sigrdataset))
1772                         dns_rdataset_disassociate(sigrdataset);
1773                 result = ISC_R_NOTFOUND;
1774         }
1775         if (result == DNS_R_NCACHENXDOMAIN)
1776                 goto setcache;
1777         if (result == DNS_R_NCACHENXRRSET) {
1778                 dns_rdataset_disassociate(rdataset);
1779                 if (dns_rdataset_isassociated(sigrdataset))
1780                         dns_rdataset_disassociate(sigrdataset);
1781         }
1782         if (result == ISC_R_SUCCESS) {
1783                 /* Remember the result as a cache */
1784                 ISC_LIST_APPEND(cfname.list, rdataset, link);
1785                 if (dns_rdataset_isassociated(sigrdataset)) {
1786                         ISC_LIST_APPEND(cfname.list, sigrdataset, link);
1787                         sigrdataset = query_newrdataset(client);
1788                 }
1789                 rdataset = query_newrdataset(client);
1790                 if (sigrdataset == NULL || rdataset == NULL) {
1791                         /* do not cache incomplete information */
1792                         goto foundcache;
1793                 }
1794         }
1795
1796         /* Find AAAA RRset with sig RRset */
1797         result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa,
1798                                      0, client->now, rdataset, sigrdataset);
1799         /*
1800          * If we can't promote glue/pending from the cache to secure
1801          * then drop it.
1802          */
1803         if (result == ISC_R_SUCCESS &&
1804             additionaltype == dns_rdatasetadditional_fromcache &&
1805             (DNS_TRUST_PENDING(rdataset->trust) ||
1806              DNS_TRUST_GLUE(rdataset->trust)) &&
1807             !validate(client, db, fname, rdataset, sigrdataset)) {
1808                 dns_rdataset_disassociate(rdataset);
1809                 if (dns_rdataset_isassociated(sigrdataset))
1810                         dns_rdataset_disassociate(sigrdataset);
1811                 result = ISC_R_NOTFOUND;
1812         }
1813         if (result == ISC_R_SUCCESS) {
1814                 ISC_LIST_APPEND(cfname.list, rdataset, link);
1815                 rdataset = NULL;
1816                 if (dns_rdataset_isassociated(sigrdataset)) {
1817                         ISC_LIST_APPEND(cfname.list, sigrdataset, link);
1818                         sigrdataset = NULL;
1819                 }
1820         }
1821
1822  setcache:
1823         /*
1824          * Set the new result in the cache if required.  We do not support
1825          * caching additional data from a cache DB.
1826          */
1827         if (needadditionalcache == ISC_TRUE &&
1828             (additionaltype == dns_rdatasetadditional_fromauth ||
1829              additionaltype == dns_rdatasetadditional_fromglue)) {
1830                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1831                                                  type, client->view->acache,
1832                                                  zone, db, version, node,
1833                                                  &cfname);
1834         }
1835
1836  foundcache:
1837         need_sigrrset = ISC_FALSE;
1838         mname0 = NULL;
1839         for (crdataset = ISC_LIST_HEAD(cfname.list);
1840              crdataset != NULL;
1841              crdataset = crdataset_next) {
1842                 dns_name_t *mname;
1843
1844                 crdataset_next = ISC_LIST_NEXT(crdataset, link);
1845
1846                 mname = NULL;
1847                 if (crdataset->type == dns_rdatatype_a ||
1848                     crdataset->type == dns_rdatatype_aaaa) {
1849                         if (!query_isduplicate(client, fname, crdataset->type,
1850                                                &mname)) {
1851                                 if (mname != NULL) {
1852                                         /*
1853                                          * A different type of this name is
1854                                          * already stored in the additional
1855                                          * section.  We'll reuse the name.
1856                                          * Note that this should happen at most
1857                                          * once.  Otherwise, fname->link could
1858                                          * leak below.
1859                                          */
1860                                         INSIST(mname0 == NULL);
1861
1862                                         query_releasename(client, &fname);
1863                                         fname = mname;
1864                                         mname0 = mname;
1865                                 } else
1866                                         need_addname = ISC_TRUE;
1867                                 ISC_LIST_UNLINK(cfname.list, crdataset, link);
1868                                 ISC_LIST_APPEND(fname->list, crdataset, link);
1869                                 added_something = ISC_TRUE;
1870                                 need_sigrrset = ISC_TRUE;
1871                         } else
1872                                 need_sigrrset = ISC_FALSE;
1873                 } else if (crdataset->type == dns_rdatatype_rrsig &&
1874                            need_sigrrset && WANTDNSSEC(client)) {
1875                         ISC_LIST_UNLINK(cfname.list, crdataset, link);
1876                         ISC_LIST_APPEND(fname->list, crdataset, link);
1877                         added_something = ISC_TRUE; /* just in case */
1878                         need_sigrrset = ISC_FALSE;
1879                 }
1880         }
1881
1882         CTRACE("query_addadditional2: addname");
1883
1884         /*
1885          * If we haven't added anything, then we're done.
1886          */
1887         if (!added_something)
1888                 goto cleanup;
1889
1890         /*
1891          * We may have added our rdatasets to an existing name, if so, then
1892          * need_addname will be ISC_FALSE.  Whether we used an existing name
1893          * or a new one, we must set fname to NULL to prevent cleanup.
1894          */
1895         if (need_addname)
1896                 dns_message_addname(client->message, fname,
1897                                     DNS_SECTION_ADDITIONAL);
1898         fname = NULL;
1899
1900  cleanup:
1901         CTRACE("query_addadditional2: cleanup");
1902
1903         if (rdataset != NULL)
1904                 query_putrdataset(client, &rdataset);
1905         if (sigrdataset != NULL)
1906                 query_putrdataset(client, &sigrdataset);
1907         while  ((crdataset = ISC_LIST_HEAD(cfname.list)) != NULL) {
1908                 ISC_LIST_UNLINK(cfname.list, crdataset, link);
1909                 query_putrdataset(client, &crdataset);
1910         }
1911         if (fname != NULL)
1912                 query_releasename(client, &fname);
1913         if (node != NULL)
1914                 dns_db_detachnode(db, &node);
1915         if (db != NULL)
1916                 dns_db_detach(&db);
1917         if (zone != NULL)
1918                 dns_zone_detach(&zone);
1919
1920         CTRACE("query_addadditional2: done");
1921         return (eresult);
1922 }
1923
1924 static inline void
1925 query_addrdataset(ns_client_t *client, dns_name_t *fname,
1926                   dns_rdataset_t *rdataset)
1927 {
1928         client_additionalctx_t additionalctx;
1929
1930         /*
1931          * Add 'rdataset' and any pertinent additional data to
1932          * 'fname', a name in the response message for 'client'.
1933          */
1934
1935         CTRACE("query_addrdataset");
1936
1937         ISC_LIST_APPEND(fname->list, rdataset, link);
1938
1939         if (client->view->order != NULL)
1940                 rdataset->attributes |= dns_order_find(client->view->order,
1941                                                        fname, rdataset->type,
1942                                                        rdataset->rdclass);
1943         rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
1944
1945         if (NOADDITIONAL(client))
1946                 return;
1947
1948         /*
1949          * Add additional data.
1950          *
1951          * We don't care if dns_rdataset_additionaldata() fails.
1952          */
1953         additionalctx.client = client;
1954         additionalctx.rdataset = rdataset;
1955         (void)dns_rdataset_additionaldata(rdataset, query_addadditional2,
1956                                           &additionalctx);
1957         CTRACE("query_addrdataset: done");
1958 }
1959
1960 static void
1961 query_addrrset(ns_client_t *client, dns_name_t **namep,
1962                dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
1963                isc_buffer_t *dbuf, dns_section_t section)
1964 {
1965         dns_name_t *name, *mname;
1966         dns_rdataset_t *rdataset, *mrdataset, *sigrdataset;
1967         isc_result_t result;
1968
1969         /*%
1970          * To the current response for 'client', add the answer RRset
1971          * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
1972          * owner name '*namep', to section 'section', unless they are
1973          * already there.  Also add any pertinent additional data.
1974          *
1975          * If 'dbuf' is not NULL, then '*namep' is the name whose data is
1976          * stored in 'dbuf'.  In this case, query_addrrset() guarantees that
1977          * when it returns the name will either have been kept or released.
1978          */
1979         CTRACE("query_addrrset");
1980         name = *namep;
1981         rdataset = *rdatasetp;
1982         if (sigrdatasetp != NULL)
1983                 sigrdataset = *sigrdatasetp;
1984         else
1985                 sigrdataset = NULL;
1986         mname = NULL;
1987         mrdataset = NULL;
1988         result = dns_message_findname(client->message, section,
1989                                       name, rdataset->type, rdataset->covers,
1990                                       &mname, &mrdataset);
1991         if (result == ISC_R_SUCCESS) {
1992                 /*
1993                  * We've already got an RRset of the given name and type.
1994                  * There's nothing else to do;
1995                  */
1996                 CTRACE("query_addrrset: dns_message_findname succeeded: done");
1997                 if (dbuf != NULL)
1998                         query_releasename(client, namep);
1999                 return;
2000         } else if (result == DNS_R_NXDOMAIN) {
2001                 /*
2002                  * The name doesn't exist.
2003                  */
2004                 if (dbuf != NULL)
2005                         query_keepname(client, name, dbuf);
2006                 dns_message_addname(client->message, name, section);
2007                 *namep = NULL;
2008                 mname = name;
2009         } else {
2010                 RUNTIME_CHECK(result == DNS_R_NXRRSET);
2011                 if (dbuf != NULL)
2012                         query_releasename(client, namep);
2013         }
2014
2015         if (rdataset->trust != dns_trust_secure &&
2016             (section == DNS_SECTION_ANSWER ||
2017              section == DNS_SECTION_AUTHORITY))
2018                 client->query.attributes &= ~NS_QUERYATTR_SECURE;
2019         /*
2020          * Note: we only add SIGs if we've added the type they cover, so
2021          * we do not need to check if the SIG rdataset is already in the
2022          * response.
2023          */
2024         query_addrdataset(client, mname, rdataset);
2025         *rdatasetp = NULL;
2026         if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
2027                 /*
2028                  * We have a signature.  Add it to the response.
2029                  */
2030                 ISC_LIST_APPEND(mname->list, sigrdataset, link);
2031                 *sigrdatasetp = NULL;
2032         }
2033         CTRACE("query_addrrset: done");
2034 }
2035
2036 static inline isc_result_t
2037 query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
2038              isc_boolean_t zero_ttl)
2039 {
2040         dns_name_t *name;
2041         dns_dbnode_t *node;
2042         isc_result_t result, eresult;
2043         dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
2044         dns_rdataset_t **sigrdatasetp = NULL;
2045
2046         CTRACE("query_addsoa");
2047         /*
2048          * Initialization.
2049          */
2050         eresult = ISC_R_SUCCESS;
2051         name = NULL;
2052         rdataset = NULL;
2053         node = NULL;
2054
2055         /*
2056          * Get resources and make 'name' be the database origin.
2057          */
2058         result = dns_message_gettempname(client->message, &name);
2059         if (result != ISC_R_SUCCESS)
2060                 return (result);
2061         dns_name_init(name, NULL);
2062         dns_name_clone(dns_db_origin(db), name);
2063         rdataset = query_newrdataset(client);
2064         if (rdataset == NULL) {
2065                 eresult = DNS_R_SERVFAIL;
2066                 goto cleanup;
2067         }
2068         if (WANTDNSSEC(client) && dns_db_issecure(db)) {
2069                 sigrdataset = query_newrdataset(client);
2070                 if (sigrdataset == NULL) {
2071                         eresult = DNS_R_SERVFAIL;
2072                         goto cleanup;
2073                 }
2074         }
2075
2076         /*
2077          * Find the SOA.
2078          */
2079         result = dns_db_getoriginnode(db, &node);
2080         if (result == ISC_R_SUCCESS) {
2081                 result = dns_db_findrdataset(db, node, version,
2082                                              dns_rdatatype_soa,
2083                                              0, client->now, rdataset,
2084                                              sigrdataset);
2085         } else {
2086                 dns_fixedname_t foundname;
2087                 dns_name_t *fname;
2088
2089                 dns_fixedname_init(&foundname);
2090                 fname = dns_fixedname_name(&foundname);
2091
2092                 result = dns_db_find(db, name, version, dns_rdatatype_soa,
2093                                      client->query.dboptions, 0, &node,
2094                                      fname, rdataset, sigrdataset);
2095         }
2096         if (result != ISC_R_SUCCESS) {
2097                 /*
2098                  * This is bad.  We tried to get the SOA RR at the zone top
2099                  * and it didn't work!
2100                  */
2101                 eresult = DNS_R_SERVFAIL;
2102         } else {
2103                 /*
2104                  * Extract the SOA MINIMUM.
2105                  */
2106                 dns_rdata_soa_t soa;
2107                 dns_rdata_t rdata = DNS_RDATA_INIT;
2108                 result = dns_rdataset_first(rdataset);
2109                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2110                 dns_rdataset_current(rdataset, &rdata);
2111                 result = dns_rdata_tostruct(&rdata, &soa, NULL);
2112                 if (result != ISC_R_SUCCESS)
2113                         goto cleanup;
2114
2115                 if (zero_ttl) {
2116                         rdataset->ttl = 0;
2117                         if (sigrdataset != NULL)
2118                                 sigrdataset->ttl = 0;
2119                 }
2120
2121                 /*
2122                  * Add the SOA and its SIG to the response, with the
2123                  * TTLs adjusted per RFC2308 section 3.
2124                  */
2125                 if (rdataset->ttl > soa.minimum)
2126                         rdataset->ttl = soa.minimum;
2127                 if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum)
2128                         sigrdataset->ttl = soa.minimum;
2129
2130                 if (sigrdataset != NULL)
2131                         sigrdatasetp = &sigrdataset;
2132                 else
2133                         sigrdatasetp = NULL;
2134                 query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL,
2135                                DNS_SECTION_AUTHORITY);
2136         }
2137
2138  cleanup:
2139         query_putrdataset(client, &rdataset);
2140         if (sigrdataset != NULL)
2141                 query_putrdataset(client, &sigrdataset);
2142         if (name != NULL)
2143                 query_releasename(client, &name);
2144         if (node != NULL)
2145                 dns_db_detachnode(db, &node);
2146
2147         return (eresult);
2148 }
2149
2150 static inline isc_result_t
2151 query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
2152         dns_name_t *name, *fname;
2153         dns_dbnode_t *node;
2154         isc_result_t result, eresult;
2155         dns_fixedname_t foundname;
2156         dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
2157         dns_rdataset_t **sigrdatasetp = NULL;
2158
2159         CTRACE("query_addns");
2160         /*
2161          * Initialization.
2162          */
2163         eresult = ISC_R_SUCCESS;
2164         name = NULL;
2165         rdataset = NULL;
2166         node = NULL;
2167         dns_fixedname_init(&foundname);
2168         fname = dns_fixedname_name(&foundname);
2169
2170         /*
2171          * Get resources and make 'name' be the database origin.
2172          */
2173         result = dns_message_gettempname(client->message, &name);
2174         if (result != ISC_R_SUCCESS) {
2175                 CTRACE("query_addns: dns_message_gettempname failed: done");
2176                 return (result);
2177         }
2178         dns_name_init(name, NULL);
2179         dns_name_clone(dns_db_origin(db), name);
2180         rdataset = query_newrdataset(client);
2181         if (rdataset == NULL) {
2182                 CTRACE("query_addns: query_newrdataset failed");
2183                 eresult = DNS_R_SERVFAIL;
2184                 goto cleanup;
2185         }
2186         if (WANTDNSSEC(client) && dns_db_issecure(db)) {
2187                 sigrdataset = query_newrdataset(client);
2188                 if (sigrdataset == NULL) {
2189                         CTRACE("query_addns: query_newrdataset failed");
2190                         eresult = DNS_R_SERVFAIL;
2191                         goto cleanup;
2192                 }
2193         }
2194
2195         /*
2196          * Find the NS rdataset.
2197          */
2198         result = dns_db_getoriginnode(db, &node);
2199         if (result == ISC_R_SUCCESS) {
2200                 result = dns_db_findrdataset(db, node, version,
2201                                              dns_rdatatype_ns,
2202                                              0, client->now, rdataset,
2203                                              sigrdataset);
2204         } else {
2205                 CTRACE("query_addns: calling dns_db_find");
2206                 result = dns_db_find(db, name, NULL, dns_rdatatype_ns,
2207                                      client->query.dboptions, 0, &node,
2208                                      fname, rdataset, sigrdataset);
2209                 CTRACE("query_addns: dns_db_find complete");
2210         }
2211         if (result != ISC_R_SUCCESS) {
2212                 CTRACE("query_addns: "
2213                        "dns_db_findrdataset or dns_db_find failed");
2214                 /*
2215                  * This is bad.  We tried to get the NS rdataset at the zone
2216                  * top and it didn't work!
2217                  */
2218                 eresult = DNS_R_SERVFAIL;
2219         } else {
2220                 if (sigrdataset != NULL)
2221                         sigrdatasetp = &sigrdataset;
2222                 else
2223                         sigrdatasetp = NULL;
2224                 query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL,
2225                                DNS_SECTION_AUTHORITY);
2226         }
2227
2228  cleanup:
2229         CTRACE("query_addns: cleanup");
2230         query_putrdataset(client, &rdataset);
2231         if (sigrdataset != NULL)
2232                 query_putrdataset(client, &sigrdataset);
2233         if (name != NULL)
2234                 query_releasename(client, &name);
2235         if (node != NULL)
2236                 dns_db_detachnode(db, &node);
2237
2238         CTRACE("query_addns: done");
2239         return (eresult);
2240 }
2241
2242 static inline isc_result_t
2243 query_addcnamelike(ns_client_t *client, dns_name_t *qname, dns_name_t *tname,
2244                    dns_rdataset_t *dname, dns_name_t **anamep,
2245                    dns_rdatatype_t type)
2246 {
2247         dns_rdataset_t *rdataset;
2248         dns_rdatalist_t *rdatalist;
2249         dns_rdata_t *rdata;
2250         isc_result_t result;
2251         isc_region_t r;
2252
2253         /*
2254          * We assume the name data referred to by tname won't go away.
2255          */
2256
2257         REQUIRE(anamep != NULL);
2258
2259         rdatalist = NULL;
2260         result = dns_message_gettemprdatalist(client->message, &rdatalist);
2261         if (result != ISC_R_SUCCESS)
2262                 return (result);
2263         rdata = NULL;
2264         result = dns_message_gettemprdata(client->message, &rdata);
2265         if (result != ISC_R_SUCCESS)
2266                 return (result);
2267         rdataset = NULL;
2268         result = dns_message_gettemprdataset(client->message, &rdataset);
2269         if (result != ISC_R_SUCCESS)
2270                 return (result);
2271         dns_rdataset_init(rdataset);
2272         result = dns_name_dup(qname, client->mctx, *anamep);
2273         if (result != ISC_R_SUCCESS) {
2274                 dns_message_puttemprdataset(client->message, &rdataset);
2275                 return (result);
2276         }
2277
2278         rdatalist->type = type;
2279         rdatalist->covers = 0;
2280         rdatalist->rdclass = client->message->rdclass;
2281         rdatalist->ttl = dname->ttl;
2282
2283         dns_name_toregion(tname, &r);
2284         rdata->data = r.base;
2285         rdata->length = r.length;
2286         rdata->rdclass = client->message->rdclass;
2287         rdata->type = type;
2288
2289         ISC_LIST_INIT(rdatalist->rdata);
2290         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2291         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset)
2292                       == ISC_R_SUCCESS);
2293         rdataset->trust = dname->trust;
2294
2295         query_addrrset(client, anamep, &rdataset, NULL, NULL,
2296                        DNS_SECTION_ANSWER);
2297
2298         if (rdataset != NULL) {
2299                 if (dns_rdataset_isassociated(rdataset))
2300                         dns_rdataset_disassociate(rdataset);
2301                 dns_message_puttemprdataset(client->message, &rdataset);
2302         }
2303
2304         return (ISC_R_SUCCESS);
2305 }
2306
2307 /*
2308  * Mark the RRsets as secure.  Update the cache (db) to reflect the
2309  * change in trust level.
2310  */
2311 static void
2312 mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2313             isc_uint32_t ttl, dns_rdataset_t *rdataset,
2314             dns_rdataset_t *sigrdataset)
2315 {
2316         isc_result_t result;
2317         dns_dbnode_t *node = NULL;
2318
2319         rdataset->trust = dns_trust_secure;
2320         sigrdataset->trust = dns_trust_secure;
2321
2322         /*
2323          * Save the updated secure state.  Ignore failures.
2324          */
2325         result = dns_db_findnode(db, name, ISC_TRUE, &node);
2326         if (result != ISC_R_SUCCESS)
2327                 return;
2328         /*
2329          * Bound the validated ttls then minimise.
2330          */
2331         if (sigrdataset->ttl > ttl)
2332                 sigrdataset->ttl = ttl;
2333         if (rdataset->ttl > ttl)
2334                 rdataset->ttl = ttl;
2335         if (rdataset->ttl > sigrdataset->ttl)
2336                 rdataset->ttl = sigrdataset->ttl;
2337         else
2338                 sigrdataset->ttl = rdataset->ttl;
2339
2340         (void)dns_db_addrdataset(db, node, NULL, client->now, rdataset,
2341                                  0, NULL);
2342         (void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset,
2343                                  0, NULL);
2344         dns_db_detachnode(db, &node);
2345 }
2346
2347 /*
2348  * Find the secure key that corresponds to rrsig.
2349  * Note: 'keyrdataset' maintains state between successive calls,
2350  * there may be multiple keys with the same keyid.
2351  * Return ISC_FALSE if we have exhausted all the possible keys.
2352  */
2353 static isc_boolean_t
2354 get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
2355         dns_rdataset_t *keyrdataset, dst_key_t **keyp)
2356 {
2357         isc_result_t result;
2358         dns_dbnode_t *node = NULL;
2359         isc_boolean_t secure = ISC_FALSE;
2360
2361         if (!dns_rdataset_isassociated(keyrdataset)) {
2362                 result = dns_db_findnode(db, &rrsig->signer, ISC_FALSE, &node);
2363                 if (result != ISC_R_SUCCESS)
2364                         return (ISC_FALSE);
2365
2366                 result = dns_db_findrdataset(db, node, NULL,
2367                                              dns_rdatatype_dnskey, 0,
2368                                              client->now, keyrdataset, NULL);
2369                 dns_db_detachnode(db, &node);
2370                 if (result != ISC_R_SUCCESS)
2371                         return (ISC_FALSE);
2372
2373                 if (keyrdataset->trust != dns_trust_secure)
2374                         return (ISC_FALSE);
2375
2376                 result = dns_rdataset_first(keyrdataset);
2377         } else
2378                 result = dns_rdataset_next(keyrdataset);
2379
2380         for ( ; result == ISC_R_SUCCESS;
2381              result = dns_rdataset_next(keyrdataset)) {
2382                 dns_rdata_t rdata = DNS_RDATA_INIT;
2383                 isc_buffer_t b;
2384
2385                 dns_rdataset_current(keyrdataset, &rdata);
2386                 isc_buffer_init(&b, rdata.data, rdata.length);
2387                 isc_buffer_add(&b, rdata.length);
2388                 result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
2389                                          client->mctx, keyp);
2390                 if (result != ISC_R_SUCCESS)
2391                         continue;
2392                 if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
2393                     rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
2394                     dst_key_iszonekey(*keyp)) {
2395                         secure = ISC_TRUE;
2396                         break;
2397                 }
2398                 dst_key_free(keyp);
2399         }
2400         return (secure);
2401 }
2402
2403 static isc_boolean_t
2404 verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
2405        dns_rdata_t *rdata, isc_mem_t *mctx, isc_boolean_t acceptexpired)
2406 {
2407         isc_result_t result;
2408         dns_fixedname_t fixed;
2409         isc_boolean_t ignore = ISC_FALSE;
2410
2411         dns_fixedname_init(&fixed);
2412
2413 again:
2414         result = dns_dnssec_verify2(name, rdataset, key, ignore, mctx,
2415                                     rdata, NULL);
2416         if (result == DNS_R_SIGEXPIRED && acceptexpired) {
2417                 ignore = ISC_TRUE;
2418                 goto again;
2419         }
2420         if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD)
2421                 return (ISC_TRUE);
2422         return (ISC_FALSE);
2423 }
2424
2425 /*
2426  * Validate the rdataset if possible with available records.
2427  */
2428 static isc_boolean_t
2429 validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2430          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
2431 {
2432         isc_result_t result;
2433         dns_rdata_t rdata = DNS_RDATA_INIT;
2434         dns_rdata_rrsig_t rrsig;
2435         dst_key_t *key = NULL;
2436         dns_rdataset_t keyrdataset;
2437
2438         if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
2439                 return (ISC_FALSE);
2440
2441         for (result = dns_rdataset_first(sigrdataset);
2442              result == ISC_R_SUCCESS;
2443              result = dns_rdataset_next(sigrdataset)) {
2444
2445                 dns_rdata_reset(&rdata);
2446                 dns_rdataset_current(sigrdataset, &rdata);
2447                 result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
2448                 if (result != ISC_R_SUCCESS)
2449                         return (ISC_FALSE);
2450                 if (!dns_resolver_algorithm_supported(client->view->resolver,
2451                                                       name, rrsig.algorithm))
2452                         continue;
2453                 if (!dns_name_issubdomain(name, &rrsig.signer))
2454                         continue;
2455                 dns_rdataset_init(&keyrdataset);
2456                 do {
2457                         if (!get_key(client, db, &rrsig, &keyrdataset, &key))
2458                                 break;
2459                         if (verify(key, name, rdataset, &rdata, client->mctx,
2460                                    client->view->acceptexpired)) {
2461                                 dst_key_free(&key);
2462                                 dns_rdataset_disassociate(&keyrdataset);
2463                                 mark_secure(client, db, name,
2464                                             rrsig.originalttl,
2465                                             rdataset, sigrdataset);
2466                                 return (ISC_TRUE);
2467                         }
2468                         dst_key_free(&key);
2469                 } while (1);
2470                 if (dns_rdataset_isassociated(&keyrdataset))
2471                         dns_rdataset_disassociate(&keyrdataset);
2472         }
2473         return (ISC_FALSE);
2474 }
2475
2476 static void
2477 query_addbestns(ns_client_t *client) {
2478         dns_db_t *db, *zdb;
2479         dns_dbnode_t *node;
2480         dns_name_t *fname, *zfname;
2481         dns_rdataset_t *rdataset, *sigrdataset, *zrdataset, *zsigrdataset;
2482         isc_boolean_t is_zone, use_zone;
2483         isc_buffer_t *dbuf;
2484         isc_result_t result;
2485         dns_dbversion_t *version;
2486         dns_zone_t *zone;
2487         isc_buffer_t b;
2488
2489         CTRACE("query_addbestns");
2490         fname = NULL;
2491         zfname = NULL;
2492         rdataset = NULL;
2493         zrdataset = NULL;
2494         sigrdataset = NULL;
2495         zsigrdataset = NULL;
2496         node = NULL;
2497         db = NULL;
2498         zdb = NULL;
2499         version = NULL;
2500         zone = NULL;
2501         is_zone = ISC_FALSE;
2502         use_zone = ISC_FALSE;
2503
2504         /*
2505          * Find the right database.
2506          */
2507         result = query_getdb(client, client->query.qname, dns_rdatatype_ns, 0,
2508                              &zone, &db, &version, &is_zone);
2509         if (result != ISC_R_SUCCESS)
2510                 goto cleanup;
2511
2512  db_find:
2513         /*
2514          * We'll need some resources...
2515          */
2516         dbuf = query_getnamebuf(client);
2517         if (dbuf == NULL)
2518                 goto cleanup;
2519         fname = query_newname(client, dbuf, &b);
2520         rdataset = query_newrdataset(client);
2521         if (fname == NULL || rdataset == NULL)
2522                 goto cleanup;
2523         /*
2524          * Get the RRSIGs if the client requested them or if we may
2525          * need to validate answers from the cache.
2526          */
2527         if (WANTDNSSEC(client) || !is_zone) {
2528                 sigrdataset = query_newrdataset(client);
2529                 if (sigrdataset == NULL)
2530                         goto cleanup;
2531         }
2532
2533         /*
2534          * Now look for the zonecut.
2535          */
2536         if (is_zone) {
2537                 result = dns_db_find(db, client->query.qname, version,
2538                                      dns_rdatatype_ns, client->query.dboptions,
2539                                      client->now, &node, fname,
2540                                      rdataset, sigrdataset);
2541                 if (result != DNS_R_DELEGATION)
2542                         goto cleanup;
2543                 if (USECACHE(client)) {
2544                         query_keepname(client, fname, dbuf);
2545                         zdb = db;
2546                         zfname = fname;
2547                         fname = NULL;
2548                         zrdataset = rdataset;
2549                         rdataset = NULL;
2550                         zsigrdataset = sigrdataset;
2551                         sigrdataset = NULL;
2552                         dns_db_detachnode(db, &node);
2553                         version = NULL;
2554                         db = NULL;
2555                         dns_db_attach(client->view->cachedb, &db);
2556                         is_zone = ISC_FALSE;
2557                         goto db_find;
2558                 }
2559         } else {
2560                 result = dns_db_findzonecut(db, client->query.qname,
2561                                             client->query.dboptions,
2562                                             client->now, &node, fname,
2563                                             rdataset, sigrdataset);
2564                 if (result == ISC_R_SUCCESS) {
2565                         if (zfname != NULL &&
2566                             !dns_name_issubdomain(fname, zfname)) {
2567                                 /*
2568                                  * We found a zonecut in the cache, but our
2569                                  * zone delegation is better.
2570                                  */
2571                                 use_zone = ISC_TRUE;
2572                         }
2573                 } else if (result == ISC_R_NOTFOUND && zfname != NULL) {
2574                         /*
2575                          * We didn't find anything in the cache, but we
2576                          * have a zone delegation, so use it.
2577                          */
2578                         use_zone = ISC_TRUE;
2579                 } else
2580                         goto cleanup;
2581         }
2582
2583         if (use_zone) {
2584                 query_releasename(client, &fname);
2585                 fname = zfname;
2586                 zfname = NULL;
2587                 /*
2588                  * We've already done query_keepname() on
2589                  * zfname, so we must set dbuf to NULL to
2590                  * prevent query_addrrset() from trying to
2591                  * call query_keepname() again.
2592                  */
2593                 dbuf = NULL;
2594                 query_putrdataset(client, &rdataset);
2595                 if (sigrdataset != NULL)
2596                         query_putrdataset(client, &sigrdataset);
2597                 rdataset = zrdataset;
2598                 zrdataset = NULL;
2599                 sigrdataset = zsigrdataset;
2600                 zsigrdataset = NULL;
2601         }
2602
2603         /*
2604          * Attempt to validate RRsets that are pending or that are glue.
2605          */
2606         if ((DNS_TRUST_PENDING(rdataset->trust) ||
2607              (sigrdataset != NULL && DNS_TRUST_PENDING(sigrdataset->trust)))
2608             && !validate(client, db, fname, rdataset, sigrdataset) &&
2609             !PENDINGOK(client->query.dboptions))
2610                 goto cleanup;
2611
2612         if ((DNS_TRUST_GLUE(rdataset->trust) ||
2613              (sigrdataset != NULL && DNS_TRUST_GLUE(sigrdataset->trust))) &&
2614             !validate(client, db, fname, rdataset, sigrdataset) &&
2615             SECURE(client) && WANTDNSSEC(client))
2616                 goto cleanup;
2617
2618         /*
2619          * If the client doesn't want DNSSEC we can discard the sigrdataset
2620          * now.
2621          */
2622         if (!WANTDNSSEC(client))
2623                 query_putrdataset(client, &sigrdataset);
2624         query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2625                        DNS_SECTION_AUTHORITY);
2626
2627  cleanup:
2628         if (rdataset != NULL)
2629                 query_putrdataset(client, &rdataset);
2630         if (sigrdataset != NULL)
2631                 query_putrdataset(client, &sigrdataset);
2632         if (fname != NULL)
2633                 query_releasename(client, &fname);
2634         if (node != NULL)
2635                 dns_db_detachnode(db, &node);
2636         if (db != NULL)
2637                 dns_db_detach(&db);
2638         if (zone != NULL)
2639                 dns_zone_detach(&zone);
2640         if (zdb != NULL) {
2641                 query_putrdataset(client, &zrdataset);
2642                 if (zsigrdataset != NULL)
2643                         query_putrdataset(client, &zsigrdataset);
2644                 if (zfname != NULL)
2645                         query_releasename(client, &zfname);
2646                 dns_db_detach(&zdb);
2647         }
2648 }
2649
2650 static void
2651 fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) {
2652         if (*rdataset == NULL)
2653                 *rdataset = query_newrdataset(client);
2654         else  if (dns_rdataset_isassociated(*rdataset))
2655                 dns_rdataset_disassociate(*rdataset);
2656 }
2657
2658 static void
2659 fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf,
2660          isc_buffer_t *nbuf)
2661 {
2662         if (*fname == NULL) {
2663                 *dbuf = query_getnamebuf(client);
2664                 if (*dbuf == NULL)
2665                         return;
2666                 *fname = query_newname(client, *dbuf, nbuf);
2667         }
2668 }
2669
2670 static void
2671 query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node,
2672             dns_dbversion_t *version, dns_name_t *name)
2673 {
2674         dns_fixedname_t fixed;
2675         dns_name_t *fname = NULL;
2676         dns_name_t *rname;
2677         dns_rdataset_t *rdataset, *sigrdataset;
2678         isc_buffer_t *dbuf, b;
2679         isc_result_t result;
2680         unsigned int count;
2681
2682         CTRACE("query_addds");
2683         rname = NULL;
2684         rdataset = NULL;
2685         sigrdataset = NULL;
2686
2687         /*
2688          * We'll need some resources...
2689          */
2690         rdataset = query_newrdataset(client);
2691         sigrdataset = query_newrdataset(client);
2692         if (rdataset == NULL || sigrdataset == NULL)
2693                 goto cleanup;
2694
2695         /*
2696          * Look for the DS record, which may or may not be present.
2697          */
2698         result = dns_db_findrdataset(db, node, version, dns_rdatatype_ds, 0,
2699                                      client->now, rdataset, sigrdataset);
2700         /*
2701          * If we didn't find it, look for an NSEC.
2702          */
2703         if (result == ISC_R_NOTFOUND)
2704                 result = dns_db_findrdataset(db, node, version,
2705                                              dns_rdatatype_nsec, 0, client->now,
2706                                              rdataset, sigrdataset);
2707         if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
2708                 goto addnsec3;
2709         if (!dns_rdataset_isassociated(rdataset) ||
2710             !dns_rdataset_isassociated(sigrdataset))
2711                 goto addnsec3;
2712
2713         /*
2714          * We've already added the NS record, so if the name's not there,
2715          * we have other problems.  Use this name rather than calling
2716          * query_addrrset().
2717          */
2718         result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
2719         if (result != ISC_R_SUCCESS)
2720                 goto cleanup;
2721
2722         rname = NULL;
2723         dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
2724                                 &rname);
2725         result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
2726         if (result != ISC_R_SUCCESS)
2727                 goto cleanup;
2728
2729         ISC_LIST_APPEND(rname->list, rdataset, link);
2730         ISC_LIST_APPEND(rname->list, sigrdataset, link);
2731         rdataset = NULL;
2732         sigrdataset = NULL;
2733         return;
2734
2735    addnsec3:
2736         if (!dns_db_iszone(db))
2737                 goto cleanup;
2738         /*
2739          * Add the NSEC3 which proves the DS does not exist.
2740          */
2741         dbuf = query_getnamebuf(client);
2742         if (dbuf == NULL)
2743                 goto cleanup;
2744         fname = query_newname(client, dbuf, &b);
2745         dns_fixedname_init(&fixed);
2746         if (dns_rdataset_isassociated(rdataset))
2747                 dns_rdataset_disassociate(rdataset);
2748         if (dns_rdataset_isassociated(sigrdataset))
2749                 dns_rdataset_disassociate(sigrdataset);
2750         query_findclosestnsec3(name, db, version, client, rdataset,
2751                                sigrdataset, fname, ISC_TRUE,
2752                                dns_fixedname_name(&fixed));
2753         if (!dns_rdataset_isassociated(rdataset))
2754                 goto cleanup;
2755         query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2756                        DNS_SECTION_AUTHORITY);
2757         /*
2758          * Did we find the closest provable encloser instead?
2759          * If so add the nearest to the closest provable encloser.
2760          */
2761         if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
2762                 count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
2763                 dns_name_getlabelsequence(name,
2764                                           dns_name_countlabels(name) - count,
2765                                           count, dns_fixedname_name(&fixed));
2766                 fixfname(client, &fname, &dbuf, &b);
2767                 fixrdataset(client, &rdataset);
2768                 fixrdataset(client, &sigrdataset);
2769                 if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2770                                 goto cleanup;
2771                 query_findclosestnsec3(dns_fixedname_name(&fixed), db, version,
2772                                        client, rdataset, sigrdataset, fname,
2773                                        ISC_FALSE, NULL);
2774                 if (!dns_rdataset_isassociated(rdataset))
2775                         goto cleanup;
2776                 query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2777                                DNS_SECTION_AUTHORITY);
2778         }
2779
2780  cleanup:
2781         if (rdataset != NULL)
2782                 query_putrdataset(client, &rdataset);
2783         if (sigrdataset != NULL)
2784                 query_putrdataset(client, &sigrdataset);
2785         if (fname != NULL)
2786                 query_releasename(client, &fname);
2787 }
2788
2789 static void
2790 query_addwildcardproof(ns_client_t *client, dns_db_t *db,
2791                        dns_dbversion_t *version, dns_name_t *name,
2792                        isc_boolean_t ispositive)
2793 {
2794         isc_buffer_t *dbuf, b;
2795         dns_name_t *fname;
2796         dns_rdataset_t *rdataset, *sigrdataset;
2797         dns_fixedname_t wfixed;
2798         dns_name_t *wname;
2799         dns_dbnode_t *node;
2800         unsigned int options;
2801         unsigned int olabels, nlabels, labels;
2802         isc_result_t result;
2803         dns_rdata_t rdata = DNS_RDATA_INIT;
2804         dns_rdata_nsec_t nsec;
2805         isc_boolean_t have_wname;
2806         int order;
2807         dns_fixedname_t cfixed;
2808         dns_name_t *cname;
2809
2810         CTRACE("query_addwildcardproof");
2811         fname = NULL;
2812         rdataset = NULL;
2813         sigrdataset = NULL;
2814         node = NULL;
2815
2816         /*
2817          * Get the NOQNAME proof then if !ispositive
2818          * get the NOWILDCARD proof.
2819          *
2820          * DNS_DBFIND_NOWILD finds the NSEC records that covers the
2821          * name ignoring any wildcard.  From the owner and next names
2822          * of this record you can compute which wildcard (if it exists)
2823          * will match by finding the longest common suffix of the
2824          * owner name and next names with the qname and prefixing that
2825          * with the wildcard label.
2826          *
2827          * e.g.
2828          *   Given:
2829          *      example SOA
2830          *      example NSEC b.example
2831          *      b.example A
2832          *      b.example NSEC a.d.example
2833          *      a.d.example A
2834          *      a.d.example NSEC g.f.example
2835          *      g.f.example A
2836          *      g.f.example NSEC z.i.example
2837          *      z.i.example A
2838          *      z.i.example NSEC example
2839          *
2840          *   QNAME:
2841          *   a.example -> example NSEC b.example
2842          *      owner common example
2843          *      next common example
2844          *      wild *.example
2845          *   d.b.example -> b.example NSEC a.d.example
2846          *      owner common b.example
2847          *      next common example
2848          *      wild *.b.example
2849          *   a.f.example -> a.d.example NSEC g.f.example
2850          *      owner common example
2851          *      next common f.example
2852          *      wild *.f.example
2853          *  j.example -> z.i.example NSEC example
2854          *      owner common example
2855          *      next common example
2856          *      wild *.f.example
2857          */
2858         options = client->query.dboptions | DNS_DBFIND_NOWILD;
2859         dns_fixedname_init(&wfixed);
2860         wname = dns_fixedname_name(&wfixed);
2861  again:
2862         have_wname = ISC_FALSE;
2863         /*
2864          * We'll need some resources...
2865          */
2866         dbuf = query_getnamebuf(client);
2867         if (dbuf == NULL)
2868                 goto cleanup;
2869         fname = query_newname(client, dbuf, &b);
2870         rdataset = query_newrdataset(client);
2871         sigrdataset = query_newrdataset(client);
2872         if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2873                 goto cleanup;
2874
2875         result = dns_db_find(db, name, version, dns_rdatatype_nsec, options,
2876                              0, &node, fname, rdataset, sigrdataset);
2877         if (node != NULL)
2878                 dns_db_detachnode(db, &node);
2879
2880         if (!dns_rdataset_isassociated(rdataset)) {
2881                 /*
2882                  * No NSEC proof available, return NSEC3 proofs instead.
2883                  */
2884                 dns_fixedname_init(&cfixed);
2885                 cname = dns_fixedname_name(&cfixed);
2886                 /*
2887                  * Find the closest encloser.
2888                  */
2889                 dns_name_copy(name, cname, NULL);
2890                 while (result == DNS_R_NXDOMAIN) {
2891                         labels = dns_name_countlabels(cname) - 1;
2892                         dns_name_split(cname, labels, NULL, cname);
2893                         result = dns_db_find(db, cname, version,
2894                                              dns_rdatatype_nsec,
2895                                              options, 0, NULL, fname,
2896                                              NULL, NULL);
2897                 }
2898                 /*
2899                  * Add closest (provable) encloser NSEC3.
2900                  */
2901                 query_findclosestnsec3(cname, db, NULL, client, rdataset,
2902                                        sigrdataset, fname, ISC_TRUE, cname);
2903                 if (!dns_rdataset_isassociated(rdataset))
2904                         goto cleanup;
2905                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2906                                dbuf, DNS_SECTION_AUTHORITY);
2907
2908                 /*
2909                  * Replace resources which were consumed by query_addrrset.
2910                  */
2911                 if (fname == NULL) {
2912                         dbuf = query_getnamebuf(client);
2913                         if (dbuf == NULL)
2914                                 goto cleanup;
2915                         fname = query_newname(client, dbuf, &b);
2916                 }
2917
2918                 if (rdataset == NULL)
2919                         rdataset = query_newrdataset(client);
2920                 else if (dns_rdataset_isassociated(rdataset))
2921                         dns_rdataset_disassociate(rdataset);
2922
2923                 if (sigrdataset == NULL)
2924                         sigrdataset = query_newrdataset(client);
2925                 else if (dns_rdataset_isassociated(sigrdataset))
2926                         dns_rdataset_disassociate(sigrdataset);
2927
2928                 if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2929                         goto cleanup;
2930                 /*
2931                  * Add no qname proof.
2932                  */
2933                 labels = dns_name_countlabels(cname) + 1;
2934                 if (dns_name_countlabels(name) == labels)
2935                         dns_name_copy(name, wname, NULL);
2936                 else
2937                         dns_name_split(name, labels, NULL, wname);
2938
2939                 query_findclosestnsec3(wname, db, NULL, client, rdataset,
2940                                        sigrdataset, fname, ISC_FALSE, NULL);
2941                 if (!dns_rdataset_isassociated(rdataset))
2942                         goto cleanup;
2943                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2944                                dbuf, DNS_SECTION_AUTHORITY);
2945
2946                 if (ispositive)
2947                         goto cleanup;
2948
2949                 /*
2950                  * Replace resources which were consumed by query_addrrset.
2951                  */
2952                 if (fname == NULL) {
2953                         dbuf = query_getnamebuf(client);
2954                         if (dbuf == NULL)
2955                                 goto cleanup;
2956                         fname = query_newname(client, dbuf, &b);
2957                 }
2958
2959                 if (rdataset == NULL)
2960                         rdataset = query_newrdataset(client);
2961                 else if (dns_rdataset_isassociated(rdataset))
2962                         dns_rdataset_disassociate(rdataset);
2963
2964                 if (sigrdataset == NULL)
2965                         sigrdataset = query_newrdataset(client);
2966                 else if (dns_rdataset_isassociated(sigrdataset))
2967                         dns_rdataset_disassociate(sigrdataset);
2968
2969                 if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2970                         goto cleanup;
2971                 /*
2972                  * Add the no wildcard proof.
2973                  */
2974                 result = dns_name_concatenate(dns_wildcardname,
2975                                               cname, wname, NULL);
2976                 if (result != ISC_R_SUCCESS)
2977                         goto cleanup;
2978
2979                 query_findclosestnsec3(wname, db, NULL, client, rdataset,
2980                                        sigrdataset, fname, ISC_FALSE, NULL);
2981                 if (!dns_rdataset_isassociated(rdataset))
2982                         goto cleanup;
2983                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2984                                dbuf, DNS_SECTION_AUTHORITY);
2985
2986                 goto cleanup;
2987         } else if (result == DNS_R_NXDOMAIN) {
2988                 if (!ispositive)
2989                         result = dns_rdataset_first(rdataset);
2990                 if (result == ISC_R_SUCCESS) {
2991                         dns_rdataset_current(rdataset, &rdata);
2992                         result = dns_rdata_tostruct(&rdata, &nsec, NULL);
2993                 }
2994                 if (result == ISC_R_SUCCESS) {
2995                         (void)dns_name_fullcompare(name, fname, &order,
2996                                                    &olabels);
2997                         (void)dns_name_fullcompare(name, &nsec.next, &order,
2998                                                    &nlabels);
2999                         /*
3000                          * Check for a pathological condition created when
3001                          * serving some malformed signed zones and bail out.
3002                          */
3003                         if (dns_name_countlabels(name) == nlabels)
3004                                 goto cleanup;
3005
3006                         if (olabels > nlabels)
3007                                 dns_name_split(name, olabels, NULL, wname);
3008                         else
3009                                 dns_name_split(name, nlabels, NULL, wname);
3010                         result = dns_name_concatenate(dns_wildcardname,
3011                                                       wname, wname, NULL);
3012                         if (result == ISC_R_SUCCESS)
3013                                 have_wname = ISC_TRUE;
3014                         dns_rdata_freestruct(&nsec);
3015                 }
3016                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
3017                                dbuf, DNS_SECTION_AUTHORITY);
3018         }
3019         if (rdataset != NULL)
3020                 query_putrdataset(client, &rdataset);
3021         if (sigrdataset != NULL)
3022                 query_putrdataset(client, &sigrdataset);
3023         if (fname != NULL)
3024                 query_releasename(client, &fname);
3025         if (have_wname) {
3026                 ispositive = ISC_TRUE;  /* prevent loop */
3027                 if (!dns_name_equal(name, wname)) {
3028                         name = wname;
3029                         goto again;
3030                 }
3031         }
3032  cleanup:
3033         if (rdataset != NULL)
3034                 query_putrdataset(client, &rdataset);
3035         if (sigrdataset != NULL)
3036                 query_putrdataset(client, &sigrdataset);
3037         if (fname != NULL)
3038                 query_releasename(client, &fname);
3039 }
3040
3041 static void
3042 query_addnxrrsetnsec(ns_client_t *client, dns_db_t *db,
3043                      dns_dbversion_t *version, dns_name_t **namep,
3044                      dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp)
3045 {
3046         dns_name_t *name;
3047         dns_rdataset_t *sigrdataset;
3048         dns_rdata_t sigrdata;
3049         dns_rdata_rrsig_t sig;
3050         unsigned int labels;
3051         isc_buffer_t *dbuf, b;
3052         dns_name_t *fname;
3053         isc_result_t result;
3054
3055         name = *namep;
3056         if ((name->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
3057                 query_addrrset(client, namep, rdatasetp, sigrdatasetp,
3058                                NULL, DNS_SECTION_AUTHORITY);
3059                 return;
3060         }
3061
3062         if (sigrdatasetp == NULL)
3063                 return;
3064
3065         sigrdataset = *sigrdatasetp;
3066         if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
3067                 return;
3068         result = dns_rdataset_first(sigrdataset);
3069         if (result != ISC_R_SUCCESS)
3070                 return;
3071         dns_rdata_init(&sigrdata);
3072         dns_rdataset_current(sigrdataset, &sigrdata);
3073         result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
3074         if (result != ISC_R_SUCCESS)
3075                 return;
3076
3077         labels = dns_name_countlabels(name);
3078         if ((unsigned int)sig.labels + 1 >= labels)
3079                 return;
3080
3081         /* XXX */
3082         query_addwildcardproof(client, db, version, client->query.qname,
3083                                ISC_TRUE);
3084
3085         /*
3086          * We'll need some resources...
3087          */
3088         dbuf = query_getnamebuf(client);
3089         if (dbuf == NULL)
3090                 return;
3091         fname = query_newname(client, dbuf, &b);
3092         if (fname == NULL)
3093                 return;
3094         dns_name_split(name, sig.labels + 1, NULL, fname);
3095         /* This will succeed, since we've stripped labels. */
3096         RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
3097                                            NULL) == ISC_R_SUCCESS);
3098         query_addrrset(client, &fname, rdatasetp, sigrdatasetp,
3099                        dbuf, DNS_SECTION_AUTHORITY);
3100 }
3101
3102 static void
3103 query_resume(isc_task_t *task, isc_event_t *event) {
3104         dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
3105         dns_fetch_t *fetch;
3106         ns_client_t *client;
3107         isc_boolean_t fetch_canceled, client_shuttingdown;
3108         isc_result_t result;
3109         isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_EERRORS;
3110         int errorloglevel;
3111
3112         /*
3113          * Resume a query after recursion.
3114          */
3115
3116         UNUSED(task);
3117
3118         REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
3119         client = devent->ev_arg;
3120         REQUIRE(NS_CLIENT_VALID(client));
3121         REQUIRE(task == client->task);
3122         REQUIRE(RECURSING(client));
3123
3124         LOCK(&client->query.fetchlock);
3125         if (client->query.fetch != NULL) {
3126                 /*
3127                  * This is the fetch we've been waiting for.
3128                  */
3129                 INSIST(devent->fetch == client->query.fetch);
3130                 client->query.fetch = NULL;
3131                 fetch_canceled = ISC_FALSE;
3132                 /*
3133                  * Update client->now.
3134                  */
3135                 isc_stdtime_get(&client->now);
3136         } else {
3137                 /*
3138                  * This is a fetch completion event for a canceled fetch.
3139                  * Clean up and don't resume the find.
3140                  */
3141                 fetch_canceled = ISC_TRUE;
3142         }
3143         UNLOCK(&client->query.fetchlock);
3144         INSIST(client->query.fetch == NULL);
3145
3146         client->query.attributes &= ~NS_QUERYATTR_RECURSING;
3147         fetch = devent->fetch;
3148         devent->fetch = NULL;
3149
3150         /*
3151          * If this client is shutting down, or this transaction
3152          * has timed out, do not resume the find.
3153          */
3154         client_shuttingdown = ns_client_shuttingdown(client);
3155         if (fetch_canceled || client_shuttingdown) {
3156                 if (devent->node != NULL)
3157                         dns_db_detachnode(devent->db, &devent->node);
3158                 if (devent->db != NULL)
3159                         dns_db_detach(&devent->db);
3160                 query_putrdataset(client, &devent->rdataset);
3161                 if (devent->sigrdataset != NULL)
3162                         query_putrdataset(client, &devent->sigrdataset);
3163                 isc_event_free(&event);
3164                 if (fetch_canceled)
3165                         query_error(client, DNS_R_SERVFAIL, __LINE__);
3166                 else
3167                         query_next(client, ISC_R_CANCELED);
3168                 /*
3169                  * This may destroy the client.
3170                  */
3171                 ns_client_detach(&client);
3172         } else {
3173                 result = query_find(client, devent, 0);
3174                 if (result != ISC_R_SUCCESS) {
3175                         if (result == DNS_R_SERVFAIL)
3176                                 errorloglevel = ISC_LOG_DEBUG(2);
3177                         else
3178                                 errorloglevel = ISC_LOG_DEBUG(4);
3179                         if (isc_log_wouldlog(ns_g_lctx, errorloglevel)) {
3180                                 dns_resolver_logfetch(fetch, ns_g_lctx,
3181                                                       logcategory,
3182                                                       NS_LOGMODULE_QUERY,
3183                                                       errorloglevel, ISC_FALSE);
3184                         }
3185                 }
3186         }
3187
3188         dns_resolver_destroyfetch(&fetch);
3189 }
3190
3191 static isc_result_t
3192 query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
3193               dns_rdataset_t *nameservers, isc_boolean_t resuming)
3194 {
3195         isc_result_t result;
3196         dns_rdataset_t *rdataset, *sigrdataset;
3197         isc_sockaddr_t *peeraddr;
3198
3199         if (!resuming)
3200                 inc_stats(client, dns_nsstatscounter_recursion);
3201
3202         /*
3203          * We are about to recurse, which means that this client will
3204          * be unavailable for serving new requests for an indeterminate
3205          * amount of time.  If this client is currently responsible
3206          * for handling incoming queries, set up a new client
3207          * object to handle them while we are waiting for a
3208          * response.  There is no need to replace TCP clients
3209          * because those have already been replaced when the
3210          * connection was accepted (if allowed by the TCP quota).
3211          */
3212         if (client->recursionquota == NULL) {
3213                 result = isc_quota_attach(&ns_g_server->recursionquota,
3214                                           &client->recursionquota);
3215                 if  (result == ISC_R_SOFTQUOTA) {
3216                         static isc_stdtime_t last = 0;
3217                         isc_stdtime_t now;
3218                         isc_stdtime_get(&now);
3219                         if (now != last) {
3220                                 last = now;
3221                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3222                                               NS_LOGMODULE_QUERY,
3223                                               ISC_LOG_WARNING,
3224                                               "recursive-clients soft limit "
3225                                               "exceeded, aborting oldest query");
3226                         }
3227                         ns_client_killoldestquery(client);
3228                         result = ISC_R_SUCCESS;
3229                 } else if (result == ISC_R_QUOTA) {
3230                         static isc_stdtime_t last = 0;
3231                         isc_stdtime_t now;
3232                         isc_stdtime_get(&now);
3233                         if (now != last) {
3234                                 last = now;
3235                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3236                                               NS_LOGMODULE_QUERY,
3237                                               ISC_LOG_WARNING,
3238                                               "no more recursive clients: %s",
3239                                               isc_result_totext(result));
3240                         }
3241                         ns_client_killoldestquery(client);
3242                 }
3243                 if (result == ISC_R_SUCCESS && !client->mortal &&
3244                     (client->attributes & NS_CLIENTATTR_TCP) == 0) {
3245                         result = ns_client_replace(client);
3246                         if (result != ISC_R_SUCCESS) {
3247                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3248                                               NS_LOGMODULE_QUERY,
3249                                               ISC_LOG_WARNING,
3250                                               "ns_client_replace() failed: %s",
3251                                               isc_result_totext(result));
3252                                 isc_quota_detach(&client->recursionquota);
3253                         }
3254                 }
3255                 if (result != ISC_R_SUCCESS)
3256                         return (result);
3257                 ns_client_recursing(client);
3258         }
3259
3260         /*
3261          * Invoke the resolver.
3262          */
3263         REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
3264         REQUIRE(client->query.fetch == NULL);
3265
3266         rdataset = query_newrdataset(client);
3267         if (rdataset == NULL)
3268                 return (ISC_R_NOMEMORY);
3269         if (WANTDNSSEC(client)) {
3270                 sigrdataset = query_newrdataset(client);
3271                 if (sigrdataset == NULL) {
3272                         query_putrdataset(client, &rdataset);
3273                         return (ISC_R_NOMEMORY);
3274                 }
3275         } else
3276                 sigrdataset = NULL;
3277
3278         if (client->query.timerset == ISC_FALSE)
3279                 ns_client_settimeout(client, 60);
3280         if ((client->attributes & NS_CLIENTATTR_TCP) == 0)
3281                 peeraddr = &client->peeraddr;
3282         else
3283                 peeraddr = NULL;
3284         result = dns_resolver_createfetch2(client->view->resolver,
3285                                            client->query.qname,
3286                                            qtype, qdomain, nameservers,
3287                                            NULL, peeraddr, client->message->id,
3288                                            client->query.fetchoptions,
3289                                            client->task,
3290                                            query_resume, client,
3291                                            rdataset, sigrdataset,
3292                                            &client->query.fetch);
3293
3294         if (result == ISC_R_SUCCESS) {
3295                 /*
3296                  * Record that we're waiting for an event.  A client which
3297                  * is shutting down will not be destroyed until all the
3298                  * events have been received.
3299                  */
3300         } else {
3301                 query_putrdataset(client, &rdataset);
3302                 if (sigrdataset != NULL)
3303                         query_putrdataset(client, &sigrdataset);
3304         }
3305
3306         return (result);
3307 }
3308
3309 #define MAX_RESTARTS 16
3310
3311 #define QUERY_ERROR(r) \
3312 do { \
3313         eresult = r; \
3314         want_restart = ISC_FALSE; \
3315         line = __LINE__; \
3316 } while (0)
3317
3318 #define RECURSE_ERROR(r) \
3319 do { \
3320         if ((r) == DNS_R_DUPLICATE || (r) == DNS_R_DROP) \
3321                 QUERY_ERROR(r); \
3322         else \
3323                 QUERY_ERROR(DNS_R_SERVFAIL); \
3324 } while (0)
3325
3326 /*
3327  * Extract a network address from the RDATA of an A or AAAA
3328  * record.
3329  *
3330  * Returns:
3331  *      ISC_R_SUCCESS
3332  *      ISC_R_NOTIMPLEMENTED    The rdata is not a known address type.
3333  */
3334 static isc_result_t
3335 rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
3336         struct in_addr ina;
3337         struct in6_addr in6a;
3338
3339         switch (rdata->type) {
3340         case dns_rdatatype_a:
3341                 INSIST(rdata->length == 4);
3342                 memcpy(&ina.s_addr, rdata->data, 4);
3343                 isc_netaddr_fromin(netaddr, &ina);
3344                 return (ISC_R_SUCCESS);
3345         case dns_rdatatype_aaaa:
3346                 INSIST(rdata->length == 16);
3347                 memcpy(in6a.s6_addr, rdata->data, 16);
3348                 isc_netaddr_fromin6(netaddr, &in6a);
3349                 return (ISC_R_SUCCESS);
3350         default:
3351                 return (ISC_R_NOTIMPLEMENTED);
3352         }
3353 }
3354
3355 /*
3356  * Find the sort order of 'rdata' in the topology-like
3357  * ACL forming the second element in a 2-element top-level
3358  * sortlist statement.
3359  */
3360 static int
3361 query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
3362         isc_netaddr_t netaddr;
3363
3364         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3365                 return (INT_MAX);
3366         return (ns_sortlist_addrorder2(&netaddr, arg));
3367 }
3368
3369 /*
3370  * Find the sort order of 'rdata' in the matching element
3371  * of a 1-element top-level sortlist statement.
3372  */
3373 static int
3374 query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
3375         isc_netaddr_t netaddr;
3376
3377         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3378                 return (INT_MAX);
3379         return (ns_sortlist_addrorder1(&netaddr, arg));
3380 }
3381
3382 /*
3383  * Find the sortlist statement that applies to 'client' and set up
3384  * the sortlist info in in client->message appropriately.
3385  */
3386 static void
3387 setup_query_sortlist(ns_client_t *client) {
3388         isc_netaddr_t netaddr;
3389         dns_rdatasetorderfunc_t order = NULL;
3390         const void *order_arg = NULL;
3391
3392         isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
3393         switch (ns_sortlist_setup(client->view->sortlist,
3394                                &netaddr, &order_arg)) {
3395         case NS_SORTLISTTYPE_1ELEMENT:
3396                 order = query_sortlist_order_1element;
3397                 break;
3398         case NS_SORTLISTTYPE_2ELEMENT:
3399                 order = query_sortlist_order_2element;
3400                 break;
3401         case NS_SORTLISTTYPE_NONE:
3402                 order = NULL;
3403                 break;
3404         default:
3405                 INSIST(0);
3406                 break;
3407         }
3408         dns_message_setsortorder(client->message, order, order_arg);
3409 }
3410
3411 static void
3412 query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) {
3413         isc_buffer_t *dbuf, b;
3414         dns_name_t *fname;
3415         dns_rdataset_t *neg, *negsig;
3416         isc_result_t result = ISC_R_NOMEMORY;
3417
3418         CTRACE("query_addnoqnameproof");
3419
3420         fname = NULL;
3421         neg = NULL;
3422         negsig = NULL;
3423
3424         dbuf = query_getnamebuf(client);
3425         if (dbuf == NULL)
3426                 goto cleanup;
3427         fname = query_newname(client, dbuf, &b);
3428         neg = query_newrdataset(client);
3429         negsig = query_newrdataset(client);
3430         if (fname == NULL || neg == NULL || negsig == NULL)
3431                 goto cleanup;
3432
3433         result = dns_rdataset_getnoqname(rdataset, fname, neg, negsig);
3434         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3435
3436         query_addrrset(client, &fname, &neg, &negsig, dbuf,
3437                        DNS_SECTION_AUTHORITY);
3438
3439         if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) == 0)
3440                 goto cleanup;
3441
3442         if (fname == NULL) {
3443                 dbuf = query_getnamebuf(client);
3444                 if (dbuf == NULL)
3445                         goto cleanup;
3446                 fname = query_newname(client, dbuf, &b);
3447         }
3448         if (neg == NULL)
3449                 neg = query_newrdataset(client);
3450         else if (dns_rdataset_isassociated(neg))
3451                 dns_rdataset_disassociate(neg);
3452         if (negsig == NULL)
3453                 negsig = query_newrdataset(client);
3454         else if (dns_rdataset_isassociated(negsig))
3455                 dns_rdataset_disassociate(negsig);
3456         if (fname == NULL || neg == NULL || negsig == NULL)
3457                 goto cleanup;
3458         result = dns_rdataset_getclosest(rdataset, fname, neg, negsig);
3459         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3460
3461         query_addrrset(client, &fname, &neg, &negsig, dbuf,
3462                        DNS_SECTION_AUTHORITY);
3463
3464  cleanup:
3465         if (neg != NULL)
3466                 query_putrdataset(client, &neg);
3467         if (negsig != NULL)
3468                 query_putrdataset(client, &negsig);
3469         if (fname != NULL)
3470                 query_releasename(client, &fname);
3471 }
3472
3473 static inline void
3474 answer_in_glue(ns_client_t *client, dns_rdatatype_t qtype) {
3475         dns_name_t *name;
3476         dns_message_t *msg;
3477         dns_section_t section = DNS_SECTION_ADDITIONAL;
3478         dns_rdataset_t *rdataset = NULL;
3479
3480         msg = client->message;
3481         for (name = ISC_LIST_HEAD(msg->sections[section]);
3482              name != NULL;
3483              name = ISC_LIST_NEXT(name, link))
3484                 if (dns_name_equal(name, client->query.qname)) {
3485                         for (rdataset = ISC_LIST_HEAD(name->list);
3486                              rdataset != NULL;
3487                              rdataset = ISC_LIST_NEXT(rdataset, link))
3488                                 if (rdataset->type == qtype)
3489                                         break;
3490                         break;
3491                 }
3492         if (rdataset != NULL) {
3493                 ISC_LIST_UNLINK(msg->sections[section], name, link);
3494                 ISC_LIST_PREPEND(msg->sections[section], name, link);
3495                 ISC_LIST_UNLINK(name->list, rdataset, link);
3496                 ISC_LIST_PREPEND(name->list, rdataset, link);
3497                 rdataset->attributes |= DNS_RDATASETATTR_REQUIREDGLUE;
3498         }
3499 }
3500
3501 #define NS_NAME_INIT(A,B) \
3502          { \
3503                 DNS_NAME_MAGIC, \
3504                 A, sizeof(A), sizeof(B), \
3505                 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \
3506                 B, NULL, { (void *)-1, (void *)-1}, \
3507                 {NULL, NULL} \
3508         }
3509
3510 static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
3511 static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
3512 static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
3513
3514 static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
3515
3516 static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
3517 static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
3518 static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
3519 static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
3520 static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
3521 static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
3522 static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
3523 static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
3524 static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
3525 static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
3526 static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
3527 static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
3528 static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
3529 static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
3530 static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
3531 static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
3532
3533 static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
3534
3535 static dns_name_t rfc1918names[] = {
3536         NS_NAME_INIT(inaddr10, inaddr10_offsets),
3537         NS_NAME_INIT(inaddr16172, inaddr172_offsets),
3538         NS_NAME_INIT(inaddr17172, inaddr172_offsets),
3539         NS_NAME_INIT(inaddr18172, inaddr172_offsets),
3540         NS_NAME_INIT(inaddr19172, inaddr172_offsets),
3541         NS_NAME_INIT(inaddr20172, inaddr172_offsets),
3542         NS_NAME_INIT(inaddr21172, inaddr172_offsets),
3543         NS_NAME_INIT(inaddr22172, inaddr172_offsets),
3544         NS_NAME_INIT(inaddr23172, inaddr172_offsets),
3545         NS_NAME_INIT(inaddr24172, inaddr172_offsets),
3546         NS_NAME_INIT(inaddr25172, inaddr172_offsets),
3547         NS_NAME_INIT(inaddr26172, inaddr172_offsets),
3548         NS_NAME_INIT(inaddr27172, inaddr172_offsets),
3549         NS_NAME_INIT(inaddr28172, inaddr172_offsets),
3550         NS_NAME_INIT(inaddr29172, inaddr172_offsets),
3551         NS_NAME_INIT(inaddr30172, inaddr172_offsets),
3552         NS_NAME_INIT(inaddr31172, inaddr172_offsets),
3553         NS_NAME_INIT(inaddr168192, inaddr192_offsets)
3554 };
3555
3556
3557 static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
3558 static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org";
3559
3560 static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
3561 static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
3562
3563 static dns_name_t prisoner = NS_NAME_INIT(prisoner_data, prisoner_offsets);
3564 static dns_name_t hostmaster = NS_NAME_INIT(hostmaster_data, hostmaster_offsets);
3565
3566 static void
3567 warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
3568         unsigned int i;
3569         dns_rdata_t rdata = DNS_RDATA_INIT;
3570         dns_rdata_soa_t soa;
3571         dns_rdataset_t found;
3572         isc_result_t result;
3573
3574         for (i = 0; i < (sizeof(rfc1918names)/sizeof(*rfc1918names)); i++) {
3575                 if (dns_name_issubdomain(fname, &rfc1918names[i])) {
3576                         dns_rdataset_init(&found);
3577                         result = dns_ncache_getrdataset(rdataset,
3578                                                         &rfc1918names[i],
3579                                                         dns_rdatatype_soa,
3580                                                         &found);
3581                         if (result != ISC_R_SUCCESS)
3582                                 return;
3583
3584                         result = dns_rdataset_first(&found);
3585                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3586                         dns_rdataset_current(&found, &rdata);
3587                         result = dns_rdata_tostruct(&rdata, &soa, NULL);
3588                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3589                         if (dns_name_equal(&soa.origin, &prisoner) &&
3590                             dns_name_equal(&soa.contact, &hostmaster)) {
3591                                 char buf[DNS_NAME_FORMATSIZE];
3592                                 dns_name_format(fname, buf, sizeof(buf));
3593                                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3594                                               NS_LOGMODULE_QUERY,
3595                                               ISC_LOG_WARNING,
3596                                               "RFC 1918 response from "
3597                                               "Internet for %s", buf);
3598                         }
3599                         dns_rdataset_disassociate(&found);
3600                         return;
3601                 }
3602         }
3603 }
3604
3605 static void
3606 query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
3607                        dns_dbversion_t *version, ns_client_t *client,
3608                        dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
3609                        dns_name_t *fname, isc_boolean_t exact,
3610                        dns_name_t *found)
3611 {
3612         unsigned char salt[256];
3613         size_t salt_length;
3614         isc_uint16_t iterations;
3615         isc_result_t result;
3616         unsigned int dboptions;
3617         dns_fixedname_t fixed;
3618         dns_hash_t hash;
3619         dns_name_t name;
3620         int order;
3621         unsigned int count;
3622         dns_rdata_nsec3_t nsec3;
3623         dns_rdata_t rdata = DNS_RDATA_INIT;
3624         isc_boolean_t optout;
3625
3626         salt_length = sizeof(salt);
3627         result = dns_db_getnsec3parameters(db, version, &hash, NULL,
3628                                            &iterations, salt, &salt_length);
3629         if (result != ISC_R_SUCCESS)
3630                 return;
3631
3632         dns_name_init(&name, NULL);
3633         dns_name_clone(qname, &name);
3634
3635         /*
3636          * Map unknown algorithm to known value.
3637          */
3638         if (hash == DNS_NSEC3_UNKNOWNALG)
3639                 hash = 1;
3640
3641  again:
3642         dns_fixedname_init(&fixed);
3643         result = dns_nsec3_hashname(&fixed, NULL, NULL, &name,
3644                                     dns_db_origin(db), hash,
3645                                     iterations, salt, salt_length);
3646         if (result != ISC_R_SUCCESS)
3647                 return;
3648
3649         dboptions = client->query.dboptions | DNS_DBFIND_FORCENSEC3;
3650         result = dns_db_find(db, dns_fixedname_name(&fixed), version,
3651                              dns_rdatatype_nsec3, dboptions, client->now,
3652                              NULL, fname, rdataset, sigrdataset);
3653
3654         if (result == DNS_R_NXDOMAIN) {
3655                 if (!dns_rdataset_isassociated(rdataset)) {
3656                         return;
3657                 }
3658                 result = dns_rdataset_first(rdataset);
3659                 INSIST(result == ISC_R_SUCCESS);
3660                 dns_rdataset_current(rdataset, &rdata);
3661                 dns_rdata_tostruct(&rdata, &nsec3, NULL);
3662                 dns_rdata_reset(&rdata);
3663                 optout = ISC_TF((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
3664                 if (found != NULL && optout &&
3665                     dns_name_fullcompare(&name, dns_db_origin(db), &order,
3666                                          &count) == dns_namereln_subdomain) {
3667                         dns_rdataset_disassociate(rdataset);
3668                         if (dns_rdataset_isassociated(sigrdataset))
3669                                 dns_rdataset_disassociate(sigrdataset);
3670                         count = dns_name_countlabels(&name) - 1;
3671                         dns_name_getlabelsequence(&name, 1, count, &name);
3672                         ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
3673                                       NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3),
3674                                       "looking for closest provable encloser");
3675                         goto again;
3676                 }
3677                 if (exact)
3678                         ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
3679                                       NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
3680                                       "expected a exact match NSEC3, got "
3681                                       "a covering record");
3682
3683         } else if (result != ISC_R_SUCCESS) {
3684                 return;
3685         } else if (!exact)
3686                 ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
3687                               NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
3688                               "expected covering NSEC3, got an exact match");
3689         if (found != NULL)
3690                 dns_name_copy(&name, found, NULL);
3691         return;
3692 }
3693
3694 /*
3695  * Do the bulk of query processing for the current query of 'client'.
3696  * If 'event' is non-NULL, we are returning from recursion and 'qtype'
3697  * is ignored.  Otherwise, 'qtype' is the query type.
3698  */
3699 static isc_result_t
3700 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
3701 {
3702         dns_db_t *db, *zdb;
3703         dns_dbnode_t *node;
3704         dns_rdatatype_t type;
3705         dns_name_t *fname, *zfname, *tname, *prefix;
3706         dns_rdataset_t *rdataset, *trdataset;
3707         dns_rdataset_t *sigrdataset, *zrdataset, *zsigrdataset;
3708         dns_rdataset_t **sigrdatasetp;
3709         dns_rdata_t rdata = DNS_RDATA_INIT;
3710         dns_rdatasetiter_t *rdsiter;
3711         isc_boolean_t want_restart, authoritative, is_zone, need_wildcardproof;
3712         unsigned int n, nlabels;
3713         dns_namereln_t namereln;
3714         int order;
3715         isc_buffer_t *dbuf;
3716         isc_buffer_t b;
3717         isc_result_t result, eresult;
3718         dns_fixedname_t fixed;
3719         dns_fixedname_t wildcardname;
3720         dns_dbversion_t *version, *zversion;
3721         dns_zone_t *zone;
3722         dns_rdata_cname_t cname;
3723         dns_rdata_dname_t dname;
3724         unsigned int options;
3725         isc_boolean_t empty_wild;
3726         dns_rdataset_t *noqname;
3727         isc_boolean_t resuming;
3728         int line = -1;
3729
3730         CTRACE("query_find");
3731
3732         /*
3733          * One-time initialization.
3734          *
3735          * It's especially important to initialize anything that the cleanup
3736          * code might cleanup.
3737          */
3738
3739         eresult = ISC_R_SUCCESS;
3740         fname = NULL;
3741         zfname = NULL;
3742         rdataset = NULL;
3743         zrdataset = NULL;
3744         sigrdataset = NULL;
3745         zsigrdataset = NULL;
3746         zversion = NULL;
3747         node = NULL;
3748         db = NULL;
3749         zdb = NULL;
3750         version = NULL;
3751         zone = NULL;
3752         need_wildcardproof = ISC_FALSE;
3753         empty_wild = ISC_FALSE;
3754         options = 0;
3755         resuming = ISC_FALSE;
3756         is_zone = ISC_FALSE;
3757
3758         if (event != NULL) {
3759                 /*
3760                  * We're returning from recursion.  Restore the query context
3761                  * and resume.
3762                  */
3763
3764                 want_restart = ISC_FALSE;
3765                 authoritative = ISC_FALSE;
3766
3767                 qtype = event->qtype;
3768                 if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3769                         type = dns_rdatatype_any;
3770                 else
3771                         type = qtype;
3772                 db = event->db;
3773                 node = event->node;
3774                 rdataset = event->rdataset;
3775                 sigrdataset = event->sigrdataset;
3776
3777                 /*
3778                  * We'll need some resources...
3779                  */
3780                 dbuf = query_getnamebuf(client);
3781                 if (dbuf == NULL) {
3782                         QUERY_ERROR(DNS_R_SERVFAIL);
3783                         goto cleanup;
3784                 }
3785                 fname = query_newname(client, dbuf, &b);
3786                 if (fname == NULL) {
3787                         QUERY_ERROR(DNS_R_SERVFAIL);
3788                         goto cleanup;
3789                 }
3790                 tname = dns_fixedname_name(&event->foundname);
3791                 result = dns_name_copy(tname, fname, NULL);
3792                 if (result != ISC_R_SUCCESS) {
3793                         QUERY_ERROR(DNS_R_SERVFAIL);
3794                         goto cleanup;
3795                 }
3796
3797                 result = event->result;
3798                 resuming = ISC_TRUE;
3799
3800                 goto resume;
3801         }
3802
3803         /*
3804          * Not returning from recursion.
3805          */
3806
3807         /*
3808          * If it's a SIG query, we'll iterate the node.
3809          */
3810         if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3811                 type = dns_rdatatype_any;
3812         else
3813                 type = qtype;
3814
3815  restart:
3816         CTRACE("query_find: restart");
3817         want_restart = ISC_FALSE;
3818         authoritative = ISC_FALSE;
3819         version = NULL;
3820         need_wildcardproof = ISC_FALSE;
3821
3822         if (client->view->checknames &&
3823             !dns_rdata_checkowner(client->query.qname,
3824                                   client->message->rdclass,
3825                                   qtype, ISC_FALSE)) {
3826                 char namebuf[DNS_NAME_FORMATSIZE];
3827                 char typename[DNS_RDATATYPE_FORMATSIZE];
3828                 char classname[DNS_RDATACLASS_FORMATSIZE];
3829
3830                 dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
3831                 dns_rdatatype_format(qtype, typename, sizeof(typename));
3832                 dns_rdataclass_format(client->message->rdclass, classname,
3833                                       sizeof(classname));
3834                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3835                               NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
3836                               "check-names failure %s/%s/%s", namebuf,
3837                               typename, classname);
3838                 QUERY_ERROR(DNS_R_REFUSED);
3839                 goto cleanup;
3840         }
3841
3842         /*
3843          * First we must find the right database.
3844          */
3845         options &= DNS_GETDB_NOLOG; /* Preserve DNS_GETDB_NOLOG. */
3846         if (dns_rdatatype_atparent(qtype) &&
3847             !dns_name_equal(client->query.qname, dns_rootname))
3848                 options |= DNS_GETDB_NOEXACT;
3849         result = query_getdb(client, client->query.qname, qtype, options,
3850                              &zone, &db, &version, &is_zone);
3851         if ((result != ISC_R_SUCCESS || !is_zone) && !RECURSIONOK(client) &&
3852             (options & DNS_GETDB_NOEXACT) != 0 && qtype == dns_rdatatype_ds) {
3853                 /*
3854                  * Look to see if we are authoritative for the
3855                  * child zone if the query type is DS.
3856                  */
3857                 dns_db_t *tdb = NULL;
3858                 dns_zone_t *tzone = NULL;
3859                 dns_dbversion_t *tversion = NULL;
3860                 isc_result_t tresult;
3861
3862                 tresult = query_getzonedb(client, client->query.qname, qtype,
3863                                          DNS_GETDB_PARTIAL, &tzone, &tdb,
3864                                          &tversion);
3865                 if (tresult == ISC_R_SUCCESS) {
3866                         options &= ~DNS_GETDB_NOEXACT;
3867                         query_putrdataset(client, &rdataset);
3868                         if (db != NULL)
3869                                 dns_db_detach(&db);
3870                         if (zone != NULL)
3871                                 dns_zone_detach(&zone);
3872                         version = tversion;
3873                         db = tdb;
3874                         zone = tzone;
3875                         is_zone = ISC_TRUE;
3876                         result = ISC_R_SUCCESS;
3877                 } else {
3878                         if (tdb != NULL)
3879                                 dns_db_detach(&tdb);
3880                         if (tzone != NULL)
3881                                 dns_zone_detach(&tzone);
3882                 }
3883         }
3884         if (result != ISC_R_SUCCESS) {
3885                 if (result == DNS_R_REFUSED) {
3886                         if (WANTRECURSION(client)) {
3887                                 inc_stats(client,
3888                                           dns_nsstatscounter_recurserej);
3889                         } else
3890                                 inc_stats(client, dns_nsstatscounter_authrej);
3891                         if (!PARTIALANSWER(client))
3892                                 QUERY_ERROR(DNS_R_REFUSED);
3893                 } else
3894                         QUERY_ERROR(DNS_R_SERVFAIL);
3895                 goto cleanup;
3896         }
3897
3898         if (is_zone)
3899                 authoritative = ISC_TRUE;
3900
3901         if (event == NULL && client->query.restarts == 0) {
3902                 if (is_zone) {
3903 #ifdef DLZ
3904                         if (zone != NULL) {
3905                                 /*
3906                                  * if is_zone = true, zone = NULL then this is
3907                                  * a DLZ zone.  Don't attempt to attach zone.
3908                                  */
3909 #endif
3910                                 dns_zone_attach(zone, &client->query.authzone);
3911 #ifdef DLZ
3912                         }
3913 #endif
3914                         dns_db_attach(db, &client->query.authdb);
3915                 }
3916                 client->query.authdbset = ISC_TRUE;
3917         }
3918
3919  db_find:
3920         CTRACE("query_find: db_find");
3921         /*
3922          * We'll need some resources...
3923          */
3924         dbuf = query_getnamebuf(client);
3925         if (dbuf == NULL) {
3926                 QUERY_ERROR(DNS_R_SERVFAIL);
3927                 goto cleanup;
3928         }
3929         fname = query_newname(client, dbuf, &b);
3930         rdataset = query_newrdataset(client);
3931         if (fname == NULL || rdataset == NULL) {
3932                 QUERY_ERROR(DNS_R_SERVFAIL);
3933                 goto cleanup;
3934         }
3935         if (WANTDNSSEC(client) && (!is_zone || dns_db_issecure(db))) {
3936                 sigrdataset = query_newrdataset(client);
3937                 if (sigrdataset == NULL) {
3938                         QUERY_ERROR(DNS_R_SERVFAIL);
3939                         goto cleanup;
3940                 }
3941         }
3942
3943         /*
3944          * Now look for an answer in the database.
3945          */
3946         result = dns_db_find(db, client->query.qname, version, type,
3947                              client->query.dboptions, client->now,
3948                              &node, fname, rdataset, sigrdataset);
3949
3950  resume:
3951         CTRACE("query_find: resume");
3952         switch (result) {
3953         case ISC_R_SUCCESS:
3954                 /*
3955                  * This case is handled in the main line below.
3956                  */
3957                 break;
3958         case DNS_R_GLUE:
3959         case DNS_R_ZONECUT:
3960                 /*
3961                  * These cases are handled in the main line below.
3962                  */
3963                 INSIST(is_zone);
3964                 authoritative = ISC_FALSE;
3965                 break;
3966         case ISC_R_NOTFOUND:
3967                 /*
3968                  * The cache doesn't even have the root NS.  Get them from
3969                  * the hints DB.
3970                  */
3971                 INSIST(!is_zone);
3972                 if (db != NULL)
3973                         dns_db_detach(&db);
3974
3975                 if (client->view->hints == NULL) {
3976                         /* We have no hints. */
3977                         result = ISC_R_FAILURE;
3978                 } else {
3979                         dns_db_attach(client->view->hints, &db);
3980                         result = dns_db_find(db, dns_rootname,
3981                                              NULL, dns_rdatatype_ns,
3982                                              0, client->now, &node, fname,
3983                                              rdataset, sigrdataset);
3984                 }
3985                 if (result != ISC_R_SUCCESS) {
3986                         /*
3987                          * Nonsensical root hints may require cleanup.
3988                          */
3989                         if (dns_rdataset_isassociated(rdataset))
3990                                 dns_rdataset_disassociate(rdataset);
3991                         if (sigrdataset != NULL &&
3992                             dns_rdataset_isassociated(sigrdataset))
3993                                 dns_rdataset_disassociate(sigrdataset);
3994                         if (node != NULL)
3995                                 dns_db_detachnode(db, &node);
3996
3997                         /*
3998                          * We don't have any root server hints, but
3999                          * we may have working forwarders, so try to
4000                          * recurse anyway.
4001                          */
4002                         if (RECURSIONOK(client)) {
4003                                 result = query_recurse(client, qtype,
4004                                                        NULL, NULL, resuming);
4005                                 if (result == ISC_R_SUCCESS)
4006                                         client->query.attributes |=
4007                                                 NS_QUERYATTR_RECURSING;
4008                                 else
4009                                         RECURSE_ERROR(result);
4010                                 goto cleanup;
4011                         } else {
4012                                 /* Unable to give root server referral. */
4013                                 QUERY_ERROR(DNS_R_SERVFAIL);
4014                                 goto cleanup;
4015                         }
4016                 }
4017                 /*
4018                  * XXXRTH  We should trigger root server priming here.
4019                  */
4020                 /* FALLTHROUGH */
4021         case DNS_R_DELEGATION:
4022                 authoritative = ISC_FALSE;
4023                 if (is_zone) {
4024                         /*
4025                          * Look to see if we are authoritative for the
4026                          * child zone if the query type is DS.
4027                          */
4028                         if (!RECURSIONOK(client) &&
4029                             (options & DNS_GETDB_NOEXACT) != 0 &&
4030                             qtype == dns_rdatatype_ds) {
4031                                 dns_db_t *tdb = NULL;
4032                                 dns_zone_t *tzone = NULL;
4033                                 dns_dbversion_t *tversion = NULL;
4034                                 result = query_getzonedb(client,
4035                                                          client->query.qname,
4036                                                          qtype,
4037                                                          DNS_GETDB_PARTIAL,
4038                                                          &tzone, &tdb,
4039                                                          &tversion);
4040                                 if (result == ISC_R_SUCCESS) {
4041                                         options &= ~DNS_GETDB_NOEXACT;
4042                                         query_putrdataset(client, &rdataset);
4043                                         if (sigrdataset != NULL)
4044                                                 query_putrdataset(client,
4045                                                                   &sigrdataset);
4046                                         if (fname != NULL)
4047                                                 query_releasename(client,
4048                                                                   &fname);
4049                                         if (node != NULL)
4050                                                 dns_db_detachnode(db, &node);
4051                                         if (db != NULL)
4052                                                 dns_db_detach(&db);
4053                                         if (zone != NULL)
4054                                                 dns_zone_detach(&zone);
4055                                         version = tversion;
4056                                         db = tdb;
4057                                         zone = tzone;
4058                                         authoritative = ISC_TRUE;
4059                                         goto db_find;
4060                                 }
4061                                 if (tdb != NULL)
4062                                         dns_db_detach(&tdb);
4063                                 if (tzone != NULL)
4064                                         dns_zone_detach(&tzone);
4065                         }
4066                         /*
4067                          * We're authoritative for an ancestor of QNAME.
4068                          */
4069                         if (!USECACHE(client) || !RECURSIONOK(client)) {
4070                                 dns_fixedname_t fixed;
4071
4072                                 dns_fixedname_init(&fixed);
4073                                 dns_name_copy(fname,
4074                                               dns_fixedname_name(&fixed), NULL);
4075
4076                                 /*
4077                                  * If we don't have a cache, this is the best
4078                                  * answer.
4079                                  *
4080                                  * If the client is making a nonrecursive
4081                                  * query we always give out the authoritative
4082                                  * delegation.  This way even if we get
4083                                  * junk in our cache, we won't fail in our
4084                                  * role as the delegating authority if another
4085                                  * nameserver asks us about a delegated
4086                                  * subzone.
4087                                  *
4088                                  * We enable the retrieval of glue for this
4089                                  * database by setting client->query.gluedb.
4090                                  */
4091                                 client->query.gluedb = db;
4092                                 client->query.isreferral = ISC_TRUE;
4093                                 /*
4094                                  * We must ensure NOADDITIONAL is off,
4095                                  * because the generation of
4096                                  * additional data is required in
4097                                  * delegations.
4098                                  */
4099                                 client->query.attributes &=
4100                                         ~NS_QUERYATTR_NOADDITIONAL;
4101                                 if (sigrdataset != NULL)
4102                                         sigrdatasetp = &sigrdataset;
4103                                 else
4104                                         sigrdatasetp = NULL;
4105                                 query_addrrset(client, &fname,
4106                                                &rdataset, sigrdatasetp,
4107                                                dbuf, DNS_SECTION_AUTHORITY);
4108                                 client->query.gluedb = NULL;
4109                                 if (WANTDNSSEC(client))
4110                                         query_addds(client, db, node, version,
4111                                                    dns_fixedname_name(&fixed));
4112                         } else {
4113                                 /*
4114                                  * We might have a better answer or delegation
4115                                  * in the cache.  We'll remember the current
4116                                  * values of fname, rdataset, and sigrdataset.
4117                                  * We'll then go looking for QNAME in the
4118                                  * cache.  If we find something better, we'll
4119                                  * use it instead.
4120                                  */
4121                                 query_keepname(client, fname, dbuf);
4122                                 zdb = db;
4123                                 zfname = fname;
4124                                 fname = NULL;
4125                                 zrdataset = rdataset;
4126                                 rdataset = NULL;
4127                                 zsigrdataset = sigrdataset;
4128                                 sigrdataset = NULL;
4129                                 dns_db_detachnode(db, &node);
4130                                 zversion = version;
4131                                 version = NULL;
4132                                 db = NULL;
4133                                 dns_db_attach(client->view->cachedb, &db);
4134                                 is_zone = ISC_FALSE;
4135                                 goto db_find;
4136                         }
4137                 } else {
4138                         if (zfname != NULL &&
4139                             !dns_name_issubdomain(fname, zfname)) {
4140                                 /*
4141                                  * We've already got a delegation from
4142                                  * authoritative data, and it is better
4143                                  * than what we found in the cache.  Use
4144                                  * it instead of the cache delegation.
4145                                  */
4146                                 query_releasename(client, &fname);
4147                                 fname = zfname;
4148                                 zfname = NULL;
4149                                 /*
4150                                  * We've already done query_keepname() on
4151                                  * zfname, so we must set dbuf to NULL to
4152                                  * prevent query_addrrset() from trying to
4153                                  * call query_keepname() again.
4154                                  */
4155                                 dbuf = NULL;
4156                                 query_putrdataset(client, &rdataset);
4157                                 if (sigrdataset != NULL)
4158                                         query_putrdataset(client,
4159                                                           &sigrdataset);
4160                                 rdataset = zrdataset;
4161                                 zrdataset = NULL;
4162                                 sigrdataset = zsigrdataset;
4163                                 zsigrdataset = NULL;
4164                                 version = zversion;
4165                                 zversion = NULL;
4166                                 /*
4167                                  * We don't clean up zdb here because we
4168                                  * may still need it.  It will get cleaned
4169                                  * up by the main cleanup code.
4170                                  */
4171                         }
4172
4173                         if (RECURSIONOK(client)) {
4174                                 /*
4175                                  * Recurse!
4176                                  */
4177                                 if (dns_rdatatype_atparent(type))
4178                                         result = query_recurse(client, qtype,
4179                                                                NULL, NULL,
4180                                                                resuming);
4181                                 else
4182                                         result = query_recurse(client, qtype,
4183                                                                fname, rdataset,
4184                                                                resuming);
4185                                 if (result == ISC_R_SUCCESS)
4186                                         client->query.attributes |=
4187                                                 NS_QUERYATTR_RECURSING;
4188                                 else
4189                                         RECURSE_ERROR(result);
4190                         } else {
4191                                 dns_fixedname_t fixed;
4192
4193                                 dns_fixedname_init(&fixed);
4194                                 dns_name_copy(fname,
4195                                               dns_fixedname_name(&fixed), NULL);
4196                                 /*
4197                                  * This is the best answer.
4198                                  */
4199                                 client->query.attributes |=
4200                                         NS_QUERYATTR_CACHEGLUEOK;
4201                                 client->query.gluedb = zdb;
4202                                 client->query.isreferral = ISC_TRUE;
4203                                 /*
4204                                  * We must ensure NOADDITIONAL is off,
4205                                  * because the generation of
4206                                  * additional data is required in
4207                                  * delegations.
4208                                  */
4209                                 client->query.attributes &=
4210                                         ~NS_QUERYATTR_NOADDITIONAL;
4211                                 if (sigrdataset != NULL)
4212                                         sigrdatasetp = &sigrdataset;
4213                                 else
4214                                         sigrdatasetp = NULL;
4215                                 query_addrrset(client, &fname,
4216                                                &rdataset, sigrdatasetp,
4217                                                dbuf, DNS_SECTION_AUTHORITY);
4218                                 client->query.gluedb = NULL;
4219                                 client->query.attributes &=
4220                                         ~NS_QUERYATTR_CACHEGLUEOK;
4221                                 if (WANTDNSSEC(client))
4222                                         query_addds(client, db, node, version,
4223                                                    dns_fixedname_name(&fixed));
4224                         }
4225                 }
4226                 goto cleanup;
4227         case DNS_R_EMPTYNAME:
4228                 result = DNS_R_NXRRSET;
4229                 /* FALLTHROUGH */
4230         case DNS_R_NXRRSET:
4231                 INSIST(is_zone);
4232                 /*
4233                  * Look for a NSEC3 record if we don't have a NSEC record.
4234                  */
4235                 if (!dns_rdataset_isassociated(rdataset) &&
4236                      WANTDNSSEC(client)) {
4237                         if ((fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
4238                                 dns_name_t *found;
4239                                 dns_name_t *qname;
4240
4241                                 dns_fixedname_init(&fixed);
4242                                 found = dns_fixedname_name(&fixed);
4243                                 qname = client->query.qname;
4244
4245                                 query_findclosestnsec3(qname, db, version,
4246                                                        client, rdataset,
4247                                                        sigrdataset, fname,
4248                                                        ISC_TRUE, found);
4249                                 /*
4250                                  * Did we find the closest provable encloser
4251                                  * instead? If so add the nearest to the
4252                                  * closest provable encloser.
4253                                  */
4254                                 if (found &&
4255                                     dns_rdataset_isassociated(rdataset) &&
4256                                     !dns_name_equal(qname, found))
4257                                 {
4258                                         unsigned int count;
4259                                         unsigned int skip;
4260
4261                                         /*
4262                                          * Add the closest provable encloser.
4263                                          */
4264                                         query_addrrset(client, &fname,
4265                                                        &rdataset, &sigrdataset,
4266                                                        dbuf,
4267                                                        DNS_SECTION_AUTHORITY);
4268
4269                                         count = dns_name_countlabels(found)
4270                                                          + 1;
4271                                         skip = dns_name_countlabels(qname) -
4272                                                          count;
4273                                         dns_name_getlabelsequence(qname, skip,
4274                                                                   count,
4275                                                                   found);
4276
4277                                         fixfname(client, &fname, &dbuf, &b);
4278                                         fixrdataset(client, &rdataset);
4279                                         fixrdataset(client, &sigrdataset);
4280                                         if (fname == NULL ||
4281                                             rdataset == NULL ||
4282                                             sigrdataset == NULL) {
4283                                                 QUERY_ERROR(DNS_R_SERVFAIL);
4284                                                 goto cleanup;
4285                                         }
4286                                         /*
4287                                          * 'nearest' doesn't exist so
4288                                          * 'exist' is set to ISC_FALSE.
4289                                          */
4290                                         query_findclosestnsec3(found, db,
4291                                                                version,
4292                                                                client,
4293                                                                rdataset,
4294                                                                sigrdataset,
4295                                                                fname,
4296                                                                ISC_FALSE,
4297                                                                NULL);
4298                                 }
4299                         } else {
4300                                 query_releasename(client, &fname);
4301                                 query_addwildcardproof(client, db, version,
4302                                                        client->query.qname,
4303                                                        ISC_FALSE);
4304                         }
4305                 }
4306                 if (dns_rdataset_isassociated(rdataset)) {
4307                         /*
4308                          * If we've got a NSEC record, we need to save the
4309                          * name now because we're going call query_addsoa()
4310                          * below, and it needs to use the name buffer.
4311                          */
4312                         query_keepname(client, fname, dbuf);
4313                 } else if (fname != NULL) {
4314                         /*
4315                          * We're not going to use fname, and need to release
4316                          * our hold on the name buffer so query_addsoa()
4317                          * may use it.
4318                          */
4319                         query_releasename(client, &fname);
4320                 }
4321                 /*
4322                  * Add SOA.
4323                  */
4324                 result = query_addsoa(client, db, version, ISC_FALSE);
4325                 if (result != ISC_R_SUCCESS) {
4326                         QUERY_ERROR(result);
4327                         goto cleanup;
4328                 }
4329                 /*
4330                  * Add NSEC record if we found one.
4331                  */
4332                 if (WANTDNSSEC(client)) {
4333                         if (dns_rdataset_isassociated(rdataset))
4334                                 query_addnxrrsetnsec(client, db, version,
4335                                                      &fname, &rdataset,
4336                                                      &sigrdataset);
4337                 }
4338                 goto cleanup;
4339
4340         case DNS_R_EMPTYWILD:
4341                 empty_wild = ISC_TRUE;
4342                 /* FALLTHROUGH */
4343
4344         case DNS_R_NXDOMAIN:
4345                 INSIST(is_zone);
4346                 if (dns_rdataset_isassociated(rdataset)) {
4347                         /*
4348                          * If we've got a NSEC record, we need to save the
4349                          * name now because we're going call query_addsoa()
4350                          * below, and it needs to use the name buffer.
4351                          */
4352                         query_keepname(client, fname, dbuf);
4353                 } else if (fname != NULL) {
4354                         /*
4355                          * We're not going to use fname, and need to release
4356                          * our hold on the name buffer so query_addsoa()
4357                          * may use it.
4358                          */
4359                         query_releasename(client, &fname);
4360                 }
4361                 /*
4362                  * Add SOA.  If the query was for a SOA record force the
4363                  * ttl to zero so that it is possible for clients to find
4364                  * the containing zone of an arbitrary name with a stub
4365                  * resolver and not have it cached.
4366                  */
4367                 if (qtype == dns_rdatatype_soa &&
4368 #ifdef DLZ
4369                     zone != NULL &&
4370 #endif
4371                     dns_zone_getzeronosoattl(zone))
4372                         result = query_addsoa(client, db, version, ISC_TRUE);
4373                 else
4374                         result = query_addsoa(client, db, version, ISC_FALSE);
4375                 if (result != ISC_R_SUCCESS) {
4376                         QUERY_ERROR(result);
4377                         goto cleanup;
4378                 }
4379
4380                 if (WANTDNSSEC(client)) {
4381                         /*
4382                          * Add NSEC record if we found one.
4383                          */
4384                         if (dns_rdataset_isassociated(rdataset))
4385                                 query_addrrset(client, &fname, &rdataset,
4386                                                &sigrdataset,
4387                                                NULL, DNS_SECTION_AUTHORITY);
4388                         query_addwildcardproof(client, db, version,
4389                                                client->query.qname, ISC_FALSE);
4390                 }
4391
4392                 /*
4393                  * Set message rcode.
4394                  */
4395                 if (empty_wild)
4396                         client->message->rcode = dns_rcode_noerror;
4397                 else
4398                         client->message->rcode = dns_rcode_nxdomain;
4399                 goto cleanup;
4400
4401         case DNS_R_NCACHENXDOMAIN:
4402         case DNS_R_NCACHENXRRSET:
4403                 INSIST(!is_zone);
4404                 authoritative = ISC_FALSE;
4405                 /*
4406                  * Set message rcode, if required.
4407                  */
4408                 if (result == DNS_R_NCACHENXDOMAIN)
4409                         client->message->rcode = dns_rcode_nxdomain;
4410                 /*
4411                  * Look for RFC 1918 leakage from Internet.
4412                  */
4413                 if (result == DNS_R_NCACHENXDOMAIN &&
4414                     qtype == dns_rdatatype_ptr &&
4415                     client->message->rdclass == dns_rdataclass_in &&
4416                     dns_name_countlabels(fname) == 7)
4417                         warn_rfc1918(client, fname, rdataset);
4418                 /*
4419                  * We don't call query_addrrset() because we don't need any
4420                  * of its extra features (and things would probably break!).
4421                  */
4422                 query_keepname(client, fname, dbuf);
4423                 dns_message_addname(client->message, fname,
4424                                     DNS_SECTION_AUTHORITY);
4425                 ISC_LIST_APPEND(fname->list, rdataset, link);
4426                 fname = NULL;
4427                 rdataset = NULL;
4428                 goto cleanup;
4429
4430         case DNS_R_CNAME:
4431                 /*
4432                  * Keep a copy of the rdataset.  We have to do this because
4433                  * query_addrrset may clear 'rdataset' (to prevent the
4434                  * cleanup code from cleaning it up).
4435                  */
4436                 trdataset = rdataset;
4437                 /*
4438                  * Add the CNAME to the answer section.
4439                  */
4440                 if (sigrdataset != NULL)
4441                         sigrdatasetp = &sigrdataset;
4442                 else
4443                         sigrdatasetp = NULL;
4444                 if (WANTDNSSEC(client) &&
4445                     (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4446                 {
4447                         dns_fixedname_init(&wildcardname);
4448                         dns_name_copy(fname, dns_fixedname_name(&wildcardname),
4449                                       NULL);
4450                         need_wildcardproof = ISC_TRUE;
4451                 }
4452                 if (NOQNAME(rdataset) && WANTDNSSEC(client))
4453                         noqname = rdataset;
4454                 else
4455                         noqname = NULL;
4456                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4457                                DNS_SECTION_ANSWER);
4458                 if (noqname != NULL)
4459                         query_addnoqnameproof(client, noqname);
4460                 /*
4461                  * We set the PARTIALANSWER attribute so that if anything goes
4462                  * wrong later on, we'll return what we've got so far.
4463                  */
4464                 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
4465                 /*
4466                  * Reset qname to be the target name of the CNAME and restart
4467                  * the query.
4468                  */
4469                 tname = NULL;
4470                 result = dns_message_gettempname(client->message, &tname);
4471                 if (result != ISC_R_SUCCESS)
4472                         goto cleanup;
4473                 result = dns_rdataset_first(trdataset);
4474                 if (result != ISC_R_SUCCESS) {
4475                         dns_message_puttempname(client->message, &tname);
4476                         goto cleanup;
4477                 }
4478                 dns_rdataset_current(trdataset, &rdata);
4479                 result = dns_rdata_tostruct(&rdata, &cname, NULL);
4480                 dns_rdata_reset(&rdata);
4481                 if (result != ISC_R_SUCCESS) {
4482                         dns_message_puttempname(client->message, &tname);
4483                         goto cleanup;
4484                 }
4485                 dns_name_init(tname, NULL);
4486                 result = dns_name_dup(&cname.cname, client->mctx, tname);
4487                 if (result != ISC_R_SUCCESS) {
4488                         dns_message_puttempname(client->message, &tname);
4489                         dns_rdata_freestruct(&cname);
4490                         goto cleanup;
4491                 }
4492                 dns_rdata_freestruct(&cname);
4493                 ns_client_qnamereplace(client, tname);
4494                 want_restart = ISC_TRUE;
4495                 if (!WANTRECURSION(client))
4496                         options |= DNS_GETDB_NOLOG;
4497                 goto addauth;
4498         case DNS_R_DNAME:
4499                 /*
4500                  * Compare the current qname to the found name.  We need
4501                  * to know how many labels and bits are in common because
4502                  * we're going to have to split qname later on.
4503                  */
4504                 namereln = dns_name_fullcompare(client->query.qname, fname,
4505                                                 &order, &nlabels);
4506                 INSIST(namereln == dns_namereln_subdomain);
4507                 /*
4508                  * Keep a copy of the rdataset.  We have to do this because
4509                  * query_addrrset may clear 'rdataset' (to prevent the
4510                  * cleanup code from cleaning it up).
4511                  */
4512                 trdataset = rdataset;
4513                 /*
4514                  * Add the DNAME to the answer section.
4515                  */
4516                 if (sigrdataset != NULL)
4517                         sigrdatasetp = &sigrdataset;
4518                 else
4519                         sigrdatasetp = NULL;
4520                 if (WANTDNSSEC(client) &&
4521                     (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4522                 {
4523                         dns_fixedname_init(&wildcardname);
4524                         dns_name_copy(fname, dns_fixedname_name(&wildcardname),
4525                                       NULL);
4526                         need_wildcardproof = ISC_TRUE;
4527                 }
4528                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4529                                DNS_SECTION_ANSWER);
4530                 /*
4531                  * We set the PARTIALANSWER attribute so that if anything goes
4532                  * wrong later on, we'll return what we've got so far.
4533                  */
4534                 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
4535                 /*
4536                  * Get the target name of the DNAME.
4537                  */
4538                 tname = NULL;
4539                 result = dns_message_gettempname(client->message, &tname);
4540                 if (result != ISC_R_SUCCESS)
4541                         goto cleanup;
4542                 result = dns_rdataset_first(trdataset);
4543                 if (result != ISC_R_SUCCESS) {
4544                         dns_message_puttempname(client->message, &tname);
4545                         goto cleanup;
4546                 }
4547                 dns_rdataset_current(trdataset, &rdata);
4548                 result = dns_rdata_tostruct(&rdata, &dname, NULL);
4549                 dns_rdata_reset(&rdata);
4550                 if (result != ISC_R_SUCCESS) {
4551                         dns_message_puttempname(client->message, &tname);
4552                         goto cleanup;
4553                 }
4554                 dns_name_init(tname, NULL);
4555                 dns_name_clone(&dname.dname, tname);
4556                 dns_rdata_freestruct(&dname);
4557                 /*
4558                  * Construct the new qname.
4559                  */
4560                 dns_fixedname_init(&fixed);
4561                 prefix = dns_fixedname_name(&fixed);
4562                 dns_name_split(client->query.qname, nlabels, prefix, NULL);
4563                 INSIST(fname == NULL);
4564                 dbuf = query_getnamebuf(client);
4565                 if (dbuf == NULL) {
4566                         dns_message_puttempname(client->message, &tname);
4567                         goto cleanup;
4568                 }
4569                 fname = query_newname(client, dbuf, &b);
4570                 if (fname == NULL) {
4571                         dns_message_puttempname(client->message, &tname);
4572                         goto cleanup;
4573                 }
4574                 result = dns_name_concatenate(prefix, tname, fname, NULL);
4575                 if (result != ISC_R_SUCCESS) {
4576                         dns_message_puttempname(client->message, &tname);
4577                         if (result == ISC_R_NOSPACE) {
4578                                 /*
4579                                  * RFC2672, section 4.1, subsection 3c says
4580                                  * we should return YXDOMAIN if the constructed
4581                                  * name would be too long.
4582                                  */
4583                                 client->message->rcode = dns_rcode_yxdomain;
4584                         }
4585                         goto cleanup;
4586                 }
4587                 query_keepname(client, fname, dbuf);
4588                 /*
4589                  * Synthesize a CNAME for this DNAME.
4590                  *
4591                  * We want to synthesize a CNAME since if we don't
4592                  * then older software that doesn't understand DNAME
4593                  * will not chain like it should.
4594                  *
4595                  * We do not try to synthesize a signature because we hope
4596                  * that security aware servers will understand DNAME.  Also,
4597                  * even if we had an online key, making a signature
4598                  * on-the-fly is costly, and not really legitimate anyway
4599                  * since the synthesized CNAME is NOT in the zone.
4600                  */
4601                 dns_name_init(tname, NULL);
4602                 (void)query_addcnamelike(client, client->query.qname, fname,
4603                                          trdataset, &tname,
4604                                          dns_rdatatype_cname);
4605                 if (tname != NULL)
4606                         dns_message_puttempname(client->message, &tname);
4607                 /*
4608                  * Switch to the new qname and restart.
4609                  */
4610                 ns_client_qnamereplace(client, fname);
4611                 fname = NULL;
4612                 want_restart = ISC_TRUE;
4613                 if (!WANTRECURSION(client))
4614                         options |= DNS_GETDB_NOLOG;
4615                 goto addauth;
4616         default:
4617                 /*
4618                  * Something has gone wrong.
4619                  */
4620                 QUERY_ERROR(DNS_R_SERVFAIL);
4621                 goto cleanup;
4622         }
4623
4624         if (WANTDNSSEC(client) &&
4625             (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4626         {
4627                 dns_fixedname_init(&wildcardname);
4628                 dns_name_copy(fname, dns_fixedname_name(&wildcardname), NULL);
4629                 need_wildcardproof = ISC_TRUE;
4630         }
4631
4632         if (type == dns_rdatatype_any) {
4633                 /*
4634                  * XXXRTH  Need to handle zonecuts with special case
4635                  * code.
4636                  */
4637                 n = 0;
4638                 rdsiter = NULL;
4639                 result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
4640                 if (result != ISC_R_SUCCESS) {
4641                         QUERY_ERROR(DNS_R_SERVFAIL);
4642                         goto cleanup;
4643                 }
4644                 /*
4645                  * Calling query_addrrset() with a non-NULL dbuf is going
4646                  * to either keep or release the name.  We don't want it to
4647                  * release fname, since we may have to call query_addrrset()
4648                  * more than once.  That means we have to call query_keepname()
4649                  * now, and pass a NULL dbuf to query_addrrset().
4650                  *
4651                  * If we do a query_addrrset() below, we must set fname to
4652                  * NULL before leaving this block, otherwise we might try to
4653                  * cleanup fname even though we're using it!
4654                  */
4655                 query_keepname(client, fname, dbuf);
4656                 tname = fname;
4657                 result = dns_rdatasetiter_first(rdsiter);
4658                 while (result == ISC_R_SUCCESS) {
4659                         dns_rdatasetiter_current(rdsiter, rdataset);
4660                         if (is_zone && qtype == dns_rdatatype_any &&
4661                             !dns_db_issecure(db) &&
4662                             dns_rdatatype_isdnssec(rdataset->type)) {
4663                                 /*
4664                                  * The zone is transitioning from insecure
4665                                  * to secure. Hide the dnssec records from
4666                                  * ANY queries.
4667                                  */
4668                                 dns_rdataset_disassociate(rdataset);
4669                         } else if ((qtype == dns_rdatatype_any ||
4670                              rdataset->type == qtype) && rdataset->type != 0) {
4671                                 if (NOQNAME(rdataset) && WANTDNSSEC(client))
4672                                         noqname = rdataset;
4673                                 else
4674                                         noqname = NULL;
4675                                 query_addrrset(client,
4676                                                fname != NULL ? &fname : &tname,
4677                                                &rdataset, NULL,
4678                                                NULL, DNS_SECTION_ANSWER);
4679                                 if (noqname != NULL)
4680                                         query_addnoqnameproof(client, noqname);
4681                                 n++;
4682                                 INSIST(tname != NULL);
4683                                 /*
4684                                  * rdataset is non-NULL only in certain
4685                                  * pathological cases involving DNAMEs.
4686                                  */
4687                                 if (rdataset != NULL)
4688                                         query_putrdataset(client, &rdataset);
4689                                 rdataset = query_newrdataset(client);
4690                                 if (rdataset == NULL)
4691                                         break;
4692                         } else {
4693                                 /*
4694                                  * We're not interested in this rdataset.
4695                                  */
4696                                 dns_rdataset_disassociate(rdataset);
4697                         }
4698                         result = dns_rdatasetiter_next(rdsiter);
4699                 }
4700
4701                 if (fname != NULL)
4702                         dns_message_puttempname(client->message, &fname);
4703
4704                 if (n == 0 && is_zone) {
4705                         /*
4706                          * We didn't match any rdatasets.
4707                          */
4708                         if (qtype == dns_rdatatype_rrsig &&
4709                             result == ISC_R_NOMORE) {
4710                                 /*
4711                                  * XXXRTH  If this is a secure zone and we
4712                                  * didn't find any SIGs, we should generate
4713                                  * an error unless we were searching for
4714                                  * glue.  Ugh.
4715                                  */
4716                                 if (!is_zone) {
4717                                         authoritative = ISC_FALSE;
4718                                         dns_rdatasetiter_destroy(&rdsiter);
4719                                         if (RECURSIONOK(client)) {
4720                                                 result = query_recurse(client,
4721                                                                        qtype,
4722                                                                        NULL,
4723                                                                        NULL,
4724                                                                        resuming);
4725                                                 if (result == ISC_R_SUCCESS)
4726                                                     client->query.attributes |=
4727                                                         NS_QUERYATTR_RECURSING;
4728                                                 else
4729                                                     RECURSE_ERROR(result);
4730                                         }
4731                                         goto addauth;
4732                                 }
4733                                 /*
4734                                  * We were searching for SIG records in
4735                                  * a nonsecure zone.  Send a "no error,
4736                                  * no data" response.
4737                                  */
4738                                 /*
4739                                  * Add SOA.
4740                                  */
4741                                 result = query_addsoa(client, db, version,
4742                                                       ISC_FALSE);
4743                                 if (result == ISC_R_SUCCESS)
4744                                         result = ISC_R_NOMORE;
4745                         } else {
4746                                 /*
4747                                  * Something went wrong.
4748                                  */
4749                                 result = DNS_R_SERVFAIL;
4750                         }
4751                 }
4752                 dns_rdatasetiter_destroy(&rdsiter);
4753                 if (result != ISC_R_NOMORE) {
4754                         QUERY_ERROR(DNS_R_SERVFAIL);
4755                         goto cleanup;
4756                 }
4757         } else {
4758                 /*
4759                  * This is the "normal" case -- an ordinary question to which
4760                  * we know the answer.
4761                  */
4762                 if (sigrdataset != NULL)
4763                         sigrdatasetp = &sigrdataset;
4764                 else
4765                         sigrdatasetp = NULL;
4766                 if (NOQNAME(rdataset) && WANTDNSSEC(client))
4767                         noqname = rdataset;
4768                 else
4769                         noqname = NULL;
4770                 /*
4771                  * BIND 8 priming queries need the additional section.
4772                  */
4773                 if (is_zone && qtype == dns_rdatatype_ns &&
4774                     dns_name_equal(client->query.qname, dns_rootname))
4775                         client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
4776
4777                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4778                                DNS_SECTION_ANSWER);
4779                 if (noqname != NULL)
4780                         query_addnoqnameproof(client, noqname);
4781                 /*
4782                  * We shouldn't ever fail to add 'rdataset'
4783                  * because it's already in the answer.
4784                  */
4785                 INSIST(rdataset == NULL);
4786         }
4787
4788  addauth:
4789         CTRACE("query_find: addauth");
4790         /*
4791          * Add NS records to the authority section (if we haven't already
4792          * added them to the answer section).
4793          */
4794         if (!want_restart && !NOAUTHORITY(client)) {
4795                 if (is_zone) {
4796                         if (!((qtype == dns_rdatatype_ns ||
4797                                qtype == dns_rdatatype_any) &&
4798                               dns_name_equal(client->query.qname,
4799                                              dns_db_origin(db))))
4800                                 (void)query_addns(client, db, version);
4801                 } else if (qtype != dns_rdatatype_ns) {
4802                         if (fname != NULL)
4803                                 query_releasename(client, &fname);
4804                         query_addbestns(client);
4805                 }
4806         }
4807
4808         /*
4809          * Add NSEC records to the authority section if they're needed for
4810          * DNSSEC wildcard proofs.
4811          */
4812         if (need_wildcardproof && dns_db_issecure(db))
4813                 query_addwildcardproof(client, db, version,
4814                                        dns_fixedname_name(&wildcardname),
4815                                        ISC_TRUE);
4816  cleanup:
4817         CTRACE("query_find: cleanup");
4818         /*
4819          * General cleanup.
4820          */
4821         if (rdataset != NULL)
4822                 query_putrdataset(client, &rdataset);
4823         if (sigrdataset != NULL)
4824                 query_putrdataset(client, &sigrdataset);
4825         if (fname != NULL)
4826                 query_releasename(client, &fname);
4827         if (node != NULL)
4828                 dns_db_detachnode(db, &node);
4829         if (db != NULL)
4830                 dns_db_detach(&db);
4831         if (zone != NULL)
4832                 dns_zone_detach(&zone);
4833         if (zdb != NULL) {
4834                 query_putrdataset(client, &zrdataset);
4835                 if (zsigrdataset != NULL)
4836                         query_putrdataset(client, &zsigrdataset);
4837                 if (zfname != NULL)
4838                         query_releasename(client, &zfname);
4839                 dns_db_detach(&zdb);
4840         }
4841         if (event != NULL)
4842                 isc_event_free(ISC_EVENT_PTR(&event));
4843
4844         /*
4845          * AA bit.
4846          */
4847         if (client->query.restarts == 0 && !authoritative) {
4848                 /*
4849                  * We're not authoritative, so we must ensure the AA bit
4850                  * isn't set.
4851                  */
4852                 client->message->flags &= ~DNS_MESSAGEFLAG_AA;
4853         }
4854
4855         /*
4856          * Restart the query?
4857          */
4858         if (want_restart && client->query.restarts < MAX_RESTARTS) {
4859                 client->query.restarts++;
4860                 goto restart;
4861         }
4862
4863         if (eresult != ISC_R_SUCCESS &&
4864             (!PARTIALANSWER(client) || WANTRECURSION(client))) {
4865                 if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) {
4866                         /*
4867                          * This was a duplicate query that we are
4868                          * recursing on.  Don't send a response now.
4869                          * The original query will still cause a response.
4870                          */
4871                         query_next(client, eresult);
4872                 } else {
4873                         /*
4874                          * If we don't have any answer to give the client,
4875                          * or if the client requested recursion and thus wanted
4876                          * the complete answer, send an error response.
4877                          */
4878                         INSIST(line >= 0);
4879                         query_error(client, eresult, line);
4880                 }
4881                 ns_client_detach(&client);
4882         } else if (!RECURSING(client)) {
4883                 /*
4884                  * We are done.  Set up sortlist data for the message
4885                  * rendering code, make a final tweak to the AA bit if the
4886                  * auth-nxdomain config option says so, then render and
4887                  * send the response.
4888                  */
4889                 setup_query_sortlist(client);
4890
4891                 /*
4892                  * If this is a referral and the answer to the question
4893                  * is in the glue sort it to the start of the additional
4894                  * section.
4895                  */
4896                 if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) &&
4897                     client->message->rcode == dns_rcode_noerror &&
4898                     (qtype == dns_rdatatype_a || qtype == dns_rdatatype_aaaa))
4899                         answer_in_glue(client, qtype);
4900
4901                 if (client->message->rcode == dns_rcode_nxdomain &&
4902                     client->view->auth_nxdomain == ISC_TRUE)
4903                         client->message->flags |= DNS_MESSAGEFLAG_AA;
4904
4905                 /*
4906                  * If the response is somehow unexpected for the client and this
4907                  * is a result of recursion, return an error to the caller
4908                  * to indicate it may need to be logged.
4909                  */
4910                 if (resuming &&
4911                     (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) ||
4912                      client->message->rcode != dns_rcode_noerror))
4913                         eresult = ISC_R_FAILURE;
4914
4915                 query_send(client);
4916                 ns_client_detach(&client);
4917         }
4918         CTRACE("query_find: done");
4919
4920         return (eresult);
4921 }
4922
4923 static inline void
4924 log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) {
4925         char namebuf[DNS_NAME_FORMATSIZE];
4926         char typename[DNS_RDATATYPE_FORMATSIZE];
4927         char classname[DNS_RDATACLASS_FORMATSIZE];
4928         dns_rdataset_t *rdataset;
4929         int level = ISC_LOG_INFO;
4930
4931         if (! isc_log_wouldlog(ns_g_lctx, level))
4932                 return;
4933
4934         rdataset = ISC_LIST_HEAD(client->query.qname->list);
4935         INSIST(rdataset != NULL);
4936         dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
4937         dns_rdataclass_format(rdataset->rdclass, classname, sizeof(classname));
4938         dns_rdatatype_format(rdataset->type, typename, sizeof(typename));
4939
4940         ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
4941                       level, "query: %s %s %s %s%s%s%s%s", namebuf, classname,
4942                       typename, WANTRECURSION(client) ? "+" : "-",
4943                       (client->signer != NULL) ? "S": "",
4944                       (client->opt != NULL) ? "E" : "",
4945                       ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) ? "D" : "",
4946                       ((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : "");
4947 }
4948
4949 static inline void
4950 log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) {
4951         char namebuf[DNS_NAME_FORMATSIZE];
4952         char typename[DNS_RDATATYPE_FORMATSIZE];
4953         char classname[DNS_RDATACLASS_FORMATSIZE];
4954         const char *namep, *typep, *classp, *sep1, *sep2;
4955         dns_rdataset_t *rdataset;
4956
4957         if (!isc_log_wouldlog(ns_g_lctx, level))
4958                 return;
4959
4960         namep = typep = classp = sep1 = sep2 = "";
4961
4962         /*
4963          * Query errors can happen for various reasons.  In some cases we cannot
4964          * even assume the query contains a valid question section, so we should
4965          * expect exceptional cases.
4966          */
4967         if (client->query.origqname != NULL) {
4968                 dns_name_format(client->query.origqname, namebuf,
4969                                 sizeof(namebuf));
4970                 namep = namebuf;
4971                 sep1 = " for ";
4972
4973                 rdataset = ISC_LIST_HEAD(client->query.origqname->list);
4974                 if (rdataset != NULL) {
4975                         dns_rdataclass_format(rdataset->rdclass, classname,
4976                                               sizeof(classname));
4977                         classp = classname;
4978                         dns_rdatatype_format(rdataset->type, typename,
4979                                              sizeof(typename));
4980                         typep = typename;
4981                         sep2 = "/";
4982                 }
4983         }
4984
4985         ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, NS_LOGMODULE_QUERY,
4986                       level, "query failed (%s)%s%s%s%s%s%s at %s:%d",
4987                       isc_result_totext(result), sep1, namep, sep2,
4988                       classp, sep2, typep, __FILE__, line);
4989 }
4990
4991 void
4992 ns_query_start(ns_client_t *client) {
4993         isc_result_t result;
4994         dns_message_t *message = client->message;
4995         dns_rdataset_t *rdataset;
4996         ns_client_t *qclient;
4997         dns_rdatatype_t qtype;
4998         unsigned int saved_extflags = client->extflags;
4999         unsigned int saved_flags = client->message->flags;
5000         isc_boolean_t want_ad;
5001
5002         CTRACE("ns_query_start");
5003
5004         /*
5005          * Test only.
5006          */
5007         if (ns_g_clienttest && (client->attributes & NS_CLIENTATTR_TCP) == 0)
5008                 RUNTIME_CHECK(ns_client_replace(client) == ISC_R_SUCCESS);
5009
5010         /*
5011          * Ensure that appropriate cleanups occur.
5012          */
5013         client->next = query_next_callback;
5014
5015         /*
5016          * Behave as if we don't support DNSSEC if not enabled.
5017          */
5018         if (!client->view->enablednssec) {
5019                 message->flags &= ~DNS_MESSAGEFLAG_CD;
5020                 client->extflags &= ~DNS_MESSAGEEXTFLAG_DO;
5021                 if (client->opt != NULL)
5022                         client->opt->ttl &= ~DNS_MESSAGEEXTFLAG_DO;
5023         }
5024
5025         if ((message->flags & DNS_MESSAGEFLAG_RD) != 0)
5026                 client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
5027
5028         if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0)
5029                 client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
5030
5031         if (client->view->minimalresponses)
5032                 client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
5033                                              NS_QUERYATTR_NOADDITIONAL);
5034
5035         if ((client->view->cachedb == NULL)
5036             || (!client->view->additionalfromcache)) {
5037                 /*
5038                  * We don't have a cache.  Turn off cache support and
5039                  * recursion.
5040                  */
5041                 client->query.attributes &=
5042                         ~(NS_QUERYATTR_RECURSIONOK|NS_QUERYATTR_CACHEOK);
5043         } else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
5044                    (message->flags & DNS_MESSAGEFLAG_RD) == 0) {
5045                 /*
5046                  * If the client isn't allowed to recurse (due to
5047                  * "recursion no", the allow-recursion ACL, or the
5048                  * lack of a resolver in this view), or if it
5049                  * doesn't want recursion, turn recursion off.
5050                  */
5051                 client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
5052         }
5053
5054         /*
5055          * Get the question name.
5056          */
5057         result = dns_message_firstname(message, DNS_SECTION_QUESTION);
5058         if (result != ISC_R_SUCCESS) {
5059                 query_error(client, result, __LINE__);
5060                 return;
5061         }
5062         dns_message_currentname(message, DNS_SECTION_QUESTION,
5063                                 &client->query.qname);
5064         client->query.origqname = client->query.qname;
5065         result = dns_message_nextname(message, DNS_SECTION_QUESTION);
5066         if (result != ISC_R_NOMORE) {
5067                 if (result == ISC_R_SUCCESS) {
5068                         /*
5069                          * There's more than one QNAME in the question
5070                          * section.
5071                          */
5072                         query_error(client, DNS_R_FORMERR, __LINE__);
5073                 } else
5074                         query_error(client, result, __LINE__);
5075                 return;
5076         }
5077
5078         if (ns_g_server->log_queries)
5079                 log_query(client, saved_flags, saved_extflags);
5080
5081         /*
5082          * Check for multiple question queries, since edns1 is dead.
5083          */
5084         if (message->counts[DNS_SECTION_QUESTION] > 1) {
5085                 query_error(client, DNS_R_FORMERR, __LINE__);
5086                 return;
5087         }
5088
5089         /*
5090          * Check for meta-queries like IXFR and AXFR.
5091          */
5092         rdataset = ISC_LIST_HEAD(client->query.qname->list);
5093         INSIST(rdataset != NULL);
5094         qtype = rdataset->type;
5095         dns_rdatatypestats_increment(ns_g_server->rcvquerystats, qtype);
5096         if (dns_rdatatype_ismeta(qtype)) {
5097                 switch (qtype) {
5098                 case dns_rdatatype_any:
5099                         break; /* Let query_find handle it. */
5100                 case dns_rdatatype_ixfr:
5101                 case dns_rdatatype_axfr:
5102                         ns_xfr_start(client, rdataset->type);
5103                         return;
5104                 case dns_rdatatype_maila:
5105                 case dns_rdatatype_mailb:
5106                         query_error(client, DNS_R_NOTIMP, __LINE__);
5107                         return;
5108                 case dns_rdatatype_tkey:
5109                         result = dns_tkey_processquery(client->message,
5110                                                 ns_g_server->tkeyctx,
5111                                                 client->view->dynamickeys);
5112                         if (result == ISC_R_SUCCESS)
5113                                 query_send(client);
5114                         else
5115                                 query_error(client, result, __LINE__);
5116                         return;
5117                 default: /* TSIG, etc. */
5118                         query_error(client, DNS_R_FORMERR, __LINE__);
5119                         return;
5120                 }
5121         }
5122
5123         /*
5124          * Turn on minimal response for DNSKEY and DS queries.
5125          */
5126         if (qtype == dns_rdatatype_dnskey || qtype == dns_rdatatype_ds)
5127                 client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
5128                                              NS_QUERYATTR_NOADDITIONAL);
5129
5130         /*
5131          * Turn on minimal responses for EDNS/UDP bufsize 512 queries.
5132          */
5133         if (client->opt != NULL && client->udpsize <= 512U &&
5134             (client->attributes & NS_CLIENTATTR_TCP) == 0)
5135                 client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
5136                                              NS_QUERYATTR_NOADDITIONAL);
5137
5138         /*
5139          * If the client has requested that DNSSEC checking be disabled,
5140          * allow lookups to return pending data and instruct the resolver
5141          * to return data before validation has completed.
5142          *
5143          * We don't need to set DNS_DBFIND_PENDINGOK when validation is
5144          * disabled as there will be no pending data.
5145          */
5146         if (message->flags & DNS_MESSAGEFLAG_CD ||
5147             qtype == dns_rdatatype_rrsig)
5148         {
5149                 client->query.dboptions |= DNS_DBFIND_PENDINGOK;
5150                 client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
5151         } else if (!client->view->enablevalidation)
5152                 client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
5153
5154         /*
5155          * Allow glue NS records to be added to the authority section
5156          * if the answer is secure.
5157          */
5158         if (message->flags & DNS_MESSAGEFLAG_CD)
5159                 client->query.attributes &= ~NS_QUERYATTR_SECURE;
5160
5161         /*
5162          * Set 'want_ad' if the client has set AD in the query.
5163          * This allows AD to be returned on queries without DO set.
5164          */
5165         if ((message->flags & DNS_MESSAGEFLAG_AD) != 0)
5166                 want_ad = ISC_TRUE;
5167         else
5168                 want_ad = ISC_FALSE;
5169
5170         /*
5171          * This is an ordinary query.
5172          */
5173         result = dns_message_reply(message, ISC_TRUE);
5174         if (result != ISC_R_SUCCESS) {
5175                 query_next(client, result);
5176                 return;
5177         }
5178
5179         /*
5180          * Assume authoritative response until it is known to be
5181          * otherwise.
5182          */
5183         message->flags |= DNS_MESSAGEFLAG_AA;
5184
5185         /*
5186          * Set AD.  We must clear it if we add non-validated data to a
5187          * response.
5188          */
5189         if (WANTDNSSEC(client) || want_ad)
5190                 message->flags |= DNS_MESSAGEFLAG_AD;
5191
5192         qclient = NULL;
5193         ns_client_attach(client, &qclient);
5194         (void)query_find(qclient, NULL, qtype);
5195 }