Browse Source

[1535] make ZoneFinder::find throw on out-of-zone query

Added new OutOfZoneFind exception, which is thrown (instead of NXDOMAIN result) when zonefinder::find() is called for an out-of-zone name (normally this should not happen; the zonefinder object is itself the result of a call to findZone()
Jelte Jansen 13 years ago
parent
commit
f8c0d29e25

+ 2 - 1
src/lib/datasrc/database.cc

@@ -865,7 +865,8 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
         name.compare(getOrigin()).getRelation();
     if (reln != NameComparisonResult::SUBDOMAIN &&
         reln != NameComparisonResult::EQUAL) {
-        return (ResultContext(NXDOMAIN, ConstRRsetPtr()));
+        isc_throw(OutOfZoneFind, "out-of-zone find(): " << name.toText() <<
+                                 " not in " << getOrigin().toText());
     }
 
     // First, go through all superdomains from the origin down, searching for

+ 9 - 0
src/lib/datasrc/memory_datasrc.cc

@@ -1202,6 +1202,15 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
         LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).
             arg(type);
 
+        const NameComparisonResult::NameRelation reln =
+            name.compare(origin_).getRelation();
+        if (reln != NameComparisonResult::SUBDOMAIN &&
+            reln != NameComparisonResult::EQUAL) {
+            isc_throw(OutOfZoneFind, "out-of-zone find(): " <<
+                                     name.toText() <<
+                                     " not in " << origin_.toText());
+        }
+
         // Get the node.  All other cases than an exact match are handled
         // in findNode().  We simply construct a result structure and return.
         const ZoneData::FindNodeResult node_result =

+ 25 - 27
src/lib/datasrc/tests/database_unittest.cc

@@ -1877,33 +1877,31 @@ TYPED_TEST(DatabaseClientTest, findOutOfZone) {
     vector<ConstRRsetPtr> target;
 
     // Superdomain
-    doFindTest(*finder, Name("org"), this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->empty_rdatas_, this->empty_rdatas_);
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, finder->findAll(Name("org"), target)->code);
+    EXPECT_THROW(finder->find(Name("org"), this->qtype_,
+                 ZoneFinder::FIND_DEFAULT), OutOfZoneFind);
+    EXPECT_THROW(finder->findAll(Name("org"), target), OutOfZoneFind);
+
     // sharing a common ancestor
-    doFindTest(*finder, Name("noexample.org"), this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->empty_rdatas_, this->empty_rdatas_);
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, finder->findAll(Name("noexample.org"),
-                                                    target)->code);
+    EXPECT_THROW(finder->find(Name("noexample.org"), this->qtype_,
+                 ZoneFinder::FIND_DEFAULT), OutOfZoneFind);
+    EXPECT_THROW(finder->findAll(Name("noexample.org"), target),
+                 OutOfZoneFind);
+
     // totally unrelated domain, smaller number of labels
-    doFindTest(*finder, Name("com"), this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->empty_rdatas_, this->empty_rdatas_);
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, finder->findAll(Name("com"), target)->code);
+    EXPECT_THROW(finder->find(Name("com"), this->qtype_,
+                 ZoneFinder::FIND_DEFAULT), OutOfZoneFind);
+    EXPECT_THROW(finder->findAll(Name("com"), target), OutOfZoneFind);
+
     // totally unrelated domain, same number of labels
-    doFindTest(*finder, Name("example.com"), this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->empty_rdatas_, this->empty_rdatas_);
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, finder->findAll(Name("example.com"),
-                                                    target)->code);
+    EXPECT_THROW(finder->find(Name("example.com"), this->qtype_,
+                 ZoneFinder::FIND_DEFAULT), OutOfZoneFind);
+    EXPECT_THROW(finder->findAll(Name("example.com"), target), OutOfZoneFind);
+
     // totally unrelated domain, larger number of labels
-    doFindTest(*finder, Name("more.example.com"), this->qtype_, this->qtype_,
-               this->rrttl_, ZoneFinder::NXDOMAIN,
-               this->empty_rdatas_, this->empty_rdatas_);
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, finder->findAll(Name("more.example.com"),
-                                                    target)->code);
+    EXPECT_THROW(finder->find(Name("more.example.com"), this->qtype_,
+                 ZoneFinder::FIND_DEFAULT), OutOfZoneFind);
+    EXPECT_THROW(finder->findAll(Name("more.example.com"), target),
+                 OutOfZoneFind);
 }
 
 TYPED_TEST(DatabaseClientTest, findDelegation) {
@@ -2835,10 +2833,10 @@ TYPED_TEST(DatabaseClientTest, addDeviantRR) {
         // regardless of whether adding the RR succeeded, so this check
         // actually doesn't confirm it.
         SCOPED_TRACE("add out-of-zone RR");
-        doFindTest(this->updater_->getFinder(), Name("example.com"),
-                   this->qtype_, this->qtype_, this->rrttl_,
-                   ZoneFinder::NXDOMAIN, this->empty_rdatas_,
-                   this->empty_rdatas_);
+        EXPECT_THROW(this->updater_->getFinder().find(Name("example.com"),
+                                                      this->qtype_,
+                                                      ZoneFinder::FIND_DEFAULT),
+                     OutOfZoneFind);
     }
 }
 

+ 14 - 10
src/lib/datasrc/tests/memory_datasrc_unittest.cc

@@ -899,8 +899,9 @@ TEST_F(InMemoryZoneFinderTest, findAny) {
     findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
 
     // out zone name
-    findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
-                vector<ConstRRsetPtr>());
+    EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
+                             vector<ConstRRsetPtr>()),
+                 OutOfZoneFind);
 
     expected_sets.clear();
     expected_sets.push_back(rr_child_glue_);
