Browse Source

[2108] Save RRsets and call RdataSet::create() with their corresponding RRSIGs

Mukund Sivaraman 12 years ago
parent
commit
d074626ee7
1 changed files with 158 additions and 150 deletions
  1. 158 150
      src/lib/datasrc/memory/memory_client.cc

+ 158 - 150
src/lib/datasrc/memory/memory_client.cc

@@ -111,6 +111,7 @@ public:
     unsigned int zone_count_;
     ZoneTable* zone_table_;
     FileNameTree* file_name_tree_;
+    ConstRRsetPtr last_rrset_;
 
     // Common process for zone load.
     // rrset_installer is a functor that takes another functor as an argument,
@@ -292,87 +293,9 @@ public:
         }
     }
 
-    result::Result addRRsig(const ConstRRsetPtr sig_rrset, ZoneData& zone_data)
-    {
-        // Check consistency of the type covered.
-        // We know the RRset isn't empty, so the following check is safe.
-        RdataIteratorPtr rit = sig_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: "
-                          << sig_rrset->toText());
-            }
-        }
-
-        // Find the RRset to be covered; if not found, treat it as an error
-        // for now.
-        ConstRRsetPtr covered_rrset;
-        if (covered != RRType::NSEC3()) {
-            DomainNode* node = NULL;
-            if (zone_data.domains_.find(sig_rrset->getName(), &node) !=
-                DomainTree::EXACTMATCH || node == NULL || !node->getData()) {
-                isc_throw(AddError,
-                          "RRSIG is being added, but no RR to be covered: "
-                          << sig_rrset->getName());
-            }
-            const Domain::const_iterator it = node->getData()->find(covered);
-            if (it != node->getData()->end()) {
-                covered_rrset = it->second;
-            }
-        } else {
-            // In case of NSEC3 if something is found it must be NSEC3 RRset
-            // under the assumption of our current implementation.
-            if (zone_data.nsec3_data_) {
-                // Convert the first label to upper-cased text.  Note that
-                // for a valid NSEC3 RR the label should only consist of
-                // positive 8-bit char values, so using toupper(int) should be
-                // safe (if it's a bogus label for NSEC3 the zone won't work
-                // anyway).  Also note the '::' below: g++'s STL implementation
-                // seems to require it to toupper to make this compile.
-                string fst_label =
-                    sig_rrset->getName().split(0, 1).toText(true);
-                transform(fst_label.begin(), fst_label.end(),
-                          fst_label.begin(), ::toupper);
-
-                NSEC3Map::const_iterator found =
-                    zone_data.nsec3_data_->map_.find(fst_label);
-                if (found != zone_data.nsec3_data_->map_.end()) {
-                    covered_rrset = found->second;
-                    assert(covered_rrset->getType() == covered);
-                }
-            }
-        }
-        if (!covered_rrset) {
-            isc_throw(AddError, "RRSIG is being added, but no RR of "
-                      "covered type found: " << sig_rrset->toText());
-        }
-
-        // The current implementation doesn't allow an existing RRSIG to be
-        // overridden (or updated with additional ones).
-        if (covered_rrset->getRRsig()) {
-            isc_throw(AddError,
-                      "RRSIG is being added to override an existing one: "
-                      << sig_rrset->toText());
-        }
-
-        // All okay, setting the RRSIG.
-        // XXX: we break const-ness of the covered RRsets.  In practice the
-        // ownership of these RRsets would have been given to us so it should
-        // be safe, but it's still a very bad practice.
-        // We'll fix this problem anyway when we update the underlying
-        // representation so that it's more space efficient.
-        // Note: there's a slight chance of getting an exception.
-        // As noted in add(), we give up strong exception guarantee in such
-        // cases.
-        boost::const_pointer_cast<AbstractRRset>(covered_rrset)->addRRsig(sig_rrset);
-
-        return (result::SUCCESS);
-    }
-
-    result::Result addNSEC3(const ConstRRsetPtr rrset, ZoneData& zone_data) {
+    void addNSEC3(const ConstRRsetPtr rrset,
+                  const ConstRRsetPtr rrsig,
+                  ZoneData& zone_data) {
         // We know rrset has exactly one RDATA
         const generic::NSEC3& nsec3_rdata =
             dynamic_cast<const generic::NSEC3&>(
@@ -405,13 +328,155 @@ public:
         nsec3_data->insertName(local_mem_sgmt_, Name(fst_label), &node);
 
         RdataEncoder encoder;
+
+        // We assume that rrsig has already been checked to match rrset
+        // by the caller.
         RdataSet *set = RdataSet::create(local_mem_sgmt_, encoder,
-                                         rrset, ConstRRsetPtr());
+                                         rrset, rrsig);
         RdataSet *old_set = node->setData(set);
         if (old_set != NULL) {
             RdataSet::destroy(local_mem_sgmt_, rrclass_, old_set);
         }
+    }
+
+    void addRdataSet(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 rrsig is passed, validate it against the last-saved rrset.
+        if (rrsig) {
+            // The covered RRset should have been saved by now.
+            if (!last_rrset_) {
+                isc_throw(AddError,
+                          "RRSIG is being added, "
+                          "but doesn't follow its covered RR: "
+                          << rrsig->getName());
+            }
+
+            if (rrsig->getName() != last_rrset_->getName()) {
+                isc_throw(AddError,
+                          "RRSIG is being added, "
+                          "but doesn't match the last RR's name: "
+                          << last_rrset_->getName() << " vs. "
+                          << rrsig->getName());
+            }
+
+            // Consistency of other types in rrsig are checked in addRRsig().
+            RdataIteratorPtr rit = rrsig->getRdataIterator();
+            const RRType covered = dynamic_cast<const generic::RRSIG&>(
+                rit->getCurrent()).typeCovered();
+
+            if (covered != last_rrset_->getType()) {
+                isc_throw(AddError,
+                          "RRSIG is being added, "
+                          "but doesn't match the last RR's type: "
+                          << last_rrset_->getType() << " vs. "
+                          << rrsig->getType());
+            }
+        }
 
+        if (!last_rrset_) {
+            last_rrset_ = rrset;
+            return;
+        }
+
+        if (last_rrset_->getType() == RRType::NSEC3()) {
+            addNSEC3(last_rrset_, rrsig, zone_data);
+        } else {
+            ZoneNode* node;
+            zone_data.insertName(local_mem_sgmt_, last_rrset_->getName(), &node);
+
+            RdataSet* set = 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, *last_rrset_, set);
+
+            if (RdataSet::find(set, last_rrset_->getType()) != NULL) {
+                isc_throw(AddError,
+                          "RRset of the type already exists: "
+                          << last_rrset_->getName() << " (type: "
+                          << last_rrset_->getType() << ")");
+            }
+
+            RdataEncoder encoder;
+            RdataSet *new_set = RdataSet::create(local_mem_sgmt_, encoder,
+                                                 last_rrset_, rrsig);
+            new_set->next = set;
+            node->setData(new_set);
+
+            // 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 (last_rrset_->getType() == RRType::NS() &&
+                last_rrset_->getName() != zone_name) {
+                node->setFlag(ZoneNode::FLAG_CALLBACK);
+                // If it is DNAME, we have a callback as well here
+            } else if (last_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 (last_rrset_->getType() == RRType::NSEC3PARAM() &&
+                last_rrset_->getName() == zone_name) {
+                // We know rrset has exactly one RDATA
+                const generic::NSEC3PARAM& param =
+                    dynamic_cast<const generic::NSEC3PARAM&>
+                      (last_rrset_->getRdataIterator()->getCurrent());
+
+                NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
+                if (nsec3_data == NULL) {
+                    nsec3_data = NSEC3Data::create(local_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: "
+                                  << last_rrset_->toText());
+                    }
+                }
+            } else if (last_rrset_->getType() == RRType::NSEC()) {
+                // If it is NSEC signed zone, so we put a flag there
+                // (flag is enough)
+                zone_data.setSigned(true);
+            }
+        }
+
+        last_rrset_ = rrset;
+    }
+
+    result::Result addRRsig(const ConstRRsetPtr sig_rrset,
+                            const Name& zone_name, ZoneData& zone_data)
+    {
+        // Check consistency of the type covered.
+        // We know the RRset isn't empty, so the following check is safe.
+        RdataIteratorPtr rit = sig_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: "
+                          << sig_rrset->toText());
+            }
+        }
+
+        addRdataSet(zone_name, zone_data, ConstRRsetPtr(), sig_rrset);
         return (result::SUCCESS);
     }
 
