From: Mukund Sivaraman Date: Wed, 5 Sep 2012 05:32:02 +0000 (+0530) Subject: [2108] Save RRsets and call RdataSet::create() with their corresponding RRSIGs X-Git-Tag: trac2351_base~70^2~103 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d074626ee7d65dee4011443bbf0be2b16bb44411;p=thirdparty%2Fkea.git [2108] Save RRsets and call RdataSet::create() with their corresponding RRSIGs --- diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc index ea4eba318f..7aab10c461 100644 --- a/src/lib/datasrc/memory/memory_client.cc +++ b/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( - rit->getCurrent()).typeCovered(); - for (rit->next(); !rit->isLast(); rit->next()) { - if (dynamic_cast( - 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(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( @@ -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( + 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 + (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& 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( + rit->getCurrent()).typeCovered(); + for (rit->next(); !rit->isLast(); rit->next()) { + if (dynamic_cast( + 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 - (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& 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 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