]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/bind9/bin/named/query.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / bind9 / bin / named / query.c
1 /*
2  * Copyright (C) 2004-2008  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.46 2008/10/15 22:33:01 marka 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                         /*
2761                          * Check for a pathological condition created when
2762                          * serving some malformed signed zones and bail out.
2763                          */
2764                         if (dns_name_countlabels(name) == nlabels)
2765                                 goto cleanup;
2766
2767                         if (olabels > nlabels)
2768                                 dns_name_split(name, olabels, NULL, wname);
2769                         else
2770                                 dns_name_split(name, nlabels, NULL, wname);
2771                         result = dns_name_concatenate(dns_wildcardname,
2772                                                       wname, wname, NULL);
2773                         if (result == ISC_R_SUCCESS)
2774                                 have_wname = ISC_TRUE;
2775                         dns_rdata_freestruct(&nsec);
2776                 }
2777                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2778                                dbuf, DNS_SECTION_AUTHORITY);
2779         }
2780         if (rdataset != NULL)
2781                 query_putrdataset(client, &rdataset);
2782         if (sigrdataset != NULL)
2783                 query_putrdataset(client, &sigrdataset);
2784         if (fname != NULL)
2785                 query_releasename(client, &fname);
2786         if (have_wname) {
2787                 ispositive = ISC_TRUE;  /* prevent loop */
2788                 if (!dns_name_equal(name, wname)) {
2789                         name = wname;
2790                         goto again;
2791                 }
2792         }
2793  cleanup:
2794         if (rdataset != NULL)
2795                 query_putrdataset(client, &rdataset);
2796         if (sigrdataset != NULL)
2797                 query_putrdataset(client, &sigrdataset);
2798         if (fname != NULL)
2799                 query_releasename(client, &fname);
2800 }
2801
2802 static void
2803 query_addnxrrsetnsec(ns_client_t *client, dns_db_t *db,
2804                      dns_dbversion_t *version, dns_name_t **namep,
2805                      dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp)
2806 {
2807         dns_name_t *name;
2808         dns_rdataset_t *sigrdataset;
2809         dns_rdata_t sigrdata;
2810         dns_rdata_rrsig_t sig;
2811         unsigned int labels;
2812         isc_buffer_t *dbuf, b;
2813         dns_name_t *fname;
2814         isc_result_t result;
2815
2816         name = *namep;
2817         if ((name->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
2818                 query_addrrset(client, namep, rdatasetp, sigrdatasetp,
2819                                NULL, DNS_SECTION_AUTHORITY);
2820                 return;
2821         }
2822
2823         if (sigrdatasetp == NULL)
2824                 return;
2825         sigrdataset = *sigrdatasetp;
2826         if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
2827                 return;
2828         result = dns_rdataset_first(sigrdataset);
2829         if (result != ISC_R_SUCCESS)
2830                 return;
2831         dns_rdata_init(&sigrdata);
2832         dns_rdataset_current(sigrdataset, &sigrdata);
2833         result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
2834         if (result != ISC_R_SUCCESS)
2835                 return;
2836
2837         labels = dns_name_countlabels(name);
2838         if ((unsigned int)sig.labels + 1 >= labels)
2839                 return;
2840
2841         /* XXX */
2842         query_addwildcardproof(client, db, version, client->query.qname,
2843                                ISC_TRUE);
2844
2845         /*
2846          * We'll need some resources...
2847          */
2848         dbuf = query_getnamebuf(client);
2849         if (dbuf == NULL)
2850                 return;
2851         fname = query_newname(client, dbuf, &b);
2852         if (fname == NULL)
2853                 return;
2854         dns_name_split(name, sig.labels + 1, NULL, fname);
2855         /* This will succeed, since we've stripped labels. */
2856         RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
2857                                            NULL) == ISC_R_SUCCESS);
2858         query_addrrset(client, &fname, rdatasetp, sigrdatasetp,
2859                        dbuf, DNS_SECTION_AUTHORITY);
2860 }
2861
2862 static void
2863 query_resume(isc_task_t *task, isc_event_t *event) {
2864         dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
2865         ns_client_t *client;
2866         isc_boolean_t fetch_cancelled, client_shuttingdown;
2867
2868         /*
2869          * Resume a query after recursion.
2870          */
2871
2872         UNUSED(task);
2873
2874         REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
2875         client = devent->ev_arg;
2876         REQUIRE(NS_CLIENT_VALID(client));
2877         REQUIRE(task == client->task);
2878         REQUIRE(RECURSING(client));
2879
2880         LOCK(&client->query.fetchlock);
2881         if (client->query.fetch != NULL) {
2882                 /*
2883                  * This is the fetch we've been waiting for.
2884                  */
2885                 INSIST(devent->fetch == client->query.fetch);
2886                 client->query.fetch = NULL;
2887                 fetch_cancelled = ISC_FALSE;
2888                 /*
2889                  * Update client->now.
2890                  */
2891                 isc_stdtime_get(&client->now);
2892         } else {
2893                 /*
2894                  * This is a fetch completion event for a cancelled fetch.
2895                  * Clean up and don't resume the find.
2896                  */
2897                 fetch_cancelled = ISC_TRUE;
2898         }
2899         UNLOCK(&client->query.fetchlock);
2900         INSIST(client->query.fetch == NULL);
2901
2902         client->query.attributes &= ~NS_QUERYATTR_RECURSING;
2903         dns_resolver_destroyfetch(&devent->fetch);
2904
2905         /*
2906          * If this client is shutting down, or this transaction
2907          * has timed out, do not resume the find.
2908          */
2909         client_shuttingdown = ns_client_shuttingdown(client);
2910         if (fetch_cancelled || client_shuttingdown) {
2911                 if (devent->node != NULL)
2912                         dns_db_detachnode(devent->db, &devent->node);
2913                 if (devent->db != NULL)
2914                         dns_db_detach(&devent->db);
2915                 query_putrdataset(client, &devent->rdataset);
2916                 if (devent->sigrdataset != NULL)
2917                         query_putrdataset(client, &devent->sigrdataset);
2918                 isc_event_free(&event);
2919                 if (fetch_cancelled)
2920                         query_error(client, DNS_R_SERVFAIL);
2921                 else
2922                         query_next(client, ISC_R_CANCELED);
2923                 /*
2924                  * This may destroy the client.
2925                  */
2926                 ns_client_detach(&client);
2927         } else {
2928                 query_find(client, devent, 0);
2929         }
2930 }
2931
2932 static isc_result_t
2933 query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
2934               dns_rdataset_t *nameservers, isc_boolean_t resuming)
2935 {
2936         isc_result_t result;
2937         dns_rdataset_t *rdataset, *sigrdataset;
2938         isc_sockaddr_t *peeraddr;
2939
2940         if (!resuming)
2941                 inc_stats(client, dns_statscounter_recursion);
2942
2943         /*
2944          * We are about to recurse, which means that this client will
2945          * be unavailable for serving new requests for an indeterminate
2946          * amount of time.  If this client is currently responsible
2947          * for handling incoming queries, set up a new client
2948          * object to handle them while we are waiting for a
2949          * response.  There is no need to replace TCP clients
2950          * because those have already been replaced when the
2951          * connection was accepted (if allowed by the TCP quota).
2952          */
2953         if (client->recursionquota == NULL) {
2954                 result = isc_quota_attach(&ns_g_server->recursionquota,
2955                                           &client->recursionquota);
2956                 if  (result == ISC_R_SOFTQUOTA) {
2957                         static isc_stdtime_t last = 0;
2958                         isc_stdtime_t now;
2959                         isc_stdtime_get(&now);
2960                         if (now != last) {
2961                                 last = now;
2962                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
2963                                               NS_LOGMODULE_QUERY,
2964                                               ISC_LOG_WARNING,
2965                                               "recursive-clients soft limit "
2966                                               "exceeded, aborting oldest query");
2967                         }
2968                         ns_client_killoldestquery(client);
2969                         result = ISC_R_SUCCESS;
2970                 } else if (result == ISC_R_QUOTA) {
2971                         static isc_stdtime_t last = 0;
2972                         isc_stdtime_t now;
2973                         isc_stdtime_get(&now);
2974                         if (now != last) {
2975                                 last = now;
2976                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
2977                                               NS_LOGMODULE_QUERY,
2978                                               ISC_LOG_WARNING,
2979                                               "no more recursive clients: %s",
2980                                               isc_result_totext(result));
2981                         }
2982                         ns_client_killoldestquery(client);
2983                 }
2984                 if (result == ISC_R_SUCCESS && !client->mortal &&
2985                     (client->attributes & NS_CLIENTATTR_TCP) == 0) {
2986                         result = ns_client_replace(client);
2987                         if (result != ISC_R_SUCCESS) {
2988                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
2989                                               NS_LOGMODULE_QUERY,
2990                                               ISC_LOG_WARNING,
2991                                               "ns_client_replace() failed: %s",
2992                                               isc_result_totext(result));
2993                                 isc_quota_detach(&client->recursionquota);
2994                         }
2995                 }
2996                 if (result != ISC_R_SUCCESS)
2997                         return (result);
2998                 ns_client_recursing(client);
2999         }
3000
3001         /*
3002          * Invoke the resolver.
3003          */
3004         REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
3005         REQUIRE(client->query.fetch == NULL);
3006
3007         rdataset = query_newrdataset(client);
3008         if (rdataset == NULL)
3009                 return (ISC_R_NOMEMORY);
3010         if (WANTDNSSEC(client)) {
3011                 sigrdataset = query_newrdataset(client);
3012                 if (sigrdataset == NULL) {
3013                         query_putrdataset(client, &rdataset);
3014                         return (ISC_R_NOMEMORY);
3015                 }
3016         } else
3017                 sigrdataset = NULL;
3018
3019         if (client->query.timerset == ISC_FALSE)
3020                 ns_client_settimeout(client, 60);
3021         if ((client->attributes & NS_CLIENTATTR_TCP) == 0)
3022                 peeraddr = &client->peeraddr;
3023         else
3024                 peeraddr = NULL;
3025         result = dns_resolver_createfetch2(client->view->resolver,
3026                                            client->query.qname,
3027                                            qtype, qdomain, nameservers,
3028                                            NULL, peeraddr, client->message->id,
3029                                            client->query.fetchoptions,
3030                                            client->task,
3031                                            query_resume, client,
3032                                            rdataset, sigrdataset,
3033                                            &client->query.fetch);
3034
3035         if (result == ISC_R_SUCCESS) {
3036                 /*
3037                  * Record that we're waiting for an event.  A client which
3038                  * is shutting down will not be destroyed until all the
3039                  * events have been received.
3040                  */
3041         } else {
3042                 query_putrdataset(client, &rdataset);
3043                 if (sigrdataset != NULL)
3044                         query_putrdataset(client, &sigrdataset);
3045         }
3046
3047         return (result);
3048 }
3049
3050 #define MAX_RESTARTS 16
3051
3052 #define QUERY_ERROR(r) \
3053 do { \
3054         eresult = r; \
3055         want_restart = ISC_FALSE; \
3056 } while (0)
3057
3058 /*
3059  * Extract a network address from the RDATA of an A or AAAA
3060  * record.
3061  *
3062  * Returns:
3063  *      ISC_R_SUCCESS
3064  *      ISC_R_NOTIMPLEMENTED    The rdata is not a known address type.
3065  */
3066 static isc_result_t
3067 rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
3068         struct in_addr ina;
3069         struct in6_addr in6a;
3070
3071         switch (rdata->type) {
3072         case dns_rdatatype_a:
3073                 INSIST(rdata->length == 4);
3074                 memcpy(&ina.s_addr, rdata->data, 4);
3075                 isc_netaddr_fromin(netaddr, &ina);
3076                 return (ISC_R_SUCCESS);
3077         case dns_rdatatype_aaaa:
3078                 INSIST(rdata->length == 16);
3079                 memcpy(in6a.s6_addr, rdata->data, 16);
3080                 isc_netaddr_fromin6(netaddr, &in6a);
3081                 return (ISC_R_SUCCESS);
3082         default:
3083                 return (ISC_R_NOTIMPLEMENTED);
3084         }
3085 }
3086
3087 /*
3088  * Find the sort order of 'rdata' in the topology-like
3089  * ACL forming the second element in a 2-element top-level
3090  * sortlist statement.
3091  */
3092 static int
3093 query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
3094         isc_netaddr_t netaddr;
3095
3096         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3097                 return (INT_MAX);
3098         return (ns_sortlist_addrorder2(&netaddr, arg));
3099 }
3100
3101 /*
3102  * Find the sort order of 'rdata' in the matching element
3103  * of a 1-element top-level sortlist statement.
3104  */
3105 static int
3106 query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
3107         isc_netaddr_t netaddr;
3108
3109         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3110                 return (INT_MAX);
3111         return (ns_sortlist_addrorder1(&netaddr, arg));
3112 }
3113
3114 /*
3115  * Find the sortlist statement that applies to 'client' and set up
3116  * the sortlist info in in client->message appropriately.
3117  */
3118 static void
3119 setup_query_sortlist(ns_client_t *client) {
3120         isc_netaddr_t netaddr;
3121         dns_rdatasetorderfunc_t order = NULL;
3122         const void *order_arg = NULL;
3123
3124         isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
3125         switch (ns_sortlist_setup(client->view->sortlist,
3126                                &netaddr, &order_arg)) {
3127         case NS_SORTLISTTYPE_1ELEMENT:
3128                 order = query_sortlist_order_1element;
3129                 break;
3130         case NS_SORTLISTTYPE_2ELEMENT:
3131                 order = query_sortlist_order_2element;
3132                 break;
3133         case NS_SORTLISTTYPE_NONE:
3134                 order = NULL;
3135                 break;
3136         default:
3137                 INSIST(0);
3138                 break;
3139         }
3140         dns_message_setsortorder(client->message, order, order_arg);
3141 }
3142
3143 static void
3144 query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) {
3145         isc_buffer_t *dbuf, b;
3146         dns_name_t *fname;
3147         dns_rdataset_t *nsec, *nsecsig;
3148         isc_result_t result = ISC_R_NOMEMORY;
3149
3150         CTRACE("query_addnoqnameproof");
3151
3152         fname = NULL;
3153         nsec = NULL;
3154         nsecsig = NULL;
3155
3156         dbuf = query_getnamebuf(client);
3157         if (dbuf == NULL)
3158                 goto cleanup;
3159         fname = query_newname(client, dbuf, &b);
3160         nsec = query_newrdataset(client);
3161         nsecsig = query_newrdataset(client);
3162         if (fname == NULL || nsec == NULL || nsecsig == NULL)
3163                 goto cleanup;
3164
3165         result = dns_rdataset_getnoqname(rdataset, fname, nsec, nsecsig);
3166         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3167
3168         query_addrrset(client, &fname, &nsec, &nsecsig, dbuf,
3169                        DNS_SECTION_AUTHORITY);
3170
3171  cleanup:
3172         if (nsec != NULL)
3173                 query_putrdataset(client, &nsec);
3174         if (nsecsig != NULL)
3175                 query_putrdataset(client, &nsecsig);
3176         if (fname != NULL)
3177                 query_releasename(client, &fname);
3178 }
3179
3180 static inline void
3181 answer_in_glue(ns_client_t *client, dns_rdatatype_t qtype) {
3182         dns_name_t *name;
3183         dns_message_t *msg;
3184         dns_section_t section = DNS_SECTION_ADDITIONAL;
3185         dns_rdataset_t *rdataset = NULL;
3186
3187         msg = client->message;
3188         for (name = ISC_LIST_HEAD(msg->sections[section]);
3189              name != NULL;
3190              name = ISC_LIST_NEXT(name, link))
3191                 if (dns_name_equal(name, client->query.qname)) {
3192                         for (rdataset = ISC_LIST_HEAD(name->list);
3193                              rdataset != NULL;
3194                              rdataset = ISC_LIST_NEXT(rdataset, link))
3195                                 if (rdataset->type == qtype)
3196                                         break;
3197                         break;
3198                 }
3199         if (rdataset != NULL) {
3200                 ISC_LIST_UNLINK(msg->sections[section], name, link);
3201                 ISC_LIST_PREPEND(msg->sections[section], name, link);
3202                 ISC_LIST_UNLINK(name->list, rdataset, link);
3203                 ISC_LIST_PREPEND(name->list, rdataset, link);
3204                 rdataset->attributes |= DNS_RDATASETATTR_REQUIREDGLUE;
3205         }
3206 }
3207
3208 #define NS_NAME_INIT(A,B) \
3209          { \
3210                 DNS_NAME_MAGIC, \
3211                 A, sizeof(A), sizeof(B), \
3212                 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \
3213                 B, NULL, { (void *)-1, (void *)-1}, \
3214                 {NULL, NULL} \
3215         }
3216
3217 static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
3218 static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
3219 static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
3220
3221 static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
3222
3223 static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
3224 static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
3225 static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
3226 static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
3227 static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
3228 static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
3229 static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
3230 static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
3231 static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
3232 static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
3233 static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
3234 static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
3235 static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
3236 static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
3237 static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
3238 static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
3239
3240 static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
3241
3242 static dns_name_t rfc1918names[] = {
3243         NS_NAME_INIT(inaddr10, inaddr10_offsets),
3244         NS_NAME_INIT(inaddr16172, inaddr172_offsets),
3245         NS_NAME_INIT(inaddr17172, inaddr172_offsets),
3246         NS_NAME_INIT(inaddr18172, inaddr172_offsets),
3247         NS_NAME_INIT(inaddr19172, inaddr172_offsets),
3248         NS_NAME_INIT(inaddr20172, inaddr172_offsets),
3249         NS_NAME_INIT(inaddr21172, inaddr172_offsets),
3250         NS_NAME_INIT(inaddr22172, inaddr172_offsets),
3251         NS_NAME_INIT(inaddr23172, inaddr172_offsets),
3252         NS_NAME_INIT(inaddr24172, inaddr172_offsets),
3253         NS_NAME_INIT(inaddr25172, inaddr172_offsets),
3254         NS_NAME_INIT(inaddr26172, inaddr172_offsets),
3255         NS_NAME_INIT(inaddr27172, inaddr172_offsets),
3256         NS_NAME_INIT(inaddr28172, inaddr172_offsets),
3257         NS_NAME_INIT(inaddr29172, inaddr172_offsets),
3258         NS_NAME_INIT(inaddr30172, inaddr172_offsets),
3259         NS_NAME_INIT(inaddr31172, inaddr172_offsets),
3260         NS_NAME_INIT(inaddr168192, inaddr192_offsets)
3261 };
3262
3263
3264 static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
3265 static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org";
3266
3267 static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
3268 static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
3269
3270 static dns_name_t prisoner = NS_NAME_INIT(prisoner_data, prisoner_offsets);
3271 static dns_name_t hostmaster = NS_NAME_INIT(hostmaster_data, hostmaster_offsets);
3272
3273 static void
3274 warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
3275         unsigned int i;
3276         dns_rdata_t rdata = DNS_RDATA_INIT;
3277         dns_rdata_soa_t soa;
3278         dns_rdataset_t found;
3279         isc_result_t result;
3280
3281         for (i = 0; i < (sizeof(rfc1918names)/sizeof(*rfc1918names)); i++) {
3282                 if (dns_name_issubdomain(fname, &rfc1918names[i])) {
3283                         dns_rdataset_init(&found);
3284                         result = dns_ncache_getrdataset(rdataset,
3285                                                         &rfc1918names[i],
3286                                                         dns_rdatatype_soa,
3287                                                         &found);
3288                         if (result != ISC_R_SUCCESS)
3289                                 return;
3290
3291                         result = dns_rdataset_first(&found);
3292                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3293                         dns_rdataset_current(&found, &rdata);
3294                         result = dns_rdata_tostruct(&rdata, &soa, NULL);
3295                         if (result != ISC_R_SUCCESS)
3296                                 return;
3297                         if (dns_name_equal(&soa.origin, &prisoner) &&
3298                             dns_name_equal(&soa.contact, &hostmaster)) {
3299                                 char buf[DNS_NAME_FORMATSIZE];
3300                                 dns_name_format(fname, buf, sizeof(buf));
3301                                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3302                                               NS_LOGMODULE_QUERY,
3303                                               ISC_LOG_WARNING,
3304                                               "RFC 1918 response from "
3305                                               "Internet for %s", buf);
3306                         }
3307                         dns_rdataset_disassociate(&found);
3308                         return;
3309                 }
3310         }
3311 }
3312
3313 /*
3314  * Do the bulk of query processing for the current query of 'client'.
3315  * If 'event' is non-NULL, we are returning from recursion and 'qtype'
3316  * is ignored.  Otherwise, 'qtype' is the query type.
3317  */
3318 static void
3319 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
3320 {
3321         dns_db_t *db, *zdb;
3322         dns_dbnode_t *node;
3323         dns_rdatatype_t type;
3324         dns_name_t *fname, *zfname, *tname, *prefix;
3325         dns_rdataset_t *rdataset, *trdataset;
3326         dns_rdataset_t *sigrdataset, *zrdataset, *zsigrdataset;
3327         dns_rdataset_t **sigrdatasetp;
3328         dns_rdata_t rdata = DNS_RDATA_INIT;
3329         dns_rdatasetiter_t *rdsiter;
3330         isc_boolean_t want_restart, authoritative, is_zone, need_wildcardproof;
3331         unsigned int n, nlabels;
3332         dns_namereln_t namereln;
3333         int order;
3334         isc_buffer_t *dbuf;
3335         isc_buffer_t b;
3336         isc_result_t result, eresult;
3337         dns_fixedname_t fixed;
3338         dns_fixedname_t wildcardname;
3339         dns_dbversion_t *version;
3340         dns_zone_t *zone;
3341         dns_rdata_cname_t cname;
3342         dns_rdata_dname_t dname;
3343         unsigned int options;
3344         isc_boolean_t empty_wild;
3345         dns_rdataset_t *noqname;
3346         isc_boolean_t resuming;
3347
3348         CTRACE("query_find");
3349
3350         /*
3351          * One-time initialization.
3352          *
3353          * It's especially important to initialize anything that the cleanup
3354          * code might cleanup.
3355          */
3356
3357         eresult = ISC_R_SUCCESS;
3358         fname = NULL;
3359         zfname = NULL;
3360         rdataset = NULL;
3361         zrdataset = NULL;
3362         sigrdataset = NULL;
3363         zsigrdataset = NULL;
3364         node = NULL;
3365         db = NULL;
3366         zdb = NULL;
3367         version = NULL;
3368         zone = NULL;
3369         need_wildcardproof = ISC_FALSE;
3370         empty_wild = ISC_FALSE;
3371         options = 0;
3372         resuming = ISC_FALSE;
3373         is_zone = ISC_FALSE;
3374
3375         if (event != NULL) {
3376                 /*
3377                  * We're returning from recursion.  Restore the query context
3378                  * and resume.
3379                  */
3380
3381                 want_restart = ISC_FALSE;
3382                 authoritative = ISC_FALSE;
3383
3384                 qtype = event->qtype;
3385                 if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3386                         type = dns_rdatatype_any;
3387                 else
3388                         type = qtype;
3389                 db = event->db;
3390                 node = event->node;
3391                 rdataset = event->rdataset;
3392                 sigrdataset = event->sigrdataset;
3393
3394                 /*
3395                  * We'll need some resources...
3396                  */
3397                 dbuf = query_getnamebuf(client);
3398                 if (dbuf == NULL) {
3399                         QUERY_ERROR(DNS_R_SERVFAIL);
3400                         goto cleanup;
3401                 }
3402                 fname = query_newname(client, dbuf, &b);
3403                 if (fname == NULL) {
3404                         QUERY_ERROR(DNS_R_SERVFAIL);
3405                         goto cleanup;
3406                 }
3407                 tname = dns_fixedname_name(&event->foundname);
3408                 result = dns_name_copy(tname, fname, NULL);
3409                 if (result != ISC_R_SUCCESS) {
3410                         QUERY_ERROR(DNS_R_SERVFAIL);
3411                         goto cleanup;
3412                 }
3413
3414                 result = event->result;
3415                 resuming = ISC_TRUE;
3416
3417                 goto resume;
3418         }
3419
3420         /*
3421          * Not returning from recursion.
3422          */
3423
3424         /*
3425          * If it's a SIG query, we'll iterate the node.
3426          */
3427         if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3428                 type = dns_rdatatype_any;
3429         else
3430                 type = qtype;
3431
3432  restart:
3433         CTRACE("query_find: restart");
3434         want_restart = ISC_FALSE;
3435         authoritative = ISC_FALSE;
3436         version = NULL;
3437         need_wildcardproof = ISC_FALSE;
3438
3439         if (client->view->checknames &&
3440             !dns_rdata_checkowner(client->query.qname,
3441                                   client->message->rdclass,
3442                                   qtype, ISC_FALSE)) {
3443                 char namebuf[DNS_NAME_FORMATSIZE];
3444                 char typename[DNS_RDATATYPE_FORMATSIZE];
3445                 char classname[DNS_RDATACLASS_FORMATSIZE];
3446
3447                 dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
3448                 dns_rdatatype_format(qtype, typename, sizeof(typename));
3449                 dns_rdataclass_format(client->message->rdclass, classname,
3450                                       sizeof(classname));
3451                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3452                               NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
3453                               "check-names failure %s/%s/%s", namebuf,
3454                               typename, classname);
3455                 QUERY_ERROR(DNS_R_REFUSED);
3456                 goto cleanup;
3457         }
3458
3459         /*
3460          * First we must find the right database.
3461          */
3462         options &= DNS_GETDB_NOLOG; /* Preserve DNS_GETDB_NOLOG. */
3463         if (dns_rdatatype_atparent(qtype) &&
3464             !dns_name_equal(client->query.qname, dns_rootname))
3465                 options |= DNS_GETDB_NOEXACT;
3466         result = query_getdb(client, client->query.qname, qtype, options,
3467                              &zone, &db, &version, &is_zone);
3468         if ((result != ISC_R_SUCCESS || !is_zone) && !RECURSIONOK(client) &&
3469             (options & DNS_GETDB_NOEXACT) != 0 && qtype == dns_rdatatype_ds) {
3470                 /*
3471                  * Look to see if we are authoritative for the
3472                  * child zone if the query type is DS.
3473                  */
3474                 dns_db_t *tdb = NULL;
3475                 dns_zone_t *tzone = NULL;
3476                 dns_dbversion_t *tversion = NULL;
3477                 isc_result_t tresult;
3478
3479                 tresult = query_getzonedb(client, client->query.qname, qtype,
3480                                          DNS_GETDB_PARTIAL, &tzone, &tdb,
3481                                          &tversion);
3482                 if (tresult == ISC_R_SUCCESS) {
3483                         options &= ~DNS_GETDB_NOEXACT;
3484                         query_putrdataset(client, &rdataset);
3485                         if (db != NULL)
3486                                 dns_db_detach(&db);
3487                         if (zone != NULL)
3488                                 dns_zone_detach(&zone);
3489                         version = tversion;
3490                         db = tdb;
3491                         zone = tzone;
3492                         is_zone = ISC_TRUE;
3493                         result = ISC_R_SUCCESS;
3494                 } else {
3495                         if (tdb != NULL)
3496                                 dns_db_detach(&tdb);
3497                         if (tzone != NULL)
3498                                 dns_zone_detach(&tzone);
3499                 }
3500         }
3501         if (result != ISC_R_SUCCESS) {
3502                 if (result == DNS_R_REFUSED) {
3503                         if (!PARTIALANSWER(client))
3504                                 QUERY_ERROR(DNS_R_REFUSED);
3505                 } else
3506                         QUERY_ERROR(DNS_R_SERVFAIL);
3507                 goto cleanup;
3508         }
3509
3510         if (is_zone)
3511                 authoritative = ISC_TRUE;
3512
3513         if (event == NULL && client->query.restarts == 0) {
3514                 if (is_zone) {
3515 #ifdef DLZ
3516                         if (zone != NULL) {
3517                                 /*
3518                                  * if is_zone = true, zone = NULL then this is
3519                                  * a DLZ zone.  Don't attempt to attach zone.
3520                                  */
3521 #endif
3522                                 dns_zone_attach(zone, &client->query.authzone);
3523 #ifdef DLZ
3524                         }
3525 #endif
3526                         dns_db_attach(db, &client->query.authdb);
3527                 }
3528                 client->query.authdbset = ISC_TRUE;
3529         }
3530
3531  db_find:
3532         CTRACE("query_find: db_find");
3533         /*
3534          * We'll need some resources...
3535          */
3536         dbuf = query_getnamebuf(client);
3537         if (dbuf == NULL) {
3538                 QUERY_ERROR(DNS_R_SERVFAIL);
3539                 goto cleanup;
3540         }
3541         fname = query_newname(client, dbuf, &b);
3542         rdataset = query_newrdataset(client);
3543         if (fname == NULL || rdataset == NULL) {
3544                 QUERY_ERROR(DNS_R_SERVFAIL);
3545                 goto cleanup;
3546         }
3547         if (WANTDNSSEC(client)) {
3548                 sigrdataset = query_newrdataset(client);
3549                 if (sigrdataset == NULL) {
3550                         QUERY_ERROR(DNS_R_SERVFAIL);
3551                         goto cleanup;
3552                 }
3553         }
3554
3555         /*
3556          * Now look for an answer in the database.
3557          */
3558         result = dns_db_find(db, client->query.qname, version, type,
3559                              client->query.dboptions, client->now,
3560                              &node, fname, rdataset, sigrdataset);
3561
3562  resume:
3563         CTRACE("query_find: resume");
3564         switch (result) {
3565         case ISC_R_SUCCESS:
3566                 /*
3567                  * This case is handled in the main line below.
3568                  */
3569                 break;
3570         case DNS_R_GLUE:
3571         case DNS_R_ZONECUT:
3572                 /*
3573                  * These cases are handled in the main line below.
3574                  */
3575                 INSIST(is_zone);
3576                 authoritative = ISC_FALSE;
3577                 break;
3578         case ISC_R_NOTFOUND:
3579                 /*
3580                  * The cache doesn't even have the root NS.  Get them from
3581                  * the hints DB.
3582                  */
3583                 INSIST(!is_zone);
3584                 if (db != NULL)
3585                         dns_db_detach(&db);
3586
3587                 if (client->view->hints == NULL) {
3588                         /* We have no hints. */
3589                         result = ISC_R_FAILURE;
3590                 } else {
3591                         dns_db_attach(client->view->hints, &db);
3592                         result = dns_db_find(db, dns_rootname,
3593                                              NULL, dns_rdatatype_ns,
3594                                              0, client->now, &node, fname,
3595                                              rdataset, sigrdataset);
3596                 }
3597                 if (result != ISC_R_SUCCESS) {
3598                         /*
3599                          * Nonsensical root hints may require cleanup.
3600                          */
3601                         if (dns_rdataset_isassociated(rdataset))
3602                                 dns_rdataset_disassociate(rdataset);
3603                         if (sigrdataset != NULL &&
3604                             dns_rdataset_isassociated(sigrdataset))
3605                                 dns_rdataset_disassociate(sigrdataset);
3606                         if (node != NULL)
3607                                 dns_db_detachnode(db, &node);
3608
3609                         /*
3610                          * We don't have any root server hints, but
3611                          * we may have working forwarders, so try to
3612                          * recurse anyway.
3613                          */
3614                         if (RECURSIONOK(client)) {
3615                                 result = query_recurse(client, qtype,
3616                                                        NULL, NULL, resuming);
3617                                 if (result == ISC_R_SUCCESS)
3618                                         client->query.attributes |=
3619                                                 NS_QUERYATTR_RECURSING;
3620                                 else if (result == DNS_R_DUPLICATE ||
3621                                          result == DNS_R_DROP) {
3622                                         /* Duplicate query. */
3623                                         QUERY_ERROR(result);
3624                                 } else {
3625                                         /* Unable to recurse. */
3626                                         QUERY_ERROR(DNS_R_SERVFAIL);
3627                                 }
3628                                 goto cleanup;
3629                         } else {
3630                                 /* Unable to give root server referral. */
3631                                 QUERY_ERROR(DNS_R_SERVFAIL);
3632                                 goto cleanup;
3633                         }
3634                 }
3635                 /*
3636                  * XXXRTH  We should trigger root server priming here.
3637                  */
3638                 /* FALLTHROUGH */
3639         case DNS_R_DELEGATION:
3640                 authoritative = ISC_FALSE;
3641                 if (is_zone) {
3642                         /*
3643                          * Look to see if we are authoritative for the
3644                          * child zone if the query type is DS.
3645                          */
3646                         if (!RECURSIONOK(client) &&
3647                             (options & DNS_GETDB_NOEXACT) != 0 &&
3648                             qtype == dns_rdatatype_ds) {
3649                                 dns_db_t *tdb = NULL;
3650                                 dns_zone_t *tzone = NULL;
3651                                 dns_dbversion_t *tversion = NULL;
3652                                 result = query_getzonedb(client,
3653                                                          client->query.qname,
3654                                                          qtype,
3655                                                          DNS_GETDB_PARTIAL,
3656                                                          &tzone, &tdb,
3657                                                          &tversion);
3658                                 if (result == ISC_R_SUCCESS) {
3659                                         options &= ~DNS_GETDB_NOEXACT;
3660                                         query_putrdataset(client, &rdataset);
3661                                         if (sigrdataset != NULL)
3662                                                 query_putrdataset(client,
3663                                                                   &sigrdataset);
3664                                         if (fname != NULL)
3665                                                 query_releasename(client,
3666                                                                   &fname);
3667                                         if (node != NULL)
3668                                                 dns_db_detachnode(db, &node);
3669                                         if (db != NULL)
3670                                                 dns_db_detach(&db);
3671                                         if (zone != NULL)
3672                                                 dns_zone_detach(&zone);
3673                                         version = tversion;
3674                                         db = tdb;
3675                                         zone = tzone;
3676                                         authoritative = ISC_TRUE;
3677                                         goto db_find;
3678                                 }
3679                                 if (tdb != NULL)
3680                                         dns_db_detach(&tdb);
3681                                 if (tzone != NULL)
3682                                         dns_zone_detach(&tzone);
3683                         }
3684                         /*
3685                          * We're authoritative for an ancestor of QNAME.
3686                          */
3687                         if (!USECACHE(client) || !RECURSIONOK(client)) {
3688                                 /*
3689                                  * If we don't have a cache, this is the best
3690                                  * answer.
3691                                  *
3692                                  * If the client is making a nonrecursive
3693                                  * query we always give out the authoritative
3694                                  * delegation.  This way even if we get
3695                                  * junk in our cache, we won't fail in our
3696                                  * role as the delegating authority if another
3697                                  * nameserver asks us about a delegated
3698                                  * subzone.
3699                                  *
3700                                  * We enable the retrieval of glue for this
3701                                  * database by setting client->query.gluedb.
3702                                  */
3703                                 client->query.gluedb = db;
3704                                 client->query.isreferral = ISC_TRUE;
3705                                 /*
3706                                  * We must ensure NOADDITIONAL is off,
3707                                  * because the generation of
3708                                  * additional data is required in
3709                                  * delegations.
3710                                  */
3711                                 client->query.attributes &=
3712                                         ~NS_QUERYATTR_NOADDITIONAL;
3713                                 if (sigrdataset != NULL)
3714                                         sigrdatasetp = &sigrdataset;
3715                                 else
3716                                         sigrdatasetp = NULL;
3717                                 query_addrrset(client, &fname,
3718                                                &rdataset, sigrdatasetp,
3719                                                dbuf, DNS_SECTION_AUTHORITY);
3720                                 client->query.gluedb = NULL;
3721                                 if (WANTDNSSEC(client) && dns_db_issecure(db))
3722                                         query_addds(client, db, node, version);
3723                         } else {
3724                                 /*
3725                                  * We might have a better answer or delegation
3726                                  * in the cache.  We'll remember the current
3727                                  * values of fname, rdataset, and sigrdataset.
3728                                  * We'll then go looking for QNAME in the
3729                                  * cache.  If we find something better, we'll
3730                                  * use it instead.
3731                                  */
3732                                 query_keepname(client, fname, dbuf);
3733                                 zdb = db;
3734                                 zfname = fname;
3735                                 fname = NULL;
3736                                 zrdataset = rdataset;
3737                                 rdataset = NULL;
3738                                 zsigrdataset = sigrdataset;
3739                                 sigrdataset = NULL;
3740                                 dns_db_detachnode(db, &node);
3741                                 version = NULL;
3742                                 db = NULL;
3743                                 dns_db_attach(client->view->cachedb, &db);
3744                                 is_zone = ISC_FALSE;
3745                                 goto db_find;
3746                         }
3747                 } else {
3748                         if (zfname != NULL &&
3749                             !dns_name_issubdomain(fname, zfname)) {
3750                                 /*
3751                                  * We've already got a delegation from
3752                                  * authoritative data, and it is better
3753                                  * than what we found in the cache.  Use
3754                                  * it instead of the cache delegation.
3755                                  */
3756                                 query_releasename(client, &fname);
3757                                 fname = zfname;
3758                                 zfname = NULL;
3759                                 /*
3760                                  * We've already done query_keepname() on
3761                                  * zfname, so we must set dbuf to NULL to
3762                                  * prevent query_addrrset() from trying to
3763                                  * call query_keepname() again.
3764                                  */
3765                                 dbuf = NULL;
3766                                 query_putrdataset(client, &rdataset);
3767                                 if (sigrdataset != NULL)
3768                                         query_putrdataset(client,
3769                                                           &sigrdataset);
3770                                 rdataset = zrdataset;
3771                                 zrdataset = NULL;
3772                                 sigrdataset = zsigrdataset;
3773                                 zsigrdataset = NULL;
3774                                 /*
3775                                  * We don't clean up zdb here because we
3776                                  * may still need it.  It will get cleaned
3777                                  * up by the main cleanup code.
3778                                  */
3779                         }
3780
3781                         if (RECURSIONOK(client)) {
3782                                 /*
3783                                  * Recurse!
3784                                  */
3785                                 if (dns_rdatatype_atparent(type))
3786                                         result = query_recurse(client, qtype,
3787                                                                NULL, NULL,
3788                                                                resuming);
3789                                 else
3790                                         result = query_recurse(client, qtype,
3791                                                                fname, rdataset,
3792                                                                resuming);
3793                                 if (result == ISC_R_SUCCESS)
3794                                         client->query.attributes |=
3795                                                 NS_QUERYATTR_RECURSING;
3796                                 else if (result == DNS_R_DUPLICATE ||
3797                                          result == DNS_R_DROP)
3798                                         QUERY_ERROR(result);
3799                                 else
3800                                         QUERY_ERROR(DNS_R_SERVFAIL);
3801                         } else {
3802                                 /*
3803                                  * This is the best answer.
3804                                  */
3805                                 client->query.attributes |=
3806                                         NS_QUERYATTR_CACHEGLUEOK;
3807                                 client->query.gluedb = zdb;
3808                                 client->query.isreferral = ISC_TRUE;
3809                                 /*
3810                                  * We must ensure NOADDITIONAL is off,
3811                                  * because the generation of
3812                                  * additional data is required in
3813                                  * delegations.
3814                                  */
3815                                 client->query.attributes &=
3816                                         ~NS_QUERYATTR_NOADDITIONAL;
3817                                 if (sigrdataset != NULL)
3818                                         sigrdatasetp = &sigrdataset;
3819                                 else
3820                                         sigrdatasetp = NULL;
3821                                 query_addrrset(client, &fname,
3822                                                &rdataset, sigrdatasetp,
3823                                                dbuf, DNS_SECTION_AUTHORITY);
3824                                 client->query.gluedb = NULL;
3825                                 client->query.attributes &=
3826                                         ~NS_QUERYATTR_CACHEGLUEOK;
3827                                 if (WANTDNSSEC(client))
3828                                         query_addds(client, db, node, version);
3829                         }
3830                 }
3831                 goto cleanup;
3832         case DNS_R_EMPTYNAME:
3833                 result = DNS_R_NXRRSET;
3834                 /* FALLTHROUGH */
3835         case DNS_R_NXRRSET:
3836                 INSIST(is_zone);
3837                 if (dns_rdataset_isassociated(rdataset)) {
3838                         /*
3839                          * If we've got a NSEC record, we need to save the
3840                          * name now because we're going call query_addsoa()
3841                          * below, and it needs to use the name buffer.
3842                          */
3843                         query_keepname(client, fname, dbuf);
3844                 } else {
3845                         /*
3846                          * We're not going to use fname, and need to release
3847                          * our hold on the name buffer so query_addsoa()
3848                          * may use it.
3849                          */
3850                         query_releasename(client, &fname);
3851                 }
3852                 /*
3853                  * Add SOA.
3854                  */
3855                 result = query_addsoa(client, db, version, ISC_FALSE);
3856                 if (result != ISC_R_SUCCESS) {
3857                         QUERY_ERROR(result);
3858                         goto cleanup;
3859                 }
3860                 /*
3861                  * Add NSEC record if we found one.
3862                  */
3863                 if (WANTDNSSEC(client)) {
3864                         if (dns_rdataset_isassociated(rdataset))
3865                                 query_addnxrrsetnsec(client, db, version,
3866                                                      &fname, &rdataset,
3867                                                      &sigrdataset);
3868                 }
3869                 goto cleanup;
3870         case DNS_R_EMPTYWILD:
3871                 empty_wild = ISC_TRUE;
3872                 /* FALLTHROUGH */
3873         case DNS_R_NXDOMAIN:
3874                 INSIST(is_zone);
3875                 if (dns_rdataset_isassociated(rdataset)) {
3876                         /*
3877                          * If we've got a NSEC record, we need to save the
3878                          * name now because we're going call query_addsoa()
3879                          * below, and it needs to use the name buffer.
3880                          */
3881                         query_keepname(client, fname, dbuf);
3882                 } else {
3883                         /*
3884                          * We're not going to use fname, and need to release
3885                          * our hold on the name buffer so query_addsoa()
3886                          * may use it.
3887                          */
3888                         query_releasename(client, &fname);
3889                 }
3890                 /*
3891                  * Add SOA.  If the query was for a SOA record force the
3892                  * ttl to zero so that it is possible for clients to find
3893                  * the containing zone of an arbitrary name with a stub
3894                  * resolver and not have it cached.
3895                  */
3896                 if (qtype == dns_rdatatype_soa &&
3897 #ifdef DLZ
3898                     zone != NULL &&
3899 #endif
3900                     dns_zone_getzeronosoattl(zone))
3901                         result = query_addsoa(client, db, version, ISC_TRUE);
3902                 else
3903                         result = query_addsoa(client, db, version, ISC_FALSE);
3904                 if (result != ISC_R_SUCCESS) {
3905                         QUERY_ERROR(result);
3906                         goto cleanup;
3907                 }
3908                 /*
3909                  * Add NSEC record if we found one.
3910                  */
3911                 if (dns_rdataset_isassociated(rdataset)) {
3912                         if (WANTDNSSEC(client)) {
3913                                 query_addrrset(client, &fname, &rdataset,
3914                                                &sigrdataset,
3915                                                NULL, DNS_SECTION_AUTHORITY);
3916                                 query_addwildcardproof(client, db, version,
3917                                                        client->query.qname,
3918                                                        ISC_FALSE);
3919                         }
3920                 }
3921                 /*
3922                  * Set message rcode.
3923                  */
3924                 if (empty_wild)
3925                         client->message->rcode = dns_rcode_noerror;
3926                 else
3927                         client->message->rcode = dns_rcode_nxdomain;
3928                 goto cleanup;
3929         case DNS_R_NCACHENXDOMAIN:
3930         case DNS_R_NCACHENXRRSET:
3931                 INSIST(!is_zone);
3932                 authoritative = ISC_FALSE;
3933                 /*
3934                  * Set message rcode, if required.
3935                  */
3936                 if (result == DNS_R_NCACHENXDOMAIN)
3937                         client->message->rcode = dns_rcode_nxdomain;
3938                 /*
3939                  * Look for RFC 1918 leakage from Internet.
3940                  */
3941                 if (result == DNS_R_NCACHENXDOMAIN &&
3942                     qtype == dns_rdatatype_ptr &&
3943                     client->message->rdclass == dns_rdataclass_in &&
3944                     dns_name_countlabels(fname) == 7)
3945                         warn_rfc1918(client, fname, rdataset);
3946                 /*
3947                  * We don't call query_addrrset() because we don't need any
3948                  * of its extra features (and things would probably break!).
3949                  */
3950                 query_keepname(client, fname, dbuf);
3951                 dns_message_addname(client->message, fname,
3952                                     DNS_SECTION_AUTHORITY);
3953                 ISC_LIST_APPEND(fname->list, rdataset, link);
3954                 fname = NULL;
3955                 rdataset = NULL;
3956                 goto cleanup;
3957         case DNS_R_CNAME:
3958                 /*
3959                  * Keep a copy of the rdataset.  We have to do this because
3960                  * query_addrrset may clear 'rdataset' (to prevent the
3961                  * cleanup code from cleaning it up).
3962                  */
3963                 trdataset = rdataset;
3964                 /*
3965                  * Add the CNAME to the answer section.
3966                  */
3967                 if (sigrdataset != NULL)
3968                         sigrdatasetp = &sigrdataset;
3969                 else
3970                         sigrdatasetp = NULL;
3971                 if (WANTDNSSEC(client) &&
3972                     (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
3973                 {
3974                         dns_fixedname_init(&wildcardname);
3975                         dns_name_copy(fname, dns_fixedname_name(&wildcardname),
3976                                       NULL);
3977                         need_wildcardproof = ISC_TRUE;
3978                 }
3979                 if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0 &&
3980                      WANTDNSSEC(client))
3981                         noqname = rdataset;
3982                 else
3983                         noqname = NULL;
3984                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
3985                                DNS_SECTION_ANSWER);
3986                 if (noqname != NULL)
3987                         query_addnoqnameproof(client, noqname);
3988                 /*
3989                  * We set the PARTIALANSWER attribute so that if anything goes
3990                  * wrong later on, we'll return what we've got so far.
3991                  */
3992                 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
3993                 /*
3994                  * Reset qname to be the target name of the CNAME and restart
3995                  * the query.
3996                  */
3997                 tname = NULL;
3998                 result = dns_message_gettempname(client->message, &tname);
3999                 if (result != ISC_R_SUCCESS)
4000                         goto cleanup;
4001                 result = dns_rdataset_first(trdataset);
4002                 if (result != ISC_R_SUCCESS) {
4003                         dns_message_puttempname(client->message, &tname);
4004                         goto cleanup;
4005                 }
4006                 dns_rdataset_current(trdataset, &rdata);
4007                 result = dns_rdata_tostruct(&rdata, &cname, NULL);
4008                 dns_rdata_reset(&rdata);
4009                 if (result != ISC_R_SUCCESS) {
4010                         dns_message_puttempname(client->message, &tname);
4011                         goto cleanup;
4012                 }
4013                 dns_name_init(tname, NULL);
4014                 result = dns_name_dup(&cname.cname, client->mctx, tname);
4015                 if (result != ISC_R_SUCCESS) {
4016                         dns_message_puttempname(client->message, &tname);
4017                         dns_rdata_freestruct(&cname);
4018                         goto cleanup;
4019                 }
4020                 dns_rdata_freestruct(&cname);
4021                 ns_client_qnamereplace(client, tname);
4022                 want_restart = ISC_TRUE;
4023                 if (!WANTRECURSION(client))
4024                         options |= DNS_GETDB_NOLOG;
4025                 goto addauth;
4026         case DNS_R_DNAME:
4027                 /*
4028                  * Compare the current qname to the found name.  We need
4029                  * to know how many labels and bits are in common because
4030                  * we're going to have to split qname later on.
4031                  */
4032                 namereln = dns_name_fullcompare(client->query.qname, fname,
4033                                                 &order, &nlabels);
4034                 INSIST(namereln == dns_namereln_subdomain);
4035                 /*
4036                  * Keep a copy of the rdataset.  We have to do this because
4037                  * query_addrrset may clear 'rdataset' (to prevent the
4038                  * cleanup code from cleaning it up).
4039                  */
4040                 trdataset = rdataset;
4041                 /*
4042                  * Add the DNAME to the answer section.
4043                  */
4044                 if (sigrdataset != NULL)
4045                         sigrdatasetp = &sigrdataset;
4046                 else
4047                         sigrdatasetp = NULL;
4048                 if (WANTDNSSEC(client) &&
4049                     (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4050                 {
4051                         dns_fixedname_init(&wildcardname);
4052                         dns_name_copy(fname, dns_fixedname_name(&wildcardname),
4053                                       NULL);
4054                         need_wildcardproof = ISC_TRUE;
4055                 }
4056                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4057                                DNS_SECTION_ANSWER);
4058                 /*
4059                  * We set the PARTIALANSWER attribute so that if anything goes
4060                  * wrong later on, we'll return what we've got so far.
4061                  */
4062                 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
4063                 /*
4064                  * Get the target name of the DNAME.
4065                  */
4066                 tname = NULL;
4067                 result = dns_message_gettempname(client->message, &tname);
4068                 if (result != ISC_R_SUCCESS)
4069                         goto cleanup;
4070                 result = dns_rdataset_first(trdataset);
4071                 if (result != ISC_R_SUCCESS) {
4072                         dns_message_puttempname(client->message, &tname);
4073                         goto cleanup;
4074                 }
4075                 dns_rdataset_current(trdataset, &rdata);
4076                 result = dns_rdata_tostruct(&rdata, &dname, NULL);
4077                 dns_rdata_reset(&rdata);
4078                 if (result != ISC_R_SUCCESS) {
4079                         dns_message_puttempname(client->message, &tname);
4080                         goto cleanup;
4081                 }
4082                 dns_name_init(tname, NULL);
4083                 dns_name_clone(&dname.dname, tname);
4084                 dns_rdata_freestruct(&dname);
4085                 /*
4086                  * Construct the new qname.
4087                  */
4088                 dns_fixedname_init(&fixed);
4089                 prefix = dns_fixedname_name(&fixed);
4090                 dns_name_split(client->query.qname, nlabels, prefix, NULL);
4091                 INSIST(fname == NULL);
4092                 dbuf = query_getnamebuf(client);
4093                 if (dbuf == NULL) {
4094                         dns_message_puttempname(client->message, &tname);
4095                         goto cleanup;
4096                 }
4097                 fname = query_newname(client, dbuf, &b);
4098                 if (fname == NULL) {
4099                         dns_message_puttempname(client->message, &tname);
4100                         goto cleanup;
4101                 }
4102                 result = dns_name_concatenate(prefix, tname, fname, NULL);
4103                 if (result != ISC_R_SUCCESS) {
4104                         dns_message_puttempname(client->message, &tname);
4105                         if (result == ISC_R_NOSPACE) {
4106                                 /*
4107                                  * RFC2672, section 4.1, subsection 3c says
4108                                  * we should return YXDOMAIN if the constructed
4109                                  * name would be too long.
4110                                  */
4111                                 client->message->rcode = dns_rcode_yxdomain;
4112                         }
4113                         goto cleanup;
4114                 }
4115                 query_keepname(client, fname, dbuf);
4116                 /*
4117                  * Synthesize a CNAME for this DNAME.
4118                  *
4119                  * We want to synthesize a CNAME since if we don't
4120                  * then older software that doesn't understand DNAME
4121                  * will not chain like it should.
4122                  *
4123                  * We do not try to synthesize a signature because we hope
4124                  * that security aware servers will understand DNAME.  Also,
4125                  * even if we had an online key, making a signature
4126                  * on-the-fly is costly, and not really legitimate anyway
4127                  * since the synthesized CNAME is NOT in the zone.
4128                  */
4129                 dns_name_init(tname, NULL);
4130                 (void)query_addcnamelike(client, client->query.qname, fname,
4131                                          trdataset->trust, &tname,
4132                                          dns_rdatatype_cname);
4133                 if (tname != NULL)
4134                         dns_message_puttempname(client->message, &tname);
4135                 /*
4136                  * Switch to the new qname and restart.
4137                  */
4138                 ns_client_qnamereplace(client, fname);
4139                 fname = NULL;
4140                 want_restart = ISC_TRUE;
4141                 if (!WANTRECURSION(client))
4142                         options |= DNS_GETDB_NOLOG;
4143                 goto addauth;
4144         default:
4145                 /*
4146                  * Something has gone wrong.
4147                  */
4148                 QUERY_ERROR(DNS_R_SERVFAIL);
4149                 goto cleanup;
4150         }
4151
4152         if (WANTDNSSEC(client) &&
4153             (fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
4154         {
4155                 dns_fixedname_init(&wildcardname);
4156                 dns_name_copy(fname, dns_fixedname_name(&wildcardname), NULL);
4157                 need_wildcardproof = ISC_TRUE;
4158         }
4159
4160         if (type == dns_rdatatype_any) {
4161                 /*
4162                  * XXXRTH  Need to handle zonecuts with special case
4163                  * code.
4164                  */
4165                 n = 0;
4166                 rdsiter = NULL;
4167                 result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
4168                 if (result != ISC_R_SUCCESS) {
4169                         QUERY_ERROR(DNS_R_SERVFAIL);
4170                         goto cleanup;
4171                 }
4172                 /*
4173                  * Calling query_addrrset() with a non-NULL dbuf is going
4174                  * to either keep or release the name.  We don't want it to
4175                  * release fname, since we may have to call query_addrrset()
4176                  * more than once.  That means we have to call query_keepname()
4177                  * now, and pass a NULL dbuf to query_addrrset().
4178                  *
4179                  * If we do a query_addrrset() below, we must set fname to
4180                  * NULL before leaving this block, otherwise we might try to
4181                  * cleanup fname even though we're using it!
4182                  */
4183                 query_keepname(client, fname, dbuf);
4184                 tname = fname;
4185                 result = dns_rdatasetiter_first(rdsiter);
4186                 while (result == ISC_R_SUCCESS) {
4187                         dns_rdatasetiter_current(rdsiter, rdataset);
4188                         if ((qtype == dns_rdatatype_any ||
4189                              rdataset->type == qtype) && rdataset->type != 0) {
4190                                 query_addrrset(client,
4191                                                fname != NULL ? &fname : &tname,
4192                                                &rdataset, NULL,
4193                                                NULL, DNS_SECTION_ANSWER);
4194                                 n++;
4195                                 INSIST(tname != NULL);
4196                                 /*
4197                                  * rdataset is non-NULL only in certain pathological
4198                                  * cases involving DNAMEs.
4199                                  */
4200                                 if (rdataset != NULL)
4201                                         query_putrdataset(client, &rdataset);
4202                                 rdataset = query_newrdataset(client);
4203                                 if (rdataset == NULL)
4204                                         break;
4205                         } else {
4206                                 /*
4207                                  * We're not interested in this rdataset.
4208                                  */
4209                                 dns_rdataset_disassociate(rdataset);
4210                         }
4211                         result = dns_rdatasetiter_next(rdsiter);
4212                 }
4213
4214                 if (fname != NULL)
4215                         dns_message_puttempname(client->message, &fname);
4216
4217                 if (n == 0) {
4218                         /*
4219                          * We didn't match any rdatasets.
4220                          */
4221                         if (qtype == dns_rdatatype_rrsig &&
4222                             result == ISC_R_NOMORE) {
4223                                 /*
4224                                  * XXXRTH  If this is a secure zone and we
4225                                  * didn't find any SIGs, we should generate
4226                                  * an error unless we were searching for
4227                                  * glue.  Ugh.
4228                                  */
4229                                 if (!is_zone) {
4230                                         authoritative = ISC_FALSE;
4231                                         dns_rdatasetiter_destroy(&rdsiter);
4232                                         if (RECURSIONOK(client)) {
4233                                                 result = query_recurse(client,
4234                                                                        qtype,
4235                                                                        NULL,
4236                                                                        NULL,
4237                                                                        resuming);
4238                                                 if (result == ISC_R_SUCCESS)
4239                                                     client->query.attributes |=
4240                                                         NS_QUERYATTR_RECURSING;
4241                                                 else
4242                                                     QUERY_ERROR(DNS_R_SERVFAIL);                                        }
4243                                         goto addauth;
4244                                 }
4245                                 /*
4246                                  * We were searching for SIG records in
4247                                  * a nonsecure zone.  Send a "no error,
4248                                  * no data" response.
4249                                  */
4250                                 /*
4251                                  * Add SOA.
4252                                  */
4253                                 result = query_addsoa(client, db, version,
4254                                                       ISC_FALSE);
4255                                 if (result == ISC_R_SUCCESS)
4256                                         result = ISC_R_NOMORE;
4257                         } else {
4258                                 /*
4259                                  * Something went wrong.
4260                                  */
4261                                 result = DNS_R_SERVFAIL;
4262                         }
4263                 }
4264                 dns_rdatasetiter_destroy(&rdsiter);
4265                 if (result != ISC_R_NOMORE) {
4266                         QUERY_ERROR(DNS_R_SERVFAIL);
4267                         goto cleanup;
4268                 }
4269         } else {
4270                 /*
4271                  * This is the "normal" case -- an ordinary question to which
4272                  * we know the answer.
4273                  */
4274                 if (sigrdataset != NULL)
4275                         sigrdatasetp = &sigrdataset;
4276                 else
4277                         sigrdatasetp = NULL;
4278                 if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0 &&
4279                      WANTDNSSEC(client))
4280                         noqname = rdataset;
4281                 else
4282                         noqname = NULL;
4283                 /*
4284                  * BIND 8 priming queries need the additional section.
4285                  */
4286                 if (is_zone && qtype == dns_rdatatype_ns &&
4287                     dns_name_equal(client->query.qname, dns_rootname))
4288                         client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
4289
4290                 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
4291                                DNS_SECTION_ANSWER);
4292                 if (noqname != NULL)
4293                         query_addnoqnameproof(client, noqname);
4294                 /*
4295                  * We shouldn't ever fail to add 'rdataset'
4296                  * because it's already in the answer.
4297                  */
4298                 INSIST(rdataset == NULL);
4299         }
4300
4301  addauth:
4302         CTRACE("query_find: addauth");
4303         /*
4304          * Add NS records to the authority section (if we haven't already
4305          * added them to the answer section).
4306          */
4307         if (!want_restart && !NOAUTHORITY(client)) {
4308                 if (is_zone) {
4309                         if (!((qtype == dns_rdatatype_ns ||
4310                                qtype == dns_rdatatype_any) &&
4311                               dns_name_equal(client->query.qname,
4312                                              dns_db_origin(db))))
4313                                 (void)query_addns(client, db, version);
4314                 } else if (qtype != dns_rdatatype_ns) {
4315                         if (fname != NULL)
4316                                 query_releasename(client, &fname);
4317                         query_addbestns(client);
4318                 }
4319         }
4320
4321         /*
4322          * Add NSEC records to the authority section if they're needed for
4323          * DNSSEC wildcard proofs.
4324          */
4325         if (need_wildcardproof && dns_db_issecure(db))
4326                 query_addwildcardproof(client, db, version,
4327                                        dns_fixedname_name(&wildcardname),
4328                                        ISC_TRUE);
4329  cleanup:
4330         CTRACE("query_find: cleanup");
4331         /*
4332          * General cleanup.
4333          */
4334         if (rdataset != NULL)
4335                 query_putrdataset(client, &rdataset);
4336         if (sigrdataset != NULL)
4337                 query_putrdataset(client, &sigrdataset);
4338         if (fname != NULL)
4339                 query_releasename(client, &fname);
4340         if (node != NULL)
4341                 dns_db_detachnode(db, &node);
4342         if (db != NULL)
4343                 dns_db_detach(&db);
4344         if (zone != NULL)
4345                 dns_zone_detach(&zone);
4346         if (zdb != NULL) {
4347                 query_putrdataset(client, &zrdataset);
4348                 if (zsigrdataset != NULL)
4349                         query_putrdataset(client, &zsigrdataset);
4350                 if (zfname != NULL)
4351                         query_releasename(client, &zfname);
4352                 dns_db_detach(&zdb);
4353         }
4354         if (event != NULL)
4355                 isc_event_free(ISC_EVENT_PTR(&event));
4356
4357         /*
4358          * AA bit.
4359          */
4360         if (client->query.restarts == 0 && !authoritative) {
4361                 /*
4362                  * We're not authoritative, so we must ensure the AA bit
4363                  * isn't set.
4364                  */
4365                 client->message->flags &= ~DNS_MESSAGEFLAG_AA;
4366         }
4367
4368         /*
4369          * Restart the query?
4370          */
4371         if (want_restart && client->query.restarts < MAX_RESTARTS) {
4372                 client->query.restarts++;
4373                 goto restart;
4374         }
4375
4376         if (eresult != ISC_R_SUCCESS &&
4377             (!PARTIALANSWER(client) || WANTRECURSION(client))) {
4378                 if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) {
4379                         /*
4380                          * This was a duplicate query that we are
4381                          * recursing on.  Don't send a response now.
4382                          * The original query will still cause a response.
4383                          */
4384                         query_next(client, eresult);
4385                 } else {
4386                         /*
4387                          * If we don't have any answer to give the client,
4388                          * or if the client requested recursion and thus wanted
4389                          * the complete answer, send an error response.
4390                          */
4391                         query_error(client, eresult);
4392                 }
4393                 ns_client_detach(&client);
4394         } else if (!RECURSING(client)) {
4395                 /*
4396                  * We are done.  Set up sortlist data for the message
4397                  * rendering code, make a final tweak to the AA bit if the
4398                  * auth-nxdomain config option says so, then render and
4399                  * send the response.
4400                  */
4401                 setup_query_sortlist(client);
4402
4403                 /*
4404                  * If this is a referral and the answer to the question
4405                  * is in the glue sort it to the start of the additional
4406                  * section.
4407                  */
4408                 if (client->message->counts[DNS_SECTION_ANSWER] == 0 &&
4409                     client->message->rcode == dns_rcode_noerror &&
4410                     (qtype == dns_rdatatype_a || qtype == dns_rdatatype_aaaa))
4411                         answer_in_glue(client, qtype);
4412
4413                 if (client->message->rcode == dns_rcode_nxdomain &&
4414                     client->view->auth_nxdomain == ISC_TRUE)
4415                         client->message->flags |= DNS_MESSAGEFLAG_AA;
4416
4417                 query_send(client);
4418                 ns_client_detach(&client);
4419         }
4420         CTRACE("query_find: done");
4421 }
4422
4423 static inline void
4424 log_query(ns_client_t *client) {
4425         char namebuf[DNS_NAME_FORMATSIZE];
4426         char typename[DNS_RDATATYPE_FORMATSIZE];
4427         char classname[DNS_RDATACLASS_FORMATSIZE];
4428         dns_rdataset_t *rdataset;
4429         int level = ISC_LOG_INFO;
4430
4431         if (! isc_log_wouldlog(ns_g_lctx, level))
4432                 return;
4433
4434         rdataset = ISC_LIST_HEAD(client->query.qname->list);
4435         INSIST(rdataset != NULL);
4436         dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
4437         dns_rdataclass_format(rdataset->rdclass, classname, sizeof(classname));
4438         dns_rdatatype_format(rdataset->type, typename, sizeof(typename));
4439
4440         ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
4441                       level, "query: %s %s %s %s%s%s", namebuf, classname,
4442                       typename, WANTRECURSION(client) ? "+" : "-",
4443                       (client->signer != NULL) ? "S": "",
4444                       (client->opt != NULL) ? "E" : "");
4445 }
4446
4447 void
4448 ns_query_start(ns_client_t *client) {
4449         isc_result_t result;
4450         dns_message_t *message = client->message;
4451         dns_rdataset_t *rdataset;
4452         ns_client_t *qclient;
4453         dns_rdatatype_t qtype;
4454         isc_boolean_t want_ad;
4455
4456         CTRACE("ns_query_start");
4457
4458         /*
4459          * Ensure that appropriate cleanups occur.
4460          */
4461         client->next = query_next_callback;
4462
4463         /*
4464          * Behave as if we don't support DNSSEC if not enabled.
4465          */
4466         if (!client->view->enablednssec) {
4467                 message->flags &= ~DNS_MESSAGEFLAG_CD;
4468                 client->extflags &= ~DNS_MESSAGEEXTFLAG_DO;
4469                 if (client->opt != NULL)
4470                         client->opt->ttl &= ~DNS_MESSAGEEXTFLAG_DO;
4471         }
4472
4473         if ((message->flags & DNS_MESSAGEFLAG_RD) != 0)
4474                 client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
4475
4476         if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0)
4477                 client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
4478
4479         if (client->view->minimalresponses)
4480                 client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
4481                                              NS_QUERYATTR_NOADDITIONAL);
4482
4483         if ((client->view->cachedb == NULL)
4484             || (!client->view->additionalfromcache)) {
4485                 /*
4486                  * We don't have a cache.  Turn off cache support and
4487                  * recursion.
4488                  */
4489                 client->query.attributes &=
4490                         ~(NS_QUERYATTR_RECURSIONOK|NS_QUERYATTR_CACHEOK);
4491         } else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
4492                    (message->flags & DNS_MESSAGEFLAG_RD) == 0) {
4493                 /*
4494                  * If the client isn't allowed to recurse (due to
4495                  * "recursion no", the allow-recursion ACL, or the
4496                  * lack of a resolver in this view), or if it
4497                  * doesn't want recursion, turn recursion off.
4498                  */
4499                 client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
4500         }
4501
4502         /*
4503          * Get the question name.
4504          */
4505         result = dns_message_firstname(message, DNS_SECTION_QUESTION);
4506         if (result != ISC_R_SUCCESS) {
4507                 query_error(client, result);
4508                 return;
4509         }
4510         dns_message_currentname(message, DNS_SECTION_QUESTION,
4511                                 &client->query.qname);
4512         client->query.origqname = client->query.qname;
4513         result = dns_message_nextname(message, DNS_SECTION_QUESTION);
4514         if (result != ISC_R_NOMORE) {
4515                 if (result == ISC_R_SUCCESS) {
4516                         /*
4517                          * There's more than one QNAME in the question
4518                          * section.
4519                          */
4520                         query_error(client, DNS_R_FORMERR);
4521                 } else
4522                         query_error(client, result);
4523                 return;
4524         }
4525
4526         if (ns_g_server->log_queries)
4527                 log_query(client);
4528
4529         /*
4530          * Check for multiple question queries, since edns1 is dead.
4531          */
4532         if (message->counts[DNS_SECTION_QUESTION] > 1) {
4533                 query_error(client, DNS_R_FORMERR);
4534                 return;
4535         }
4536
4537         /*
4538          * Check for meta-queries like IXFR and AXFR.
4539          */
4540         rdataset = ISC_LIST_HEAD(client->query.qname->list);
4541         INSIST(rdataset != NULL);
4542         qtype = rdataset->type;
4543         if (dns_rdatatype_ismeta(qtype)) {
4544                 switch (qtype) {
4545                 case dns_rdatatype_any:
4546                         break; /* Let query_find handle it. */
4547                 case dns_rdatatype_ixfr:
4548                 case dns_rdatatype_axfr:
4549                         ns_xfr_start(client, rdataset->type);
4550                         return;
4551                 case dns_rdatatype_maila:
4552                 case dns_rdatatype_mailb:
4553                         query_error(client, DNS_R_NOTIMP);
4554                         return;
4555                 case dns_rdatatype_tkey:
4556                         result = dns_tkey_processquery(client->message,
4557                                                 ns_g_server->tkeyctx,
4558                                                 client->view->dynamickeys);
4559                         if (result == ISC_R_SUCCESS)
4560                                 query_send(client);
4561                         else
4562                                 query_error(client, result);
4563                         return;
4564                 default: /* TSIG, etc. */
4565                         query_error(client, DNS_R_FORMERR);
4566                         return;
4567                 }
4568         }
4569
4570         /*
4571          * If the client has requested that DNSSEC checking be disabled,
4572          * allow lookups to return pending data and instruct the resolver
4573          * to return data before validation has completed.
4574          *
4575          * We don't need to set DNS_DBFIND_PENDINGOK when validation is
4576          * disabled as there will be no pending data.
4577          */
4578         if (message->flags & DNS_MESSAGEFLAG_CD ||
4579             qtype == dns_rdatatype_rrsig)
4580         {
4581                 client->query.dboptions |= DNS_DBFIND_PENDINGOK;
4582                 client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
4583         } else if (!client->view->enablevalidation)
4584                 client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
4585
4586         /*
4587          * Allow glue NS records to be added to the authority section
4588          * if the answer is secure.
4589          */
4590         if (message->flags & DNS_MESSAGEFLAG_CD)
4591                 client->query.attributes &= ~NS_QUERYATTR_SECURE;
4592
4593         /*
4594          * Set 'want_ad' if the client has set AD in the query.
4595          * This allows AD to be returned on queries without DO set.
4596          */
4597         if ((message->flags & DNS_MESSAGEFLAG_AD) != 0)
4598                 want_ad = ISC_TRUE;
4599         else
4600                 want_ad = ISC_FALSE;
4601
4602         /*
4603          * This is an ordinary query.
4604          */
4605         result = dns_message_reply(message, ISC_TRUE);
4606         if (result != ISC_R_SUCCESS) {
4607                 query_next(client, result);
4608                 return;
4609         }
4610
4611         /*
4612          * Assume authoritative response until it is known to be
4613          * otherwise.
4614          */
4615         message->flags |= DNS_MESSAGEFLAG_AA;
4616
4617         /*
4618          * Set AD.  We must clear it if we add non-validated data to a
4619          * response.
4620          */
4621         if (WANTDNSSEC(client) || want_ad)
4622                 message->flags |= DNS_MESSAGEFLAG_AD;
4623
4624         qclient = NULL;
4625         ns_client_attach(client, &qclient);
4626         query_find(qclient, NULL, qtype);
4627 }