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