Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / named / query.c
blob4c67fff0b9310c72821db94e5637f512742fdae9
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
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.
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.
18 /* $Id: query.c,v 1.198.2.19 2004/04/15 02:16:25 marka Exp $ */
20 #include <config.h>
22 #include <string.h>
24 #include <isc/mem.h>
25 #include <isc/util.h>
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>
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>
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)
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
88 #define DNS_GETDB_NOEXACT 0x01U
89 #define DNS_GETDB_NOLOG 0x02U
91 static unsigned char ip6int_ndata[] = "\003ip6\003int";
92 static unsigned char ip6int_offsets[] = { 0, 4, 8 };
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}
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);
108 static inline void
109 query_adda6rrset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset,
110 dns_rdataset_t *sigrdataset);
112 static void
113 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
115 static void
116 synth_fwd_start(ns_client_t *client);
118 static void
119 synth_fwd_startfind(ns_client_t *client);
121 static void
122 synth_fwd_respond(ns_client_t *client, dns_adbfind_t *find);
124 static void
125 synth_fwd_finddone(isc_task_t *task, isc_event_t *ev);
127 static void
128 synth_finish(ns_client_t *client, isc_result_t result);
130 static void
131 synth_rev_start(ns_client_t *client);
133 static void
134 synth_rev_byaddrdone_arpa(isc_task_t *task, isc_event_t *event);
136 static void
137 synth_rev_byaddrdone_int(isc_task_t *task, isc_event_t *event);
139 static void
140 synth_rev_respond(ns_client_t *client, dns_byaddrevent_t *bevent);
143 * Increment query statistics counters.
145 static inline void
146 inc_stats(ns_client_t *client, dns_statscounter_t counter) {
147 dns_zone_t *zone = client->query.authzone;
149 REQUIRE(counter < DNS_STATS_NCOUNTERS);
151 ns_g_server->querystats[counter]++;
153 if (zone != NULL) {
154 isc_uint64_t *zonestats = dns_zone_getstatscounters(zone);
155 if (zonestats != NULL)
156 zonestats[counter]++;
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;
170 } else {
171 counter = dns_statscounter_success;
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;
179 inc_stats(client, counter);
180 ns_client_send(client);
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);
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);
195 static inline void
196 query_maybeputqname(ns_client_t *client) {
197 if (client->query.restarts > 0) {
199 * client->query.qname was dynamically allocated.
201 dns_message_puttempname(client->message,
202 &client->query.qname);
203 client->query.qname = NULL;
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;
214 * Reset the query state of a client to its default state.
218 * Cancel the fetch if it's running.
220 if (client->query.fetch != NULL) {
221 dns_resolver_cancelfetch(client->query.fetch);
223 client->query.fetch = NULL;
227 * Cleanup any active versions.
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);
239 ISC_LIST_INIT(client->query.activeversions);
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);
247 * Clean up free versions.
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);
254 * If we're not freeing everything, we keep the first three
255 * dbversions structures around.
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);
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);
275 query_maybeputqname(client);
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;
290 static void
291 query_next_callback(ns_client_t *client) {
292 query_reset(client, ISC_FALSE);
295 void
296 ns_query_free(ns_client_t *client) {
297 query_reset(client, ISC_TRUE);
300 static inline isc_result_t
301 query_newnamebuf(ns_client_t *client) {
302 isc_buffer_t *dbuf;
303 isc_result_t result;
305 CTRACE("query_newnamebuf");
307 * Allocate a name buffer.
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);
316 ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
318 CTRACE("query_newnamebuf: done");
319 return (ISC_R_SUCCESS);
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;
328 CTRACE("query_getnamebuf");
330 * Return a name buffer with space for a maximal name, allocating
331 * a new one if necessary.
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);
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);
352 dbuf = ISC_LIST_TAIL(client->query.namebufs);
353 isc_buffer_availableregion(dbuf, &r);
354 INSIST(r.length >= 255);
356 CTRACE("query_getnamebuf: done");
357 return (dbuf);
360 static inline void
361 query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
362 isc_region_t r;
364 CTRACE("query_keepname");
366 * 'name' is using space in 'dbuf', but 'dbuf' has not yet been
367 * adjusted to take account of that. We do the adjustment.
370 REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0);
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;
378 static inline void
379 query_releasename(ns_client_t *client, dns_name_t **namep) {
380 dns_name_t *name = *namep;
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.
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;
394 dns_message_puttempname(client->message, namep);
395 CTRACE("query_releasename: done");
398 static inline dns_name_t *
399 query_newname(ns_client_t *client, isc_buffer_t *dbuf,
400 isc_buffer_t *nbuf)
402 dns_name_t *name;
403 isc_region_t r;
404 isc_result_t result;
406 REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
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);
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;
421 CTRACE("query_newname: done");
422 return (name);
425 static inline dns_rdataset_t *
426 query_newrdataset(ns_client_t *client) {
427 dns_rdataset_t *rdataset;
428 isc_result_t result;
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);
438 dns_rdataset_init(rdataset);
440 CTRACE("query_newrdataset: done");
441 return (rdataset);
444 static inline void
445 query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
446 dns_rdataset_t *rdataset = *rdatasetp;
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);
454 CTRACE("query_putrdataset: done");
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;
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 {
472 * We only return ISC_R_NOMEMORY if we couldn't
473 * allocate anything.
475 if (i == 0)
476 return (ISC_R_NOMEMORY);
477 else
478 return (ISC_R_SUCCESS);
482 return (ISC_R_SUCCESS);
485 static inline ns_dbversion_t *
486 query_getdbversion(ns_client_t *client) {
487 isc_result_t result;
488 ns_dbversion_t *dbversion;
490 if (ISC_LIST_EMPTY(client->query.freeversions)) {
491 result = query_newdbversion(client, 1);
492 if (result != ISC_R_SUCCESS)
493 return (NULL);
495 dbversion = ISC_LIST_HEAD(client->query.freeversions);
496 INSIST(dbversion != NULL);
497 ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
499 return (dbversion);
502 isc_result_t
503 ns_query_init(ns_client_t *client) {
504 isc_result_t result;
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));
526 static inline ns_dbversion_t *
527 query_findversion(ns_client_t *client, dns_db_t *db,
528 isc_boolean_t *newzonep)
530 ns_dbversion_t *dbversion;
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.
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;
544 if (dbversion == NULL) {
546 * This is a new zone for this query. Add it to
547 * the active list.
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;
561 return (dbversion);
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)
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;
576 REQUIRE(zonep != NULL && *zonep == NULL);
577 REQUIRE(dbp != NULL && *dbp == NULL);
580 * Find a zone database to answer the query.
582 ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
583 DNS_ZTFIND_NOEXACT : 0;
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);
590 if (result != ISC_R_SUCCESS)
591 goto fail;
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.
599 if (!client->view->additionalfromauth &&
600 client->query.authdbset &&
601 db != client->query.authdb)
602 goto refuse;
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.
609 * Also, get the database version to use.
612 check_acl = ISC_TRUE; /* Keep compiler happy. */
613 queryacl = NULL;
616 * Get the current version of this database.
618 dbversion = query_findversion(client, db, &new_zone);
619 if (dbversion == NULL) {
620 result = DNS_R_SERVFAIL;
621 goto fail;
623 if (new_zone) {
624 check_acl = ISC_TRUE;
625 } else if (!dbversion->queryok) {
626 goto refuse;
627 } else {
628 check_acl = ISC_FALSE;
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) {
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.
642 check_acl = ISC_FALSE;
643 if ((client->query.attributes &
644 NS_QUERYATTR_QUERYOK) == 0)
645 goto refuse;
646 } else {
648 * We haven't evaluated the view's queryacl yet.
650 check_acl = ISC_TRUE;
654 if (check_acl) {
655 isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
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)))
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);
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);
684 if (queryacl == client->view->queryacl) {
685 if (result == ISC_R_SUCCESS) {
687 * We were allowed by the default
688 * "allow-query" ACL. Remember this so we
689 * don't have to check again.
691 client->query.attributes |=
692 NS_QUERYATTR_QUERYOK;
695 * We've now evaluated the view's query ACL, and
696 * the NS_QUERYATTR_QUERYOK attribute is now valid.
698 client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
701 if (result != ISC_R_SUCCESS)
702 goto refuse;
705 /* Approved. */
708 * Remember the result of the ACL check so we
709 * don't have to check again.
711 dbversion->queryok = ISC_TRUE;
713 /* Transfer ownership. */
714 *zonep = zone;
715 *dbp = db;
716 *versionp = dbversion->version;
718 return (ISC_R_SUCCESS);
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);
728 return (result);
731 static inline isc_result_t
732 query_getcachedb(ns_client_t *client, dns_db_t **dbp, unsigned int options)
734 isc_result_t result;
735 isc_boolean_t check_acl;
736 dns_db_t *db = NULL;
738 REQUIRE(dbp != NULL && *dbp == NULL);
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.
746 if (!USECACHE(client))
747 return (DNS_R_REFUSED);
748 dns_db_attach(client->view->cachedb, &db);
750 if ((client->query.attributes &
751 NS_QUERYATTR_QUERYOKVALID) != 0) {
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.
758 check_acl = ISC_FALSE;
759 if ((client->query.attributes &
760 NS_QUERYATTR_QUERYOK) == 0)
761 goto refuse;
762 } else {
764 * We haven't evaluated the view's queryacl yet.
766 check_acl = ISC_TRUE;
769 if (check_acl) {
770 isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
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) {
779 * We were allowed by the default
780 * "allow-query" ACL. Remember this so we
781 * don't have to check again.
783 client->query.attributes |=
784 NS_QUERYATTR_QUERYOK;
787 * We've now evaluated the view's query ACL, and
788 * the NS_QUERYATTR_QUERYOK attribute is now valid.
790 client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
792 if (result != ISC_R_SUCCESS)
793 goto refuse;
796 /* Approved. */
798 /* Transfer ownership. */
799 *dbp = db;
801 return (ISC_R_SUCCESS);
803 refuse:
804 result = DNS_R_REFUSED;
806 if (db != NULL)
807 dns_db_detach(&db);
809 return (result);
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)
818 isc_result_t result;
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;
827 return (result);
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)
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;
845 REQUIRE(NS_CLIENT_VALID(client));
846 REQUIRE(rdataset != NULL);
848 dns_rdataset_init(&zrdataset);
849 if (sigrdataset != NULL)
850 dns_rdataset_init(&zsigrdataset);
853 * Find a database to answer the query.
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;
862 db_find:
864 * Now look for an answer in the database.
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)) {
883 * Either the answer is in the cache, or we
884 * don't know it.
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;
892 } else {
894 * We don't have the data in the cache. If we've got
895 * glue from the zone, use it.
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;
908 * We don't know the answer.
910 result = ISC_R_NOTFOUND;
911 } else if (result == DNS_R_GLUE) {
912 if (USECACHE(client) && RECURSIONOK(client)) {
914 * We found an answer, but the cache may be better.
915 * Remember what we've got and go look in the cache.
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))
924 dns_rdataset_clone(sigrdataset, &zsigrdataset);
925 dns_rdataset_disassociate(sigrdataset);
927 dns_db_detach(&db);
928 dns_db_attach(client->view->cachedb, &db);
929 goto db_find;
932 * Otherwise, the glue is the best answer.
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;
944 * If we get here, the result is ISC_R_SUCCESS, and we found the
945 * answer we were looking for in the zone.
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);
955 if (db != NULL)
956 dns_db_detach(&db);
957 if (zone != NULL)
958 dns_zone_detach(&zone);
960 return (result);
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)
967 dns_section_t section;
968 dns_name_t *mname = NULL;
969 isc_result_t result;
971 CTRACE("query_isduplicate");
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) {
980 * We've already got this RRset in the response.
982 CTRACE("query_isduplicate: true: done");
983 return (ISC_TRUE);
984 } else if (result == DNS_R_NXRRSET) {
986 * The name exists, but the rdataset does not.
988 if (section == DNS_SECTION_ADDITIONAL)
989 break;
990 } else
991 RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
992 mname = NULL;
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.
999 if (name == mname)
1000 mname = NULL;
1002 *mnamep = mname;
1004 CTRACE("query_isduplicate: false: done");
1005 return (ISC_FALSE);
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;
1023 REQUIRE(NS_CLIENT_VALID(client));
1024 REQUIRE(qtype != dns_rdatatype_any);
1026 if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype))
1027 return (ISC_R_SUCCESS);
1029 CTRACE("query_addadditional");
1032 * Initialization.
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;
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.
1053 if (qtype == dns_rdatatype_a)
1054 type = dns_rdatatype_any;
1055 else
1056 type = qtype;
1059 * Get some resources.
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;
1075 * Look for a zone database that might contain authoritative
1076 * additional data.
1078 result = query_getzonedb(client, name, DNS_GETDB_NOLOG,
1079 &zone, &db, &version);
1080 if (result != ISC_R_SUCCESS)
1081 goto try_cache;
1083 CTRACE("query_addadditional: db_find");
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.
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;
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);
1107 * No authoritative data was found. The cache is our next best bet.
1110 try_cache:
1111 result = query_getcachedb(client, &db, DNS_GETDB_NOLOG);
1112 if (result != ISC_R_SUCCESS)
1114 * Most likely the client isn't allowed to query the cache.
1116 goto try_glue;
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;
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);
1132 try_glue:
1134 * No cached data was found. Glue is our last chance.
1135 * RFC1035 sayeth:
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.
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).
1148 if (client->query.gluedb == NULL)
1149 goto cleanup;
1152 * Don't poision caches using the bailiwick protection model.
1154 if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
1155 goto cleanup;
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;
1167 found:
1169 * We have found a potential additional data rdataset, or
1170 * at least a node to iterate over.
1172 query_keepname(client, fname, dbuf);
1175 * If we have an rdataset, add it to the additional data
1176 * section.
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;
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.
1195 if (sigrdataset != NULL &&
1196 dns_rdataset_isassociated(sigrdataset))
1198 ISC_LIST_APPEND(fname->list, sigrdataset, link);
1199 sigrdataset = NULL;
1203 if (qtype == dns_rdatatype_a) {
1205 * We now go looking for A, A6, and AAAA records, along with
1206 * their signatures.
1208 * XXXRTH This code could be more efficient.
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;
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;
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);
1235 * Negative cache entries don't have sigrdatasets.
1237 INSIST(sigrdataset == NULL ||
1238 ! dns_rdataset_isassociated(sigrdataset));
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))
1254 ISC_LIST_APPEND(fname->list,
1255 sigrdataset, link);
1256 sigrdataset =
1257 query_newrdataset(client);
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);
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));
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))
1297 ISC_LIST_APPEND(fname->list,
1298 sigrdataset, link);
1299 sigrdataset =
1300 query_newrdataset(client);
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);
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));
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))
1339 ISC_LIST_APPEND(fname->list,
1340 sigrdataset, link);
1341 sigrdataset = NULL;
1343 rdataset = NULL;
1348 addname:
1349 CTRACE("query_addadditional: addname");
1351 * If we haven't added anything, then we're done.
1353 if (!added_something)
1354 goto cleanup;
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.
1361 if (need_addname)
1362 dns_message_addname(client->message, fname,
1363 DNS_SECTION_ADDITIONAL);
1364 fname = NULL;
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.
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.
1377 if (type == dns_rdatatype_a || type == dns_rdatatype_aaaa) {
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.
1386 * XXXRTH We should lower the priority here. Alternatively,
1387 * we could raise the priority of glue records.
1389 eresult = query_addadditional(client, name, dns_rdatatype_key);
1390 } else if (type == dns_rdatatype_srv && trdataset != NULL) {
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.
1396 eresult = dns_rdataset_additionaldata(trdataset,
1397 query_addadditional,
1398 client);
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.
1406 if (a6rdataset != NULL) {
1407 dns_a6_reset(&client->query.a6ctx);
1408 dns_a6_foreach(&client->query.a6ctx, a6rdataset, client->now);
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);
1425 CTRACE("query_addadditional: done");
1426 return (eresult);
1429 static void
1430 query_adda6rrset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset,
1431 dns_rdataset_t *sigrdataset)
1433 ns_client_t *client = arg;
1434 dns_rdataset_t *crdataset, *csigrdataset;
1435 isc_buffer_t b, *dbuf;
1436 dns_name_t *fname, *mname;
1439 * Add an rrset to the additional data section.
1442 REQUIRE(NS_CLIENT_VALID(client));
1443 REQUIRE(rdataset->type == dns_rdatatype_a6);
1446 * Get some resources...
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;
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);
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);
1482 ISC_LIST_APPEND(fname->list, crdataset, link);
1483 crdataset = NULL;
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.
1489 if (sigrdataset != NULL && dns_rdataset_isassociated(csigrdataset)) {
1490 ISC_LIST_APPEND(fname->list, csigrdataset, link);
1491 csigrdataset = NULL;
1494 fname = NULL;
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.
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);
1509 static inline void
1510 query_addrdataset(ns_client_t *client, dns_name_t *fname,
1511 dns_rdataset_t *rdataset)
1513 dns_rdatatype_t type = rdataset->type;
1516 * Add 'rdataset' and any pertinent additional data to
1517 * 'fname', a name in the response message for 'client'.
1520 CTRACE("query_addrdataset");
1522 ISC_LIST_APPEND(fname->list, rdataset, link);
1524 if (NOADDITIONAL(client))
1525 return;
1528 * Add additional data.
1530 * We don't care if dns_a6_foreach or dns_rdataset_additionaldata()
1531 * fail.
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);
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.
1545 * We don't care if query_addadditional() fails.
1547 if (type == dns_rdatatype_ns || type == dns_rdatatype_soa ||
1548 type == dns_rdatatype_a || type == dns_rdatatype_aaaa ||
1549 type == dns_rdatatype_a6) {
1551 * XXXRTH We should lower the priority here. Alternatively,
1552 * we could raise the priority of glue records.
1554 (void)query_addadditional(client, fname, dns_rdatatype_key);
1556 CTRACE("query_addrdataset: done");
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)
1564 dns_name_t *name, *mname;
1565 dns_rdataset_t *rdataset, *mrdataset, *sigrdataset;
1566 isc_result_t result;
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.
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.
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) {
1592 * We've already got an RRset of the given name and type.
1593 * There's nothing else to do;
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) {
1601 * The name doesn't exist.
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);
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.
1619 query_addrdataset(client, mname, rdataset);
1620 *rdatasetp = NULL;
1621 if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
1623 * We have a signature. Add it to the response.
1625 ISC_LIST_APPEND(mname->list, sigrdataset, link);
1626 *sigrdatasetp = NULL;
1628 CTRACE("query_addrrset: done");
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;
1640 CTRACE("query_addsoa");
1642 * Initialization.
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);
1652 * Get resources and make 'name' be the database origin.
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;
1664 if (WANTDNSSEC(client)) {
1665 sigrdataset = query_newrdataset(client);
1666 if (sigrdataset == NULL) {
1667 eresult = DNS_R_SERVFAIL;
1668 goto cleanup;
1673 * Find the SOA.
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) {
1680 * This is bad. We tried to get the SOA RR at the zone top
1681 * and it didn't work!
1683 eresult = DNS_R_SERVFAIL;
1684 } else {
1686 * Extract the SOA MINIMUM.
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);
1695 if (zero_ttl) {
1696 rdataset->ttl = 0;
1697 if (sigrdataset != NULL)
1698 sigrdataset->ttl = 0;
1702 * Add the SOA and its SIG to the response, with the
1703 * TTLs adjusted per RFC2308 section 3.
1705 if (rdataset->ttl > soa.minimum)
1706 rdataset->ttl = soa.minimum;
1707 if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum)
1708 sigrdataset->ttl = soa.minimum;
1710 if (sigrdataset != NULL)
1711 sigrdatasetp = &sigrdataset;
1712 else
1713 sigrdatasetp = NULL;
1714 query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL,
1715 DNS_SECTION_AUTHORITY);
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);
1727 return (eresult);
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;
1739 CTRACE("query_addns");
1741 * Initialization.
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);
1751 * Get resources and make 'name' be the database origin.
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);
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;
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;
1776 * Find the NS rdataset.
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");
1786 * This is bad. We tried to get the NS rdataset at the zone
1787 * top and it didn't work!
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);
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);
1809 CTRACE("query_addns: done");
1810 return (eresult);
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)
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;
1824 * We assume the name data referred to by tname won't go away.
1827 REQUIRE(anamep != NULL);
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);
1848 rdatalist->type = type;
1849 rdatalist->covers = 0;
1850 rdatalist->rdclass = client->message->rdclass;
1851 rdatalist->ttl = ttl;
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;
1859 ISC_LIST_INIT(rdatalist->rdata);
1860 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1861 dns_rdatalist_tordataset(rdatalist, rdataset);
1863 query_addrrset(client, anamep, &rdataset, NULL, NULL,
1864 DNS_SECTION_ANSWER);
1866 if (rdataset != NULL) {
1867 if (dns_rdataset_isassociated(rdataset))
1868 dns_rdataset_disassociate(rdataset);
1869 dns_message_puttemprdataset(client->message, &rdataset);
1872 return (ISC_R_SUCCESS);
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;
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;
1904 * Find the right database.
1906 result = query_getdb(client, client->query.qname, 0, &zone, &db,
1907 &version, &is_zone);
1908 if (result != ISC_R_SUCCESS)
1909 goto cleanup;
1911 db_find:
1913 * We'll need some resources...
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;
1929 * Now look for the zonecut.
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;
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)) {
1963 * We found a zonecut in the cache, but our
1964 * zone delegation is better.
1966 use_zone = ISC_TRUE;
1968 } else if (result == ISC_R_NOTFOUND && zfname != NULL) {
1970 * We didn't find anything in the cache, but we
1971 * have a zone delegation, so use it.
1973 use_zone = ISC_TRUE;
1974 } else
1975 goto cleanup;
1978 if (use_zone) {
1979 query_releasename(client, &fname);
1980 fname = zfname;
1981 zfname = NULL;
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.
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;
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;
2003 query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
2004 DNS_SECTION_AUTHORITY);
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);
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;
2036 * Resume a query after recursion.
2039 UNUSED(task);
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));
2047 if (devent->fetch != NULL) {
2049 * This is the fetch we've been waiting for.
2051 INSIST(devent->fetch == client->query.fetch);
2052 client->query.fetch = NULL;
2053 fetch_cancelled = ISC_FALSE;
2055 * Update client->now.
2057 isc_stdtime_get(&client->now);
2058 } else {
2060 * This is a fetch completion event for a cancelled fetch.
2061 * Clean up and don't resume the find.
2063 fetch_cancelled = ISC_TRUE;
2065 INSIST(client->query.fetch == NULL);
2067 client->query.attributes &= ~NS_QUERYATTR_RECURSING;
2068 dns_resolver_destroyfetch(&devent->fetch);
2071 * If this client is shutting down, or this transaction
2072 * has timed out, do not resume the find.
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);
2086 * This may destroy the client.
2088 ns_client_detach(&client);
2089 } else {
2090 query_find(client, devent, 0);
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)
2098 isc_result_t result;
2099 dns_rdataset_t *rdataset, *sigrdataset;
2101 inc_stats(client, dns_statscounter_recursion);
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).
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);
2129 * Invoke the resolver.
2131 REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
2132 REQUIRE(client->query.fetch == NULL);
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);
2143 } else
2144 sigrdataset = NULL;
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);
2157 if (result == ISC_R_SUCCESS) {
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.
2163 } else {
2164 query_putrdataset(client, &rdataset);
2165 if (sigrdataset != NULL)
2166 query_putrdataset(client, &sigrdataset);
2169 return (result);
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)
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;
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.
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);
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;
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);
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;
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);
2261 return (result);
2264 #define MAX_RESTARTS 16
2266 #define QUERY_ERROR(r) \
2267 do { \
2268 eresult = r; \
2269 want_restart = ISC_FALSE; \
2270 } while (0)
2273 * Extract a network address from the RDATA of an A or AAAA
2274 * record.
2276 * Returns:
2277 * ISC_R_SUCCESS
2278 * ISC_R_NOTIMPLEMENTED The rdata is not a known address type.
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;
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);
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.
2306 static int
2307 query_sortlist_order_2element(dns_rdata_t *rdata, void *arg) {
2308 isc_netaddr_t netaddr;
2310 if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
2311 return (INT_MAX);
2312 return (ns_sortlist_addrorder2(&netaddr, arg));
2316 * Find the sort order of 'rdata' in the matching element
2317 * of a 1-element top-level sortlist statement.
2319 static int
2320 query_sortlist_order_1element(dns_rdata_t *rdata, void *arg) {
2321 isc_netaddr_t netaddr;
2323 if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS)
2324 return (INT_MAX);
2325 return (ns_sortlist_addrorder1(&netaddr, arg));
2329 * Find the sortlist statement that applies to 'client' and set up
2330 * the sortlist info in in client->message appropriately.
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;
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;
2354 dns_message_setsortorder(client->message, order, order_arg);
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.
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;
2387 CTRACE("query_find");
2390 * One-time initialization.
2392 * It's especially important to initialize anything that the cleanup
2393 * code might cleanup.
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;
2410 if (event != NULL) {
2412 * We're returning from recursion. Restore the query context
2413 * and resume.
2416 want_restart = ISC_FALSE;
2417 authoritative = ISC_FALSE;
2418 is_zone = ISC_FALSE;
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;
2431 * We'll need some resources...
2433 dbuf = query_getnamebuf(client);
2434 if (dbuf == NULL) {
2435 QUERY_ERROR(DNS_R_SERVFAIL);
2436 goto cleanup;
2438 fname = query_newname(client, dbuf, &b);
2439 if (fname == NULL) {
2440 QUERY_ERROR(DNS_R_SERVFAIL);
2441 goto cleanup;
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;
2450 result = event->result;
2452 goto resume;
2456 * Not returning from recursion.
2460 * If it's a SIG query, we'll iterate the node.
2462 if (qtype == dns_rdatatype_sig)
2463 type = dns_rdatatype_any;
2464 else
2465 type = qtype;
2467 restart:
2468 CTRACE("query_find: restart");
2469 want_restart = ISC_FALSE;
2470 authoritative = ISC_FALSE;
2471 version = NULL;
2474 * First we must find the right database.
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;
2486 if (is_zone)
2487 authoritative = ISC_TRUE;
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);
2494 client->query.authdbset = ISC_TRUE;
2497 db_find:
2498 CTRACE("query_find: db_find");
2500 * We'll need some resources...
2502 dbuf = query_getnamebuf(client);
2503 if (dbuf == NULL) {
2504 QUERY_ERROR(DNS_R_SERVFAIL);
2505 goto cleanup;
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;
2513 if (WANTDNSSEC(client)) {
2514 sigrdataset = query_newrdataset(client);
2515 if (sigrdataset == NULL) {
2516 QUERY_ERROR(DNS_R_SERVFAIL);
2517 goto cleanup;
2522 * Now look for an answer in the database.
2524 result = dns_db_find(db, client->query.qname, version, type,
2525 client->query.dboptions, client->now,
2526 &node, fname, rdataset, sigrdataset);
2529 * We interrupt our normal query processing to bring you this special
2530 * case...
2532 * RFC 2535 (DNSSEC), section 2.3.4, discusses various special
2533 * cases that can occur at delegation points.
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.
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))) {
2548 * We're looking for a KEY at the top of an unsecure zone,
2549 * and we didn't find it.
2551 result = query_findparentkey(client, client->query.qname,
2552 &zone, &db, &version, &node,
2553 rdataset, sigrdataset);
2554 if (result == ISC_R_SUCCESS) {
2556 * We found the parent KEY.
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.
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).
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;
2575 } else {
2577 * We couldn't find the KEY in a parent zone.
2578 * Continue with processing of the original
2579 * results of dns_db_find().
2581 result = DNS_R_NXRRSET;
2585 resume:
2586 CTRACE("query_find: resume");
2587 switch (result) {
2588 case ISC_R_SUCCESS:
2590 * This case is handled in the main line below.
2592 break;
2593 case DNS_R_GLUE:
2594 case DNS_R_ZONECUT:
2596 * These cases are handled in the main line below.
2598 INSIST(is_zone);
2599 authoritative = ISC_FALSE;
2600 break;
2601 case ISC_R_NOTFOUND:
2603 * The cache doesn't even have the root NS. Get them from
2604 * the hints DB.
2606 INSIST(!is_zone);
2607 if (db != NULL)
2608 dns_db_detach(&db);
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);
2620 if (result != ISC_R_SUCCESS) {
2622 * Nonsensical root hints may require cleanup.
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);
2633 * We don't have any root server hints, but
2634 * we may have working forwarders, so try to
2635 * recurse anyway.
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);
2647 goto cleanup;
2648 } else {
2649 /* Unable to give root server referral. */
2650 QUERY_ERROR(DNS_R_SERVFAIL);
2651 goto cleanup;
2655 * XXXRTH We should trigger root server priming here.
2657 /* FALLTHROUGH */
2658 case DNS_R_DELEGATION:
2659 authoritative = ISC_FALSE;
2660 if (is_zone) {
2662 * We're authoritative for an ancestor of QNAME.
2664 if (!USECACHE(client) || !RECURSIONOK(client)) {
2666 * If we don't have a cache, this is the best
2667 * answer.
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.
2677 * We enable the retrieval of glue for this
2678 * database by setting client->query.gluedb.
2680 client->query.gluedb = db;
2681 client->query.isreferral = ISC_TRUE;
2683 * We must ensure NOADDITIONAL is off,
2684 * because the generation of
2685 * additional data is required in
2686 * delegations.
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 {
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.
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;
2722 } else {
2723 if (zfname != NULL &&
2724 !dns_name_issubdomain(fname, zfname)) {
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.
2731 query_releasename(client, &fname);
2732 fname = zfname;
2733 zfname = NULL;
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.
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;
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.
2756 if (RECURSIONOK(client)) {
2758 * Recurse!
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 {
2773 * This is the best answer.
2775 client->query.attributes |=
2776 NS_QUERYATTR_CACHEGLUEOK;
2777 client->query.gluedb = zdb;
2778 client->query.isreferral = ISC_TRUE;
2780 * We must ensure NOADDITIONAL is off,
2781 * because the generation of
2782 * additional data is required in
2783 * delegations.
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;
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)) {
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.
2811 query_keepname(client, fname, dbuf);
2812 } else {
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.
2818 query_releasename(client, &fname);
2821 * Add SOA.
2823 result = query_addsoa(client, db, ISC_FALSE);
2824 if (result != ISC_R_SUCCESS) {
2825 QUERY_ERROR(result);
2826 goto cleanup;
2829 * Add NXT record if we found one.
2831 if (dns_rdataset_isassociated(rdataset)) {
2832 if (WANTDNSSEC(client))
2833 query_addrrset(client, &fname, &rdataset,
2834 &sigrdataset,
2835 NULL, DNS_SECTION_AUTHORITY);
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)) {
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.
2849 query_keepname(client, fname, dbuf);
2850 } else {
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.
2856 query_releasename(client, &fname);
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.
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;
2873 * Add NXT record if we found one.
2875 if (dns_rdataset_isassociated(rdataset)) {
2876 if (WANTDNSSEC(client))
2877 query_addrrset(client, &fname, &rdataset,
2878 &sigrdataset,
2879 NULL, DNS_SECTION_AUTHORITY);
2882 * Set message rcode.
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;
2894 * Set message rcode, if required.
2896 if (result == DNS_R_NCACHENXDOMAIN)
2897 client->message->rcode = dns_rcode_nxdomain;
2899 * We don't call query_addrrset() because we don't need any
2900 * of its extra features (and things would probably break!).
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:
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).
2915 trdataset = rdataset;
2917 * Add the CNAME to the answer section.
2919 if (sigrdataset != NULL)
2920 sigrdatasetp = &sigrdataset;
2921 else
2922 sigrdatasetp = NULL;
2923 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
2924 DNS_SECTION_ANSWER);
2926 * We set the PARTIALANSWER attribute so that if anything goes
2927 * wrong later on, we'll return what we've got so far.
2929 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
2931 * Reset qname to be the target name of the CNAME and restart
2932 * the query.
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;
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;
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;
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:
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.
2968 namereln = dns_name_fullcompare(client->query.qname, fname,
2969 &order, &nlabels, &nbits);
2970 INSIST(namereln == dns_namereln_subdomain);
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).
2976 trdataset = rdataset;
2978 * Add the DNAME to the answer section.
2980 if (sigrdataset != NULL)
2981 sigrdatasetp = &sigrdataset;
2982 else
2983 sigrdatasetp = NULL;
2984 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
2985 DNS_SECTION_ANSWER);
2987 * We set the PARTIALANSWER attribute so that if anything goes
2988 * wrong later on, we'll return what we've got so far.
2990 client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
2992 * Get the target name of the DNAME.
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;
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;
3010 dns_name_init(tname, NULL);
3011 dns_name_clone(&dname.dname, tname);
3012 dns_rdata_freestruct(&dname);
3014 * Construct the new qname.
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;
3024 INSIST(fname == NULL);
3025 dbuf = query_getnamebuf(client);
3026 if (dbuf == NULL) {
3027 dns_message_puttempname(client->message, &tname);
3028 goto cleanup;
3030 fname = query_newname(client, dbuf, &b);
3031 if (fname == NULL) {
3032 dns_message_puttempname(client->message, &tname);
3033 goto cleanup;
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) {
3040 * RFC 2672, section 4.1, subsection 3c says
3041 * we should return YXDOMAIN if the constructed
3042 * name would be too long.
3044 client->message->rcode = dns_rcode_yxdomain;
3046 goto cleanup;
3048 query_keepname(client, fname, dbuf);
3050 * Synthesize a CNAME for this DNAME.
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.
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.
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);
3068 * Switch to the new qname and restart.
3070 query_maybeputqname(client);
3071 client->query.qname = fname;
3072 fname = NULL;
3073 want_restart = ISC_TRUE;
3074 goto addauth;
3075 default:
3077 * Something has gone wrong.
3079 QUERY_ERROR(DNS_R_SERVFAIL);
3080 goto cleanup;
3083 if (type == dns_rdatatype_any) {
3085 * XXXRTH Need to handle zonecuts with special case
3086 * code.
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;
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().
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!
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);
3120 * rdataset is non-NULL only in certain pathological
3121 * cases involving DNAMEs.
3123 if (rdataset != NULL)
3124 query_putrdataset(client, &rdataset);
3125 rdataset = query_newrdataset(client);
3126 if (rdataset == NULL)
3127 break;
3128 } else {
3130 * We're not interested in this rdataset.
3132 dns_rdataset_disassociate(rdataset);
3134 result = dns_rdatasetiter_next(rdsiter);
3137 if (fname != NULL)
3138 dns_message_puttempname(client->message, &fname);
3140 if (n == 0) {
3142 * We didn't match any rdatasets.
3144 if (qtype == dns_rdatatype_sig &&
3145 result == ISC_R_NOMORE) {
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.
3153 * We were searching for SIG records in
3154 * a nonsecure zone. Send a "no error,
3155 * no data" response.
3158 * Add SOA.
3160 result = query_addsoa(client, db, ISC_FALSE);
3161 if (result == ISC_R_SUCCESS)
3162 result = ISC_R_NOMORE;
3163 } else {
3165 * Something went wrong.
3167 result = DNS_R_SERVFAIL;
3170 dns_rdatasetiter_destroy(&rdsiter);
3171 if (result != ISC_R_NOMORE) {
3172 QUERY_ERROR(DNS_R_SERVFAIL);
3173 goto cleanup;
3175 } else {
3177 * This is the "normal" case -- an ordinary question to which
3178 * we know the answer.
3180 if (sigrdataset != NULL)
3181 sigrdatasetp = &sigrdataset;
3182 else
3183 sigrdatasetp = NULL;
3184 query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
3185 DNS_SECTION_ANSWER);
3187 * We shouldn't ever fail to add 'rdataset'
3188 * because it's already in the answer.
3190 INSIST(rdataset == NULL);
3193 addauth:
3194 CTRACE("query_find: addauth");
3196 * Add NS records to the authority section (if we haven't already
3197 * added them to the answer section).
3199 if (!want_restart && !NOAUTHORITY(client)
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);
3214 cleanup:
3215 CTRACE("query_find: cleanup");
3217 * General cleanup.
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);
3239 if (event != NULL)
3240 isc_event_free(ISC_EVENT_PTR(&event));
3243 * AA bit.
3245 if (client->query.restarts == 0 && !authoritative) {
3247 * We're not authoritative, so we must ensure the AA bit
3248 * isn't set.
3250 client->message->flags &= ~DNS_MESSAGEFLAG_AA;
3254 * Restart the query?
3256 if (want_restart && client->query.restarts < MAX_RESTARTS) {
3257 client->query.restarts++;
3258 goto restart;
3261 if (eresult != ISC_R_SUCCESS &&
3262 (!PARTIALANSWER(client) || WANTRECURSION(client))) {
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.
3268 query_error(client, eresult);
3269 ns_client_detach(&client);
3270 } else if (!RECURSING(client)) {
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.
3277 setup_query_sortlist(client);
3279 if (client->message->rcode == dns_rcode_nxdomain &&
3280 client->view->auth_nxdomain == ISC_TRUE)
3281 client->message->flags |= DNS_MESSAGEFLAG_AA;
3283 query_send(client);
3284 ns_client_detach(&client);
3286 CTRACE("query_find: done");
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;
3297 if (! isc_log_wouldlog(ns_g_lctx, level))
3298 return;
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));
3306 ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
3307 level, "query: %s %s %s", namebuf, classname, typename);
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;
3318 CTRACE("ns_query_start");
3321 * Ensure that appropriate cleanups occur.
3323 client->next = query_next_callback;
3325 if ((message->flags & DNS_MESSAGEFLAG_RD) != 0)
3326 client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
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
3334 if (client->view->minimalresponses)
3335 client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
3336 NS_QUERYATTR_NOADDITIONAL);
3338 if ((client->view->cachedb == NULL)
3339 || (!client->view->additionalfromcache)) {
3341 * We don't have a cache. Turn off cache support and
3342 * recursion.
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) {
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.
3354 client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
3358 * Get the question name.
3360 result = dns_message_firstname(message, DNS_SECTION_QUESTION);
3361 if (result != ISC_R_SUCCESS) {
3362 query_error(client, result);
3363 return;
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) {
3372 * There's more than one QNAME in the question
3373 * section.
3375 query_error(client, DNS_R_FORMERR);
3376 } else
3377 query_error(client, result);
3378 return;
3381 if (ns_g_server->log_queries)
3382 log_query(client);
3385 * Check for multiple question queries, since edns1 is dead.
3387 if (message->counts[DNS_SECTION_QUESTION] > 1) {
3388 query_error(client, DNS_R_FORMERR);
3389 return;
3393 * Check for meta-queries like IXFR and AXFR.
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;
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.
3430 if (message->flags & DNS_MESSAGEFLAG_CD ||
3431 qtype == dns_rdatatype_sig)
3433 client->query.dboptions |= DNS_DBFIND_PENDINGOK;
3434 client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
3438 * This is an ordinary query.
3440 result = dns_message_reply(message, ISC_TRUE);
3441 if (result != ISC_R_SUCCESS) {
3442 query_next(client, result);
3443 return;
3447 * Assume authoritative response until it is known to be
3448 * otherwise.
3450 message->flags |= DNS_MESSAGEFLAG_AA;
3453 * Set AD. We must clear it if we add non-validated data to a
3454 * response.
3456 if (WANTDNSSEC(client))
3457 message->flags |= DNS_MESSAGEFLAG_AD;
3460 * Synthesize IPv6 responses if appropriate.
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)
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;
3487 qclient = NULL;
3488 ns_client_attach(client, &qclient);
3489 query_find(qclient, NULL, qtype);
3493 * Generate a synthetic IPv6 forward mapping response for the current
3494 * query of 'client'.
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");
3501 synth_fwd_startfind(client);
3505 * Start an ADB find to get addresses, or more addresses, for
3506 * a synthetic IPv6 forward mapping response.
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;
3515 dns_fixedname_init(&target_fixed);
3516 target = dns_fixedname_name(&target_fixed);
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);
3526 ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
3527 ISC_LOG_DEBUG(5), "find returned %s",
3528 isc_result_totext(result));
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;
3537 * Make a persistent copy of the 'target' name data in 'ptarget';
3538 * it will become the new query name.
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);
3548 dns_adb_destroyfind(&find);
3551 * Get another temporary name 'tname' for insertion into the
3552 * response message.
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;
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 {
3575 * Probably a CNAME loop. Reply with partial
3576 * CNAME chain.
3578 result = ISC_R_SUCCESS;
3579 goto done;
3581 } else if (result != ISC_R_SUCCESS) {
3582 if (find != NULL)
3583 dns_adb_destroyfind(&find);
3584 goto fail;
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);
3594 return;
3596 fail:
3597 result = DNS_R_SERVFAIL;
3598 done:
3599 synth_finish(client, result);
3603 * Handle an ADB finddone event generated as part of synthetic IPv6
3604 * forward mapping processing.
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;
3612 UNUSED(task);
3614 ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
3615 ISC_LOG_DEBUG(5), "got find event");
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);
3624 isc_event_free(&ev);
3625 dns_adb_destroyfind(&find);
3630 * Generate a synthetic IPv6 forward mapping response based on
3631 * a completed ADB lookup.
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;
3641 result = dns_message_gettempname(client->message, &tname);
3642 if (result != ISC_R_SUCCESS)
3643 goto cleanup;
3644 dns_name_init(tname, NULL);
3646 result = dns_message_gettemprdatalist(client->message, &rdatalist);
3647 if (result != ISC_R_SUCCESS)
3648 goto cleanup;
3650 result = dns_message_gettemprdataset(client->message, &rdataset);
3651 if (result != ISC_R_SUCCESS)
3652 goto cleanup;
3653 dns_rdataset_init(rdataset);
3655 ISC_LIST_INIT(rdatalist->rdata);
3657 rdatalist->type = dns_rdatatype_aaaa;
3658 rdatalist->covers = 0;
3659 rdatalist->rdclass = client->message->rdclass;
3660 rdatalist->ttl = 0;
3662 dns_name_clone(client->query.qname, tname);
3664 for (ai = ISC_LIST_HEAD(find->list);
3665 ai != NULL;
3666 ai = ISC_LIST_NEXT(ai, publink)) {
3667 dns_rdata_t *rdata = NULL;
3669 struct sockaddr_in6 *sin6 = &ai->sockaddr.type.sin6;
3671 * Could it be useful to return IPv4 addresses as A records?
3673 if (sin6->sin6_family != AF_INET6)
3674 continue;
3676 result = dns_message_gettemprdata(client->message, &rdata);
3677 if (result != ISC_R_SUCCESS)
3678 goto cleanup;
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);
3687 dns_rdatalist_tordataset(rdatalist, rdataset);
3689 query_addrrset(client, &tname, &rdataset, NULL, NULL,
3690 DNS_SECTION_ANSWER);
3692 cleanup:
3693 if (tname != NULL)
3694 dns_message_puttempname(client->message, &tname);
3696 if (rdataset != NULL) {
3697 if (dns_rdataset_isassociated(rdataset))
3698 dns_rdataset_disassociate(rdataset);
3699 dns_message_puttemprdataset(client->message, &rdataset);
3702 synth_finish(client, result);
3706 * Finish synthetic IPv6 forward mapping processing.
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);
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
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.
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);
3755 * Convert the ip6.int name 'name' into the corresponding IPv6 address
3756 * in 'na'.
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;
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;
3775 isc_netaddr_fromin6(na, &ina6);
3776 return (ISC_R_SUCCESS);
3780 * Generate a synthetic IPv6 reverse mapping response for the current
3781 * query of 'client'.
3783 static void
3784 synth_rev_start(ns_client_t *client) {
3785 isc_result_t result;
3786 dns_byaddr_t *byaddr_dummy = NULL;
3788 ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
3789 ISC_LOG_DEBUG(5), "generating synthetic PTR response");
3791 result = nibbles2netaddr(client->query.qname, &client->query.synth.na);
3792 if (result != ISC_R_SUCCESS) {
3793 result = DNS_R_NXDOMAIN;
3794 goto cleanup;
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);
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;
3819 UNUSED(task);
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);
3836 dns_byaddr_destroy(&byaddr);
3837 isc_event_free(&event);
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;
3846 UNUSED(task);
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) {
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.
3861 synth_finish(client, DNS_R_NXDOMAIN);
3862 } else {
3863 synth_finish(client, bevent->result);
3865 isc_event_free(&event);
3866 dns_byaddr_destroy(&byaddr);
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;
3874 for (name = ISC_LIST_HEAD(bevent->names);
3875 name != NULL;
3876 name = ISC_LIST_NEXT(name, link))
3878 dns_name_t *tname = NULL;
3881 * Get a temporary name 'tname' for insertion into the
3882 * response message.
3884 result = dns_message_gettempname(client->message, &tname);
3885 if (result != ISC_R_SUCCESS)
3886 goto fail;
3887 dns_name_init(tname, NULL);
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;
3897 fail:
3898 synth_finish(client, result);