]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1410. [func] handle records that live in the parent zone, e.g. DS.
authorMark Andrews <marka@isc.org>
Tue, 14 Jan 2003 00:28:50 +0000 (00:28 +0000)
committerMark Andrews <marka@isc.org>
Tue, 14 Jan 2003 00:28:50 +0000 (00:28 +0000)
developer: marka
reviewer: explorer

CHANGES
bin/named/query.c
lib/dns/include/dns/result.h
lib/dns/resolver.c
lib/dns/result.c

diff --git a/CHANGES b/CHANGES
index 10da04fe70228457e987f6756942828efea35a32..2b697f3d4b7d492a0a3f2ad57f6d3e23cd445fa9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+1410.  [func]          handle records that live in the parent zone, e.g. DS.
+
 1409.  [bug]           DS should have attibute DNS_RDATATYPEATTR_DNSSEC.
 
 1408.  [bug]           distclean was not complete. [RT #4700]
index 82b6da79301d7b754f092274e941f3a83845fbd8..4b7caaebccaa8c860766d6650f3ec02e787781ed 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: query.c,v 1.238 2002/11/27 09:52:45 marka Exp $ */
+/* $Id: query.c,v 1.239 2003/01/14 00:28:49 marka Exp $ */
 
 #include <config.h>
 
@@ -88,6 +88,7 @@
 
 #define DNS_GETDB_NOEXACT 0x01U
 #define DNS_GETDB_NOLOG 0x02U
+#define DNS_GETDB_PARTIAL 0x04U
 
 static void
 query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
@@ -544,6 +545,7 @@ query_getzonedb(ns_client_t *client, dns_name_t *name, unsigned int options,
        unsigned int ztoptions;
        dns_zone_t *zone = NULL;
        dns_db_t *db = NULL;
+       isc_boolean_t partial = ISC_FALSE;
 
        REQUIRE(zonep != NULL && *zonep == NULL);
        REQUIRE(dbp != NULL && *dbp == NULL);
@@ -556,6 +558,8 @@ query_getzonedb(ns_client_t *client, dns_name_t *name, unsigned int options,
 
        result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
                             &zone);
+       if (result == DNS_R_PARTIALMATCH)
+               partial = ISC_TRUE;
        if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
                result = dns_zone_getdb(zone, &db);
 
@@ -687,6 +691,8 @@ query_getzonedb(ns_client_t *client, dns_name_t *name, unsigned int options,
        *dbp = db;
        *versionp = dbversion->version;
 
+       if (partial && (options & DNS_GETDB_PARTIAL) != 0)
+               return (DNS_R_PARTIALMATCH);
        return (ISC_R_SUCCESS);
 
  refuse:
@@ -2266,6 +2272,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
        version = NULL;
        zone = NULL;
        need_wildcardproof = ISC_FALSE;
+       options = 0;
 
        if (event != NULL) {
                /*
@@ -2340,6 +2347,39 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                options |= DNS_GETDB_NOEXACT;
        result = query_getdb(client, client->query.qname, options, &zone, &db,
                             &version, &is_zone);
+       if ((result != ISC_R_SUCCESS || !is_zone) && !RECURSIONOK(client) &&
+           (options & DNS_GETDB_NOEXACT) != 0 && qtype == dns_rdatatype_ds) {
+               /*
+                * Look to see if we are authoritative for the
+                * child zone if the query type is DS.
+                */
+               dns_db_t *tdb = NULL;
+               dns_zone_t *tzone = NULL;
+               dns_dbversion_t *tversion = NULL;
+               isc_result_t tresult;
+
+               tresult = query_getzonedb(client, client->query.qname,
+                                        DNS_GETDB_PARTIAL, &tzone, &tdb,
+                                        &tversion);
+               if (tresult == ISC_R_SUCCESS) {
+                       options &= ~DNS_GETDB_NOEXACT;
+                       query_putrdataset(client, &rdataset);
+                       if (db != NULL)
+                               dns_db_detach(&db);
+                       if (zone != NULL)
+                               dns_zone_detach(&zone);
+                       version = tversion;
+                       db = tdb;
+                       zone = tzone;
+                       is_zone = ISC_TRUE;
+                       result = ISC_R_SUCCESS;
+               } else {
+                       if (tdb != NULL)
+                               dns_db_detach(&tdb);
+                       if (tzone != NULL)
+                               dns_zone_detach(&tzone);
+               }
+       }
        if (result != ISC_R_SUCCESS) {
                if (result == DNS_R_REFUSED)
                        QUERY_ERROR(DNS_R_REFUSED);
@@ -2466,6 +2506,47 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
        case DNS_R_DELEGATION:
                authoritative = ISC_FALSE;
                if (is_zone) {
+                       /*
+                        * Look to see if we are authoritative for the
+                        * child zone if the query type is DS.
+                        */
+                       if (!RECURSIONOK(client) &&
+                           (options & DNS_GETDB_NOEXACT) != 0 &&
+                           qtype == dns_rdatatype_ds) {
+                               dns_db_t *tdb = NULL;
+                               dns_zone_t *tzone = NULL;
+                               dns_dbversion_t *tversion = NULL;
+                               result = query_getzonedb(client,
+                                                        client->query.qname,
+                                                        DNS_GETDB_PARTIAL,
+                                                        &tzone, &tdb,
+                                                        &tversion);
+                               if (result == ISC_R_SUCCESS) {
+                                       options &= ~DNS_GETDB_NOEXACT;
+                                       query_putrdataset(client, &rdataset);
+                                       if (sigrdataset != NULL)
+                                               query_putrdataset(client,
+                                                                 &sigrdataset);
+                                       if (fname != NULL)
+                                               query_releasename(client,
+                                                                 &fname);
+                                       if (node != NULL)
+                                               dns_db_detachnode(db, &node);
+                                       if (db != NULL)
+                                               dns_db_detach(&db);
+                                       if (zone != NULL)
+                                               dns_zone_detach(&zone);
+                                       version = tversion;
+                                       db = tdb;
+                                       zone = tzone;
+                                       authoritative = ISC_TRUE;
+                                       goto db_find;
+                               }
+                               if (tdb != NULL)
+                                       dns_db_detach(&tdb);
+                               if (tzone != NULL)
+                                       dns_zone_detach(&tzone);
+                       }
                        /*
                         * We're authoritative for an ancestor of QNAME.
                         */
index 31aa1daf5fb3fe514fc1e3ac7cfcee57ef71eed7..c706360ce45152db1d964ac1afe59cca06157a7d 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.94 2002/08/27 04:53:43 marka Exp $ */
+/* $Id: result.h,v 1.95 2003/01/14 00:28:50 marka Exp $ */
 
 #ifndef DNS_RESULT_H
 #define DNS_RESULT_H 1
 #define DNS_R_LAME                     (ISC_RESULTCLASS_DNS + 88)
 #define DNS_R_UNEXPECTEDRCODE          (ISC_RESULTCLASS_DNS + 89)
 #define DNS_R_UNEXPECTEDOPCODE         (ISC_RESULTCLASS_DNS + 90)
+#define DNS_R_CHASEDSSERVERS           (ISC_RESULTCLASS_DNS + 91)
 
-#define DNS_R_NRESULTS                 91      /* Number of results */
+#define DNS_R_NRESULTS                 92      /* Number of results */
 
 /*
  * DNS wire format rcodes.
index fdc009daa161a21ffe5f90c00ef0ad9364867e49..d9f61016c0f5cf804de9f68f35364a8b82841d61 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.c,v 1.256 2003/01/05 23:19:29 marka Exp $ */
+/* $Id: resolver.c,v 1.257 2003/01/14 00:28:49 marka Exp $ */
 
 #include <config.h>
 
@@ -199,6 +199,12 @@ struct fetchctx {
         * is used for EDNS0 black hole detection.
         */
        unsigned int                    timeouts;
+       /*
+        * Look aside state for DS lookups.
+        */
+       dns_name_t                      nsname; 
+       dns_fetch_t *                   nsfetch;
+       dns_rdataset_t                  nsrrset;
 };
 
 #define FCTX_MAGIC                     ISC_MAGIC('F', '!', '!', '!')
@@ -2024,6 +2030,9 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
                dns_validator_cancel(validator);
                validator = ISC_LIST_NEXT(validator, link);
        }
+       
+       if (fctx->nsfetch != NULL)
+               dns_resolver_cancelfetch(fctx->nsfetch);
 
        /*
         * Shut down anything that is still running on behalf of this
@@ -2234,6 +2243,10 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
        fctx->timeouts = 0;
        fctx->attributes = 0;
 
+       dns_name_init(&fctx->nsname, NULL);
+        fctx->nsfetch = NULL;
+        dns_rdataset_init(&fctx->nsrrset);
+
        if (domain == NULL) {
                dns_forwarders_t *forwarders = NULL;
                result = dns_fwdtable_find(fctx->res->view->fwdtable,
@@ -3710,6 +3723,15 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
                        return (result);
        }
 
+       /*
+        * Trigger lookups for DNS nameservers.
+        */
+       if (negative_response && message->rcode == dns_rcode_noerror &&
+           fctx->type == dns_rdatatype_ds && soa_name != NULL &&
+           dns_name_equal(soa_name, qname) &&
+           !dns_name_equal(qname, dns_rootname))
+               return (DNS_R_CHASEDSSERVERS);
+
        /*
         * Did we find anything?
         */
@@ -4211,6 +4233,98 @@ answer_response(fetchctx_t *fctx) {
        return (result);
 }
 
+static void
+resume_dslookup(isc_task_t *task, isc_event_t *event) {
+       dns_fetchevent_t *fevent;
+       dns_resolver_t *res;
+       fetchctx_t *fctx;
+       isc_result_t result;
+       isc_boolean_t bucket_empty = ISC_FALSE;
+       isc_boolean_t locked = ISC_FALSE;
+
+       REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+       fevent = (dns_fetchevent_t *)event;
+       fctx = event->ev_arg;
+       REQUIRE(VALID_FCTX(fctx));
+       res = fctx->res;
+
+       UNUSED(task);
+       FCTXTRACE("resume_dslookup");
+
+       if (fevent->node != NULL)
+               dns_db_detachnode(fevent->db, &fevent->node);
+       if (fevent->db != NULL)
+               dns_db_detach(&fevent->db);
+
+       dns_resolver_destroyfetch(&fctx->nsfetch);
+
+       if (fevent->result == ISC_R_CANCELED)
+               fctx_done(fctx, ISC_R_CANCELED);
+       else if (fevent->result == ISC_R_SUCCESS) {
+
+               FCTXTRACE("resuming DS lookup");
+
+               if (dns_rdataset_isassociated(&fctx->nameservers))
+                       dns_rdataset_disassociate(&fctx->nameservers);
+               dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
+               dns_name_free(&fctx->domain, fctx->res->mctx);
+               dns_name_init(&fctx->domain, NULL);
+               result = dns_name_dup(&fctx->nsname, fctx->res->mctx,
+                                     &fctx->domain);
+               if (result != ISC_R_SUCCESS) {
+                       fctx_done(fctx, DNS_R_SERVFAIL);
+                       goto cleanup;
+               }
+               /*
+                * Try again.
+                */
+               fctx_try(fctx);
+       } else {
+               unsigned int n;
+
+               n = dns_name_countlabels(&fctx->nsname);
+               dns_name_getlabelsequence(&fctx->nsname, 1, n - 1,
+                                         &fctx->nsname);
+
+               if (dns_name_equal(&fctx->nsname, &fctx->domain)) {
+                       fctx_done(fctx, DNS_R_SERVFAIL);
+                       goto cleanup;
+               }
+               if (dns_rdataset_isassociated(fevent->rdataset))
+                       dns_rdataset_disassociate(fevent->rdataset);
+               FCTXTRACE("continuing to look for parent's NS records");
+               result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+                                                 dns_rdatatype_ns,
+                                                 &fctx->domain,
+                                                 &fctx->nameservers, NULL,
+                                                 0, task,
+                                                 resume_dslookup, fctx,
+                                                 &fctx->nsrrset, NULL,
+                                                 &fctx->nsfetch);
+               if (result != ISC_R_SUCCESS)
+                       fctx_done(fctx, result);
+               else {
+                       LOCK(&res->buckets[fctx->bucketnum].lock);
+                       locked = ISC_TRUE;
+                       fctx->references++;
+               }
+       }
+
+ cleanup:
+       if (dns_rdataset_isassociated(fevent->rdataset))
+               dns_rdataset_disassociate(fevent->rdataset);
+       INSIST(fevent->sigrdataset == NULL);
+       isc_event_free(&event);
+       if (!locked)
+               LOCK(&res->buckets[fctx->bucketnum].lock);
+       fctx->references--;
+       if (fctx->references == 0)
+               bucket_empty = fctx_destroy(fctx);
+       UNLOCK(&res->buckets[fctx->bucketnum].lock);
+       if (bucket_empty)
+               empty_bucket(res);
+}
+
 static void
 resquery_response(isc_task_t *task, isc_event_t *event) {
        isc_result_t result = ISC_R_SUCCESS;
@@ -4235,7 +4349,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
        REQUIRE(VALID_FCTX(fctx));
        REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
 
-       UNUSED(task);
        QTRACE("response");
 
        (void)isc_timer_touch(fctx->timer);
@@ -4569,7 +4682,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
                 * NXDOMAIN, NXRDATASET, or referral.
                 */
                result = noanswer_response(fctx, NULL, ISC_FALSE);
-               if (result == DNS_R_DELEGATION) {
+               if (result == DNS_R_CHASEDSSERVERS) {
+               } else if (result == DNS_R_DELEGATION) {
                force_referral:
                        /*
                         * We don't have the answer, but we know a better
@@ -4728,6 +4842,34 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
                result = fctx_stopidletimer(fctx);
                if (result != ISC_R_SUCCESS)
                        fctx_done(fctx, result);
+       } else if (result == DNS_R_CHASEDSSERVERS) {
+               unsigned int n;
+               add_bad(fctx, &addrinfo->sockaddr, result);
+               fctx_cancelqueries(fctx, ISC_TRUE);
+               fctx_cleanupfinds(fctx);
+               fctx_cleanupforwaddrs(fctx);
+
+               n = dns_name_countlabels(&fctx->name);
+               dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname);
+
+               FCTXTRACE("suspending DS lookup to find parent's NS records");
+
+               result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+                                                 dns_rdatatype_ns,
+                                                 &fctx->domain,
+                                                 &fctx->nameservers, NULL,
+                                                 0, task,
+                                                 resume_dslookup, fctx,
+                                                 &fctx->nsrrset, NULL,
+                                                 &fctx->nsfetch);
+               if (result != ISC_R_SUCCESS)
+                       fctx_done(fctx, result);
+               LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+               fctx->references++;
+               UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+               result = fctx_stopidletimer(fctx);
+               if (result != ISC_R_SUCCESS)
+                       fctx_done(fctx, result);
        } else {
                /*
                 * We're done.
index 1242f216a1920ac7fa773412b8c18b98b64e99de..4d2afb16ddf2c28336dcb31e2a342a821ac3e11f 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.c,v 1.104 2002/08/27 04:53:43 marka Exp $ */
+/* $Id: result.c,v 1.105 2003/01/14 00:28:49 marka Exp $ */
 
 #include <config.h>
 
@@ -137,7 +137,9 @@ static const char *text[DNS_R_NRESULTS] = {
        "truncated TCP response",              /* 87 DNS_R_TRUNCATEDTCP      */
        "lame server detected",                /* 88 DNS_R_LAME              */
        "unexpected RCODE",                    /* 89 DNS_R_UNEXPECTEDRCODE   */
-       "unexpected OPCODE"                    /* 90 DNS_R_UNEXPECTEDOPCODE  */
+
+       "unexpected OPCODE",                   /* 90 DNS_R_UNEXPECTEDOPCODE  */
+       "chase DS servers"                     /* 91 DNS_R_CHASEDSSERVERS    */
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {