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