Browse Source

[2267] have add() take both RRset and RRSIG at the same time.

as a helper another version of addRdataSet() is introduced too.
these don't need the last_rrset_ magic.
InMemoryClient::add now uses this version.
JINMEI Tatuya 12 years ago
parent
commit
7e5dbd9146
1 changed files with 139 additions and 14 deletions
  1. 139 14
      src/lib/datasrc/memory/memory_client.cc

+ 139 - 14
src/lib/datasrc/memory/memory_client.cc

@@ -247,7 +247,23 @@ public:
                       << rrset->getName() << " which isn't supported");
         }
 
-        NameComparisonResult compare(zone_name.compare(rrset->getName()));
+        // For RRSIGs, check consistency of the type covered.
+        // We know the RRset isn't empty, so the following check is safe.
+        if (rrset->getType() == RRType::RRSIG()) {
+            RdataIteratorPtr rit = rrset->getRdataIterator();
+            const RRType covered = dynamic_cast<const generic::RRSIG&>(
+                rit->getCurrent()).typeCovered();
+            for (rit->next(); !rit->isLast(); rit->next()) {
+                if (dynamic_cast<const generic::RRSIG&>(
+                        rit->getCurrent()).typeCovered() != covered) {
+                    isc_throw(AddError, "RRSIG contains mixed covered types: "
+                              << rrset->toText());
+                }
+            }
+        }
+
+        const NameComparisonResult compare =
+            zone_name.compare(rrset->getName());
         if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
             compare.getRelation() != NameComparisonResult::EQUAL)
         {
@@ -463,6 +479,89 @@ public:
         last_rrset_ = rrset;
     }
 
+    void addRdataSet2(const Name& zone_name, ZoneData& zone_data,
+                      const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
+    {
+        // Only one of these can be passed at a time.
+        assert(!(rrset && rrsig));
+
+        if (rrset->getType() == RRType::NSEC3()) {
+            addNSEC3(rrset, rrsig, zone_data);
+        } else {
+            ZoneNode* node;
+            zone_data.insertName(mem_sgmt_, rrset->getName(), &node);
+
+            RdataSet* rdataset_head = node->getData();
+
+            // Checks related to the surrounding data.
+            // Note: when the check fails and the exception is thrown,
+            // it may break strong exception guarantee.  At the moment
+            // we prefer code simplicity and don't bother to introduce
+            // complicated recovery code.
+            contextCheck(zone_name, *rrset, rdataset_head);
+
+            if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
+                isc_throw(AddError,
+                          "RRset of the type already exists: "
+                          << rrset->getName() << " (type: "
+                          << rrset->getType() << ")");
+            }
+
+            RdataEncoder encoder;
+            RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder, rrset,
+                                                  rrsig);
+            rdataset->next = rdataset_head;
+            node->setData(rdataset);
+
+            // Ok, we just put it in
+
+            // If this RRset creates a zone cut at this node, mark the
+            // node indicating the need for callback in find().
+            if (rrset->getType() == RRType::NS() &&
+                rrset->getName() != zone_name) {
+                node->setFlag(ZoneNode::FLAG_CALLBACK);
+                // If it is DNAME, we have a callback as well here
+            } else if (rrset->getType() == RRType::DNAME()) {
+                node->setFlag(ZoneNode::FLAG_CALLBACK);
+            }
+
+            // If we've added NSEC3PARAM at zone origin, set up NSEC3
+            // specific data or check consistency with already set up
+            // parameters.
+            if (rrset->getType() == RRType::NSEC3PARAM() &&
+                rrset->getName() == zone_name) {
+                // We know rrset has exactly one RDATA
+                const generic::NSEC3PARAM& param =
+                    dynamic_cast<const generic::NSEC3PARAM&>
+                      (rrset->getRdataIterator()->getCurrent());
+
+                NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
+                if (nsec3_data == NULL) {
+                    nsec3_data = NSEC3Data::create(mem_sgmt_, param);
+                    zone_data.setNSEC3Data(nsec3_data);
+                } else {
+                    size_t salt_len = nsec3_data->getSaltLen();
+                    const uint8_t* salt_data = nsec3_data->getSaltData();
+                    const vector<uint8_t>& salt_data_2 = param.getSalt();
+
+                    if ((param.getHashalg() != nsec3_data->hashalg) ||
+                        (param.getIterations() != nsec3_data->iterations) ||
+                        (salt_data_2.size() != salt_len) ||
+                        (std::memcmp(&salt_data_2[0],
+                                     salt_data, salt_len) != 0)) {
+                        isc_throw(AddError,
+                                  "NSEC3PARAM with inconsistent parameters: "
+                                  << rrset->toText());
+                    }
+                }
+            } else if (rrset->getType() == RRType::NSEC()) {
+                // If it is NSEC signed zone, so we put a flag there
+                // (flag is enough)
+                zone_data.setSigned(true);
+            }
+        }
+    }
+
     result::Result addRRsig(const ConstRRsetPtr sig_rrset,
                             const Name& zone_name, ZoneData& zone_data)
     {
@@ -522,6 +621,37 @@ public:
         return (result::SUCCESS);
     }
 
+    result::Result add(const ConstRRsetPtr& rrset,
+                       const ConstRRsetPtr& sig_rrset,
+                       const Name& zone_name, ZoneData& zone_data)
+    {
+        // Sanitize input.  This will cause an exception to be thrown
+        // if the input RRset is empty.
+        addValidation(zone_name, rrset);
+        if (sig_rrset) {
+            addValidation(zone_name, sig_rrset);
+        }
+
+        // OK, can add the RRset.
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
+            arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
+
+        if (rrset->getType() == RRType::NSEC3()) {
+            addRdataSet2(zone_name, zone_data, rrset, sig_rrset);
+            return (result::SUCCESS);
+        }
+
+        // Add wildcards possibly contained in the owner name to the domain
+        // tree.
+        // Note: this can throw an exception, breaking strong exception
+        // guarantee.  (see also the note for contextCheck() below).
+        addWildcards(zone_name, zone_data, rrset->getName());
+
+        addRdataSet2(zone_name, zone_data, rrset, sig_rrset);
+
+        return (result::SUCCESS);
+    }
+
     /*
      * Wrapper around above.
      */
@@ -736,25 +866,20 @@ InMemoryClient::getFileName(const isc::dns::Name& zone_name) const {
 
 result::Result
 InMemoryClient::add(const isc::dns::Name& zone_name,
-                    const ConstRRsetPtr& rrset) {
+                    const ConstRRsetPtr& rrset)
+{
     assert(!impl_->last_rrset_);
 
-    ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+    const ZoneTable::FindResult result =
+        impl_->zone_table_->findZone(zone_name);
     if (result.code != result::SUCCESS) {
         isc_throw(DataSourceError, "No such zone: " + zone_name.toText());
     }
 
-    result::Result ret(impl_->add(rrset, zone_name, *result.zone_data));
-    // Add any associated RRSIG too. This has to be done here, as both
-    // the RRset and its RRSIG have to be passed when constructing an
-    // RdataSet.
-    if ((ret == result::SUCCESS) && rrset->getRRsig()) {
-        impl_->add(rrset->getRRsig(), zone_name, *result.zone_data);
-    }
-
-    // Add any last RRset that was left
-    impl_->addRdataSet(zone_name, *result.zone_data,
-                       ConstRRsetPtr(), ConstRRsetPtr());
+    const ConstRRsetPtr sig_rrset =
+        rrset ? rrset->getRRsig() : ConstRRsetPtr();
+    const result::Result ret(impl_->add(rrset, sig_rrset,
+                                        zone_name, *result.zone_data));
 
     assert(!impl_->last_rrset_);