bind - Applied DragonFly specific patches for 9.5.2
[dragonfly.git] / contrib / bind-9.5.2 / bin / named / query.c
1 /*
2  * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: query.c,v 1.298.48.15 2009/09/16 22:28:52 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <isc/mem.h>
27 #include <isc/stats.h>
28 #include <isc/util.h>
29
30 #include <dns/adb.h>
31 #include <dns/byaddr.h>
32 #include <dns/db.h>
33 #ifdef DLZ
34 #include <dns/dlz.h>
35 #endif
36 #include <dns/dnssec.h>
37 #include <dns/events.h>
38 #include <dns/message.h>
39 #include <dns/ncache.h>
40 #include <dns/order.h>
41 #include <dns/rdata.h>
42 #include <dns/rdataclass.h>
43 #include <dns/rdatalist.h>
44 #include <dns/rdataset.h>
45 #include <dns/rdatasetiter.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/rdatatype.h>
48 #include <dns/resolver.h>
49 #include <dns/result.h>
50 #include <dns/stats.h>
51 #include <dns/tkey.h>
52 #include <dns/view.h>
53 #include <dns/zone.h>
54 #include <dns/zt.h>
55
56 #include <named/client.h>
57 #include <named/log.h>
58 #include <named/server.h>
59 #include <named/sortlist.h>
60 #include <named/xfrout.h>
61
62 /*% Partial answer? */
63 #define PARTIALANSWER(c)        (((c)->query.attributes & \
64                                   NS_QUERYATTR_PARTIALANSWER) != 0)
65 /*% Use Cache? */
66 #define USECACHE(c)             (((c)->query.attributes & \
67                                   NS_QUERYATTR_CACHEOK) != 0)
68 /*% Recursion OK? */
69 #define RECURSIONOK(c)          (((c)->query.attributes & \
70                                   NS_QUERYATTR_RECURSIONOK) != 0)
71 /*% Recursing? */
72 #define RECURSING(c)            (((c)->query.attributes & \
73                                   NS_QUERYATTR_RECURSING) != 0)
74 /*% Cache glue ok? */
75 #define CACHEGLUEOK(c)          (((c)->query.attributes & \
76                                   NS_QUERYATTR_CACHEGLUEOK) != 0)
77 /*% Want Recursion? */
78 #define WANTRECURSION(c)        (((c)->query.attributes & \
79                                   NS_QUERYATTR_WANTRECURSION) != 0)
80 /*% Want DNSSEC? */
81 #define WANTDNSSEC(c)           (((c)->attributes & \
82                                   NS_CLIENTATTR_WANTDNSSEC) != 0)
83 /*% No authority? */
84 #define NOAUTHORITY(c)          (((c)->query.attributes & \
85                                   NS_QUERYATTR_NOAUTHORITY) != 0)
86 /*% No additional? */
87 #define NOADDITIONAL(c)         (((c)->query.attributes & \
88                                   NS_QUERYATTR_NOADDITIONAL) != 0)
89 /*% Secure? */
90 #define SECURE(c)               (((c)->query.attributes & \
91                                   NS_QUERYATTR_SECURE) != 0)
92
93 #if 0
94 #define CTRACE(m)       isc_log_write(ns_g_lctx, \
95                                       NS_LOGCATEGORY_CLIENT, \
96                                       NS_LOGMODULE_QUERY, \
97                                       ISC_LOG_DEBUG(3), \
98                                       "client %p: %s", client, (m))
99 #define QTRACE(m)       isc_log_write(ns_g_lctx, \
100                                       NS_LOGCATEGORY_GENERAL, \
101                                       NS_LOGMODULE_QUERY, \
102                                       ISC_LOG_DEBUG(3), \
103                                       "query %p: %s", query, (m))
104 #else
105 #define CTRACE(m) ((void)m)
106 #define QTRACE(m) ((void)m)
107 #endif
108
109 #define DNS_GETDB_NOEXACT 0x01U
110 #define DNS_GETDB_NOLOG 0x02U
111 #define DNS_GETDB_PARTIAL 0x04U
112
113 typedef struct client_additionalctx {
114         ns_client_t *client;
115         dns_rdataset_t *rdataset;
116 } client_additionalctx_t;
117
118 static isc_result_t
119 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
120
121 static isc_boolean_t
122 validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
123          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
124
125 static inline void
126 log_queryerror(ns_client_t *client, isc_result_t result, int line, int level);
127
128 /*%
129  * Increment query statistics counters.
130  */
131 static inline void
132 inc_stats(ns_client_t *client, isc_statscounter_t counter) {
133         dns_zone_t *zone = client->query.authzone;
134
135         isc_stats_increment(ns_g_server->nsstats, counter);
136
137         if (zone != NULL) {
138                 isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
139                 if (zonestats != NULL)
140                         isc_stats_increment(zonestats, counter);
141         }
142 }
143
144 static void
145 query_send(ns_client_t *client) {
146         isc_statscounter_t counter;
147         if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0)
148                 inc_stats(client, dns_nsstatscounter_nonauthans);
149         else
150                 inc_stats(client, dns_nsstatscounter_authans);
151         if (client->message->rcode == dns_rcode_noerror) {
152                 if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) {
153                         if (client->query.isreferral) {
154                                 counter = dns_nsstatscounter_referral;
155                         } else {
156                                 counter = dns_nsstatscounter_nxrrset;
157                         }
158                 } else {
159                         counter = dns_nsstatscounter_success;
160                 }
161         } else if (client->message->rcode == dns_rcode_nxdomain) {
162                 counter = dns_nsstatscounter_nxdomain;
163         } else {
164                 /* We end up here in case of YXDOMAIN, and maybe others */
165                 counter = dns_nsstatscounter_failure;
166         }
167         inc_stats(client, counter);
168         ns_client_send(client);
169 }
170
171 static void
172 query_error(ns_client_t *client, isc_result_t result, int line) {
173         int loglevel = ISC_LOG_DEBUG(3);
174
175         switch (result) {
176         case DNS_R_SERVFAIL:
177                 loglevel = ISC_LOG_DEBUG(1);
178                 inc_stats(client, dns_nsstatscounter_servfail);
179                 break;
180         case DNS_R_FORMERR:
181                 inc_stats(client, dns_nsstatscounter_formerr);
182                 break;
183         default:
184                 inc_stats(client, dns_nsstatscounter_failure);
185                 break;
186         }
187
188         log_queryerror(client, result, line, loglevel);
189
190         ns_client_error(client, result);
191 }
192
193 static void
194 query_next(ns_client_t *client, isc_result_t result) {
195         if (result == DNS_R_DUPLICATE)
196                 inc_stats(client, dns_nsstatscounter_duplicate);
197         else if (result == DNS_R_DROP)
198                 inc_stats(client, dns_nsstatscounter_dropped);
199         else
200                 inc_stats(client, dns_nsstatscounter_failure);
201         ns_client_next(client, result);
202 }
203
204 static inline void
205 query_freefreeversions(ns_client_t *client, isc_boolean_t everything) {
206         ns_dbversion_t *dbversion, *dbversion_next;
207         unsigned int i;
208
209         for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
210              dbversion != NULL;
211              dbversion = dbversion_next, i++)
212         {
213                 dbversion_next = ISC_LIST_NEXT(dbversion, link);
214                 /*
215                  * If we're not freeing everything, we keep the first three
216                  * dbversions structures around.
217                  */
218                 if (i > 3 || everything) {
219                         ISC_LIST_UNLINK(client->query.freeversions, dbversion,
220                                         link);
221                         isc_mem_put(client->mctx, dbversion,
222                                     sizeof(*dbversion));
223                 }
224         }
225 }
226
227 void
228 ns_query_cancel(ns_client_t *client) {
229         LOCK(&client->query.fetchlock);
230         if (client->query.fetch != NULL) {
231                 dns_resolver_cancelfetch(client->query.fetch);
232
233                 client->query.fetch = NULL;
234         }
235         UNLOCK(&client->query.fetchlock);
236 }
237
238 static inline void
239 query_reset(ns_client_t *client, isc_boolean_t everything) {
240         isc_buffer_t *dbuf, *dbuf_next;
241         ns_dbversion_t *dbversion, *dbversion_next;
242
243         /*%
244          * Reset the query state of a client to its default state.
245          */
246
247         /*
248          * Cancel the fetch if it's running.
249          */
250         ns_query_cancel(client);
251
252         /*
253          * Cleanup any active versions.
254          */
255         for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
256              dbversion != NULL;
257              dbversion = dbversion_next) {
258                 dbversion_next = ISC_LIST_NEXT(dbversion, link);
259                 dns_db_closeversion(dbversion->db, &dbversion->version,
260                                     ISC_FALSE);
261                 dns_db_detach(&dbversion->db);
262                 ISC_LIST_INITANDAPPEND(client->query.freeversions,
263                                       dbversion, link);
264         }
265         ISC_LIST_INIT(client->query.activeversions);
266
267         if (client->query.authdb != NULL)
268                 dns_db_detach(&client->query.authdb);
269         if (client->query.authzone != NULL)
270                 dns_zone_detach(&client->query.authzone);
271
272         query_freefreeversions(client, everything);
273
274         for (dbuf = ISC_LIST_HEAD(client->query.namebufs);
275              dbuf != NULL;
276              dbuf = dbuf_next) {
277                 dbuf_next = ISC_LIST_NEXT(dbuf, link);
278                 if (dbuf_next != NULL || everything) {
279                         ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
280                         isc_buffer_free(&dbuf);
281                 }
282         }
283
284         if (client->query.restarts > 0) {
285                 /*
286                  * client->query.qname was dynamically allocated.
287                  */
288                 dns_message_puttempname(client->message,
289                                         &client->query.qname);
290         }
291         client->query.qname = NULL;
292         client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
293                                     NS_QUERYATTR_CACHEOK |
294                                     NS_QUERYATTR_SECURE);
295         client->query.restarts = 0;
296         client->query.timerset = ISC_FALSE;
297         client->query.origqname = NULL;
298         client->query.qname = NULL;
299         client->query.dboptions = 0;
300         client->query.fetchoptions = 0;
301         client->query.gluedb = NULL;
302         client->query.authdbset = ISC_FALSE;
303         client->query.isreferral = ISC_FALSE;
304 }
305
306 static void
307 query_next_callback(ns_client_t *client) {
308         query_reset(client, ISC_FALSE);
309 }
310
311 void
312 ns_query_free(ns_client_t *client) {
313         query_reset(client, ISC_TRUE);
314 }
315
316 static inline isc_result_t
317 query_newnamebuf(ns_client_t *client) {
318         isc_buffer_t *dbuf;
319         isc_result_t result;
320
321         CTRACE("query_newnamebuf");
322         /*%
323          * Allocate a name buffer.
324          */
325
326         dbuf = NULL;
327         result = isc_buffer_allocate(client->mctx, &dbuf, 1024);
328         if (result != ISC_R_SUCCESS) {
329                 CTRACE("query_newnamebuf: isc_buffer_allocate failed: done");
330                 return (result);
331         }
332         ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
333
334         CTRACE("query_newnamebuf: done");
335         return (ISC_R_SUCCESS);
336 }
337
338 static inline isc_buffer_t *
339 query_getnamebuf(ns_client_t *client) {
340         isc_buffer_t *dbuf;
341         isc_result_t result;
342         isc_region_t r;
343
344         CTRACE("query_getnamebuf");
345         /*%
346          * Return a name buffer with space for a maximal name, allocating
347          * a new one if necessary.
348          */
349
350         if (ISC_LIST_EMPTY(client->query.namebufs)) {
351                 result = query_newnamebuf(client);
352                 if (result != ISC_R_SUCCESS) {
353                     CTRACE("query_getnamebuf: query_newnamebuf failed: done");
354                         return (NULL);
355                 }
356         }
357
358         dbuf = ISC_LIST_TAIL(client->query.namebufs);
359         INSIST(dbuf != NULL);
360         isc_buffer_availableregion(dbuf, &r);
361         if (r.length < 255) {
362                 result = query_newnamebuf(client);
363                 if (result != ISC_R_SUCCESS) {
364                     CTRACE("query_getnamebuf: query_newnamebuf failed: done");
365                         return (NULL);
366
367                 }
368                 dbuf = ISC_LIST_TAIL(client->query.namebufs);
369                 isc_buffer_availableregion(dbuf, &r);
370                 INSIST(r.length >= 255);
371         }
372         CTRACE("query_getnamebuf: done");
373         return (dbuf);
374 }
375
376 static inline void
377 query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
378         isc_region_t r;
379
380         CTRACE("query_keepname");
381         /*%
382          * 'name' is using space in 'dbuf', but 'dbuf' has not yet been
383          * adjusted to take account of that.  We do the adjustment.
384          */
385
386         REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0);
387
388         dns_name_toregion(name, &r);
389         isc_buffer_add(dbuf, r.length);
390         dns_name_setbuffer(name, NULL);
391         client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
392 }
393
394 static inline void
395 query_releasename(ns_client_t *client, dns_name_t **namep) {
396         dns_name_t *name = *namep;
397
398         /*%
399          * 'name' is no longer needed.  Return it to our pool of temporary
400          * names.  If it is using a name buffer, relinquish its exclusive
401          * rights on the buffer.
402          */
403
404         CTRACE("query_releasename");
405         if (dns_name_hasbuffer(name)) {
406                 INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED)
407                        != 0);
408                 client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
409         }
410         dns_message_puttempname(client->message, namep);
411         CTRACE("query_releasename: done");
412 }
413
414 static inline dns_name_t *
415 query_newname(ns_client_t *client, isc_buffer_t *dbuf,
416               isc_buffer_t *nbuf)
417 {
418         dns_name_t *name;
419         isc_region_t r;
420         isc_result_t result;
421
422         REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
423
424         CTRACE("query_newname");
425         name = NULL;
426         result = dns_message_gettempname(client->message, &name);
427         if (result != ISC_R_SUCCESS) {
428                 CTRACE("query_newname: dns_message_gettempname failed: done");
429                 return (NULL);
430         }
431         isc_buffer_availableregion(dbuf, &r);
432         isc_buffer_init(nbuf, r.base, r.length);
433         dns_name_init(name, NULL);
434         dns_name_setbuffer(name, nbuf);
435         client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED;
436
437         CTRACE("query_newname: done");
438         return (name);
439 }
440
441 static inline dns_rdataset_t *
442 query_newrdataset(ns_client_t *client) {
443         dns_rdataset_t *rdataset;
444         isc_result_t result;
445
446         CTRACE("query_newrdataset");
447         rdataset = NULL;
448         result = dns_message_gettemprdataset(client->message, &rdataset);
449         if (result != ISC_R_SUCCESS) {
450           CTRACE("query_newrdataset: "
451                  "dns_message_gettemprdataset failed: done");
452                 return (NULL);
453         }
454         dns_rdataset_init(rdataset);
455
456         CTRACE("query_newrdataset: done");
457         return (rdataset);
458 }
459
460 static inline void
461 query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
462         dns_rdataset_t *rdataset = *rdatasetp;
463
464         CTRACE("query_putrdataset");
465         if (rdataset != NULL) {
466                 if (dns_rdataset_isassociated(rdataset))
467                         dns_rdataset_disassociate(rdataset);
468                 dns_message_puttemprdataset(client->message, rdatasetp);
469         }
470         CTRACE("query_putrdataset: done");
471 }
472
473
474 static inline isc_result_t
475 query_newdbversion(ns_client_t *client, unsigned int n) {
476         unsigned int i;
477         ns_dbversion_t *dbversion;
478
479         for (i = 0; i < n; i++) {
480                 dbversion = isc_mem_get(client->mctx, sizeof(*dbversion));
481                 if (dbversion != NULL) {
482                         dbversion->db = NULL;
483                         dbversion->version = NULL;
484                         ISC_LIST_INITANDAPPEND(client->query.freeversions,
485                                               dbversion, link);
486                 } else {
487                         /*
488                          * We only return ISC_R_NOMEMORY if we couldn't
489                          * allocate anything.
490                          */
491                         if (i == 0)
492                                 return (ISC_R_NOMEMORY);
493                         else
494                                 return (ISC_R_SUCCESS);
495                 }
496         }
497
498         return (ISC_R_SUCCESS);
499 }
500
501 static inline ns_dbversion_t *
502 query_getdbversion(ns_client_t *client) {
503         isc_result_t result;
504         ns_dbversion_t *dbversion;
505
506         if (ISC_LIST_EMPTY(client->query.freeversions)) {
507                 result = query_newdbversion(client, 1);
508                 if (result != ISC_R_SUCCESS)
509                         return (NULL);
510         }
511         dbversion = ISC_LIST_HEAD(client->query.freeversions);
512         INSIST(dbversion != NULL);
513         ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
514
515         return (dbversion);
516 }
517
518 isc_result_t
519 ns_query_init(ns_client_t *client) {
520         isc_result_t result;
521
522         ISC_LIST_INIT(client->query.namebufs);
523         ISC_LIST_INIT(client->query.activeversions);
524         ISC_LIST_INIT(client->query.freeversions);
525         client->query.restarts = 0;
526         client->query.timerset = ISC_FALSE;
527         client->query.qname = NULL;
528         result = isc_mutex_init(&client->query.fetchlock);
529         if (result != ISC_R_SUCCESS)
530                 return (result);
531         client->query.fetch = NULL;
532         client->query.authdb = NULL;
533         client->query.authzone = NULL;
534         client->query.authdbset = ISC_FALSE;
535         client->query.isreferral = ISC_FALSE;
536         query_reset(client, ISC_FALSE);
537         result = query_newdbversion(client, 3);
538         if (result != ISC_R_SUCCESS) {
539                 DESTROYLOCK(&client->query.fetchlock);
540                 return (result);
541         }
542         result = query_newnamebuf(client);
543         if (result != ISC_R_SUCCESS)
544                 query_freefreeversions(client, ISC_TRUE);
545
546         return (result);
547 }
548
549 static inline ns_dbversion_t *
550 query_findversion(ns_client_t *client, dns_db_t *db,
551                   isc_boolean_t *newzonep)
552 {
553         ns_dbversion_t *dbversion;
554
555         /*%
556          * We may already have done a query related to this
557          * database.  If so, we must be sure to make subsequent
558          * queries from the same version.
559          */
560         for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
561              dbversion != NULL;
562              dbversion = ISC_LIST_NEXT(dbversion, link)) {
563                 if (dbversion->db == db)
564                         break;
565         }
566
567         if (dbversion == NULL) {
568                 /*
569                  * This is a new zone for this query.  Add it to
570                  * the active list.
571                  */
572                 dbversion = query_getdbversion(client);
573                 if (dbversion == NULL)
574                         return (NULL);
575                 dns_db_attach(db, &dbversion->db);
576                 dns_db_currentversion(db, &dbversion->version);
577                 dbversion->queryok = ISC_FALSE;
578                 ISC_LIST_APPEND(client->query.activeversions,
579                                 dbversion, link);
580                 *newzonep = ISC_TRUE;
581         } else
582                 *newzonep = ISC_FALSE;
583
584         return (dbversion);
585 }
586
587 static inline isc_result_t
588 query_validatezonedb(ns_client_t *client, dns_name_t *name,
589                      dns_rdatatype_t qtype, unsigned int options,
590                      dns_zone_t *zone, dns_db_t *db,
591                      dns_dbversion_t **versionp)
592 {
593         isc_result_t result;
594         isc_boolean_t check_acl, new_zone;
595         dns_acl_t *queryacl;
596         ns_dbversion_t *dbversion;
597
598         REQUIRE(zone != NULL);
599         REQUIRE(db != NULL);
600
601         /*
602          * This limits our searching to the zone where the first name
603          * (the query target) was looked for.  This prevents following
604          * CNAMES or DNAMES into other zones and prevents returning
605          * additional data from other zones.
606          */
607         if (!client->view->additionalfromauth &&
608             client->query.authdbset &&
609             db != client->query.authdb)
610                 goto refuse;
611
612         /*
613          * If the zone has an ACL, we'll check it, otherwise
614          * we use the view's "allow-query" ACL.  Each ACL is only checked
615          * once per query.
616          *
617          * Also, get the database version to use.
618          */
619
620         check_acl = ISC_TRUE;   /* Keep compiler happy. */
621         queryacl = NULL;
622
623         /*
624          * Get the current version of this database.
625          */
626         dbversion = query_findversion(client, db, &new_zone);
627         if (dbversion == NULL) {
628                 result = DNS_R_SERVFAIL;
629                 goto fail;
630         }
631         if (new_zone) {
632                 check_acl = ISC_TRUE;
633         } else if (!dbversion->queryok) {
634                 goto refuse;
635         } else {
636                 check_acl = ISC_FALSE;
637         }
638
639         queryacl = dns_zone_getqueryacl(zone);
640         if (queryacl == NULL) {
641                 queryacl = client->view->queryacl;
642                 if ((client->query.attributes &
643                      NS_QUERYATTR_QUERYOKVALID) != 0) {
644                         /*
645                          * We've evaluated the view's queryacl already.  If
646                          * NS_QUERYATTR_QUERYOK is set, then the client is
647                          * allowed to make queries, otherwise the query should
648                          * be refused.
649                          */
650                         check_acl = ISC_FALSE;
651                         if ((client->query.attributes &
652                              NS_QUERYATTR_QUERYOK) == 0)
653                                 goto refuse;
654                 } else {
655                         /*
656                          * We haven't evaluated the view's queryacl yet.
657                          */
658                         check_acl = ISC_TRUE;
659                 }
660         }
661
662         if (check_acl) {
663                 isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
664
665                 result = ns_client_checkaclsilent(client, NULL, queryacl,
666                                                   ISC_TRUE);
667                 if (log) {
668                         char msg[NS_CLIENT_ACLMSGSIZE("query")];
669                         if (result == ISC_R_SUCCESS) {
670                                 if (isc_log_wouldlog(ns_g_lctx,
671                                                      ISC_LOG_DEBUG(3)))
672                                 {
673                                         ns_client_aclmsg("query", name, qtype,
674                                                          client->view->rdclass,
675                                                          msg, sizeof(msg));
676                                         ns_client_log(client,
677                                                       DNS_LOGCATEGORY_SECURITY,
678                                                       NS_LOGMODULE_QUERY,
679                                                       ISC_LOG_DEBUG(3),
680                                                       "%s approved", msg);
681                                 }
682                         } else {
683                                 ns_client_aclmsg("query", name, qtype,
684                                                  client->view->rdclass,
685                                                  msg, sizeof(msg));
686                                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
687                                               NS_LOGMODULE_QUERY, ISC_LOG_INFO,
688                                               "%s denied", msg);
689                         }
690                 }
691
692                 if (queryacl == client->view->queryacl) {
693                         if (result == ISC_R_SUCCESS) {
694                                 /*
695                                  * We were allowed by the default
696                                  * "allow-query" ACL.  Remember this so we
697                                  * don't have to check again.
698                                  */
699                                 client->query.attributes |=
700                                         NS_QUERYATTR_QUERYOK;
701                         }
702                         /*
703                          * We've now evaluated the view's query ACL, and
704                          * the NS_QUERYATTR_QUERYOK attribute is now valid.
705                          */
706                         client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
707                 }
708
709                 if (result != ISC_R_SUCCESS)
710                         goto refuse;
711         }
712
713         /* Approved. */
714
715         /*
716          * Remember the result of the ACL check so we
717          * don't have to check again.
718          */
719         dbversion->queryok = ISC_TRUE;
720
721         /* Transfer ownership, if necessary. */
722         if (versionp != NULL)
723                 *versionp = dbversion->version;
724
725         return (ISC_R_SUCCESS);
726
727  refuse:
728         return (DNS_R_REFUSED);
729
730  fail:
731         return (result);
732 }
733
734 static inline isc_result_t
735 query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
736                 unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
737                 dns_dbversion_t **versionp)
738 {
739         isc_result_t result;
740         unsigned int ztoptions;
741         dns_zone_t *zone = NULL;
742         dns_db_t *db = NULL;
743         isc_boolean_t partial = ISC_FALSE;
744
745         REQUIRE(zonep != NULL && *zonep == NULL);
746         REQUIRE(dbp != NULL && *dbp == NULL);
747
748         /*%
749          * Find a zone database to answer the query.
750          */
751         ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
752                 DNS_ZTFIND_NOEXACT : 0;
753
754         result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
755                              &zone);
756         if (result == DNS_R_PARTIALMATCH)
757                 partial = ISC_TRUE;
758         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
759                 result = dns_zone_getdb(zone, &db);
760
761         if (result != ISC_R_SUCCESS)
762                 goto fail;
763
764         result = query_validatezonedb(client, name, qtype, options, zone, db,
765                                       versionp);
766
767         if (result != ISC_R_SUCCESS)
768                 goto fail;
769
770         /* Transfer ownership. */
771         *zonep = zone;
772         *dbp = db;
773
774         if (partial && (options & DNS_GETDB_PARTIAL) != 0)
775                 return (DNS_R_PARTIALMATCH);
776         return (ISC_R_SUCCESS);
777
778  fail:
779         if (zone != NULL)
780                 dns_zone_detach(&zone);
781         if (db != NULL)
782                 dns_db_detach(&db);
783
784         return (result);
785 }
786
787 static inline isc_result_t
788 query_getcachedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
789                  dns_db_t **dbp, unsigned int options)
790 {
791         isc_result_t result;
792         isc_boolean_t check_acl;
793         dns_db_t *db = NULL;
794
795         REQUIRE(dbp != NULL && *dbp == NULL);
796
797         /*%
798          * Find a cache database to answer the query.
799          * This may fail with DNS_R_REFUSED if the client
800          * is not allowed to use the cache.
801          */
802
803         if (!USECACHE(client))
804                 return (DNS_R_REFUSED);
805         dns_db_attach(client->view->cachedb, &db);
806
807         if ((client->query.attributes &
808              NS_QUERYATTR_QUERYOKVALID) != 0) {
809                 /*
810                  * We've evaluated the view's queryacl already.  If
811                  * NS_QUERYATTR_QUERYOK is set, then the client is
812                  * allowed to make queries, otherwise the query should
813                  * be refused.
814                  */
815                 check_acl = ISC_FALSE;
816                 if ((client->query.attributes &
817                      NS_QUERYATTR_QUERYOK) == 0)
818                         goto refuse;
819         } else {
820                 /*
821                  * We haven't evaluated the view's queryacl yet.
822                  */
823                 check_acl = ISC_TRUE;
824         }
825
826         if (check_acl) {
827                 isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
828                 char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
829
830                 result = ns_client_checkaclsilent(client, NULL,
831                                                   client->view->queryacl,
832                                                   ISC_TRUE);
833                 if (result == ISC_R_SUCCESS) {
834                         /*
835                          * We were allowed by the default
836                          * "allow-query" ACL.  Remember this so we
837                          * don't have to check again.
838                          */
839                         client->query.attributes |=
840                                 NS_QUERYATTR_QUERYOK;
841                         if (log && isc_log_wouldlog(ns_g_lctx,
842                                                      ISC_LOG_DEBUG(3)))
843                         {
844                                 ns_client_aclmsg("query (cache)", name, qtype,
845                                                  client->view->rdclass,
846                                                  msg, sizeof(msg));
847                                 ns_client_log(client,
848                                               DNS_LOGCATEGORY_SECURITY,
849                                               NS_LOGMODULE_QUERY,
850                                               ISC_LOG_DEBUG(3),
851                                               "%s approved", msg);
852                         }
853                 } else if (log) {
854                         ns_client_aclmsg("query (cache)", name, qtype,
855                                          client->view->rdclass, msg,
856                                          sizeof(msg));
857                         ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
858                                       NS_LOGMODULE_QUERY, ISC_LOG_INFO,
859                                       "%s denied", msg);
860                 }
861                 /*
862                  * We've now evaluated the view's query ACL, and
863                  * the NS_QUERYATTR_QUERYOK attribute is now valid.
864                  */
865                 client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
866
867                 if (result != ISC_R_SUCCESS)
868                         goto refuse;
869         }
870
871         /* Approved. */
872
873         /* Transfer ownership. */
874         *dbp = db;
875
876         return (ISC_R_SUCCESS);
877
878  refuse:
879         result = DNS_R_REFUSED;
880
881         if (db != NULL)
882                 dns_db_detach(&db);
883
884         return (result);
885 }
886
887
888 static inline isc_result_t
889 query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
890             unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
891             dns_dbversion_t **versionp, isc_boolean_t *is_zonep)
892 {
893         isc_result_t result;
894
895 #ifdef DLZ
896         isc_result_t tresult;
897         unsigned int namelabels;
898         unsigned int zonelabels;
899         dns_zone_t *zone = NULL;
900         dns_db_t *tdbp;
901
902         REQUIRE(zonep != NULL && *zonep == NULL);
903
904         tdbp = NULL;
905
906         /* Calculate how many labels are in name. */
907         namelabels = dns_name_countlabels(name);
908         zonelabels = 0;
909
910         /* Try to find name in bind's standard database. */
911         result = query_getzonedb(client, name, qtype, options, &zone,
912                                  dbp, versionp);
913
914         /* See how many labels are in the zone's name.    */
915         if (result == ISC_R_SUCCESS && zone != NULL)
916                 zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
917         /*
918          * If # zone labels < # name labels, try to find an even better match
919          * Only try if a DLZ driver is loaded for this view
920          */
921         if (zonelabels < namelabels && client->view->dlzdatabase != NULL) {
922                 tresult = dns_dlzfindzone(client->view, name,
923                                           zonelabels, &tdbp);
924                  /* If we successful, we found a better match. */
925                 if (tresult == ISC_R_SUCCESS) {
926                         /*
927                          * If the previous search returned a zone, detach it.
928                          */
929                         if (zone != NULL)
930                                 dns_zone_detach(&zone);
931
932                         /*
933                          * If the previous search returned a database,
934                          * detach it.
935                          */
936                         if (*dbp != NULL)
937                                 dns_db_detach(dbp);
938
939                         /*
940                          * If the previous search returned a version, clear it.
941                          */
942                         *versionp = NULL;
943
944                         /*
945                          * Get our database version.
946                          */
947                         dns_db_currentversion(tdbp, versionp);
948
949                         /*
950                          * Be sure to return our database.
951                          */
952                         *dbp = tdbp;
953
954                         /*
955                          * We return a null zone, No stats for DLZ zones.
956                          */
957                         zone = NULL;
958                         result = tresult;
959                 }
960         }
961 #else
962         result = query_getzonedb(client, name, qtype, options,
963                                  zonep, dbp, versionp);
964 #endif
965
966         /* If successful, Transfer ownership of zone. */
967         if (result == ISC_R_SUCCESS) {
968 #ifdef DLZ
969                 *zonep = zone;
970 #endif
971                 /*
972                  * If neither attempt above succeeded, return the cache instead
973                  */
974                 *is_zonep = ISC_TRUE;
975         } else if (result == ISC_R_NOTFOUND) {
976                 result = query_getcachedb(client, name, qtype, dbp, options);
977                 *is_zonep = ISC_FALSE;
978         }
979         return (result);
980 }
981
982 static inline isc_boolean_t
983 query_isduplicate(ns_client_t *client, dns_name_t *name,
984                   dns_rdatatype_t type, dns_name_t **mnamep)
985 {
986         dns_section_t section;
987         dns_name_t *mname = NULL;
988         isc_result_t result;
989
990         CTRACE("query_isduplicate");
991
992         for (section = DNS_SECTION_ANSWER;
993              section <= DNS_SECTION_ADDITIONAL;
994              section++) {
995                 result = dns_message_findname(client->message, section,
996                                               name, type, 0, &mname, NULL);
997                 if (result == ISC_R_SUCCESS) {
998                         /*
999                          * We've already got this RRset in the response.
1000                          */
1001                         CTRACE("query_isduplicate: true: done");
1002                         return (ISC_TRUE);
1003                 } else if (result == DNS_R_NXRRSET) {
1004                         /*
1005                          * The name exists, but the rdataset does not.
1006                          */
1007                         if (section == DNS_SECTION_ADDITIONAL)
1008                                 break;
1009                 } else
1010                         RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
1011                 mname = NULL;
1012         }
1013
1014         /*
1015          * If the dns_name_t we're looking up is already in the message,
1016          * we don't want to trigger the caller's name replacement logic.
1017          */
1018         if (name == mname)
1019                 mname = NULL;
1020
1021         *mnamep = mname;
1022
1023         CTRACE("query_isduplicate: false: done");
1024         return (ISC_FALSE);
1025 }
1026
1027 static isc_result_t
1028 query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
1029         ns_client_t *client = arg;
1030         isc_result_t result, eresult;
1031         dns_dbnode_t *node;
1032         dns_db_t *db;
1033         dns_name_t *fname, *mname;
1034         dns_rdataset_t *rdataset, *sigrdataset, *trdataset;
1035         isc_buffer_t *dbuf;
1036         isc_buffer_t b;
1037         dns_dbversion_t *version;
1038         isc_boolean_t added_something, need_addname;
1039         dns_zone_t *zone;
1040         dns_rdatatype_t type;
1041
1042         REQUIRE(NS_CLIENT_VALID(client));
1043         REQUIRE(qtype != dns_rdatatype_any);
1044
1045         if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype))
1046                 return (ISC_R_SUCCESS);
1047
1048         CTRACE("query_addadditional");
1049
1050         /*
1051          * Initialization.
1052          */
1053         eresult = ISC_R_SUCCESS;
1054         fname = NULL;
1055         rdataset = NULL;
1056         sigrdataset = NULL;
1057         trdataset = NULL;
1058         db = NULL;
1059         version = NULL;
1060         node = NULL;
1061         added_something = ISC_FALSE;
1062         need_addname = ISC_FALSE;
1063         zone = NULL;
1064
1065         /*
1066          * We treat type A additional section processing as if it
1067          * were "any address type" additional section processing.
1068          * To avoid multiple lookups, we do an 'any' database
1069          * lookup and iterate over the node.
1070          */
1071         if (qtype == dns_rdatatype_a)
1072                 type = dns_rdatatype_any;
1073         else
1074                 type = qtype;
1075
1076         /*
1077          * Get some resources.
1078          */
1079         dbuf = query_getnamebuf(client);
1080         if (dbuf == NULL)
1081                 goto cleanup;
1082         fname = query_newname(client, dbuf, &b);
1083         rdataset = query_newrdataset(client);
1084         if (fname == NULL || rdataset == NULL)
1085                 goto cleanup;
1086         if (WANTDNSSEC(client)) {
1087                 sigrdataset = query_newrdataset(client);
1088                 if (sigrdataset == NULL)
1089                         goto cleanup;
1090         }
1091
1092         /*
1093          * Look for a zone database that might contain authoritative
1094          * additional data.
1095          */
1096         result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
1097                                  &zone, &db, &version);
1098         if (result != ISC_R_SUCCESS)
1099                 goto try_cache;
1100
1101         CTRACE("query_addadditional: db_find");
1102
1103         /*
1104          * Since we are looking for authoritative data, we do not set
1105          * the GLUEOK flag.  Glue will be looked for later, but not
1106          * necessarily in the same database.
1107          */
1108         node = NULL;
1109         result = dns_db_find(db, name, version, type, client->query.dboptions,
1110                              client->now, &node, fname, rdataset,
1111                              sigrdataset);
1112         if (result == ISC_R_SUCCESS)
1113                 goto found;
1114
1115         if (dns_rdataset_isassociated(rdataset))
1116                 dns_rdataset_disassociate(rdataset);
1117         if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset))
1118                 dns_rdataset_disassociate(sigrdataset);
1119         if (node != NULL)
1120                 dns_db_detachnode(db, &node);
1121         version = NULL;
1122         dns_db_detach(&db);
1123
1124         /*
1125          * No authoritative data was found.  The cache is our next best bet.
1126          */
1127
1128  try_cache:
1129         result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
1130         if (result != ISC_R_SUCCESS)
1131                 /*
1132                  * Most likely the client isn't allowed to query the cache.
1133                  */
1134                 goto try_glue;
1135         /*
1136          * Attempt to validate glue.
1137          */
1138         if (sigrdataset == NULL) {
1139                 sigrdataset = query_newrdataset(client);
1140                 if (sigrdataset == NULL)
1141                         goto cleanup;
1142         }
1143         result = dns_db_find(db, name, version, type,
1144                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1145                              client->now, &node, fname, rdataset,
1146                              sigrdataset);
1147         if (result == DNS_R_GLUE &&
1148             validate(client, db, fname, rdataset, sigrdataset))
1149                 result = ISC_R_SUCCESS;
1150         if (!WANTDNSSEC(client))
1151                 query_putrdataset(client, &sigrdataset);
1152         if (result == ISC_R_SUCCESS)
1153                 goto found;
1154
1155         if (dns_rdataset_isassociated(rdataset))
1156                 dns_rdataset_disassociate(rdataset);
1157         if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset))
1158                 dns_rdataset_disassociate(sigrdataset);
1159         if (node != NULL)
1160                 dns_db_detachnode(db, &node);
1161         dns_db_detach(&db);
1162
1163  try_glue:
1164         /*
1165          * No cached data was found.  Glue is our last chance.
1166          * RFC1035 sayeth:
1167          *
1168          *      NS records cause both the usual additional section
1169          *      processing to locate a type A record, and, when used
1170          *      in a referral, a special search of the zone in which
1171          *      they reside for glue information.
1172          *
1173          * This is the "special search".  Note that we must search
1174          * the zone where the NS record resides, not the zone it
1175          * points to, and that we only do the search in the delegation
1176          * case (identified by client->query.gluedb being set).
1177          */
1178
1179         if (client->query.gluedb == NULL)
1180                 goto cleanup;
1181
1182         /*
1183          * Don't poison caches using the bailiwick protection model.
1184          */
1185         if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
1186                 goto cleanup;
1187
1188         dns_db_attach(client->query.gluedb, &db);
1189         result = dns_db_find(db, name, version, type,
1190                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1191                              client->now, &node, fname, rdataset,
1192                              sigrdataset);
1193         if (!(result == ISC_R_SUCCESS ||
1194               result == DNS_R_ZONECUT ||
1195               result == DNS_R_GLUE))
1196                 goto cleanup;
1197
1198  found:
1199         /*
1200          * We have found a potential additional data rdataset, or
1201          * at least a node to iterate over.
1202          */
1203         query_keepname(client, fname, dbuf);
1204
1205         /*
1206          * If we have an rdataset, add it to the additional data
1207          * section.
1208          */
1209         mname = NULL;
1210         if (dns_rdataset_isassociated(rdataset) &&
1211             !query_isduplicate(client, fname, type, &mname)) {
1212                 if (mname != NULL) {
1213                         query_releasename(client, &fname);
1214                         fname = mname;
1215                 } else
1216                         need_addname = ISC_TRUE;
1217                 ISC_LIST_APPEND(fname->list, rdataset, link);
1218                 trdataset = rdataset;
1219                 rdataset = NULL;
1220                 added_something = ISC_TRUE;
1221                 /*
1222                  * Note: we only add SIGs if we've added the type they cover,
1223                  * so we do not need to check if the SIG rdataset is already
1224                  * in the response.
1225                  */
1226                 if (sigrdataset != NULL &&
1227                     dns_rdataset_isassociated(sigrdataset))
1228                 {
1229                         ISC_LIST_APPEND(fname->list, sigrdataset, link);
1230                         sigrdataset = NULL;
1231                 }
1232         }
1233
1234         if (qtype == dns_rdatatype_a) {
1235                 /*
1236                  * We now go looking for A and AAAA records, along with
1237                  * their signatures.
1238                  *
1239                  * XXXRTH  This code could be more efficient.
1240                  */
1241                 if (rdataset != NULL) {
1242                         if (dns_rdataset_isassociated(rdataset))
1243                                 dns_rdataset_disassociate(rdataset);
1244                 } else {
1245                         rdataset = query_newrdataset(client);
1246                         if (rdataset == NULL)
1247                                 goto addname;
1248                 }
1249                 if (sigrdataset != NULL) {
1250                         if (dns_rdataset_isassociated(sigrdataset))
1251                                 dns_rdataset_disassociate(sigrdataset);
1252                 } else if (WANTDNSSEC(client)) {
1253                         sigrdataset = query_newrdataset(client);
1254                         if (sigrdataset == NULL)
1255                                 goto addname;
1256                 }
1257                 result = dns_db_findrdataset(db, node, version,
1258                                              dns_rdatatype_a, 0,
1259                                              client->now, rdataset,
1260                                              sigrdataset);
1261                 if (result == DNS_R_NCACHENXDOMAIN)
1262                         goto addname;
1263                 if (result == DNS_R_NCACHENXRRSET) {
1264                         dns_rdataset_disassociate(rdataset);
1265                         /*
1266                          * Negative cache entries don't have sigrdatasets.
1267                          */
1268                         INSIST(sigrdataset == NULL ||
1269                                ! dns_rdataset_isassociated(sigrdataset));
1270                 }
1271                 if (result == ISC_R_SUCCESS) {
1272                         mname = NULL;
1273                         if (!query_isduplicate(client, fname,
1274                                                dns_rdatatype_a, &mname)) {
1275                                 if (mname != NULL) {
1276                                         query_releasename(client, &fname);
1277                                         fname = mname;
1278                                 } else
1279                                         need_addname = ISC_TRUE;
1280                                 ISC_LIST_APPEND(fname->list, rdataset, link);
1281                                 added_something = ISC_TRUE;
1282                                 if (sigrdataset != NULL &&
1283                                     dns_rdataset_isassociated(sigrdataset))
1284                                 {
1285                                         ISC_LIST_APPEND(fname->list,
1286                                                         sigrdataset, link);
1287                                         sigrdataset =
1288                                                 query_newrdataset(client);
1289                                 }
1290                                 rdataset = query_newrdataset(client);
1291                                 if (rdataset == NULL)
1292                                         goto addname;
1293                                 if (WANTDNSSEC(client) && sigrdataset == NULL)
1294                                         goto addname;
1295                         } else {
1296                                 dns_rdataset_disassociate(rdataset);
1297                                 if (sigrdataset != NULL &&
1298                                     dns_rdataset_isassociated(sigrdataset))
1299                                         dns_rdataset_disassociate(sigrdataset);
1300                         }
1301                 }
1302                 result = dns_db_findrdataset(db, node, version,
1303                                              dns_rdatatype_aaaa, 0,
1304                                              client->now, rdataset,
1305                                              sigrdataset);
1306                 if (result == DNS_R_NCACHENXDOMAIN)
1307                         goto addname;
1308                 if (result == DNS_R_NCACHENXRRSET) {
1309                         dns_rdataset_disassociate(rdataset);
1310                         INSIST(sigrdataset == NULL ||
1311                                ! dns_rdataset_isassociated(sigrdataset));
1312                 }
1313                 if (result == ISC_R_SUCCESS) {
1314                         mname = NULL;
1315                         if (!query_isduplicate(client, fname,
1316                                                dns_rdatatype_aaaa, &mname)) {
1317                                 if (mname != NULL) {
1318                                         query_releasename(client, &fname);
1319                                         fname = mname;
1320                                 } else
1321                                         need_addname = ISC_TRUE;
1322                                 ISC_LIST_APPEND(fname->list, rdataset, link);
1323                                 added_something = ISC_TRUE;
1324                                 if (sigrdataset != NULL &&
1325                                     dns_rdataset_isassociated(sigrdataset))
1326                                 {
1327                                         ISC_LIST_APPEND(fname->list,
1328                                                         sigrdataset, link);
1329                                         sigrdataset = NULL;
1330                                 }
1331                                 rdataset = NULL;
1332                         }
1333                 }
1334         }
1335
1336  addname:
1337         CTRACE("query_addadditional: addname");
1338         /*
1339          * If we haven't added anything, then we're done.
1340          */
1341         if (!added_something)
1342                 goto cleanup;
1343
1344         /*
1345          * We may have added our rdatasets to an existing name, if so, then
1346          * need_addname will be ISC_FALSE.  Whether we used an existing name
1347          * or a new one, we must set fname to NULL to prevent cleanup.
1348          */
1349         if (need_addname)
1350                 dns_message_addname(client->message, fname,
1351                                     DNS_SECTION_ADDITIONAL);
1352         fname = NULL;
1353
1354         /*
1355          * In a few cases, we want to add additional data for additional
1356          * data.  It's simpler to just deal with special cases here than
1357          * to try to create a general purpose mechanism and allow the
1358          * rdata implementations to do it themselves.
1359          *
1360          * This involves recursion, but the depth is limited.  The
1361          * most complex case is adding a SRV rdataset, which involves
1362          * recursing to add address records, which in turn can cause
1363          * recursion to add KEYs.
1364          */
1365         if (type == dns_rdatatype_srv && trdataset != NULL) {
1366                 /*
1367                  * If we're adding SRV records to the additional data
1368                  * section, it's helpful if we add the SRV additional data
1369                  * as well.
1370                  */
1371                 eresult = dns_rdataset_additionaldata(trdataset,
1372                                                       query_addadditional,
1373                                                       client);
1374         }
1375
1376  cleanup:
1377         CTRACE("query_addadditional: cleanup");
1378         query_putrdataset(client, &rdataset);
1379         if (sigrdataset != NULL)
1380                 query_putrdataset(client, &sigrdataset);
1381         if (fname != NULL)
1382                 query_releasename(client, &fname);
1383         if (node != NULL)
1384                 dns_db_detachnode(db, &node);
1385         if (db != NULL)
1386                 dns_db_detach(&db);
1387         if (zone != NULL)
1388                 dns_zone_detach(&zone);
1389
1390         CTRACE("query_addadditional: done");
1391         return (eresult);
1392 }
1393
1394 static inline void
1395 query_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base,
1396                    dns_rdatasetadditional_t additionaltype,
1397                    dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp,
1398                    dns_dbversion_t **versionp, dns_dbnode_t **nodep,
1399                    dns_name_t *fname)
1400 {
1401         dns_rdataset_t *rdataset;
1402
1403         while  ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
1404                 ISC_LIST_UNLINK(fname->list, rdataset, link);
1405                 query_putrdataset(client, &rdataset);
1406         }
1407         if (*versionp != NULL)
1408                 dns_db_closeversion(*dbp, versionp, ISC_FALSE);
1409         if (*nodep != NULL)
1410                 dns_db_detachnode(*dbp, nodep);
1411         if (*dbp != NULL)
1412                 dns_db_detach(dbp);
1413         if (*zonep != NULL)
1414                 dns_zone_detach(zonep);
1415         (void)dns_rdataset_putadditional(client->view->acache, rdataset_base,
1416                                          additionaltype, type);
1417 }
1418
1419 static inline isc_result_t
1420 query_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0,
1421                    dns_dbversion_t *version)
1422 {
1423         isc_result_t result = ISC_R_SUCCESS;
1424         dns_dbversion_t *version_current = NULL;
1425         dns_db_t *db_current = db0;
1426
1427         if (db_current == NULL) {
1428                 result = dns_zone_getdb(zone, &db_current);
1429                 if (result != ISC_R_SUCCESS)
1430                         return (result);
1431         }
1432         dns_db_currentversion(db_current, &version_current);
1433         if (db_current != db || version_current != version) {
1434                 result = ISC_R_FAILURE;
1435                 goto cleanup;
1436         }
1437
1438  cleanup:
1439         dns_db_closeversion(db_current, &version_current, ISC_FALSE);
1440         if (db0 == NULL && db_current != NULL)
1441                 dns_db_detach(&db_current);
1442
1443         return (result);
1444 }
1445
1446 static isc_result_t
1447 query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
1448         client_additionalctx_t *additionalctx = arg;
1449         dns_rdataset_t *rdataset_base;
1450         ns_client_t *client;
1451         isc_result_t result, eresult;
1452         dns_dbnode_t *node, *cnode;
1453         dns_db_t *db, *cdb;
1454         dns_name_t *fname, *mname0, cfname;
1455         dns_rdataset_t *rdataset, *sigrdataset;
1456         dns_rdataset_t *crdataset, *crdataset_next;
1457         isc_buffer_t *dbuf;
1458         isc_buffer_t b;
1459         dns_dbversion_t *version, *cversion;
1460         isc_boolean_t added_something, need_addname, needadditionalcache;
1461         isc_boolean_t need_sigrrset;
1462         dns_zone_t *zone;
1463         dns_rdatatype_t type;
1464         dns_rdatasetadditional_t additionaltype;
1465
1466         if (qtype != dns_rdatatype_a) {
1467                 /*
1468                  * This function is optimized for "address" types.  For other
1469                  * types, use a generic routine.
1470                  * XXX: ideally, this function should be generic enough.
1471                  */
1472                 return (query_addadditional(additionalctx->client,
1473                                             name, qtype));
1474         }
1475
1476         /*
1477          * Initialization.
1478          */
1479         rdataset_base = additionalctx->rdataset;
1480         client = additionalctx->client;
1481         REQUIRE(NS_CLIENT_VALID(client));
1482         eresult = ISC_R_SUCCESS;
1483         fname = NULL;
1484         rdataset = NULL;
1485         sigrdataset = NULL;
1486         db = NULL;
1487         cdb = NULL;
1488         version = NULL;
1489         cversion = NULL;
1490         node = NULL;
1491         cnode = NULL;
1492         added_something = ISC_FALSE;
1493         need_addname = ISC_FALSE;
1494         zone = NULL;
1495         needadditionalcache = ISC_FALSE;
1496         additionaltype = dns_rdatasetadditional_fromauth;
1497         dns_name_init(&cfname, NULL);
1498
1499         CTRACE("query_addadditional2");
1500
1501         /*
1502          * We treat type A additional section processing as if it
1503          * were "any address type" additional section processing.
1504          * To avoid multiple lookups, we do an 'any' database
1505          * lookup and iterate over the node.
1506          * XXXJT: this approach can cause a suboptimal result when the cache
1507          * DB only has partial address types and the glue DB has remaining
1508          * ones.
1509          */
1510         type = dns_rdatatype_any;
1511
1512         /*
1513          * Get some resources.
1514          */
1515         dbuf = query_getnamebuf(client);
1516         if (dbuf == NULL)
1517                 goto cleanup;
1518         fname = query_newname(client, dbuf, &b);
1519         if (fname == NULL)
1520                 goto cleanup;
1521         dns_name_setbuffer(&cfname, &b); /* share the buffer */
1522
1523         /* Check additional cache */
1524         result = dns_rdataset_getadditional(rdataset_base, additionaltype,
1525                                             type, client->view->acache, &zone,
1526                                             &cdb, &cversion, &cnode, &cfname,
1527                                             client->message, client->now);
1528         if (result != ISC_R_SUCCESS)
1529                 goto findauthdb;
1530         if (zone == NULL) {
1531                 CTRACE("query_addadditional2: auth zone not found");
1532                 goto try_cache;
1533         }
1534
1535         /* Is the cached DB up-to-date? */
1536         result = query_iscachevalid(zone, cdb, NULL, cversion);
1537         if (result != ISC_R_SUCCESS) {
1538                 CTRACE("query_addadditional2: old auth additional cache");
1539                 query_discardcache(client, rdataset_base, additionaltype,
1540                                    type, &zone, &cdb, &cversion, &cnode,
1541                                    &cfname);
1542                 goto findauthdb;
1543         }
1544
1545         if (cnode == NULL) {
1546                 /*
1547                  * We have a negative cache.  We don't have to check the zone
1548                  * ACL, since the result (not using this zone) would be same
1549                  * regardless of the result.
1550                  */
1551                 CTRACE("query_addadditional2: negative auth additional cache");
1552                 dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1553                 dns_db_detach(&cdb);
1554                 dns_zone_detach(&zone);
1555                 goto try_cache;
1556         }
1557
1558         result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG,
1559                                       zone, cdb, NULL);
1560         if (result != ISC_R_SUCCESS) {
1561                 query_discardcache(client, rdataset_base, additionaltype,
1562                                    type, &zone, &cdb, &cversion, &cnode,
1563                                    &cfname);
1564                 goto try_cache;
1565         }
1566
1567         /* We've got an active cache. */
1568         CTRACE("query_addadditional2: auth additional cache");
1569         dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1570         db = cdb;
1571         node = cnode;
1572         dns_name_clone(&cfname, fname);
1573         query_keepname(client, fname, dbuf);
1574         goto foundcache;
1575
1576         /*
1577          * Look for a zone database that might contain authoritative
1578          * additional data.
1579          */
1580  findauthdb:
1581         result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
1582                                  &zone, &db, &version);
1583         if (result != ISC_R_SUCCESS) {
1584                 /* Cache the negative result */
1585                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1586                                                  type, client->view->acache,
1587                                                  NULL, NULL, NULL, NULL,
1588                                                  NULL);
1589                 goto try_cache;
1590         }
1591
1592         CTRACE("query_addadditional2: db_find");
1593
1594         /*
1595          * Since we are looking for authoritative data, we do not set
1596          * the GLUEOK flag.  Glue will be looked for later, but not
1597          * necessarily in the same database.
1598          */
1599         node = NULL;
1600         result = dns_db_find(db, name, version, type, client->query.dboptions,
1601                              client->now, &node, fname, NULL, NULL);
1602         if (result == ISC_R_SUCCESS)
1603                 goto found;
1604
1605         /* Cache the negative result */
1606         (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1607                                          type, client->view->acache, zone, db,
1608                                          version, NULL, fname);
1609
1610         if (node != NULL)
1611                 dns_db_detachnode(db, &node);
1612         version = NULL;
1613         dns_db_detach(&db);
1614
1615         /*
1616          * No authoritative data was found.  The cache is our next best bet.
1617          */
1618
1619  try_cache:
1620         additionaltype = dns_rdatasetadditional_fromcache;
1621         result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
1622         if (result != ISC_R_SUCCESS)
1623                 /*
1624                  * Most likely the client isn't allowed to query the cache.
1625                  */
1626                 goto try_glue;
1627
1628         result = dns_db_find(db, name, version, type,
1629                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1630                              client->now, &node, fname, NULL, NULL);
1631         if (result == ISC_R_SUCCESS)
1632                 goto found;
1633
1634         if (node != NULL)
1635                 dns_db_detachnode(db, &node);
1636         dns_db_detach(&db);
1637
1638  try_glue:
1639         /*
1640          * No cached data was found.  Glue is our last chance.
1641          * RFC1035 sayeth:
1642          *
1643          *      NS records cause both the usual additional section
1644          *      processing to locate a type A record, and, when used
1645          *      in a referral, a special search of the zone in which
1646          *      they reside for glue information.
1647          *
1648          * This is the "special search".  Note that we must search
1649          * the zone where the NS record resides, not the zone it
1650          * points to, and that we only do the search in the delegation
1651          * case (identified by client->query.gluedb being set).
1652          */
1653         if (client->query.gluedb == NULL)
1654                 goto cleanup;
1655
1656         /*
1657          * Don't poison caches using the bailiwick protection model.
1658          */
1659         if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
1660                 goto cleanup;
1661
1662         /* Check additional cache */
1663         additionaltype = dns_rdatasetadditional_fromglue;
1664         result = dns_rdataset_getadditional(rdataset_base, additionaltype,
1665                                             type, client->view->acache, NULL,
1666                                             &cdb, &cversion, &cnode, &cfname,
1667                                             client->message, client->now);
1668         if (result != ISC_R_SUCCESS)
1669                 goto findglue;
1670
1671         result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion);
1672         if (result != ISC_R_SUCCESS) {
1673                 CTRACE("query_addadditional2: old glue additional cache");
1674                 query_discardcache(client, rdataset_base, additionaltype,
1675                                    type, &zone, &cdb, &cversion, &cnode,
1676                                    &cfname);
1677                 goto findglue;
1678         }
1679
1680         if (cnode == NULL) {
1681                 /* We have a negative cache. */
1682                 CTRACE("query_addadditional2: negative glue additional cache");
1683                 dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1684                 dns_db_detach(&cdb);
1685                 goto cleanup;
1686         }
1687
1688         /* Cache hit. */
1689         CTRACE("query_addadditional2: glue additional cache");
1690         dns_db_closeversion(cdb, &cversion, ISC_FALSE);
1691         db = cdb;
1692         node = cnode;
1693         dns_name_clone(&cfname, fname);
1694         query_keepname(client, fname, dbuf);
1695         goto foundcache;
1696
1697  findglue:
1698         dns_db_attach(client->query.gluedb, &db);
1699         result = dns_db_find(db, name, version, type,
1700                              client->query.dboptions | DNS_DBFIND_GLUEOK,
1701                              client->now, &node, fname, NULL, NULL);
1702         if (!(result == ISC_R_SUCCESS ||
1703               result == DNS_R_ZONECUT ||
1704               result == DNS_R_GLUE)) {
1705                 /* cache the negative result */
1706                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1707                                                  type, client->view->acache,
1708                                                  NULL, db, version, NULL,
1709                                                  fname);
1710                 goto cleanup;
1711         }
1712
1713  found:
1714         /*
1715          * We have found a DB node to iterate over from a DB.
1716          * We are going to look for address RRsets (i.e., A and AAAA) in the DB
1717          * node we've just found.  We'll then store the complete information
1718          * in the additional data cache.
1719          */
1720         dns_name_clone(fname, &cfname);
1721         query_keepname(client, fname, dbuf);
1722         needadditionalcache = ISC_TRUE;
1723
1724         rdataset = query_newrdataset(client);
1725         if (rdataset == NULL)
1726                 goto cleanup;
1727
1728         sigrdataset = query_newrdataset(client);
1729         if (sigrdataset == NULL)
1730                 goto cleanup;
1731
1732         /*
1733          * Find A RRset with sig RRset.  Even if we don't find a sig RRset
1734          * for a client using DNSSEC, we'll continue the process to make a
1735          * complete list to be cached.  However, we need to cancel the
1736          * caching when something unexpected happens, in order to avoid
1737          * caching incomplete information.
1738          */
1739         result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0,
1740                                      client->now, rdataset, sigrdataset);
1741         /*
1742          * If we can't promote glue/pending from the cache to secure
1743          * then drop it.
1744          */
1745         if (result == ISC_R_SUCCESS &&
1746             additionaltype == dns_rdatasetadditional_fromcache &&
1747             (rdataset->trust == dns_trust_pending ||
1748              rdataset->trust == dns_trust_glue) &&
1749             !validate(client, db, fname, rdataset, sigrdataset)) {
1750                 dns_rdataset_disassociate(rdataset);
1751                 if (dns_rdataset_isassociated(sigrdataset))
1752                         dns_rdataset_disassociate(sigrdataset);
1753                 result = ISC_R_NOTFOUND;
1754         }
1755         if (result == DNS_R_NCACHENXDOMAIN)
1756                 goto setcache;
1757         if (result == DNS_R_NCACHENXRRSET) {
1758                 dns_rdataset_disassociate(rdataset);
1759                 /*
1760                  * Negative cache entries don't have sigrdatasets.
1761                  */
1762                 INSIST(! dns_rdataset_isassociated(sigrdataset));
1763         }
1764         if (result == ISC_R_SUCCESS) {
1765                 /* Remember the result as a cache */
1766                 ISC_LIST_APPEND(cfname.list, rdataset, link);
1767                 if (dns_rdataset_isassociated(sigrdataset)) {
1768                         ISC_LIST_APPEND(cfname.list, sigrdataset, link);
1769                         sigrdataset = query_newrdataset(client);
1770                 }
1771                 rdataset = query_newrdataset(client);
1772                 if (sigrdataset == NULL || rdataset == NULL) {
1773                         /* do not cache incomplete information */
1774                         goto foundcache;
1775                 }
1776         }
1777
1778         /* Find AAAA RRset with sig RRset */
1779         result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa,
1780                                      0, client->now, rdataset, sigrdataset);
1781         /*
1782          * If we can't promote glue/pending from the cache to secure
1783          * then drop it.
1784          */
1785         if (result == ISC_R_SUCCESS &&
1786             additionaltype == dns_rdatasetadditional_fromcache &&
1787             (rdataset->trust == dns_trust_pending ||
1788              rdataset->trust == dns_trust_glue) &&
1789             !validate(client, db, fname, rdataset, sigrdataset)) {
1790                 dns_rdataset_disassociate(rdataset);
1791                 if (dns_rdataset_isassociated(sigrdataset))
1792                         dns_rdataset_disassociate(sigrdataset);
1793                 result = ISC_R_NOTFOUND;
1794         }
1795         if (result == ISC_R_SUCCESS) {
1796                 ISC_LIST_APPEND(cfname.list, rdataset, link);
1797                 rdataset = NULL;
1798                 if (dns_rdataset_isassociated(sigrdataset)) {
1799                         ISC_LIST_APPEND(cfname.list, sigrdataset, link);
1800                         sigrdataset = NULL;
1801                 }
1802         }
1803
1804  setcache:
1805         /*
1806          * Set the new result in the cache if required.  We do not support
1807          * caching additional data from a cache DB.
1808          */
1809         if (needadditionalcache == ISC_TRUE &&
1810             (additionaltype == dns_rdatasetadditional_fromauth ||
1811              additionaltype == dns_rdatasetadditional_fromglue)) {
1812                 (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
1813                                                  type, client->view->acache,
1814                                                  zone, db, version, node,
1815                                                  &cfname);
1816         }
1817
1818  foundcache:
1819         need_sigrrset = ISC_FALSE;
1820         mname0 = NULL;
1821         for (crdataset = ISC_LIST_HEAD(cfname.list);
1822              crdataset != NULL;
1823              crdataset = crdataset_next) {
1824                 dns_name_t *mname;
1825
1826                 crdataset_next = ISC_LIST_NEXT(crdataset, link);
1827
1828                 mname = NULL;
1829                 if (crdataset->type == dns_rdatatype_a ||
1830                     crdataset->type == dns_rdatatype_aaaa) {
1831                         if (!query_isduplicate(client, fname, crdataset->type,
1832                                                &mname)) {
1833                                 if (mname != NULL) {
1834                                         /*
1835                                          * A different type of this name is
1836                                          * already stored in the additional
1837                                          * section.  We'll reuse the name.
1838                                          * Note that this should happen at most
1839                                          * once.  Otherwise, fname->link could
1840                                          * leak below.
1841                                          */
1842                                         INSIST(mname0 == NULL);
1843
1844                                         query_releasename(client, &fname);
1845                                         fname = mname;
1846                                         mname0 = mname;
1847                                 } else
1848                                         need_addname = ISC_TRUE;
1849                                 ISC_LIST_UNLINK(cfname.list, crdataset, link);
1850                                 ISC_LIST_APPEND(fname->list, crdataset, link);
1851                                 added_something = ISC_TRUE;
1852                                 need_sigrrset = ISC_TRUE;
1853                         } else
1854                                 need_sigrrset = ISC_FALSE;
1855                 } else if (crdataset->type == dns_rdatatype_rrsig &&
1856                            need_sigrrset && WANTDNSSEC(client)) {
1857                         ISC_LIST_UNLINK(cfname.list, crdataset, link);
1858                         ISC_LIST_APPEND(fname->list, crdataset, link);
1859                         added_something = ISC_TRUE; /* just in case */
1860                         need_sigrrset = ISC_FALSE;
1861                 }
1862         }
1863
1864         CTRACE("query_addadditional2: addname");
1865
1866         /*
1867          * If we haven't added anything, then we're done.
1868          */
1869         if (!added_something)
1870                 goto cleanup;
1871
1872         /*
1873          * We may have added our rdatasets to an existing name, if so, then
1874          * need_addname will be ISC_FALSE.  Whether we used an existing name
1875          * or a new one, we must set fname to NULL to prevent cleanup.
1876          */
1877         if (need_addname)
1878                 dns_message_addname(client->message, fname,
1879                                     DNS_SECTION_ADDITIONAL);
1880         fname = NULL;
1881
1882  cleanup:
1883         CTRACE("query_addadditional2: cleanup");
1884
1885         if (rdataset != NULL)
1886                 query_putrdataset(client, &rdataset);
1887         if (sigrdataset != NULL)
1888                 query_putrdataset(client, &sigrdataset);
1889         while  ((crdataset = ISC_LIST_HEAD(cfname.list)) != NULL) {
1890                 ISC_LIST_UNLINK(cfname.list, crdataset, link);
1891                 query_putrdataset(client, &crdataset);
1892         }
1893         if (fname != NULL)
1894                 query_releasename(client, &fname);
1895         if (node != NULL)
1896                 dns_db_detachnode(db, &node);
1897         if (db != NULL)
1898                 dns_db_detach(&db);
1899         if (zone != NULL)
1900                 dns_zone_detach(&zone);
1901
1902         CTRACE("query_addadditional2: done");
1903         return (eresult);
1904 }
1905
1906 static inline void
1907 query_addrdataset(ns_client_t *client, dns_name_t *fname,
1908                   dns_rdataset_t *rdataset)
1909 {
1910         client_additionalctx_t additionalctx;
1911
1912         /*
1913          * Add 'rdataset' and any pertinent additional data to
1914          * 'fname', a name in the response message for 'client'.
1915          */
1916
1917         CTRACE("query_addrdataset");
1918
1919         ISC_LIST_APPEND(fname->list, rdataset, link);
1920
1921         if (client->view->order != NULL)
1922                 rdataset->attributes |= dns_order_find(client->view->order,
1923                                                        fname, rdataset->type,
1924                                                        rdataset->rdclass);
1925         rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
1926
1927         if (NOADDITIONAL(client))
1928                 return;
1929
1930         /*
1931          * Add additional data.
1932          *
1933          * We don't care if dns_rdataset_additionaldata() fails.
1934          */
1935         additionalctx.client = client;
1936         additionalctx.rdataset = rdataset;
1937         (void)dns_rdataset_additionaldata(rdataset, query_addadditional2,
1938                                           &additionalctx);
1939         CTRACE("query_addrdataset: done");
1940 }
1941
1942 static void
1943 query_addrrset(ns_client_t *client, dns_name_t **namep,
1944                dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
1945                isc_buffer_t *dbuf, dns_section_t section)
1946 {
1947         dns_name_t *name, *mname;
1948         dns_rdataset_t *rdataset, *mrdataset, *sigrdataset;
1949         isc_result_t result;
1950
1951         /*%
1952          * To the current response for 'client', add the answer RRset
1953          * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
1954          * owner name '*namep', to section 'section', unless they are
1955          * already there.  Also add any pertinent additional data.
1956          *
1957          * If 'dbuf' is not NULL, then '*namep' is the name whose data is
1958          * stored in 'dbuf'.  In this case, query_addrrset() guarantees that
1959          * when it returns the name will either have been kept or released.
1960          */
1961         CTRACE("query_addrrset");
1962         name = *namep;
1963         rdataset = *rdatasetp;
1964         if (sigrdatasetp != NULL)
1965                 sigrdataset = *sigrdatasetp;
1966         else
1967                 sigrdataset = NULL;
1968         mname = NULL;
1969         mrdataset = NULL;
1970         result = dns_message_findname(client->message, section,
1971                                       name, rdataset->type, rdataset->covers,
1972                                       &mname, &mrdataset);
1973         if (result == ISC_R_SUCCESS) {
1974                 /*
1975                  * We've already got an RRset of the given name and type.
1976                  * There's nothing else to do;
1977                  */
1978                 CTRACE("query_addrrset: dns_message_findname succeeded: done");
1979                 if (dbuf != NULL)
1980                         query_releasename(client, namep);
1981                 return;
1982         } else if (result == DNS_R_NXDOMAIN) {
1983                 /*
1984                  * The name doesn't exist.
1985                  */
1986                 if (dbuf != NULL)
1987                         query_keepname(client, name, dbuf);
1988                 dns_message_addname(client->message, name, section);
1989                 *namep = NULL;
1990                 mname = name;
1991         } else {
1992                 RUNTIME_CHECK(result == DNS_R_NXRRSET);
1993                 if (dbuf != NULL)
1994                         query_releasename(client, namep);
1995         }
1996
1997         if (rdataset->trust != dns_trust_secure &&
1998             (section == DNS_SECTION_ANSWER ||
1999              section == DNS_SECTION_AUTHORITY))
2000                 client->query.attributes &= ~NS_QUERYATTR_SECURE;
2001         /*
2002          * Note: we only add SIGs if we've added the type they cover, so
2003          * we do not need to check if the SIG rdataset is already in the
2004          * response.
2005          */
2006         query_addrdataset(client, mname, rdataset);
2007         *rdatasetp = NULL;
2008         if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
2009                 /*
2010                  * We have a signature.  Add it to the response.
2011                  */
2012                 ISC_LIST_APPEND(mname->list, sigrdataset, link);
2013                 *sigrdatasetp = NULL;
2014         }
2015         CTRACE("query_addrrset: done");
2016 }
2017
2018 static inline isc_result_t
2019 query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
2020              isc_boolean_t zero_ttl)
2021 {
2022         dns_name_t *name;
2023         dns_dbnode_t *node;
2024         isc_result_t result, eresult;
2025         dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
2026         dns_rdataset_t **sigrdatasetp = NULL;
2027
2028         CTRACE("query_addsoa");
2029         /*
2030          * Initialization.
2031          */
2032         eresult = ISC_R_SUCCESS;
2033         name = NULL;
2034         rdataset = NULL;
2035         node = NULL;
2036
2037         /*
2038          * Get resources and make 'name' be the database origin.
2039          */
2040         result = dns_message_gettempname(client->message, &name);
2041         if (result != ISC_R_SUCCESS)
2042                 return (result);
2043         dns_name_init(name, NULL);
2044         dns_name_clone(dns_db_origin(db), name);
2045         rdataset = query_newrdataset(client);
2046         if (rdataset == NULL) {
2047                 eresult = DNS_R_SERVFAIL;
2048                 goto cleanup;
2049         }
2050         if (WANTDNSSEC(client)) {
2051                 sigrdataset = query_newrdataset(client);
2052                 if (sigrdataset == NULL) {
2053                         eresult = DNS_R_SERVFAIL;
2054                         goto cleanup;
2055                 }
2056         }
2057
2058         /*
2059          * Find the SOA.
2060          */
2061         result = dns_db_getoriginnode(db, &node);
2062         if (result == ISC_R_SUCCESS) {
2063                 result = dns_db_findrdataset(db, node, version,
2064                                              dns_rdatatype_soa,
2065                                              0, client->now, rdataset,
2066                                              sigrdataset);
2067         } else {
2068                 dns_fixedname_t foundname;
2069                 dns_name_t *fname;
2070
2071                 dns_fixedname_init(&foundname);
2072                 fname = dns_fixedname_name(&foundname);
2073
2074                 result = dns_db_find(db, name, version, dns_rdatatype_soa,
2075                                      client->query.dboptions, 0, &node,
2076                                      fname, rdataset, sigrdataset);
2077         }
2078         if (result != ISC_R_SUCCESS) {
2079                 /*
2080                  * This is bad.  We tried to get the SOA RR at the zone top
2081                  * and it didn't work!
2082                  */
2083                 eresult = DNS_R_SERVFAIL;
2084         } else {
2085                 /*
2086                  * Extract the SOA MINIMUM.
2087                  */
2088                 dns_rdata_soa_t soa;
2089                 dns_rdata_t rdata = DNS_RDATA_INIT;
2090                 result = dns_rdataset_first(rdataset);
2091                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2092                 dns_rdataset_current(rdataset, &rdata);
2093                 result = dns_rdata_tostruct(&rdata, &soa, NULL);
2094                 if (result != ISC_R_SUCCESS)
2095                         goto cleanup;
2096
2097                 if (zero_ttl) {
2098                         rdataset->ttl = 0;
2099                         if (sigrdataset != NULL)
2100                                 sigrdataset->ttl = 0;
2101                 }
2102
2103                 /*
2104                  * Add the SOA and its SIG to the response, with the
2105                  * TTLs adjusted per RFC2308 section 3.
2106                  */
2107                 if (rdataset->ttl > soa.minimum)
2108                         rdataset->ttl = soa.minimum;
2109                 if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum)
2110                         sigrdataset->ttl = soa.minimum;
2111
2112                 if (sigrdataset != NULL)
2113                         sigrdatasetp = &sigrdataset;
2114                 else
2115                         sigrdatasetp = NULL;
2116                 query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL,
2117                                DNS_SECTION_AUTHORITY);
2118         }
2119
2120  cleanup:
2121         query_putrdataset(client, &rdataset);
2122         if (sigrdataset != NULL)
2123                 query_putrdataset(client, &sigrdataset);
2124         if (name != NULL)
2125                 query_releasename(client, &name);
2126         if (node != NULL)
2127                 dns_db_detachnode(db, &node);
2128
2129         return (eresult);
2130 }
2131
2132 static inline isc_result_t
2133 query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
2134         dns_name_t *name, *fname;
2135         dns_dbnode_t *node;
2136         isc_result_t result, eresult;
2137         dns_fixedname_t foundname;
2138         dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
2139         dns_rdataset_t **sigrdatasetp = NULL;
2140
2141         CTRACE("query_addns");
2142         /*
2143          * Initialization.
2144          */
2145         eresult = ISC_R_SUCCESS;
2146         name = NULL;
2147         rdataset = NULL;
2148         node = NULL;
2149         dns_fixedname_init(&foundname);
2150         fname = dns_fixedname_name(&foundname);
2151
2152         /*
2153          * Get resources and make 'name' be the database origin.
2154          */
2155         result = dns_message_gettempname(client->message, &name);
2156         if (result != ISC_R_SUCCESS) {
2157                 CTRACE("query_addns: dns_message_gettempname failed: done");
2158                 return (result);
2159         }
2160         dns_name_init(name, NULL);
2161         dns_name_clone(dns_db_origin(db), name);
2162         rdataset = query_newrdataset(client);
2163         if (rdataset == NULL) {
2164                 CTRACE("query_addns: query_newrdataset failed");
2165                 eresult = DNS_R_SERVFAIL;
2166                 goto cleanup;
2167         }
2168         if (WANTDNSSEC(client)) {
2169                 sigrdataset = query_newrdataset(client);
2170                 if (sigrdataset == NULL) {
2171                         CTRACE("query_addns: query_newrdataset failed");
2172                         eresult = DNS_R_SERVFAIL;
2173                         goto cleanup;
2174                 }
2175         }
2176
2177         /*
2178          * Find the NS rdataset.
2179          */
2180         result = dns_db_getoriginnode(db, &node);
2181         if (result == ISC_R_SUCCESS) {
2182                 result = dns_db_findrdataset(db, node, version,
2183                                              dns_rdatatype_ns,
2184                                              0, client->now, rdataset,
2185                                              sigrdataset);
2186         } else {
2187                 CTRACE("query_addns: calling dns_db_find");
2188                 result = dns_db_find(db, name, NULL, dns_rdatatype_ns,
2189                                      client->query.dboptions, 0, &node,
2190                                      fname, rdataset, sigrdataset);
2191                 CTRACE("query_addns: dns_db_find complete");
2192         }
2193         if (result != ISC_R_SUCCESS) {
2194                 CTRACE("query_addns: "
2195                        "dns_db_findrdataset or dns_db_find failed");
2196                 /*
2197                  * This is bad.  We tried to get the NS rdataset at the zone
2198                  * top and it didn't work!
2199                  */
2200                 eresult = DNS_R_SERVFAIL;
2201         } else {
2202                 if (sigrdataset != NULL)
2203                         sigrdatasetp = &sigrdataset;
2204                 else
2205                         sigrdatasetp = NULL;
2206                 query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL,
2207                                DNS_SECTION_AUTHORITY);
2208         }
2209
2210  cleanup:
2211         CTRACE("query_addns: cleanup");
2212         query_putrdataset(client, &rdataset);
2213         if (sigrdataset != NULL)
2214                 query_putrdataset(client, &sigrdataset);
2215         if (name != NULL)
2216                 query_releasename(client, &name);
2217         if (node != NULL)
2218                 dns_db_detachnode(db, &node);
2219
2220         CTRACE("query_addns: done");
2221         return (eresult);
2222 }
2223
2224 static inline isc_result_t
2225 query_addcnamelike(ns_client_t *client, dns_name_t *qname, dns_name_t *tname,
2226                    dns_trust_t trust, dns_name_t **anamep, dns_rdatatype_t type)
2227 {
2228         dns_rdataset_t *rdataset;
2229         dns_rdatalist_t *rdatalist;
2230         dns_rdata_t *rdata;
2231         isc_result_t result;
2232         isc_region_t r;
2233
2234         /*
2235          * We assume the name data referred to by tname won't go away.
2236          */
2237
2238         REQUIRE(anamep != NULL);
2239
2240         rdatalist = NULL;
2241         result = dns_message_gettemprdatalist(client->message, &rdatalist);
2242         if (result != ISC_R_SUCCESS)
2243                 return (result);
2244         rdata = NULL;
2245         result = dns_message_gettemprdata(client->message, &rdata);
2246         if (result != ISC_R_SUCCESS)
2247                 return (result);
2248         rdataset = NULL;
2249         result = dns_message_gettemprdataset(client->message, &rdataset);
2250         if (result != ISC_R_SUCCESS)
2251                 return (result);
2252         dns_rdataset_init(rdataset);
2253         result = dns_name_dup(qname, client->mctx, *anamep);
2254         if (result != ISC_R_SUCCESS) {
2255                 dns_message_puttemprdataset(client->message, &rdataset);
2256                 return (result);
2257         }
2258
2259         rdatalist->type = type;
2260         rdatalist->covers = 0;
2261         rdatalist->rdclass = client->message->rdclass;
2262         rdatalist->ttl = 0;
2263
2264         dns_name_toregion(tname, &r);
2265         rdata->data = r.base;
2266         rdata->length = r.length;
2267         rdata->rdclass = client->message->rdclass;
2268         rdata->type = type;
2269
2270         ISC_LIST_INIT(rdatalist->rdata);
2271         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2272         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset)
2273                       == ISC_R_SUCCESS);
2274         rdataset->trust = trust;
2275
2276         query_addrrset(client, anamep, &rdataset, NULL, NULL,
2277                        DNS_SECTION_ANSWER);
2278
2279         if (rdataset != NULL) {
2280                 if (dns_rdataset_isassociated(rdataset))
2281                         dns_rdataset_disassociate(rdataset);
2282                 dns_message_puttemprdataset(client->message, &rdataset);
2283         }
2284
2285         return (ISC_R_SUCCESS);
2286 }
2287
2288 /*
2289  * Mark the RRsets as secure.  Update the cache (db) to reflect the
2290  * change in trust level.
2291  */
2292 static void
2293 mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2294             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
2295 {
2296         isc_result_t result;
2297         dns_dbnode_t *node = NULL;
2298
2299         rdataset->trust = dns_trust_secure;
2300         sigrdataset->trust = dns_trust_secure;
2301
2302         /*
2303          * Save the updated secure state.  Ignore failures.
2304          */
2305         result = dns_db_findnode(db, name, ISC_TRUE, &node);
2306         if (result != ISC_R_SUCCESS)
2307                 return;
2308         (void)dns_db_addrdataset(db, node, NULL, client->now, rdataset,
2309                                  0, NULL);
2310         (void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset,
2311                                  0, NULL);
2312         dns_db_detachnode(db, &node);
2313 }
2314
2315 /*
2316  * Find the secure key that corresponds to rrsig.
2317  * Note: 'keyrdataset' maintains state between successive calls,
2318  * there may be multiple keys with the same keyid.
2319  * Return ISC_FALSE if we have exhausted all the possible keys.
2320  */
2321 static isc_boolean_t
2322 get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
2323         dns_rdataset_t *keyrdataset, dst_key_t **keyp)
2324 {
2325         isc_result_t result;
2326         dns_dbnode_t *node = NULL;
2327         isc_boolean_t secure = ISC_FALSE;
2328
2329         if (!dns_rdataset_isassociated(keyrdataset)) {
2330                 result = dns_db_findnode(db, &rrsig->signer, ISC_FALSE, &node);
2331                 if (result != ISC_R_SUCCESS)
2332                         return (ISC_FALSE);
2333
2334                 result = dns_db_findrdataset(db, node, NULL,
2335                                              dns_rdatatype_dnskey, 0,
2336                                              client->now, keyrdataset, NULL);
2337                 dns_db_detachnode(db, &node);
2338                 if (result != ISC_R_SUCCESS)
2339                         return (ISC_FALSE);
2340
2341                 if (keyrdataset->trust != dns_trust_secure)
2342                         return (ISC_FALSE);
2343
2344                 result = dns_rdataset_first(keyrdataset);
2345         } else
2346                 result = dns_rdataset_next(keyrdataset);
2347
2348         for ( ; result == ISC_R_SUCCESS;
2349              result = dns_rdataset_next(keyrdataset)) {
2350                 dns_rdata_t rdata = DNS_RDATA_INIT;
2351                 isc_buffer_t b;
2352
2353                 dns_rdataset_current(keyrdataset, &rdata);
2354                 isc_buffer_init(&b, rdata.data, rdata.length);
2355                 isc_buffer_add(&b, rdata.length);
2356                 result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
2357                                          client->mctx, keyp);
2358                 if (result != ISC_R_SUCCESS)
2359                         continue;
2360                 if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
2361                     rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
2362                     dst_key_iszonekey(*keyp)) {
2363                         secure = ISC_TRUE;
2364                         break;
2365                 }
2366                 dst_key_free(keyp);
2367         }
2368         return (secure);
2369 }
2370
2371 static isc_boolean_t
2372 verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
2373        dns_rdata_t *rdata, isc_mem_t *mctx, isc_boolean_t acceptexpired)
2374 {
2375         isc_result_t result;
2376         dns_fixedname_t fixed;
2377         isc_boolean_t ignore = ISC_FALSE;
2378
2379         dns_fixedname_init(&fixed);
2380
2381 again:
2382         result = dns_dnssec_verify2(name, rdataset, key, ignore, mctx,
2383                                     rdata, NULL);
2384         if (result == DNS_R_SIGEXPIRED && acceptexpired) {
2385                 ignore = ISC_TRUE;
2386                 goto again;
2387         }
2388         if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD)
2389                 return (ISC_TRUE);
2390         return (ISC_FALSE);
2391 }
2392
2393 /*
2394  * Validate the rdataset if possible with available records.
2395  */
2396 static isc_boolean_t
2397 validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2398          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
2399 {
2400         isc_result_t result;
2401         dns_rdata_t rdata = DNS_RDATA_INIT;
2402         dns_rdata_rrsig_t rrsig;
2403         dst_key_t *key = NULL;
2404         dns_rdataset_t keyrdataset;
2405
2406         if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
2407                 return (ISC_FALSE);
2408
2409         for (result = dns_rdataset_first(sigrdataset);
2410              result == ISC_R_SUCCESS;
2411              result = dns_rdataset_next(sigrdataset)) {
2412
2413                 dns_rdata_reset(&rdata);
2414                 dns_rdataset_current(sigrdataset, &rdata);
2415                 result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
2416                 if (result != ISC_R_SUCCESS)
2417                         return (ISC_FALSE);
2418                 if (!dns_resolver_algorithm_supported(client->view->resolver,
2419                                                       name, rrsig.algorithm))
2420                         continue;
2421                 if (!dns_name_issubdomain(name, &rrsig.signer))
2422                         continue;
2423                 dns_rdataset_init(&keyrdataset);
2424                 do {
2425                         if (!get_key(client, db, &rrsig, &keyrdataset, &key))
2426                                 break;
2427                         if (verify(key, name, rdataset, &rdata, client->mctx,
2428                                    client->view->acceptexpired)) {
2429                                 dst_key_free(&key);
2430                                 dns_rdataset_disassociate(&keyrdataset);
2431                                 mark_secure(client, db, name, rdataset,
2432                                             sigrdataset);
2433                                 return (ISC_TRUE);
2434                         }
2435                         dst_key_free(&key);
2436                 } while (1);
2437                 if (dns_rdataset_isassociated(&keyrdataset))
2438                         dns_rdataset_disassociate(&keyrdataset);
2439         }
2440         return (ISC_FALSE);
2441 }
2442
2443 static void
2444 query_addbestns(ns_client_t *client) {
2445         dns_db_t *db, *zdb;
2446         dns_dbnode_t *node;
2447         dns_name_t *fname, *zfname;
2448         dns_rdataset_t *rdataset, *sigrdataset, *zrdataset, *zsigrdataset;
2449         isc_boolean_t is_zone, use_zone;
2450         isc_buffer_t *dbuf;
2451         isc_result_t result;
2452         dns_dbversion_t *version;
2453         dns_zone_t *zone;
2454         isc_buffer_t b;
2455
2456         CTRACE("query_addbestns");
2457         fname = NULL;
2458         zfname = NULL;
2459         rdataset = NULL;
2460         zrdataset = NULL;
2461         sigrdataset = NULL;
2462         zsigrdataset = NULL;
2463         node = NULL;
2464         db = NULL;
2465         zdb = NULL;
2466         version = NULL;
2467         zone = NULL;
2468         is_zone = ISC_FALSE;
2469         use_zone = ISC_FALSE;
2470
2471         /*
2472          * Find the right database.
2473          */
2474         result = query_getdb(client, client->query.qname, dns_rdatatype_ns, 0,
2475                              &zone, &db, &version, &is_zone);
2476         if (result != ISC_R_SUCCESS)
2477                 goto cleanup;
2478
2479  db_find:
2480         /*
2481          * We'll need some resources...
2482          */
2483         dbuf = query_getnamebuf(client);
2484         if (dbuf == NULL)
2485                 goto cleanup;
2486         fname = query_newname(client, dbuf, &b);
2487         rdataset = query_newrdataset(client);
2488         if (fname == NULL || rdataset == NULL)
2489                 goto cleanup;
2490         /*
2491          * Get the RRSIGs if the client requested them or if we may
2492          * need to validate answers from the cache.
2493          */
2494         if (WANTDNSSEC(client) || !is_zone) {
2495                 sigrdataset = query_newrdataset(client);
2496                 if (sigrdataset == NULL)
2497                         goto cleanup;
2498         }
2499
2500         /*
2501          * Now look for the zonecut.
2502          */
2503         if (is_zone) {
2504                 result = dns_db_find(db, client->query.qname, version,
2505                                      dns_rdatatype_ns, client->query.dboptions,
2506                                      client->now, &node, fname,
2507                                      rdataset, sigrdataset);
2508                 if (result != DNS_R_DELEGATION)
2509                         goto cleanup;
2510                 if (USECACHE(client)) {
2511                         query_keepname(client, fname, dbuf);
2512                         zdb = db;
2513                         zfname = fname;
2514                         fname = NULL;
2515                         zrdataset = rdataset;
2516                         rdataset = NULL;
2517                         zsigrdataset = sigrdataset;
2518                         sigrdataset = NULL;
2519                         dns_db_detachnode(db, &node);
2520                         version = NULL;
2521                         db = NULL;
2522                         dns_db_attach(client->view->cachedb, &db);
2523                         is_zone = ISC_FALSE;
2524                         goto db_find;
2525                 }
2526         } else {
2527                 result = dns_db_findzonecut(db, client->query.qname,
2528                                             client->query.dboptions,
2529                                             client->now, &node, fname,
2530                                             rdataset, sigrdataset);
2531                 if (result == ISC_R_SUCCESS) {
2532                         if (zfname != NULL &&
2533                             !dns_name_issubdomain(fname, zfname)) {
2534                                 /*
2535                                  * We found a zonecut in the cache, but our
2536                                  * zone delegation is better.
2537                                  */
2538                                 use_zone = ISC_TRUE;
2539                         }
2540                 } else if (result == ISC_R_NOTFOUND && zfname != NULL) {
2541                         /*
2542                          * We didn't find anything in the cache, but we
2543                          * have a zone delegation, so use it.
2544                          */
2545                         use_zone = ISC_TRUE;
2546                 } else
2547                         goto cleanup;
2548         }
2549
2550         if (use_zone) {
2551                 query_releasename(client, &fname);
2552                 fname = zfname;
2553                 zfname = NULL;
2554                 /*
2555                  * We've already done query_keepname() on
2556                  * zfname, so we must set dbuf to NULL to
2557                  * prevent query_addrrset() from trying to
2558                  * call query_keepname() again.
2559                  */
2560                 dbuf = NULL;
2561                 query_putrdataset(client, &rdataset);
2562                 if (sigrdataset != NULL)
2563                         query_putrdataset(client, &sigrdataset);
2564                 rdataset = zrdataset;
2565                 zrdataset = NULL;
2566                 sigrdataset = zsigrdataset;
2567                 zsigrdataset = NULL;
2568         }
2569
2570         /*
2571          * Attempt to validate RRsets that are pending or that are glue.
2572          */
2573         if ((rdataset->trust == dns_trust_pending ||
2574              (sigrdataset != NULL && sigrdataset->trust == dns_trust_pending))
2575             && !validate(client, db, fname, rdataset, sigrdataset) &&
2576             (client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0)
2577                 goto cleanup;
2578
2579         if ((rdataset->trust == dns_trust_glue ||
2580              (sigrdataset != NULL && sigrdataset->trust == dns_trust_glue)) &&
2581             !validate(client, db, fname, rdataset, sigrdataset) &&
2582             SECURE(client) && WANTDNSSEC(client))
2583                 goto cleanup;
2584
2585         /*
2586          * If the client doesn't want DNSSEC we can discard the sigrdataset
2587          * now.
2588          */
2589         if (!WANTDNSSEC(client))
2590                 query_putrdataset(client, &sigrdataset);
2591         query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2592                        DNS_SECTION_AUTHORITY);
2593
2594  cleanup:
2595         if (rdataset != NULL)
2596                 query_putrdataset(client, &rdataset);
2597         if (sigrdataset != NULL)
2598                 query_putrdataset(client, &sigrdataset);
2599         if (fname != NULL)
2600                 query_releasename(client, &fname);
2601         if (node != NULL)
2602                 dns_db_detachnode(db, &node);
2603         if (db != NULL)
2604                 dns_db_detach(&db);
2605         if (zone != NULL)
2606                 dns_zone_detach(&zone);
2607         if (zdb != NULL) {
2608                 query_putrdataset(client, &zrdataset);
2609                 if (zsigrdataset != NULL)
2610                         query_putrdataset(client, &zsigrdataset);
2611                 if (zfname != NULL)
2612                         query_releasename(client, &zfname);
2613                 dns_db_detach(&zdb);
2614         }
2615 }
2616
2617 static void
2618 query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node,
2619             dns_dbversion_t *version)
2620 {
2621         dns_name_t *rname;
2622         dns_rdataset_t *rdataset, *sigrdataset;
2623         isc_result_t result;
2624
2625         CTRACE("query_addds");
2626         rname = NULL;
2627         rdataset = NULL;
2628         sigrdataset = NULL;
2629
2630         /*
2631          * We'll need some resources...
2632          */
2633         rdataset = query_newrdataset(client);
2634         sigrdataset = query_newrdataset(client);
2635         if (rdataset == NULL || sigrdataset == NULL)
2636                 goto cleanup;
2637
2638         /*
2639          * Look for the DS record, which may or may not be present.
2640          */
2641         result = dns_db_findrdataset(db, node, version, dns_rdatatype_ds, 0,
2642                                      client->now, rdataset, sigrdataset);
2643         /*
2644          * If we didn't find it, look for an NSEC. */
2645         if (result == ISC_R_NOTFOUND)
2646                 result = dns_db_findrdataset(db, node, version,
2647                                              dns_rdatatype_nsec, 0, client->now,
2648                                              rdataset, sigrdataset);
2649         if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
2650                 goto cleanup;
2651         if (!dns_rdataset_isassociated(rdataset) ||
2652             !dns_rdataset_isassociated(sigrdataset))
2653                 goto cleanup;
2654
2655         /*
2656          * We've already added the NS record, so if the name's not there,
2657          * we have other problems.  Use this name rather than calling
2658          * query_addrrset().
2659          */
2660         result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
2661         if (result != ISC_R_SUCCESS)
2662                 goto cleanup;
2663
2664         rname = NULL;
2665         dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
2666                                 &rname);
2667         result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
2668         if (result != ISC_R_SUCCESS)
2669                 goto cleanup;
2670
2671         ISC_LIST_APPEND(rname->list, rdataset, link);
2672         ISC_LIST_APPEND(rname->list, sigrdataset, link);
2673         rdataset = NULL;
2674         sigrdataset = NULL;
2675
2676  cleanup:
2677         if (rdataset != NULL)
2678                 query_putrdataset(client, &rdataset);
2679         if (sigrdataset != NULL)
2680                 query_putrdataset(client, &sigrdataset);
2681 }
2682
2683 static void
2684 query_addwildcardproof(ns_client_t *client, dns_db_t *db,
2685                        dns_dbversion_t *version, dns_name_t *name,
2686                        isc_boolean_t ispositive)
2687 {
2688         isc_buffer_t *dbuf, b;
2689         dns_name_t *fname;
2690         dns_rdataset_t *rdataset, *sigrdataset;
2691         dns_fixedname_t wfixed;
2692         dns_name_t *wname;
2693         dns_dbnode_t *node;
2694         unsigned int options;
2695         unsigned int olabels, nlabels;
2696         isc_result_t result;
2697         dns_rdata_t rdata = DNS_RDATA_INIT;
2698         dns_rdata_nsec_t nsec;
2699         isc_boolean_t have_wname;
2700         int order;
2701
2702         CTRACE("query_addwildcardproof");
2703         fname = NULL;
2704         rdataset = NULL;
2705         sigrdataset = NULL;
2706         node = NULL;
2707
2708         /*
2709          * Get the NOQNAME proof then if !ispositive
2710          * get the NOWILDCARD proof.
2711          *
2712          * DNS_DBFIND_NOWILD finds the NSEC records that covers the
2713          * name ignoring any wildcard.  From the owner and next names
2714          * of this record you can compute which wildcard (if it exists)
2715          * will match by finding the longest common suffix of the
2716          * owner name and next names with the qname and prefixing that
2717          * with the wildcard label.
2718          *
2719          * e.g.
2720          *   Given:
2721          *      example SOA
2722          *      example NSEC b.example
2723          *      b.example A
2724          *      b.example NSEC a.d.example
2725          *      a.d.example A
2726          *      a.d.example NSEC g.f.example
2727          *      g.f.example A
2728          *      g.f.example NSEC z.i.example
2729          *      z.i.example A
2730          *      z.i.example NSEC example
2731          *
2732          *   QNAME:
2733          *   a.example -> example NSEC b.example
2734          *      owner common example
2735          *      next common example
2736          *      wild *.example
2737          *   d.b.example -> b.example NSEC a.d.example
2738          *      owner common b.example
2739          *      next common example
2740          *      wild *.b.example
2741          *   a.f.example -> a.d.example NSEC g.f.example
2742          *      owner common example
2743          *      next common f.example
2744          *      wild *.f.example
2745          *  j.example -> z.i.example NSEC example
2746          *      owner common example
2747          *      next common example
2748          *      wild *.f.example
2749          */
2750         options = client->query.dboptions | DNS_DBFIND_NOWILD;
2751         dns_fixedname_init(&wfixed);
2752         wname = dns_fixedname_name(&wfixed);
2753  again:
2754         have_wname = ISC_FALSE;
2755         /*
2756          * We'll need some resources...
2757          */
2758         dbuf = query_getnamebuf(client);
2759         if (dbuf == NULL)
2760                 goto cleanup;
2761         fname = query_newname(client, dbuf, &b);
2762         rdataset = query_newrdataset(client);
2763         sigrdataset = query_newrdataset(client);
2764         if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
2765                 goto cleanup;
2766
2767         result = dns_db_find(db, name, version, dns_rdatatype_nsec, options,
2768                              0, &node, fname, rdataset, sigrdataset);
2769         if (node != NULL)
2770                 dns_db_detachnode(db, &node);
2771         if (result == DNS_R_NXDOMAIN) {
2772                 if (!ispositive)
2773                         result = dns_rdataset_first(rdataset);
2774                 if (result == ISC_R_SUCCESS) {
2775                         dns_rdataset_current(rdataset, &rdata);
2776                         result = dns_rdata_tostruct(&rdata, &nsec, NULL);
2777                 }
2778                 if (result == ISC_R_SUCCESS) {
2779                         (void)dns_name_fullcompare(name, fname, &order,
2780                                                    &olabels);
2781                         (void)dns_name_fullcompare(name, &nsec.next, &order,
2782                                                    &nlabels);
2783                         /*
2784                          * Check for a pathological condition created when
2785                          * serving some malformed signed zones and bail out.
2786                          */
2787                         if (dns_name_countlabels(name) == nlabels)
2788                                 goto cleanup;
2789
2790                         if (olabels > nlabels)
2791                                 dns_name_split(name, olabels, NULL, wname);
2792                         else
2793                                 dns_name_split(name, nlabels, NULL, wname);
2794                         result = dns_name_concatenate(dns_wildcardname,
2795                                                       wname, wname, NULL);
2796                         if (result == ISC_R_SUCCESS)
2797                                 have_wname = ISC_TRUE;
2798                         dns_rdata_freestruct(&nsec);
2799                 }
2800                 query_addrrset(client, &fname, &rdataset, &sigrdataset,
2801                                dbuf, DNS_SECTION_AUTHORITY);
2802         }
2803         if (rdataset != NULL)
2804                 query_putrdataset(client, &rdataset);
2805         if (sigrdataset != NULL)
2806                 query_putrdataset(client, &sigrdataset);
2807         if (fname != NULL)
2808                 query_releasename(client, &fname);
2809         if (have_wname) {
2810                 ispositive = ISC_TRUE;  /* prevent loop */
2811                 if (!dns_name_equal(name, wname)) {
2812                         name = wname;
2813                         goto again;
2814                 }
2815         }
2816  cleanup:
2817         if (rdataset != NULL)
2818                 query_putrdataset(client, &rdataset);
2819         if (sigrdataset != NULL)
2820                 query_putrdataset(client, &sigrdataset);
2821         if (fname != NULL)
2822                 query_releasename(client, &fname);
2823 }
2824
2825 static void
2826 query_addnxrrsetnsec(ns_client_t *client, dns_db_t *db,
2827                      dns_dbversion_t *version, dns_name_t **namep,
2828                      dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp)
2829 {
2830         dns_name_t *name;
2831         dns_rdataset_t *sigrdataset;
2832         dns_rdata_t sigrdata;
2833         dns_rdata_rrsig_t sig;
2834         unsigned int labels;
2835         isc_buffer_t *dbuf, b;
2836         dns_name_t *fname;
2837         isc_result_t result;
2838
2839         name = *namep;
2840         if ((name->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
2841                 query_addrrset(client, namep, rdatasetp, sigrdatasetp,
2842                                NULL, DNS_SECTION_AUTHORITY);
2843                 return;
2844         }
2845
2846         if (sigrdatasetp == NULL)
2847                 return;
2848         sigrdataset = *sigrdatasetp;
2849         if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
2850                 return;
2851         result = dns_rdataset_first(sigrdataset);
2852         if (result != ISC_R_SUCCESS)
2853                 return;
2854         dns_rdata_init(&sigrdata);
2855         dns_rdataset_current(sigrdataset, &sigrdata);
2856         result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
2857         if (result != ISC_R_SUCCESS)
2858                 return;
2859
2860         labels = dns_name_countlabels(name);
2861         if ((unsigned int)sig.labels + 1 >= labels)
2862                 return;
2863
2864         /* XXX */
2865         query_addwildcardproof(client, db, version, client->query.qname,
2866                                ISC_TRUE);
2867
2868         /*
2869          * We'll need some resources...
2870          */
2871         dbuf = query_getnamebuf(client);
2872         if (dbuf == NULL)
2873                 return;
2874         fname = query_newname(client, dbuf, &b);
2875         if (fname == NULL)
2876                 return;
2877         dns_name_split(name, sig.labels + 1, NULL, fname);
2878         /* This will succeed, since we've stripped labels. */
2879         RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
2880                                            NULL) == ISC_R_SUCCESS);
2881         query_addrrset(client, &fname, rdatasetp, sigrdatasetp,
2882                        dbuf, DNS_SECTION_AUTHORITY);
2883 }
2884
2885 static void
2886 query_resume(isc_task_t *task, isc_event_t *event) {
2887         dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
2888         dns_fetch_t *fetch;
2889         ns_client_t *client;
2890         isc_boolean_t fetch_canceled, client_shuttingdown;
2891         isc_result_t result;
2892         isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_EERRORS;
2893         int errorloglevel;
2894
2895         /*
2896          * Resume a query after recursion.
2897          */
2898
2899         UNUSED(task);
2900
2901         REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
2902         client = devent->ev_arg;
2903         REQUIRE(NS_CLIENT_VALID(client));
2904         REQUIRE(task == client->task);
2905         REQUIRE(RECURSING(client));
2906
2907         LOCK(&client->query.fetchlock);
2908         if (client->query.fetch != NULL) {
2909                 /*
2910                  * This is the fetch we've been waiting for.
2911                  */
2912                 INSIST(devent->fetch == client->query.fetch);
2913                 client->query.fetch = NULL;
2914                 fetch_canceled = ISC_FALSE;
2915                 /*
2916                  * Update client->now.
2917                  */
2918                 isc_stdtime_get(&client->now);
2919         } else {
2920                 /*
2921                  * This is a fetch completion event for a canceled fetch.
2922                  * Clean up and don't resume the find.
2923                  */
2924                 fetch_canceled = ISC_TRUE;
2925         }
2926         UNLOCK(&client->query.fetchlock);
2927         INSIST(client->query.fetch == NULL);
2928
2929         client->query.attributes &= ~NS_QUERYATTR_RECURSING;
2930         fetch = devent->fetch;
2931         devent->fetch = NULL;
2932
2933         /*
2934          * If this client is shutting down, or this transaction
2935          * has timed out, do not resume the find.
2936          */
2937         client_shuttingdown = ns_client_shuttingdown(client);
2938         if (fetch_canceled || client_shuttingdown) {
2939                 if (devent->node != NULL)
2940                         dns_db_detachnode(devent->db, &devent->node);
2941                 if (devent->db != NULL)
2942                         dns_db_detach(&devent->db);
2943                 query_putrdataset(client, &devent->rdataset);
2944                 if (devent->sigrdataset != NULL)
2945                         query_putrdataset(client, &devent->sigrdataset);
2946                 isc_event_free(&event);
2947                 if (fetch_canceled)
2948                         query_error(client, DNS_R_SERVFAIL, __LINE__);
2949                 else
2950                         query_next(client, ISC_R_CANCELED);
2951                 /*
2952                  * This may destroy the client.
2953                  */
2954                 ns_client_detach(&client);
2955         } else {
2956                 result = query_find(client, devent, 0);
2957                 if (result != ISC_R_SUCCESS) {
2958                         if (result == DNS_R_SERVFAIL)
2959                                 errorloglevel = ISC_LOG_DEBUG(2);
2960                         else
2961                                 errorloglevel = ISC_LOG_DEBUG(4);
2962                         if (isc_log_wouldlog(ns_g_lctx, errorloglevel)) {
2963                                 dns_resolver_logfetch(fetch, ns_g_lctx,
2964                                                       logcategory,
2965                                                       NS_LOGMODULE_QUERY,
2966                                                       errorloglevel, ISC_FALSE);
2967                         }
2968                 }
2969         }
2970
2971         dns_resolver_destroyfetch(&fetch);
2972 }
2973
2974 static isc_result_t
2975 query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
2976               dns_rdataset_t *nameservers, isc_boolean_t resuming)
2977 {
2978         isc_result_t result;
2979         dns_rdataset_t *rdataset, *sigrdataset;
2980         isc_sockaddr_t *peeraddr;
2981
2982         if (!resuming)
2983                 inc_stats(client, dns_nsstatscounter_recursion);
2984
2985         /*
2986          * We are about to recurse, which means that this client will
2987          * be unavailable for serving new requests for an indeterminate
2988          * amount of time.  If this client is currently responsible
2989          * for handling incoming queries, set up a new client
2990          * object to handle them while we are waiting for a
2991          * response.  There is no need to replace TCP clients
2992          * because those have already been replaced when the
2993          * connection was accepted (if allowed by the TCP quota).
2994          */
2995         if (client->recursionquota == NULL) {
2996                 result = isc_quota_attach(&ns_g_server->recursionquota,
2997                                           &client->recursionquota);
2998                 if  (result == ISC_R_SOFTQUOTA) {
2999                         static isc_stdtime_t last = 0;
3000                         isc_stdtime_t now;
3001                         isc_stdtime_get(&now);
3002                         if (now != last) {
3003                                 last = now;
3004                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3005                                               NS_LOGMODULE_QUERY,
3006                                               ISC_LOG_WARNING,
3007                                               "recursive-clients soft limit "
3008                                               "exceeded, aborting oldest query");
3009                         }
3010                         ns_client_killoldestquery(client);
3011                         result = ISC_R_SUCCESS;
3012                 } else if (result == ISC_R_QUOTA) {
3013                         static isc_stdtime_t last = 0;
3014                         isc_stdtime_t now;
3015                         isc_stdtime_get(&now);
3016                         if (now != last) {
3017                                 last = now;
3018                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3019                                               NS_LOGMODULE_QUERY,
3020                                               ISC_LOG_WARNING,
3021                                               "no more recursive clients: %s",
3022                                               isc_result_totext(result));
3023                         }
3024                         ns_client_killoldestquery(client);
3025                 }
3026                 if (result == ISC_R_SUCCESS && !client->mortal &&
3027                     (client->attributes & NS_CLIENTATTR_TCP) == 0) {
3028                         result = ns_client_replace(client);
3029                         if (result != ISC_R_SUCCESS) {
3030                                 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
3031                                               NS_LOGMODULE_QUERY,
3032                                               ISC_LOG_WARNING,
3033                                               "ns_client_replace() failed: %s",
3034                                               isc_result_totext(result));
3035                                 isc_quota_detach(&client->recursionquota);
3036                         }
3037                 }
3038                 if (result != ISC_R_SUCCESS)
3039                         return (result);
3040                 ns_client_recursing(client);
3041         }
3042
3043         /*
3044          * Invoke the resolver.
3045          */
3046         REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
3047         REQUIRE(client->query.fetch == NULL);
3048
3049         rdataset = query_newrdataset(client);
3050         if (rdataset == NULL)
3051                 return (ISC_R_NOMEMORY);
3052         if (WANTDNSSEC(client)) {
3053                 sigrdataset = query_newrdataset(client);
3054                 if (sigrdataset == NULL) {
3055                         query_putrdataset(client, &rdataset);
3056                         return (ISC_R_NOMEMORY);
3057                 }
3058         } else
3059                 sigrdataset = NULL;
3060
3061         if (client->query.timerset == ISC_FALSE)
3062                 ns_client_settimeout(client, 60);
3063         if ((client->attributes & NS_CLIENTATTR_TCP) == 0)
3064                 peeraddr = &client->peeraddr;
3065         else
3066                 peeraddr = NULL;
3067         result = dns_resolver_createfetch2(client->view->resolver,
3068                                            client->query.qname,
3069                                            qtype, qdomain, nameservers,
3070                                            NULL, peeraddr, client->message->id,
3071                                            client->query.fetchoptions,
3072                                            client->task,
3073                                            query_resume, client,
3074                                            rdataset, sigrdataset,
3075                                            &client->query.fetch);
3076
3077         if (result == ISC_R_SUCCESS) {
3078                 /*
3079                  * Record that we're waiting for an event.  A client which
3080                  * is shutting down will not be destroyed until all the
3081                  * events have been received.
3082                  */
3083         } else {
3084                 query_putrdataset(client, &rdataset);
3085                 if (sigrdataset != NULL)
3086                         query_putrdataset(client, &sigrdataset);
3087         }
3088
3089         return (result);
3090 }
3091
3092 #define MAX_RESTARTS 16
3093
3094 #define QUERY_ERROR(r) \
3095 do { \
3096         eresult = r; \
3097         want_restart = ISC_FALSE; \
3098         line = __LINE__; \
3099 } while (0)
3100
3101 /*
3102  * Extract a network address from the RDATA of an A or AAAA
3103  * record.
3104  *
3105  * Returns:
3106  *      ISC_R_SUCCESS
3107  *      ISC_R_NOTIMPLEMENTED    The rdata is not a known address type.
3108  */
3109 static isc_result_t
3110 rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
3111         struct in_addr ina;
3112         struct in6_addr in6a;
3113
3114         switch (rdata->type) {
3115         case dns_rdatatype_a:
3116                 INSIST(rdata->length == 4);
3117                 memcpy(&ina.s_addr, rdata->data, 4);
3118                 isc_netaddr_fromin(netaddr, &ina);
3119                 return (ISC_R_SUCCESS);
3120         case dns_rdatatype_aaaa:
3121                 INSIST(rdata->length == 16);
3122                 memcpy(in6a.s6_addr, rdata->data, 16);
3123                 isc_netaddr_fromin6(netaddr, &in6a);
3124                 return (ISC_R_SUCCESS);
3125         default:
3126                 return (ISC_R_NOTIMPLEMENTED);
3127         }
3128 }
3129
3130 /*
3131  * Find the sort order of 'rdata' in the topology-like
3132  * ACL forming the second element in a 2-element top-level
3133  * sortlist statement.
3134  */
3135 static int
3136 query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
3137         isc_netaddr_t netaddr;
3138
3139         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3140                 return (INT_MAX);
3141         return (ns_sortlist_addrorder2(&netaddr, arg));
3142 }
3143
3144 /*
3145  * Find the sort order of 'rdata' in the matching element
3146  * of a 1-element top-level sortlist statement.
3147  */
3148 static int
3149 query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
3150         isc_netaddr_t netaddr;
3151
3152         if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
3153                 return (INT_MAX);
3154         return (ns_sortlist_addrorder1(&netaddr, arg));
3155 }
3156
3157 /*
3158  * Find the sortlist statement that applies to 'client' and set up
3159  * the sortlist info in in client->message appropriately.
3160  */
3161 static void
3162 setup_query_sortlist(ns_client_t *client) {
3163         isc_netaddr_t netaddr;
3164         dns_rdatasetorderfunc_t order = NULL;
3165         const void *order_arg = NULL;
3166
3167         isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
3168         switch (ns_sortlist_setup(client->view->sortlist,
3169                                &netaddr, &order_arg)) {
3170         case NS_SORTLISTTYPE_1ELEMENT:
3171                 order = query_sortlist_order_1element;
3172                 break;
3173         case NS_SORTLISTTYPE_2ELEMENT:
3174                 order = query_sortlist_order_2element;
3175                 break;
3176         case NS_SORTLISTTYPE_NONE:
3177                 order = NULL;
3178                 break;
3179         default:
3180                 INSIST(0);
3181                 break;
3182         }
3183         dns_message_setsortorder(client->message, order, order_arg);
3184 }
3185
3186 static void
3187 query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) {
3188         isc_buffer_t *dbuf, b;
3189         dns_name_t *fname;
3190         dns_rdataset_t *nsec, *nsecsig;
3191         isc_result_t result = ISC_R_NOMEMORY;
3192
3193         CTRACE("query_addnoqnameproof");
3194
3195         fname = NULL;
3196         nsec = NULL;
3197         nsecsig = NULL;
3198
3199         dbuf = query_getnamebuf(client);
3200         if (dbuf == NULL)
3201                 goto cleanup;
3202         fname = query_newname(client, dbuf, &b);
3203         nsec = query_newrdataset(client);
3204         nsecsig = query_newrdataset(client);
3205         if (fname == NULL || nsec == NULL || nsecsig == NULL)
3206                 goto cleanup;
3207
3208         result = dns_rdataset_getnoqname(rdataset, fname, nsec, nsecsig);
3209         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3210
3211         query_addrrset(client, &fname, &nsec, &nsecsig, dbuf,
3212                        DNS_SECTION_AUTHORITY);
3213
3214  cleanup:
3215         if (nsec != NULL)
3216                 query_putrdataset(client, &nsec);
3217         if (nsecsig != NULL)
3218                 query_putrdataset(client, &nsecsig);
3219         if (fname != NULL)
3220                 query_releasename(client, &fname);
3221 }
3222
3223 static inline void
3224 answer_in_glue(ns_client_t *client, dns_rdatatype_t qtype) {
3225         dns_name_t *name;
3226         dns_message_t *msg;
3227         dns_section_t section = DNS_SECTION_ADDITIONAL;
3228         dns_rdataset_t *rdataset = NULL;
3229
3230         msg = client->message;
3231         for (name = ISC_LIST_HEAD(msg->sections[section]);
3232              name != NULL;
3233              name = ISC_LIST_NEXT(name, link))
3234                 if (dns_name_equal(name, client->query.qname)) {
3235                         for (rdataset = ISC_LIST_HEAD(name->list);
3236                              rdataset != NULL;
3237                              rdataset = ISC_LIST_NEXT(rdataset, link))
3238                                 if (rdataset->type == qtype)
3239                                         break;
3240                         break;
3241                 }
3242         if (rdataset != NULL) {
3243                 ISC_LIST_UNLINK(msg->sections[section], name, link);
3244                 ISC_LIST_PREPEND(msg->sections[section], name, link);
3245                 ISC_LIST_UNLINK(name->list, rdataset, link);
3246                 ISC_LIST_PREPEND(name->list, rdataset, link);
3247                 rdataset->attributes |= DNS_RDATASETATTR_REQUIREDGLUE;
3248         }
3249 }
3250
3251 #define NS_NAME_INIT(A,B) \
3252          { \
3253                 DNS_NAME_MAGIC, \
3254                 A, sizeof(A), sizeof(B), \
3255                 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \
3256                 B, NULL, { (void *)-1, (void *)-1}, \
3257                 {NULL, NULL} \
3258         }
3259
3260 static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
3261 static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
3262 static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
3263
3264 static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
3265
3266 static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
3267 static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
3268 static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
3269 static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
3270 static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
3271 static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
3272 static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
3273 static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
3274 static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
3275 static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
3276 static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
3277 static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
3278 static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
3279 static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
3280 static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
3281 static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
3282
3283 static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
3284
3285 static dns_name_t rfc1918names[] = {
3286         NS_NAME_INIT(inaddr10, inaddr10_offsets),
3287         NS_NAME_INIT(inaddr16172, inaddr172_offsets),
3288         NS_NAME_INIT(inaddr17172, inaddr172_offsets),
3289         NS_NAME_INIT(inaddr18172, inaddr172_offsets),
3290         NS_NAME_INIT(inaddr19172, inaddr172_offsets),
3291         NS_NAME_INIT(inaddr20172, inaddr172_offsets),
3292         NS_NAME_INIT(inaddr21172, inaddr172_offsets),
3293         NS_NAME_INIT(inaddr22172, inaddr172_offsets),
3294         NS_NAME_INIT(inaddr23172, inaddr172_offsets),
3295         NS_NAME_INIT(inaddr24172, inaddr172_offsets),
3296         NS_NAME_INIT(inaddr25172, inaddr172_offsets),
3297         NS_NAME_INIT(inaddr26172, inaddr172_offsets),
3298         NS_NAME_INIT(inaddr27172, inaddr172_offsets),
3299         NS_NAME_INIT(inaddr28172, inaddr172_offsets),
3300         NS_NAME_INIT(inaddr29172, inaddr172_offsets),
3301         NS_NAME_INIT(inaddr30172, inaddr172_offsets),
3302         NS_NAME_INIT(inaddr31172, inaddr172_offsets),
3303         NS_NAME_INIT(inaddr168192, inaddr192_offsets)
3304 };
3305
3306
3307 static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
3308 static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org";
3309
3310 static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
3311 static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
3312
3313 static dns_name_t prisoner = NS_NAME_INIT(prisoner_data, prisoner_offsets);
3314 static dns_name_t hostmaster = NS_NAME_INIT(hostmaster_data, hostmaster_offsets);
3315
3316 static void
3317 warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
3318         unsigned int i;
3319         dns_rdata_t rdata = DNS_RDATA_INIT;
3320         dns_rdata_soa_t soa;
3321         dns_rdataset_t found;
3322         isc_result_t result;
3323
3324         for (i = 0; i < (sizeof(rfc1918names)/sizeof(*rfc1918names)); i++) {
3325                 if (dns_name_issubdomain(fname, &rfc1918names[i])) {
3326                         dns_rdataset_init(&found);
3327                         result = dns_ncache_getrdataset(rdataset,
3328                                                         &rfc1918names[i],
3329                                                         dns_rdatatype_soa,
3330                                                         &found);
3331                         if (result != ISC_R_SUCCESS)
3332                                 return;
3333
3334                         result = dns_rdataset_first(&found);
3335                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3336                         dns_rdataset_current(&found, &rdata);
3337                         result = dns_rdata_tostruct(&rdata, &soa, NULL);
3338                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3339                         if (dns_name_equal(&soa.origin, &prisoner) &&
3340                             dns_name_equal(&soa.contact, &hostmaster)) {
3341                                 char buf[DNS_NAME_FORMATSIZE];
3342                                 dns_name_format(fname, buf, sizeof(buf));
3343                                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3344                                               NS_LOGMODULE_QUERY,
3345                                               ISC_LOG_WARNING,
3346                                               "RFC 1918 response from "
3347                                               "Internet for %s", buf);
3348                         }
3349                         dns_rdataset_disassociate(&found);
3350                         return;
3351                 }
3352         }
3353 }
3354
3355 /*
3356  * Do the bulk of query processing for the current query of 'client'.
3357  * If 'event' is non-NULL, we are returning from recursion and 'qtype'
3358  * is ignored.  Otherwise, 'qtype' is the query type.
3359  */
3360 static isc_result_t
3361 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
3362 {
3363         dns_db_t *db, *zdb;
3364         dns_dbnode_t *node;
3365         dns_rdatatype_t type;
3366         dns_name_t *fname, *zfname, *tname, *prefix;
3367         dns_rdataset_t *rdataset, *trdataset;
3368         dns_rdataset_t *sigrdataset, *zrdataset, *zsigrdataset;
3369         dns_rdataset_t **sigrdatasetp;
3370         dns_rdata_t rdata = DNS_RDATA_INIT;
3371         dns_rdatasetiter_t *rdsiter;
3372         isc_boolean_t want_restart, authoritative, is_zone, need_wildcardproof;
3373         unsigned int n, nlabels;
3374         dns_namereln_t namereln;
3375         int order;
3376         isc_buffer_t *dbuf;
3377         isc_buffer_t b;
3378         isc_result_t result, eresult;
3379         dns_fixedname_t fixed;
3380         dns_fixedname_t wildcardname;
3381         dns_dbversion_t *version;
3382         dns_zone_t *zone;
3383         dns_rdata_cname_t cname;
3384         dns_rdata_dname_t dname;
3385         unsigned int options;
3386         isc_boolean_t empty_wild;
3387         dns_rdataset_t *noqname;
3388         isc_boolean_t resuming;
3389         int line = -1;
3390
3391         CTRACE("query_find");
3392
3393         /*
3394          * One-time initialization.
3395          *
3396          * It's especially important to initialize anything that the cleanup
3397          * code might cleanup.
3398          */
3399
3400         eresult = ISC_R_SUCCESS;
3401         fname = NULL;
3402         zfname = NULL;
3403         rdataset = NULL;
3404         zrdataset = NULL;
3405         sigrdataset = NULL;
3406         zsigrdataset = NULL;
3407         node = NULL;
3408         db = NULL;
3409         zdb = NULL;
3410         version = NULL;
3411         zone = NULL;
3412         need_wildcardproof = ISC_FALSE;
3413         empty_wild = ISC_FALSE;
3414         options = 0;
3415         resuming = ISC_FALSE;
3416         is_zone = ISC_FALSE;
3417
3418         if (event != NULL) {
3419                 /*
3420                  * We're returning from recursion.  Restore the query context
3421                  * and resume.
3422                  */
3423
3424                 want_restart = ISC_FALSE;
3425                 authoritative = ISC_FALSE;
3426
3427                 qtype = event->qtype;
3428                 if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3429                         type = dns_rdatatype_any;
3430                 else
3431                         type = qtype;
3432                 db = event->db;
3433                 node = event->node;
3434                 rdataset = event->rdataset;
3435                 sigrdataset = event->sigrdataset;
3436
3437                 /*
3438                  * We'll need some resources...
3439                  */
3440                 dbuf = query_getnamebuf(client);
3441                 if (dbuf == NULL) {
3442                         QUERY_ERROR(DNS_R_SERVFAIL);
3443                         goto cleanup;
3444                 }
3445                 fname = query_newname(client, dbuf, &b);
3446                 if (fname == NULL) {
3447                         QUERY_ERROR(DNS_R_SERVFAIL);
3448                         goto cleanup;
3449                 }
3450                 tname = dns_fixedname_name(&event->foundname);
3451                 result = dns_name_copy(tname, fname, NULL);
3452                 if (result != ISC_R_SUCCESS) {
3453                         QUERY_ERROR(DNS_R_SERVFAIL);
3454                         goto cleanup;
3455                 }
3456
3457                 result = event->result;
3458                 resuming = ISC_TRUE;
3459
3460                 goto resume;
3461         }
3462
3463         /*
3464          * Not returning from recursion.
3465          */
3466
3467         /*
3468          * If it's a SIG query, we'll iterate the node.
3469          */
3470         if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig)
3471                 type = dns_rdatatype_any;
3472         else
3473                 type = qtype;
3474
3475  restart:
3476         CTRACE("query_find: restart");
3477         want_restart = ISC_FALSE;
3478         authoritative = ISC_FALSE;
3479         version = NULL;
3480         need_wildcardproof = ISC_FALSE;
3481
3482         if (client->view->checknames &&
3483             !dns_rdata_checkowner(client->query.qname,
3484                                   client->message->rdclass,
3485                                   qtype, ISC_FALSE)) {
3486                 char namebuf[DNS_NAME_FORMATSIZE];
3487                 char typename[DNS_RDATATYPE_FORMATSIZE];
3488                 char classname[DNS_RDATACLASS_FORMATSIZE];
3489
3490                 dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
3491                 dns_rdatatype_format(qtype, typename, sizeof(typename));
3492                 dns_rdataclass_format(client->message->rdclass, classname,
3493                                       sizeof(classname));
3494                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
3495                               NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
3496                               "check-names failure %s/%s/%s", namebuf,
3497                               typename, classname);
3498                 QUERY_ERROR(DNS_R_REFUSED);
3499                 goto cleanup;
3500         }
3501
3502         /*
3503          * First we must find the right database.
3504          */
3505         options &= DNS_GETDB_NOLOG; /* Preserve DNS_GETDB_NOLOG. */
3506         if (dns_rdatatype_atparent(qtype) &&
3507             !dns_name_equal(client->query.qname, dns_rootname))
3508                 options |= DNS_GETDB_NOEXACT;
3509         result = query_getdb(client, client->query.qname, qtype, options,
3510                              &zone, &db, &version, &is_zone);
3511         if ((result != ISC_R_SUCCESS || !is_zone) && !RECURSIONOK(client) &&
3512             (options & DNS_GETDB_NOEXACT) != 0 && qtype == dns_rdatatype_ds) {
3513                 /*
3514                  * Look to see if we are authoritative for the
3515                  * child zone if the query type is DS.
3516                  */
3517                 dns_db_t *tdb = NULL;
3518                 dns_zone_t *tzone = NULL;
3519                 dns_dbversion_t *tversion = NULL;
3520                 isc_result_t tresult;
3521
3522                 tresult = query_getzonedb(client, client->query.qname, qtype,
3523                                          DNS_GETDB_PARTIAL, &tzone, &tdb,
3524                                          &tversion);
3525                 if (tresult == ISC_R_SUCCESS) {
3526                         options &= ~DNS_GETDB_NOEXACT;
3527                         query_putrdataset(client, &rdataset);
3528                         if (db != NULL)
3529                                 dns_db_detach(&db);
3530                         if (zone != NULL)
3531                                 dns_zone_detach(&zone);
3532                         version = tversion;
3533                         db = tdb;
3534                         zone = tzone;
3535                         is_zone = ISC_TRUE;
3536                         result = ISC_R_SUCCESS;
3537                 } else {
3538                         if (tdb != NULL)
3539                                 dns_db_detach(&tdb);
3540                         if (tzone != NULL)
3541                                 dns_zone_detach(&tzone);
3542                 }
3543         }
3544         if (result != ISC_R_SUCCESS) {
3545                 if (result == DNS_R_REFUSED) {
3546                         if (WANTRECURSION(client)) {
3547                                 inc_stats(client,
3548                                           dns_nsstatscounter_recurserej);
3549                         } else
3550                                 inc_stats(client, dns_nsstatscounter_authrej);
3551                         if (!PARTIALANSWER(client))
3552                                 QUERY_ERROR(DNS_R_REFUSED);
3553                 } else
3554                         QUERY_ERROR(DNS_R_SERVFAIL);
3555                 goto cleanup;
3556         }
3557
3558         if (is_zone)
3559                 authoritative = ISC_TRUE;
3560
3561         if (event == NULL && client->query.restarts == 0) {
3562                 if (is_zone) {
3563 #ifdef DLZ
3564                         if (zone != NULL) {
3565                                 /*
3566                                  * if is_zone = true, zone = NULL then this is
3567                                  * a DLZ zone.  Don't attempt to attach zone.
3568                                  */
3569 #endif
3570                                 dns_zone_attach(zone, &client->query.authzone);
3571 #ifdef DLZ
3572                         }
3573 #endif
3574                         dns_db_attach(db, &client->query.authdb);
3575                 }
3576                 client->query.authdbset = ISC_TRUE;
3577         }
3578
3579  db_find:
3580         CTRACE("query_find: db_find");
3581         /*
3582          * We'll need some resources...
3583          */
3584         dbuf = query_getnamebuf(client);
3585         if (dbuf == NULL) {
3586                 QUERY_ERROR(DNS_R_SERVFAIL);
3587                 goto cleanup;
3588         }
3589         fname = query_newname(client, dbuf, &b);
3590         rdataset = query_newrdataset(client);
3591         if (fname == NULL || rdataset == NULL) {
3592                 QUERY_ERROR(DNS_R_SERVFAIL);
3593                 goto cleanup;
3594         }
3595         if (WANTDNSSEC(client)) {
3596                 sigrdataset = query_newrdataset(client);
3597                 if (sigrdataset == NULL) {
3598                         QUERY_ERROR(DNS_R_SERVFAIL);
3599                         goto cleanup;
3600                 }
3601         }
3602
3603         /*
3604          * Now look for an answer in the database.
3605          */
3606         result = dns_db_find(db, client->query.qname, version, type,
3607                              client->query.dboptions, client->now,
3608                              &node, fname, rdataset, sigrdataset);
3609
3610  resume:
3611         CTRACE("query_find: resume");
3612         switch (result) {
3613         case ISC_R_SUCCESS:
3614                 /*
3615                  * This case is handled in the main line below.
3616                  */
3617                 break;
3618         case DNS_R_GLUE:
3619         case DNS_R_ZONECUT:
3620                 /*
3621                  * These cases are handled in the main line below.
3622                  */
3623                 INSIST(is_zone);
3624                 authoritative = ISC_FALSE;
3625                 break;
3626         case ISC_R_NOTFOUND:
3627                 /*
3628                  * The cache doesn't even have the root NS.  Get them from
3629                  * the hints DB.
3630                  */
3631                 INSIST(!is_zone);
3632                 if (db != NULL)
3633                         dns_db_detach(&db);
3634
3635                 if (client->view->hints == NULL) {
3636                         /* We have no hints. */
3637                         result = ISC_R_FAILURE;
3638                 } else {
3639                         dns_db_attach(client->view->hints, &db);
3640                         result = dns_db_find(db, dns_rootname,
3641                                              NULL, dns_rdatatype_ns,
3642                                              0, client->now, &node, fname,
3643                                              rdataset, sigrdataset);
3644                 }
3645                 if (result != ISC_R_SUCCESS) {
3646                         /*
3647                          * Nonsensical root hints may require cleanup.
3648                          */
3649                         if (dns_rdataset_isassociated(rdataset))
3650                                 dns_rdataset_disassociate(rdataset);
3651                         if (sigrdataset != NULL &&
3652                             dns_rdataset_isassociated(sigrdataset))
3653                                 dns_rdataset_disassociate(sigrdataset);
3654                         if (node != NULL)
3655                                 dns_db_detachnode(db, &node);
3656
3657                         /*
3658                          * We don't have any root server hints, but
3659                          * we may have working forwarders, so try to
3660                          * recurse anyway.
3661                          */
3662                         if (RECURSIONOK(client)) {
3663                                 result = query_recurse(client, qtype,
3664                                                        NULL, NULL, resuming);
3665  &