summaryrefslogtreecommitdiffstats
path: root/lib/dns/resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/resolver.c')
-rw-r--r--lib/dns/resolver.c115
1 files changed, 83 insertions, 32 deletions
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 8803a05..290bb0f 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.384.14.20.10.3 2010/06/23 23:46:25 tbox Exp $ */
+/* $Id: resolver.c,v 1.384.14.30 2011-01-27 23:45:47 tbox Exp $ */
/*! \file */
@@ -203,6 +203,7 @@ struct fetchctx {
isc_sockaddrlist_t bad;
isc_sockaddrlist_t edns;
isc_sockaddrlist_t edns512;
+ isc_sockaddrlist_t bad_edns;
dns_validator_t *validator;
ISC_LIST(dns_validator_t) validators;
dns_db_t * cache;
@@ -482,7 +483,7 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
inc_stats(fctx->res, dns_resstatscounter_val);
if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
INSIST(fctx->validator == NULL);
- fctx->validator = validator;
+ fctx->validator = validator;
}
ISC_LIST_APPEND(fctx->validators, validator, link);
} else
@@ -1559,6 +1560,36 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
}
static isc_boolean_t
+bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ isc_sockaddr_t *sa;
+
+ for (sa = ISC_LIST_HEAD(fctx->bad_edns);
+ sa != NULL;
+ sa = ISC_LIST_NEXT(sa, link)) {
+ if (isc_sockaddr_equal(sa, address))
+ return (ISC_TRUE);
+ }
+
+ return (ISC_FALSE);
+}
+
+static void
+add_bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ isc_sockaddr_t *sa;
+
+ if (bad_edns(fctx, address))
+ return;
+
+ sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+ sizeof(*sa));
+ if (sa == NULL)
+ return;
+
+ *sa = *address;
+ ISC_LIST_INITANDAPPEND(fctx->bad_edns, sa, link);
+}
+
+static isc_boolean_t
triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
isc_sockaddr_t *sa;
@@ -3131,6 +3162,14 @@ fctx_destroy(fetchctx_t *fctx) {
isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
}
+ for (sa = ISC_LIST_HEAD(fctx->bad_edns);
+ sa != NULL;
+ sa = next_sa) {
+ next_sa = ISC_LIST_NEXT(sa, link);
+ ISC_LIST_UNLINK(fctx->bad_edns, sa, link);
+ isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+ }
+
isc_timer_detach(&fctx->timer);
dns_message_destroy(&fctx->rmessage);
dns_message_destroy(&fctx->qmessage);
@@ -3501,6 +3540,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
ISC_LIST_INIT(fctx->bad);
ISC_LIST_INIT(fctx->edns);
ISC_LIST_INIT(fctx->edns512);
+ ISC_LIST_INIT(fctx->bad_edns);
ISC_LIST_INIT(fctx->validators);
fctx->validator = NULL;
fctx->find = NULL;
@@ -3870,14 +3910,6 @@ maybe_destroy(fetchctx_t *fctx) {
validator != NULL; validator = next_validator) {
next_validator = ISC_LIST_NEXT(validator, link);
dns_validator_cancel(validator);
- /*
- * If this is a active validator wait for the cancel
- * to complete before calling dns_validator_destroy().
- */
- if (validator == fctx->validator)
- continue;
- ISC_LIST_UNLINK(fctx->validators, validator, link);
- dns_validator_destroy(&validator);
}
bucketnum = fctx->bucketnum;
@@ -6115,6 +6147,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
unsigned int findoptions;
isc_result_t broken_server;
badnstype_t broken_type = badns_response;
+ isc_boolean_t no_response;
REQUIRE(VALID_QUERY(query));
fctx = query->fctx;
@@ -6137,6 +6170,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
resend = ISC_FALSE;
truncated = ISC_FALSE;
finish = NULL;
+ no_response = ISC_FALSE;
if (fctx->res->exiting) {
result = ISC_R_SHUTTINGDOWN;
@@ -6184,7 +6218,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
/*
* If this is a network error on an exclusive query
* socket, mark the server as bad so that we won't try
- * it for this fetch again.
+ * it for this fetch again. Also adjust finish and
+ * no_response so that we penalize this address in SRTT
+ * adjustment later.
*/
if (query->exclusivesocket &&
(devent->result == ISC_R_HOSTUNREACH ||
@@ -6193,6 +6229,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
devent->result == ISC_R_CANCELED)) {
broken_server = devent->result;
broken_type = badns_unreachable;
+ finish = NULL;
+ no_response = ISC_TRUE;
}
}
goto done;
@@ -6324,6 +6362,25 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
* ensured by the dispatch code).
*/
+ /*
+ * We have an affirmative response to the query and we have
+ * previously got a response from this server which indicated
+ * EDNS may not be supported so we can now cache the lack of
+ * EDNS support.
+ */
+ if (opt == NULL &&
+ (message->rcode == dns_rcode_noerror ||
+ message->rcode == dns_rcode_nxdomain ||
+ message->rcode == dns_rcode_refused ||
+ message->rcode == dns_rcode_yxdomain) &&
+ bad_edns(fctx, &query->addrinfo->sockaddr)) {
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
+ sizeof(addrbuf));
+ dns_adb_changeflags(fctx->adb, query->addrinfo,
+ DNS_FETCHOPT_NOEDNS0,
+ DNS_FETCHOPT_NOEDNS0);
+ }
/*
* Deal with truncated responses by retrying using TCP.
@@ -6379,9 +6436,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
if (message->rcode != dns_rcode_noerror &&
message->rcode != dns_rcode_nxdomain) {
if (((message->rcode == dns_rcode_formerr ||
- message->rcode == dns_rcode_notimp) ||
- (message->rcode == dns_rcode_servfail &&
- dns_message_getopt(message) == NULL)) &&
+ message->rcode == dns_rcode_notimp) ||
+ (message->rcode == dns_rcode_servfail &&
+ dns_message_getopt(message) == NULL)) &&
(query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
/*
* It's very likely they don't like EDNS0.
@@ -6397,12 +6454,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
options |= DNS_FETCHOPT_NOEDNS0;
resend = ISC_TRUE;
/*
- * Remember that they don't like EDNS0.
+ * Remember that they may not like EDNS0.
*/
- if (message->rcode != dns_rcode_servfail)
- dns_adb_changeflags(fctx->adb, query->addrinfo,
- DNS_FETCHOPT_NOEDNS0,
- DNS_FETCHOPT_NOEDNS0);
+ add_bad_edns(fctx, &query->addrinfo->sockaddr);
inc_stats(fctx->res, dns_resstatscounter_edns0fail);
} else if (message->rcode == dns_rcode_formerr) {
if (ISFORWARDER(query->addrinfo)) {
@@ -6666,7 +6720,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*
* XXXRTH Don't cancel the query if waiting for validation?
*/
- fctx_cancelquery(&query, &devent, finish, ISC_FALSE);
+ fctx_cancelquery(&query, &devent, finish, no_response);
if (keep_trying) {
if (result == DNS_R_FORMERR)
@@ -7389,6 +7443,13 @@ static inline isc_boolean_t
fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
unsigned int options)
{
+ /*
+ * Don't match fetch contexts that are shutting down.
+ */
+ if (fctx->cloned || fctx->state == fetchstate_done ||
+ ISC_LIST_EMPTY(fctx->events))
+ return (ISC_FALSE);
+
if (fctx->type != type || fctx->options != options)
return (ISC_FALSE);
return (dns_name_equal(&fctx->name, name));
@@ -7523,17 +7584,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
}
}
- /*
- * If we didn't have a fetch, would attach to a done fetch, this
- * fetch has already cloned its results, or if the fetch has gone
- * "idle" (no one was interested in it), we need to start a new
- * fetch instead of joining with the existing one.
- */
- if (fctx == NULL ||
- fctx->state == fetchstate_done ||
- fctx->cloned ||
- ISC_LIST_EMPTY(fctx->events)) {
- fctx = NULL;
+ if (fctx == NULL) {
result = fctx_create(res, name, type, domain, nameservers,
options, bucketnum, &fctx);
if (result != ISC_R_SUCCESS)
OpenPOWER on IntegriCloud