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