Parcourir la source

[1066] More wildcard cornercases

Wildcard match below NS with GLUE_OK mode
Empty non-terminal asterisk
Michal 'vorner' Vaner il y a 13 ans
Parent
commit
2384bcf387
2 fichiers modifiés avec 93 ajouts et 10 suppressions
  1. 32 8
      src/lib/datasrc/database.cc
  2. 61 2
      src/lib/datasrc/tests/database_unittest.cc

+ 32 - 8
src/lib/datasrc/database.cc

@@ -316,6 +316,9 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
     std::pair<bool, isc::dns::RRsetPtr> found;
     logger.debug(DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
         .arg(database_->getDBName()).arg(name).arg(type);
+    // In case we are in GLUE_OK mode and start matching wildcards,
+    // we can't do it under NS, so we store it here to check
+    isc::dns::RRsetPtr first_ns;
 
     try {
         // First, do we have any kind of delegation (NS/DNAME) here?
@@ -336,6 +339,12 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
             if (found.first) {
                 // It contains some RRs, so it exists.
                 last_known = superdomain.getLabelCount();
+                // In case we are in GLUE_OK, we want to store the highest
+                // encounderet RRset.
+                if (glue_ok && !first_ns && i != remove_labels) {
+                    first_ns = getRRset(superdomain, NULL, false, false,
+                                        true).second;
+                }
             }
             if (found.second) {
                 // We found something redirecting somewhere else
@@ -376,27 +385,42 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
                 // 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) {
+                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
+                    // 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);
                     if (found.first) {
-                        // Nothing we added as part of the * can exist directly,
-                        // as we go up only to first existing domain,
-                        // but it could be empty non-terminal. In that case, we
-                        // need to cancel the match.
-                        if (!hasSubdomains(name.split(i - 1).toText())) {
+                        if (first_ns) {
+                            // In case we are under NS, we don't
+                            // wildcard-match, but return delegation
+                            result_rrset = first_ns;
+                            result_status = DELEGATION;
+                            records_found = true;
+                            // We pretend to switch to non-glue_ok mode
+                            glue_ok = false;
+                        } else if (!hasSubdomains(name.split(i - 1).toText()))
+                        {
+                            // Nothing we added as part of the * can exist
+                            // directly, as we go up only to first existing
+                            // domain, but it could be empty non-terminal. In
+                            // that case, we need to cancel the match.
                             records_found = true;
                             result_rrset = found.second;
                         }
                         break;
+                    } else if (hasSubdomains(wildcard.toText())) {
+                        // Empty non-terminal asterisk
+                        records_found = true;
+                        break;
                     }
                 }
             }

+ 61 - 2
src/lib/datasrc/tests/database_unittest.cc

@@ -332,6 +332,14 @@ private:
         addCurName("*.wild.example.org.");
         addRecord("AAAA", "3600", "", "2001:db8::5");
         addCurName("cancel.here.wild.example.org.");
+        addRecord("NS", "3600", "", "ns.example.com.");
+        addCurName("delegatedwild.example.org.");
+        addRecord("A", "3600", "", "192.0.2.5");
+        addCurName("*.delegatedwild.example.org.");
+        addRecord("A", "3600", "", "192.0.2.5");
+        addCurName("wild.*.foo.example.org.");
+        addRecord("A", "3600", "", "192.0.2.5");
+        addCurName("wild.*.foo.*.bar.example.org.");
     }
 };
 
@@ -1030,8 +1038,59 @@ TEST_F(DatabaseClientTest, wildcard) {
                isc::dns::RRTTL(3600), ZoneFinder::NXRRSET, expected_rdatas_,
                expected_sig_rdatas_);
 
-    // TODO Check delegation, multiple wildcards and wildcards somewhere
-    // in the middle.
+    // How wildcard go together with delegation
+    expected_rdatas_.push_back("ns.example.com.");
+    doFindTest(finder, isc::dns::Name("below.delegatedwild.example.org"),
+               isc::dns::RRType::A(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_,
+               isc::dns::Name("delegatedwild.example.org"));
+    // FIXME: This doesn't look logically OK, GLUE_OK should make it transparent,
+    // so the match should either work or be canceled, but return NXDOMAIN
+    doFindTest(finder, isc::dns::Name("below.delegatedwild.example.org"),
+               isc::dns::RRType::A(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_,
+               isc::dns::Name("delegatedwild.example.org"),
+               ZoneFinder::FIND_GLUE_OK);
+
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.5");
+    // These are direct matches
+    const char* positive_names[] = {
+        "wild.*.foo.example.org.",
+        "wild.*.foo.*.bar.example.org.",
+        NULL
+    };
+    for (const char** name(positive_names); *name != NULL; ++ name) {
+        doFindTest(finder, isc::dns::Name(*name), isc::dns::RRType::A(),
+                   isc::dns::RRType::A(), isc::dns::RRTTL(3600),
+                   ZoneFinder::SUCCESS, expected_rdatas_,
+                   expected_sig_rdatas_);
+    }
+
+    // These are wildcard matches against empty nonterminal asterisk
+    expected_rdatas_.clear();
+    const char* negative_names[] = {
+        "a.foo.example.org.",
+        "*.foo.example.org.",
+        "foo.example.org.",
+        "wild.bar.foo.example.org.",
+        "baz.foo.*.bar.example.org",
+        "baz.foo.baz.bar.example.org",
+        "*.foo.baz.bar.example.org",
+        "*.foo.*.bar.example.org",
+        "foo.*.bar.example.org",
+        "*.bar.example.org",
+        "bar.example.org",
+        NULL
+    };
+    for (const char** name(negative_names); *name != NULL; ++ name) {
+        doFindTest(finder, isc::dns::Name(*name), isc::dns::RRType::A(),
+                   isc::dns::RRType::A(), isc::dns::RRTTL(3600),
+                   ZoneFinder::NXRRSET, expected_rdatas_,
+                   expected_sig_rdatas_);
+    }
 }
 
 TEST_F(DatabaseClientTest, getOrigin) {