Browse Source

[1063] Implement the delegations

Michal 'vorner' Vaner 13 years ago
parent
commit
c5cf3cc081
3 changed files with 84 additions and 19 deletions
  1. 69 10
      src/lib/datasrc/database.cc
  2. 5 2
      src/lib/datasrc/database.h
  3. 10 7
      src/lib/datasrc/tests/database_unittest.cc

+ 69 - 10
src/lib/datasrc/database.cc

@@ -164,7 +164,9 @@ private:
 
 std::pair<bool, isc::dns::RRsetPtr>
 DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
-                                 const isc::dns::RRType& type)
+                                 const isc::dns::RRType* type,
+                                 bool want_cname, bool want_dname,
+                                 bool want_ns)
 {
     RRsigStore sig_store;
     database_->searchForRecords(zone_id_, name.toText());
@@ -194,16 +196,21 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
             // of the 'type covered' field in the RRSIG Rdata).
             //cur_sigtype(columns[SIGTYPE_COLUMN]);
 
-            if (cur_type == type) {
+            if (type != NULL && cur_type == *type) {
                 if (result_rrset &&
                     result_rrset->getType() == isc::dns::RRType::CNAME()) {
                     isc_throw(DataSourceError, "CNAME found but it is not "
                               "the only record for " + name.toText());
+                } else if (result_rrset && want_ns &&
+                           result_rrset->getType() == isc::dns::RRType::NS()) {
+                    // In case there's a NS, we should find the delegation, not
+                    // the data
+                    continue;
                 }
                 addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
                             columns[DatabaseAccessor::RDATA_COLUMN],
                             *database_);
-            } else if (cur_type == isc::dns::RRType::CNAME()) {
+            } else if (want_cname && cur_type == isc::dns::RRType::CNAME()) {
                 // There should be no other data, so result_rrset should
                 // be empty.
                 if (result_rrset) {
@@ -213,6 +220,26 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
                 addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
                             columns[DatabaseAccessor::RDATA_COLUMN],
                             *database_);
+            } else if (want_ns && cur_type == isc::dns::RRType::NS()) {
+                if (result_rrset &&
+                    // In case we already found some data here, we should
+                    // replace it with the NS, we should delegate
+                    result_rrset->getType() != isc::dns::RRType::NS()) {
+                    result_rrset = isc::dns::RRsetPtr();
+                }
+                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                            columns[DatabaseAccessor::RDATA_COLUMN],
+                            *database_);
+            } else if (want_dname && cur_type == isc::dns::RRType::DNAME()) {
+                // There should be max one RR of DNAME present
+                if (result_rrset &&
+                    result_rrset->getType() == isc::dns::RRType::DNAME()) {
+                    isc_throw(DataSourceError, "DNAME with multiple RRs in " +
+                              name.toText());
+                }
+                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                            columns[DatabaseAccessor::RDATA_COLUMN],
+                            *database_);
             } else if (cur_type == isc::dns::RRType::RRSIG()) {
                 // If we get signatures before we get the actual data, we
                 // can't know which ones to keep and which to drop...
@@ -256,19 +283,51 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
     bool records_found = false;
     isc::dns::RRsetPtr result_rrset;
     ZoneFinder::Result result_status = SUCCESS;
+    std::pair<bool, isc::dns::RRsetPtr> found;
     logger.debug(DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
         .arg(database_->getDBName()).arg(name).arg(type);
 
     try {
         // First, do we have any kind of delegation (NS/DNAME) here?
+        Name origin(getOrigin());
+        size_t originLabelCount(origin.getLabelCount());
+        size_t currentLabelCount(name.getLabelCount());
+        // This is how many labels we remove to get origin
+        size_t removeLabels(currentLabelCount - originLabelCount);
+        // Now go trough all superdomains from origin down
+        for (int i(removeLabels); i > 0; -- i) {
+            Name superdomain(name.split(i));
+            // Look if there's NS or DNAME (but ignore the NS in origin)
+            found = getRRset(superdomain, NULL, false, true,
+                             i != removeLabels);
+            if (found.second) {
+                // We found something redirecting somewhere else
+                // (it can be only NS or DNAME here)
+                result_rrset = found.second;
+                if (result_rrset->getType() == isc::dns::RRType::NS()) {
+                    result_status = DELEGATION;
+                } else {
+                    result_status = DNAME;
+                }
+                // Don't search more
+                break;
+            }
+        }
 
-        // Try getting the final result and extract it
-        std::pair<bool, isc::dns::RRsetPtr> found(getRRset(name, type));
-        records_found = found.first;
-        result_rrset = found.second;
-        if (result_rrset && type != isc::dns::RRType::CNAME() &&
-            result_rrset->getType() == isc::dns::RRType::CNAME()) {
-            result_status = CNAME;
+        if (!result_rrset) { // Only if we didn't find a redirect already
+            // Try getting the final result and extract it
+            // It is special if there's a CNAME or NS, DNAME is ignored here
+            // And we don't consider the NS in origin
+            found = getRRset(name, &type, true, false, name != origin);
+            records_found = found.first;
+            result_rrset = found.second;
+            if (result_rrset && type != isc::dns::RRType::NS() &&
+                result_rrset->getType() == isc::dns::RRType::NS()) {
+                result_status = DELEGATION;
+            } else if (result_rrset && type != isc::dns::RRType::CNAME() &&
+                       result_rrset->getType() == isc::dns::RRType::CNAME()) {
+                result_status = CNAME;
+            }
         }
     } catch (const DataSourceError& dse) {
         logger.error(DATASRC_DATABASE_FIND_ERROR)

+ 5 - 2
src/lib/datasrc/database.h

@@ -293,8 +293,11 @@ public:
         /// \brief Searches database for an RRset
         std::pair<bool, isc::dns::RRsetPtr> getRRset(const isc::dns::Name&
                                                      name,
-                                                     const isc::dns::RRType&
-                                                     type);
+                                                     const isc::dns::RRType*
+                                                     type,
+                                                     bool want_cname,
+                                                     bool want_dname,
+                                                     bool want_ns);
     };
     /**
      * \brief Find a zone in the database

+ 10 - 7
src/lib/datasrc/tests/database_unittest.cc

@@ -370,14 +370,17 @@ doFindTest(shared_ptr<DatabaseClient::Finder> finder,
            const isc::dns::RRTTL expected_ttl,
            ZoneFinder::Result expected_result,
            const std::vector<std::string>& expected_rdatas,
-           const std::vector<std::string>& expected_sig_rdatas)
+           const std::vector<std::string>& expected_sig_rdatas,
+           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME())
 {
+    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
     ZoneFinder::FindResult result =
         finder->find(name, type, NULL, ZoneFinder::FIND_DEFAULT);
     ASSERT_EQ(expected_result, result.code) << name << " " << type;
     if (expected_rdatas.size() > 0) {
-        checkRRset(result.rrset, name, finder->getClass(),
-                   expected_type, expected_ttl, expected_rdatas);
+        checkRRset(result.rrset, expected_name != Name(".") ? expected_name :
+                   name, finder->getClass(), expected_type, expected_ttl,
+                   expected_rdatas);
 
         if (expected_sig_rdatas.size() > 0) {
             checkRRset(result.rrset->getRRsig(), name,
@@ -709,12 +712,12 @@ TEST_F(DatabaseClientTest, find) {
     doFindTest(finder, isc::dns::Name("ns.delegation.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::NS(),
                isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas,
-               expected_sig_rdatas);
+               expected_sig_rdatas, isc::dns::Name("delegation.example.org."));
     EXPECT_FALSE(current_database_->searchRunning());
     doFindTest(finder, isc::dns::Name("ns.delegation.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::NS(),
                isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas,
-               expected_sig_rdatas);
+               expected_sig_rdatas, isc::dns::Name("delegation.example.org."));
     EXPECT_FALSE(current_database_->searchRunning());
 
     // Even when we check directly at the delegation point, we should get
@@ -738,12 +741,12 @@ TEST_F(DatabaseClientTest, find) {
     doFindTest(finder, isc::dns::Name("below.dname.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::DNAME(),
                isc::dns::RRTTL(3600), ZoneFinder::DNAME, expected_rdatas,
-               expected_sig_rdatas);
+               expected_sig_rdatas, isc::dns::Name("dname.example.org."));
     EXPECT_FALSE(current_database_->searchRunning());
     doFindTest(finder, isc::dns::Name("below.dname.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(),
                isc::dns::RRTTL(3600), ZoneFinder::DNAME, expected_rdatas,
-               expected_sig_rdatas);
+               expected_sig_rdatas, isc::dns::Name("dname.example.org."));
     EXPECT_FALSE(current_database_->searchRunning());
 
     // But we don't delegate at DNAME point