diff options
Diffstat (limited to 'lib/dns/resolver.c')
-rw-r--r-- | lib/dns/resolver.c | 115 |
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) |