Browse Source

[1066] Basic wildcard matching

Still, some canceling needs to be done properly.
Michal 'vorner' Vaner 14 years ago
parent
commit
e3c81bd070
2 changed files with 58 additions and 17 deletions
  1. 52 16
      src/lib/datasrc/database.cc
  2. 6 1
      src/lib/datasrc/database.h

+ 52 - 16
src/lib/datasrc/database.cc

@@ -170,7 +170,8 @@ std::pair<bool, isc::dns::RRsetPtr>
 DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
                                  const isc::dns::RRType* type,
                                  bool want_cname, bool want_dname,
-                                 bool want_ns)
+                                 bool want_ns,
+                                 const isc::dns::Name* construct_name)
 {
     RRsigStore sig_store;
     database_->searchForRecords(zone_id_, name.toText());
@@ -178,6 +179,9 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
     isc::dns::RRsetPtr result_rrset;
 
     std::string columns[DatabaseAccessor::COLUMN_COUNT];
+    if (construct_name == NULL) {
+        construct_name = &name;
+    }
     while (database_->getNextRecord(columns, DatabaseAccessor::COLUMN_COUNT)) {
         if (!records_found) {
             records_found = true;
@@ -212,7 +216,8 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
                     isc_throw(DataSourceError, "NS found together with data"
                               " in non-apex domain " + name.toText());
                 }
-                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                addOrCreate(result_rrset, *construct_name, getClass(),
+                            cur_type, cur_ttl,
                             columns[DatabaseAccessor::RDATA_COLUMN],
                             *database_);
             } else if (type != NULL && cur_type == *type) {
@@ -225,7 +230,8 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
                     isc_throw(DataSourceError, "NS found together with data"
                               " in non-apex domain " + name.toText());
                 }
-                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                addOrCreate(result_rrset, *construct_name, getClass(),
+                            cur_type, cur_ttl,
                             columns[DatabaseAccessor::RDATA_COLUMN],
                             *database_);
             } else if (want_cname && cur_type == isc::dns::RRType::CNAME()) {
@@ -235,7 +241,8 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
                     isc_throw(DataSourceError, "CNAME found but it is not "
                               "the only record for " + name.toText());
                 }
-                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                addOrCreate(result_rrset, *construct_name, getClass(),
+                            cur_type, cur_ttl,
                             columns[DatabaseAccessor::RDATA_COLUMN],
                             *database_);
             } else if (want_dname && cur_type == isc::dns::RRType::DNAME()) {
@@ -245,7 +252,8 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
                     isc_throw(DataSourceError, "DNAME with multiple RRs in " +
                               name.toText());
                 }
-                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                addOrCreate(result_rrset, *construct_name, getClass(),
+                            cur_type, cur_ttl,
                             columns[DatabaseAccessor::RDATA_COLUMN],
                             *database_);
             } else if (cur_type == isc::dns::RRType::RRSIG()) {
@@ -300,6 +308,8 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
         // First, do we have any kind of delegation (NS/DNAME) here?
         Name origin(getOrigin());
         size_t origin_label_count(origin.getLabelCount());
+        // Number of labels in the last known non-empty domain
+        size_t last_known(origin_label_count);
         size_t current_label_count(name.getLabelCount());
         // This is how many labels we remove to get origin
         size_t remove_labels(current_label_count - origin_label_count);
@@ -310,6 +320,10 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
             // Look if there's NS or DNAME (but ignore the NS in origin)
             found = getRRset(superdomain, NULL, false, true,
                              i != remove_labels && !glue_ok);
+            if (found.first) {
+                // It contains some RRs, so it exists.
+                last_known = superdomain.getLabelCount();
+            }
             if (found.second) {
                 // We found something redirecting somewhere else
                 // (it can be only NS or DNAME here)
@@ -338,19 +352,10 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
                              name != origin && !glue_ok);
             records_found = found.first;
             result_rrset = found.second;
-            if (result_rrset && name != origin && !glue_ok &&
-                result_rrset->getType() == isc::dns::RRType::NS()) {
-                LOG_DEBUG(logger, DBG_TRACE_DETAILED,
-                          DATASRC_DATABASE_FOUND_DELEGATION_EXACT).
-                    arg(database_->getDBName()).arg(name);
-                result_status = DELEGATION;
-            } else if (result_rrset && type != isc::dns::RRType::CNAME() &&
-                       result_rrset->getType() == isc::dns::RRType::CNAME()) {
-                result_status = CNAME;
-            }
         }
         if (!result_rrset && !records_found) {
-            // Nothing lives here. But check if something lives below this
+            // Nothing lives here.
+            // But check if something lives below this
             // domain and if so, pretend something is here as well.
             database_->searchForRecords(zone_id_, name.toText(), true);
             std::string columns[DatabaseAccessor::COLUMN_COUNT];
@@ -359,8 +364,39 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
                 records_found = true;
                 // We don't consume everything, so get rid of the rest
                 database_->resetSearch();
+            } else {
+                // It's not empty non-terminal. So check for wildcards.
+                // We remove labels one by one and look for the wildcard there.
+                // Go up to first non-empty domain.
+                remove_labels = current_label_count - last_known;
+                Name star("*");
+                for (size_t i(1); i < remove_labels; ++ i) {
+                    // Construct the name with *
+                    // TODO: Once the underlying DatabaseAccessor takes string,
+                    // do the concatenation on strings, not Names
+                    Name superdomain(name.split(i));
+                    Name wildcard(star.concatenate(superdomain));
+                    // TODO What do we do about DNAME here?
+                    found = getRRset(wildcard, &type, true, false, true,
+                                     &name);
+                    result_rrset = found.second;
+                    if (found.first) {
+                        records_found = true;
+                        break;
+                    }
+                }
             }
         }
+        if (result_rrset && name != origin && !glue_ok &&
+            result_rrset->getType() == isc::dns::RRType::NS()) {
+            LOG_DEBUG(logger, DBG_TRACE_DETAILED,
+                      DATASRC_DATABASE_FOUND_DELEGATION_EXACT).
+                arg(database_->getDBName()).arg(name);
+            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)
             .arg(database_->getDBName()).arg(dse.what());

+ 6 - 1
src/lib/datasrc/database.h

@@ -327,6 +327,9 @@ public:
          *     DataSourceError.
          * \param want_ns This allows redirection by NS to be returned. If
          *     any other data is met as well, DataSourceError is thrown.
+         * \param construct_name If set to non-NULL, the resulting RRset will
+         *     be constructed for this name instead of the queried one. This
+         *     is useful for wildcards.
          * \note It may happen that some of the above error conditions are not
          *     detected in some circumstances. The goal here is not to validate
          *     the domain in DB, but to avoid bad behaviour resulting from
@@ -344,7 +347,9 @@ public:
                                                      type,
                                                      bool want_cname,
                                                      bool want_dname,
-                                                     bool want_ns);
+                                                     bool want_ns, const
+                                                     isc::dns::Name*
+                                                     construct_name = NULL);
     };
     /**
      * \brief Find a zone in the database