ISC에서 2012년 4월 초에 릴리즈된 버전에 문제가 있다라고 합니다. 5월 중순에 문제를 해결한 버전을 다시 릴리즈를 한다라고 합니다.
https://lists.isc.org/pipermail/bind-announce/2012-April/000772.html
관심이 있는 분야라서 소스를 확인해봤습니다. 패치가 나오면 제가 예상 했던 부분과 비교를 해봐야 할것 같네요.
[stone@localhost ~]$ diff -Nur bind-9.7.4-P1/lib/dns/resolver.c bind-9.7.5/lib/dns/resolver.c --- bind-9.7.4-P1/lib/dns/resolver.c 2011-06-09 08:15:43.000000000 +0900 +++ bind-9.7.5/lib/dns/resolver.c 2012-03-23 04:14:04.000000000 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2012 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.413.14.17 2011-06-08 23:15:43 each Exp $ */ +/* $Id$ */ /*! \file */ @@ -208,6 +208,8 @@ ISC_LIST(dns_validator_t) validators; dns_db_t * cache; dns_adb_t * adb; + isc_boolean_t ns_ttl_ok; + isc_uint32_t ns_ttl; /*% * The number of events we're waiting for. @@ -444,7 +446,7 @@ dns_rdataset_t *ardataset, isc_result_t *eresultp); static void validated(isc_task_t *task, isc_event_t *event); -static void maybe_destroy(fetchctx_t *fctx); +static isc_boolean_t maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked); static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, badnstype_t badtype); @@ -737,8 +739,11 @@ INSIST(query->tcpsocket == NULL); query->fctx->nqueries--; - if (SHUTTINGDOWN(query->fctx)) - maybe_destroy(query->fctx); /* Locks bucket. */ + if (SHUTTINGDOWN(query->fctx)) { + dns_resolver_t *res = query->fctx->res; + if (maybe_destroy(query->fctx, ISC_FALSE)) + empty_bucket(res); + } query->magic = 0; isc_mem_put(query->mctx, query, sizeof(*query)); *queryp = NULL; @@ -1553,9 +1558,11 @@ dns_dispatch_detach(&query->dispatch); cleanup_query: - query->magic = 0; - isc_mem_put(res->buckets[fctx->bucketnum].mctx, - query, sizeof(*query)); + if (query->connects == 0) { + query->magic = 0; + isc_mem_put(res->buckets[fctx->bucketnum].mctx, + query, sizeof(*query)); + } stop_idle_timer: RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS); @@ -1673,6 +1680,7 @@ dns_compress_t cctx; isc_boolean_t cleanup_cctx = ISC_FALSE; isc_boolean_t secure_domain; + isc_boolean_t connecting = ISC_FALSE; fctx = query->fctx; QTRACE("send"); @@ -1963,6 +1971,7 @@ query); if (result != ISC_R_SUCCESS) goto cleanup_message; + connecting = ISC_TRUE; query->connects++; } } @@ -1974,8 +1983,19 @@ */ result = isc_socket_sendto(socket, &r, task, resquery_senddone, query, address, NULL); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + if (connecting) { + /* + * This query is still connecting. + * Mark it as canceled so that it will just be + * cleaned up when the connected event is received. + * Keep fctx around until the event is processed. + */ + query->fctx->nqueries++; + query->attributes |= RESQUERY_ATTR_CANCELED; + } goto cleanup_message; + } query->sends++; @@ -2137,6 +2157,7 @@ isc_boolean_t want_try = ISC_FALSE; isc_boolean_t want_done = ISC_FALSE; isc_boolean_t bucket_empty = ISC_FALSE; + isc_boolean_t destroy = ISC_FALSE; unsigned int bucketnum; find = event->ev_sender; @@ -2148,6 +2169,9 @@ FCTXTRACE("finddone"); + bucketnum = fctx->bucketnum; + LOCK(&res->buckets[bucketnum].lock); + INSIST(fctx->pending > 0); fctx->pending--; @@ -2172,17 +2196,17 @@ } } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 && fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { - bucketnum = fctx->bucketnum; - LOCK(&res->buckets[bucketnum].lock); /* * Note that we had to wait until we had the lock before * looking at fctx->references. */ if (fctx->references == 0) - bucket_empty = fctx_destroy(fctx); - UNLOCK(&res->buckets[bucketnum].lock); + destroy = ISC_TRUE; } + UNLOCK(&res->buckets[bucketnum].lock); + if (destroy) + bucket_empty = fctx_destroy(fctx); isc_event_free(&event); dns_adb_destroyfind(&find); @@ -3476,6 +3500,20 @@ return (ISC_R_SUCCESS); } +static inline void +log_ns_ttl(fetchctx_t *fctx, const char *where) { + char namebuf[DNS_NAME_FORMATSIZE]; + char domainbuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10), + "log_ns_ttl: fctx %p: %s: %s (in '%s'?): %u %u", + fctx, where, namebuf, domainbuf, + fctx->ns_ttl_ok, fctx->ns_ttl); +} + static isc_result_t fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_name_t *domain, dns_rdataset_t *nameservers, @@ -3569,6 +3607,8 @@ fctx->timeout = ISC_FALSE; fctx->addrinfo = NULL; fctx->client = NULL; + fctx->ns_ttl = 0; + fctx->ns_ttl_ok = ISC_FALSE; dns_name_init(&fctx->nsname, NULL); fctx->nsfetch = NULL; @@ -3618,6 +3658,8 @@ dns_rdataset_disassociate(&fctx->nameservers); goto cleanup_name; } + fctx->ns_ttl = fctx->nameservers.ttl; + fctx->ns_ttl_ok = ISC_TRUE; } else { /* * We're in forward-only mode. Set the query domain. @@ -3635,8 +3677,12 @@ if (result != ISC_R_SUCCESS) goto cleanup_name; dns_rdataset_clone(nameservers, &fctx->nameservers); + fctx->ns_ttl = fctx->nameservers.ttl; + fctx->ns_ttl_ok = ISC_TRUE; } + log_ns_ttl(fctx, "fctx_create"); + INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain)); fctx->qmessage = NULL; @@ -3929,14 +3975,16 @@ /* * Destroy '*fctx' if it is ready to be destroyed (i.e., if it has - * no references and is no longer waiting for any events). If this - * was the last fctx in the resolver, destroy the resolver. + * no references and is no longer waiting for any events). * * Requires: * '*fctx' is shutting down. + * + * Returns: + * true if the resolver is exiting and this is the last fctx in the bucket. */ -static void -maybe_destroy(fetchctx_t *fctx) { +static isc_boolean_t +maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked) { unsigned int bucketnum; isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res = fctx->res; @@ -3944,8 +3992,11 @@ REQUIRE(SHUTTINGDOWN(fctx)); + bucketnum = fctx->bucketnum; + if (!locked) + LOCK(&res->buckets[bucketnum].lock); if (fctx->pending != 0 || fctx->nqueries != 0) - return; + goto unlock; for (validator = ISC_LIST_HEAD(fctx->validators); validator != NULL; validator = next_validator) { @@ -3953,14 +4004,12 @@ dns_validator_cancel(validator); } - bucketnum = fctx->bucketnum; - LOCK(&res->buckets[bucketnum].lock); if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) bucket_empty = fctx_destroy(fctx); - UNLOCK(&res->buckets[bucketnum].lock); - - if (bucket_empty) - empty_bucket(res); + unlock: + if (!locked) + UNLOCK(&res->buckets[bucketnum].lock); + return (bucket_empty); } /* @@ -3968,31 +4017,33 @@ */ static void validated(isc_task_t *task, isc_event_t *event) { - isc_result_t result = ISC_R_SUCCESS; - isc_result_t eresult = ISC_R_SUCCESS; - isc_stdtime_t now; - fetchctx_t *fctx; - dns_validatorevent_t *vevent; - dns_fetchevent_t *hevent; - dns_rdataset_t *ardataset = NULL; - dns_rdataset_t *asigrdataset = NULL; + dns_adbaddrinfo_t *addrinfo; dns_dbnode_t *node = NULL; - isc_boolean_t negative; - isc_boolean_t chaining; - isc_boolean_t sentresponse; - isc_uint32_t ttl; dns_dbnode_t *nsnode = NULL; + dns_fetchevent_t *hevent; dns_name_t *name; + dns_rdataset_t *ardataset = NULL; + dns_rdataset_t *asigrdataset = NULL; dns_rdataset_t *rdataset; dns_rdataset_t *sigrdataset; + dns_resolver_t *res; dns_valarg_t *valarg; - dns_adbaddrinfo_t *addrinfo; + dns_validatorevent_t *vevent; + fetchctx_t *fctx; + isc_boolean_t chaining; + isc_boolean_t negative; + isc_boolean_t sentresponse; + isc_result_t eresult = ISC_R_SUCCESS; + isc_result_t result = ISC_R_SUCCESS; + isc_stdtime_t now; + isc_uint32_t ttl; UNUSED(task); /* for now */ REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE); valarg = event->ev_arg; fctx = valarg->fctx; + res = fctx->res; addrinfo = valarg->addrinfo; REQUIRE(VALID_FCTX(fctx)); REQUIRE(!ISC_LIST_EMPTY(fctx->validators)); @@ -4002,6 +4053,8 @@ FCTXTRACE("received validation completion event"); + LOCK(&res->buckets[fctx->bucketnum].lock); + ISC_LIST_UNLINK(fctx->validators, vevent->validator, link); fctx->validator = NULL; @@ -4010,7 +4063,7 @@ * destroy the fctx if necessary. */ dns_validator_destroy(&vevent->validator); - isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx, + isc_mem_put(res->buckets[fctx->bucketnum].mctx, valarg, sizeof(*valarg)); negative = ISC_TF(vevent->rdataset == NULL); @@ -4023,12 +4076,15 @@ * so, destroy the fctx. */ if (SHUTTINGDOWN(fctx) && !sentresponse) { - maybe_destroy(fctx); /* Locks bucket. */ + isc_uint32_t bucketnum = fctx->bucketnum; + isc_boolean_t bucket_empty; + bucket_empty = maybe_destroy(fctx, ISC_TRUE); + UNLOCK(&res->buckets[bucketnum].lock); + if (bucket_empty) + empty_bucket(res); goto cleanup_event; } - LOCK(&fctx->res->buckets[fctx->bucketnum].lock); - isc_stdtime_get(&now); /* @@ -4074,7 +4130,7 @@ if (vevent->result != ISC_R_SUCCESS) { FCTXTRACE("validation failed"); - inc_stats(fctx->res, dns_resstatscounter_valfail); + inc_stats(res, dns_resstatscounter_valfail); fctx->valfail++; fctx->vresult = vevent->result; if (fctx->vresult != DNS_R_BROKENCHAIN) { @@ -4123,7 +4179,7 @@ result = fctx->vresult; add_bad(fctx, addrinfo, result, badns_validation); isc_event_free(&event); - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + UNLOCK(&res->buckets[fctx->bucketnum].lock); INSIST(fctx->validator == NULL); fctx->validator = ISC_LIST_HEAD(fctx->validators); if (fctx->validator != NULL) @@ -4142,8 +4198,7 @@ fctx->type == dns_rdatatype_dlv || fctx->type == dns_rdatatype_ds) && tresult == ISC_R_SUCCESS) - dns_resolver_addbadcache(fctx->res, - &fctx->name, + dns_resolver_addbadcache(res, &fctx->name, fctx->type, &expire); fctx_done(fctx, result, __LINE__); /* Locks bucket. */ } else @@ -4156,7 +4211,7 @@ dns_rdatatype_t covers; FCTXTRACE("nonexistence validation OK"); - inc_stats(fctx->res, dns_resstatscounter_valnegsuccess); + inc_stats(res, dns_resstatscounter_valnegsuccess); if (fctx->rmessage->rcode == dns_rcode_nxdomain) covers = dns_rdatatype_any; @@ -4173,10 +4228,9 @@ * to zero to facilitate locating the containing zone of * a arbitrary zone. */ - ttl = fctx->res->view->maxncachettl; + ttl = res->view->maxncachettl; if (fctx->type == dns_rdatatype_soa && - covers == dns_rdatatype_any && - fctx->res->zero_no_soa_ttl) + covers == dns_rdatatype_any && res->zero_no_soa_ttl) ttl = 0; result = ncache_adderesult(fctx->rmessage, fctx->cache, node, @@ -4186,7 +4240,7 @@ goto noanswer_response; goto answer_response; } else - inc_stats(fctx->res, dns_resstatscounter_valsuccess); + inc_stats(res, dns_resstatscounter_valsuccess); FCTXTRACE("validation OK"); @@ -4234,14 +4288,17 @@ } if (sentresponse) { + isc_boolean_t bucket_empty = ISC_FALSE; /* * 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. */ + bucket_empty = maybe_destroy(fctx, ISC_TRUE); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + if (bucket_empty) + empty_bucket(res); goto cleanup_event; } @@ -4256,7 +4313,7 @@ * be validated. */ dns_db_detachnode(fctx->cache, &node); - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + UNLOCK(&res->buckets[fctx->bucketnum].lock); dns_validator_send(ISC_LIST_HEAD(fctx->validators)); goto cleanup_event; } @@ -4331,8 +4388,7 @@ if (node != NULL) dns_db_detachnode(fctx->cache, &node); - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); - + UNLOCK(&res->buckets[fctx->bucketnum].lock); fctx_done(fctx, result, __LINE__); /* Locks bucket. */ cleanup_event: @@ -5303,6 +5359,26 @@ return (ISC_TRUE); } +static void +trim_ns_ttl(fetchctx_t *fctx, dns_name_t *name, dns_rdataset_t *rdataset) { + char ns_namebuf[DNS_NAME_FORMATSIZE]; + char namebuf[DNS_NAME_FORMATSIZE]; + char tbuf[DNS_RDATATYPE_FORMATSIZE]; + + if (fctx->ns_ttl_ok && rdataset->ttl > fctx->ns_ttl) { + dns_name_format(name, ns_namebuf, sizeof(ns_namebuf)); + dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); + dns_rdatatype_format(fctx->type, tbuf, sizeof(tbuf)); + + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10), + "fctx %p: trimming ttl of %s/NS for %s/%s: " + "%u -> %u", fctx, ns_namebuf, namebuf, tbuf, + rdataset->ttl, fctx->ns_ttl); + rdataset->ttl = fctx->ns_ttl; + } +} + /* * Handle a no-answer response (NXDOMAIN, NXRRSET, or referral). * If look_in_options has LOOK_FOR_NS_IN_ANSWER then we look in the answer @@ -5473,6 +5549,9 @@ if (aa) rdataset->trust = dns_trust_authauthority; + else if (ISFORWARDER(fctx->addrinfo)) + rdataset->trust = + dns_trust_answer; else rdataset->trust = dns_trust_additional; @@ -5486,6 +5565,12 @@ return (result); } + log_ns_ttl(fctx, "noanswer_response"); + + if (ns_rdataset != NULL && dns_name_equal(&fctx->domain, ns_name) && + !dns_name_equal(ns_name, dns_rootname)) + trim_ns_ttl(fctx, ns_name, ns_rdataset); + /* * A negative response has a SOA record (Type 2) * and a optional NS RRset (Type 1) or it has neither @@ -5526,6 +5611,9 @@ if (aa) rdataset->trust = dns_trust_authauthority; + else if (ISFORWARDER(fctx->addrinfo)) + rdataset->trust = + dns_trust_answer; else rdataset->trust = dns_trust_additional; @@ -5567,6 +5655,9 @@ if (aa) rdataset->trust = dns_trust_authauthority; + else if (ISFORWARDER(fctx->addrinfo)) + rdataset->trust = + dns_trust_answer; else rdataset->trust = dns_trust_additional; @@ -5698,6 +5789,8 @@ if (result != ISC_R_SUCCESS) return (result); fctx->attributes |= FCTX_ATTR_WANTCACHE; + fctx->ns_ttl_ok = ISC_FALSE; + log_ns_ttl(fctx, "DELEGATION"); return (DNS_R_DELEGATION); } @@ -5718,8 +5811,8 @@ answer_response(fetchctx_t *fctx) { isc_result_t result; dns_message_t *message; - dns_name_t *name, *qname, tname; - dns_rdataset_t *rdataset; + dns_name_t *name, *qname, tname, *ns_name; + dns_rdataset_t *rdataset, *ns_rdataset; isc_boolean_t done, external, chaining, aa, found, want_chaining; isc_boolean_t have_answer, found_cname, found_type, wanted_chaining; unsigned int aflag; @@ -6119,6 +6212,8 @@ * in this section, and we expect that it is not external. */ done = ISC_FALSE; + ns_name = NULL; + ns_rdataset = NULL; result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (!done && result == ISC_R_SUCCESS) { name = NULL; @@ -6146,6 +6241,10 @@ rdataset->trust = dns_trust_additional; + if (rdataset->type == dns_rdatatype_ns) { + ns_name = name; + ns_rdataset = rdataset; + } /* * Mark any additional data related * to this rdataset. @@ -6163,6 +6262,12 @@ if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; + log_ns_ttl(fctx, "answer_response"); + + if (ns_rdataset != NULL && dns_name_equal(&fctx->domain, ns_name) && + !dns_name_equal(ns_name, dns_rootname)) + trim_ns_ttl(fctx, ns_name, ns_rdataset); + return (result); } @@ -6234,6 +6339,9 @@ if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); dns_rdataset_clone(fevent->rdataset, &fctx->nameservers); + fctx->ns_ttl = fctx->nameservers.ttl; + fctx->ns_ttl_ok = ISC_TRUE; + log_ns_ttl(fctx, "resume_dslookup"); dns_name_free(&fctx->domain, fctx->res->buckets[bucketnum].mctx); dns_name_init(&fctx->domain, NULL); @@ -7167,6 +7275,8 @@ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } + fctx->ns_ttl = fctx->nameservers.ttl; + fctx->ns_ttl_ok = ISC_TRUE; fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupaltfinds(fctx); |