@@ -997,8 +998,8 @@ InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags) {
     // These domains don't exist (and one is out of the zone)
     findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN,
              true, ConstRRsetPtr(), expected_flags);
-    findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN, true,
-             ConstRRsetPtr(), expected_flags);
+    EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A(),
+                 ZoneFinder::FIND_DEFAULT), OutOfZoneFind);
 }
 
 TEST_F(InMemoryZoneFinderTest, find) {
@@ -1053,8 +1054,9 @@ InMemoryZoneFinderTest::emptyNodeCheck(
     // Note: basically we don't expect such a query to be performed (the common
     // operation is to identify the best matching zone first then perform
     // search it), but we shouldn't be confused even in the unexpected case.
-    findTest(Name("org"), RRType::A(), ZoneFinder::NXDOMAIN, true,
-             ConstRRsetPtr(), expected_flags);
+    EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A(),
+                                   ZoneFinder::FIND_DEFAULT),
+                 OutOfZoneFind);
 }
 
 TEST_F(InMemoryZoneFinderTest, emptyNode) {
@@ -1512,14 +1514,16 @@ TEST_F(InMemoryZoneFinderTest, swap) {
     EXPECT_EQ(RRClass::CH(), finder1.getClass());
     EXPECT_EQ(RRClass::IN(), finder2.getClass());
     // make sure the zone data is swapped, too
-    findTest(origin_, RRType::NS(), ZoneFinder::NXDOMAIN, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
+    EXPECT_THROW(finder1.find(origin_, RRType::NS(),
+                              ZoneFinder::FIND_DEFAULT),
+                 OutOfZoneFind);
     findTest(other_origin, RRType::TXT(), ZoneFinder::SUCCESS, false,
              ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
     findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, false,
              ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
-    findTest(other_origin, RRType::TXT(), ZoneFinder::NXDOMAIN, false,
-             ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
+    EXPECT_THROW(finder2.find(other_origin, RRType::TXT(),
+                              ZoneFinder::FIND_DEFAULT),
+                 OutOfZoneFind);
 }
 
 TEST_F(InMemoryZoneFinderTest, getFileName) {

+ 10 - 0
src/lib/datasrc/zone.h

@@ -27,6 +27,14 @@
 namespace isc {
 namespace datasrc {
 
+/// \brief Thrown when ZoneFinder::find() is called for out-of-zone data
+///
+class OutOfZoneFind : public Exception {
+public:
+    OutOfZoneFind(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
 /// \brief The base class to search a zone for RRsets
 ///
 /// The \c ZoneFinder class is an abstract base class for representing
@@ -466,6 +474,8 @@ public:
     ///
     /// \exception std::bad_alloc Memory allocation such as for constructing
     ///  the resulting RRset fails
+    /// \throw OutOfZoneFind The Name \c name is outside of the origin
+    /// of the zone of this ZoneFinder.
     /// \exception DataSourceError Derived class specific exception, e.g.
     /// when encountering a bad zone configuration or database connection
     /// failure.  Although these are considered rare, exceptional events,

+ 4 - 0
src/lib/python/isc/datasrc/datasrc.cc

@@ -233,6 +233,7 @@ initModulePart_ZoneJournalReader(PyObject* mod) {
 }
 
 PyObject* po_DataSourceError;
+PyObject* po_OutOfZoneFind;
 PyObject* po_NotImplemented;
 
 PyModuleDef iscDataSrc = {
@@ -287,6 +288,9 @@ PyInit_datasrc(void) {
         po_DataSourceError = PyErr_NewException("isc.datasrc.Error", NULL,
                                                 NULL);
         PyObjectContainer(po_DataSourceError).installToModule(mod, "Error");
+        po_OutOfZoneFind = PyErr_NewException("isc.datasrc.OutOfZoneFind",
+                                              NULL, NULL);
+        PyObjectContainer(po_OutOfZoneFind).installToModule(mod, "OutOfZoneFind");
         po_NotImplemented = PyErr_NewException("isc.datasrc.NotImplemented",
                                                NULL, NULL);
         PyObjectContainer(po_NotImplemented).installToModule(mod,

+ 4 - 0
src/lib/python/isc/datasrc/finder_python.cc

@@ -97,6 +97,10 @@ PyObject* ZoneFinder_helper(ZoneFinder* finder, PyObject* args) {
             } else {
                 return (Py_BuildValue("IOI", r, Py_None, result_flags));
             }
+        } catch (const OutOfZoneFind& oozf) {
+            PyErr_SetString(getDataSourceException("OutOfZoneFind"),
+                            oozf.what());
+            return (NULL);
         } catch (const DataSourceError& dse) {
             PyErr_SetString(getDataSourceException("Error"), dse.what());
             return (NULL);

+ 4 - 5
src/lib/python/isc/datasrc/tests/datasrc_test.py

@@ -379,11 +379,10 @@ class DataSrcClient(unittest.TestCase):
         self.assertEqual(finder.NXDOMAIN, result)
         self.assertEqual(None, rrset)
 
-        result, rrset, _ = finder.find(isc.dns.Name("www.some.other.domain"),
-                                       isc.dns.RRType.A(),
-                                       finder.FIND_DEFAULT)
-        self.assertEqual(finder.NXDOMAIN, result)
-        self.assertEqual(None, rrset)
+
+        self.assertRaises(isc.datasrc.OutOfZoneFind, finder.find,
+                          isc.dns.Name("www.some.other.domain"),
+                          isc.dns.RRType.A(), finder.FIND_DEFAULT)
 
         result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
                                        isc.dns.RRType.TXT(),