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