Browse Source

[2499] Perform validation using dns::checkZone() during in-memory loading

Also fix various invalid zone files.
Mukund Sivaraman 12 years ago
parent
commit
58c958d450

+ 13 - 0
src/lib/datasrc/memory/memory_messages.mes

@@ -88,3 +88,16 @@ The software refuses to load NS records into a wildcard domain.  It isn't
 explicitly forbidden, but the protocol is ambiguous about how this should
 behave and BIND 9 refuses that as well. Please describe your intention using
 different tools.
+
+% DATASRC_MEMORY_CHECK_ERROR post-load check of zone %1/%2 failed: %3
+The zone was loaded into the data source successfully, but the content fails
+basic sanity checks. See the message if you want to know what exactly is wrong
+with the data. The data can not be used and previous version, if any, will be
+preserved.
+
+% DATASRC_MEMORY_CHECK_WARNING %1/%2: %3
+The zone was loaded into the data source successfully, but there's some problem
+with the content. The problem does not stop the new version from being used
+(though there may be other problems that do, see DATASRC_MEMORY_CHECK_ERROR),
+but it should still be checked and fixed. See the message to know what exactly
+is wrong with the data.

+ 26 - 6
src/lib/datasrc/memory/zone_data_loader.cc

@@ -18,11 +18,13 @@
 #include <datasrc/memory/logger.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/util_internal.h>
+#include <datasrc/memory/rrset_collection.h>
 
 #include <dns/master_loader.h>
 #include <dns/rrcollator.h>
 #include <dns/rdataclass.h>
 #include <dns/rrset.h>
+#include <dns/zone_checker.h>
 
 #include <boost/foreach.hpp>
 #include <boost/bind.hpp>
@@ -148,6 +150,22 @@ ZoneDataLoader::getCurrentName() const {
     return (node_rrsigsets_.begin()->second->getName());
 }
 
+void
+logWarning(const dns::Name* zone_name, const dns::RRClass* rrclass,
+           const std::string& reason)
+{
+    LOG_WARN(logger, DATASRC_MEMORY_CHECK_WARNING).arg(*zone_name).
+        arg(*rrclass).arg(reason);
+}
+
+void
+logError(const dns::Name* zone_name, const dns::RRClass* rrclass,
+         const std::string& reason)
+{
+    LOG_ERROR(logger, DATASRC_MEMORY_CHECK_ERROR).arg(*zone_name).arg(*rrclass).
+        arg(reason);
+}
+
 ZoneData*
 loadZoneDataInternal(util::MemorySegment& mem_sgmt,
                      const isc::dns::RRClass& rrclass,
@@ -172,12 +190,14 @@ loadZoneDataInternal(util::MemorySegment& mem_sgmt,
         }
     }
 
