BIND 10 master, updated. 1af6565d9d5f789c82ececbf83ca725cf3208b3f [master] Merge branch 'trac1608'
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Mar 13 21:56:20 UTC 2012
The branch, master has been updated
via 1af6565d9d5f789c82ececbf83ca725cf3208b3f (commit)
via a8c1ced88d2e49827f5082555e335e209fd32ef8 (commit)
via 2cc4d39e5c74092c2fda2d9be3682b432243099b (commit)
via ae873233be8b119b0495b98d843fada53949ab58 (commit)
via 62a3bb1472df7765c40525dfe9c07ab949fa4a72 (commit)
via bf8e9e937a158253853013a6f316573d3b53e3ee (commit)
via a2d27b3d05763fa267d6f19cff7468ac86063a38 (commit)
via 0f0ab5b692e5670b0ff6774d0003a5f676a79dcc (commit)
via b87b288e07b97629fa80b36b0cfa0833727b785a (commit)
via a979801041c9a650f2b24a4c39498df80d72b75a (commit)
via 97bca3e1ce5cb69be9fb6fcbc9bf976fb05e3a2d (commit)
via 27ec89e237865a6f9d92639256291acade7af69f (commit)
via 004375eb0955a2eb1fbfa5d5988cdc5b10ae441f (commit)
via 6c506ce59394354abe02a650579ec0517867a3a4 (commit)
via 8efd8d022529b4d5178329bee08a6909d5823c04 (commit)
via f64dbc690b23b7354c8c67ca0add3b2ae07fcd0c (commit)
via d4935b95254646ab389e43517bf3cf61373d23e0 (commit)
via 08ac200f2f3e15548a81b4c252b72fc8ac72edbe (commit)
via fe8e4b87d5b493fa2cf41f1e8dce1b5809c27679 (commit)
via 1030e6751920c754fa9d02360ef95342541b85b6 (commit)
from 55d44fc94c8e0ddae7b9b383e7e29b9514ce23ff (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 1af6565d9d5f789c82ececbf83ca725cf3208b3f
Merge: 55d44fc a8c1ced
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Mar 13 14:39:21 2012 -0700
[master] Merge branch 'trac1608'
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/memory_datasrc.cc | 502 ++++++++++++++++++--
src/lib/datasrc/memory_datasrc.h | 6 +
src/lib/datasrc/rbnode_rrset.h | 155 +++---
src/lib/datasrc/rbtree.h | 6 +-
src/lib/datasrc/tests/testdata/contexttest.zone | 42 ++-
.../datasrc/tests/zone_finder_context_unittest.cc | 90 ++++
src/lib/datasrc/zone.h | 7 +
7 files changed, 680 insertions(+), 128 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 33ab82f..477baa5 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -12,16 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <algorithm>
-#include <map>
-#include <utility>
-#include <cctype>
-#include <cassert>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/bind.hpp>
-
#include <exceptions/exceptions.h>
#include <dns/name.h>
@@ -39,6 +29,17 @@
#include <datasrc/data_source.h>
#include <datasrc/factory.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+#include <algorithm>
+#include <map>
+#include <utility>
+#include <cctype>
+#include <cassert>
+
using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
@@ -47,8 +48,15 @@ using boost::scoped_ptr;
namespace isc {
namespace datasrc {
+using namespace internal;
+
namespace {
// Some type aliases
+
+// RRset specified for this implementation
+typedef boost::shared_ptr<internal::RBNodeRRset> RBNodeRRsetPtr;
+typedef boost::shared_ptr<const internal::RBNodeRRset> ConstRBNodeRRsetPtr;
+
/*
* Each domain consists of some RRsets. They will be looked up by the
* RRType.
@@ -60,19 +68,44 @@ namespace {
* critical place and map has better interface for the lookups, so we use
* that.
*/
-typedef map<RRType, ConstRRsetPtr> Domain;
+typedef map<RRType, ConstRBNodeRRsetPtr> Domain;
typedef Domain::value_type DomainPair;
typedef boost::shared_ptr<Domain> DomainPtr;
// The tree stores domains
typedef RBTree<Domain> DomainTree;
typedef RBNode<Domain> DomainNode;
+// In the following dedicated namespace we define a few application-specific
+// RBNode flags. We use a separate namespace so we can consolidate the
+// definition in a single place, which would hopefully reduce the risk of
+// collisions.
+// (Note: it's within an unnamed namespace, so effectively private.)
+namespace domain_flag {
+// This flag indicates the node is at a "wildcard level" (in short, it means
+// one of the node's immediate child is a wildcard). See addWildcards()
+// for more details.
+const DomainNode::Flags WILD = DomainNode::FLAG_USER1;
+
+// This flag is used for additional record shortcut. If a node has this
+// flag, it's under a zone cut for a delegation to a child zone.
+// Note: for a statically built zone this information is stable, but if we
+// change the implementation to be dynamically modifiable, it may not be
+// realistic to keep this flag update for all affected nodes, and we may
+// have to reconsider the mechanism.
+const DomainNode::Flags GLUE = DomainNode::FLAG_USER2;
+};
+
// Separate storage for NSEC3 RRs (and their RRSIGs). It's an STL map
// from string to the NSEC3 RRset. The map key is the first label
// (upper cased) of the owner name of the corresponding NSEC3 (i.e., map
// value). We can use the standard string comparison (if the comparison
// target is also upper cased) due to the nature of NSEC3 owner names.
-typedef map<string, ConstRRsetPtr> NSEC3Map;
+//
+// Note: We maintain the RRsets in the form of RBNodeRRset even if they are
+// not stored in the RB tree. The reason is because comparison can be
+// more efficient if we make sure all RRsets returned from this module are
+// of the same type.
+typedef map<string, ConstRBNodeRRsetPtr> NSEC3Map;
typedef NSEC3Map::value_type NSEC3Pair;
// Actual zone data: Essentially a set of zone's RRs. This is defined as
@@ -106,6 +139,275 @@ struct ZoneData {
};
}
+namespace internal {
+
+/// \brief An encapsulation type for a pointer of an additional node
+/// associated with an \c RBNodeRRset object.
+///
+/// Currently this is defined as a structure only so that it can declared
+/// in rbnode_rrset.h; this is essentially a pointer to \c DomainNode.
+/// In future, however, this structure may have other attributes.
+struct AdditionalNodeInfo {
+ AdditionalNodeInfo(DomainNode* node) : node_(node) {}
+ DomainNode* node_;
+};
+
+//
+// RBNodeRRset details
+//
+struct RBNodeRRsetImpl {
+public:
+ RBNodeRRsetImpl(const ConstRRsetPtr& rrset) : rrset_(rrset)
+ {}
+
+ ConstRRsetPtr rrset_; ///< Underlying RRset
+ scoped_ptr<vector<AdditionalNodeInfo> > additionals_;
+};
+
+RBNodeRRset::RBNodeRRset(const ConstRRsetPtr& rrset) :
+ impl_(new RBNodeRRsetImpl(rrset))
+{
+}
+
+RBNodeRRset::~RBNodeRRset() {
+ delete impl_;
+}
+
+unsigned int
+RBNodeRRset::getRdataCount() const {
+ return (impl_->rrset_->getRdataCount());
+}
+
+const Name&
+RBNodeRRset::getName() const {
+ return (impl_->rrset_->getName());
+}
+
+const RRClass&
+RBNodeRRset::getClass() const {
+ return (impl_->rrset_->getClass());
+}
+
+const RRType&
+RBNodeRRset::getType() const {
+ return (impl_->rrset_->getType());
+}
+
+const RRTTL&
+RBNodeRRset::getTTL() const {
+ return (impl_->rrset_->getTTL());
+}
+
+void
+RBNodeRRset::setName(const Name&) {
+ isc_throw(isc::NotImplemented, "RBNodeRRset::setName() not supported");
+}
+
+void
+RBNodeRRset::setTTL(const RRTTL&) {
+ isc_throw(isc::NotImplemented, "RBNodeRRset::setTTL() not supported");
+}
+
+string
+RBNodeRRset::toText() const {
+ return (impl_->rrset_->toText());
+}
+
+unsigned int
+RBNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
+ return (impl_->rrset_->toWire(renderer));
+}
+
+unsigned int
+RBNodeRRset::toWire(isc::util::OutputBuffer& buffer) const {
+ return (impl_->rrset_->toWire(buffer));
+}
+
+void
+RBNodeRRset::addRdata(ConstRdataPtr) {
+ isc_throw(isc::NotImplemented, "RBNodeRRset::addRdata() not supported");
+}
+
+void
+RBNodeRRset::addRdata(const Rdata&) {
+ isc_throw(isc::NotImplemented, "RBNodeRRset::addRdata() not supported");
+}
+
+RdataIteratorPtr
+RBNodeRRset::getRdataIterator() const {
+ return (impl_->rrset_->getRdataIterator());
+}
+
+RRsetPtr
+RBNodeRRset::getRRsig() const {
+ return (impl_->rrset_->getRRsig());
+}
+
+void
+RBNodeRRset::addRRsig(const ConstRdataPtr& rdata) {
+ AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
+ p->addRRsig(rdata);
+}
+
+void
+RBNodeRRset::addRRsig(const RdataPtr& rdata) {
+ AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
+ p->addRRsig(rdata);
+}
+
+void
+RBNodeRRset::addRRsig(const AbstractRRset& sigs) {
+ AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
+ p->addRRsig(sigs);
+}
+
+void
+RBNodeRRset::addRRsig(const ConstRRsetPtr& sigs) {
+ AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
+ p->addRRsig(sigs);
+}
+
+void
+RBNodeRRset::addRRsig(const RRsetPtr& sigs) {
+ AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
+ p->addRRsig(sigs);
+}
+
+void
+RBNodeRRset::removeRRsig() {
+ AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
+ p->removeRRsig();
+}
+
+ConstRRsetPtr
+RBNodeRRset::getUnderlyingRRset() const {
+ return (impl_->rrset_);
+}
+
+void
+RBNodeRRset::addAdditionalNode(const AdditionalNodeInfo& additional) {
+ // Lazy initialization
+ if (!impl_->additionals_) {
+ impl_->additionals_.reset(new vector<AdditionalNodeInfo>);
+ }
+ impl_->additionals_->push_back(additional);
+}
+
+const vector<AdditionalNodeInfo>*
+RBNodeRRset::getAdditionalNodes() const {
+ return (impl_->additionals_.get());
+}
+
+void
+RBNodeRRset::copyAdditionalNodes(RBNodeRRset& dst) const {
+ if (impl_->additionals_) {
+ dst.impl_->additionals_.reset(
+ new vector<AdditionalNodeInfo>(impl_->additionals_->begin(),
+ impl_->additionals_->end()));
+ }
+}
+
+} // end of internal
+
+namespace {
+// Specialized version of ZoneFinder::ResultContext, which specifically
+// holds rrset in the form of RBNodeRRset.
+struct RBNodeResultContext {
+ /// \brief Constructor
+ ///
+ /// The first three parameters correspond to those of
+ /// ZoneFinder::ResultContext. If node is non NULL, it specifies the
+ /// found RBNode in the search.
+ RBNodeResultContext(ZoneFinder::Result code_param,
+ ConstRBNodeRRsetPtr rrset_param,
+ ZoneFinder::FindResultFlags flags_param,
+ const DomainNode* node) :
+ code(code_param), rrset(rrset_param), flags(flags_param),
+ found_node(node)
+ {}
+
+ const ZoneFinder::Result code;
+ const ConstRBNodeRRsetPtr rrset;
+ const ZoneFinder::FindResultFlags flags;
+ const DomainNode* const found_node;
+};
+}
+
+class InMemoryZoneFinder::Context : public ZoneFinder::Context {
+public:
+ /// \brief Constructor.
+ ///
+ /// Note that we don't have a specific constructor for the findAll() case.
+ /// For (successful) type ANY query, found_node points to the
+ /// corresponding RB node, which is recorded within this specialized
+ /// context.
+ Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
+ const RBNodeResultContext& result) :
+ ZoneFinder::Context(finder, options,
+ ResultContext(result.code, result.rrset,
+ result.flags)),
+ rrset_(result.rrset), found_node_(result.found_node)
+ {}
+
+protected:
+ virtual void getAdditionalImpl(const vector<RRType>& requested_types,
+ vector<ConstRRsetPtr>& result)
+ {
+ if (!rrset_) {
+ // In this case this context should encapsulate the result of
+ // findAll() and found_node_ should point to a valid answer node.
+ if (found_node_ == NULL || found_node_->isEmpty()) {
+ isc_throw(isc::Unexpected,
+ "Invalid call to in-memory getAdditional: caller's "
+ "bug or broken zone");
+ }
+ BOOST_FOREACH(const DomainPair& dom_it, *found_node_->getData()) {
+ getAdditionalForRRset(*dom_it.second, requested_types,
+ result);
+ }
+ } else {
+ getAdditionalForRRset(*rrset_, requested_types, result);
+ }
+ }
+
+private:
+ // Retrieve additional RRsets for a given RRset associated in the context.
+ // The process is straightforward: it examines the link to
+ // AdditionalNodeInfo vector (if set), and find RRsets of the requested
+ // type for each node.
+ static void getAdditionalForRRset(const RBNodeRRset& rrset,
+ const vector<RRType>& requested_types,
+ vector<ConstRRsetPtr>& result)
+ {
+ const vector<AdditionalNodeInfo>* additionals_ =
+ rrset.getAdditionalNodes();
+ if (additionals_ == NULL) {
+ return;
+ }
+ const bool glue_ok = (rrset.getType() == RRType::NS());
+ BOOST_FOREACH(const AdditionalNodeInfo& additional, *additionals_) {
+ assert(additional.node_ != NULL);
+ if (additional.node_->isEmpty()) {
+ continue;
+ }
+ if (!glue_ok && additional.node_->getFlag(domain_flag::GLUE)) {
+ continue;
+ }
+ BOOST_FOREACH(const RRType& rrtype, requested_types) {
+ Domain::const_iterator found =
+ additional.node_->getData()->find(rrtype);
+ if (found != additional.node_->getData()->end()) {
+ // TODO: wildcard consideration
+ result.push_back(found->second);
+ }
+ }
+ }
+ }
+
+ const ConstRBNodeRRsetPtr rrset_;
+ const DomainNode* const found_node_;
+};
+
// Private data and hidden methods of InMemoryZoneFinder
struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// Constructor
@@ -114,8 +416,6 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
zone_data_(new ZoneData(origin_))
{}
- static const DomainNode::Flags DOMAINFLAG_WILD = DomainNode::FLAG_USER1;
-
// Information about the zone
RRClass zone_class_;
Name origin_;
@@ -154,7 +454,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
&node));
assert(result == DomainTree::SUCCESS ||
result == DomainTree::ALREADYEXISTS);
- node->setFlag(DOMAINFLAG_WILD);
+ node->setFlag(domain_flag::WILD);
// Ensure a separate level exists for the wildcard name.
// Note: for 'name' itself we do this later anyway, but the
@@ -407,7 +707,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
return (result::EXIST);
}
- zone_data.nsec3_data_->map_.insert(NSEC3Pair(fst_label, rrset));
+ zone_data.nsec3_data_->map_.insert(
+ NSEC3Pair(fst_label, ConstRBNodeRRsetPtr(new RBNodeRRset(rrset))));
return (result::SUCCESS);
}
@@ -416,7 +717,9 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
* access is without the impl_-> and it will get inlined anyway.
*/
// Implementation of InMemoryZoneFinder::add
- result::Result add(const ConstRRsetPtr& rawrrset, ZoneData& zone_data) {
+ result::Result add(const ConstRRsetPtr& rawrrset, ZoneData& zone_data,
+ vector<RBNodeRRset*>* need_additionals)
+ {
// Sanitize input. This will cause an exception to be thrown
// if the input RRset is empty.
addValidation(rawrrset);
@@ -428,7 +731,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// ... although instead of loading the RRset directly, we encapsulate
// it within an RBNodeRRset. This contains additional information that
// speeds up queries.
- ConstRRsetPtr rrset(new internal::RBNodeRRset(rawrrset));
+ RBNodeRRsetPtr rrset(new RBNodeRRset(rawrrset));
if (rrset->getType() == RRType::NSEC3()) {
return (addNSEC3(rrset, zone_data));
@@ -485,6 +788,12 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
node->setFlag(DomainNode::FLAG_CALLBACK);
}
+ if (need_additionals != NULL &&
+ (rrset->getType() == RRType::NS() ||
+ rrset->getType() == RRType::MX())) {
+ need_additionals->push_back(rrset.get());
+ }
+
// 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() &&
@@ -513,8 +822,10 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
* Same as above, but it checks the return value and if it already exists,
* it throws.
*/
- void addFromLoad(const ConstRRsetPtr& set, ZoneData* zone_data) {
- switch (add(set, *zone_data)) {
+ void addFromLoad(const ConstRRsetPtr& set, ZoneData* zone_data,
+ vector<RBNodeRRset*>* need_additionals)
+ {
+ switch (add(set, *zone_data, need_additionals)) {
case result::EXIST:
LOG_ERROR(logger, DATASRC_MEM_DUP_RRSET).
arg(set->getName()).arg(set->getType());
@@ -540,7 +851,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
{}
const DomainNode* zonecut_node_;
const DomainNode* dname_node_;
- ConstRRsetPtr rrset_;
+ ConstRBNodeRRsetPtr rrset_;
const FindOptions options_;
};
@@ -613,18 +924,19 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
* It is designed for wildcard case, where we create the rrsets
* dynamically.
*/
- static ConstRRsetPtr prepareRRset(const Name& name,
- const ConstRRsetPtr& rrset,
- bool rename, FindOptions options)
+ static ConstRBNodeRRsetPtr prepareRRset(const Name& name,
+ const ConstRBNodeRRsetPtr& rrset,
+ bool rename, FindOptions options)
{
if (rename) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_RENAME).
arg(rrset->getName()).arg(name);
- RRsetPtr result(new RRset(name, rrset->getClass(),
- rrset->getType(), rrset->getTTL()));
+ RRsetPtr result_base(new RRset(name, rrset->getClass(),
+ rrset->getType(),
+ rrset->getTTL()));
for (RdataIteratorPtr i(rrset->getRdataIterator()); !i->isLast();
i->next()) {
- result->addRdata(i->getCurrent());
+ result_base->addRdata(i->getCurrent());
}
if ((options & FIND_DNSSEC) != 0) {
ConstRRsetPtr sig_rrset = rrset->getRRsig();
@@ -638,9 +950,11 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
{
result_sig->addRdata(i->getCurrent());
}
- result->addRRsig(result_sig);
+ result_base->addRRsig(result_sig);
}
}
+ RBNodeRRsetPtr result(new RBNodeRRset(result_base));
+ rrset->copyAdditionalNodes(*result);
return (result);
} else {
return (rrset);
@@ -651,8 +965,13 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// account wildcard matches and DNSSEC information. We set the NSEC/NSEC3
// flag when applicable regardless of the find option; the caller would
// simply ignore these when they didn't request DNSSEC related results.
- ResultContext createFindResult(Result code, ConstRRsetPtr rrset,
- bool wild = false) const
+ // When the optional parameter 'node' is given (in which case it should be
+ // non NULL), it means it's a result of ANY query and the context should
+ // remember the matched node.
+ RBNodeResultContext createFindResult(Result code,
+ ConstRBNodeRRsetPtr rrset,
+ bool wild = false,
+ const DomainNode* node = NULL) const
{
FindResultFlags flags = RESULT_DEFAULT;
if (wild) {
@@ -662,13 +981,13 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
zone_data_->nsec3_data_) {
flags = flags | RESULT_NSEC3_SIGNED;
}
- return (ZoneFinder::ResultContext(code, rrset, flags));
+ return (RBNodeResultContext(code, rrset, flags, node));
}
// Implementation of InMemoryZoneFinder::find
- ZoneFinder::ResultContext find(const Name& name, RRType type,
- std::vector<ConstRRsetPtr>* target,
- const FindOptions options) const
+ RBNodeResultContext find(const Name& name, RRType type,
+ std::vector<ConstRRsetPtr>* target,
+ const FindOptions options) const
{
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).
arg(type);
@@ -722,7 +1041,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
NameComparisonResult::SUPERDOMAIN) {
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).
arg(name);
- return (createFindResult(NXRRSET, ConstRRsetPtr()));
+ return (createFindResult(NXRRSET, ConstRBNodeRRsetPtr()));
}
/*
@@ -733,7 +1052,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
* not match according to 4.3.3 of RFC 1034 (the query name
* is known to exist).
*/
- if (node->getFlag(DOMAINFLAG_WILD)) {
+ if (node->getFlag(domain_flag::WILD)) {
/* Should we cancel this match?
*
* If we compare with some node and get a common ancestor,
@@ -761,7 +1080,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
getLastComparisonResult().getCommonLabels() > 1) {
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEM_WILDCARD_CANCEL).arg(name);
- return (createFindResult(NXDOMAIN, ConstRRsetPtr(),
+ return (createFindResult(NXDOMAIN,
+ ConstRBNodeRRsetPtr(),
false));
}
const Name wildcard(Name("*").concatenate(
@@ -769,7 +1089,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
DomainTree::Result result =
zone_data_->domains_.find(wildcard, &node);
/*
- * Otherwise, why would the DOMAINFLAG_WILD be there if
+ * Otherwise, why would the domain_flag::WILD be there if
* there was no wildcard under it?
*/
assert(result == DomainTree::EXACTMATCH);
@@ -787,7 +1107,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
case DomainTree::NOTFOUND:
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).
arg(name);
- return (createFindResult(NXDOMAIN, ConstRRsetPtr(), false));
+ return (createFindResult(NXDOMAIN, ConstRBNodeRRsetPtr(),
+ false));
case DomainTree::EXACTMATCH: // This one is OK, handle it
break;
default:
@@ -800,7 +1121,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
if (node->isEmpty()) {
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
arg(name);
- return (createFindResult(NXRRSET, ConstRRsetPtr(), rename));
+ return (createFindResult(NXRRSET, ConstRBNodeRRsetPtr(), rename));
}
Domain::const_iterator found;
@@ -832,7 +1153,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
}
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
arg(name);
- return (createFindResult(SUCCESS, ConstRRsetPtr(), rename));
+ return (createFindResult(SUCCESS, ConstRBNodeRRsetPtr(), rename,
+ node));
}
found = node->getData()->find(type);
@@ -858,7 +1180,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// No exact match or CNAME. Return NXRRSET.
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NXRRSET).arg(type).
arg(name);
- return (createFindResult(NXRRSET, ConstRRsetPtr(), rename));
+ return (createFindResult(NXRRSET, ConstRBNodeRRsetPtr(), rename));
}
};
@@ -890,8 +1212,8 @@ InMemoryZoneFinder::find(const Name& name, const RRType& type,
const FindOptions options)
{
return (ZoneFinderContextPtr(
- new Context(*this, options,
- impl_->find(name, type, NULL, options))));
+ new Context(*this, options, impl_->find(name, type, NULL,
+ options))));
}
ZoneFinderContextPtr
@@ -901,8 +1223,7 @@ InMemoryZoneFinder::findAll(const Name& name,
{
return (ZoneFinderContextPtr(
new Context(*this, options, impl_->find(name, RRType::ANY(),
- &target, options),
- target)));
+ &target, options))));
}
ZoneFinder::FindNSEC3Result
@@ -934,7 +1255,7 @@ InMemoryZoneFinder::findNSEC3(const Name& name, bool recursive) {
const unsigned int olabels = impl_->origin_.getLabelCount();
const unsigned int qlabels = name.getLabelCount();
- ConstRRsetPtr covering_proof; // placeholder of the next closer proof
+ ConstRBNodeRRsetPtr covering_proof; // 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.
@@ -984,20 +1305,101 @@ InMemoryZoneFinder::findNSEC3(const Name& name, bool recursive) {
result::Result
InMemoryZoneFinder::add(const ConstRRsetPtr& rrset) {
- return (impl_->add(rrset, *impl_->zone_data_));
+ return (impl_->add(rrset, *impl_->zone_data_, NULL));
+}
+
+namespace {
+// This should eventually be more generalized.
+const Name
+getAdditionalName(RRType rrtype, const rdata::Rdata& rdata) {
+ if (rrtype == RRType::NS()) {
+ const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
+ return (ns.getNSName());
+ } else if (rrtype == RRType::MX()) {
+ const generic::MX& mx = dynamic_cast<const generic::MX&>(rdata);
+ return (mx.getMXName());
+ }
+ // In our usage this shouldn't happen.
+ assert(false);
+}
+
+bool
+checkZoneCut(const DomainNode& node, pair<bool, bool>* arg) {
+ // We are only interested in the highest zone cut information.
+ // Ignore others and continue the search.
+ if (arg->first) {
+ return (false);
+ }
+ // Once we encounter a delegation point due to a DNAME, anything under it
+ // should be hidden.
+ if (node.getData()->find(RRType::DNAME()) != node.getData()->end()) {
+ return (true);
+ } else if (node.getData()->find(RRType::NS()) != node.getData()->end()) {
+ arg->first = true;
+ arg->second = true;
+ return (false);
+ }
+ return (false);
}
+void
+addAdditional(RBNodeRRset* rrset, ZoneData* zone_data) {
+ RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
+ for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
+ // For each domain name that requires additional section processing
+ // in each RDATA, search the tree for the name and remember it if
+ // found. If the name is under a zone cut (for a delegation to a
+ // child zone), mark the node as "GLUE", so we can selectively
+ // include/exclude them when we use it.
+
+ // TODO: wildcard
+ RBTreeNodeChain<Domain> node_path;
+ DomainNode* node = NULL;
+ // The callback argument is a pair of bools: the first is a flag to
+ // only check the highest cut; the second one records whether the
+ // search goes under a zone cut.
+ pair<bool, bool> callback_arg(false, false);
+ const DomainTree::Result result =
+ zone_data->domains_.find(
+ getAdditionalName(rrset->getType(),
+ rdata_iterator->getCurrent()),
+ &node, node_path, checkZoneCut, &callback_arg);
+ if (result == DomainTree::EXACTMATCH) {
+ assert(node != NULL);
+ if (callback_arg.second ||
+ (node->getFlag(DomainNode::FLAG_CALLBACK) &&
+ node->getData()->find(RRType::NS()) !=
+ node->getData()->end())) {
+ // The node is under or at a zone cut; mark it as a glue.
+ node->setFlag(domain_flag::GLUE);
+ }
+ // Note that node may be empty. We should keep it in the list
+ // in case we dynamically update the tree and it becomes non empty
+ // (which is not supported yet)
+ rrset->addAdditionalNode(node);
+ }
+ }
+}
+}
void
InMemoryZoneFinder::load(const string& filename) {
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
arg(filename);
- // Load it into temporary zone data
+ // Load it into temporary zone data. As we build the zone, we record
+ // the (RBNode)RRsets that needs to be associated with additional
+ // information in 'need_additionals'.
+ vector<RBNodeRRset*> need_additionals;
scoped_ptr<ZoneData> tmp(new ZoneData(getOrigin()));
masterLoad(filename.c_str(), getOrigin(), getClass(),
boost::bind(&InMemoryZoneFinderImpl::addFromLoad, impl_,
- _1, tmp.get()));
+ _1, tmp.get(), &need_additionals));
+
+ // For each RRset in need_additionals, identify the corresponding
+ // RBnode for additional processing and associate it in the RRset.
+ for_each(need_additionals.begin(), need_additionals.end(),
+ boost::bind(addAdditional, _1, tmp.get()));
// If the zone is NSEC3-signed, check if it has NSEC3PARAM
if (tmp->nsec3_data_) {
diff --git a/src/lib/datasrc/memory_datasrc.h b/src/lib/datasrc/memory_datasrc.h
index 9ee6747..fbeb2c3 100644
--- a/src/lib/datasrc/memory_datasrc.h
+++ b/src/lib/datasrc/memory_datasrc.h
@@ -218,6 +218,12 @@ private:
// extracts the pointer to data and puts it into the iterator.
// The access is read only.
friend class InMemoryClient;
+
+ /// \brief In-memory version of finder context.
+ ///
+ /// The implementation (and any specialized interface) is completely local
+ /// to the InMemoryZoneFinder class, so it's defined as private
+ class Context;
};
/// \brief A data source client that holds all necessary data in memory.
diff --git a/src/lib/datasrc/rbnode_rrset.h b/src/lib/datasrc/rbnode_rrset.h
index 968e7a8..f687919 100644
--- a/src/lib/datasrc/rbnode_rrset.h
+++ b/src/lib/datasrc/rbnode_rrset.h
@@ -24,11 +24,27 @@
#include <util/buffer.h>
#include <string>
+#include <vector>
namespace isc {
namespace datasrc {
namespace internal {
+/// \brief The actual content of \c RBNodeRRset
+///
+/// This is defined in the namespace-scope (not hidden in the main class)
+/// so that the In-memory data source implementation can refer to it.
+struct RBNodeRRsetImpl;
+
+// Forward declaration of an opaque data type defined and used within the
+// implementation. This is public only because it needs to be used within
+// the in-memory data source implementation, but conceptually this is a
+// private type for the in-memory data source implementation.
+// Note that the definition of the structure is still hidden within the
+// implementation, so, basically, a normal application should never be able
+// to use it directly even if it peeks into the "internal" namespace.
+struct AdditionalNodeInfo;
+
/// \brief Special RRset for optimizing memory datasource requirement
///
/// To speed up the performance of the in-memory data source, at load time
@@ -84,11 +100,10 @@ public:
/// Creates an RBNodeRRset from the pointer to the RRset passed to it.
///
/// \param rrset Pointer to underlying RRset encapsulated by this object.
- explicit RBNodeRRset(const isc::dns::ConstRRsetPtr& rrset) : rrset_(rrset)
- {}
+ explicit RBNodeRRset(const isc::dns::ConstRRsetPtr& rrset);
/// \brief Destructor
- virtual ~RBNodeRRset() {}
+ virtual ~RBNodeRRset();
// Getter and Setter Methods
//
@@ -96,64 +111,34 @@ public:
// setter methods thrown an exception - this specialisation of the RRset
// object does not expect the underlying RRset to be modified.
- virtual unsigned int getRdataCount() const {
- return (rrset_->getRdataCount());
- }
+ virtual unsigned int getRdataCount() const;
- virtual const isc::dns::Name& getName() const {
- return (rrset_->getName());
- }
+ virtual const isc::dns::Name& getName() const;
- virtual const isc::dns::RRClass& getClass() const {
- return (rrset_->getClass());
- }
+ virtual const isc::dns::RRClass& getClass() const;
- virtual const isc::dns::RRType& getType() const {
- return (rrset_->getType());
- }
+ virtual const isc::dns::RRType& getType() const;
- virtual const isc::dns::RRTTL& getTTL() const {
- return (rrset_->getTTL());
- }
+ virtual const isc::dns::RRTTL& getTTL() const;
- virtual void setName(const isc::dns::Name&) {
- isc_throw(isc::NotImplemented, "RBNodeRRset::setName() not supported");
- }
+ virtual void setName(const isc::dns::Name&);
- virtual void setTTL(const isc::dns::RRTTL&) {
- isc_throw(isc::NotImplemented, "RBNodeRRset::setTTL() not supported");
- }
+ virtual void setTTL(const isc::dns::RRTTL&);
- virtual std::string toText() const {
- return (rrset_->toText());
- }
+ virtual std::string toText() const;
virtual unsigned int toWire(
- isc::dns::AbstractMessageRenderer& renderer) const {
- return (rrset_->toWire(renderer));
- }
+ isc::dns::AbstractMessageRenderer& renderer) const;
- virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const {
- return (rrset_->toWire(buffer));
- }
+ virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const;
- virtual void addRdata(isc::dns::rdata::ConstRdataPtr) {
- isc_throw(isc::NotImplemented,
- "RBNodeRRset::addRdata() not supported");
- }
+ virtual void addRdata(isc::dns::rdata::ConstRdataPtr);
- virtual void addRdata(const isc::dns::rdata::Rdata&) {
- isc_throw(isc::NotImplemented,
- "RBNodeRRset::addRdata() not supported");
- }
+ virtual void addRdata(const isc::dns::rdata::Rdata&);
- virtual isc::dns::RdataIteratorPtr getRdataIterator() const {
- return (rrset_->getRdataIterator());
- }
+ virtual isc::dns::RdataIteratorPtr getRdataIterator() const;
- virtual isc::dns::RRsetPtr getRRsig() const {
- return (rrset_->getRRsig());
- }
+ virtual isc::dns::RRsetPtr getRRsig() const;
// With all the RRsig methods, we have the problem that we store the
// underlying RRset using a ConstRRsetPtr - a pointer to a "const" RRset -
@@ -161,45 +146,65 @@ public:
// this by temporarily violating the "const" nature of the RRset to add the
// data.
- virtual void addRRsig(const isc::dns::rdata::ConstRdataPtr& rdata) {
- AbstractRRset* p = const_cast<AbstractRRset*>(rrset_.get());
- p->addRRsig(rdata);
- }
+ virtual void addRRsig(const isc::dns::rdata::ConstRdataPtr& rdata);
+
+ virtual void addRRsig(const isc::dns::rdata::RdataPtr& rdata);
+
+ virtual void addRRsig(const AbstractRRset& sigs);
- virtual void addRRsig(const isc::dns::rdata::RdataPtr& rdata) {
- AbstractRRset* p = const_cast<AbstractRRset*>(rrset_.get());
- p->addRRsig(rdata);
- }
+ virtual void addRRsig(const isc::dns::ConstRRsetPtr& sigs);
- virtual void addRRsig(const AbstractRRset& sigs) {
- AbstractRRset* p = const_cast<AbstractRRset*>(rrset_.get());
- p->addRRsig(sigs);
- }
+ virtual void addRRsig(const isc::dns::RRsetPtr& sigs);
- virtual void addRRsig(const isc::dns::ConstRRsetPtr& sigs) {
- AbstractRRset* p = const_cast<AbstractRRset*>(rrset_.get());
- p->addRRsig(sigs);
- }
+ virtual void removeRRsig();
- virtual void addRRsig(const isc::dns::RRsetPtr& sigs) {
- AbstractRRset* p = const_cast<AbstractRRset*>(rrset_.get());
- p->addRRsig(sigs);
- }
+ /// \brief Associate a link to an RB node of the additional record.
+ ///
+ /// This method adds a given opaque object that holds a link to an RB node
+ /// of the underlying in-memory data source that is corresponding to an
+ /// RDATA of this RRset.
+ ///
+ /// This method is exposed as public so it can be used within the in-memory
+ /// data source implementation, and only for that purpose.
+ ///
+ /// \param additional An opaque \c AdditionalNodeInfo object to be
+ /// associated with this RRset.
+ void addAdditionalNode(const AdditionalNodeInfo& additional);
- virtual void removeRRsig() {
- AbstractRRset* p = const_cast<AbstractRRset*>(rrset_.get());
- p->removeRRsig();
- }
+ /// \brief Return a pointer to the list (vector) of additional RB nodes.
+ ///
+ /// This method returns a pointer to a vector storing the opaque
+ /// \c AdditionalNodeInfo object that may be possibly set in this RRset.
+ /// Not all RRsets are associated with additional nodes; if no
+ /// such node is stored, this method returns NULL.
+ ///
+ /// Like \c addAdditionalNode(), this method is exposed as public only for
+ /// the in-memory data source implementation.
+ ///
+ /// \return A pointer to the associated vector of \c AdditionalNodeInfo;
+ /// NULL if no additional nodes are associated to this RRset.
+ const std::vector<AdditionalNodeInfo>* getAdditionalNodes() const;
+
+ /// \brief Copy the list of additional RB nodes to another RRset.
+ ///
+ /// This method copies the internal list (an STL vector in the actual
+ /// implementation) of additional RB nodes for this RRset to another
+ /// \c RBNodeRRset object. The copy destination is generally expected to
+ /// be newly created and have an empty list, but this method does not
+ /// check the condition. If the destination already has a non empty list,
+ /// the existing entries will be lost.
+ ///
+ /// \param dst The \c RBNodeRRset object to which the additional
+ /// RB node list is to be copied.
+ void copyAdditionalNodes(RBNodeRRset& dst) const;
/// \brief Return underlying RRset pointer
///
/// ... mainly for testing.
- isc::dns::ConstRRsetPtr getUnderlyingRRset() const {
- return (rrset_);
- }
+ isc::dns::ConstRRsetPtr getUnderlyingRRset() const;
private:
- isc::dns::ConstRRsetPtr rrset_; ///< Underlying RRset
+ RBNodeRRsetImpl* impl_;
};
} // namespace internal
diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h
index 4757a45..161affb 100644
--- a/src/lib/datasrc/rbtree.h
+++ b/src/lib/datasrc/rbtree.h
@@ -123,7 +123,8 @@ public:
/// set to on by the \c setFlag() method.
enum Flags {
FLAG_CALLBACK = 1, ///< Callback enabled. See \ref callback
- FLAG_USER1 = 0x80000000U ///< Application specific flag
+ FLAG_USER1 = 0x80000000U, ///< Application specific flag
+ FLAG_USER2 = 0x40000000U ///< Application specific flag
};
private:
// Some flag values are expected to be used for internal purposes
@@ -131,7 +132,8 @@ private:
// limit the settable flags via the \c setFlag() method to those
// explicitly defined in \c Flags. This constant represents all
// such flags.
- static const uint32_t SETTABLE_FLAGS = (FLAG_CALLBACK | FLAG_USER1);
+ static const uint32_t SETTABLE_FLAGS = (FLAG_CALLBACK | FLAG_USER1 |
+ FLAG_USER2);
public:
diff --git a/src/lib/datasrc/tests/testdata/contexttest.zone b/src/lib/datasrc/tests/testdata/contexttest.zone
index 7227ced..425866a 100644
--- a/src/lib/datasrc/tests/testdata/contexttest.zone
+++ b/src/lib/datasrc/tests/testdata/contexttest.zone
@@ -1,7 +1,7 @@
;; 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. 22 3600 300 3600000 3600
+example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. 56 3600 300 3600000 3600
example.org. 3600 IN NS ns1.example.org.
example.org. 3600 IN NS ns2.example.org.
example.org. 3600 IN MX 1 mx1.example.org.
@@ -28,8 +28,48 @@ ns2.a.example.org. 3600 IN A 192.0.2.6
ns2.a.example.org. 3600 IN AAAA 2001:db8::6
mx.a.example.org. 3600 IN A 192.0.2.7
+;; delegation, one of its NS names is at zone cut.
+b.example.org. 3600 IN NS ns.b.example.org.
+b.example.org. 3600 IN NS b.example.org.
+b.example.org. 3600 IN AAAA 2001:db8::8
+
+ns.b.example.org. 3600 IN A 192.0.2.9
+
+;; The MX name is at a zone cut. shouldn't be included in the
+;; additional section.
+mxatcut.example.org. 3600 IN MX 1 b.example.org.
+
+;; delegation, one of its NS names is under a DNAME delegation point;
+;; another is at that point; and yet another is under DNAME below a
+;; zone cut.
+c.example.org. 3600 IN NS ns.dname.example.org.
+c.example.org. 3600 IN NS dname.example.org.
+c.example.org. 3600 IN NS ns.deepdname.example.org.
+ns.dname.example.org. 3600 IN A 192.0.2.11
+dname.example.org. 3600 IN A 192.0.2.12
+ns.deepdname.example.org. 3600 IN AAAA 2001:db8::9
+
+;; delegation, one of its NS name is at an empty non terminal.
+d.example.org. 3600 IN NS ns.empty.example.org.
+d.example.org. 3600 IN NS ns1.example.org.
+;; by adding these two we can create an empty RB node for
+;; ns.empty.example.org in the in-memory zone
+foo.ns.empty.example.org. 3600 IN A 192.0.2.13
+bar.ns.empty.example.org. 3600 IN A 192.0.2.14
+
+;; delegation; the NS name matches a wildcard (and there's no exact match)
+e.example.org. 3600 IN NS ns.wild.example.org.
+*.wild.example.org. 3600 IN A 192.0.2.15
+
+;; additional for an answer RRset (MX) as a result of wildcard
+;; expansion
+*.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
+
;; CNAME
alias.example.org. 3600 IN CNAME cname.example.org.
;; DNAME
dname.example.org. 3600 IN DNAME dname.example.com.
+
+;; DNAME under a NS (strange one)
+deepdname.c.example.org. 3600 IN DNAME deepdname.example.com.
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index 5639f26..9134307 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -214,6 +214,81 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegation) {
result_sets_.begin(), result_sets_.end());
}
+TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
+ // Similar to the previous case, but one of the NS addresses is at the
+ // zone cut.
+
+ // XXX: the current database-based data source incorrectly rejects this
+ // setup (see #1771)
+ if (GetParam() == createSQLite3Client) {
+ return;
+ }
+
+ ZoneFinderContextPtr ctx = finder_->find(Name("www.b.example.org"),
+ RRType::SOA());
+ EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
+
+ ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+ rrsetsCheck("b.example.org. 3600 IN AAAA 2001:db8::8\n"
+ "ns.b.example.org. 3600 IN A 192.0.2.9\n",
+ result_sets_.begin(), result_sets_.end());
+}
+
+TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithDname) {
+ // Delegation: One of the NS names under a DNAME delegation; another
+ // is at the delegation point; yet another is under DNAME below a zone cut.
+ // The first should be hidden.
+ ZoneFinderContextPtr ctx = finder_->find(Name("www.c.example.org"),
+ RRType::TXT());
+ EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
+
+ ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+ rrsetsCheck("dname.example.org. 3600 IN A 192.0.2.12\n"
+ "ns.deepdname.example.org. 3600 IN AAAA 2001:db8::9\n",
+ result_sets_.begin(), result_sets_.end());
+}
+
+TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithEmptyName) {
+ // One of NS names is at an empty non terminal node. It shouldn't cause
+ // any disruption.
+ ZoneFinderContextPtr ctx = finder_->find(Name("www.d.example.org"),
+ RRType::A());
+ EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
+
+ ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+ rrsetsCheck("ns1.example.org. 3600 IN A 192.0.2.1\n"
+ "ns1.example.org. 3600 IN AAAA 2001:db8::1\n",
+ result_sets_.begin(), result_sets_.end());
+}
+
+TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithWild) {
+ // The NS name needs to be expanded by a wildcard. Currently it doesn't
+ // work for the optimized in-memory version.
+ if (GetParam() == createInMemoryClient) {
+ return;
+ }
+
+ ZoneFinderContextPtr ctx = finder_->find(Name("www.e.example.org"),
+ RRType::AAAA());
+ EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
+ ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+ rrsetsCheck("ns.wild.example.org. 3600 IN A 192.0.2.15\n",
+ result_sets_.begin(), result_sets_.end());
+}
+
+TEST_P(ZoneFinderContextTest, getAdditionalDelegationForWild) {
+ // additional for an answer RRset (MX) as a result of wildcard expansion.
+ // note the difference from the previous test. in this case wildcard
+ // applies to the owner name of the answer, not the owner name of the
+ // additional.
+ ZoneFinderContextPtr ctx = finder_->find(Name("mx.wildmx.example.org"),
+ RRType::MX());
+ EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
+ ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+ rrsetsCheck("mx1.example.org. 3600 IN A 192.0.2.10\n",
+ result_sets_.begin(), result_sets_.end());
+}
+
TEST_P(ZoneFinderContextTest, getAdditionalMX) {
// Similar to the previous cases, but for MX addresses. The test zone
// contains MX name under a zone cut. Its address shouldn't be returned.
@@ -239,6 +314,21 @@ TEST_P(ZoneFinderContextTest, getAdditionalMX) {
result_sets_.begin(), result_sets_.end());
}
+TEST_P(ZoneFinderContextTest, getAdditionalMXAtZoneCut) {
+ // XXX: the current database-based data source incorrectly rejects this
+ // setup (see #1771)
+ if (GetParam() == createSQLite3Client) {
+ return;
+ }
+
+ ZoneFinderContextPtr ctx = finder_->find(Name("mxatcut.example.org."),
+ RRType::MX());
+ EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
+
+ ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+ EXPECT_TRUE(result_sets_.empty());
+}
+
TEST_P(ZoneFinderContextTest, getAdditionalWithSIG) {
// Similar to the AuthNS test, but the original find() requested DNSSEC
// RRSIGs. Then additional records will also have RRSIGs.
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index 361a03a..c705279 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -252,6 +252,13 @@ public:
/// call resulted in SUCCESS or DELEGATION. Otherwise this method
/// does nothing.
///
+ /// \note The additional RRsets returned via method are limited to
+ /// ones contained in the zone which the corresponding find/findAll
+ /// call searched (possibly including glues under a zone cut where
+ /// they are applicable). If the caller needs to get out-of-zone
+ /// additional RRsets, it needs to explicitly finds them by
+ /// identifying the corresponding zone and calls \c find() for it.
+ ///
/// \param requested_types A vector of RR types for desired additional
/// RRsets.
/// \param result A vector to which any found additional RRsets are
More information about the bind10-changes
mailing list