BIND 10 master, updated. 6744c100953f6def5500bcb4bfc330b9ffba0f5f [master] Merge branch 'trac2420'
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Nov 29 23:32:59 UTC 2012
The branch, master has been updated
via 6744c100953f6def5500bcb4bfc330b9ffba0f5f (commit)
via 0c36cd61ca034017db27d2f03d7a791c4717813a (commit)
via 41b26fc471f6e15525a7fe5d522529eea45c73db (commit)
via bb38dbf06510c2a9dfa60b68e56836404d62f694 (commit)
via c42c6b938afa4e77d8b0545f1b2dbd335c9d3890 (commit)
via 4263ba5f49dad8f1d282de20b9dc7644953472b7 (commit)
via f31f6dd3b5abf5e25c3416ac963d8de8db43175f (commit)
via 9397bd5dbf2b82a62f2006775ea92bb3b05b755d (commit)
via 7eb7d5efa51485ec96434c08249856cc8cf7c8c9 (commit)
via 38f650c71af54bc238221b540dd2fa302a862885 (commit)
via f7e29b88367c65f57c6a84383fd0ebc520dc26d6 (commit)
via 798e61add913f36ebf6967d62e456ec6c6e1b757 (commit)
via cb20cd84c91a2de735a0e31653cf8704efd5e159 (commit)
via 56b5c356dd0e122da66a0ee94c33368ff1f86386 (commit)
via d805ae680fc4fc5920c5bc50e2ae0817379df1cf (commit)
via 371ad74bd7276f2c5e6c9917f154ebd333a835e0 (commit)
via bedd068396a44ac7fed5a7d4c3f3a8a94861c327 (commit)
via 4fb2c320d91021da1a7fa3c3f9f2f3a2906ee24f (commit)
via 002527091f067467ab0d85837d12b89295e961d1 (commit)
via 1558c3b17a0c31adb4aa62ad2f9d1cff65056bbd (commit)
via 89a677920d39e4da45f49811f6bb61e3e46fcd49 (commit)
from 3b408810eb76ca8e360da549b0e271d15d02b0ce (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 6744c100953f6def5500bcb4bfc330b9ffba0f5f
Merge: 3b40881 0c36cd6
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Nov 29 15:04:11 2012 -0800
[master] Merge branch 'trac2420'
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/memory/Makefile.am | 1 +
src/lib/datasrc/memory/rdataset.cc | 4 +-
src/lib/datasrc/memory/rdataset.h | 31 ++-
src/lib/datasrc/memory/util_internal.h | 57 ++++++
src/lib/datasrc/memory/zone_data.cc | 2 +-
src/lib/datasrc/memory/zone_data_loader.cc | 31 +--
src/lib/datasrc/memory/zone_data_updater.cc | 94 ++++++---
src/lib/datasrc/memory/zone_data_updater.h | 37 +++-
src/lib/datasrc/memory/zone_finder.cc | 13 +-
src/lib/datasrc/tests/Makefile.am | 1 +
src/lib/datasrc/tests/memory/Makefile.am | 2 +
.../datasrc/tests/memory/memory_client_unittest.cc | 10 -
src/lib/datasrc/tests/memory/rdataset_unittest.cc | 75 ++++++-
.../tests/memory/zone_data_loader_unittest.cc | 65 ++++++
.../tests/memory/zone_data_updater_unittest.cc | 208 ++++++++++++++++++++
.../datasrc/tests/memory/zone_finder_unittest.cc | 81 ++++++++
src/lib/datasrc/tests/memory_datasrc_unittest.cc | 2 +-
...ttest.zone => contexttest-almost-obsolete.zone} | 2 +-
src/lib/datasrc/tests/testdata/contexttest.zone | 7 +
.../datasrc/tests/zone_finder_context_unittest.cc | 12 ++
20 files changed, 641 insertions(+), 94 deletions(-)
create mode 100644 src/lib/datasrc/memory/util_internal.h
create mode 100644 src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
create mode 100644 src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
copy src/lib/datasrc/tests/testdata/{contexttest.zone => contexttest-almost-obsolete.zone} (99%)
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 7b82269..72b3273 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -27,6 +27,7 @@ libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
libdatasrc_memory_la_SOURCES += zone_writer.h
libdatasrc_memory_la_SOURCES += zone_writer_local.h zone_writer_local.cc
libdatasrc_memory_la_SOURCES += load_action.h
+libdatasrc_memory_la_SOURCES += util_internal.h
nodist_libdatasrc_memory_la_SOURCES = memory_messages.h memory_messages.cc
diff --git a/src/lib/datasrc/memory/rdataset.cc b/src/lib/datasrc/memory/rdataset.cc
index aae64f3..e7a070f 100644
--- a/src/lib/datasrc/memory/rdataset.cc
+++ b/src/lib/datasrc/memory/rdataset.cc
@@ -122,8 +122,8 @@ RdataSet::create(util::MemorySegment& mem_sgmt, RdataEncoder& encoder,
}
void
-RdataSet::destroy(util::MemorySegment& mem_sgmt, RRClass rrclass,
- RdataSet* rdataset)
+RdataSet::destroy(util::MemorySegment& mem_sgmt, RdataSet* rdataset,
+ RRClass rrclass)
{
const size_t data_len =
RdataReader(rrclass, rdataset->type,
diff --git a/src/lib/datasrc/memory/rdataset.h b/src/lib/datasrc/memory/rdataset.h
index b0b3b48..ffa5075 100644
--- a/src/lib/datasrc/memory/rdataset.h
+++ b/src/lib/datasrc/memory/rdataset.h
@@ -187,12 +187,12 @@ public:
///
/// \param mem_sgmt The \c MemorySegment that allocated memory for
/// \c node.
- /// \param rrclass The RR class of the \c RdataSet to be destroyed.
/// \param rdataset A non NULL pointer to a valid \c RdataSet object
+ /// \param rrclass The RR class of the \c RdataSet to be destroyed.
/// that was originally created by the \c create() method (the behavior
/// is undefined if this condition isn't met).
- static void destroy(util::MemorySegment& mem_sgmt, dns::RRClass rrclass,
- RdataSet* rdataset);
+ static void destroy(util::MemorySegment& mem_sgmt, RdataSet* rdataset,
+ dns::RRClass rrclass);
/// \brief Find \c RdataSet of given RR type from a list (const version).
///
@@ -205,6 +205,11 @@ public:
/// if not found in the entire list, it returns NULL. The head pointer
/// can be NULL, in which case this function will simply return NULL.
///
+ /// By default, this method ignores an RdataSet that only contains an
+ /// RRSIG (i.e., missing the covered RdataSet); if the optional
+ /// sigonly_ok parameter is explicitly set to true, it matches such
+ /// RdataSet and returns it if found.
+ ///
/// \note This function is defined as a (static) class method to
/// clarify its an operation for \c RdataSet objects and to make the
/// name shorter. But its implementation does not depend on private
@@ -215,10 +220,14 @@ public:
/// \param rdata_head A pointer to \c RdataSet from which the search
/// starts. It can be NULL.
/// \param type The RRType of \c RdataSet to find.
+ /// \param sigonly_ok Whether it should find an RdataSet that only has
+ /// RRSIG
/// \return A pointer to the found \c RdataSet or NULL if none found.
static const RdataSet*
- find(const RdataSet* rdataset_head, const dns::RRType& type) {
- return (find<const RdataSet>(rdataset_head, type));
+ find(const RdataSet* rdataset_head, const dns::RRType& type,
+ bool sigonly_ok = false)
+ {
+ return (find<const RdataSet>(rdataset_head, type, sigonly_ok));
}
/// \brief Find \c RdataSet of given RR type from a list (non const
@@ -227,8 +236,10 @@ public:
/// This is similar to the const version, except it takes and returns non
/// const pointers.
static RdataSet*
- find(RdataSet* rdataset_head, const dns::RRType& type) {
- return (find<RdataSet>(rdataset_head, type));
+ find(RdataSet* rdataset_head, const dns::RRType& type,
+ bool sigonly_ok = false)
+ {
+ return (find<RdataSet>(rdataset_head, type, sigonly_ok));
}
typedef boost::interprocess::offset_ptr<RdataSet> RdataSetPtr;
@@ -347,12 +358,14 @@ private:
// Shared by both mutable and immutable versions of find()
template <typename RdataSetType>
static RdataSetType*
- find(RdataSetType* rdataset_head, const dns::RRType& type) {
+ find(RdataSetType* rdataset_head, const dns::RRType& type, bool sigonly_ok)
+ {
for (RdataSetType* rdataset = rdataset_head;
rdataset != NULL;
rdataset = rdataset->getNext()) // use getNext() for efficiency
{
- if (rdataset->type == type) {
+ if (rdataset->type == type &&
+ (rdataset->getRdataCount() > 0 || sigonly_ok)) {
return (rdataset);
}
}
diff --git a/src/lib/datasrc/memory/util_internal.h b/src/lib/datasrc/memory/util_internal.h
new file mode 100644
index 0000000..05aaa29
--- /dev/null
+++ b/src/lib/datasrc/memory/util_internal.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_MEMORY_UTIL_INTERNAL_H
+#define DATASRC_MEMORY_UTIL_INTERNAL_H 1
+
+#include <dns/rdataclass.h>
+#include <dns/rrset.h>
+#include <dns/rrtype.h>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace detail {
+
+/// \brief Return the covered RR type of an RRSIG RRset.
+///
+/// This is a commonly used helper to extract the type covered field of an
+/// RRSIG RRset and return it in the form of an RRType object.
+///
+/// Normally, an empty RRSIG shouldn't be passed to this function, whether
+/// it comes from a master file or another data source iterator, but it could
+/// still happen in some buggy situations. This function catches and rejects
+/// such cases.
+inline dns::RRType
+getCoveredType(const dns::ConstRRsetPtr& sig_rrset) {
+ dns::RdataIteratorPtr it = sig_rrset->getRdataIterator();
+ if (it->isLast()) {
+ isc_throw(isc::Unexpected,
+ "Empty RRset is passed in-memory loader, name: "
+ << sig_rrset->getName());
+ }
+ return (dynamic_cast<const dns::rdata::generic::RRSIG&>(it->getCurrent()).
+ typeCovered());
+}
+
+} // namespace detail
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_UTIL_INTERNAL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory/zone_data.cc b/src/lib/datasrc/memory/zone_data.cc
index e2cbdef..1bf9c9c 100644
--- a/src/lib/datasrc/memory/zone_data.cc
+++ b/src/lib/datasrc/memory/zone_data.cc
@@ -49,7 +49,7 @@ rdataSetDeleter(RRClass rrclass, util::MemorySegment* mem_sgmt,
rdataset = rdataset_next)
{
rdataset_next = rdataset->getNext();
- RdataSet::destroy(*mem_sgmt, rrclass, rdataset);
+ RdataSet::destroy(*mem_sgmt, rdataset, rrclass);
}
}
diff --git a/src/lib/datasrc/memory/zone_data_loader.cc b/src/lib/datasrc/memory/zone_data_loader.cc
index d0a43a3..051acc3 100644
--- a/src/lib/datasrc/memory/zone_data_loader.cc
+++ b/src/lib/datasrc/memory/zone_data_loader.cc
@@ -16,6 +16,7 @@
#include <datasrc/memory/zone_data_updater.h>
#include <datasrc/memory/logger.h>
#include <datasrc/memory/segment_object_holder.h>
+#include <datasrc/memory/util_internal.h>
#include <dns/rdataclass.h>
#include <dns/rrset.h>
@@ -35,6 +36,7 @@ namespace datasrc {
namespace memory {
using detail::SegmentObjectHolder;
+using detail::getCoveredType;
namespace { // unnamed namespace
@@ -75,8 +77,6 @@ private:
typedef NodeRRsets::value_type NodeRRsetsVal;
// A helper to identify the covered type of an RRSIG.
- static isc::dns::RRType getCoveredType
- (const isc::dns::ConstRRsetPtr& sig_rrset);
const isc::dns::Name& getCurrentName() const;
private:
@@ -126,34 +126,17 @@ ZoneDataLoader::flushNodeRRsets() {
updater_.add(val.second, sig_rrset);
}
- // Right now, we don't accept RRSIG without covered RRsets (this
- // should eventually allowed, but to do so we'll need to update the
- // finder).
- if (!node_rrsigsets_.empty()) {
- isc_throw(ZoneDataUpdater::AddError,
- "RRSIG is added without covered RRset for "
- << getCurrentName());
+ // Normally rrsigsets map should be empty at this point, but it's still
+ // possible that an RRSIG that don't has covered RRset is added; they
+ // still remain in the map. We add them to the zone separately.
+ BOOST_FOREACH(NodeRRsetsVal val, node_rrsigsets_) {
+ updater_.add(ConstRRsetPtr(), val.second);
}
node_rrsets_.clear();
node_rrsigsets_.clear();
}
-RRType
-ZoneDataLoader::getCoveredType(const ConstRRsetPtr& sig_rrset) {
- RdataIteratorPtr it = sig_rrset->getRdataIterator();
- // Empty RRSIG shouldn't be passed either via a master file or
- // another data source iterator, but it could still happen if the
- // iterator has a bug. We catch and reject such cases.
- if (it->isLast()) {
- isc_throw(isc::Unexpected,
- "Empty RRset is passed in-memory loader, name: "
- << sig_rrset->getName());
- }
- return (dynamic_cast<const generic::RRSIG&>(it->getCurrent()).
- typeCovered());
-}
-
const Name&
ZoneDataLoader::getCurrentName() const {
if (!node_rrsets_.empty()) {
diff --git a/src/lib/datasrc/memory/zone_data_updater.cc b/src/lib/datasrc/memory/zone_data_updater.cc
index 3df8c66..7605644 100644
--- a/src/lib/datasrc/memory/zone_data_updater.cc
+++ b/src/lib/datasrc/memory/zone_data_updater.cc
@@ -12,12 +12,18 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <exceptions/exceptions.h>
+
#include <datasrc/memory/zone_data_updater.h>
#include <datasrc/memory/logger.h>
+#include <datasrc/memory/util_internal.h>
#include <datasrc/zone.h>
#include <dns/rdataclass.h>
+#include <cassert>
+#include <string>
+
using namespace isc::dns;
using namespace isc::dns::rdata;
@@ -25,6 +31,8 @@ namespace isc {
namespace datasrc {
namespace memory {
+using detail::getCoveredType;
+
void
ZoneDataUpdater::addWildcards(const Name& name) {
Name wname(name);
@@ -99,9 +107,7 @@ ZoneDataUpdater::contextCheck(const AbstractRRset& rrset,
void
ZoneDataUpdater::validate(const isc::dns::ConstRRsetPtr rrset) const {
- if (!rrset) {
- isc_throw(NullRRset, "The rrset provided is NULL");
- }
+ assert(rrset);
if (rrset->getRdataCount() == 0) {
isc_throw(AddError,
@@ -241,31 +247,46 @@ ZoneDataUpdater::setupNSEC3(const ConstRRsetPtr rrset) {
}
void
-ZoneDataUpdater::addNSEC3(const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
+ZoneDataUpdater::addNSEC3(const Name& name, const ConstRRsetPtr rrset,
+ const ConstRRsetPtr rrsig)
{
- setupNSEC3<generic::NSEC3>(rrset);
+ if (rrset) {
+ setupNSEC3<generic::NSEC3>(rrset);
+ }
NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+ if (nsec3_data == NULL) {
+ // This is some tricky case: an RRSIG for NSEC3 is given without the
+ // covered NSEC3, and we don't even know any NSEC3 related data.
+ // This situation is not necessarily broken, but in our current
+ // implementation it's very difficult to deal with. So we reject it;
+ // hopefully this case shouldn't happen in practice, at least unless
+ // zone is really broken.
+ assert(!rrset);
+ isc_throw(NotImplemented,
+ "RRSIG for NSEC3 cannot be added - no known NSEC3 data");
+ }
ZoneNode* node;
- nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
+ nsec3_data->insertName(mem_sgmt_, name, &node);
RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig);
RdataSet* old_rdataset = node->setData(rdataset);
if (old_rdataset != NULL) {
- RdataSet::destroy(mem_sgmt_, rrclass_, old_rdataset);
+ RdataSet::destroy(mem_sgmt_, old_rdataset, rrclass_);
}
}
void
-ZoneDataUpdater::addRdataSet(const ConstRRsetPtr rrset,
+ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
+ const ConstRRsetPtr rrset,
const ConstRRsetPtr rrsig)
{
- if (rrset->getType() == RRType::NSEC3()) {
- addNSEC3(rrset, rrsig);
+ if (rrtype == RRType::NSEC3()) {
+ addNSEC3(name, rrset, rrsig);
} else {
ZoneNode* node;
- zone_data_.insertName(mem_sgmt_, rrset->getName(), &node);
+ zone_data_.insertName(mem_sgmt_, name, &node);
RdataSet* rdataset_head = node->getData();
@@ -273,13 +294,14 @@ ZoneDataUpdater::addRdataSet(const ConstRRsetPtr rrset,
// fails and the exception is thrown, it may break strong
// exception guarantee. At the moment we prefer code simplicity
// and don't bother to introduce complicated recovery code.
- contextCheck(*rrset, rdataset_head);
+ if (rrset) { // this check is only for covered RRset, not RRSIG
+ contextCheck(*rrset, rdataset_head);
+ }
- if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
+ if (RdataSet::find(rdataset_head, rrtype, true) != NULL) {
isc_throw(AddError,
"RRset of the type already exists: "
- << rrset->getName() << " (type: "
- << rrset->getType() << ")");
+ << name << " (type: " << rrtype << ")");
}
RdataSet* rdataset_new = RdataSet::create(mem_sgmt_, encoder_,
@@ -289,23 +311,25 @@ ZoneDataUpdater::addRdataSet(const ConstRRsetPtr rrset,
// Ok, we just put it in.
+ // Convenient (and more efficient) shortcut to check RRsets at origin
+ const bool is_origin = (node == zone_data_.getOriginNode());
+
// If this RRset creates a zone cut at this node, mark the node
- // indicating the need for callback in find().
- if (rrset->getType() == RRType::NS() &&
- rrset->getName() != zone_name_) {
+ // indicating the need for callback in find(). Note that we do this
+ // only when non RRSIG RRset of that type is added.
+ if (rrset && rrtype == RRType::NS() && !is_origin) {
node->setFlag(ZoneNode::FLAG_CALLBACK);
// If it is DNAME, we have a callback as well here
- } else if (rrset->getType() == RRType::DNAME()) {
+ } else if (rrset && rrtype == RRType::DNAME()) {
node->setFlag(ZoneNode::FLAG_CALLBACK);
}
// If we've added NSEC3PARAM at zone origin, set up NSEC3
// specific data or check consistency with already set up
// parameters.
- if (rrset->getType() == RRType::NSEC3PARAM() &&
- rrset->getName() == zone_name_) {
+ if (rrset && rrtype == RRType::NSEC3PARAM() && is_origin) {
setupNSEC3<generic::NSEC3PARAM>(rrset);
- } else if (rrset->getType() == RRType::NSEC()) {
+ } else if (rrset && rrtype == RRType::NSEC() && is_origin) {
// If it is NSEC signed zone, we mark the zone as signed
// (conceptually "signed" is a broader notion but our
// current zone finder implementation regards "signed" as
@@ -319,27 +343,37 @@ void
ZoneDataUpdater::add(const ConstRRsetPtr& rrset,
const ConstRRsetPtr& sig_rrset)
{
- // Validate input. This will cause an exception to be thrown if the
- // input RRset is empty.
- validate(rrset);
+ // Validate input.
+ if (!rrset && !sig_rrset) {
+ isc_throw(NullRRset,
+ "ZoneDataUpdater::add is given 2 NULL pointers");
+ }
+ if (rrset) {
+ validate(rrset);
+ }
if (sig_rrset) {
validate(sig_rrset);
}
+ const Name& name = rrset ? rrset->getName() : sig_rrset->getName();
+ const RRType& rrtype = rrset ? rrset->getType() :
+ getCoveredType(sig_rrset);
+
// OK, can add the RRset.
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
- arg(rrset->getName()).arg(rrset->getType()).arg(zone_name_);
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).arg(name).
+ arg(rrset ? rrtype.toText() : "RRSIG(" + rrtype.toText() + ")").
+ arg(zone_name_);
// Add wildcards possibly contained in the owner name to the domain
// tree. This can only happen for the normal (non-NSEC3) tree.
// Note: this can throw an exception, breaking strong exception
// guarantee. (see also the note for the call to contextCheck()
// above).
- if (rrset->getType() != RRType::NSEC3()) {
- addWildcards(rrset->getName());
+ if (rrtype != RRType::NSEC3()) {
+ addWildcards(name);
}
- addRdataSet(rrset, sig_rrset);
+ addRdataSet(name, rrtype, rrset, sig_rrset);
}
} // namespace memory
diff --git a/src/lib/datasrc/memory/zone_data_updater.h b/src/lib/datasrc/memory/zone_data_updater.h
index fa9a6af..9d669a0 100644
--- a/src/lib/datasrc/memory/zone_data_updater.h
+++ b/src/lib/datasrc/memory/zone_data_updater.h
@@ -110,10 +110,32 @@ public:
/// populated with the record data and added to the ZoneData for the
/// name in the RRset.
///
- /// This method throws an \c NullRRset exception (see above) if
- /// \c rrset is empty. It throws \c AddError if any of a variety of
- /// validation checks fail for the \c rrset and its associated
- /// \c sig_rrset.
+ /// At least one of \c rrset or \c sig_rrset must be non NULL.
+ /// \c sig_rrset can be reasonably NULL when \c rrset is not signed in
+ /// the zone; it's unusual that \c rrset is NULL, but is still possible
+ /// if these RRsets are given separately to the loader, or if even the
+ /// zone is half broken and really contains an RRSIG that doesn't have
+ /// any covered RRset. This implementation supports these cases (but
+ /// see the note below).
+ ///
+ /// There is one tricky case: Due to a limitation of the current
+ /// implementation, it cannot accept an RRSIG for NSEC3 without the covered
+ /// NSEC3, unless at least one NSEC3 or NSEC3PARAM has been added.
+ /// In this case an isc::NotImplemented exception will be thrown. It
+ /// should be very rare in practice, and hopefully wouldn't be a real
+ /// issue.
+ ///
+ /// \note Due to limitations of the current implementation, if a
+ /// (non RRSIG) RRset and its RRSIG are added separately in different
+ /// calls to this method, the second attempt will be rejected due to
+ /// an \c AddError exception. This will be loosened in Trac
+ /// ticket #2441.
+ ///
+ /// \throw NullRRset Both \c rrset and sig_rrset is NULL
+ /// \throw AddError any of a variety of validation checks fail for the
+ /// \c rrset and its associated \c sig_rrset.
+ /// \throw NotImplemented RRSIG for NSEC3 cannot be added due to internal
+ /// restriction.
///
/// \param rrset The RRset to be added.
/// \param sig_rrset An associated RRSIG RRset for the \c rrset. It
@@ -152,9 +174,12 @@ private:
const isc::dns::NSEC3Hash* getNSEC3Hash();
template <typename T>
void setupNSEC3(const isc::dns::ConstRRsetPtr rrset);
- void addNSEC3(const isc::dns::ConstRRsetPtr rrset,
+ void addNSEC3(const isc::dns::Name& name,
+ const isc::dns::ConstRRsetPtr rrset,
const isc::dns::ConstRRsetPtr rrsig);
- void addRdataSet(const isc::dns::ConstRRsetPtr rrset,
+ void addRdataSet(const isc::dns::Name& name,
+ const isc::dns::RRType& rrtype,
+ const isc::dns::ConstRRsetPtr rrset,
const isc::dns::ConstRRsetPtr rrsig);
util::MemorySegment& mem_sgmt_;
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index 11188a0..4240c21 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -216,6 +216,14 @@ createNSEC3RRset(const ZoneNode* node, const RRClass& rrclass) {
assert(rdataset != NULL);
assert(rdataset->type == RRType::NSEC3());
+ // Check for the rare case of RRSIG-only record; in theory it could exist
+ // but we simply consider it broken for NSEC3.
+ if (rdataset->getRdataCount() == 0) {
+ uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+ isc_throw(DataSourceError, "Broken zone: RRSIG-only NSEC3 record at "
+ << node->getAbsoluteLabels(labels_buf) << "/" << rrclass);
+ }
+
// Create the RRset. Note the DNSSEC flag: NSEC3 implies DNSSEC.
return (createTreeNodeRRset(node, rdataset, rrclass,
ZoneFinder::FIND_DNSSEC));
@@ -627,7 +635,10 @@ private:
// This can be a bit more optimized, but unless we have many
// requested types the effect is probably marginal. For now we
// keep it simple.
- if (std::find(type_beg, type_end, rdset->type) != type_end) {
+ // Check for getRdataCount is necessary not to include RRSIG-only
+ // records accidentally (should be rare, but possible).
+ if (std::find(type_beg, type_end, rdset->type) != type_end &&
+ rdset->getRdataCount() > 0) {
result->push_back(createTreeNodeRRset(node, rdset, rrclass_,
options, real_name));
}
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index 7cdf0ee..d3ef3bf 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -94,6 +94,7 @@ endif
EXTRA_DIST = testdata/brokendb.sqlite3
EXTRA_DIST += testdata/contexttest.zone
+EXTRA_DIST += testdata/contexttest-almost-obsolete.zone
EXTRA_DIST += testdata/diffs.sqlite3
EXTRA_DIST += testdata/duplicate_rrset.zone
EXTRA_DIST += testdata/example2.com
diff --git a/src/lib/datasrc/tests/memory/Makefile.am b/src/lib/datasrc/tests/memory/Makefile.am
index 67e63b9..a5d73b4 100644
--- a/src/lib/datasrc/tests/memory/Makefile.am
+++ b/src/lib/datasrc/tests/memory/Makefile.am
@@ -32,6 +32,8 @@ run_unittests_SOURCES += ../../tests/faked_nsec3.h ../../tests/faked_nsec3.cc
run_unittests_SOURCES += memory_segment_test.h
run_unittests_SOURCES += segment_object_holder_unittest.cc
run_unittests_SOURCES += memory_client_unittest.cc
+run_unittests_SOURCES += zone_data_loader_unittest.cc
+run_unittests_SOURCES += zone_data_updater_unittest.cc
run_unittests_SOURCES += zone_table_segment_test.h
run_unittests_SOURCES += zone_table_segment_unittest.cc
run_unittests_SOURCES += zone_writer_unittest.cc
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index 38f6eff..2a9a35d 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -576,16 +576,6 @@ TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
// Teardown checks for memory segment leaks
}
-TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
- // This causes the situation where an RRSIG is added without a covered
- // RRset. Such cases are currently rejected.
- EXPECT_THROW(client_->load(Name("example.org"),
- TEST_DATA_DIR
- "/example.org-rrsig-follows-nothing.zone"),
- ZoneDataUpdater::AddError);
- // Teardown checks for memory segment leaks
-}
-
TEST_F(MemoryClientTest, loadRRSIGs) {
client_->load(Name("example.org"),
TEST_DATA_DIR "/example.org-rrsigs.zone");
diff --git a/src/lib/datasrc/tests/memory/rdataset_unittest.cc b/src/lib/datasrc/tests/memory/rdataset_unittest.cc
index 897e53c..f599999 100644
--- a/src/lib/datasrc/tests/memory/rdataset_unittest.cc
+++ b/src/lib/datasrc/tests/memory/rdataset_unittest.cc
@@ -24,6 +24,7 @@
#include <dns/rrtype.h>
#include <dns/rrttl.h>
+#include <datasrc/memory/segment_object_holder.h>
#include <datasrc/memory/rdata_serialization.h>
#include <datasrc/memory/rdataset.h>
@@ -39,6 +40,7 @@ using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc::memory;
using namespace isc::testutils;
+using isc::datasrc::memory::detail::SegmentObjectHolder;
using boost::lexical_cast;
namespace {
@@ -112,7 +114,7 @@ TEST_F(RdataSetTest, create) {
RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
ConstRRsetPtr());
checkRdataSet(*rdataset, true, false);
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
}
TEST_F(RdataSetTest, getNext) {
@@ -131,7 +133,62 @@ TEST_F(RdataSetTest, getNext) {
rdataset->next = rdataset;
EXPECT_EQ(rdataset, static_cast<const RdataSet*>(rdataset)->getNext());
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
+}
+
+TEST_F(RdataSetTest, find) {
+ // Create some RdataSets and make a chain of them.
+ SegmentObjectHolder<RdataSet, RRClass> holder1(
+ mem_sgmt_,
+ RdataSet::create(mem_sgmt_, encoder_, a_rrset_, ConstRRsetPtr()),
+ RRClass::IN());
+ ConstRRsetPtr aaaa_rrset =
+ textToRRset("www.example.com. 1076895760 IN AAAA 2001:db8::1");
+ SegmentObjectHolder<RdataSet, RRClass> holder2(
+ mem_sgmt_,
+ RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset, ConstRRsetPtr()),
+ RRClass::IN());
+ ConstRRsetPtr sigonly_rrset =
+ textToRRset("www.example.com. 1076895760 IN RRSIG "
+ "TXT 5 2 3600 20120814220826 20120715220826 "
+ "1234 example.com. FAKE");
+ SegmentObjectHolder<RdataSet, RRClass> holder3(
+ mem_sgmt_,
+ RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(), sigonly_rrset),
+ RRClass::IN());
+
+ RdataSet* rdataset_a = holder1.get();
+ RdataSet* rdataset_aaaa = holder2.get();
+ RdataSet* rdataset_sigonly = holder3.get();
+ RdataSet* rdataset_null = NULL;
+ rdataset_a->next = rdataset_aaaa;
+ rdataset_aaaa->next = rdataset_sigonly;
+
+ // If a non-RRSIG part of rdataset exists for the given type, it will be
+ // returned regardless of the value of sigonly_ok. If it's RRSIG-only
+ // rdataset, it returns non NULL iff sigonly_ok is explicitly set to true.
+ EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA()));
+ EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA(), true));
+ EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA(), false));
+
+ EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a, RRType::TXT()));
+ EXPECT_EQ(rdataset_sigonly, RdataSet::find(rdataset_a, RRType::TXT(),
+ true));
+ EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a, RRType::TXT(), false));
+
+ // Same tests for the const version of find().
+ const RdataSet* rdataset_a_const = holder1.get();
+ EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA()));
+ EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA(),
+ true));
+ EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA(),
+ false));
+
+ EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a_const, RRType::TXT()));
+ EXPECT_EQ(rdataset_sigonly, RdataSet::find(rdataset_a_const, RRType::TXT(),
+ true));
+ EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a_const, RRType::TXT(),
+ false));
}
// A helper function to create an RRset containing the given number of
@@ -154,7 +211,7 @@ TEST_F(RdataSetTest, createManyRRs) {
ConstRRsetPtr());
EXPECT_EQ(8191, rdataset->getRdataCount());
EXPECT_EQ(0, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
// Exceeding that will result in an exception.
EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_,
@@ -173,7 +230,7 @@ TEST_F(RdataSetTest, createWithRRSIG) {
RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
rrsig_rrset_);
checkRdataSet(*rdataset, true, true);
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
// Unusual case: TTL doesn't match. This implementation accepts that,
// using the TTL of the covered RRset.
@@ -183,7 +240,7 @@ TEST_F(RdataSetTest, createWithRRSIG) {
"20120715220826 1234 example.com. FAKE"));
rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_, rrsig_badttl);
checkRdataSet(*rdataset, true, true);
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
}
// A helper function to create an RRSIG RRset containing the given number of
@@ -218,21 +275,21 @@ TEST_F(RdataSetTest, createManyRRSIGs) {
RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
getRRSIGWithRdataCount(7));
EXPECT_EQ(7, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
// 8 would cause overflow in the normal 3-bit field if there were no extra
// count field.
rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
getRRSIGWithRdataCount(8));
EXPECT_EQ(8, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
// Up to 2^16-1 RRSIGs are allowed (although that would be useless
// in practice)
rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
getRRSIGWithRdataCount(65535));
EXPECT_EQ(65535, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
// Exceeding this limit will result in an exception.
EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
@@ -250,7 +307,7 @@ TEST_F(RdataSetTest, createWithRRSIGOnly) {
RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
rrsig_rrset_);
checkRdataSet(*rdataset, false, true);
- RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+ RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
}
TEST_F(RdataSetTest, badCeate) {
diff --git a/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
new file mode 100644
index 0000000..c005bf1
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/memory/rdataset.h>
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/zone_data_loader.h>
+
+#include "memory_segment_test.h"
+
+#include <gtest/gtest.h>
+
+using namespace isc::dns;
+using namespace isc::datasrc::memory;
+
+namespace {
+
+class ZoneDataLoaderTest : public ::testing::Test {
+protected:
+ ZoneDataLoaderTest() : zclass_(RRClass::IN()), zone_data_(NULL) {}
+ void TearDown() {
+ if (zone_data_ != NULL) {
+ ZoneData::destroy(mem_sgmt_, zone_data_, zclass_);
+ }
+ EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
+ }
+ const RRClass zclass_;
+ test::MemorySegmentTest mem_sgmt_;
+ ZoneData* zone_data_;
+};
+
+TEST_F(ZoneDataLoaderTest, loadRRSIGFollowsNothing) {
+ // This causes the situation where an RRSIG is added without a covered
+ // RRset. It will be accepted, and corresponding "sig-only" rdata will
+ // be created.
+ zone_data_ = loadZoneData(mem_sgmt_, zclass_, Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-rrsig-follows-nothing.zone");
+ ZoneNode* node = NULL;
+ zone_data_->insertName(mem_sgmt_, Name("ns1.example.org"), &node);
+ ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
+ const RdataSet* rdset = node->getData();
+ ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
+ EXPECT_EQ(RRType::A(), rdset->type); // there should be only 1 data here
+ EXPECT_EQ(0, rdset->getRdataCount()); // no RDATA
+ EXPECT_EQ(1, rdset->getSigRdataCount()); // but 1 SIG
+
+ // Teardown checks for memory segment leaks
+}
+
+}
diff --git a/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
new file mode 100644
index 0000000..63c69c8
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
@@ -0,0 +1,208 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <testutils/dnsmessage_test.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+
+#include <datasrc/memory/rdataset.h>
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/zone_data_updater.h>
+
+#include "memory_segment_test.h"
+
+#include <gtest/gtest.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <cassert>
+
+using isc::testutils::textToRRset;
+using namespace isc::dns;
+using namespace isc::datasrc::memory;
+
+namespace {
+
+class ZoneDataUpdaterTest : public ::testing::Test {
+protected:
+ ZoneDataUpdaterTest() :
+ zname_("example.org"), zclass_(RRClass::IN()),
+ zone_data_(ZoneData::create(mem_sgmt_, zname_)),
+ updater_(new ZoneDataUpdater(mem_sgmt_, zclass_, zname_, *zone_data_))
+ {}
+
+ ~ZoneDataUpdaterTest() {
+ if (zone_data_ != NULL) {
+ ZoneData::destroy(mem_sgmt_, zone_data_, zclass_);
+ }
+ if (!mem_sgmt_.allMemoryDeallocated()) {
+ ADD_FAILURE() << "Memory leak detected";
+ }
+ }
+
+ void clearZoneData() {
+ assert(zone_data_ != NULL);
+ ZoneData::destroy(mem_sgmt_, zone_data_, zclass_);
+ zone_data_ = ZoneData::create(mem_sgmt_, zname_);
+ updater_.reset(new ZoneDataUpdater(mem_sgmt_, zclass_, zname_,
+ *zone_data_));
+ }
+
+ const Name zname_;
+ const RRClass zclass_;
+ test::MemorySegmentTest mem_sgmt_;
+ ZoneData* zone_data_;
+ boost::scoped_ptr<ZoneDataUpdater> updater_;
+};
+
+TEST_F(ZoneDataUpdaterTest, bothNull) {
+ // At least either covered RRset or RRSIG must be non NULL.
+ EXPECT_THROW(updater_->add(ConstRRsetPtr(), ConstRRsetPtr()),
+ ZoneDataUpdater::NullRRset);
+}
+
+ZoneNode*
+getNode(isc::util::MemorySegment& mem_sgmt, const Name& name,
+ ZoneData* zone_data)
+{
+ ZoneNode* node = NULL;
+ zone_data->insertName(mem_sgmt, name, &node);
+ EXPECT_NE(static_cast<ZoneNode*>(NULL), node);
+ return (node);
+}
+
+TEST_F(ZoneDataUpdaterTest, rrsigOnly) {
+ // RRSIG that doesn't have covered RRset can be added. The resulting
+ // rdataset won't have "normal" RDATA but sig RDATA.
+ updater_->add(ConstRRsetPtr(), textToRRset(
+ "www.example.org. 3600 IN RRSIG A 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ ZoneNode* node = getNode(mem_sgmt_, Name("www.example.org"), zone_data_);
+ const RdataSet* rdset = node->getData();
+ ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
+ rdset = RdataSet::find(rdset, RRType::A(), true);
+ ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
+ EXPECT_EQ(0, rdset->getRdataCount());
+ EXPECT_EQ(1, rdset->getSigRdataCount());
+
+ // The RRSIG covering A prohibits an actual A RRset from being added.
+ // This should be loosened in future version, but we check the current
+ // behavior.
+ EXPECT_THROW(updater_->add(
+ textToRRset("www.example.org. 3600 IN A 192.0.2.1"),
+ ConstRRsetPtr()), ZoneDataUpdater::AddError);
+
+ // The special "wildcarding" node mark should be added for the RRSIG-only
+ // case, too.
+ updater_->add(ConstRRsetPtr(), textToRRset(
+ "*.wild.example.org. 3600 IN RRSIG A 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ node = getNode(mem_sgmt_, Name("wild.example.org"), zone_data_);
+ EXPECT_TRUE(node->getFlag(ZoneData::WILDCARD_NODE));
+
+ // Simply adding RRSIG covering (delegating NS) shouldn't enable callback
+ // in search.
+ updater_->add(ConstRRsetPtr(), textToRRset(
+ "child.example.org. 3600 IN RRSIG NS 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ node = getNode(mem_sgmt_, Name("child.example.org"), zone_data_);
+ EXPECT_FALSE(node->getFlag(ZoneNode::FLAG_CALLBACK));
+
+ // Same for DNAME
+ updater_->add(ConstRRsetPtr(), textToRRset(
+ "dname.example.org. 3600 IN RRSIG DNAME 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ node = getNode(mem_sgmt_, Name("dname.example.org"), zone_data_);
+ EXPECT_FALSE(node->getFlag(ZoneNode::FLAG_CALLBACK));
+
+ // Likewise, RRSIG for NSEC3PARAM alone shouldn't make the zone
+ // "NSEC3-signed".
+ updater_->add(ConstRRsetPtr(), textToRRset(
+ "example.org. 3600 IN RRSIG NSEC3PARAM 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ EXPECT_FALSE(zone_data_->isNSEC3Signed());
+
+ // And same for (RRSIG for) NSEC and "is signed".
+ updater_->add(ConstRRsetPtr(), textToRRset(
+ "example.org. 3600 IN RRSIG NSEC 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ EXPECT_FALSE(zone_data_->isSigned());
+}
+
+// Commonly used checks for rrsigForNSEC3Only
+void
+checkNSEC3Rdata(isc::util::MemorySegment& mem_sgmt, const Name& name,
+ ZoneData* zone_data)
+{
+ ZoneNode* node = NULL;
+ zone_data->getNSEC3Data()->insertName(mem_sgmt, name, &node);
+ ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
+ const RdataSet* rdset = node->getData();
+ ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
+ ASSERT_EQ(RRType::NSEC3(), rdset->type);
+ EXPECT_EQ(0, rdset->getRdataCount());
+ EXPECT_EQ(1, rdset->getSigRdataCount());
+}
+
+TEST_F(ZoneDataUpdaterTest, rrsigForNSEC3Only) {
+ // Adding only RRSIG covering NSEC3 is tricky. It should go to the
+ // separate NSEC3 tree, but the separate space is only created when
+ // NSEC3 or NSEC3PARAM is added. So, in many cases RRSIG-only is allowed,
+ // but if no NSEC3 or NSEC3PARAM has been added it will be rejected.
+
+ // Below we use abnormal owner names and RDATA for NSEC3s for brevity,
+ // but that doesn't matter for this test.
+
+ // Add NSEC3PARAM, then RRSIG-only, which is okay.
+ updater_->add(textToRRset(
+ "example.org. 3600 IN NSEC3PARAM 1 0 12 AABBCCDD"),
+ textToRRset(
+ "example.org. 3600 IN RRSIG NSEC3PARAM 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ EXPECT_TRUE(zone_data_->isNSEC3Signed());
+ updater_->add(ConstRRsetPtr(),
+ textToRRset(
+ "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ checkNSEC3Rdata(mem_sgmt_, Name("09GM.example.org"), zone_data_);
+
+ // Clear the current content of zone, then add NSEC3
+ clearZoneData();
+ updater_->add(textToRRset(
+ "AABB.example.org. 3600 IN NSEC3 1 0 10 AA 00000000 A"),
+ textToRRset(
+ "AABB.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ updater_->add(ConstRRsetPtr(),
+ textToRRset(
+ "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE"));
+ checkNSEC3Rdata(mem_sgmt_, Name("09GM.example.org"), zone_data_);
+
+ // If we add only RRSIG without any NSEC3 related data beforehand,
+ // it will be rejected; it's a limitation of the current implementation.
+ clearZoneData();
+ EXPECT_THROW(updater_->add(
+ ConstRRsetPtr(),
+ textToRRset(
+ "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+ "20150420235959 20051021000000 1 example.org. FAKE")),
+ isc::NotImplemented);
+}
+
+}
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index 4cd08c0..f112119 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -1358,6 +1358,74 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
DataSourceError);
}
+TEST_F(InMemoryZoneFinderTest, findOrphanRRSIG) {
+ // Make the zone "NSEC signed"
+ addToZoneData(rr_nsec_);
+ const ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_NSEC_SIGNED;
+
+ // Add A for ns.example.org, and RRSIG-only covering TXT for the same name.
+ // query for the TXT should result in NXRRSET.
+ addToZoneData(rr_ns_a_);
+ updater_.add(ConstRRsetPtr(),
+ textToRRset(
+ "ns.example.org. 300 IN RRSIG TXT 5 3 300 20120814220826 "
+ "20120715220826 1234 example.com. FAKE"));
+ findTest(Name("ns.example.org"), RRType::TXT(),
+ ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
+
+ // Add RRSIG-only covering NSEC. This shouldn't be returned when NSEC is
+ // requested, whether it's for NXRRSET or NXDOMAIN
+ updater_.add(ConstRRsetPtr(),
+ textToRRset(
+ "ns.example.org. 300 IN RRSIG NSEC 5 3 300 "
+ "20120814220826 20120715220826 1234 example.com. FAKE"));
+ // The added RRSIG for NSEC could be used for NXRRSET but shouldn't
+ findTest(Name("ns.example.org"), RRType::TXT(),
+ ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
+ expected_flags, NULL, ZoneFinder::FIND_DNSSEC);
+ // The added RRSIG for NSEC could be used for NXDOMAIN but shouldn't
+ findTest(Name("nz.example.org"), RRType::A(),
+ ZoneFinder::NXDOMAIN, true, rr_nsec_,
+ expected_flags, NULL, ZoneFinder::FIND_DNSSEC);
+
+ // RRSIG-only CNAME shouldn't be accidentally confused with real CNAME.
+ updater_.add(ConstRRsetPtr(),
+ textToRRset(
+ "nocname.example.org. 300 IN RRSIG CNAME 5 3 300 "
+ "20120814220826 20120715220826 1234 example.com. FAKE"));
+ findTest(Name("nocname.example.org"), RRType::A(),
+ ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
+
+ // RRSIG-only for NS wouldn't invoke delegation anyway, but we check this
+ // case explicitly.
+ updater_.add(ConstRRsetPtr(),
+ textToRRset(
+ "nodelegation.example.org. 300 IN RRSIG NS 5 3 300 "
+ "20120814220826 20120715220826 1234 example.com. FAKE"));
+ findTest(Name("nodelegation.example.org"), RRType::A(),
+ ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
+ findTest(Name("www.nodelegation.example.org"), RRType::A(),
+ ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
+
+ // Same for RRSIG-only for DNAME
+ updater_.add(ConstRRsetPtr(),
+ textToRRset(
+ "nodname.example.org. 300 IN RRSIG DNAME 5 3 300 "
+ "20120814220826 20120715220826 1234 example.com. FAKE"));
+ findTest(Name("www.nodname.example.org"), RRType::A(),
+ ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
+ // If we have a delegation NS at this node, it will be a bit trickier,
+ // because the zonecut processing actually takes place at the node.
+ // But the RRSIG-only for DNAME shouldn't confuse the process and the NS
+ // should win.
+ ConstRRsetPtr ns_rrset =
+ textToRRset("nodname.example.org. 300 IN NS ns.nodname.example.org.");
+ addToZoneData(ns_rrset);
+ findTest(Name("www.nodname.example.org"), RRType::A(),
+ ZoneFinder::DELEGATION, true, ns_rrset);
+}
+
/// \brief NSEC3 specific tests fixture for the InMemoryZoneFinder class
class InMemoryZoneFinderNSEC3Test : public InMemoryZoneFinderTest {
public:
@@ -1481,4 +1549,17 @@ TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3Walk) {
}
}
}
+
+TEST_F(InMemoryZoneFinderNSEC3Test, RRSIGOnly) {
+ // add an RRSIG-only NSEC3 to the NSEC3 space, and try to find it; it
+ // should result in an exception.
+ const string n8_hash = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
+ updater_.add(ConstRRsetPtr(),
+ textToRRset(
+ n8_hash + ".example.org. 300 IN RRSIG NSEC3 5 3 300 "
+ "20120814220826 20120715220826 1234 example.com. FAKE"));
+ EXPECT_THROW(zone_finder_.findNSEC3(Name("n8.example.org"), false),
+ DataSourceError);
+}
+
}
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
index 5223d83..85be310 100644
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
@@ -1219,7 +1219,7 @@ TEST_F(InMemoryZoneFinderTest, loadFromIterator) {
// purpose of this test, so it should just succeed.
db_client = unittest::createSQLite3Client(
class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied",
- TEST_DATA_DIR "/contexttest.zone");
+ TEST_DATA_DIR "/contexttest-almost-obsolete.zone");
zone_finder_.load(*db_client->getIterator(origin_));
// just checking a couple of RRs in the new version of zone.
diff --git a/src/lib/datasrc/tests/testdata/contexttest-almost-obsolete.zone b/src/lib/datasrc/tests/testdata/contexttest-almost-obsolete.zone
new file mode 100644
index 0000000..f65f8c1
--- /dev/null
+++ b/src/lib/datasrc/tests/testdata/contexttest-almost-obsolete.zone
@@ -0,0 +1,85 @@
+;; 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. 78 3600 300 3600000 3600
+example.org. 3600 IN NS ns1.example.org.
+example.org. 3600 IN NS ns2.example.org.
+example.org. 3600 IN RRSIG NS 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKEFAKE
+example.org. 3600 IN MX 1 mx1.example.org.
+example.org. 3600 IN MX 2 mx2.example.org.
+example.org. 3600 IN MX 3 mx.a.example.org.
+
+ns1.example.org. 3600 IN A 192.0.2.1
+ns1.example.org. 3600 IN RRSIG A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
+ns1.example.org. 3600 IN AAAA 2001:db8::1
+ns1.example.org. 3600 IN RRSIG AAAA 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKEFAKE
+ns2.example.org. 3600 IN A 192.0.2.2
+ns2.example.org. 3600 IN TXT "text data"
+
+mx1.example.org. 3600 IN A 192.0.2.10
+mx2.example.org. 3600 IN AAAA 2001:db8::10
+
+;; delegation
+a.example.org. 3600 IN NS ns1.a.example.org.
+a.example.org. 3600 IN NS ns2.a.example.org.
+a.example.org. 3600 IN NS ns.example.com.
+
+ns1.a.example.org. 3600 IN A 192.0.2.5
+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). One of the NS names matches an empty wildcard node, for
+;; which no additional record should be provided (or any other
+;; disruption should happen).
+e.example.org. 3600 IN NS ns.wild.example.org.
+e.example.org. 3600 IN NS ns.emptywild.example.org.
+e.example.org. 3600 IN NS ns2.example.org.
+*.wild.example.org. 3600 IN A 192.0.2.15
+a.*.emptywild.example.org. 3600 IN AAAA 2001:db8::2
+
+;; additional for an answer RRset (MX) as a result of wildcard
+;; expansion
+*.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
+
+;; the owner name of additional for an answer RRset (MX) has DNAME
+dnamemx.example.org. 3600 IN MX 1 dname.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/testdata/contexttest.zone b/src/lib/datasrc/tests/testdata/contexttest.zone
index 0c1393c..ae028c4 100644
--- a/src/lib/datasrc/tests/testdata/contexttest.zone
+++ b/src/lib/datasrc/tests/testdata/contexttest.zone
@@ -68,6 +68,13 @@ e.example.org. 3600 IN NS ns2.example.org.
*.wild.example.org. 3600 IN A 192.0.2.15
a.*.emptywild.example.org. 3600 IN AAAA 2001:db8::2
+;; One of the additional records actually only has RRSIG, which should
+;; be ignored.
+f.example.org. 3600 IN MX 5 mx1.f.example.org.
+f.example.org. 3600 IN MX 10 mx2.f.example.org.
+mx1.f.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
+mx2.f.example.org. 3600 IN A 192.0.2.16
+
;; additional for an answer RRset (MX) as a result of wildcard
;; expansion
*.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index 1a4cae2..6844712 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -418,4 +418,16 @@ TEST_P(ZoneFinderContextTest, getAdditionalForAny) {
result_sets_.begin(), result_sets_.end());
}
+TEST_P(ZoneFinderContextTest, getAdditionalWithRRSIGOnly) {
+ // This has two MX records, but type-A for one of them only has RRSIG.
+ // It shouldn't be contained in the result.
+ ZoneFinderContextPtr ctx = finder_->find(Name("f.example.org"),
+ RRType::MX(),
+ ZoneFinder::FIND_DNSSEC);
+ EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
+ ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+ rrsetsCheck("mx2.f.example.org. 3600 IN A 192.0.2.16\n",
+ result_sets_.begin(), result_sets_.end());
+}
+
}
More information about the bind10-changes
mailing list