query.c revision 71f8edccba553c4ed4988dd12ac877564e4987d1
2bdfb330af70122f9ca5aae2556a112a3010e9efMark Andrews * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC")
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * Copyright (C) 1999-2003 Internet Software Consortium.
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * Permission to use, copy, modify, and/or distribute this software for any
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff * purpose with or without fee is hereby granted, provided that the above
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff * copyright notice and this permission notice appear in all copies.
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * PERFORMANCE OF THIS SOFTWARE.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * It has been recommended that DNS64 be changed to return excluded
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * AAAA addresses if DNS64 synthesis does not occur. This minimises
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * the impact on the lookup results. While most DNS AAAA lookups are
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * done to send IP packets to a host, not all of them are and filtering
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * excluded addresses has a negative impact on those uses.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Partial answer? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#define PARTIALANSWER(c) (((c)->query.attributes & \
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Use Cache? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Recursion OK? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#define RECURSIONOK(c) (((c)->query.attributes & \
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington/*% Recursing? */
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington#define RECURSING(c) (((c)->query.attributes & \
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Cache glue ok? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#define CACHEGLUEOK(c) (((c)->query.attributes & \
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Want Recursion? */
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews#define WANTRECURSION(c) (((c)->query.attributes & \
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Want DNSSEC? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Want WANTAD? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% No authority? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#define NOAUTHORITY(c) (((c)->query.attributes & \
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% No additional? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#define NOADDITIONAL(c) (((c)->query.attributes & \
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% Secure? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% DNS64 A lookup? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#define DNS64EXCLUDE(c) (((c)->query.attributes & \
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*% No QNAME Proof? */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#define CTRACE(m) ((void)m)
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff#define QTRACE(m) ((void)m)
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington#define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0)
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellingtonquery_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
383665e42ad838046472e847b16c4e0d3f1aaf76Bob Halleyvalidate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsquery_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
784a904bd06c7492361ed09a882d10c636b1291bAutomatic Updater dns_dbversion_t *version, ns_client_t *client,
c1ee8bb4ba3e9ab1463403ed685729631de406b1Mark Andrews dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
c1ee8bb4ba3e9ab1463403ed685729631de406b1Mark Andrewsstatic inline void
c1ee8bb4ba3e9ab1463403ed685729631de406b1Mark Andrewslog_queryerror(ns_client_t *client, isc_result_t result, int line, int level);
c1ee8bb4ba3e9ab1463403ed685729631de406b1Mark Andrews * Increment query statistics counters.
383665e42ad838046472e847b16c4e0d3f1aaf76Bob Halleystatic inline void
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellingtoninc_stats(ns_client_t *client, isc_statscounter_t counter) {
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington isc_stats_increment(ns_g_server->nsstats, counter);
383665e42ad838046472e847b16c4e0d3f1aaf76Bob Halley /* Do regular response type stats */
383665e42ad838046472e847b16c4e0d3f1aaf76Bob Halley /* Do query type statistics
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * We only increment per-type if we're using the authoriative
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * answer counter, preventing double-counting.
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington querystats = dns_zone_getrcvquerystats(zone);
383665e42ad838046472e847b16c4e0d3f1aaf76Bob Halley rdataset = ISC_LIST_HEAD(client->query.qname->list);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews inc_stats(client, dns_nsstatscounter_nonauthans);
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews if (client->message->rcode == dns_rcode_noerror) {
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews if (ISC_LIST_EMPTY(client->message->sections[answer])) {
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews } else if (client->message->rcode == dns_rcode_nxdomain)
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews else /* We end up here in case of YXDOMAIN, and maybe others */
65085946d4f92481699678e276e3ced04bcfdafbMark Andrewsquery_error(ns_client_t *client, isc_result_t result, int line) {
c1ee8bb4ba3e9ab1463403ed685729631de406b1Mark Andrews inc_stats(client, dns_nsstatscounter_servfail);
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff inc_stats(client, dns_nsstatscounter_failure);
383665e42ad838046472e847b16c4e0d3f1aaf76Bob Halleyquery_next(ns_client_t *client, isc_result_t result) {
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff inc_stats(client, dns_nsstatscounter_duplicate);
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff inc_stats(client, dns_nsstatscounter_dropped);
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff inc_stats(client, dns_nsstatscounter_failure);
da41917c3f882b6e12c7101b653926830a396b81Andreas Gustafssonstatic inline void
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellingtonquery_freefreeversions(ns_client_t *client, isc_boolean_t everything) {
e672951ed28b2e9cc7a19c3d7fa4a258382f981cAutomatic Updater ns_dbversion_t *dbversion, *dbversion_next;
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews unsigned int i;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews dbversion_next = ISC_LIST_NEXT(dbversion, link);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * If we're not freeing everything, we keep the first three
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews * dbversions structures around.
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff ISC_LIST_UNLINK(client->query.freeversions, dbversion,
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic inline void
65085946d4f92481699678e276e3ced04bcfdafbMark Andrewsquery_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews dns_message_puttemprdataset(client->message, rdatasetp);
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrewsstatic inline void
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrewsquery_reset(ns_client_t *client, isc_boolean_t everything) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * Reset the query state of a client to its default state.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * Cancel the fetch if it's running.
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff * Cleanup any active versions.
c1ee8bb4ba3e9ab1463403ed685729631de406b1Mark Andrews for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff dbversion_next = ISC_LIST_NEXT(dbversion, link);
cd82aa8fa32698240ecd6634f11e3052ca7a2448Michael Graff dns_db_closeversion(dbversion->db, &dbversion->version,
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington ISC_LIST_INITANDAPPEND(client->query.freeversions,
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington ISC_LIST_INIT(client->query.activeversions);
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington query_putrdataset(client, &client->query.dns64_aaaa);
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews query_putrdataset(client, &client->query.dns64_sigaaaa);
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews isc_mem_put(client->mctx, client->query.dns64_aaaaok,
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington query_freefreeversions(client, everything);
80b782f356f0692c11b4e52e8dd46ec41704e5a2Mark Andrews for (dbuf = ISC_LIST_HEAD(client->query.namebufs);
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
80b782f356f0692c11b4e52e8dd46ec41704e5a2Mark Andrews * client->query.qname was dynamically allocated.
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington isc_mem_put(client->mctx, client->query.rpz_st,
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington * Allocate a name buffer.
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington result = isc_buffer_allocate(client->mctx, &dbuf, 1024);
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington CTRACE("query_newnamebuf: isc_buffer_allocate failed: done");
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington * Return a name buffer with space for a maximal name, allocating
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington * a new one if necessary.
d0eb2cc33c5db3366a16b1cb0abcca6ec7c8ee3cTatuya JINMEI 神明達哉 if (ISC_LIST_EMPTY(client->query.namebufs)) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews CTRACE("query_getnamebuf: query_newnamebuf failed: done");
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington dbuf = ISC_LIST_TAIL(client->query.namebufs);
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington CTRACE("query_getnamebuf: query_newnamebuf failed: done");
f9f2e770a992cb0ed2234b2f985162273059c6d3Brian Wellington dbuf = ISC_LIST_TAIL(client->query.namebufs);
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellingtonstatic inline void
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellingtonquery_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
80b782f356f0692c11b4e52e8dd46ec41704e5a2Mark Andrews * 'name' is using space in 'dbuf', but 'dbuf' has not yet been
8cf24d101a291aa3274e8fd07d1a13cb5fe9976bBrian Wellington * adjusted to take account of that. We do the adjustment.
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halley REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0);
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halley client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halleystatic inline void
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halleyquery_releasename(ns_client_t *client, dns_name_t **namep) {
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halley * 'name' is no longer needed. Return it to our pool of temporary
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halley * names. If it is using a name buffer, relinquish its exclusive
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halley * rights on the buffer.
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED)
e800570a5a7572a94604815cd7d7e788c0479ed2Bob Halley client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
da41917c3f882b6e12c7101b653926830a396b81Andreas Gustafssonquery_newname(ns_client_t *client, isc_buffer_t *dbuf,
da41917c3f882b6e12c7101b653926830a396b81Andreas Gustafsson REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews result = dns_message_gettempname(client->message, &name);
da41917c3f882b6e12c7101b653926830a396b81Andreas Gustafsson CTRACE("query_newname: dns_message_gettempname failed: done");
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED;
da41917c3f882b6e12c7101b653926830a396b81Andreas Gustafsson result = dns_message_gettemprdataset(client->message, &rdataset);
da41917c3f882b6e12c7101b653926830a396b81Andreas Gustafsson "dns_message_gettemprdataset failed: done");
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellingtonquery_newdbversion(ns_client_t *client, unsigned int n) {
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews unsigned int i;
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington for (i = 0; i < n; i++) {
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington dbversion = isc_mem_get(client->mctx, sizeof(*dbversion));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews ISC_LIST_INITANDAPPEND(client->query.freeversions,
da41917c3f882b6e12c7101b653926830a396b81Andreas Gustafsson * We only return ISC_R_NOMEMORY if we couldn't
e672951ed28b2e9cc7a19c3d7fa4a258382f981cAutomatic Updater * allocate anything.
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halleystatic inline ns_dbversion_t *
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews if (ISC_LIST_EMPTY(client->query.freeversions)) {
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington dbversion = ISC_LIST_HEAD(client->query.freeversions);
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley result = isc_mutex_init(&client->query.fetchlock);
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halleystatic inline ns_dbversion_t *
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halleyquery_findversion(ns_client_t *client, dns_db_t *db)
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews * We may already have done a query related to this
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * database. If so, we must be sure to make subsequent
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * queries from the same version.
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley * This is a new zone for this query. Add it to
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley * the active list.
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews dns_db_currentversion(db, &dbversion->version);
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington ISC_LIST_APPEND(client->query.activeversions,
65085946d4f92481699678e276e3ced04bcfdafbMark Andrewsquery_validatezonedb(ns_client_t *client, dns_name_t *name,
9d2c9f789654ace01489c29af64c68cf42c6cb30Mark Andrews * This limits our searching to the zone where the first name
9d2c9f789654ace01489c29af64c68cf42c6cb30Mark Andrews * (the query target) was looked for. This prevents following
9d2c9f789654ace01489c29af64c68cf42c6cb30Mark Andrews * CNAMES or DNAMES into other zones and prevents returning
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley * additional data from other zones.
bab57cc87ffc890ba1ba3dbc6c022ae1a36726bcBob Halley * Non recursive query to a static-stub zone is prohibited; its
bab57cc87ffc890ba1ba3dbc6c022ae1a36726bcBob Halley * zone content is not public data, but a part of local configuration
bab57cc87ffc890ba1ba3dbc6c022ae1a36726bcBob Halley * and should not be disclosed.
bab57cc87ffc890ba1ba3dbc6c022ae1a36726bcBob Halley if (dns_zone_gettype(zone) == dns_zone_staticstub &&
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley * If the zone has an ACL, we'll check it, otherwise
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley * we use the view's "allow-query" ACL. Each ACL is only checked
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley * once per query.
e851ea826066ac5a5b01c2c23218faa0273a12e8Evan Hunt * Also, get the database version to use.
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews * Get the current version of this database.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * We've evaluated the view's queryacl already. If
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews * NS_QUERYATTR_QUERYOK is set, then the client is
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * allowed to make queries, otherwise the query should
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley * be refused.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE);
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington if (isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(3))) {
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews * We were allowed by the default
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington * "allow-query" ACL. Remember this so we
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews * don't have to check again.
a76b380643a22f23a67a9df284e86cd7ef7608c1Mark Andrews client->query.attributes |= NS_QUERYATTR_QUERYOK;
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington * We've now evaluated the view's query ACL, and
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington * the NS_QUERYATTR_QUERYOK attribute is now valid.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington /* If and only if we've gotten this far, check allow-query-on too */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews result = ns_client_checkaclsilent(client, NULL,
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews "query-on denied");
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews /* Transfer ownership, if necessary. */
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellingtonquery_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
368b37b616234fce3d23099eb180f1dd38e1fb62Mark Andrews unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley * Find a zone database to answer the query.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
5bfea18ff8bfa907b86ba7d17fb38b9cf493ae97Bob Halley if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley result = query_validatezonedb(client, name, qtype, options, zone, db,
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews /* Transfer ownership. */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (partial && (options & DNS_GETDB_PARTIAL) != 0)
0dae46cbc7f31e9ca9700016ae486f709b940bafAndreas Gustafssonrpz_log_rewrite(ns_client_t *client, const char *disabled,
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley if (!isc_log_wouldlog(ns_g_lctx, DNS_RPZ_INFO_LEVEL))
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf));
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley dns_name_format(rpz_qname, rpz_qname_buf, sizeof(rpz_qname_buf));
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley ns_client_log(client, DNS_LOGCATEGORY_RPZ, NS_LOGMODULE_QUERY,
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews DNS_RPZ_INFO_LEVEL, "%srpz %s %s rewrite %s via %s",
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews dns_rpz_type2str(type), dns_rpz_policy2str(policy),
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley dns_name_format(client->query.qname, namebuf1, sizeof(namebuf1));
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley dns_name_format(name, namebuf2, sizeof(namebuf2));
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS,
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley "rpz %s rewrite %s via %s %sfailed: %s",
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley namebuf1, namebuf2, str, isc_result_totext(result));
9b6fd12d8e53afbfc31022c881c16d2ccbe5fc51Bob Halley * Get a policy rewrite zone database.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsrpz_getdb(ns_client_t *client, dns_rpz_type_t rpz_type, dns_name_t *rpz_qname,
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp)
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews result = query_getzonedb(client, rpz_qname, dns_rdatatype_any,
b55c30f2de6e1baaa3a9ba69b92f428f2c255ac3Mark Andrews DNS_GETDB_IGNOREACL, zonep, dbp, &rpz_version);
b55c30f2de6e1baaa3a9ba69b92f428f2c255ac3Mark Andrews if (isc_log_wouldlog(ns_g_lctx, DNS_RPZ_DEBUG_LEVEL2)) {
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley dns_name_format(rpz_qname, namebuf2, sizeof(namebuf2));
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff "try rpz %s rewrite %s via %s",
9b6fd12d8e53afbfc31022c881c16d2ccbe5fc51Bob Halley rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, rpz_type, rpz_qname,
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffquery_getcachedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * Find a cache database to answer the query.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * This may fail with DNS_R_REFUSED if the client
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews * is not allowed to use the cache.
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley if ((client->query.attributes & NS_QUERYATTR_CACHEACLOKVALID) != 0) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * We've evaluated the view's cacheacl already. If
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews * NS_QUERYATTR_CACHEACLOK is set, then the client is
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * allowed to make queries, otherwise the query should
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley * be refused.
0dae46cbc7f31e9ca9700016ae486f709b940bafAndreas Gustafsson if ((client->query.attributes & NS_QUERYATTR_CACHEACLOK) == 0)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * We haven't evaluated the view's queryacl yet.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
65085946d4f92481699678e276e3ced04bcfdafbMark Andrews char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley * We were allowed by the "allow-query-cache" ACL.
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley * Remember this so we don't have to check again.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews } else if (log) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley * We've now evaluated the view's query ACL, and
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley * the NS_QUERYATTR_CACHEACLOKVALID attribute is now valid.
926cde044f4334f7afd9d1123ab0f01ec93e7e72Bob Halley client->query.attributes |= NS_QUERYATTR_CACHEACLOKVALID;
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington /* Approved. */
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington /* Transfer ownership. */
65085946d4f92481699678e276e3ced04bcfdafbMark Andrewsquery_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington dns_dbversion_t **versionp, isc_boolean_t *is_zonep)
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington /* Calculate how many labels are in name. */
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington /* Try to find name in bind's standard database. */
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington result = query_getzonedb(client, name, qtype, options, &zone,
88b9c12a3cbafc3bebedf50a731bec9ce2f99a13Brian Wellington /* See how many labels are in the zone's name. */
6434457b0b380aa43d7159299776959a00269d65Michael Graff zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
6434457b0b380aa43d7159299776959a00269d65Michael Graff * If # zone labels < # name labels, try to find an even better match
6434457b0b380aa43d7159299776959a00269d65Michael Graff * Only try if DLZ drivers are loaded for this view
6434457b0b380aa43d7159299776959a00269d65Michael Graff dns_clientinfomethods_init(&cm, ns_client_sourceip);
6434457b0b380aa43d7159299776959a00269d65Michael Graff tresult = dns_view_searchdlz(client->view, name,
6434457b0b380aa43d7159299776959a00269d65Michael Graff /* If we successful, we found a better match. */
6434457b0b380aa43d7159299776959a00269d65Michael Graff * If the previous search returned a zone, detach it.
6434457b0b380aa43d7159299776959a00269d65Michael Graff * If the previous search returned a database,
6434457b0b380aa43d7159299776959a00269d65Michael Graff * If the previous search returned a version, clear it.
return (result);
static inline isc_boolean_t
section++) {
return (ISC_TRUE);
return (ISC_FALSE);
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET:
case DNS_R_CNAME:
case DNS_R_DNAME:
case DNS_R_GLUE:
case DNS_R_ZONECUT:
static isc_result_t
isc_buffer_t b;
return (ISC_R_SUCCESS);
goto cleanup;
goto cleanup;
goto cleanup;
goto try_cache;
goto found;
goto try_glue;
goto cleanup;
goto found;
goto cleanup;
goto cleanup;
goto cleanup;
#ifdef ALLOW_FILTER_AAAA
goto addname;
goto addname;
goto aaaa_lookup;
dns_rdatatype_a, 0,
goto addname;
#ifdef ALLOW_FILTER_AAAA
goto addname;
goto addname;
goto addname;
goto addname;
#ifdef ALLOW_FILTER_AAAA
if (have_a &&
goto addname;
if (!added_something)
goto cleanup;
if (need_addname)
client);
return (eresult);
static inline isc_result_t
return (result);
goto cleanup;
return (result);
static isc_result_t
isc_buffer_t b;
goto cleanup;
goto cleanup;
goto findauthdb;
goto try_cache;
&cfname);
goto findauthdb;
goto try_cache;
&cfname);
goto try_cache;
goto foundcache;
NULL);
goto try_cache;
goto found;
goto try_glue;
goto found;
goto cleanup;
goto cleanup;
goto findglue;
&cfname);
goto findglue;
goto cleanup;
goto foundcache;
fname);
goto cleanup;
goto cleanup;
goto cleanup;
goto aaaa_lookup;
goto setcache;
goto foundcache;
goto foundcache;
&cfname);
&mname)) {
if (!added_something)
goto cleanup;
if (need_addname)
return (eresult);
static isc_result_t
isc_region_t r;
unsigned int flags = 0;
return (ISC_R_SUCCESS);
goto cleanup;
goto cleanup;
goto cleanup;
&dns64_rdata);
goto cleanup;
dns_rdatatype_aaaa, &r);
link);
goto cleanup;
goto cleanup;
goto cleanup;
return (result);
isc_region_t r;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
dns_rdatatype_aaaa, &r);
goto cleanup;
goto cleanup;
static inline isc_result_t
return (ISC_R_SUCCESS);
return (result);
goto cleanup;
goto cleanup;
goto cleanup;
return (eresult);
static inline isc_result_t
return (result);
goto cleanup;
goto cleanup;
return (eresult);
static isc_result_t
isc_region_t r;
return (result);
return (result);
return (result);
return (result);
return (result);
== ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
0, NULL);
0, NULL);
static isc_boolean_t
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
isc_buffer_t b;
return (secure);
static isc_boolean_t
goto again;
return (ISC_TRUE);
return (ISC_FALSE);
static isc_boolean_t
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
isc_buffer_t b;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
if (is_zone) {
goto cleanup;
goto db_find;
goto cleanup;
if (use_zone) {
goto cleanup;
goto cleanup;
* If the answer is secure only add NS records if they are secure * when the client may be looking for AD in the response.
goto cleanup;
unsigned int count;
goto cleanup;
goto addnsec3;
goto addnsec3;
goto cleanup;
&rname);
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
unsigned int options;
int order;
goto cleanup;
goto cleanup;
if (labels == 0U)
goto cleanup;
goto cleanup;
if (!ispositive)
goto cleanup;
goto cleanup;
goto cleanup;
if (ispositive)
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
if (!ispositive)
&olabels);
&nlabels);
goto cleanup;
if (have_wname) {
goto again;
unsigned int labels;
int errorloglevel;
if (fetch_canceled)
static isc_result_t
if (!resuming)
return (result);
return (ISC_R_NOMEMORY);
return (ISC_R_NOMEMORY);
return (result);
static inline isc_result_t
return (DNS_R_SERVFAIL);
return (ISC_R_SUCCESS);
static isc_result_t
return (result);
return (result);
return (result);
return (result);
static isc_result_t
return (DNS_R_SERVFAIL);
return (ISC_R_SUCCESS);
static isc_result_t
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_EMPTYNAME:
case DNS_R_EMPTYWILD:
case DNS_R_NXDOMAIN:
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NXRRSET:
case DNS_R_NCACHENXRRSET:
case ISC_R_NOTFOUND:
case DNS_R_DELEGATION:
case DNS_R_DUPLICATE:
case DNS_R_DROP:
case DNS_R_CNAME:
case DNS_R_DNAME:
return (result);
static isc_result_t
resuming);
resuming);
return (result);
static isc_result_t
return (result);
return (DNS_R_NXDOMAIN);
&rdsiter);
return (DNS_R_SERVFAIL);
result);
return (DNS_R_SERVFAIL);
* Ask again to get the right DNS_R_DNAME/NXRRSET/...
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_DNAME:
case DNS_R_NXRRSET:
case DNS_R_NXDOMAIN:
case DNS_R_EMPTYNAME:
return (result);
static isc_result_t
unsigned int labels;
return (ISC_R_SUCCESS);
switch (result) {
case DNS_R_NXDOMAIN:
case DNS_R_EMPTYNAME:
case DNS_R_SERVFAIL:
return (DNS_R_SERVFAIL);
* st->m.rpz->num > rpz->num or st->m.type >= rpz_type
return (ISC_R_SUCCESS);
static isc_result_t
return (ISC_R_NOMEMORY);
switch (qresult) {
case ISC_R_SUCCESS:
case DNS_R_GLUE:
case DNS_R_ZONECUT:
case DNS_R_EMPTYNAME:
case DNS_R_NXRRSET:
case DNS_R_NXDOMAIN:
case DNS_R_EMPTYWILD:
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET:
case DNS_R_CNAME:
case DNS_R_DNAME:
case DNS_R_DELEGATION:
case ISC_R_NOTFOUND:
return (ISC_R_SUCCESS);
case ISC_R_FAILURE:
case ISC_R_TIMEDOUT:
case DNS_R_BROKENCHAIN:
qresult);
return (ISC_R_SUCCESS);
qresult);
return (ISC_R_SUCCESS);
goto cleanup;
goto cleanup;
DNS_RPZ_HAVE_NSDNAME)) == 0) {
goto cleanup;
resuming);
goto cleanup;
switch (result) {
case ISC_R_SUCCESS:
goto cleanup;
case DNS_R_DELEGATION:
goto cleanup;
case DNS_R_EMPTYNAME:
case DNS_R_NXRRSET:
case DNS_R_EMPTYWILD:
case DNS_R_NXDOMAIN:
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET:
case ISC_R_NOTFOUND:
case DNS_R_CNAME:
case DNS_R_DNAME:
0, NULL);
case ISC_R_TIMEDOUT:
case DNS_R_BROKENCHAIN:
case ISC_R_FAILURE:
goto cleanup;
&rdataset);
goto cleanup;
goto cleanup;
return (result);
static isc_boolean_t
return (ISC_TRUE);
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_TRUE);
* Add a CNAME to the query response, including translating foo.evil.com and
* foo.evil.com CNAME foo.evil.com.example.com
static isc_result_t
unsigned int labels;
return (result);
return (result);
return (ISC_R_SUCCESS);
#define QUERY_ERROR(r) \
eresult = r; \
#define RECURSE_ERROR(r) \
QUERY_ERROR(r); \
static isc_result_t
case dns_rdatatype_a:
return (ISC_R_SUCCESS);
case dns_rdatatype_aaaa:
return (ISC_R_SUCCESS);
return (ISC_R_NOTIMPLEMENTED);
return (INT_MAX);
return (INT_MAX);
case NS_SORTLISTTYPE_1ELEMENT:
case NS_SORTLISTTYPE_2ELEMENT:
case NS_SORTLISTTYPE_NONE:
INSIST(0);
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
#define NS_NAME_INIT(A,B) \
&rfc1918names[i],
&found);
unsigned int dboptions;
int order;
unsigned int count;
goto again;
if (exact)
} else if (!exact)
#ifdef ALLOW_FILTER_AAAA
static isc_boolean_t
return (ISC_TRUE);
return (ISC_TRUE);
return (ISC_FALSE);
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
static isc_uint32_t
goto cleanup;
goto cleanup;
goto cleanup;
return (ttl);
static isc_boolean_t
unsigned int flags = 0;
unsigned int i, count;
return (ISC_TRUE);
for (i = 0; i < count; i++) {
return (ISC_TRUE);
return (ISC_FALSE);
static isc_boolean_t
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
ISC_TRUE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
static isc_result_t
unsigned int n, nlabels;
int order;
isc_buffer_t b;
unsigned int options;
options = 0;
goto cleanup;
goto cleanup;
goto cleanup;
goto resume;
sizeof(classname));
goto cleanup;
&tversion);
goto cleanup;
if (is_zone) {
if (is_zone) {
goto cleanup;
goto cleanup;
goto cleanup;
switch (rresult) {
case ISC_R_SUCCESS:
case DNS_R_DELEGATION:
goto cleanup;
goto cleanup;
case DNS_RPZ_POLICY_NXDOMAIN:
case DNS_RPZ_POLICY_NODATA:
case DNS_RPZ_POLICY_RECORD:
case DNS_RPZ_POLICY_WILDCNAME:
NULL);
goto cleanup;
goto cleanup;
case DNS_RPZ_POLICY_CNAME:
* Add overridding CNAME from a named.conf
goto cleanup;
goto cleanup;
INSIST(0);
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_GLUE:
case DNS_R_ZONECUT:
case ISC_R_NOTFOUND:
if (dns64)
if (dns64_exclude)
goto cleanup;
goto cleanup;
case DNS_R_DELEGATION:
if (is_zone) {
&tversion);
&sigrdataset);
&fname);
goto db_find;
goto db_find;
&sigrdataset);
else if (dns64)
resuming);
if (dns64)
if (dns64_exclude)
goto cleanup;
case DNS_R_EMPTYNAME:
case DNS_R_NXRRSET:
if (dns64)
goto cleanup;
goto cleanup;
if (dns64_excluded)
goto db_find;
!(ns_g_nonearest &&
unsigned int count;
unsigned int skip;
dbuf,
found);
goto cleanup;
NULL);
goto cleanup;
&sigrdataset);
goto cleanup;
case DNS_R_EMPTYWILD:
case DNS_R_NXDOMAIN:
if (!empty_wild &&
type))
goto cleanup;
if (empty_wild)
goto cleanup;
case DNS_R_NCACHENXDOMAIN:
type))
case DNS_R_NCACHENXRRSET:
if (dns64)
goto cleanup;
goto cleanup;
if (dns64_excluded)
goto db_find;
goto cleanup;
case DNS_R_CNAME:
NULL);
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto addauth;
case DNS_R_DNAME:
NULL);
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto addauth;
goto cleanup;
#ifdef ALLOW_FILTER_AAAA
ISC_TRUE);
#ifdef ALLOW_FILTER_AAAA
goto cleanup;
#ifdef ALLOW_FILTER_AAAA
#ifdef ALLOW_FILTER_AAAA
#ifdef ALLOW_FILTER_AAAA
if (!is_zone) {
goto addauth;
sizeof(namebuf));
goto nxrrset_rrsig;
goto cleanup;
#ifdef ALLOW_FILTER_AAAA
dns_rdatatype_a, 0,
} else if (authoritative ||
NS_CLIENTATTR_FILTER_AAAA_RC) != 0) {
goto cleanup;
goto db_find;
if (dns64) {
if (dns64_exclude) {
if (!is_zone)
goto cleanup;
goto cleanup;
if (is_zone)
goto iszone_nxrrset;
goto ncache_nxrrset;
goto cleanup;
if (is_zone) {
goto restart;
if (resuming &&
return (eresult);
onbuf);
sizeof(namebuf));
sizeof(classname));
sizeof(typename));
switch (qtype) {
case dns_rdatatype_any:
case dns_rdatatype_ixfr:
case dns_rdatatype_axfr:
case dns_rdatatype_maila:
case dns_rdatatype_mailb:
case dns_rdatatype_tkey:
if (!ns_g_noaa)