-    // When an empty zone file is loaded, the origin doesn't even have
-    // an SOA RR. This condition should be avoided, and hence load()
-    // should throw when an empty zone is loaded.
-    if (RdataSet::find(rdataset, RRType::SOA()) == NULL) {
-        isc_throw(EmptyZone,
-                  "Won't create an empty zone for: " << zone_name);
+    RRsetCollection collection(*(holder.get()), rrclass);
+    const dns::ZoneCheckerCallbacks
+        callbacks(boost::bind(&logError, &zone_name, &rrclass, _1),
+                  boost::bind(&logWarning, &zone_name, &rrclass, _1));
+    if (!dns::checkZone(zone_name, rrclass, collection, callbacks)) {
+        isc_throw(ZoneValidationError,
+                  "Errors found when validating zone: "
+                  << zone_name << "/" << rrclass);
     }
 
     return (holder.release());

+ 4 - 4
src/lib/datasrc/memory/zone_data_loader.h

@@ -26,12 +26,12 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
-/// \brief Zone is empty exception.
+/// \brief Zone is invalid exception.
 ///
-/// This is thrown if an empty zone would be created during
+/// This is thrown if an invalid zone would be created during
 /// \c loadZoneData().
-struct EmptyZone : public ZoneLoaderException {
-    EmptyZone(const char* file, size_t line, const char* what) :
+struct ZoneValidationError : public ZoneLoaderException {
+    ZoneValidationError(const char* file, size_t line, const char* what) :
         ZoneLoaderException(file, line, what)
     {}
 };

+ 38 - 5
src/lib/datasrc/tests/memory/memory_client_unittest.cc

@@ -59,6 +59,7 @@ namespace {
 const char* rrset_data[] = {
     "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
     "68 3600 300 3600000 3600",
+    "example.org. 3600 IN NS ns1.example.org.",
     "a.example.org. 3600 IN A 192.168.0.1\n" // RRset containing 2 RRs
     "a.example.org. 3600 IN A 192.168.0.2",
     "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
@@ -225,7 +226,7 @@ TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
 
     EXPECT_THROW(client_->load(Name("."),
                                TEST_DATA_DIR "/empty.zone"),
-                 EmptyZone);
+                 ZoneValidationError);
 
     EXPECT_EQ(0, client_->getZoneCount());
 
@@ -255,6 +256,11 @@ TEST_F(MemoryClientTest, loadFromIterator) {
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::SOA(), rrset->getType());
 
+    // RRType::NS() RRset
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
+
     // RRType::MX() RRset
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
@@ -377,6 +383,10 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(RRType::SOA(), set->type);
 
     set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::NS(), set->type);
+
+    set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
     /* Check ns1.example.org */
@@ -402,6 +412,10 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(RRType::SOA(), set->type);
 
     set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::NS(), set->type);
+
+    set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
     /* Check ns1.example.org */
@@ -636,9 +650,14 @@ TEST_F(MemoryClientTest, getIterator) {
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
 
     // First we have the SOA
-    ConstRRsetPtr rrset_soa(iterator->getNextRRset());
-    EXPECT_TRUE(rrset_soa);
-    EXPECT_EQ(RRType::SOA(), rrset_soa->getType());
+    ConstRRsetPtr rrset(iterator->getNextRRset());
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+    // Then the NS
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
 
     // There's nothing else in this iterator
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
@@ -659,6 +678,11 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::SOA(), rrset->getType());
 
+    // Then, the NS
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
+
     // Only one RRType::A() RRset
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
@@ -667,7 +691,6 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     // There's nothing else in this zone
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
 
-
     // separate_rrs = true
     ZoneIteratorPtr iterator2(client_->getIterator(Name("example.org"), true));
 
@@ -676,6 +699,11 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::SOA(), rrset->getType());
 
+    // Then, the NS
+    rrset = iterator2->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
+
     // First RRType::A() RRset
     rrset = iterator2->getNextRRset();
     EXPECT_TRUE(rrset);
@@ -751,6 +779,11 @@ TEST_F(MemoryClientTest, findZoneData) {
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(RRType::SOA(), set->type);
 
+    /* Check NS */
+    set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::NS(), set->type);
+
     set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 

+ 2 - 1
src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone

@@ -1,4 +1,5 @@
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 76 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 77 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.
 ns1.example.org.		      3600 IN A	 	192.168.0.1
 ns1.example.org.		      3600 IN A	 	192.168.0.2
 ns1.example.org.		      3600 IN AAAA 	::1

+ 2 - 1
src/lib/datasrc/tests/memory/testdata/example.org-empty.zone

@@ -1,2 +1,3 @@
 ;; empty example.org zone
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 71 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.

+ 2 - 1
src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone

@@ -1,4 +1,5 @@
 ;; Multiple RDATA for testing separate RRs iterator
-example.org.  		   	 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+example.org.  		   	 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 80 3600 300 3600000 3600
+example.org.			 3600 IN NS	ns1.example.org.
 a.example.org.		   	 3600 IN A	192.168.0.1
 a.example.org.		   	 3600 IN A	192.168.0.2

+ 2 - 1
src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone

@@ -1,5 +1,6 @@
 ;; test zone file used for ZoneFinderContext tests.
 ;; RRSIGs are (obviouslly) faked ones for testing.
 
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 69 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.
 ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE

+ 2 - 1
src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone

@@ -1,7 +1,8 @@
 ;; test zone file used for ZoneFinderContext tests.
 ;; RRSIGs are (obviouslly) faked ones for testing.
 
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 74 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 75 3600 300 3600000 3600
+example.org. 3600 IN NS		ns1.example.org.
 ns1.example.org.		      3600 IN A	 	192.168.0.1
 ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
 ns1.example.org.		      3600 IN RRSIG	A 7 2 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE