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