Browse Source

[1177] Empty non-terminal case

Michal 'vorner' Vaner 13 years ago
parent
commit
cb4d844364
2 changed files with 68 additions and 23 deletions
  1. 29 22
      src/lib/datasrc/database.cc
  2. 39 1
      src/lib/datasrc/tests/database_unittest.cc

+ 29 - 22
src/lib/datasrc/database.cc

@@ -318,6 +318,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
     bool records_found = false;
     bool glue_ok(options & FIND_GLUE_OK);
     bool dnssec_data(options & FIND_DNSSEC);
+    bool get_cover(false);
     isc::dns::RRsetPtr result_rrset;
     ZoneFinder::Result result_status = SUCCESS;
     FoundRRsets found;
@@ -430,6 +431,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
                           DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL).
                     arg(accessor_->getDBName()).arg(name);
                 records_found = true;
+                get_cover = dnssec_data;
             } else {
                 // It's not empty non-terminal. So check for wildcards.
                 // We remove labels one by one and look for the wildcard there.
@@ -521,6 +523,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
                     } else if (hasSubdomains(wildcard.toText())) {
                         // Empty non-terminal asterisk
                         records_found = true;
+                        get_cover = dnssec_data;
                         LOG_DEBUG(logger, DBG_TRACE_DETAILED,
                                   DATASRC_DATABASE_WILDCARD_EMPTY).
                             arg(accessor_->getDBName()).arg(wildcard).
@@ -531,28 +534,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
                 // This is the NXDOMAIN case (nothing found anywhere). If
                 // they wand DNSSEC data, try getting the NSEC record
                 if (dnssec_data && !records_found) {
-                    try {
-                        // Which one should contain the NSEC record?
-                        const Name coverName(findPreviousName(name));
-                        // Get the record and copy it out
-                        found = getRRsets(coverName, nsec_types, true);
-                        const FoundIterator
-                            nci(found.second.find(RRType::NSEC()));
-                        if (nci != found.second.end()) {
-                            result_status = NXDOMAIN;
-                            result_rrset = nci->second;
-                        } else {
-                            // The previous doesn't contain NSEC, bug?
-                            isc_throw(DataSourceError, "No NSEC in " +
-                                      coverName.toText() + ", but it was "
-                                      "returned as previous - "
-                                      "accessor error?");
-                        }
-                    }
-                    catch (const isc::NotImplemented&) {
-                        // Well, they want DNSSEC, but there is no available.
-                        // So we don't provide anything.
-                    }
+                    get_cover = true;
                 }
             }
         } else if (dnssec_data) {
@@ -569,6 +551,31 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
 
     if (!result_rrset) {
         if (result_status == SUCCESS) {
+            // Should we look for NSEC covering the name?
+            if (get_cover) {
+                try {
+                    // Which one should contain the NSEC record?
+                    const Name coverName(findPreviousName(name));
+                    // Get the record and copy it out
+                    found = getRRsets(coverName, nsec_types, true);
+                    const FoundIterator
+                        nci(found.second.find(RRType::NSEC()));
+                    if (nci != found.second.end()) {
+                        result_status = NXDOMAIN;
+                        result_rrset = nci->second;
+                    } else {
+                        // The previous doesn't contain NSEC, bug?
+                        isc_throw(DataSourceError, "No NSEC in " +
+                                  coverName.toText() + ", but it was "
+                                  "returned as previous - "
+                                  "accessor error?");
+                    }
+                }
+                catch (const isc::NotImplemented&) {
+                    // Well, they want DNSSEC, but there is no available.
+                    // So we don't provide anything.
+                }
+            }
             // Something is not here and we didn't decide yet what
             if (records_found) {
                 logger.debug(DBG_TRACE_DETAILED,

+ 39 - 1
src/lib/datasrc/tests/database_unittest.cc

@@ -173,6 +173,9 @@ const char* const TEST_RECORDS[][5] = {
     {"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},
     // For finding previous, this one is the last one in the zone
     {"zzz.example.org.", "NSEC", "3600", "", "example.org NSEC"},
+    // For NSEC empty non-terminal
+    {"l.example.org.", "NSEC", "3600", "", "empty.nonterminal.example.org. NSEC"},
+    {"empty.nonterminal.example.org.", "A", "3600", "", "192.0.2.1"},
 
     {NULL, NULL, NULL, NULL, NULL},
 };
@@ -549,10 +552,13 @@ public:
         } else if (id == 42) {
             if (rname == "org.example.") {
                 return ("zzz.example.org.");
+            } else if (rname == "org.example.nonterminal.") {
+                return ("l.example.org.");
             } else if (rname == "org.example.www2." ||
                        rname == "org.example.www1.") {
                 return ("www.example.org.");
-            } else if (rname == "org.example.notimplnsec.") {
+            } else if (rname == "org.example.notimplnsec." ||
+                       rname == "org.example.wild.here.") {
                 isc_throw(isc::NotImplemented, "Not implemented in this test");
             } else {
                 isc_throw(isc::Unexpected, "Unexpected name");
@@ -1645,6 +1651,38 @@ TYPED_TEST(DatabaseClientTest, NXDOMAIN_NSEC) {
                                Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
 }
 
+TYPED_TEST(DatabaseClientTest, emptyNonterminalNSEC) {
+    // Same as NXDOMAIN_NSEC, but with empty non-terminal
+    //
+    // FIXME: Is the nonexistence of this node really the correct proof
+    // we need?
+    shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+
+    this->expected_rdatas_.push_back("empty.nonterminal.example.org. NSEC");
+    doFindTest(*finder, isc::dns::Name("nonterminal.example.org."),
+               isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::NXRRSET, // FIXME: Do we want to have specific code?
+               this->expected_rdatas_, this->expected_sig_rdatas_,
+               Name("l.example.org."), ZoneFinder::FIND_DNSSEC);
+
+    // Check that if the DB doesn't support it, the exception from there
+    // is not propagated and it only does not include the NSEC
+    if (!this->is_mock_) {
+        return; // We don't make the real DB to throw
+    }
+    this->expected_rdatas_.clear();
+    this->expected_sig_rdatas_.clear();
+    EXPECT_NO_THROW(doFindTest(*finder,
+                               isc::dns::Name("here.wild.example.org."),
+                               isc::dns::RRType::TXT(),
+                               isc::dns::RRType::NSEC(),
+                               isc::dns::RRTTL(3600), ZoneFinder::NXRRSET,
+                               this->expected_rdatas_,
+                               this->expected_sig_rdatas_,
+                               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
+}
+
 TYPED_TEST(DatabaseClientTest, getOrigin) {
     DataSourceClient::FindResult
         zone(this->client_->findZone(Name("example.org")));