May 012012
 

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);
Plugin from the creators of Brindes :: More at Plulz Wordpress Plugins