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