diff options
Diffstat (limited to 'contrib/bind9/lib/dns/resolver.c')
-rw-r--r-- | contrib/bind9/lib/dns/resolver.c | 147 |
1 files changed, 107 insertions, 40 deletions
diff --git a/contrib/bind9/lib/dns/resolver.c b/contrib/bind9/lib/dns/resolver.c index 7312841..5b57005 100644 --- a/contrib/bind9/lib/dns/resolver.c +++ b/contrib/bind9/lib/dns/resolver.c @@ -2,7 +2,7 @@ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.284.18.57 2007/02/14 23:41:01 marka Exp $ */ +/* $Id: resolver.c,v 1.284.18.66 2007/11/01 13:53:27 shane Exp $ */ /*! \file */ @@ -192,6 +192,7 @@ struct fetchctx { isc_sockaddrlist_t bad; isc_sockaddrlist_t edns; isc_sockaddrlist_t edns512; + dns_validator_t *validator; ISC_LIST(dns_validator_t) validators; dns_db_t * cache; dns_adb_t * adb; @@ -250,7 +251,7 @@ struct fetchctx { #define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \ 0) #define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \ - != 0) + != 0) #define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0) #define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0) #define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0) @@ -353,6 +354,8 @@ struct dns_resolver { #define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) +#define dns_db_transfernode(a,b,c) do { (*c) = (*b); (*b) = NULL; } while (0) + static void destroy(dns_resolver_t *res); static void empty_bucket(dns_resolver_t *res); static isc_result_t resquery_send(resquery_t *query); @@ -394,9 +397,13 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, sigrdataset, fctx->rmessage, valoptions, task, validated, valarg, &validator); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { + if ((valoptions & DNS_VALIDATOR_DEFER) == 0) { + INSIST(fctx->validator == NULL); + fctx->validator = validator; + } ISC_LIST_APPEND(fctx->validators, validator, link); - else + } else isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx, valarg, sizeof(*valarg)); return (result); @@ -793,6 +800,15 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) { fctx->type == dns_rdatatype_any || fctx->type == dns_rdatatype_rrsig || fctx->type == dns_rdatatype_sig); + + /* + * Negative results must be indicated in event->result. + */ + if (dns_rdataset_isassociated(event->rdataset) && + event->rdataset->type == dns_rdatatype_none) { + INSIST(event->result == DNS_R_NCACHENXDOMAIN || + event->result == DNS_R_NCACHENXRRSET); + } isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event)); count++; @@ -802,17 +818,17 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) { fctx->spilled && (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) { LOCK(&fctx->res->lock); - if (count == fctx->res->spillat && !fctx->res->exiting) { + if (count == fctx->res->spillat && !fctx->res->exiting) { fctx->res->spillat += 5; if (fctx->res->spillat > fctx->res->spillatmax && fctx->res->spillatmax != 0) fctx->res->spillat = fctx->res->spillatmax; + logit = ISC_TRUE; isc_interval_set(&i, 20 * 60, 0); result = isc_timer_reset(fctx->res->spillattimer, isc_timertype_ticker, NULL, &i, ISC_TRUE); RUNTIME_CHECK(result == ISC_R_SUCCESS); - logit = ISC_TRUE; } UNLOCK(&fctx->res->lock); if (logit) @@ -1067,7 +1083,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_netaddr_t dstip; isc_netaddr_fromsockaddr(&dstip, &addrinfo->sockaddr); result = dns_peerlist_peerbyaddr(res->view->peers, - &dstip, &peer); + &dstip, &peer); if (result == ISC_R_SUCCESS) { result = dns_peer_getquerysource(peer, &addr); if (result == ISC_R_SUCCESS) @@ -1433,7 +1449,7 @@ resquery_send(resquery_t *query) { FCTXTRACE("too many timeouts, disabling EDNS0"); } else if ((triededns(fctx, &query->addrinfo->sockaddr) || fctx->timeouts >= MAX_EDNS0_TIMEOUTS) && - (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { + (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { query->options |= DNS_FETCHOPT_EDNS512; FCTXTRACE("too many timeouts, setting EDNS size to 512"); } @@ -1841,7 +1857,7 @@ mark_bad(fetchctx_t *fctx) { } static void -add_bad(fetchctx_t *fctx, isc_sockaddr_t *address, isc_result_t reason) { +add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) { char namebuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; char classbuf[64]; @@ -1850,6 +1866,7 @@ add_bad(fetchctx_t *fctx, isc_sockaddr_t *address, isc_result_t reason) { isc_buffer_t b; isc_sockaddr_t *sa; const char *sep1, *sep2; + isc_sockaddr_t *address = &addrinfo->sockaddr; if (bad_server(fctx, address)) { /* @@ -1870,6 +1887,11 @@ add_bad(fetchctx_t *fctx, isc_sockaddr_t *address, isc_result_t reason) { if (reason == DNS_R_LAME) /* already logged */ return; + if (reason == DNS_R_UNEXPECTEDRCODE && + fctx->rmessage->opcode == dns_rcode_servfail && + ISFORWARDER(addrinfo)) + return; + if (reason == DNS_R_UNEXPECTEDRCODE) { isc_buffer_init(&b, code, sizeof(code) - 1); dns_rcode_totext(fctx->rmessage->rcode, &b); @@ -2957,6 +2979,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, ISC_LIST_INIT(fctx->edns); ISC_LIST_INIT(fctx->edns512); ISC_LIST_INIT(fctx->validators); + fctx->validator = NULL; fctx->find = NULL; fctx->altfind = NULL; fctx->pending = 0; @@ -3166,7 +3189,7 @@ is_lame(fetchctx_t *fctx) { if (rdataset->type != dns_rdatatype_ns) continue; namereln = dns_name_fullcompare(name, &fctx->domain, - &order, &labels); + &order, &labels); if (namereln == dns_namereln_equal && (message->flags & DNS_MESSAGEFLAG_AA) != 0) return (ISC_FALSE); @@ -3295,7 +3318,7 @@ maybe_destroy(fetchctx_t *fctx) { unsigned int bucketnum; isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res = fctx->res; - dns_validator_t *validator; + dns_validator_t *validator, *next_validator; REQUIRE(SHUTTINGDOWN(fctx)); @@ -3303,16 +3326,22 @@ maybe_destroy(fetchctx_t *fctx) { return; for (validator = ISC_LIST_HEAD(fctx->validators); - validator != NULL; - validator = ISC_LIST_HEAD(fctx->validators)) { - ISC_LIST_UNLINK(fctx->validators, validator, link); + 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; LOCK(&res->buckets[bucketnum].lock); - if (fctx->references == 0) + if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) bucket_empty = fctx_destroy(fctx); UNLOCK(&res->buckets[bucketnum].lock); @@ -3359,6 +3388,7 @@ validated(isc_task_t *task, isc_event_t *event) { FCTXTRACE("received validation completion event"); ISC_LIST_UNLINK(fctx->validators, vevent->validator, link); + fctx->validator = NULL; /* * Destroy the validator early so that we can @@ -3441,12 +3471,14 @@ validated(isc_task_t *task, isc_event_t *event) { if (result == ISC_R_SUCCESS) dns_db_detachnode(fctx->cache, &node); result = vevent->result; - add_bad(fctx, &addrinfo->sockaddr, result); + add_bad(fctx, addrinfo, result); isc_event_free(&event); UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); - if (!ISC_LIST_EMPTY(fctx->validators)) - dns_validator_send(ISC_LIST_HEAD(fctx->validators)); - else if (sentresponse) + INSIST(fctx->validator == NULL); + fctx->validator = ISC_LIST_HEAD(fctx->validators); + if (fctx->validator != NULL) { + dns_validator_send(fctx->validator); + } else if (sentresponse) fctx_done(fctx, result); /* Locks bucket. */ else fctx_try(fctx); /* Locks bucket. */ @@ -3514,7 +3546,12 @@ validated(isc_task_t *task, isc_event_t *event) { if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) goto noanswer_response; - if (vevent->sigrdataset != NULL) { + if (ardataset != NULL && ardataset->type == 0) { + if (NXDOMAIN(ardataset)) + eresult = DNS_R_NCACHENXDOMAIN; + else + eresult = DNS_R_NCACHENXRRSET; + } else if (vevent->sigrdataset != NULL) { result = dns_db_addrdataset(fctx->cache, node, NULL, now, vevent->sigrdataset, 0, asigrdataset); @@ -3528,6 +3565,7 @@ validated(isc_task_t *task, isc_event_t *event) { * If we only deferred the destroy because we wanted to cache * the data, destroy now. */ + dns_db_detachnode(fctx->cache, &node); UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); if (SHUTTINGDOWN(fctx)) maybe_destroy(fctx); /* Locks bucket. */ @@ -3544,6 +3582,7 @@ validated(isc_task_t *task, isc_event_t *event) { * more rdatasets that still need to * be validated. */ + dns_db_detachnode(fctx->cache, &node); UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); dns_validator_send(ISC_LIST_HEAD(fctx->validators)); goto cleanup_event; @@ -3609,8 +3648,7 @@ validated(isc_task_t *task, isc_event_t *event) { dns_fixedname_name(&hevent->foundname), NULL) == ISC_R_SUCCESS); dns_db_attach(fctx->cache, &hevent->db); - hevent->node = node; - node = NULL; + dns_db_transfernode(fctx->cache, &node, &hevent->node); clone_results(fctx); } @@ -3623,12 +3661,14 @@ validated(isc_task_t *task, isc_event_t *event) { fctx_done(fctx, result); /* Locks bucket. */ cleanup_event: + INSIST(node == NULL); isc_event_free(&event); } static inline isc_result_t cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, - isc_stdtime_t now) { + isc_stdtime_t now) +{ dns_rdataset_t *rdataset, *sigrdataset; dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset; dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL; @@ -3742,8 +3782,10 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, fail ? "failure" : "warning", namebuf, typebuf, classbuf); if (fail) { - if (ANSWER(rdataset)) + if (ANSWER(rdataset)) { + dns_db_detachnode(fctx->cache, &node); return (DNS_R_BADNAME); + } continue; } } @@ -3808,8 +3850,29 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, result = dns_db_addrdataset(fctx->cache, node, NULL, now, rdataset, 0, addedrdataset); - if (result == DNS_R_UNCHANGED) + if (result == DNS_R_UNCHANGED) { result = ISC_R_SUCCESS; + if (!need_validation && + ardataset != NULL && + ardataset->type == 0) { + /* + * The answer in the cache is better + * than the answer we found, and is + * a negative cache entry, so we + * must set eresult appropriately. + */ + if (NXDOMAIN(ardataset)) + eresult = DNS_R_NCACHENXDOMAIN; + else + eresult = DNS_R_NCACHENXRRSET; + /* + * We have a negative response from + * the cache so don't attempt to + * add the RRSIG rrset. + */ + continue; + } + } if (result != ISC_R_SUCCESS) break; if (sigrdataset != NULL) { @@ -3926,12 +3989,10 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, * a negative cache entry, so we * must set eresult appropriately. */ - if (NXDOMAIN(ardataset)) - eresult = - DNS_R_NCACHENXDOMAIN; - else - eresult = - DNS_R_NCACHENXRRSET; + if (NXDOMAIN(ardataset)) + eresult = DNS_R_NCACHENXDOMAIN; + else + eresult = DNS_R_NCACHENXRRSET; } result = ISC_R_SUCCESS; } else if (result != ISC_R_SUCCESS) @@ -3942,15 +4003,22 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, if (valrdataset != NULL) result = valcreate(fctx, addrinfo, name, fctx->type, valrdataset, valsigrdataset, valoptions, - task); + task); if (result == ISC_R_SUCCESS && have_answer) { fctx->attributes |= FCTX_ATTR_HAVEANSWER; if (event != NULL) { + /* + * Negative results must be indicated in event->result. + */ + if (dns_rdataset_isassociated(event->rdataset) && + event->rdataset->type == dns_rdatatype_none) { + INSIST(eresult == DNS_R_NCACHENXDOMAIN || + eresult == DNS_R_NCACHENXRRSET); + } event->result = eresult; dns_db_attach(fctx->cache, adbp); - *anodep = node; - node = NULL; + dns_db_transfernode(fctx->cache, &node, anodep); clone_results(fctx); } } @@ -4190,8 +4258,7 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if (event != NULL) { event->result = eresult; dns_db_attach(fctx->cache, adbp); - *anodep = node; - node = NULL; + dns_db_transfernode(fctx->cache, &node, anodep); clone_results(fctx); } } @@ -5830,7 +5897,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * Add this server to the list of bad servers for * this fctx. */ - add_bad(fctx, &addrinfo->sockaddr, broken_server); + add_bad(fctx, addrinfo, broken_server); } if (get_nameservers) { @@ -5912,7 +5979,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { fctx_done(fctx, result); } else if (result == DNS_R_CHASEDSSERVERS) { unsigned int n; - add_bad(fctx, &addrinfo->sockaddr, result); + add_bad(fctx, addrinfo, result); fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupforwaddrs(fctx); @@ -7024,7 +7091,7 @@ static isc_boolean_t yes = ISC_TRUE, no = ISC_FALSE; isc_result_t dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name, - isc_boolean_t value) + isc_boolean_t value) { isc_result_t result; |