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