* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.257.18.50 2009/02/15 23:08:14 marka Exp $ */
+/* $Id: query.c,v 1.257.18.51 2009/09/24 21:38:50 jinmei Exp $ */
/*! \file */
dns_rdataset_t *rdataset;
} client_additionalctx_t;
-static void
+static isc_result_t
query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
static isc_boolean_t
validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+static inline void
+log_queryerror(ns_client_t *client, isc_result_t result, int line, int level);
+
/*%
* Increment query statistics counters.
*/
}
static void
-query_error(ns_client_t *client, isc_result_t result) {
+query_error(ns_client_t *client, isc_result_t result, int line) {
+ int loglevel = ISC_LOG_DEBUG(3);
+
+ if (result == DNS_R_SERVFAIL)
+ loglevel = ISC_LOG_DEBUG(1);
+
inc_stats(client, dns_statscounter_failure);
+ log_queryerror(client, result, line, loglevel);
ns_client_error(client, result);
}
static void
query_resume(isc_task_t *task, isc_event_t *event) {
dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
+ dns_fetch_t *fetch;
ns_client_t *client;
isc_boolean_t fetch_canceled, client_shuttingdown;
+ isc_result_t result;
+ isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_EERRORS;
+ int errorloglevel;
/*
* Resume a query after recursion.
INSIST(client->query.fetch == NULL);
client->query.attributes &= ~NS_QUERYATTR_RECURSING;
- dns_resolver_destroyfetch(&devent->fetch);
+ fetch = devent->fetch;
+ devent->fetch = NULL;
/*
* If this client is shutting down, or this transaction
query_putrdataset(client, &devent->sigrdataset);
isc_event_free(&event);
if (fetch_canceled)
- query_error(client, DNS_R_SERVFAIL);
+ query_error(client, DNS_R_SERVFAIL, __LINE__);
else
query_next(client, ISC_R_CANCELED);
/*
*/
ns_client_detach(&client);
} else {
- query_find(client, devent, 0);
+ result = query_find(client, devent, 0);
+ if (result != ISC_R_SUCCESS) {
+ if (result == DNS_R_SERVFAIL)
+ errorloglevel = ISC_LOG_DEBUG(2);
+ else
+ errorloglevel = ISC_LOG_DEBUG(4);
+ if (isc_log_wouldlog(ns_g_lctx, errorloglevel)) {
+ dns_resolver_logfetch(fetch, ns_g_lctx,
+ logcategory,
+ NS_LOGMODULE_QUERY,
+ errorloglevel, ISC_FALSE);
+ }
+ }
}
+
+ dns_resolver_destroyfetch(&fetch);
}
static isc_result_t
do { \
eresult = r; \
want_restart = ISC_FALSE; \
+ line = __LINE__; \
} while (0)
/*
* If 'event' is non-NULL, we are returning from recursion and 'qtype'
* is ignored. Otherwise, 'qtype' is the query type.
*/
-static void
+static isc_result_t
query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
{
dns_db_t *db, *zdb;
isc_boolean_t empty_wild;
dns_rdataset_t *noqname;
isc_boolean_t resuming;
+ int line = -1;
CTRACE("query_find");
* or if the client requested recursion and thus wanted
* the complete answer, send an error response.
*/
- query_error(client, eresult);
+ INSIST(line >= 0);
+ query_error(client, eresult, line);
}
ns_client_detach(&client);
} else if (!RECURSING(client)) {
client->view->auth_nxdomain == ISC_TRUE)
client->message->flags |= DNS_MESSAGEFLAG_AA;
+ /*
+ * If the response is somehow unexpected for the client and this
+ * is a result of recursion, return an error to the caller
+ * to indicate it may need to be logged.
+ */
+ if (resuming &&
+ (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) ||
+ client->message->rcode != dns_rcode_noerror))
+ eresult = ISC_R_FAILURE;
+
query_send(client);
ns_client_detach(&client);
}
CTRACE("query_find: done");
+
+ return (eresult);
}
static inline void
(client->opt != NULL) ? "E" : "");
}
+static inline void
+log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char typename[DNS_RDATATYPE_FORMATSIZE];
+ char classname[DNS_RDATACLASS_FORMATSIZE];
+ const char *namep, *typep, *classp, *sep1, *sep2;
+ dns_rdataset_t *rdataset;
+
+ if (!isc_log_wouldlog(ns_g_lctx, level))
+ return;
+
+ namep = typep = classp = sep1 = sep2 = "";
+
+ /*
+ * Query errors can happen for various reasons. In some cases we cannot
+ * even assume the query contains a valid question section, so we should
+ * expect exceptional cases.
+ */
+ if (client->query.origqname != NULL) {
+ dns_name_format(client->query.origqname, namebuf,
+ sizeof(namebuf));
+ namep = namebuf;
+ sep1 = " for ";
+
+ rdataset = ISC_LIST_HEAD(client->query.origqname->list);
+ if (rdataset != NULL) {
+ dns_rdataclass_format(rdataset->rdclass, classname,
+ sizeof(classname));
+ classp = classname;
+ dns_rdatatype_format(rdataset->type, typename,
+ sizeof(typename));
+ typep = typename;
+ sep2 = "/";
+ }
+ }
+
+ ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, NS_LOGMODULE_QUERY,
+ level, "query failed (%s)%s%s%s%s%s%s at %s:%d",
+ isc_result_totext(result), sep1, namep, sep2,
+ classp, sep2, typep, __FILE__, line);
+}
+
void
ns_query_start(ns_client_t *client) {
isc_result_t result;
*/
result = dns_message_firstname(message, DNS_SECTION_QUESTION);
if (result != ISC_R_SUCCESS) {
- query_error(client, result);
+ query_error(client, result, __LINE__);
return;
}
dns_message_currentname(message, DNS_SECTION_QUESTION,
* There's more than one QNAME in the question
* section.
*/
- query_error(client, DNS_R_FORMERR);
+ query_error(client, DNS_R_FORMERR, __LINE__);
} else
- query_error(client, result);
+ query_error(client, result, __LINE__);
return;
}
* Check for multiple question queries, since edns1 is dead.
*/
if (message->counts[DNS_SECTION_QUESTION] > 1) {
- query_error(client, DNS_R_FORMERR);
+ query_error(client, DNS_R_FORMERR, __LINE__);
return;
}
return;
case dns_rdatatype_maila:
case dns_rdatatype_mailb:
- query_error(client, DNS_R_NOTIMP);
+ query_error(client, DNS_R_NOTIMP, __LINE__);
return;
case dns_rdatatype_tkey:
result = dns_tkey_processquery(client->message,
if (result == ISC_R_SUCCESS)
query_send(client);
else
- query_error(client, result);
+ query_error(client, result, __LINE__);
return;
default: /* TSIG, etc. */
- query_error(client, DNS_R_FORMERR);
+ query_error(client, DNS_R_FORMERR, __LINE__);
return;
}
}
qclient = NULL;
ns_client_attach(client, &qclient);
- query_find(qclient, NULL, qtype);
+ (void)query_find(qclient, NULL, qtype);
}
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- File: $Id: Bv9ARM-book.xml,v 1.241.18.110 2009/07/14 17:57:25 jreed Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.241.18.111 2009/09/24 21:38:50 jinmei Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
</para>
</entry>
</row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><command>query-errors</command></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ Information about queries that resulted in some
+ failure.
+ </para>
+ </entry>
+ </row>
<row rowsep="0">
<entry colname="1">
<para><command>dispatch</command></para>
</tgroup>
</informaltable>
</sect3>
+ <sect3>
+ <title>The <command>query-errors</command> Category</title>
+ <para>
+ The <command>query-errors</command> category is
+ specifically intended for debugging purposes: To identify
+ why and how specific queries result in responses which
+ indicate an error.
+ Messages of this category are therefore only logged
+ with <command>debug</command> levels.
+ </para>
+
+ <para>
+ At the debug levels of 1 or higher, each response with the
+ rcode of SERVFAIL is logged as follows:
+ </para>
+ <para>
+ <computeroutput>client 127.0.0.1#61502: query failed (SERVFAIL) for www.example.com/IN/AAAA at query.c:3880</computeroutput>
+ </para>
+ <para>
+ This means an error resulting in SERVFAIL was
+ detected at line 3880 of source file
+ <filename>query.c</filename>.
+ Log messages of this level will particularly
+ help identify the cause of SERVFAIL for an
+ authoritative server.
+ </para>
+ <para>
+ At the debug levels of 2 or higher, detailed context
+ information of recursive resolutions that resulted in
+ SERVFAIL is logged.
+ The log message will look like as follows:
+ </para>
+ <para>
+<!-- NOTE: newlines and some spaces added so this would fit on page -->
+ <programlisting>
+fetch completed at resolver.c:2970 for www.example.com/A
+in 30.000183: timed out/success [domain:example.com,
+referral:2,restart:7,qrysent:8,timeout:5,lame:0,neterr:0,
+badresp:1,adberr:0,findfail:0,valfail:0]
+ </programlisting>
+ </para>
+ <para>
+ The first part before the colon shows that a recursive
+ resolution for AAAA records of www.example.com completed
+ in 30.000183 seconds and the final result that led to the
+ SERVFAIL was determined at line 2970 of source file
+ <filename>resolver.c</filename>.
+ </para>
+ <para>
+ The following part shows the detected final result and the
+ latest result of DNSSEC validation.
+ The latter is always success when no validation attempt
+ is made.
+ In this example, this query resulted in SERVFAIL probably
+ because all name servers are down or unreachable, leading
+ to a timeout in 30 seconds.
+ DNSSEC validation was probably not attempted.
+ </para>
+ <para>
+ The last part enclosed in square brackets shows statistics
+ information collected for this particular resolution
+ attempt.
+ The <varname>domain</varname> field shows the deepest zone
+ that the resolver reached;
+ it is the zone where the error was finally detected.
+ The meaning of the other fields is summarized in the
+ following table.
+ </para>
+
+ <informaltable colsep="0" rowsep="0">
+ <tgroup cols="2" colsep="0" rowsep="0" tgroupstyle="4Level-table">
+ <colspec colname="1" colnum="1" colsep="0" colwidth="1.150in"/>
+ <colspec colname="2" colnum="2" colsep="0" colwidth="3.350in"/>
+ <tbody>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>referral</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ The number of referrals the resolver received
+ throughout the resolution process.
+ In the above example this is 2, which are most
+ likely com and example.com.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>restart</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ The number of cycles that the resolver tried
+ remote servers at the <varname>domain</varname>
+ zone.
+ In each cycle the resolver sends one query
+ (possibly resending it, depending on the response)
+ to each known name server of
+ the <varname>domain</varname> zone.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>qrysent</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ The number of queries the resolver sent at the
+ <varname>domain</varname> zone.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>timeout</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ The number of timeouts since the resolver
+ received the last response.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>lame</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ The number of lame servers the resolver detected
+ at the <varname>domain</varname> zone.
+ A server is detected to be lame either by an
+ invalid response or as a result of lookup in
+ BIND9's address database (ADB), where lame
+ servers are cached.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>neterr</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ The number of erroneous results that the
+ resolver encountered in sending queries
+ at the <varname>domain</varname> zone.
+ One common case is the remote server is
+ unreachable and the resolver receives an ICMP
+ unreachable error message.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>badresp</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ The number of unexpected responses (other than
+ <varname>lame</varname>) to queries sent by the
+ resolver at the <varname>domain</varname> zone.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>adberr</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ Failures in finding remote server addresses
+ of the <varname>domain</varname> zone in the ADB.
+ One common case of this is that the remote
+ server's name does not have any address records.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>findfail</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ Failures of resolving remote server addresses.
+ This is a total number of failures throughout
+ the resolution process.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><varname>valfail</varname></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ Failures of DNSSEC validation.
+ Validation failures are counted throughout
+ the resolution process (not limited to
+ the <varname>domain</varname> zone), but should
+ only happen in <varname>domain</varname>.
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ <para>
+ At the debug levels of 3 or higher, the same messages
+ as those at the debug 1 level are logged for other errors
+ than SERVFAIL.
+ Note that negative responses such as NXDOMAIN are not
+ regarded as errors here.
+ </para>
+ <para>
+ At the debug levels of 4 or higher, the same messages
+ as those at the debug 2 level are logged for other errors
+ than SERVFAIL.
+ Unlike the above case of level 3, messages are logged for
+ negative responses.
+ This is because any unexpected results can be difficult to
+ debug in the recursion case.
+ </para>
+ </sect3>
</sect2>
<sect2>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.284.18.93 2009/08/13 04:55:16 marka Exp $ */
+/* $Id: resolver.c,v 1.284.18.94 2009/09/24 21:38:51 jinmei Exp $ */
/*! \file */
fetchstate_done /*%< FETCHDONE events posted. */
} fetchstate;
+typedef enum {
+ badns_unreachable = 0,
+ badns_response,
+ badns_validation
+} badnstype_t;
+
struct fetchctx {
/*% Not locked. */
unsigned int magic;
* Number of queries that reference this context.
*/
unsigned int nqueries;
+
+ /*%
+ * Fetch-local statistics for detailed logging.
+ */
+ isc_result_t result; /*%< fetch result */
+ isc_result_t vresult; /*%< validation result */
+ int exitline;
+ isc_time_t start;
+ isc_uint64_t duration;
+ isc_boolean_t logged;
+ unsigned int querysent;
+ unsigned int referrals;
+ unsigned int lamecount;
+ unsigned int neterr;
+ unsigned int badresp;
+ unsigned int adberr;
+ unsigned int findfail;
+ unsigned int valfail;
isc_boolean_t timeout;
};
static void validated(isc_task_t *task, isc_event_t *event);
static void maybe_destroy(fetchctx_t *fctx);
static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
- isc_result_t reason);
+ isc_result_t reason, badnstype_t badtype);
static isc_result_t
valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
}
static inline void
-fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
+fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) {
dns_fetchevent_t *event, *next_event;
isc_task_t *task;
unsigned int count = 0;
isc_interval_t i;
isc_boolean_t logit = ISC_FALSE;
+ isc_time_t now;
unsigned int old_spillat;
unsigned int new_spillat = 0; /* initialized to silence compiler warnings */
FCTXTRACE("sendevents");
+ /*
+ * Keep some record of fetch result for logging later (if required).
+ */
+ fctx->result = result;
+ fctx->exitline = line;
+ TIME_NOW(&now);
+ fctx->duration = isc_time_microdiff(&now, &fctx->start);
+
for (event = ISC_LIST_HEAD(fctx->events);
event != NULL;
event = next_event) {
}
static void
-fctx_done(fetchctx_t *fctx, isc_result_t result) {
+fctx_done(fetchctx_t *fctx, isc_result_t result, int line) {
dns_resolver_t *res;
isc_boolean_t no_response;
+ REQUIRE(line >= 0);
+
FCTXTRACE("done");
res = fctx->res;
fctx->state = fetchstate_done;
fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
- fctx_sendevents(fctx, result);
+ fctx_sendevents(fctx, result, line);
UNLOCK(&res->buckets[fctx->bucketnum].lock);
}
/*
* No route to remote.
*/
- add_bad(fctx, query->addrinfo, sevent->result);
+ add_bad(fctx, query->addrinfo, sevent->result,
+ badns_unreachable);
fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
retry = ISC_TRUE;
break;
fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
result = fctx_stopidletimer(fctx);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
else
fctx_try(fctx);
}
if (result != ISC_R_SUCCESS)
goto cleanup_dispatch;
}
+ fctx->querysent++;
ISC_LIST_APPEND(fctx->queries, query, link);
query->fctx->nqueries++;
result = fctx_startidletimer(query->fctx, &interval);
if (result != ISC_R_SUCCESS) {
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
break;
}
/*
if (result != ISC_R_SUCCESS) {
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
}
break;
fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
result = fctx_stopidletimer(fctx);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
else
fctx_try(fctx);
}
fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
want_try = ISC_TRUE;
- else if (fctx->pending == 0) {
- /*
- * We've got nothing else to wait for and don't
- * know the answer. There's nothing to do but
- * fail the fctx.
- */
- want_done = ISC_TRUE;
+ else {
+ fctx->findfail++;
+ if (fctx->pending == 0) {
+ /*
+ * We've got nothing else to wait for and don't
+ * know the answer. There's nothing to do but
+ * fail the fctx.
+ */
+ want_done = ISC_TRUE;
+ }
}
} else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
if (want_try)
fctx_try(fctx);
else if (want_done)
- fctx_done(fctx, ISC_R_FAILURE);
+ fctx_done(fctx, ISC_R_FAILURE, __LINE__);
else if (bucket_empty)
empty_bucket(res);
}
}
static void
-add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) {
+add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason,
+ badnstype_t badtype)
+{
char namebuf[DNS_NAME_FORMATSIZE];
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
char classbuf[64];
const char *sep1, *sep2;
isc_sockaddr_t *address = &addrinfo->sockaddr;
+ if (reason == DNS_R_LAME)
+ fctx->lamecount++;
+ else {
+ switch (badtype) {
+ case badns_unreachable:
+ fctx->neterr++;
+ break;
+ case badns_response:
+ fctx->badresp++;
+ break;
+ case badns_validation:
+ break; /* counted as 'valfail' */
+ }
+ }
+
if (bad_server(fctx, address)) {
/*
* We already know this server is bad.
* XXXRTH Follow the CNAME/DNAME chain?
*/
dns_adb_destroyfind(&find);
+ fctx->adberr++;
}
} else if (!ISC_LIST_EMPTY(find->list)) {
/*
find->result_v4 != DNS_R_NXDOMAIN)))
*need_alternate = ISC_TRUE;
} else {
+ if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0)
+ fctx->lamecount++; /* cached lame server */
+ else
+ fctx->adberr++; /* unreachable server, etc. */
+
/*
* If we know there are no addresses for
* the family we are using then try to add
/*
* Something bad happened.
*/
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
return;
}
* might be bad ones. In this case, return SERVFAIL.
*/
if (addrinfo == NULL) {
- fctx_done(fctx, DNS_R_SERVFAIL);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
}
result = fctx_query(fctx, addrinfo, fctx->options);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
}
static isc_boolean_t
FCTXTRACE("timeout");
if (event->ev_type == ISC_TIMEREVENT_LIFE) {
- fctx_done(fctx, ISC_R_TIMEDOUT);
+ fctx_done(fctx, ISC_R_TIMEDOUT, __LINE__);
} else {
isc_result_t result;
*/
result = fctx_starttimer(fctx);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
else
/*
* Keep trying.
if (fctx->state != fetchstate_done) {
fctx->state = fetchstate_done;
- fctx_sendevents(fctx, ISC_R_CANCELED);
+ fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__);
}
if (fctx->references == 0 && fctx->pending == 0 &&
*/
fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
fctx->state = fetchstate_done;
- fctx_sendevents(fctx, ISC_R_CANCELED);
+ fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__);
/*
* Since we haven't started, we INSIST that we have no
* pending ADB finds and no pending validations.
*/
result = fctx_starttimer(fctx);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
else
fctx_try(fctx);
} else if (bucket_empty)
fctx->altfind = NULL;
fctx->pending = 0;
fctx->restarts = 0;
+ fctx->querysent = 0;
+ fctx->referrals = 0;
+ TIME_NOW(&fctx->start);
fctx->timeouts = 0;
+ fctx->lamecount = 0;
+ fctx->adberr = 0;
+ fctx->neterr = 0;
+ fctx->badresp = 0;
+ fctx->findfail = 0;
+ fctx->valfail = 0;
+ fctx->result = ISC_R_FAILURE;
+ fctx->vresult = ISC_R_SUCCESS;
+ fctx->exitline = -1; /* sentinel */
+ fctx->logged = ISC_FALSE;
fctx->attributes = 0;
fctx->spilled = ISC_FALSE;
fctx->nqueries = 0;
if (vevent->result != ISC_R_SUCCESS) {
FCTXTRACE("validation failed");
+ fctx->valfail++;
+ fctx->vresult = vevent->result;
result = ISC_R_NOTFOUND;
if (vevent->rdataset != NULL)
result = dns_db_findnode(fctx->cache, vevent->name,
if (result == ISC_R_SUCCESS)
dns_db_detachnode(fctx->cache, &node);
result = vevent->result;
- add_bad(fctx, addrinfo, result);
+ add_bad(fctx, addrinfo, result, badns_validation);
isc_event_free(&event);
UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
INSIST(fctx->validator == NULL);
if (fctx->validator != NULL) {
dns_validator_send(fctx->validator);
} else if (sentresponse)
- fctx_done(fctx, result); /* Locks bucket. */
+ fctx_done(fctx, result, __LINE__); /* Locks bucket. */
else
fctx_try(fctx); /* Locks bucket. */
return;
UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
- fctx_done(fctx, result); /* Locks bucket. */
+ fctx_done(fctx, result, __LINE__); /* Locks bucket. */
cleanup_event:
INSIST(node == NULL);
bucketnum = fctx->bucketnum;
if (fevent->result == ISC_R_CANCELED) {
dns_resolver_destroyfetch(&fctx->nsfetch);
- fctx_done(fctx, ISC_R_CANCELED);
+ fctx_done(fctx, ISC_R_CANCELED, __LINE__);
} else if (fevent->result == ISC_R_SUCCESS) {
FCTXTRACE("resuming DS lookup");
fctx->res->buckets[bucketnum].mctx,
&fctx->domain);
if (result != ISC_R_SUCCESS) {
- fctx_done(fctx, DNS_R_SERVFAIL);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
goto cleanup;
}
/*
domain = dns_fixedname_name(&fixed);
dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL);
if (dns_name_equal(&fctx->nsname, domain)) {
- fctx_done(fctx, DNS_R_SERVFAIL);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
dns_resolver_destroyfetch(&fctx->nsfetch);
goto cleanup;
}
&fctx->nsrrset, NULL,
&fctx->nsfetch);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
else {
LOCK(&res->buckets[bucketnum].lock);
locked = ISC_TRUE;
unsigned int options;
unsigned int findoptions;
isc_result_t broken_server;
+ badnstype_t broken_type = badns_response;
REQUIRE(VALID_QUERY(query));
fctx = query->fctx;
devent->result == ISC_R_CONNREFUSED ||
devent->result == ISC_R_CANCELED)) {
broken_server = devent->result;
+ broken_type = badns_unreachable;
}
}
goto done;
* has not experienced any restarts yet.
*/
fctx->restarts = 0;
+
+ /*
+ * Update local statistics counters collected for each
+ * new zone.
+ */
+ fctx->referrals++;
+ fctx->querysent = 0;
+ fctx->lamecount = 0;
+ fctx->neterr = 0;
+ fctx->badresp = 0;
+ fctx->adberr = 0;
+
result = ISC_R_SUCCESS;
} else if (result != ISC_R_SUCCESS) {
/*
* Add this server to the list of bad servers for
* this fctx.
*/
- add_bad(fctx, addrinfo, broken_server);
+ add_bad(fctx, addrinfo, broken_server, broken_type);
}
if (get_nameservers) {
dns_fixedname_init(&foundname);
fname = dns_fixedname_name(&foundname);
if (result != ISC_R_SUCCESS) {
- fctx_done(fctx, DNS_R_SERVFAIL);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
findoptions = 0;
NULL);
if (result != ISC_R_SUCCESS) {
FCTXTRACE("couldn't find a zonecut");
- fctx_done(fctx, DNS_R_SERVFAIL);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
if (!dns_name_issubdomain(fname, &fctx->domain)) {
* QDOMAIN.
*/
FCTXTRACE("nameservers now above QDOMAIN");
- fctx_done(fctx, DNS_R_SERVFAIL);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
dns_name_free(&fctx->domain,
fctx->res->buckets[fctx->bucketnum].mctx,
&fctx->domain);
if (result != ISC_R_SUCCESS) {
- fctx_done(fctx, DNS_R_SERVFAIL);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
fctx_cancelqueries(fctx, ISC_TRUE);
FCTXTRACE("resend");
result = fctx_query(fctx, addrinfo, options);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
} else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) {
/*
* All has gone well so far, but we are waiting for the
*/
result = fctx_stopidletimer(fctx);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
} else if (result == DNS_R_CHASEDSSERVERS) {
unsigned int n;
- add_bad(fctx, addrinfo, result);
+ add_bad(fctx, addrinfo, result, broken_type);
fctx_cancelqueries(fctx, ISC_TRUE);
fctx_cleanupfinds(fctx);
fctx_cleanupforwaddrs(fctx);
&fctx->nsrrset, NULL,
&fctx->nsfetch);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
fctx->references++;
UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
result = fctx_stopidletimer(fctx);
if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
} else {
/*
* We're done.
*/
- fctx_done(fctx, result);
+ fctx_done(fctx, result, __LINE__);
}
}
empty_bucket(res);
}
+void
+dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx,
+ isc_logcategory_t *category, isc_logmodule_t *module,
+ int level, isc_boolean_t duplicateok)
+{
+ fetchctx_t *fctx;
+ dns_resolver_t *res;
+ char domainbuf[DNS_NAME_FORMATSIZE];
+
+ REQUIRE(DNS_FETCH_VALID(fetch));
+ fctx = fetch->private;
+ REQUIRE(VALID_FCTX(fctx));
+ res = fctx->res;
+
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+
+ INSIST(fctx->exitline >= 0);
+ if (!fctx->logged || duplicateok) {
+ dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+ isc_log_write(lctx, category, module, level,
+ "fetch completed at %s:%d for %s in "
+ "%" ISC_PRINT_QUADFORMAT "u."
+ "%06" ISC_PRINT_QUADFORMAT "u: %s/%s "
+ "[domain:%s,referral:%u,restart:%u,qrysent:%u,"
+ "timeout:%u,lame:%u,neterr:%u,badresp:%u,"
+ "adberr:%u,findfail:%u,valfail:%u]",
+ __FILE__, fctx->exitline, fctx->info,
+ fctx->duration / 1000000,
+ fctx->duration % 1000000,
+ isc_result_totext(fctx->result),
+ isc_result_totext(fctx->vresult), domainbuf,
+ fctx->referrals, fctx->restarts,
+ fctx->querysent, fctx->timeouts, fctx->lamecount,
+ fctx->neterr, fctx->badresp, fctx->adberr,
+ fctx->findfail, fctx->valfail);
+ fctx->logged = ISC_TRUE;
+ }
+
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
+}
+
dns_dispatchmgr_t *
dns_resolver_dispatchmgr(dns_resolver_t *resolver) {
REQUIRE(VALID_RESOLVER(resolver));