@@ -433,13 +498,14 @@ public:
             arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
 
         if (rrset->getType() == RRType::NSEC3()) {
-            return (addNSEC3(rrset, zone_data));
+            addRdataSet(zone_name, zone_data, rrset, ConstRRsetPtr());
+            return (result::SUCCESS);
         }
 
         // RRSIGs are special in various points, so we handle it in a
         // separate dedicated method.
         if (rrset->getType() == RRType::RRSIG()) {
-            return (addRRsig(rrset, zone_data));
+            return (addRRsig(rrset, zone_name, zone_data));
         }
 
         // Add wildcards possibly contained in the owner name to the domain
@@ -448,72 +514,7 @@ public:
         // guarantee.  (see also the note for contextCheck() below).
         addWildcards(zone_name, zone_data, rrset->getName());
 
-        ZoneNode* node;
-        zone_data.insertName(local_mem_sgmt_, rrset->getName(), &node);
-
-        RdataSet* set = 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, set);
-
-        if (RdataSet::find(set, rrset->getType()) != NULL) {
-            return (result::EXIST);
-        }
-
-        RdataEncoder encoder;
-        RdataSet *new_set = RdataSet::create(local_mem_sgmt_, encoder,
-                                         rrset, ConstRRsetPtr());
-        new_set->next = set;
-        node->setData(new_set);
-
-        // 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(local_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);
-        }
+        addRdataSet(zone_name, zone_data, rrset, ConstRRsetPtr());
 
         return (result::SUCCESS);
     }
@@ -549,9 +550,16 @@ InMemoryClient::InMemoryClientImpl::load(
         local_mem_sgmt_, ZoneData::create(local_mem_sgmt_, zone_name), rrclass_);
     scoped_ptr<ZoneData> tmp(holder.get());
 
+    assert(!last_rrset_);
+
     rrset_installer(boost::bind(&InMemoryClientImpl::addFromLoad, this,
                                 _1, zone_name, tmp.get()));
 
+    // Add any last RRset that was left
+    addRdataSet(zone_name, *tmp.get(), ConstRRsetPtr(), ConstRRsetPtr());
+
+    assert(!last_rrset_);
+
     // If the zone is NSEC3-signed, check if it has NSEC3PARAM
     if (tmp->isNSEC3Signed()) {
         // Note: origin_data_ is set on creation of ZoneData, and the load