BIND 10 master, updated. 47f69905aac05aa6f619cb143a81f206b396975a Merge branch 'trac550'
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Feb 9 19:55:13 UTC 2011
The branch, master has been updated
via 47f69905aac05aa6f619cb143a81f206b396975a (commit)
via ca368d008315b135fa2ad3ff366aa5ae15eb4d12 (commit)
via c5dfa657c2431f3daea2dcc49741f96383f0d18d (commit)
via 1d018cd8a62fdf430f5322db023badc030cee6ee (commit)
via f436c5c20d296c17f8afcea1e6ba6242a9d09929 (commit)
via dcfa4914665900dc475ac1dbe98336d8daab1c61 (commit)
via 389cf02a183ea2223d1c44f68fc2f764ca5d69ea (commit)
via b832c3c975bcae66717ce28e392a189887b6f08f (commit)
via f1885e6e7b4d2688be602b189eece51e4e649f42 (commit)
via 9bfbbabf77cb41babe425c9006c050edcd3cda7b (commit)
via 3715569dde8e4770696ba2552fb545d2cff81b87 (commit)
via c336287b3e5f3262b4f85ec45e7b38b893c0b2b8 (commit)
via bc1b548a3828f5cd722496dd8eb5c09fc1f95187 (commit)
from 7356673c98e3ca56e1ed4adecab4818c018ccf81 (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 47f69905aac05aa6f619cb143a81f206b396975a
Merge: ca368d0 c5dfa65
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Feb 9 11:52:40 2011 -0800
Merge branch 'trac550'
commit ca368d008315b135fa2ad3ff366aa5ae15eb4d12
Merge: 7356673 1d018cd
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Feb 9 11:52:23 2011 -0800
[master] Merge branch 'trac550' with resolving conflicts.
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/memory_datasrc.cc | 116 +++++++++---
src/lib/datasrc/rbtree.h | 92 ++++++++--
src/lib/datasrc/tests/memory_datasrc_unittest.cc | 225 +++++++++++++++-------
src/lib/datasrc/tests/rbtree_unittest.cc | 44 ++++-
4 files changed, 355 insertions(+), 122 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 0691926..fdef888 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -36,7 +36,7 @@ struct MemoryZone::MemoryZoneImpl {
// Constructor
MemoryZoneImpl(const RRClass& zone_class, const Name& origin) :
zone_class_(zone_class), origin_(origin), origin_data_(NULL),
- domains_(true)
+ domains_(true)
{
// We create the node for origin (it needs to exist anyway in future)
domains_.insert(origin, &origin_data_);
@@ -62,6 +62,7 @@ struct MemoryZone::MemoryZoneImpl {
// The tree stores domains
typedef RBTree<Domain> DomainTree;
typedef RBNode<Domain> DomainNode;
+ static const DomainNode::Flags DOMAINFLAG_WILD = DomainNode::FLAG_USER1;
// Information about the zone
RRClass zone_class_;
@@ -72,6 +73,47 @@ struct MemoryZone::MemoryZoneImpl {
// The actual zone data
DomainTree domains_;
+ // Add the necessary magic for any wildcard contained in 'name'
+ // (including itself) to be found in the zone.
+ //
+ // In order for wildcard matching to work correctly in find(),
+ // we must ensure that a node for the wildcarding level exists in the
+ // backend RBTree.
+ // E.g. if the wildcard name is "*.sub.example." then we must ensure
+ // that "sub.example." exists and is marked as a wildcard level.
+ // Note: the "wildcarding level" is for the parent name of the wildcard
+ // name (such as "sub.example.").
+ //
+ // We also perform the same trick for empty wild card names possibly
+ // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
+ void addWildcards(DomainTree& domains, const Name& name) {
+ Name wname(name);
+ const unsigned int labels(wname.getLabelCount());
+ const unsigned int origin_labels(origin_.getLabelCount());
+ for (unsigned int l = labels;
+ l > origin_labels;
+ --l, wname = wname.split(1)) {
+ if (wname.isWildcard()) {
+ // Ensure a separate level exists for the wildcard name.
+ // Note: for 'name' itself we do this later anyway, but the
+ // overhead should be marginal because wildcard names should
+ // be rare.
+ DomainNode* node;
+ DomainTree::Result result(domains.insert(wname.split(1),
+ &node));
+ assert(result == DomainTree::SUCCESS ||
+ result == DomainTree::ALREADYEXISTS);
+
+ // Ensure a separate level exists for the "wildcarding" name,
+ // and mark the node as "wild".
+ result = domains.insert(wname, &node);
+ assert(result == DomainTree::SUCCESS ||
+ result == DomainTree::ALREADYEXISTS);
+ node->setFlag(DOMAINFLAG_WILD);
+ }
+ }
+ }
+
/*
* Does some checks in context of the data that are already in the zone.
* Currently checks for forbidden combinations of RRsets in the same
@@ -114,13 +156,10 @@ struct MemoryZone::MemoryZoneImpl {
}
}
- /*
- * Implementation of longer methods. We put them here, because the
- * access is without the impl_-> and it will get inlined anyway.
- */
- // Implementation of MemoryZone::add
- result::Result add(const ConstRRsetPtr& rrset, DomainTree* domains) {
- // Sanitize input
+ // Validate rrset before adding it to the zone. If something is wrong
+ // it throws an exception. It doesn't modify the zone, and provides
+ // the strong exception guarantee.
+ void addValidation(const ConstRRsetPtr rrset) {
if (!rrset) {
isc_throw(NullRRset, "The rrset provided is NULL");
}
@@ -137,26 +176,55 @@ struct MemoryZone::MemoryZoneImpl {
<< rrset->getName());
}
- Name name(rrset->getName());
- NameComparisonResult compare(origin_.compare(name));
+ NameComparisonResult compare(origin_.compare(rrset->getName()));
if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
compare.getRelation() != NameComparisonResult::EQUAL)
{
- isc_throw(OutOfZone, "The name " << name <<
+ isc_throw(OutOfZone, "The name " << rrset->getName() <<
" is not contained in zone " << origin_);
}
+
+ // Some RR types do not really work well with a wildcard.
+ // Even though the protocol specifically doesn't completely ban such
+ // usage, we refuse to load a zone containing such RR in order to
+ // keep the lookup logic simpler and more predictable.
+ // See RFC4592 and (for DNAME) draft-ietf-dnsext-rfc2672bis-dname
+ // for more technical background. Note also that BIND 9 refuses
+ // NS at a wildcard, so in that sense we simply provide compatible
+ // behavior.
+ if (rrset->getName().isWildcard()) {
+ if (rrset->getType() == RRType::NS()) {
+ isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
+ rrset->getName());
+ }
+ if (rrset->getType() == RRType::DNAME()) {
+ isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
+ rrset->getName());
+ }
+ }
+ }
+
+ /*
+ * Implementation of longer methods. We put them here, because the
+ * access is without the impl_-> and it will get inlined anyway.
+ */
+ // Implementation of MemoryZone::add
+ result::Result add(const ConstRRsetPtr& rrset, DomainTree* domains) {
+ // Sanitize input
+ addValidation(rrset);
+
+ // Add wildcards possibly contained in the owner name to the domain
+ // tree.
+ // Note: this can throw an exception, breaking strong exception
+ // guarantee. (see also the note for contextCheck() below).
+ addWildcards(*domains, rrset->getName());
+
// Get the node
DomainNode* node;
- switch (domains->insert(name, &node)) {
- // Just check it returns reasonable results
- case DomainTree::SUCCESS:
- case DomainTree::ALREADYEXISTS:
- break;
- // Something odd got out
- default:
- assert(0);
- }
- assert(node != NULL);
+ DomainTree::Result result = domains->insert(rrset->getName(), &node);
+ // Just check it returns reasonable results
+ assert((result == DomainTree::SUCCESS ||
+ result == DomainTree::ALREADYEXISTS) && node!= NULL);
// Now get the domain
DomainPtr domain;
@@ -183,10 +251,10 @@ struct MemoryZone::MemoryZoneImpl {
// indicating the need for callback in find().
if (rrset->getType() == RRType::NS() &&
rrset->getName() != origin_) {
- node->enableCallback();
+ node->setFlag(DomainNode::FLAG_CALLBACK);
// If it is DNAME, we have a callback as well here
} else if (rrset->getType() == RRType::DNAME()) {
- node->enableCallback();
+ node->setFlag(DomainNode::FLAG_CALLBACK);
}
return (result::SUCCESS);
@@ -349,7 +417,7 @@ struct MemoryZone::MemoryZoneImpl {
// If the node callback is enabled, this may be a zone cut. If it
// has a NS RR, we should return a delegation, but not in the apex.
- if (node->isCallbackEnabled() && node != origin_data_) {
+ if (node->getFlag(DomainNode::FLAG_CALLBACK) && node != origin_data_) {
found = node->getData()->find(RRType::NS());
if (found != node->getData()->end()) {
return (FindResult(DELEGATION, found->second));
diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h
index 8ceb7e0..bd04066 100644
--- a/src/lib/datasrc/rbtree.h
+++ b/src/lib/datasrc/rbtree.h
@@ -23,6 +23,8 @@
/// issue, the design and interface are not fixed, and RBTree isn't ready
/// to be used as a base data structure by other modules.
+#include <exceptions/exceptions.h>
+
#include <dns/name.h>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
@@ -110,6 +112,29 @@ public:
/// \brief Alias for shared pointer to the data.
typedef boost::shared_ptr<T> NodeDataPtr;
+ /// Node flags.
+ ///
+ /// Each flag value defines a non default property for a specific node.
+ /// These are defined as bitmask type values for the convenience of
+ /// internal implementation, but applications are expected to use
+ /// each flag separately via the enum definitions.
+ ///
+ /// All (settable) flags are off by default; they must be explicitly
+ /// set to on by the \c setFlag() method.
+ enum Flags {
+ FLAG_CALLBACK = 1, ///< Callback enabled. See \ref callback
+ FLAG_USER1 = 0x80000000U ///< Application specific flag
+ };
+private:
+ // Some flag values are expected to be used for internal purposes
+ // (e.g., representing the node color) in future versions, so we
+ // 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);
+
+public:
+
/// \brief Destructor
///
/// It might seem strange that constructors are private and destructor
@@ -153,6 +178,52 @@ public:
void setData(const NodeDataPtr& data) { data_ = data; }
//@}
+ /// \name Node flag manipulation methods
+ //@{
+ /// Get the status of a node flag.
+ ///
+ /// This method returns whether the given node flag is set (enabled)
+ /// on the node. The \c flag parameter is expected to be one of the
+ /// defined \c Flags constants. For simplicity, the method interface
+ /// does not prohibit passing an undefined flag or combined flags, but
+ /// the return value in such a case will be meaningless for the caller
+ /// (an application would have to use an ugly cast for such an unintended
+ /// form of call, which will hopefully avoid accidental misuse).
+ ///
+ /// \exception None
+ /// \param flag The flag to be tested.
+ /// \return \c true if the \c flag is set; \c false otherwise.
+ bool getFlag(Flags flag) const {
+ return ((flags_ & flag) != 0);
+ }
+
+ /// Set or clear a node flag.
+ ///
+ /// This method changes the status of the specified node flag to either
+ /// "on" (enabled) or "off" (disabled). The new status is specified by
+ /// the \c on parameter.
+ /// Like the \c getFlag() method, \c flag is expected to be one of the
+ /// defined \c Flags constants. If an undefined or unsettable flag is
+ /// specified, \c isc::InvalidParameter exception will be thrown.
+ ///
+ /// \exception isc::InvalidParameter Unsettable flag is specified
+ /// \exception None otherwise
+ /// \param flag The node flag to be changed.
+ /// \on If \c true, set the flag to on; otherwise set it to off.
+ void setFlag(Flags flag, bool on = true) {
+ if ((flag & ~SETTABLE_FLAGS) != 0) {
+ isc_throw(isc::InvalidParameter,
+ "Unsettable RBTree flag is being set");
+ }
+ if (on) {
+ flags_ |= flag;
+ } else {
+ flags_ &= ~flag;
+ }
+ }
+ //@}
+
+private:
/// \name Callback related methods
///
/// See the description of \c RBTree<T>::find() about callbacks.
@@ -160,16 +231,8 @@ public:
/// These methods never throw an exception.
//@{
/// Return if callback is enabled at the node.
- bool isCallbackEnabled() const { return (callback_required_); }
-
- /// Enable callback at the node.
- void enableCallback() { callback_required_ = true; }
-
- /// Disable callback at the node.
- void disableCallback() { callback_required_ = false; }
//@}
-
private:
/// \brief Define rbnode color
enum RBNodeColor {BLACK, RED};
@@ -224,7 +287,7 @@ private:
/// RBTree::find().
///
/// \todo It might be needed to put it into more general attributes field.
- bool callback_required_;
+ uint32_t flags_;
};
@@ -238,7 +301,7 @@ RBNode<T>::RBNode() :
// dummy name, the value doesn't matter:
name_(isc::dns::Name::ROOT_NAME()),
down_(this),
- callback_required_(false)
+ flags_(0)
{
}
@@ -250,7 +313,7 @@ RBNode<T>::RBNode(const isc::dns::Name& name) :
color_(RED),
name_(name),
down_(NULL_NODE()),
- callback_required_(false)
+ flags_(0)
{
}
@@ -650,7 +713,7 @@ public:
///
/// This version of \c find() calls the callback whenever traversing (on
/// the way from root down the tree) a marked node on the way down through
- /// the domain namespace (see RBNode::enableCallback and related
+ /// the domain namespace (see \c RBNode::enableCallback and related
/// functions).
///
/// If you return true from the callback, the search is stopped and a
@@ -944,7 +1007,8 @@ RBTree<T>::find(const isc::dns::Name& target_name,
if (needsReturnEmptyNode_ || !node->isEmpty()) {
ret = PARTIALMATCH;
*target = node;
- if (callback != NULL && node->callback_required_) {
+ if (callback != NULL &&
+ node->getFlag(RBNode<T>::FLAG_CALLBACK)) {
if ((callback)(*node, callback_arg)) {
break;
}
@@ -1096,7 +1160,7 @@ RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
// consistent behavior (i.e., a weak form of strong exception guarantee)
// even if code after the call to this function throws an exception.
std::swap(node.data_, down_node->data_);
- std::swap(node.callback_required_, down_node->callback_required_);
+ std::swap(node.flags_, down_node->flags_);
down_node->down_ = node.down_;
node.down_ = down_node.get();
// root node of sub tree, the initial color is BLACK
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
index 65b3c95..15b06b4 100644
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
@@ -13,8 +13,14 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <sstream>
+#include <vector>
+
+#include <boost/bind.hpp>
+
#include <exceptions/exceptions.h>
+#include <dns/masterload.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
@@ -27,6 +33,7 @@
#include <gtest/gtest.h>
+using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc;
@@ -140,62 +147,86 @@ TEST_F(MemoryDataSrcTest, getZoneCount) {
EXPECT_EQ(2, memory_datasrc.getZoneCount());
}
+// A helper callback of masterLoad() used in MemoryZoneTest.
+void
+setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
+ *(*it) = rrset;
+ ++it;
+}
+
/// \brief Test fixture for the MemoryZone class
class MemoryZoneTest : public ::testing::Test {
+ // A straightforward pair of textual RR(set) and a RRsetPtr variable
+ // to store the RRset. Used to build test data below.
+ struct RRsetData {
+ const char* const text; // textual representation of an RRset
+ RRsetPtr* rrset;
+ };
public:
MemoryZoneTest() :
class_(RRClass::IN()),
origin_("example.org"),
- ns_name_("ns.example.org"),
- cname_name_("cname.example.org"),
- dname_name_("dname.example.org"),
- child_ns_name_("child.example.org"),
- child_glue_name_("ns.child.example.org"),
- grandchild_ns_name_("grand.child.example.org"),
- grandchild_glue_name_("ns.grand.child.example.org"),
- child_dname_name_("dname.child.example.org"),
- zone_(class_, origin_),
- rr_out_(new RRset(Name("example.com"), class_, RRType::A(),
- RRTTL(300))),
- rr_ns_(new RRset(origin_, class_, RRType::NS(), RRTTL(300))),
- rr_ns_a_(new RRset(ns_name_, class_, RRType::A(), RRTTL(300))),
- rr_ns_aaaa_(new RRset(ns_name_, class_, RRType::AAAA(), RRTTL(300))),
- rr_a_(new RRset(origin_, class_, RRType::A(), RRTTL(300))),
- rr_cname_(new RRset(cname_name_, class_, RRType::CNAME(), RRTTL(300))),
- rr_cname_a_(new RRset(cname_name_, class_, RRType::A(), RRTTL(300))),
- rr_dname_(new RRset(dname_name_, class_, RRType::DNAME(), RRTTL(300))),
- rr_dname_a_(new RRset(dname_name_, class_, RRType::A(),
- RRTTL(300))),
- rr_dname_ns_(new RRset(dname_name_, class_, RRType::NS(), RRTTL(300))),
- rr_dname_apex_(new RRset(origin_, class_, RRType::DNAME(),
- RRTTL(300))),
- rr_child_ns_(new RRset(child_ns_name_, class_, RRType::NS(),
- RRTTL(300))),
- rr_child_glue_(new RRset(child_glue_name_, class_, RRType::A(),
- RRTTL(300))),
- rr_grandchild_ns_(new RRset(grandchild_ns_name_, class_, RRType::NS(),
- RRTTL(300))),
- rr_grandchild_glue_(new RRset(grandchild_glue_name_, class_,
- RRType::AAAA(), RRTTL(300))),
- rr_child_dname_(new RRset(child_dname_name_, class_, RRType::DNAME(),
- RRTTL(300)))
+ zone_(class_, origin_)
{
+ // Build test RRsets. Below, we construct an RRset for
+ // each textual RR(s) of zone_data, and assign it to the corresponding
+ // rr_xxx.
+ const RRsetData zone_data[] = {
+ {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
+ {"example.org. 300 IN A 192.0.2.1", &rr_a_},
+ {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
+ {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
+ {"cname.example.org. 300 IN CNAME canonical.example.org",
+ &rr_cname_},
+ {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
+ {"dname.example.org. 300 IN DNAME target.example.org.",
+ &rr_dname_},
+ {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
+ {"dname.example.org. 300 IN NS ns.dname.example.org.",
+ &rr_dname_ns_},
+ {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
+ {"child.example.org. 300 IN NS ns.child.example.org.",
+ &rr_child_ns_},
+ {"ns.child.example.org. 300 IN A 192.0.2.153",
+ &rr_child_glue_},
+ {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
+ &rr_grandchild_ns_},
+ {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
+ &rr_grandchild_glue_},
+ {"dname.child.example.org. 300 IN DNAME example.com.",
+ &rr_child_dname_},
+ {"example.com. 300 IN A 192.0.2.10", &rr_out_},
+ {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
+ {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
+ {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
+ &rr_nested_emptywild_},
+ {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
+ {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
+ &rr_dnamewild_},
+ {NULL, NULL}
+ };
+
+ stringstream zone_data_stream;
+ vector<RRsetPtr*> rrsets;
+ for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
+ zone_data_stream << zone_data[i].text << "\n";
+ rrsets.push_back(zone_data[i].rrset);
+ }
+
+ vector<RRsetPtr*>::iterator it = rrsets.begin();
+ masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
+ boost::bind(setRRset, _1, it));
}
// Some data to test with
const RRClass class_;
- const Name origin_, ns_name_, cname_name_, dname_name_, child_ns_name_,
- child_glue_name_, grandchild_ns_name_, grandchild_glue_name_,
- child_dname_name_;
+ const Name origin_;
// The zone to torture by tests
MemoryZone zone_;
/*
* Some RRsets to put inside the zone.
- * They are empty, but the MemoryZone does not have a reason to look
- * inside anyway. We will check it finds them and does not change
- * the pointer.
*/
- ConstRRsetPtr
+ RRsetPtr
// Out of zone RRset
rr_out_,
// NS of example.org
@@ -207,16 +238,20 @@ public:
// A of example.org
rr_a_;
RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
- ConstRRsetPtr rr_cname_a_; // for mixed CNAME + A case
+ RRsetPtr rr_cname_a_; // for mixed CNAME + A case
RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
- ConstRRsetPtr rr_dname_a_; // for mixed DNAME + A case
- ConstRRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
- ConstRRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
- ConstRRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
- ConstRRsetPtr rr_child_glue_; // glue RR of the child domain
- ConstRRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
- ConstRRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
- ConstRRsetPtr rr_child_dname_; // A DNAME under NS
+ RRsetPtr rr_dname_a_; // for mixed DNAME + A case
+ RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
+ RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
+ RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
+ RRsetPtr rr_child_glue_; // glue RR of the child domain
+ RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
+ RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
+ RRsetPtr rr_child_dname_; // A DNAME under NS
+ RRsetPtr rr_wild_;
+ RRsetPtr rr_emptywild_;
+ RRsetPtr rr_nested_emptywild_;
+ RRsetPtr rr_nswild_, rr_dnamewild_;
/**
* \brief Test one find query to the zone.
@@ -292,33 +327,30 @@ TEST_F(MemoryZoneTest, add) {
}
TEST_F(MemoryZoneTest, addMultipleCNAMEs) {
- rr_cname_->addRdata(generic::CNAME("canonical1.example.org."));
rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
}
TEST_F(MemoryZoneTest, addCNAMEThenOther) {
- rr_cname_->addRdata(generic::CNAME("canonical.example.org."));
EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
EXPECT_THROW(zone_.add(rr_cname_a_), MemoryZone::AddError);
}
TEST_F(MemoryZoneTest, addOtherThenCNAME) {
- rr_cname_->addRdata(generic::CNAME("canonical.example.org."));
EXPECT_EQ(SUCCESS, zone_.add(rr_cname_a_));
EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
}
TEST_F(MemoryZoneTest, findCNAME) {
// install CNAME RR
- rr_cname_->addRdata(generic::CNAME("canonical.example.org."));
EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
// Find A RR of the same. Should match the CNAME
- findTest(cname_name_, RRType::NS(), Zone::CNAME, true, rr_cname_);
+ findTest(rr_cname_->getName(), RRType::NS(), Zone::CNAME, true, rr_cname_);
// Find the CNAME itself. Should result in normal SUCCESS
- findTest(cname_name_, RRType::CNAME(), Zone::SUCCESS, true, rr_cname_);
+ findTest(rr_cname_->getName(), RRType::CNAME(), Zone::SUCCESS, true,
+ rr_cname_);
}
TEST_F(MemoryZoneTest, findCNAMEUnderZoneCut) {
@@ -339,8 +371,7 @@ TEST_F(MemoryZoneTest, findCNAMEUnderZoneCut) {
// Having a CNAME there is disallowed too, but it is tested by
// addOtherThenCNAME and addCNAMEThenOther.
TEST_F(MemoryZoneTest, addMultipleDNAMEs) {
- rr_dname_->addRdata(generic::DNAME("dname1.example.org."));
- rr_dname_->addRdata(generic::DNAME("dname2.example.org."));
+ rr_dname_->addRdata(generic::DNAME("target2.example.org."));
EXPECT_THROW(zone_.add(rr_dname_), MemoryZone::AddError);
}
@@ -366,7 +397,8 @@ TEST_F(MemoryZoneTest, DNAMEAndNSAtApex) {
// The NS should be possible to be found, below should be DNAME, not
// delegation
findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
- findTest(child_ns_name_, RRType::A(), Zone::DNAME, true, rr_dname_apex_);
+ findTest(rr_child_ns_->getName(), RRType::A(), Zone::DNAME, true,
+ rr_dname_apex_);
}
TEST_F(MemoryZoneTest, NSAndDNAMEAtApex) {
@@ -379,7 +411,6 @@ TEST_F(MemoryZoneTest, NSAndDNAMEAtApex) {
// Search under a DNAME record. It should return the DNAME
TEST_F(MemoryZoneTest, findBelowDNAME) {
- rr_dname_->addRdata(generic::DNAME("target.example.org."));
EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
findTest(Name("below.dname.example.org"), RRType::A(), Zone::DNAME, true,
rr_dname_);
@@ -388,13 +419,13 @@ TEST_F(MemoryZoneTest, findBelowDNAME) {
// Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
// influences only the data below (see RFC 2672, section 3)
TEST_F(MemoryZoneTest, findAtDNAME) {
- rr_dname_->addRdata(generic::DNAME("target.example.org."));
EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_)));
EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_dname_a_)));
- findTest(dname_name_, RRType::A(), Zone::SUCCESS, true, rr_dname_a_);
- findTest(dname_name_, RRType::DNAME(), Zone::SUCCESS, true, rr_dname_);
- findTest(dname_name_, RRType::TXT(), Zone::NXRRSET, true);
+ const Name dname_name(rr_dname_->getName());
+ findTest(dname_name, RRType::A(), Zone::SUCCESS, true, rr_dname_a_);
+ findTest(dname_name, RRType::DNAME(), Zone::SUCCESS, true, rr_dname_);
+ findTest(dname_name, RRType::TXT(), Zone::NXRRSET, true);
}
// Try searching something that is both under NS and DNAME, without and with
@@ -458,7 +489,7 @@ TEST_F(MemoryZoneTest, findAny) {
EXPECT_EQ(0, out_rrsets.size());
RRsetList glue_child_rrsets;
- findTest(child_glue_name_, RRType::ANY(), Zone::SUCCESS, true,
+ findTest(rr_child_glue_->getName(), RRType::ANY(), Zone::SUCCESS, true,
ConstRRsetPtr(), &glue_child_rrsets);
EXPECT_EQ(rr_child_glue_, glue_child_rrsets.findRRset(RRType::A(),
RRClass::IN()));
@@ -472,13 +503,13 @@ TEST_F(MemoryZoneTest, findAny) {
// zone cut
RRsetList child_rrsets;
- findTest(child_ns_name_, RRType::ANY(), Zone::DELEGATION, true,
+ findTest(rr_child_ns_->getName(), RRType::ANY(), Zone::DELEGATION, true,
rr_child_ns_, &child_rrsets);
EXPECT_EQ(0, child_rrsets.size());
// glue for this zone cut
RRsetList new_glue_child_rrsets;
- findTest(child_glue_name_, RRType::ANY(), Zone::DELEGATION, true,
+ findTest(rr_child_glue_->getName(), RRType::ANY(), Zone::DELEGATION, true,
rr_child_ns_, &new_glue_child_rrsets);
EXPECT_EQ(0, new_glue_child_rrsets.size());
}
@@ -495,16 +526,16 @@ TEST_F(MemoryZoneTest, glue) {
EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_grandchild_glue_)));
// by default glue is hidden due to the zone cut
- findTest(child_glue_name_, RRType::A(), Zone::DELEGATION, true,
+ findTest(rr_child_glue_->getName(), RRType::A(), Zone::DELEGATION, true,
rr_child_ns_);
// If we do it in the "glue OK" mode, we should find the exact match.
- findTest(child_glue_name_, RRType::A(), Zone::SUCCESS, true,
+ findTest(rr_child_glue_->getName(), RRType::A(), Zone::SUCCESS, true,
rr_child_glue_, NULL, NULL, Zone::FIND_GLUE_OK);
// glue OK + NXRRSET case
- findTest(child_glue_name_, RRType::AAAA(), Zone::NXRRSET, true,
+ findTest(rr_child_glue_->getName(), RRType::AAAA(), Zone::NXRRSET, true,
ConstRRsetPtr(), NULL, NULL, Zone::FIND_GLUE_OK);
// glue OK + NXDOMAIN case
@@ -517,7 +548,8 @@ TEST_F(MemoryZoneTest, glue) {
// (This case cannot be tested yet)
// nested cut case. The glue should be found.
- findTest(grandchild_glue_name_, RRType::AAAA(), Zone::SUCCESS,
+ findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
+ Zone::SUCCESS,
true, rr_grandchild_glue_, NULL, NULL, Zone::FIND_GLUE_OK);
// A non-existent name in nested cut. This should result in delegation
@@ -544,11 +576,11 @@ TEST_F(MemoryZoneTest, find) {
// These two should be successful
findTest(origin_, RRType::NS(), Zone::SUCCESS, true, rr_ns_);
- findTest(ns_name_, RRType::A(), Zone::SUCCESS, true, rr_ns_a_);
+ findTest(rr_ns_a_->getName(), RRType::A(), Zone::SUCCESS, true, rr_ns_a_);
// These domain exist but don't have the provided RRType
findTest(origin_, RRType::AAAA(), Zone::NXRRSET);
- findTest(ns_name_, RRType::NS(), Zone::NXRRSET);
+ findTest(rr_ns_a_->getName(), RRType::NS(), Zone::NXRRSET);
// These domains don't exist (and one is out of the zone)
findTest(Name("nothere.example.org"), RRType::A(), Zone::NXDOMAIN);
@@ -616,14 +648,59 @@ TEST_F(MemoryZoneTest, load) {
findTest(Name("a.root-servers.net."), RRType::A(), Zone::SUCCESS, false,
ConstRRsetPtr(), NULL, &rootzone);
// But this should no longer be here
- findTest(ns_name_, RRType::AAAA(), Zone::NXDOMAIN, true, ConstRRsetPtr(),
- NULL, &rootzone);
+ findTest(rr_ns_a_->getName(), RRType::AAAA(), Zone::NXDOMAIN, true,
+ ConstRRsetPtr(), NULL, &rootzone);
// Try loading zone that is wrong in a different way
EXPECT_THROW(zone_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
MasterLoadError);
}
+// Note: once #507 is merged, findTest() would succeed whether or not
+// we load the wildcard correctly, so the test will become meaningless.
+// The plan is to clean them up when we complete #551 (then the effect of
+// load will be indirectly tested via find() tests).
+TEST_F(MemoryZoneTest, loadWildcard) {
+ /*
+ * example.org.
+ * |
+ * wild (not *.wild, should have wild mark)
+ * |
+ * *
+ */
+ EXPECT_EQ(SUCCESS, zone_.add(rr_wild_));
+ findTest(Name("wild.example.org"), RRType::A(), Zone::NXRRSET);
+}
+
+// same note as loadWildcard applies.
+TEST_F(MemoryZoneTest, loadEmptyWildcard) {
+ /*
+ * example.org.
+ * foo
+ * *
+ * wild
+ */
+ EXPECT_EQ(SUCCESS, zone_.add(rr_emptywild_));
+ findTest(Name("*.foo.example.org"), RRType::A(), Zone::NXRRSET);
+ findTest(Name("foo.example.org"), RRType::A(), Zone::NXRRSET);
+}
+
+// same note as loadWildcard applies.
+TEST_F(MemoryZoneTest, loadNestedEmptyWildcard) {
+ EXPECT_EQ(SUCCESS, zone_.add(rr_nested_emptywild_));
+ findTest(Name("*.foo.*.bar.example.org"), RRType::A(), Zone::NXRRSET);
+ findTest(Name("foo.*.bar.example.org"), RRType::A(), Zone::NXRRSET);
+ findTest(Name("*.bar.example.org"), RRType::A(), Zone::NXRRSET);
+ findTest(Name("bar.example.org"), RRType::A(), Zone::NXRRSET);
+}
+
+TEST_F(MemoryZoneTest, loadBadWildcard) {
+ // We reject loading the zone if it contains a wildcard name for
+ // NS or DNAME.
+ EXPECT_THROW(zone_.add(rr_nswild_), MemoryZone::AddError);
+ EXPECT_THROW(zone_.add(rr_dnamewild_), MemoryZone::AddError);
+}
+
TEST_F(MemoryZoneTest, swap) {
// build one zone with some data
MemoryZone zone1(class_, origin_);
diff --git a/src/lib/datasrc/tests/rbtree_unittest.cc b/src/lib/datasrc/tests/rbtree_unittest.cc
index 2abe14d..82eed63 100644
--- a/src/lib/datasrc/tests/rbtree_unittest.cc
+++ b/src/lib/datasrc/tests/rbtree_unittest.cc
@@ -187,6 +187,30 @@ TEST_F(RBTreeTest, findError) {
BadValue);
}
+TEST_F(RBTreeTest, flags) {
+ EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(Name("flags.example"),
+ &rbtnode));
+
+ // by default, flags are all off
+ EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
+
+ // set operation, by default it enables the flag
+ rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
+ EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
+
+ // try disable the flag explicitly
+ rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK, false);
+ EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
+
+ // try enable the flag explicitly
+ rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK, true);
+ EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
+
+ // setting an unknown flag will trigger an exception
+ EXPECT_THROW(rbtnode->setFlag(static_cast<RBNode<int>::Flags>(2), true),
+ isc::InvalidParameter);
+}
+
bool
testCallback(const RBNode<int>&, bool* callack_checker) {
*callack_checker = true;
@@ -198,16 +222,16 @@ TEST_F(RBTreeTest, callback) {
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(Name("callback.example"),
&rbtnode));
rbtnode->setData(RBNode<int>::NodeDataPtr(new int(1)));
- EXPECT_FALSE(rbtnode->isCallbackEnabled());
+ EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
// enable/re-disable callback
- rbtnode->enableCallback();
- EXPECT_TRUE(rbtnode->isCallbackEnabled());
- rbtnode->disableCallback();
- EXPECT_FALSE(rbtnode->isCallbackEnabled());
+ rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
+ EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
+ rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK, false);
+ EXPECT_FALSE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
// enable again for subsequent tests
- rbtnode->enableCallback();
+ rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
// add more levels below and above the callback node for partial match.
RBNode<int>* subrbtnode;
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(Name("sub.callback.example"),
@@ -221,9 +245,9 @@ TEST_F(RBTreeTest, callback) {
// it.
EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("callback.example"),
&rbtnode));
- EXPECT_TRUE(rbtnode->isCallbackEnabled());
- EXPECT_FALSE(subrbtnode->isCallbackEnabled());
- EXPECT_FALSE(parentrbtnode->isCallbackEnabled());
+ EXPECT_TRUE(rbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
+ EXPECT_FALSE(subrbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
+ EXPECT_FALSE(parentrbtnode->getFlag(RBNode<int>::FLAG_CALLBACK));
// check if the callback is called from find()
RBTreeNodeChain<int> node_path1;
@@ -236,7 +260,7 @@ TEST_F(RBTreeTest, callback) {
// enable callback at the parent node, but it doesn't have data so
// the callback shouldn't be called.
RBTreeNodeChain<int> node_path2;
- parentrbtnode->enableCallback();
+ parentrbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
callback_called = false;
EXPECT_EQ(RBTree<int>::EXACTMATCH,
rbtree.find(Name("callback.example"), &crbtnode, node_path2,
More information about the bind10-changes
mailing list