Browse Source

Correctly handle NSEC and NSEC3 responses when answering with a
wildcard record. (Unit tests to follow in the morning.)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1474 e5f2f494-b856-4b98-b285-d166d9295462

Evan Hunt 15 years ago
parent
commit
1e1f5433fa
1 changed files with 34 additions and 10 deletions
  1. 34 10
      src/lib/auth/data_source.cc

+ 34 - 10
src/lib/auth/data_source.cc

@@ -344,7 +344,8 @@ getNsec3Param(Query& q, const DataSrc* ds, const Name& zonename) {
 }
 
 static inline DataSrc::Result
-proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds, const Name& zonename)
+proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds,
+        const Name& zonename, const bool wildcard)
 {
     Message& m = q.message();
     ConstNsec3ParamPtr nsec3 = getNsec3Param(q, ds, zonename);
@@ -382,8 +383,13 @@ proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds, const Name& zonename)
             }
         }
 
-        // Now add a covering NSEC3 for a wildcard under the
-        // closest provable enclosing name
+        // If we are processing a wildcard answer, we're done.
+        if (wildcard) {
+            return (DataSrc::SUCCESS);
+        }
+
+        // Otherwise, there is no wildcard record, so we must add a
+        // covering NSEC3 to prove that it doesn't exist.
         string hash3(nsec3->getHash(Name("*").concatenate(enclosure)));
         RETERR(getNsec3(ds, zonename, q.qclass(), hash3, rrset));
         if (hash3 != hash1 && hash3 != hash2) {
@@ -391,7 +397,7 @@ proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds, const Name& zonename)
         }
     } else {
         Name nsecname(task->qname);
-        if ((task->flags & DataSrc::NAME_NOT_FOUND) != 0) {
+        if ((task->flags & DataSrc::NAME_NOT_FOUND) != 0 || wildcard) {
             ds->findPreviousName(task->qname, nsecname, &zonename);
         }
 
@@ -402,6 +408,13 @@ proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds, const Name& zonename)
             return (DataSrc::SUCCESS);
         }
 
+        // If we are processing a wildcard answer, we're done.
+        if (wildcard) {
+            return (DataSrc::SUCCESS);
+        }
+
+        // Otherwise, there is no wildcard record, so we must add an
+        // NSEC for the zone to prove the wildcard doesn't exist.
         RETERR(addNSEC(q, task, zonename, zonename, ds));
     }
 
@@ -431,7 +444,7 @@ tryWildcard(Query& q, QueryTaskPtr task, const DataSrc* ds,
 
     RRsetList wild;
     const Name star("*");
-    uint32_t rflags = 0;
+    bool cname = false;
 
     for (int i = 1; i <= diff; ++i) {
         const Name& wname(star.concatenate(task->qname.split(i, nlen - i)));
@@ -439,12 +452,17 @@ tryWildcard(Query& q, QueryTaskPtr task, const DataSrc* ds,
                           QueryTask::AUTH_QUERY); 
         result = doQueryTask(ds, zonename, newtask, wild);
         if (result == DataSrc::SUCCESS) {
-            if (newtask.flags == 0 || (newtask.flags & DataSrc::CNAME_FOUND)) {
-                rflags = newtask.flags;
+            task->flags &= ~DataSrc::NAME_NOT_FOUND;
+            task->flags &= ~DataSrc::TYPE_NOT_FOUND;
+            if (newtask.flags == 0) {
                 found = true;
                 break;
+            } else if ((newtask.flags & DataSrc::CNAME_FOUND) != 0) {
+                task->flags |= DataSrc::CNAME_FOUND;
+                found = true;
+                cname = true;
+                break;
             } else if ((newtask.flags & DataSrc::TYPE_NOT_FOUND) != 0) {
-                task->flags &= ~DataSrc::NAME_NOT_FOUND;
                 task->flags |= DataSrc::TYPE_NOT_FOUND;
                 break;
             }
@@ -457,7 +475,13 @@ tryWildcard(Query& q, QueryTaskPtr task, const DataSrc* ds,
     // answer: if a CNAME, chase the target, otherwise
     // add authority.
     if (found) {
-        if ((rflags & DataSrc::CNAME_FOUND) != 0) {
+        result = proveNX(q, task, ds, *zonename, true);
+        if (result != DataSrc::SUCCESS) {
+            m.setRcode(Rcode::SERVFAIL());
+            return (DataSrc::ERROR);
+        }
+
+        if (cname) {
             RRsetPtr rrset = wild.findRRset(RRType::CNAME(), q.qclass());
             if (rrset != NULL) {
                 rrset->setName(task->qname);
@@ -688,7 +712,7 @@ DataSrc::doQuery(Query& q)
             }
 
             if (q.wantDnssec()) {
-                result = proveNX(q, task, datasource, *zonename);
+                result = proveNX(q, task, datasource, *zonename, false);
                 if (result != DataSrc::SUCCESS) {
                     m.setRcode(Rcode::SERVFAIL());
                     return;