* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.198.2.3 2002/01/24 03:49:01 marka Exp $ */
+/* $Id: query.c,v 1.198.2.4 2002/01/24 04:22:57 marka Exp $ */
#include <config.h>
* Increment query statistics counters.
*/
static inline void
-count_query(dns_zone_t *zone, isc_boolean_t is_zone,
- dns_statscounter_t counter)
-{
+inc_stats(ns_client_t *client, dns_statscounter_t counter) {
+ dns_zone_t *zone = client->query.authzone;
+
REQUIRE(counter < DNS_STATS_NCOUNTERS);
ns_g_server->querystats[counter]++;
- if (is_zone && zone != NULL) {
+ if (zone != NULL) {
isc_uint64_t *zonestats = dns_zone_getstatscounters(zone);
if (zonestats != NULL)
zonestats[counter]++;
}
}
+static void
+query_send(ns_client_t *client) {
+ dns_statscounter_t counter;
+ if (client->message->rcode == dns_rcode_noerror) {
+ if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) {
+ if (client->query.isreferral) {
+ counter = dns_statscounter_referral;
+ } else {
+ counter = dns_statscounter_nxrrset;
+ }
+ } else {
+ counter = dns_statscounter_success;
+ }
+ } else if (client->message->rcode == dns_rcode_nxdomain) {
+ counter = dns_statscounter_nxdomain;
+ } else {
+ /* We end up here in case of YXDOMAIN, and maybe others */
+ counter = dns_statscounter_failure;
+ }
+ inc_stats(client, counter);
+ ns_client_send(client);
+}
+
+static void
+query_error(ns_client_t *client, isc_result_t result) {
+ inc_stats(client, dns_statscounter_failure);
+ ns_client_error(client, result);
+}
+
+static void
+query_next(ns_client_t *client, isc_result_t result) {
+ inc_stats(client, dns_statscounter_failure);
+ ns_client_next(client, result);
+}
+
static inline void
query_maybeputqname(ns_client_t *client) {
if (client->query.restarts > 0) {
if (client->query.authdb != NULL)
dns_db_detach(&client->query.authdb);
+ if (client->query.authzone != NULL)
+ dns_zone_detach(&client->query.authzone);
/*
* Clean up free versions.
client->query.dboptions = 0;
client->query.fetchoptions = 0;
client->query.gluedb = NULL;
- client->query.authdbvalid = ISC_FALSE;
+ client->query.authdbset = ISC_FALSE;
+ client->query.isreferral = ISC_FALSE;
}
static void
-query_next(ns_client_t *client) {
+query_next_callback(ns_client_t *client) {
query_reset(client, ISC_FALSE);
}
client->query.qname = NULL;
client->query.fetch = NULL;
client->query.authdb = NULL;
- client->query.authdbvalid = ISC_FALSE;
+ client->query.authzone = NULL;
+ client->query.authdbset = ISC_FALSE;
+ client->query.isreferral = ISC_FALSE;
query_reset(client, ISC_FALSE);
result = query_newdbversion(client, 3);
if (result != ISC_R_SUCCESS)
* additional data from other zones.
*/
if (!client->view->additionalfromauth &&
- client->query.authdbvalid &&
+ client->query.authdbset &&
db != client->query.authdb)
goto refuse;
dns_rdataset_isassociated(sigrdataset))
dns_rdataset_disassociate(sigrdataset);
if (is_zone) {
- count_query(zone, is_zone, dns_statscounter_referral);
if (USECACHE(client)) {
/*
* Either the answer is in the cache, or we
}
/*
* If we get here, the result is ISC_R_SUCCESS, and we found the
- * answer we were looking for in the zone. Update the zone's
- * query counter.
+ * answer we were looking for in the zone.
*/
- if (result == ISC_R_SUCCESS)
- count_query(zone, is_zone, dns_statscounter_success);
cleanup:
if (dns_rdataset_isassociated(&zrdataset)) {
if (devent->sigrdataset != NULL)
query_putrdataset(client, &devent->sigrdataset);
isc_event_free(&event);
- ns_client_next(client, ISC_R_CANCELED);
+ query_next(client, ISC_R_CANCELED);
/*
* This may destroy the client.
*/
isc_result_t result;
dns_rdataset_t *rdataset, *sigrdataset;
+ inc_stats(client, dns_statscounter_recursion);
+
/*
* We are about to recurse, which means that this client will
* be unavailable for serving new requests for an indeterminate
*/
dbuf = query_getnamebuf(client);
if (dbuf == NULL) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
fname = query_newname(client, dbuf, &b);
if (fname == NULL) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
tname = dns_fixedname_name(&event->foundname);
result = dns_name_copy(tname, fname, NULL);
if (result != ISC_R_SUCCESS) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
result = query_getdb(client, client->query.qname, 0, &zone, &db,
&version, &is_zone);
if (result != ISC_R_SUCCESS) {
- count_query(NULL, ISC_FALSE, dns_statscounter_failure);
if (result == DNS_R_REFUSED)
QUERY_ERROR(DNS_R_REFUSED);
else
authoritative = ISC_TRUE;
if (event == NULL && client->query.restarts == 0) {
- if (is_zone)
+ if (is_zone) {
+ dns_zone_attach(zone, &client->query.authzone);
dns_db_attach(db, &client->query.authdb);
- client->query.authdbvalid = ISC_TRUE;
+ }
+ client->query.authdbset = ISC_TRUE;
}
db_find:
*/
dbuf = query_getnamebuf(client);
if (dbuf == NULL) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
fname = query_newname(client, dbuf, &b);
rdataset = query_newrdataset(client);
if (fname == NULL || rdataset == NULL) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
if (WANTDNSSEC(client)) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
result = dns_name_copy(client->query.qname,
fname, NULL);
if (result != ISC_R_SUCCESS) {
- count_query(zone, is_zone,
- dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
CTRACE("query_find: resume");
switch (result) {
case ISC_R_SUCCESS:
- count_query(zone, is_zone, dns_statscounter_success);
/*
* This case is handled in the main line below.
*/
* recurse anyway.
*/
if (RECURSIONOK(client)) {
- count_query(zone, is_zone,
- dns_statscounter_recursion);
result = query_recurse(client, qtype,
NULL, NULL);
if (result == ISC_R_SUCCESS)
NS_QUERYATTR_RECURSING;
else {
/* Unable to recurse. */
- count_query(zone, is_zone,
- dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
}
goto cleanup;
} else {
/* Unable to give root server referral. */
- count_query(zone, is_zone,
- dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
* database by setting client->query.gluedb.
*/
client->query.gluedb = db;
+ client->query.isreferral = ISC_TRUE;
/*
* We must ensure NOADDITIONAL is off,
* because the generation of
sigrdatasetp = &sigrdataset;
else
sigrdatasetp = NULL;
- query_addrrset(client, &fname, &rdataset,
- sigrdatasetp, dbuf,
- DNS_SECTION_AUTHORITY);
+ query_addrrset(client, &fname,
+ &rdataset, sigrdatasetp,
+ dbuf, DNS_SECTION_AUTHORITY);
client->query.gluedb = NULL;
} else {
/*
/*
* Recurse!
*/
- count_query(zone, is_zone,
- dns_statscounter_recursion);
if (type == dns_rdatatype_key)
result = query_recurse(client, qtype,
NULL, NULL);
if (result == ISC_R_SUCCESS)
client->query.attributes |=
NS_QUERYATTR_RECURSING;
- else {
- count_query(zone, is_zone,
- dns_statscounter_failure);
+ else
QUERY_ERROR(DNS_R_SERVFAIL);
- }
} else {
/*
* This is the best answer.
*/
- count_query(zone, is_zone,
- dns_statscounter_referral);
- client->query.gluedb = zdb;
client->query.attributes |=
NS_QUERYATTR_CACHEGLUEOK;
+ client->query.gluedb = zdb;
+ client->query.isreferral = ISC_TRUE;
/*
* We must ensure NOADDITIONAL is off,
* because the generation of
goto cleanup;
case DNS_R_NXRRSET:
INSIST(is_zone);
- count_query(zone, is_zone, dns_statscounter_nxrrset);
if (dns_rdataset_isassociated(rdataset)) {
/*
* If we've got a NXT record, we need to save the
*/
result = query_addsoa(client, db, ISC_FALSE);
if (result != ISC_R_SUCCESS) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(result);
goto cleanup;
}
goto cleanup;
case DNS_R_NXDOMAIN:
INSIST(is_zone);
- count_query(zone, is_zone, dns_statscounter_nxdomain);
if (dns_rdataset_isassociated(rdataset)) {
/*
* If we've got a NXT record, we need to save the
else
result = query_addsoa(client, db, ISC_FALSE);
if (result != ISC_R_SUCCESS) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(result);
goto cleanup;
}
client->message->rcode = dns_rcode_nxdomain;
goto cleanup;
case DNS_R_NCACHENXDOMAIN:
- INSIST(!is_zone);
- count_query(NULL, is_zone, dns_statscounter_nxdomain);
- goto ncachenxrrset;
case DNS_R_NCACHENXRRSET:
INSIST(!is_zone);
- count_query(NULL, is_zone, dns_statscounter_nxrrset);
- ncachenxrrset:
authoritative = ISC_FALSE;
/*
* Set message rcode, if required.
/*
* Something has gone wrong.
*/
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
rdsiter = NULL;
result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
if (result != ISC_R_SUCCESS) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
/*
* Something went wrong.
*/
- count_query(zone, is_zone,
- dns_statscounter_failure);
result = DNS_R_SERVFAIL;
}
}
dns_rdatasetiter_destroy(&rdsiter);
if (result != ISC_R_NOMORE) {
- count_query(zone, is_zone, dns_statscounter_failure);
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
* or if the client requested recursion and thus wanted
* the complete answer, send an error response.
*/
- ns_client_error(client, eresult);
+ query_error(client, eresult);
ns_client_detach(&client);
} else if (!RECURSING(client)) {
/*
client->view->auth_nxdomain == ISC_TRUE)
client->message->flags |= DNS_MESSAGEFLAG_AA;
- ns_client_send(client);
+ query_send(client);
ns_client_detach(&client);
}
CTRACE("query_find: done");
/*
* Ensure that appropriate cleanups occur.
*/
- client->next = query_next;
+ client->next = query_next_callback;
if ((message->flags & DNS_MESSAGEFLAG_RD) != 0)
client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
*/
result = dns_message_firstname(message, DNS_SECTION_QUESTION);
if (result != ISC_R_SUCCESS) {
- ns_client_error(client, result);
+ query_error(client, result);
return;
}
dns_message_currentname(message, DNS_SECTION_QUESTION,
* There's more than one QNAME in the question
* section.
*/
- ns_client_error(client, DNS_R_FORMERR);
+ query_error(client, DNS_R_FORMERR);
} else
- ns_client_error(client, result);
+ query_error(client, result);
return;
}
* Check for multiple question queries, since edns1 is dead.
*/
if (message->counts[DNS_SECTION_QUESTION] > 1) {
- ns_client_error(client, DNS_R_FORMERR);
+ query_error(client, DNS_R_FORMERR);
return;
}
return;
case dns_rdatatype_maila:
case dns_rdatatype_mailb:
- ns_client_error(client, DNS_R_NOTIMP);
+ query_error(client, DNS_R_NOTIMP);
return;
case dns_rdatatype_tkey:
result = dns_tkey_processquery(client->message,
ns_g_server->tkeyctx,
client->view->dynamickeys);
if (result == ISC_R_SUCCESS)
- ns_client_send(client);
+ query_send(client);
else
- ns_client_error(client, result);
+ query_error(client, result);
return;
default: /* TSIG, etc. */
- ns_client_error(client, DNS_R_FORMERR);
+ query_error(client, DNS_R_FORMERR);
return;
}
}
*/
result = dns_message_reply(message, ISC_TRUE);
if (result != ISC_R_SUCCESS) {
- ns_client_next(client, result);
+ query_next(client, result);
return;
}
static void
synth_finish(ns_client_t *client, isc_result_t result) {
if (result == ISC_R_SUCCESS)
- ns_client_send(client);
+ query_send(client);
else
- ns_client_error(client, result);
+ query_error(client, result);
ns_client_detach(&client);
}