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