Commit 8660a77a authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2282merge] Merge branch 'trac2218' into trac2282merge

with fixing Conflicts:
	src/lib/datasrc/memory/zone_finder.cc
	src/lib/datasrc/memory/zone_finder.h
parents 59c096cd d0a83e52
......@@ -373,7 +373,6 @@ private:
}
}
public:
/// \brief returns if the node is a subtree's root node
///
/// This method takes a node and returns \c true if it is the root
......@@ -391,6 +390,7 @@ public:
/// This method never throws an exception.
const DomainTreeNode<T>* getSubTreeRoot() const;
public:
/// \brief returns the parent of the root of its subtree
///
/// This method takes a node and returns the parent of the root of
......@@ -401,14 +401,6 @@ public:
/// This method never throws an exception.
const DomainTreeNode<T>* getUpperNode() const;
/// \brief returns the largest node of this node's subtree
///
/// This method takes a node and returns the largest node in its
/// subtree.
///
/// This method never throws an exception.
const DomainTreeNode<T>* getLargestInSubTree() const;
/// \brief return the next node which is bigger than current node
/// in the same subtree
///
......@@ -577,17 +569,6 @@ DomainTreeNode<T>::getUpperNode() const {
return (getSubTreeRoot()->getParent());
}
template <typename T>
const DomainTreeNode<T>*
DomainTreeNode<T>::getLargestInSubTree() const {
const DomainTreeNode<T>* sroot = getSubTreeRoot();
while (sroot->getRight() != NULL) {
sroot = sroot->getRight();
}
return (sroot);
}
template <typename T>
isc::dns::LabelSequence
DomainTreeNode<T>::getAbsoluteLabels(
......@@ -720,14 +701,26 @@ public:
/// The default constructor.
///
/// \exception None
DomainTreeNodeChain() : node_count_(0), last_compared_(NULL),
DomainTreeNodeChain() : level_count_(0), last_compared_(NULL),
// XXX: meaningless initial values:
last_comparison_(0, 0,
isc::dns::NameComparisonResult::EQUAL)
{}
/// \brief Copy constructor.
///
/// \exception None
DomainTreeNodeChain(const DomainTreeNodeChain<T>& other) :
level_count_(other.level_count_),
last_compared_(other.last_compared_),
last_comparison_(other.last_comparison_)
{
for (size_t i = 0; i < level_count_; i++) {
nodes_[i] = other.nodes_[i];
}
}
private:
DomainTreeNodeChain(const DomainTreeNodeChain<T>&);
DomainTreeNodeChain<T>& operator=(const DomainTreeNodeChain<T>&);
//@}
......@@ -739,7 +732,7 @@ public:
///
/// \exception None
void clear() {
node_count_ = 0;
level_count_ = 0;
last_compared_ = NULL;
}
......@@ -780,7 +773,7 @@ public:
/// chain, 0 will be returned.
///
/// \exception None
unsigned int getLevelCount() const { return (node_count_); }
size_t getLevelCount() const { return (level_count_); }
/// \brief return the absolute name for the node which this
/// \c DomainTreeNodeChain currently refers to.
......@@ -798,11 +791,11 @@ public:
const DomainTreeNode<T>* top_node = top();
isc::dns::Name absolute_name = top_node->getName();
int node_count = node_count_ - 1;
while (node_count > 0) {
top_node = nodes_[node_count - 1];
size_t level = level_count_ - 1;
while (level > 0) {
top_node = nodes_[level - 1];
absolute_name = absolute_name.concatenate(top_node->getName());
--node_count;
--level;
}
return (absolute_name);
}
......@@ -816,7 +809,7 @@ private:
/// \brief return whether node chain has node in it.
///
/// \exception None
bool isEmpty() const { return (node_count_ == 0); }
bool isEmpty() const { return (level_count_ == 0); }
/// \brief return the top node for the node chain
///
......@@ -826,7 +819,7 @@ private:
/// \exception None
const DomainTreeNode<T>* top() const {
assert(!isEmpty());
return (nodes_[node_count_ - 1]);
return (nodes_[level_count_ - 1]);
}
/// \brief pop the top node from the node chain
......@@ -837,7 +830,7 @@ private:
/// \exception None
void pop() {
assert(!isEmpty());
--node_count_;
--level_count_;
}
/// \brief add the node into the node chain
......@@ -848,8 +841,8 @@ private:
///
/// \exception None
void push(const DomainTreeNode<T>* node) {
assert(node_count_ < RBT_MAX_LEVEL);
nodes_[node_count_++] = node;
assert(level_count_ < RBT_MAX_LEVEL);
nodes_[level_count_++] = node;
}
private:
......@@ -858,7 +851,7 @@ private:
// it's also equal to the possible maximum level.
const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS;
int node_count_;
size_t level_count_;
const DomainTreeNode<T>* nodes_[RBT_MAX_LEVEL];
const DomainTreeNode<T>* last_compared_;
isc::dns::NameComparisonResult last_comparison_;
......@@ -1313,12 +1306,20 @@ public:
const DomainTreeNode<T>*
previousNode(DomainTreeNodeChain<T>& node_path) const;
/// \brief return the largest node in the tree of trees.
///
/// \throw none
///
/// \return A \c DomainTreeNode that is the largest node in the
/// tree. If there are no nodes, then \c NULL is returned.
const DomainTreeNode<T>* largestNode() const;
/// \brief Get the total number of nodes in the tree
///
/// It includes nodes internally created as a result of adding a domain
/// name that is a subdomain of an existing node of the tree.
/// This function is mainly intended to be used for debugging.
int getNodeCount() const { return (node_count_); }
uint32_t getNodeCount() const { return (node_count_); }
/// \name Debug function
//@{
......@@ -1450,8 +1451,15 @@ private:
//@}
typename DomainTreeNode<T>::DomainTreeNodePtr root_;
/// the node count of current tree
unsigned int node_count_;
/// the node count of current tree.
///
/// Note: uint32_t may look awkward, but we intentionally choose it so
/// that needsReturnEmptyNode_ below won't make cause extra padding
/// in 64-bit machines (and we can minimize the total size of this class).
/// 2^32 - 1 should be a reasonable max of possible number of nodes.
uint32_t node_count_;
/// search policy for domaintree
const bool needsReturnEmptyNode_;
};
......@@ -1757,6 +1765,24 @@ DomainTree<T>::previousNode(DomainTreeNodeChain<T>& node_path) const {
return (node);
}
template <typename T>
const DomainTreeNode<T>*
DomainTree<T>::largestNode() const {
const DomainTreeNode<T>* node = root_.get();
while (node != NULL) {
// We go right first, then down.
if (node->getRight() != NULL) {
node = node->getRight();
} else if (node->getDown() != NULL) {
node = node->getDown();
} else {
break;
}
}
return (node);
}
template <typename T>
typename DomainTree<T>::Result
DomainTree<T>::insert(util::MemorySegment& mem_sgmt,
......
......@@ -324,6 +324,7 @@ public:
if (nsec3_data == NULL) {
nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
zone_data.setNSEC3Data(nsec3_data);
zone_data.setSigned(true);
} else {
size_t salt_len = nsec3_data->getSaltLen();
const uint8_t* salt_data = nsec3_data->getSaltData();
......@@ -331,7 +332,12 @@ public:
if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
(nsec3_rdata.getIterations() != nsec3_data->iterations) ||
(salt_data_2.size() != salt_len) ||
(salt_data_2.size() != salt_len)) {
isc_throw(AddError,
"NSEC3 with inconsistent parameters: " <<
rrset->toText());
}
if ((salt_len > 0) &&
(std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
isc_throw(AddError,
"NSEC3 with inconsistent parameters: " <<
......@@ -339,20 +345,10 @@ public:
}
}
// Make just the NSEC3 hash label uppercase, and insert the
// entire name into the NSEC3Data ZoneTree.
string fst_label = rrset->getName().split(0, 1).toText(true);
transform(fst_label.begin(), fst_label.end(), fst_label.begin(),
::toupper);
const string rest = rrset->getName().split(1).toText(true);
ZoneNode* node;
nsec3_data->insertName(mem_sgmt_, Name(fst_label + "." + rest), &node);
nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
RdataEncoder encoder;
// We assume that rrsig has already been checked to match rrset
// by the caller.
RdataSet* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
RdataSet* old_set = node->setData(set);
if (old_set != NULL) {
......@@ -417,6 +413,7 @@ public:
if (nsec3_data == NULL) {
nsec3_data = NSEC3Data::create(mem_sgmt_, param);
zone_data.setNSEC3Data(nsec3_data);
zone_data.setSigned(true);
} else {
size_t salt_len = nsec3_data->getSaltLen();
const uint8_t* salt_data = nsec3_data->getSaltData();
......@@ -424,7 +421,13 @@ public:
if ((param.getHashalg() != nsec3_data->hashalg) ||
(param.getIterations() != nsec3_data->iterations) ||
(salt_data_2.size() != salt_len) ||
(salt_data_2.size() != salt_len)) {
isc_throw(AddError,
"NSEC3PARAM with inconsistent parameters: "
<< rrset->toText());
}
if ((salt_len > 0) &&
(std::memcmp(&salt_data_2[0],
salt_data, salt_len) != 0)) {
isc_throw(AddError,
......@@ -702,10 +705,10 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
return (DataSourceClient::FindResult(result.code, finder));
}
isc::datasrc::memory::ZoneTable::FindResult
InMemoryClient::findZone2(const isc::dns::Name& zone_name) const {
const ZoneData*
InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
return (result);
return (result.zone_data);
}
result::Result
......
......@@ -20,7 +20,7 @@
#include <datasrc/iterator.h>
#include <datasrc/client.h>
#include <datasrc/memory/zone_table.h>
#include <datasrc/zonetable.h>
#include <datasrc/memory/zone_data.h>
#include <string>
......@@ -209,12 +209,14 @@ public:
virtual isc::datasrc::DataSourceClient::FindResult
findZone(const isc::dns::Name& name) const;
/// Returns a \c ZoneTable result that best matches the given name.
/// Returns a \c ZoneData in the result that best matches the given
/// name.
///
/// This derived version of the method never throws an exception.
/// For other details see \c DataSourceClient::findZone().
virtual isc::datasrc::memory::ZoneTable::FindResult
findZone2(const isc::dns::Name& name) const;
/// This is mainly intended for use in unit tests and should not be
/// used in other code.
///
/// \throws none
const ZoneData* findZoneData(const isc::dns::Name& name);
/// \brief Implementation of the getIterator method
virtual isc::datasrc::ZoneIteratorPtr
......
example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012092602 7200 3600 2592000 1200
example.org. 86400 IN RRSIG SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
example.org. 86400 IN NS ns.example.org.
example.org. 86400 IN RRSIG NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
example.org. 86400 IN DNSKEY 256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
example.org. 86400 IN RRSIG DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
example.org. 0 IN NSEC3PARAM 1 0 10 -
example.org. 0 IN RRSIG NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
ns.example.org. 86400 IN A 192.0.2.1
ns.example.org. 86400 IN RRSIG A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 1 0 10 - RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3 1 0 10 - 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
......@@ -23,13 +23,11 @@
#include <dns/name.h>
#include <dns/rrset.h>
#include <dns/rrtype.h>
#include <util/buffer.h>
#include <util/encode/base32hex.h>
#include <util/hash/sha1.h>
#include <dns/nsec3hash.h>
#include <datasrc/logger.h>
#include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>
#include <algorithm>
......@@ -38,9 +36,6 @@
using namespace isc::dns;
using namespace isc::datasrc::memory;
using namespace isc::datasrc;
using namespace isc::util;
using namespace isc::util::encode;
using namespace isc::util::hash;
namespace isc {
namespace datasrc {
......@@ -192,6 +187,27 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
return (false);
}
/// Creates a NSEC3 ConstRRsetPtr for the given ZoneNode inside the
/// NSEC3 tree, for the given RRClass.
///
/// It asserts that the node contains data (RdataSet) and is of type
/// NSEC3.
///
/// \param node The ZoneNode inside the NSEC3 tree
/// \param rrclass The RRClass as passed by the client
ConstRRsetPtr
createNSEC3RRset(const ZoneNode* node, const RRClass& rrclass) {
const RdataSet* rdataset = node->getData();
// Only NSEC3 ZoneNodes are allowed to be passed to this method. We
// assert that these have data, and also are of type NSEC3.
assert(rdataset != NULL);
assert(rdataset->type == RRType::NSEC3());
// Create the RRset. Note the DNSSEC flag: NSEC3 implies DNSSEC.
return (createTreeNodeRRset(node, rdataset, rrclass,
ZoneFinder::FIND_DNSSEC));
}
// convenience function to fill in the final details
//
// Set up ZoneFinderResultContext object as a return value of find(),
......@@ -504,44 +520,6 @@ FindNodeResult findNode(const ZoneData& zone_data,
} // end anonymous namespace
inline void
iterateSHA1(SHA1Context* ctx, const uint8_t* input, size_t inlength,
const uint8_t* salt, size_t saltlen,
uint8_t output[SHA1_HASHSIZE])
{
SHA1Reset(ctx);
SHA1Input(ctx, input, inlength);
SHA1Input(ctx, salt, saltlen); // this works whether saltlen == or > 0
SHA1Result(ctx, output);
}
std::string
InMemoryZoneFinderNSEC3Calculate(const Name& name,
const uint16_t iterations,
const uint8_t* salt,
size_t salt_len) {
// We first need to normalize the name by converting all upper case
// characters in the labels to lower ones.
OutputBuffer obuf(Name::MAX_WIRE);
Name name_copy(name);
name_copy.downcase();
name_copy.toWire(obuf);
const uint8_t* const salt_buf = (salt_len > 0) ? salt : NULL;
std::vector<uint8_t> digest(SHA1_HASHSIZE);
uint8_t* const digest_buf = &digest[0];
SHA1Context sha1_ctx;
iterateSHA1(&sha1_ctx, static_cast<const uint8_t*>(obuf.getData()),
obuf.getLength(), salt_buf, salt_len, digest_buf);
for (unsigned int n = 0; n < iterations; ++n) {
iterateSHA1(&sha1_ctx, digest_buf, SHA1_HASHSIZE,
salt_buf, salt_len,
digest_buf);
}
return (encodeBase32Hex(digest));
}
/// \brief Specialization of the ZoneFinder::Context for the in-memory finder.
///
......@@ -827,60 +805,91 @@ InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3).arg(name).
arg(recursive ? "recursive" : "non-recursive");
uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
const LabelSequence origin_ls(zone_data_.getOriginNode()->
getAbsoluteLabels(labels_buf));
const LabelSequence name_ls(name);
if (!zone_data_.isNSEC3Signed()) {
isc_throw(DataSourceError,
"findNSEC3 attempt for non NSEC3 signed zone: " <<
getOrigin() << "/" << getClass());
origin_ls << "/" << getClass());
}
const NameComparisonResult cmp_result = name.compare(getOrigin());
const NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
// This would be a programming mistake, as ZoneData::isNSEC3Signed()
// should check this.
assert(nsec3_data != NULL);
const ZoneTree& tree = nsec3_data->getNSEC3Tree();
if (tree.getNodeCount() == 0) {
isc_throw(DataSourceError,
"findNSEC3 attempt but zone has no NSEC3 RRs: " <<
origin_ls << "/" << getClass());
}
const NameComparisonResult cmp_result = name_ls.compare(origin_ls);
if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: "
<< name << ", zone: " << getOrigin() << "/"
<< name_ls << ", zone: " << origin_ls << "/"
<< getClass());
}
// Convenient shortcuts
const ZoneFinder::FindOptions options =
ZoneFinder::FIND_DNSSEC; // NSEC3 implies DNSSEC
const unsigned int olabels = getOrigin().getLabelCount();
const unsigned int olabels = origin_ls.getLabelCount();
const unsigned int qlabels = name.getLabelCount();
const NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
// placeholder of the next closer proof
const ZoneNode* covering_node(NULL);
// Now we'll first look up the origin node and initialize orig_chain
// with it.
ZoneChain orig_chain;
const ZoneNode* node(NULL);
ZoneTree::Result result =
tree.find<void*>(origin_ls, &node, orig_chain, NULL, NULL);
if (result != ZoneTree::EXACTMATCH) {
// If the origin node doesn't exist, simply fail.
isc_throw(DataSourceError,
"findNSEC3 attempt but zone has no NSEC3 RRs: " <<
origin_ls << "/" << getClass());
}
const boost::scoped_ptr<NSEC3Hash> hash
(NSEC3Hash::create(nsec3_data->hashalg,
nsec3_data->iterations,
nsec3_data->getSaltData(),
nsec3_data->getSaltLen()));
const ZoneNode* covering_node(NULL); // placeholder of the next closer proof
// Examine all names from the query name to the origin name, stripping
// the deepest label one by one, until we find a name that has a matching
// NSEC3 hash.
for (unsigned int labels = qlabels; labels >= olabels; --labels) {
const std::string hlabel = (nsec3_calculate_)
((labels == qlabels ?
name : name.split(qlabels - labels, labels)),
nsec3_data->iterations,
nsec3_data->getSaltData(),
nsec3_data->getSaltLen());
const Name& hname = (labels == qlabels ?
name : name.split(qlabels - labels, labels));
const std::string hlabel = hash->calculate(hname);
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3_TRYHASH).
arg(name).arg(labels).arg(hlabel);
const ZoneTree& tree = nsec3_data->getNSEC3Tree();
ZoneNode* node(NULL);
ZoneChain chain;
node = NULL;
ZoneChain chain(orig_chain);
ZoneTree::Result result =
tree.find(Name(hlabel + "." + getOrigin().toText()), &node, chain);
// Now, make a label sequence relative to the origin.
const Name hlabel_name(hlabel);
LabelSequence hlabel_ls(hlabel_name);
// Remove trailing '.' making it relative
hlabel_ls.stripRight(1);
// Find hlabel relative to the orig_chain.
result = tree.find<void*>(hlabel_ls, &node, chain, NULL, NULL);
if (result == ZoneTree::EXACTMATCH) {
// We found an exact match.
RdataSet* set = node->getData();
ConstRRsetPtr closest = createTreeNodeRRset(node, set, getClass(),
options);
ConstRRsetPtr next =
createTreeNodeRRset(covering_node,
(covering_node != NULL ?
covering_node->getData() : NULL),
getClass(), options);
ConstRRsetPtr closest = createNSEC3RRset(node, getClass());
ConstRRsetPtr next;
if (covering_node != NULL) {
next = createNSEC3RRset(covering_node, getClass());
}
LOG_DEBUG(logger, DBG_TRACE_BASIC,
DATASRC_MEM_FINDNSEC3_MATCH).arg(name).arg(labels).
......@@ -888,37 +897,19 @@ InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
return (FindNSEC3Result(true, labels, closest, next));
} else {
const NameComparisonResult& last_cmp =
chain.getLastComparisonResult();
const ZoneNode* last_node = chain.getLastComparedNode();
assert(last_cmp.getOrder() != 0);
// find() finished in between one of these and last_node:
const ZoneNode* previous_node = last_node->predecessor();
const ZoneNode* next_node = last_node->successor();
// If the given hash is larger than the largest stored hash or
// the first label doesn't match the target, identify the "previous"
// hash value and remember it as the candidate next closer proof.
if (((last_cmp.getOrder() < 0) && (previous_node == NULL)) ||
((last_cmp.getOrder() > 0) && (next_node == NULL))) {
covering_node = last_node->getLargestInSubTree();
} else {
// Otherwise, H(found_entry-1) < given_hash < H(found_entry).
// The covering proof is the first one (and it's valid
// because found is neither begin nor end)
covering_node = previous_node;
while ((covering_node = tree.previousNode(chain)) != NULL &&
covering_node->isEmpty()) {
;
}
if (covering_node == NULL) {
covering_node = tree.largestNode();
}
if (!recursive) { // in non recursive mode, we are done.
ConstRRsetPtr closest =
createTreeNodeRRset(covering_node,
(covering_node != NULL ?
covering_node->getData() :
NULL),
getClass(), options);
if (closest) {
ConstRRsetPtr closest;
if (covering_node != NULL) {
closest = createNSEC3RRset(covering_node, getClass());
LOG_DEBUG(logger, DBG_TRACE_BASIC,
DATASRC_MEM_FINDNSEC3_COVER).
arg(name).arg(*closest);
......