BIND 10 trac1688, updated. 489ef518a4a386d7c86534f15db8621210c8ce9d [1688] Remove unneeded "duplicate additional" check
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Mar 16 16:21:55 UTC 2012
The branch, trac1688 has been updated
via 489ef518a4a386d7c86534f15db8621210c8ce9d (commit)
via a7f2ef92fd007ffc44e2e2572d0390efe8fcf901 (commit)
via e0c470b595d05c8c075732bd090fcb02b2af996e (commit)
via c71fd9915c82c618d865780815bfec5aaf6c19a0 (commit)
via 8e3c36663ec9ee59b710e97a1f6716fb59df1d51 (commit)
via 12f57073eb9f5ff5d11035852e253d25071debab (commit)
via 61992b3bdb4d128971e459da4e6d741a48ad01d1 (commit)
via d05c01185756886ce13c49610a813eeb4288a04f (commit)
via 579ba09beadc10c63ff523ccab6a21f112f364c5 (commit)
via 373eda27fc0e591356a7311e2ad560bb9441e64f (commit)
via 09d97fb51ee5d9d00077a52b3678f94c158a365b (commit)
via 50a11ee4e494c9a57d43cdfb2af953d6c8565e47 (commit)
via 1303709492895c08fac466f75069a2cafafb1de5 (commit)
via 77ab7a1390765dead65be7b3a75bfafdee1f6abc (commit)
via 1e62bf975ba54ebee2e5ddc2a2cc26ca5c254f44 (commit)
via 1ddc5eccbe9fc1784a3447c38f708a389a45d83f (commit)
via 9c8dd4effe803bedeb2660c30f72a3ac4ecb308d (commit)
via 5852324e1ad021881339e6ef4cb62611bdfc1b5a (commit)
via 5845ab9615b27fe8efa38b38622fd12a42350e04 (commit)
via 0bb258f8610620191d75cfd5d2308b6fc558c280 (commit)
via bc67fb7ccb6d655fd46272c1dfd89a0e58677035 (commit)
via 113f736e002db510897feb1e6e55600d622f9d26 (commit)
via aa72029e21dc74db7eb7a354ef9f921227e53a6b (commit)
via 5c681eddd0ab1819dc7fadd692cadf98991a4d64 (commit)
via 8173e046080fe51963a37ba89107a8871a0b5353 (commit)
via 758d1d155f95a65702969866454ccfdfd90a7336 (commit)
via e9a7f0106db4f30af9f64e663d39db262850f153 (commit)
via 8b2c30923f169c6b747158740a85be6d68a1d05c (commit)
via 699068ef1467867fbbb86cfebc20e823c5128100 (commit)
via 83474d8f558bebb4be0b0f75e843fab993ee3713 (commit)
via 961f28cdfb0f5cc1f5be9613d5f60a7801c92b0a (commit)
via cf5904a4ad2685c8923f4fbee1987132595908db (commit)
via 3d402d65a8aa0f271190b40f5e141c4e5ee7b31d (commit)
via 3422adaa26b0e1c24d6e230694975a4986cb0965 (commit)
via ede52d8098375352ae87a124619ad78f01fa2e28 (commit)
via 5043998b29c17dd31a06cdfa9bcd73eb2832127b (commit)
via c0c59aceac2afeec9ae3e2711b21e177046b9db3 (commit)
via 460facf264d8a653a959013ce6d7c25875695bc3 (commit)
via 4f93a3a8366f971078dc9c8fe4c846c447a7a45d (commit)
via 70c188de44d2705f6944e37c3e1513572fb5d3d9 (commit)
via 3e344c14a192be56666978933dd4ca0af3cd6a86 (commit)
via 0c1908c1225e8933ac6f2e093f63ef12d3dfc6ee (commit)
via 64caf0ab35936f4df289032579783a63a5f26fee (commit)
via d5ec40dace9fddaaec9873cfca2d670e8d35650a (commit)
via 56824afc873d66a300f2dbde46e906c163e2d492 (commit)
via 95af6c2e54fb45fa5af1a2d3650376ccadd32c7b (commit)
via 803c513e70af98eb71d4fcd954ae1714b6f1c968 (commit)
via f59f3629b17d25cf0f8920582af2e5e1ca5283c1 (commit)
via 2e14ad5917f64c67866f5b49a87515c5c6479ef3 (commit)
from b35f3264ece9358619c3831aa6fe6bf74a14c8c9 (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 489ef518a4a386d7c86534f15db8621210c8ce9d
Author: Stephen Morris <stephen at isc.org>
Date: Fri Mar 16 15:56:35 2012 +0000
[1688] Remove unneeded "duplicate additional" check
This is now replaced by the duplicate check when the response is
created.
commit a7f2ef92fd007ffc44e2e2572d0390efe8fcf901
Author: Stephen Morris <stephen at isc.org>
Date: Fri Mar 16 15:35:34 2012 +0000
[1688] Add optimisation for RBNodeRRsets
Reduce the cost of comparing RRsets when ignoring duplicate ones
in the preparation of an output message.
commit e0c470b595d05c8c075732bd090fcb02b2af996e
Author: Stephen Morris <stephen at isc.org>
Date: Fri Mar 16 14:52:11 2012 +0000
[1688] Remove duplicate RRsets when producing output message
When Query::createResponse() creates a message, this change ensures
that any duplicate RRsets are removed.
commit c71fd9915c82c618d865780815bfec5aaf6c19a0
Author: Stephen Morris <stephen at isc.org>
Date: Thu Mar 15 17:24:25 2012 +0000
[1688] Add AbstractRRset::lthan()
Provides ordering needed for adding RRsets into a multiset for
duplicate RRset removal.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 5 +
src/bin/auth/auth_srv.cc | 34 +-
src/bin/auth/query.cc | 313 +++++++-----
src/bin/auth/query.h | 111 ++++-
src/bin/auth/tests/auth_srv_unittest.cc | 22 +
src/bin/auth/tests/query_unittest.cc | 531 +++++++++++++------
src/bin/resolver/resolver.cc | 1 +
src/bin/xfrin/tests/xfrin_test.py | 53 ++-
src/bin/xfrout/xfrout.py.in | 14 +-
src/bin/xfrout/xfrout.spec.pre.in | 13 +
src/lib/acl/ip_check.cc | 1 +
src/lib/asiodns/dns_service.cc | 79 ++-
src/lib/asiodns/dns_service.h | 26 +-
src/lib/asiodns/io_fetch.cc | 1 +
src/lib/asiodns/sync_udp_server.cc | 1 +
src/lib/asiodns/tcp_server.cc | 1 +
src/lib/asiodns/tests/io_service_unittest.cc | 5 +
src/lib/asiodns/udp_server.cc | 1 +
src/lib/asiolink/io_service.cc | 1 +
src/lib/cache/tests/negative_cache_unittest.cc | 52 ++-
src/lib/datasrc/rbnode_rrset.h | 19 +
src/lib/datasrc/tests/rbnode_rrset_unittest.cc | 80 +++
src/lib/dns/rrset.cc | 29 ++
src/lib/dns/rrset.h | 22 +
src/lib/dns/tests/rrset_unittest.cc | 61 +++
src/lib/python/isc/notify/notify_out.py | 13 +-
src/lib/python/isc/notify/tests/notify_out_test.py | 29 +-
src/lib/resolve/recursive_query.cc | 1 +
src/lib/resolve/tests/recursive_query_unittest.cc | 1 +
src/lib/server_common/tests/client_unittest.cc | 1 +
src/lib/testutils/srv_test.cc | 1 +
src/lib/testutils/testdata/.gitignore | 2 +
src/lib/util/buffer.h | 4 +-
src/lib/util/tests/buffer_unittest.cc | 12 +-
.../configurations/example.org.inmem.config | 1 +
tests/lettuce/data/example.org | 12 +
tests/lettuce/features/queries.feature | 81 +++
tools/git-obsolete-branch.py | 198 ++++++++
38 files changed, 1422 insertions(+), 410 deletions(-)
create mode 100644 tests/lettuce/configurations/example.org.inmem.config
create mode 100644 tests/lettuce/data/example.org
create mode 100644 tests/lettuce/features/queries.feature
create mode 100755 tools/git-obsolete-branch.py
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index c56c407..b62825a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+402. [func] jelte
+ b10-xfrout now has a visible command to send out notifies for
+ a given zone, callable from bindctl. Xfrout notify <zone> [class]
+ (Trac #1321, git 0bb258f8610620191d75cfd5d2308b6fc558c280)
+
401. [func]* jinmei
libdns++: updated the internal implementation of the
MessageRenderer class. This is mostly a transparent change, but
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index 524d581..5bef3f8 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <algorithm>
@@ -99,6 +100,7 @@ public:
IOService io_service_;
+ MessageRenderer renderer_;
/// Currently non-configurable, but will be.
static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
@@ -161,6 +163,8 @@ private:
// validateStatistics
bool validateStatistics(isc::data::ConstElementPtr data) const;
+
+ auth::Query query_;
};
AuthSrvImpl::AuthSrvImpl(const bool use_cache,
@@ -304,8 +308,9 @@ makeErrorMessage(Message& message, OutputBuffer& buffer,
message.setHeaderFlag(Message::HEADERFLAG_CD);
}
for_each(questions.begin(), questions.end(), QuestionInserter(message));
- message.setRcode(rcode);
+ message.setRcode(rcode);
+
MessageRenderer renderer;
renderer.setBuffer(&buffer);
if (tsig_context.get() != NULL) {
@@ -551,8 +556,7 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
if (memory_client_ && memory_client_class_ == question->getClass()) {
const RRType& qtype = question->getType();
const Name& qname = question->getName();
- auth::Query(*memory_client_, qname, qtype, message,
- dnssec_ok).process();
+ query_.process(*memory_client_, qname, qtype, message, dnssec_ok);
} else {
datasrc::Query query(message, cache_, dnssec_ok);
data_sources_.doQuery(query);
@@ -563,20 +567,19 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
return (true);
}
- MessageRenderer renderer;
- renderer.setBuffer(&buffer);
+ renderer_.clear();
+ renderer_.setBuffer(&buffer);
+
const bool udp_buffer =
(io_message.getSocket().getProtocol() == IPPROTO_UDP);
- renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
+ renderer_.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
if (tsig_context.get() != NULL) {
- message.toWire(renderer, *tsig_context);
+ message.toWire(renderer_, *tsig_context);
} else {
- message.toWire(renderer);
+ message.toWire(renderer_);
}
- renderer.setBuffer(NULL);
LOG_DEBUG(auth_logger, DBG_AUTH_MESSAGES, AUTH_SEND_NORMAL_RESPONSE)
- .arg(renderer.getLength()).arg(message);
-
+ .arg(renderer_.getLength()).arg(message.toText());
return (true);
}
@@ -694,14 +697,13 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
message.setHeaderFlag(Message::HEADERFLAG_AA);
message.setRcode(Rcode::NOERROR());
- MessageRenderer renderer;
- renderer.setBuffer(&buffer);
+ renderer_.clear();
+ renderer_.setBuffer(&buffer);
if (tsig_context.get() != NULL) {
- message.toWire(renderer, *tsig_context);
+ message.toWire(renderer_, *tsig_context);
} else {
- message.toWire(renderer);
+ message.toWire(renderer_);
}
- renderer.setBuffer(NULL);
return (true);
}
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index 7d50393..3b698b5 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -15,6 +15,7 @@
#include <dns/message.h>
#include <dns/rcode.h>
#include <dns/rrtype.h>
+#include <dns/rrset.h>
#include <dns/rdataclass.h>
#include <datasrc/client.h>
@@ -26,6 +27,7 @@
#include <boost/function.hpp>
#include <algorithm> // for std::max
+#include <set>
#include <vector>
using namespace std;
@@ -35,22 +37,64 @@ using namespace isc::dns::rdata;
// Commonly used helper callback object for vector<ConstRRsetPtr> to
// insert them to (the specified section of) a message.
+//
+// One feature is that it maintains an internal set of raw pointers to the
+// RRsets as they are added (this is safe - the object is only in scope in
+// the createResponse() method and during this time, all RRsets referred to
+// remain in existence due to the presence of the ConstRRsetPtr objects
+// from which the raw objects were derived). The set is used to detect
+// and discard duplicates.
namespace {
class RRsetInserter {
+private:
+ // \brief RRset comparison functor.
+ struct RRsetLthan {
+ bool operator()(const AbstractRRset* r1, const AbstractRRset* r2) {
+ return (r1->lthan(*r2));
+ }
+ };
+
+ typedef std::set<const AbstractRRset*, RRsetLthan> AddedRRsets;
+
public:
- RRsetInserter(Message& msg, Message::Section section, bool dnssec) :
- msg_(msg), section_(section), dnssec_(dnssec)
+ RRsetInserter(Message& msg, const Message::Section section,
+ const bool dnssec) :
+ msg_(msg), section_(section), dnssec_(dnssec)
{}
- void operator()(const ConstRRsetPtr& rrset) {
- msg_.addRRset(section_,
- boost::const_pointer_cast<AbstractRRset>(rrset),
- dnssec_);
+
+ // \brief Set Target Section
+ //
+ // Sets the section into which the information added by addRRset will be
+ // inserted.
+ //
+ // \param section New section number
+ void setSection(Message::Section section) {
+ section_ = section;
+ }
+
+ // Insertion operation
+ //
+ // \param rrset Pointer to RRset to be added to the message
+ void addRRset(const ConstRRsetPtr& rrset) {
+ // Has the RRset already been added to this message?
+ std::pair<AddedRRsets::iterator, bool> result =
+ rrsets_added_.insert(rrset.get());
+ if (result.second) {
+ // Were able to add the pointer to the RRset to rrsets_added_, so
+ // the RRset has not already been seen. Add it to the message.
+ // The const-cast is wrong, but the Message interface seems
+ // to insist.
+ msg_.addRRset(section_,
+ boost::const_pointer_cast<AbstractRRset>(rrset),
+ dnssec_);
+ }
}
private:
Message& msg_;
- const Message::Section section_;
+ Message::Section section_;
const bool dnssec_;
+ AddedRRsets rrsets_added_;
};
// This is a "constant" vector storing desired RR types for the additional
@@ -65,26 +109,6 @@ A_AND_AAAA() {
return (needed_types);
}
-// A wrapper for ZoneFinder::Context::getAdditional() so we don't include
-// duplicate RRs. This is not efficient, and we should actually unify
-// this at the end of the process() method. See also #1688.
-void
-getAdditional(const Name& qname, RRType qtype,
- ZoneFinder::Context& ctx, vector<ConstRRsetPtr>& results)
-{
- vector<ConstRRsetPtr> additionals;
- ctx.getAdditional(A_AND_AAAA(), additionals);
-
- vector<ConstRRsetPtr>::const_iterator it = additionals.begin();
- vector<ConstRRsetPtr>::const_iterator it_end = additionals.end();
- for (; it != it_end; ++it) {
- if ((qtype == (*it)->getType() || qtype == RRType::ANY()) &&
- qname == (*it)->getName()) {
- continue;
- }
- results.push_back(*it);
- }
-}
}
namespace isc {
@@ -98,13 +122,7 @@ Query::addSOA(ZoneFinder& finder) {
isc_throw(NoSOA, "There's no SOA record in zone " <<
finder.getOrigin().toText());
} else {
- /*
- * FIXME:
- * The const-cast is wrong, but the Message interface seems
- * to insist.
- */
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(soa_ctx->rrset), dnssec_);
+ authorities_.push_back(soa_ctx->rrset);
}
}
@@ -123,8 +141,7 @@ Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
}
// Add the NSEC proving NXDOMAIN to the authority section.
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(nsec), dnssec_);
+ authorities_.push_back(nsec);
// Next, identify the best possible wildcard name that would match
// the query name. It's the longer common suffix with the qname
@@ -135,14 +152,14 @@ Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
// and the best possible wildcard is *.b.example.com. If the NXDOMAIN
// NSEC is a.example.com. NSEC c.b.example.com., the longer suffix
// is the next domain of the NSEC, and we get the same wildcard name.
- const int qlabels = qname_.getLabelCount();
- const int olabels = qname_.compare(nsec->getName()).getCommonLabels();
- const int nlabels = qname_.compare(
+ const int qlabels = qname_->getLabelCount();
+ const int olabels = qname_->compare(nsec->getName()).getCommonLabels();
+ const int nlabels = qname_->compare(
dynamic_cast<const generic::NSEC&>(nsec->getRdataIterator()->
getCurrent()).
getNextName()).getCommonLabels();
const int common_labels = std::max(olabels, nlabels);
- const Name wildname(Name("*").concatenate(qname_.split(qlabels -
+ const Name wildname(Name("*").concatenate(qname_->split(qlabels -
common_labels)));
// Confirm the wildcard doesn't exist (this should result in NXDOMAIN;
@@ -161,9 +178,7 @@ Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
// stage of performance optimization, we should consider optimizing this
// for some optimized data source implementations.
if (nsec->getName() != fcontext->rrset->getName()) {
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(fcontext->rrset),
- dnssec_);
+ authorities_.push_back(fcontext->rrset);
}
}
@@ -183,16 +198,10 @@ Query::addClosestEncloserProof(ZoneFinder& finder, const Name& name,
}
if (add_closest) {
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(
- result.closest_proof),
- dnssec_);
+ authorities_.push_back(result.closest_proof);
}
if (result.next_proof) {
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(
- result.next_proof),
- dnssec_);
+ authorities_.push_back(result.next_proof);
}
return (result.closest_labels);
}
@@ -208,10 +217,7 @@ Query::addNSEC3ForName(ZoneFinder& finder, const Name& name, bool match) {
<< (result.matched ? "matching" : "covering")
<< " NSEC3 found for " << name);
}
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(
- result.closest_proof),
- dnssec_);
+ authorities_.push_back(result.closest_proof);
}
void
@@ -219,12 +225,12 @@ Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
// Firstly get the NSEC3 proves for Closest Encloser Proof
// See Section 7.2.1 of RFC 5155.
const uint8_t closest_labels =
- addClosestEncloserProof(finder, qname_, false);
+ addClosestEncloserProof(finder, *qname_, false);
// Next, construct the wildcard name at the closest encloser, i.e.,
// '*' followed by the closest encloser, and add NSEC3 for it.
const Name wildname(Name("*").concatenate(
- qname_.split(qname_.getLabelCount() - closest_labels)));
+ qname_->split(qname_->getLabelCount() - closest_labels)));
addNSEC3ForName(finder, wildname, false);
}
@@ -239,17 +245,14 @@ Query::addWildcardProof(ZoneFinder& finder,
// substitution. Confirm that by specifying NO_WILDCARD. It should
// result in NXDOMAIN and an NSEC RR that proves it should be returned.
ConstZoneFinderContextPtr fcontext =
- finder.find(qname_, RRType::NSEC(),
+ finder.find(*qname_, RRType::NSEC(),
dnssec_opt_ | ZoneFinder::NO_WILDCARD);
if (fcontext->code != ZoneFinder::NXDOMAIN || !fcontext->rrset ||
fcontext->rrset->getRdataCount() == 0) {
isc_throw(BadNSEC,
"Unexpected NSEC result for wildcard proof");
}
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(
- fcontext->rrset),
- dnssec_);
+ authorities_.push_back(fcontext->rrset);
} else if (db_context.isNSEC3Signed()) {
// Case for RFC 5155 Section 7.2.6.
//
@@ -257,7 +260,7 @@ Query::addWildcardProof(ZoneFinder& finder,
// of the matching wildcard, so NSEC3 for its next closer (and only
// that NSEC3) is what we are expected to provided per the RFC (if
// this assumption isn't met the zone is broken anyway).
- addClosestEncloserProof(finder, qname_, false, false);
+ addClosestEncloserProof(finder, *qname_, false, false);
}
}
@@ -270,7 +273,7 @@ Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
}
ConstZoneFinderContextPtr fcontext =
- finder.find(qname_, RRType::NSEC(),
+ finder.find(*qname_, RRType::NSEC(),
dnssec_opt_ | ZoneFinder::NO_WILDCARD);
if (fcontext->code != ZoneFinder::NXDOMAIN || !fcontext->rrset ||
fcontext->rrset->getRdataCount() == 0) {
@@ -279,9 +282,7 @@ Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
if (nsec->getName() != fcontext->rrset->getName()) {
// one NSEC RR proves wildcard_nxrrset that no matched QNAME.
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(fcontext->rrset),
- dnssec_);
+ authorities_.push_back(fcontext->rrset);
}
}
@@ -290,10 +291,7 @@ Query::addDS(ZoneFinder& finder, const Name& dname) {
ConstZoneFinderContextPtr ds_context =
finder.find(dname, RRType::DS(), dnssec_opt_);
if (ds_context->code == ZoneFinder::SUCCESS) {
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(
- ds_context->rrset),
- dnssec_);
+ authorities_.push_back(ds_context->rrset);
} else if (ds_context->code == ZoneFinder::NXRRSET &&
ds_context->isNSECSigned()) {
addNXRRsetProof(finder, *ds_context);
@@ -312,29 +310,26 @@ Query::addNXRRsetProof(ZoneFinder& finder,
const ZoneFinder::Context& db_context)
{
if (db_context.isNSECSigned() && db_context.rrset) {
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(
- db_context.rrset),
- dnssec_);
+ authorities_.push_back(db_context.rrset);
if (db_context.isWildcard()) {
addWildcardNXRRSETProof(finder, db_context.rrset);
}
} else if (db_context.isNSEC3Signed() && !db_context.isWildcard()) {
- if (qtype_ == RRType::DS()) {
+ if (*qtype_ == RRType::DS()) {
// RFC 5155, Section 7.2.4. Add either NSEC3 for the qname or
// closest (provable) encloser proof in case of optout.
- addClosestEncloserProof(finder, qname_, true);
+ addClosestEncloserProof(finder, *qname_, true);
} else {
// RFC 5155, Section 7.2.3. Just add NSEC3 for the qname.
- addNSEC3ForName(finder, qname_, true);
+ addNSEC3ForName(finder, *qname_, true);
}
} else if (db_context.isNSEC3Signed() && db_context.isWildcard()) {
// Case for RFC 5155 Section 7.2.5: add closest encloser proof for the
// qname, construct the matched wildcard name and add NSEC3 for it.
const uint8_t closest_labels =
- addClosestEncloserProof(finder, qname_, false);
+ addClosestEncloserProof(finder, *qname_, false);
const Name wname = Name("*").concatenate(
- qname_.split(qname_.getLabelCount() - closest_labels));
+ qname_->split(qname_->getLabelCount() - closest_labels));
addNSEC3ForName(finder, wname, true);
}
}
@@ -354,10 +349,8 @@ Query::addAuthAdditional(ZoneFinder& finder,
isc_throw(NoApexNS, "There's no apex NS records in zone " <<
finder.getOrigin().toText());
}
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(
- ns_context->rrset), dnssec_);
- getAdditional(qname_, qtype_, *ns_context, additionals);
+ authorities_.push_back(ns_context->rrset);
+ ns_context->getAdditional(A_AND_AAAA(), additionals);
}
namespace {
@@ -377,10 +370,20 @@ findZone(const DataSourceClient& client, const Name& qname, RRType qtype) {
}
void
-Query::process() {
+Query::process(datasrc::DataSourceClient& datasrc_client,
+ const isc::dns::Name& qname, const isc::dns::RRType& qtype,
+ isc::dns::Message& response, bool dnssec)
+{
+ // Set up the cleaner object so internal pointers and vectors are
+ // always reset after scope leaves this method
+ QueryCleaner cleaner(*this);
+
+ // Set up query parameters for the rest of the (internal) methods
+ initialize(datasrc_client, qname, qtype, response, dnssec);
+
// Found a zone which is the nearest ancestor to QNAME
- const DataSourceClient::FindResult result = findZone(datasrc_client_,
- qname_, qtype_);
+ const DataSourceClient::FindResult result = findZone(*datasrc_client_,
+ *qname_, *qtype_);
// If we have no matching authoritative zone for the query name, return
// REFUSED. In short, this is to be compatible with BIND 9, but the
@@ -392,38 +395,34 @@ Query::process() {
// If we tried to find a "parent zone" for a DS query and failed,
// we may still have authority at the child side. If we do, the query
// has to be handled there.
- if (qtype_ == RRType::DS() && qname_.getLabelCount() > 1 &&
+ if (*qtype_ == RRType::DS() && qname_->getLabelCount() > 1 &&
processDSAtChild()) {
return;
}
- response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
- response_.setRcode(Rcode::REFUSED());
+ response_->setHeaderFlag(Message::HEADERFLAG_AA, false);
+ response_->setRcode(Rcode::REFUSED());
return;
}
ZoneFinder& zfinder = *result.zone_finder;
// We have authority for a zone that contain the query name (possibly
// indirectly via delegation). Look into the zone.
- response_.setHeaderFlag(Message::HEADERFLAG_AA);
- response_.setRcode(Rcode::NOERROR());
- vector<ConstRRsetPtr> target;
- vector<ConstRRsetPtr> additionals;
+ response_->setHeaderFlag(Message::HEADERFLAG_AA);
+ response_->setRcode(Rcode::NOERROR());
boost::function0<ZoneFinderContextPtr> find;
- const bool qtype_is_any = (qtype_ == RRType::ANY());
+ const bool qtype_is_any = (*qtype_ == RRType::ANY());
if (qtype_is_any) {
- find = boost::bind(&ZoneFinder::findAll, &zfinder, qname_,
- boost::ref(target), dnssec_opt_);
+ find = boost::bind(&ZoneFinder::findAll, &zfinder, *qname_,
+ boost::ref(answers_), dnssec_opt_);
} else {
- find = boost::bind(&ZoneFinder::find, &zfinder, qname_, qtype_,
+ find = boost::bind(&ZoneFinder::find, &zfinder, *qname_, *qtype_,
dnssec_opt_);
}
ZoneFinderContextPtr db_context(find());
switch (db_context->code) {
case ZoneFinder::DNAME: {
// First, put the dname into the answer
- response_.addRRset(Message::SECTION_ANSWER,
- boost::const_pointer_cast<AbstractRRset>(db_context->rrset),
- dnssec_);
+ answers_.push_back(db_context->rrset);
/*
* Empty DNAME should never get in, as it is impossible to
* create one in master file.
@@ -436,7 +435,7 @@ Query::process() {
dynamic_cast<const rdata::generic::DNAME&>(
db_context->rrset->getRdataIterator()->getCurrent()));
// The yet unmatched prefix dname
- const Name prefix(qname_.split(0, qname_.getLabelCount() -
+ const Name prefix(qname_->split(0, qname_->getLabelCount() -
db_context->rrset->getName().getLabelCount()));
// If we put it together, will it be too long?
// (The prefix contains trailing ., which will be removed
@@ -446,20 +445,20 @@ Query::process() {
* In case the synthesized name is too long, section 4.1
* of RFC 2672 mandates we return YXDOMAIN.
*/
- response_.setRcode(Rcode::YXDOMAIN());
- return;
+ response_->setRcode(Rcode::YXDOMAIN());
+ break;
}
// The new CNAME we are creating (it will be unsigned even
// with DNSSEC, the DNAME is signed and it can be validated
// by that)
- RRsetPtr cname(new RRset(qname_, db_context->rrset->getClass(),
+ RRsetPtr cname(new RRset(*qname_, db_context->rrset->getClass(),
RRType::CNAME(), db_context->rrset->getTTL()));
// Construct the new target by replacing the end
- cname->addRdata(rdata::generic::CNAME(qname_.split(0,
- qname_.getLabelCount() -
+ cname->addRdata(rdata::generic::CNAME(qname_->split(0,
+ qname_->getLabelCount() -
db_context->rrset->getName().getLabelCount()).
concatenate(dname.getDname())));
- response_.addRRset(Message::SECTION_ANSWER, cname, dnssec_);
+ answers_.push_back(cname);
break;
}
case ZoneFinder::CNAME:
@@ -472,9 +471,7 @@ Query::process() {
*
* So, just put it there.
*/
- response_.addRRset(Message::SECTION_ANSWER,
- boost::const_pointer_cast<AbstractRRset>(db_context->rrset),
- dnssec_);
+ answers_.push_back(db_context->rrset);
// If the answer is a result of wildcard substitution,
// add a proof that there's no closer name.
@@ -483,21 +480,13 @@ Query::process() {
}
break;
case ZoneFinder::SUCCESS:
- if (qtype_is_any) {
- // If quety type is ANY, insert all RRs under the domain
- // into answer section.
- BOOST_FOREACH(ConstRRsetPtr rrset, target) {
- response_.addRRset(Message::SECTION_ANSWER,
- boost::const_pointer_cast<AbstractRRset>(rrset), dnssec_);
- }
- } else {
- response_.addRRset(Message::SECTION_ANSWER,
- boost::const_pointer_cast<AbstractRRset>(db_context->rrset),
- dnssec_);
+ // If query type is ANY, the rrs have already been added
+ if (!qtype_is_any) {
+ answers_.push_back(db_context->rrset);
}
// Retrieve additional records for the answer
- getAdditional(qname_, qtype_, *db_context, additionals);
+ db_context->getAdditional(A_AND_AAAA(), additionals_);
// If apex NS records haven't been provided in the answer
// section, insert apex NS records into the authority section
@@ -507,9 +496,9 @@ Query::process() {
// qname is the zone origin.
if (result.code != result::SUCCESS ||
db_context->code != ZoneFinder::SUCCESS ||
- (qtype_ != RRType::NS() && !qtype_is_any))
+ (*qtype_ != RRType::NS() && !qtype_is_any))
{
- addAuthAdditional(*result.zone_finder, additionals);
+ addAuthAdditional(*result.zone_finder, additionals_);
}
// If the answer is a result of wildcard substitution,
@@ -523,16 +512,14 @@ Query::process() {
// if we are an authority of the child, too. If so, we need to
// complete the process in the child as specified in Section
// 2.2.1.2. of RFC3658.
- if (qtype_ == RRType::DS() && processDSAtChild()) {
+ if (*qtype_ == RRType::DS() && processDSAtChild()) {
return;
}
- response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<AbstractRRset>(db_context->rrset),
- dnssec_);
+ response_->setHeaderFlag(Message::HEADERFLAG_AA, false);
+ authorities_.push_back(db_context->rrset);
// Retrieve additional records for the name servers
- db_context->getAdditional(A_AND_AAAA(), additionals);
+ db_context->getAdditional(A_AND_AAAA(), additionals_);
// If DNSSEC is requested, see whether there is a DS
// record for this delegation.
@@ -541,7 +528,7 @@ Query::process() {
}
break;
case ZoneFinder::NXDOMAIN:
- response_.setRcode(Rcode::NXDOMAIN());
+ response_->setRcode(Rcode::NXDOMAIN());
addSOA(*result.zone_finder);
if (dnssec_) {
if (db_context->isNSECSigned() && db_context->rrset) {
@@ -565,15 +552,62 @@ Query::process() {
break;
}
- for_each(additionals.begin(), additionals.end(),
- RRsetInserter(response_, Message::SECTION_ADDITIONAL,
- dnssec_));
+ createResponse();
+}
+
+void
+Query::initialize(datasrc::DataSourceClient& datasrc_client,
+ const isc::dns::Name& qname, const isc::dns::RRType& qtype,
+ isc::dns::Message& response, bool dnssec)
+{
+ datasrc_client_ = &datasrc_client;
+ qname_ = &qname;
+ qtype_ = &qtype;
+ response_ = &response;
+ dnssec_ = dnssec;
+ dnssec_opt_ = (dnssec ? isc::datasrc::ZoneFinder::FIND_DNSSEC :
+ isc::datasrc::ZoneFinder::FIND_DEFAULT);
+}
+
+void
+Query::createResponse() {
+ // Add the RRsets to the message. The order of sections is important,
+ // as the RRsetInserter remembers RRsets added and will not add
+ // duplicates. Adding in the order answer, authory, additional will
+ // guarantee that if there are duplicates, the single RRset added will
+ // appear in the most important section.
+ std::vector<isc::dns::ConstRRsetPtr>::const_iterator i;
+ RRsetInserter inserter(*response_, Message::SECTION_ANSWER, dnssec_);
+ for (i = answers_.begin(); i != answers_.end(); ++i) {
+ inserter.addRRset(*i);
+ }
+
+ inserter.setSection(Message::SECTION_AUTHORITY);
+ for (i = authorities_.begin(); i != authorities_.end(); ++i) {
+ inserter.addRRset(*i);
+ }
+
+ inserter.setSection(Message::SECTION_ADDITIONAL);
+ for (i = additionals_.begin(); i != additionals_.end(); ++i) {
+ inserter.addRRset(*i);
+ }
+}
+
+void
+Query::reset() {
+ datasrc_client_ = NULL;
+ qname_ = NULL;
+ qtype_ = NULL;
+ response_ = NULL;
+ answers_.clear();
+ authorities_.clear();
+ additionals_.clear();
}
bool
Query::processDSAtChild() {
const DataSourceClient::FindResult zresult =
- datasrc_client_.findZone(qname_);
+ datasrc_client_->findZone(*qname_);
if (zresult.code != result::SUCCESS) {
return (false);
@@ -588,17 +622,18 @@ Query::processDSAtChild() {
// The important point in this case is to return SOA so that the resolver
// that happens to contact us can hunt for the appropriate parent zone
// by seeing the SOA.
- response_.setHeaderFlag(Message::HEADERFLAG_AA);
- response_.setRcode(Rcode::NOERROR());
+ response_->setHeaderFlag(Message::HEADERFLAG_AA);
+ response_->setRcode(Rcode::NOERROR());
addSOA(*zresult.zone_finder);
ConstZoneFinderContextPtr ds_context =
- zresult.zone_finder->find(qname_, RRType::DS(), dnssec_opt_);
+ zresult.zone_finder->find(*qname_, RRType::DS(), dnssec_opt_);
if (ds_context->code == ZoneFinder::NXRRSET) {
if (dnssec_) {
addNXRRsetProof(*zresult.zone_finder, *ds_context);
}
}
+ createResponse();
return (true);
}
diff --git a/src/bin/auth/query.h b/src/bin/auth/query.h
index f8a8f02..5a11288 100644
--- a/src/bin/auth/query.h
+++ b/src/bin/auth/query.h
@@ -18,6 +18,8 @@
#include <dns/rrset.h>
#include <datasrc/zone.h>
+#include <boost/noncopyable.hpp>
+
#include <vector>
namespace isc {
@@ -34,6 +36,13 @@ class DataSourceClient;
namespace auth {
+/// \brief Initial reserved size for the vectors in Query
+///
+/// The value is larger than we expect the vectors to even become, and
+/// has been chosen arbitrarily. The reason to set them quite high is
+/// to prevent reallocation on addition.
+const size_t RESERVE_RRSETS = 64;
+
/// The \c Query class represents a standard DNS query that encapsulates
/// processing logic to answer the query.
///
@@ -64,7 +73,7 @@ namespace auth {
/// likely to misuse one of the classes instead of the other
/// accidentally, and since it's considered a temporary development state,
/// we keep this name at the moment.
-class Query {
+class Query : boost::noncopyable {
private:
/// \brief Adds a SOA.
@@ -226,10 +235,10 @@ private:
void addNSEC3ForName(isc::datasrc::ZoneFinder& finder,
const isc::dns::Name& name, bool match);
-public:
- /// Constructor from query parameters.
+ /// Set up the Query object for a new query lookup
///
- /// This constructor never throws an exception.
+ /// This is the first step of the process() method, and initializes
+ /// the member data
///
/// \param datasrc_client The datasource wherein the answer to the query is
/// to be found.
@@ -238,14 +247,61 @@ public:
/// \param response The response message to store the answer to the query.
/// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
/// possible.
- Query(const isc::datasrc::DataSourceClient& datasrc_client,
- const isc::dns::Name& qname, const isc::dns::RRType& qtype,
- isc::dns::Message& response, bool dnssec = false) :
- datasrc_client_(datasrc_client), qname_(qname), qtype_(qtype),
- response_(response), dnssec_(dnssec),
- dnssec_opt_(dnssec ? isc::datasrc::ZoneFinder::FIND_DNSSEC :
- isc::datasrc::ZoneFinder::FIND_DEFAULT)
- {}
+ void initialize(datasrc::DataSourceClient& datasrc_client,
+ const isc::dns::Name& qname, const isc::dns::RRType& qtype,
+ isc::dns::Message& response, bool dnssec = false);
+
+ /// \brief Resets any partly built response data, and internal pointers
+ ///
+ /// Called by the QueryCleaner object upon its destruction
+ void reset();
+
+ /// \brief Internal class used for cleanup of Query members
+ ///
+ /// The process() call creates an object of this class, which
+ /// upon its destruction, calls Query::reset(), so that outside
+ /// of single calls to process(), the query state is always clean.
+ class QueryCleaner {
+ public:
+ QueryCleaner(isc::auth::Query& query) : query_(query) {}
+ ~QueryCleaner() { query_.reset(); }
+ private:
+ isc::auth::Query& query_;
+ };
+
+protected:
+ // Following methods declared protected so they can be accessed
+ // by unit tests.
+
+ /// \brief Fill in the response sections
+ ///
+ /// This is the final step of the process() method, and within
+ /// that method, it should be called before it returns (if any
+ /// response data is to be added)
+ ///
+ /// This will take each RRset collected in answers_, authorities_, and
+ /// additionals_, and add them to their corresponding sections in
+ /// the response message. The RRsets are filtered such that a
+ /// particular RRset appears only once in the message.
+ ///
+ /// After they are added, the vectors are cleared.
+ void createResponse();
+
+public:
+ /// Default constructor.
+ ///
+ /// Query parameters will be set by the call to process()
+ ///
+ Query() :
+ datasrc_client_(NULL), qname_(NULL), qtype_(NULL),
+ dnssec_(false), dnssec_opt_(isc::datasrc::ZoneFinder::FIND_DEFAULT),
+ response_(NULL)
+ {
+ answers_.reserve(RESERVE_RRSETS);
+ authorities_.reserve(RESERVE_RRSETS);
+ additionals_.reserve(RESERVE_RRSETS);
+ }
+
/// Process the query.
///
@@ -273,7 +329,17 @@ public:
/// This might throw BadZone or any of its specific subclasses, but that
/// shouldn't happen in real-life (as BadZone means wrong data, it should
/// have been rejected upon loading).
- void process();
+ ///
+ /// \param datasrc_client The datasource wherein the answer to the query is
+ /// to be found.
+ /// \param qname The query name
+ /// \param qtype The RR type of the query
+ /// \param response The response message to store the answer to the query.
+ /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
+ /// possible.
+ void process(datasrc::DataSourceClient& datasrc_client,
+ const isc::dns::Name& qname, const isc::dns::RRType& qtype,
+ isc::dns::Message& response, bool dnssec = false);
/// \short Bad zone data encountered.
///
@@ -342,12 +408,19 @@ public:
};
private:
- const isc::datasrc::DataSourceClient& datasrc_client_;
- const isc::dns::Name& qname_;
- const isc::dns::RRType& qtype_;
- isc::dns::Message& response_;
- const bool dnssec_;
- const isc::datasrc::ZoneFinder::FindOptions dnssec_opt_;
+ const isc::datasrc::DataSourceClient* datasrc_client_;
+ const isc::dns::Name* qname_;
+ const isc::dns::RRType* qtype_;
+ bool dnssec_;
+ isc::datasrc::ZoneFinder::FindOptions dnssec_opt_;
+
+protected:
+ // Following members declared protected to allow them to be accessed
+ // by unit tests.
+ isc::dns::Message* response_;
+ std::vector<isc::dns::ConstRRsetPtr> answers_;
+ std::vector<isc::dns::ConstRRsetPtr> authorities_;
+ std::vector<isc::dns::ConstRRsetPtr> additionals_;
};
}
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index 4823ad7..e13987a 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -1075,6 +1075,28 @@ TEST_F(AuthSrvTest, listenAddresses) {
"Released tokens");
}
+TEST_F(AuthSrvTest, processNormalQuery_reuseRenderer1) {
+ UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+ default_qid, Name("example.com"),
+ RRClass::IN(), RRType::NS());
+
+ request_message.setHeaderFlag(Message::HEADERFLAG_AA);
+ createRequestPacket(request_message, IPPROTO_UDP);
+ server.processMessage(*io_message, *parse_message, *response_obuffer, &dnsserv);
+ EXPECT_NE(request_message.getRcode(), parse_message->getRcode());
+}
+
+TEST_F(AuthSrvTest, processNormalQuery_reuseRenderer2) {
+ UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+ default_qid, Name("example.com"),
+ RRClass::IN(), RRType::SOA());
+
+ request_message.setHeaderFlag(Message::HEADERFLAG_AA);
+ createRequestPacket(request_message, IPPROTO_UDP);
+ server.processMessage(*io_message, *parse_message, *response_obuffer, &dnsserv);
+ ConstQuestionPtr question = *parse_message->beginQuestion();
+ EXPECT_STRNE(question->getType().toText().c_str(),RRType::NS().toText().c_str());
+}
//
// Tests for catching exceptions in various stages of the query processing
//
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index 3c901aa..e408543 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -12,12 +12,13 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <map>
#include <sstream>
#include <vector>
-#include <map>
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
+#include <boost/static_assert.hpp>
#include <exceptions/exceptions.h>
@@ -903,6 +904,7 @@ protected:
const qid_t qid;
const uint16_t query_code;
const string ns_addrs_and_sig_txt; // convenient shortcut
+ Query query;
};
// A wrapper to check resulting response message commonly used in
@@ -946,25 +948,40 @@ TEST_F(QueryTest, noZone) {
// There's no zone in the memory datasource. So the response should have
// REFUSED.
InMemoryClient empty_memory_client;
- Query nozone_query(empty_memory_client, qname, qtype, response);
- EXPECT_NO_THROW(nozone_query.process());
+ EXPECT_NO_THROW(query.process(empty_memory_client, qname, qtype,
+ response));
EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
}
TEST_F(QueryTest, exactMatch) {
- Query query(memory_client, qname, qtype, response);
- EXPECT_NO_THROW(query.process());
+ EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
// find match rrset
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
www_a_txt, zone_ns_txt, ns_addrs_txt);
}
+TEST_F(QueryTest, exactMatchMultipleQueries) {
+ EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+ // find match rrset
+ responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
+ www_a_txt, zone_ns_txt, ns_addrs_txt);
+
+ // clean up response for second query
+ response.clear(isc::dns::Message::RENDER);
+ response.setRcode(Rcode::NOERROR());
+ response.setOpcode(Opcode::QUERY());
+ EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+ // find match rrset
+ SCOPED_TRACE("Second query");
+ responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
+ www_a_txt, zone_ns_txt, ns_addrs_txt);
+}
+
TEST_F(QueryTest, exactMatchIgnoreSIG) {
// Check that we do not include the RRSIG when not requested even when
// we receive it from the data source.
mock_finder->setIncludeRRSIGAnyway(true);
- Query query(memory_client, qname, qtype, response);
- EXPECT_NO_THROW(query.process());
+ EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
// find match rrset
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
www_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -972,8 +989,8 @@ TEST_F(QueryTest, exactMatchIgnoreSIG) {
TEST_F(QueryTest, dnssecPositive) {
// Just like exactMatch, but the signatures should be included as well
- Query query(memory_client, qname, qtype, response, true);
- EXPECT_NO_THROW(query.process());
+ EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response,
+ true));
// find match rrset
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
(www_a_txt + std::string("www.example.com. 3600 IN RRSIG "
@@ -991,8 +1008,9 @@ TEST_F(QueryTest, dnssecPositive) {
TEST_F(QueryTest, exactAddrMatch) {
// find match rrset, omit additional data which has already been provided
// in the answer section from the additional.
- EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
- response).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("noglue.example.com"),
+ qtype, response));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 2,
"noglue.example.com. 3600 IN A 192.0.2.53\n", zone_ns_txt,
@@ -1003,8 +1021,8 @@ TEST_F(QueryTest, exactAddrMatch) {
TEST_F(QueryTest, apexNSMatch) {
// find match rrset, omit authority data which has already been provided
// in the answer section from the authority section.
- EXPECT_NO_THROW(Query(memory_client, Name("example.com"), RRType::NS(),
- response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+ RRType::NS(), response));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
zone_ns_txt, NULL, ns_addrs_txt);
@@ -1014,8 +1032,8 @@ TEST_F(QueryTest, apexNSMatch) {
TEST_F(QueryTest, exactAnyMatch) {
// find match rrset, omit additional data which has already been provided
// in the answer section from the additional.
- EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"),
- RRType::ANY(), response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("noglue.example.com"),
+ RRType::ANY(), response));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 3, 2,
(string("noglue.example.com. 3600 IN A 192.0.2.53\n") +
@@ -1028,8 +1046,8 @@ TEST_F(QueryTest, exactAnyMatch) {
TEST_F(QueryTest, apexAnyMatch) {
// find match rrset, omit additional data which has already been provided
// in the answer section from the additional.
- EXPECT_NO_THROW(Query(memory_client, Name("example.com"),
- RRType::ANY(), response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+ RRType::ANY(), response));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 5, 0, 3,
(string(soa_txt) + string(zone_ns_txt) +
string(nsec_apex_txt)).c_str(),
@@ -1037,23 +1055,23 @@ TEST_F(QueryTest, apexAnyMatch) {
}
TEST_F(QueryTest, mxANYMatch) {
- EXPECT_NO_THROW(Query(memory_client, Name("mx.example.com"),
- RRType::ANY(), response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("mx.example.com"),
+ RRType::ANY(), response));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 3, 4,
(string(mx_txt) + string(nsec_mx_txt)).c_str(), zone_ns_txt,
(string(ns_addrs_txt) + string(www_a_txt)).c_str());
}
TEST_F(QueryTest, glueANYMatch) {
- EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
- RRType::ANY(), response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("delegation.example.com"),
+ RRType::ANY(), response));
responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
NULL, delegation_txt, ns_addrs_txt);
}
TEST_F(QueryTest, nodomainANY) {
- EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"),
- RRType::ANY(), response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+ RRType::ANY(), response));
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
NULL, soa_txt, NULL, mock_finder->getOrigin());
}
@@ -1065,23 +1083,24 @@ TEST_F(QueryTest, noApexNS) {
// Disable apex NS record
mock_finder->setApexNSFlag(false);
- EXPECT_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
- response).process(), Query::NoApexNS);
+ EXPECT_THROW(query.process(memory_client, Name("noglue.example.com"), qtype,
+ response), Query::NoApexNS);
// We don't look into the response, as it threw
}
TEST_F(QueryTest, delegation) {
- EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
- qtype, response).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("delegation.example.com"),
+ qtype, response));
responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
NULL, delegation_txt, ns_addrs_txt);
}
TEST_F(QueryTest, secureDelegation) {
- EXPECT_NO_THROW(Query(memory_client,
- Name("foo.signed-delegation.example.com"),
- qtype, response, true).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("foo.signed-delegation.example.com"),
+ qtype, response, true));
// Should now contain RRSIG and DS record as well.
responseCheck(response, Rcode::NOERROR(), 0, 0, 3, 0,
@@ -1094,9 +1113,9 @@ TEST_F(QueryTest, secureDelegation) {
}
TEST_F(QueryTest, secureUnsignedDelegation) {
- EXPECT_NO_THROW(Query(memory_client,
- Name("foo.unsigned-delegation.example.com"),
- qtype, response, true).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("foo.unsigned-delegation.example.com"),
+ qtype, response, true));
// Should now contain RRSIG and NSEC record as well.
responseCheck(response, Rcode::NOERROR(), 0, 0, 3, 0,
@@ -1115,8 +1134,9 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3) {
mock_finder->setNSEC3Flag(true);
mock_finder->addRecord(unsigned_delegation_nsec3_txt);
- Query(memory_client, Name("foo.unsigned-delegation.example.com"),
- qtype, response, true).process();
+ query.process(memory_client,
+ Name("foo.unsigned-delegation.example.com"),
+ qtype, response, true);
// The response should contain the NS and matching NSEC3 with its RRSIG
responseCheck(response, Rcode::NOERROR(), 0, 0, 3, 0,
@@ -1133,8 +1153,9 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
// Similar to the previous case, but the delegation is an optout.
mock_finder->setNSEC3Flag(true);
- Query(memory_client, Name("foo.unsigned-delegation.example.com"),
- qtype, response, true).process();
+ query.process(memory_client,
+ Name("foo.unsigned-delegation.example.com"),
+ qtype, response, true);
// The response should contain the NS and the closest provable encloser
// proof (and their RRSIGs). The closest encloser is the apex (origin),
@@ -1157,19 +1178,22 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
TEST_F(QueryTest, badSecureDelegation) {
// Test whether exception is raised if DS query at delegation results in
// something different than SUCCESS or NXRRSET
- EXPECT_THROW(Query(memory_client, Name("bad-delegation.example.com"),
- qtype, response, true).process(), Query::BadDS);
+ EXPECT_THROW(query.process(memory_client,
+ Name("bad-delegation.example.com"),
+ qtype, response, true), Query::BadDS);
// But only if DNSSEC is requested (it shouldn't even try to look for
// the DS otherwise)
- EXPECT_NO_THROW(Query(memory_client, Name("bad-delegation.example.com"),
- qtype, response).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("bad-delegation.example.com"),
+ qtype, response));
}
TEST_F(QueryTest, nxdomain) {
- EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
- response).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("nxdomain.example.com"), qtype,
+ response));
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
NULL, soa_txt, NULL, mock_finder->getOrigin());
}
@@ -1178,8 +1202,9 @@ TEST_F(QueryTest, nxdomainWithNSEC) {
// NXDOMAIN with DNSSEC proof. We should have SOA, NSEC that proves
// NXDOMAIN and NSEC that proves nonexistence of matching wildcard,
// as well as their RRSIGs.
- EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
- response, true).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("nxdomain.example.com"), qtype,
+ response, true));
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
NULL, (string(soa_txt) +
string("example.com. 3600 IN RRSIG ") +
@@ -1198,8 +1223,8 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
// is derived from the next domain of the NSEC that proves NXDOMAIN, and
// the NSEC to provide the non existence of wildcard is different from
// the first NSEC.
- Query(memory_client, Name("(.no.example.com"), qtype,
- response, true).process();
+ query.process(memory_client, Name("(.no.example.com"), qtype, response,
+ true);
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
NULL, (string(soa_txt) +
string("example.com. 3600 IN RRSIG ") +
@@ -1216,8 +1241,8 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
TEST_F(QueryTest, nxdomainWithNSECDuplicate) {
// See comments about nz_txt. In this case we only need one NSEC,
// which proves both NXDOMAIN and the non existence of wildcard.
- Query(memory_client, Name("nx.no.example.com"), qtype,
- response, true).process();
+ query.process(memory_client, Name("nx.no.example.com"), qtype, response,
+ true);
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
NULL, (string(soa_txt) +
string("example.com. 3600 IN RRSIG ") +
@@ -1233,8 +1258,8 @@ TEST_F(QueryTest, nxdomainBadNSEC1) {
mock_finder->setNSECResult(Name("badnsec.example.com"),
ZoneFinder::NXDOMAIN,
mock_finder->dname_rrset_);
- EXPECT_THROW(Query(memory_client, Name("badnsec.example.com"), qtype,
- response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("badnsec.example.com"),
+ qtype, response, true),
std::bad_cast);
}
@@ -1243,8 +1268,8 @@ TEST_F(QueryTest, nxdomainBadNSEC2) {
mock_finder->setNSECResult(Name("emptynsec.example.com"),
ZoneFinder::NXDOMAIN,
mock_finder->empty_nsec_rrset_);
- EXPECT_THROW(Query(memory_client, Name("emptynsec.example.com"), qtype,
- response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("emptynsec.example.com"),
+ qtype, response, true),
Query::BadNSEC);
}
@@ -1253,8 +1278,8 @@ TEST_F(QueryTest, nxdomainBadNSEC3) {
mock_finder->setNSECResult(Name("*.example.com"),
ZoneFinder::SUCCESS,
mock_finder->dname_rrset_);
- EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
- response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+ qtype, response, true),
Query::BadNSEC);
}
@@ -1262,8 +1287,8 @@ TEST_F(QueryTest, nxdomainBadNSEC4) {
// "no-wildcard proof" doesn't return RRset.
mock_finder->setNSECResult(Name("*.example.com"),
ZoneFinder::NXDOMAIN, ConstRRsetPtr());
- EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
- response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+ qtype, response, true),
Query::BadNSEC);
}
@@ -1273,8 +1298,8 @@ TEST_F(QueryTest, nxdomainBadNSEC5) {
ZoneFinder::NXDOMAIN,
mock_finder->dname_rrset_);
// This is a bit odd, but we'll simply include the returned RRset.
- Query(memory_client, Name("nxdomain.example.com"), qtype,
- response, true).process();
+ query.process(memory_client, Name("nxdomain.example.com"), qtype,
+ response, true);
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
NULL, (string(soa_txt) +
string("example.com. 3600 IN RRSIG ") +
@@ -1293,14 +1318,14 @@ TEST_F(QueryTest, nxdomainBadNSEC6) {
mock_finder->setNSECResult(Name("*.example.com"),
ZoneFinder::NXDOMAIN,
mock_finder->empty_nsec_rrset_);
- EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
- response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+ qtype, response, true),
Query::BadNSEC);
}
TEST_F(QueryTest, nxrrset) {
- EXPECT_NO_THROW(Query(memory_client, Name("www.example.com"),
- RRType::TXT(), response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("www.example.com"),
+ RRType::TXT(), response));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
NULL, soa_txt, NULL, mock_finder->getOrigin());
@@ -1309,8 +1334,8 @@ TEST_F(QueryTest, nxrrset) {
TEST_F(QueryTest, nxrrsetWithNSEC) {
// NXRRSET with DNSSEC proof. We should have SOA, NSEC that proves the
// NXRRSET and their RRSIGs.
- Query(memory_client, Name("www.example.com"), RRType::TXT(), response,
- true).process();
+ query.process(memory_client, Name("www.example.com"), RRType::TXT(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -1330,8 +1355,8 @@ TEST_F(QueryTest, emptyNameWithNSEC) {
// exact match), so we only need one NSEC.
// From the point of the Query::process(), this is actually no different
// from the other NXRRSET case, but we check that explicitly just in case.
- Query(memory_client, Name("no.example.com"), RRType::A(), response,
- true).process();
+ query.process(memory_client, Name("no.example.com"), RRType::A(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -1346,8 +1371,8 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
// NXRRSET with DNSSEC proof requested, but there's no NSEC at that node.
// This is an unexpected event (if the zone is supposed to be properly
// signed with NSECs), but we accept and ignore the oddity.
- Query(memory_client, Name("nonsec.example.com"), RRType::TXT(), response,
- true).process();
+ query.process(memory_client, Name("nonsec.example.com"), RRType::TXT(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -1358,8 +1383,8 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
TEST_F(QueryTest, wildcardNSEC) {
// The qname matches *.wild.example.com. The response should contain
// an NSEC that proves the non existence of a closer name.
- Query(memory_client, Name("www.wild.example.com"), RRType::A(), response,
- true).process();
+ query.process(memory_client, Name("www.wild.example.com"), RRType::A(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
(string(wild_txt).replace(0, 1, "www") +
string("www.wild.example.com. 3600 IN RRSIG ") +
@@ -1378,8 +1403,8 @@ TEST_F(QueryTest, wildcardNSEC) {
TEST_F(QueryTest, CNAMEwildNSEC) {
// Similar to the previous case, but the matching wildcard record is
// CNAME.
- Query(memory_client, Name("www.cnamewild.example.com"), RRType::A(),
- response, true).process();
+ query.process(memory_client, Name("www.cnamewild.example.com"),
+ RRType::A(), response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
(string(cnamewild_txt).replace(0, 1, "www") +
string("www.cnamewild.example.com. 3600 IN RRSIG ") +
@@ -1401,8 +1426,8 @@ TEST_F(QueryTest, wildcardNSEC3) {
// of identifying the next closer name.
mock_finder->addRecord(nsec3_atwild_txt);
- Query(memory_client, Name("x.y.wild.example.com"), RRType::A(), response,
- true).process();
+ query.process(memory_client, Name("x.y.wild.example.com"), RRType::A(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
(string(wild_txt).replace(0, 1, "x.y") +
string("x.y.wild.example.com. 3600 IN RRSIG ") +
@@ -1426,8 +1451,8 @@ TEST_F(QueryTest, CNAMEwildNSEC3) {
mock_finder->setNSEC3Flag(true);
mock_finder->addRecord(nsec3_atcnamewild_txt);
- Query(memory_client, Name("www.cnamewild.example.com"), RRType::A(),
- response, true).process();
+ query.process(memory_client, Name("www.cnamewild.example.com"),
+ RRType::A(), response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
(string(cnamewild_txt).replace(0, 1, "www") +
string("www.cnamewild.example.com. 3600 IN RRSIG ") +
@@ -1449,8 +1474,8 @@ TEST_F(QueryTest, badWildcardNSEC3) {
ConstRRsetPtr());
mock_finder->setNSEC3Result(&nsec3);
- EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
- RRType::A(), response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+ RRType::A(), response, true),
Query::BadNSEC3);
}
@@ -1460,8 +1485,8 @@ TEST_F(QueryTest, badWildcardProof1) {
mock_finder->setNSECResult(Name("www.wild.example.com"),
ZoneFinder::SUCCESS,
mock_finder->dname_rrset_);
- EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
- RRType::A(), response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+ RRType::A(), response, true),
Query::BadNSEC);
}
@@ -1469,8 +1494,8 @@ TEST_F(QueryTest, badWildcardProof2) {
// "wildcard proof" doesn't return RRset.
mock_finder->setNSECResult(Name("www.wild.example.com"),
ZoneFinder::NXDOMAIN, ConstRRsetPtr());
- EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
- RRType::A(), response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+ RRType::A(), response, true),
Query::BadNSEC);
}
@@ -1479,8 +1504,8 @@ TEST_F(QueryTest, badWildcardProof3) {
mock_finder->setNSECResult(Name("www.wild.example.com"),
ZoneFinder::NXDOMAIN,
mock_finder->empty_nsec_rrset_);
- EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
- RRType::A(), response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+ RRType::A(), response, true),
Query::BadNSEC);
}
@@ -1488,8 +1513,8 @@ TEST_F(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
// NXRRSET on WILDCARD with DNSSEC proof. We should have SOA, NSEC that
// proves the NXRRSET and their RRSIGs. In this case we only need one NSEC,
// which proves both NXDOMAIN and the non existence RRSETs of wildcard.
- Query(memory_client, Name("www.wild.example.com"), RRType::TXT(), response,
- true).process();
+ query.process(memory_client, Name("www.wild.example.com"), RRType::TXT(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -1505,8 +1530,8 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC) {
// proves the NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
// one proves NXDOMAIN and the other proves non existence RRSETs of
// wildcard.
- Query(memory_client, Name("www1.uwild.example.com"), RRType::TXT(),
- response, true).process();
+ query.process(memory_client, Name("www1.uwild.example.com"),
+ RRType::TXT(), response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -1528,8 +1553,8 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3) {
mock_finder->addRecord(nsec3_uwild_txt);
mock_finder->setNSEC3Flag(true);
- Query(memory_client, Name("www1.uwild.example.com"), RRType::TXT(),
- response, true).process();
+ query.process(memory_client, Name("www1.uwild.example.com"),
+ RRType::TXT(), response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 8, 0, NULL,
// SOA + its RRSIG
@@ -1562,8 +1587,8 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Collision) {
ConstRRsetPtr());
mock_finder->setNSEC3Result(&nsec3);
- EXPECT_THROW(Query(memory_client, Name("www1.uwild.example.com"),
- RRType::TXT(), response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
+ RRType::TXT(), response, true),
Query::BadNSEC3);
}
@@ -1579,8 +1604,8 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Broken) {
mock_finder->addRecord(nsec3_wild_txt);
mock_finder->addRecord(nsec3_uwild_txt);
- EXPECT_THROW(Query(memory_client, Name("www1.uwild.example.com"),
- RRType::TXT(), response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
+ RRType::TXT(), response, true),
Query::BadNSEC3);
}
@@ -1588,8 +1613,8 @@ TEST_F(QueryTest, wildcardEmptyWithNSEC) {
// Empty WILDCARD with DNSSEC proof. We should have SOA, NSEC that proves
// the NXDOMAIN and their RRSIGs. In this case we need two NSEC RRs,
// one proves NXDOMAIN and the other proves non existence wildcard.
- Query(memory_client, Name("a.t.example.com"), RRType::A(), response,
- true).process();
+ query.process(memory_client, Name("a.t.example.com"), RRType::A(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -1612,19 +1637,19 @@ TEST_F(QueryTest, noSOA) {
mock_finder->setSOAFlag(false);
// The NX Domain
- EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"),
- qtype, response).process(), Query::NoSOA);
+ EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+ qtype, response), Query::NoSOA);
// Of course, we don't look into the response, as it throwed
// NXRRSET
- EXPECT_THROW(Query(memory_client, Name("nxrrset.example.com"),
- qtype, response).process(), Query::NoSOA);
+ EXPECT_THROW(query.process(memory_client, Name("nxrrset.example.com"),
+ qtype, response), Query::NoSOA);
}
TEST_F(QueryTest, noMatchZone) {
// there's a zone in the memory datasource but it doesn't match the qname.
// should result in REFUSED.
- Query(memory_client, Name("example.org"), qtype, response).process();
+ query.process(memory_client, Name("example.org"), qtype, response);
EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
}
@@ -1635,8 +1660,8 @@ TEST_F(QueryTest, noMatchZone) {
* A record, other to unknown out of zone one.
*/
TEST_F(QueryTest, MX) {
- Query(memory_client, Name("mx.example.com"), RRType::MX(),
- response).process();
+ query.process(memory_client, Name("mx.example.com"), RRType::MX(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
mx_txt, NULL,
@@ -1649,8 +1674,8 @@ TEST_F(QueryTest, MX) {
* This should not trigger the additional processing for the exchange.
*/
TEST_F(QueryTest, MXAlias) {
- Query(memory_client, Name("cnamemx.example.com"), RRType::MX(),
- response).process();
+ query.process(memory_client, Name("cnamemx.example.com"), RRType::MX(),
+ response);
// there shouldn't be no additional RRs for the exchanges (we have 3
// RRs for the NS). The normal MX case is tested separately so we don't
@@ -1669,8 +1694,8 @@ TEST_F(QueryTest, MXAlias) {
* returned.
*/
TEST_F(QueryTest, CNAME) {
- Query(memory_client, Name("cname.example.com"), RRType::A(),
- response).process();
+ query.process(memory_client, Name("cname.example.com"), RRType::A(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
cname_txt, NULL, NULL);
@@ -1679,8 +1704,8 @@ TEST_F(QueryTest, CNAME) {
TEST_F(QueryTest, explicitCNAME) {
// same owner name as the CNAME test but explicitly query for CNAME RR.
// expect the same response as we don't provide a full chain yet.
- Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
- response).process();
+ query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
cname_txt, zone_ns_txt, ns_addrs_txt);
@@ -1691,8 +1716,8 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
// note: with chaining, what should be expected is not trivial:
// BIND 9 returns the CNAME in answer and SOA in authority, no additional.
// NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
- Query(memory_client, Name("cname.example.com"), RRType::TXT(),
- response).process();
+ query.process(memory_client, Name("cname.example.com"), RRType::TXT(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
cname_txt, NULL, NULL);
@@ -1700,8 +1725,8 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
// same owner name as the NXRRSET test but explicitly query for CNAME RR.
- Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
- response).process();
+ query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
cname_txt, zone_ns_txt, ns_addrs_txt);
@@ -1714,8 +1739,8 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
// RCODE being NXDOMAIN.
// NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
// RCODE being NOERROR.
- Query(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
- response).process();
+ query.process(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
cname_nxdom_txt, NULL, NULL);
@@ -1723,8 +1748,8 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
// same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
- Query(memory_client, Name("cnamenxdom.example.com"), RRType::CNAME(),
- response).process();
+ query.process(memory_client, Name("cnamenxdom.example.com"),
+ RRType::CNAME(), response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
cname_nxdom_txt, zone_ns_txt, ns_addrs_txt);
@@ -1739,8 +1764,8 @@ TEST_F(QueryTest, CNAME_OUT) {
* Then the same test should be done with .org included there and
* see what it does (depends on what we want to do)
*/
- Query(memory_client, Name("cnameout.example.com"), RRType::A(),
- response).process();
+ query.process(memory_client, Name("cnameout.example.com"), RRType::A(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
cname_out_txt, NULL, NULL);
@@ -1748,8 +1773,8 @@ TEST_F(QueryTest, CNAME_OUT) {
TEST_F(QueryTest, explicitCNAME_OUT) {
// same owner name as the OUT test but explicitly query for CNAME RR.
- Query(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
- response).process();
+ query.process(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
cname_out_txt, zone_ns_txt, ns_addrs_txt);
@@ -1764,8 +1789,8 @@ TEST_F(QueryTest, explicitCNAME_OUT) {
* pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
*/
TEST_F(QueryTest, DNAME) {
- Query(memory_client, Name("www.dname.example.com"), RRType::A(),
- response).process();
+ query.process(memory_client, Name("www.dname.example.com"), RRType::A(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
(string(dname_txt) + synthetized_cname_txt).c_str(),
@@ -1780,8 +1805,8 @@ TEST_F(QueryTest, DNAME) {
* DNAME.
*/
TEST_F(QueryTest, DNAME_ANY) {
- Query(memory_client, Name("www.dname.example.com"), RRType::ANY(),
- response).process();
+ query.process(memory_client, Name("www.dname.example.com"), RRType::ANY(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
(string(dname_txt) + synthetized_cname_txt).c_str(), NULL, NULL);
@@ -1789,8 +1814,8 @@ TEST_F(QueryTest, DNAME_ANY) {
// Test when we ask for DNAME explicitly, it does no synthetizing.
TEST_F(QueryTest, explicitDNAME) {
- Query(memory_client, Name("dname.example.com"), RRType::DNAME(),
- response).process();
+ query.process(memory_client, Name("dname.example.com"), RRType::DNAME(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
dname_txt, zone_ns_txt, ns_addrs_txt);
@@ -1801,8 +1826,8 @@ TEST_F(QueryTest, explicitDNAME) {
* the CNAME, it should return the RRset.
*/
TEST_F(QueryTest, DNAME_A) {
- Query(memory_client, Name("dname.example.com"), RRType::A(),
- response).process();
+ query.process(memory_client, Name("dname.example.com"), RRType::A(),
+ response);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
dname_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -1813,8 +1838,8 @@ TEST_F(QueryTest, DNAME_A) {
* It should not synthetize the CNAME.
*/
TEST_F(QueryTest, DNAME_NX_RRSET) {
- EXPECT_NO_THROW(Query(memory_client, Name("dname.example.com"),
- RRType::TXT(), response).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("dname.example.com"),
+ RRType::TXT(), response));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
NULL, soa_txt, NULL, mock_finder->getOrigin());
@@ -1833,8 +1858,8 @@ TEST_F(QueryTest, LongDNAME) {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"dname.example.com.");
- EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
- response).process());
+ EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
+ response));
responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
dname_txt, NULL, NULL);
@@ -1852,8 +1877,8 @@ TEST_F(QueryTest, MaxLenDNAME) {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"dname.example.com.");
- EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
- response).process());
+ EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
+ response));
// Check the answer is OK
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
@@ -2038,8 +2063,9 @@ TEST_F(QueryTest, dsAboveDelegation) {
// The following will succeed only if the search goes to the parent
// zone, not the child one we added above.
- EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
- RRType::DS(), response, true).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("delegation.example.com"),
+ RRType::DS(), response, true));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
(string(delegation_ds_txt) + "\n" +
@@ -2061,9 +2087,9 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
// The following will succeed only if the search goes to the parent
// zone, not the child one we added above.
- EXPECT_NO_THROW(Query(memory_client,
- Name("unsigned-delegation.example.com"),
- RRType::DS(), response, true).process());
+ EXPECT_NO_THROW(query.process(memory_client,
+ Name("unsigned-delegation.example.com"),
+ RRType::DS(), response, true));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(soa_txt) +
@@ -2079,8 +2105,8 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
// when it happens to be sent to the child zone, as described in RFC 4035,
// section 3.1.4.1. The example is inspired by the B.8. example from the RFC.
TEST_F(QueryTest, dsBelowDelegation) {
- EXPECT_NO_THROW(Query(memory_client, Name("example.com"),
- RRType::DS(), response, true).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+ RRType::DS(), response, true));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2096,8 +2122,8 @@ TEST_F(QueryTest, dsBelowDelegation) {
// In our implementation NSEC/NSEC3 isn't attached in this case.
TEST_F(QueryTest, dsBelowDelegationWithDS) {
mock_finder->addRecord(zone_ds_txt); // add the DS to the child's apex
- EXPECT_NO_THROW(Query(memory_client, Name("example.com"),
- RRType::DS(), response, true).process());
+ EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+ RRType::DS(), response, true));
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2109,16 +2135,16 @@ TEST_F(QueryTest, dsBelowDelegationWithDS) {
// server. It should just like the "noZone" test case, but DS query involves
// special processing, so we test it explicitly.
TEST_F(QueryTest, dsNoZone) {
- Query(memory_client, Name("example"), RRType::DS(), response,
- true).process();
+ query.process(memory_client, Name("example"), RRType::DS(), response,
+ true);
responseCheck(response, Rcode::REFUSED(), 0, 0, 0, 0, NULL, NULL, NULL);
}
// DS query for a "grandchild" zone. This should result in normal
// delegation (unless this server also has authority of the grandchild zone).
TEST_F(QueryTest, dsAtGrandParent) {
- Query(memory_client, Name("grand.delegation.example.com"), RRType::DS(),
- response, true).process();
+ query.process(memory_client, Name("grand.delegation.example.com"),
+ RRType::DS(), response, true);
responseCheck(response, Rcode::NOERROR(), 0, 0, 6, 6, NULL,
(string(delegation_txt) + string(delegation_ds_txt) +
"delegation.example.com. 3600 IN RRSIG " +
@@ -2136,7 +2162,7 @@ TEST_F(QueryTest, dsAtGrandParentAndChild) {
const Name childname("grand.delegation.example.com");
memory_client.addZone(ZoneFinderPtr(
new AlternateZoneFinder(childname)));
- Query(memory_client, childname, RRType::DS(), response, true).process();
+ query.process(memory_client, childname, RRType::DS(), response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(childname.toText() + " 3600 IN SOA . . 0 0 0 0 0\n" +
childname.toText() + " 3600 IN RRSIG " +
@@ -2154,8 +2180,8 @@ TEST_F(QueryTest, dsAtRoot) {
// Pretend to be a root server.
memory_client.addZone(ZoneFinderPtr(
new AlternateZoneFinder(Name::ROOT_NAME())));
- Query(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
- true).process();
+ query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
+ true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(". 3600 IN SOA . . 0 0 0 0 0\n") +
". 3600 IN RRSIG " + getCommonRRSIGText("SOA") + "\n" +
@@ -2171,8 +2197,8 @@ TEST_F(QueryTest, dsAtRootWithDS) {
memory_client.addZone(ZoneFinderPtr(
new AlternateZoneFinder(Name::ROOT_NAME(),
true)));
- Query(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
- true).process();
+ query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
+ true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
(string(". 3600 IN DS 57855 5 1 49FD46E6C4B45C55D4AC69CBD"
"3CD34AC1AFE51DE\n") +
@@ -2188,8 +2214,8 @@ TEST_F(QueryTest, nxrrsetWithNSEC3) {
// NXRRSET with DNSSEC proof. We should have SOA, NSEC3 that proves the
// NXRRSET and their RRSIGs.
- Query(memory_client, Name("www.example.com"), RRType::TXT(), response,
- true).process();
+ query.process(memory_client, Name("www.example.com"), RRType::TXT(),
+ response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2211,8 +2237,9 @@ TEST_F(QueryTest, nxrrsetMissingNSEC3) {
ConstRRsetPtr());
mock_finder->setNSEC3Result(&nsec3);
- EXPECT_THROW(Query(memory_client, Name("www.example.com"), RRType::TXT(),
- response, true).process(), Query::BadNSEC3);
+ EXPECT_THROW(query.process(memory_client, Name("www.example.com"),
+ RRType::TXT(), response, true),
+ Query::BadNSEC3);
}
TEST_F(QueryTest, nxrrsetWithNSEC3_ds_exact) {
@@ -2221,8 +2248,8 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_exact) {
// This delegation has no DS, but does have a matching NSEC3 record
// (See RFC5155 section 7.2.4)
- Query(memory_client, Name("unsigned-delegation.example.com."),
- RRType::DS(), response, true).process();
+ query.process(memory_client, Name("unsigned-delegation.example.com."),
+ RRType::DS(), response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
getCommonRRSIGText("SOA") + "\n" +
@@ -2243,8 +2270,8 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_no_exact) {
// 'next closer' should have opt-out set, though that is not
// actually checked)
// (See RFC5155 section 7.2.4)
- Query(memory_client, Name("unsigned-delegation-optout.example.com."),
- RRType::DS(), response, true).process();
+ query.process(memory_client, Name("unsigned-delegation-optout.example.com."),
+ RRType::DS(), response, true);
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
(string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
getCommonRRSIGText("SOA") + "\n" +
@@ -2270,8 +2297,8 @@ TEST_F(QueryTest, nxdomainWithNSEC3Proof) {
// This will be the covering NSEC3 for the possible wildcard
mock_finder->addRecord(unsigned_delegation_nsec3_txt);
- Query(memory_client, Name("nxdomain.example.com"), qtype,
- response, true).process();
+ query.process(memory_client, Name("nxdomain.example.com"), qtype,
+ response, true);
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0, NULL,
// SOA + its RRSIG
(string(soa_txt) +
@@ -2305,8 +2332,8 @@ TEST_F(QueryTest, nxdomainWithBadNextNSEC3Proof) {
ConstRRsetPtr());
mock_finder->setNSEC3Result(&nsec3);
- EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"),
- RRType::TXT(), response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+ RRType::TXT(), response, true),
Query::BadNSEC3);
}
@@ -2324,8 +2351,8 @@ TEST_F(QueryTest, nxdomainWithBadWildcardNSEC3Proof) {
ConstRRsetPtr());
mock_finder->setNSEC3Result(&nsec3, &wname);
- EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
- response, true).process(),
+ EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"), qtype,
+ response, true),
Query::BadNSEC3);
}
@@ -2341,4 +2368,172 @@ TEST_F(QueryTest, emptyNameWithNSEC3) {
EXPECT_TRUE(result->isNSEC3Signed());
EXPECT_FALSE(result->isWildcard());
}
+
+// Class to allow checking of duplication removal in messages resulting from.
+// the query. This class allows the setting of the answers, authorities and
+// additionals vector in the Query class, as well as the ability to call the
+// createResponse() method.
+
+class DuplicateQuery : public isc::auth::Query {
+public:
+ // \brief Constructor
+ //
+ // Fill in the parts of Query that we test in the DuplicateRemoval test.
+ DuplicateQuery(isc::dns::Message* message,
+ const vector<RRsetPtr>& answers,
+ const vector<RRsetPtr>& authorities,
+ const vector<RRsetPtr>& additionals) : Query() {
+ response_ = message;
+ copy(answers.begin(), answers.end(),
+ back_inserter(answers_));
+ copy(authorities.begin(), authorities.end(),
+ back_inserter(authorities_));
+ copy(additionals.begin(), additionals.end(),
+ back_inserter(additionals_));
+ }
+
+ // \brief Create Response
+ //
+ // Public interface to the (protected) Query::createResponse() method.
+ void produceResponse() {
+ createResponse();
+ }
+};
+
+// Vector of RRsets used for the test. Having this external to functions and
+// classes used for the testing simplifies the code.
+std::vector<RRsetPtr> rrset_vector;
+
+// Callback function for masterLoad.
+void
+loadRRsetVectorCallback(RRsetPtr rrsetptr) {
+ rrset_vector.push_back(rrsetptr);
+}
+
+// Load a set of RRsets into a vector for use in the duplicate RRset test.
+// They don't make a lot of sense as a zone, they are just different. The
+// variables used in the stringstream input have been chosen so that each
+// represents just one RRset.
+void
+loadRRsetVector() {
+ stringstream ss;
+
+ // Comments indicate offset in the rrset_vector (when loaded) and the
+ // number of RRs in that RRset.
+ ss << soa_txt // 0(1)
+ << zone_ns_txt // 1(3)
+ << delegation_txt // 2(4)
+ << delegation_ds_txt // 3(1)
+ << mx_txt // 4(3)
+ << www_a_txt // 5(1)
+ << cname_txt // 6(1)
+ << cname_nxdom_txt // 7(1)
+ << cname_out_txt; // 8(1)
+ rrset_vector.clear();
+ masterLoad(ss, Name("example.com."), RRClass::IN(), loadRRsetVectorCallback);
+}
+
+TEST_F(QueryTest, DuplicateNameRemoval) {
+
+ // Load some RRsets into the master vector.
+ loadRRsetVector();
+ EXPECT_EQ(9, rrset_vector.size());
+
+ // Create an answer, authority and authority vector with some overlapping
+ // entries. The following indicate which elements from rrset_vector
+ // go into each section vector. (The values have been separated to show
+ // the overlap.)
+ //
+ // answer = 0 1 2 3
+ // authority = 2 3 4 5 6 7
+ // additional = 0 3 7 8
+ //
+ // If the duplicate removal works, we should end up with the following in
+ // the message created from the three vectors:
+ //
+ // answer = 0 1 2 3
+ // authority = 4 5 6 7
+ // additional = 8
+ //
+ // The expected section into which each RRset is placed is indicated in the
+ // array below.
+ const Message::Section expected_section[] = {
+ Message::SECTION_ANSWER,
+ Message::SECTION_ANSWER,
+ Message::SECTION_ANSWER,
+ Message::SECTION_ANSWER,
+ Message::SECTION_AUTHORITY,
+ Message::SECTION_AUTHORITY,
+ Message::SECTION_AUTHORITY,
+ Message::SECTION_AUTHORITY,
+ Message::SECTION_ADDITIONAL
+ };
+ EXPECT_EQ(rrset_vector.size(),
+ (sizeof(expected_section) / sizeof(Message::Section)));
+
+ // Create the vectors of RRsets (with the RRsets in a semi-random order).
+ std::vector<RRsetPtr> answer;
+ copy(rrset_vector.begin() + 2, rrset_vector.begin() + 4,
+ back_inserter(answer));
+ copy(rrset_vector.begin() + 0, rrset_vector.begin() + 2,
+ back_inserter(answer));
+
+ std::vector<RRsetPtr> authority;
+ copy(rrset_vector.begin() + 3, rrset_vector.begin() + 8,
+ back_inserter(authority));
+ authority.push_back(rrset_vector[2]);
+
+ std::vector<RRsetPtr> additional;
+ copy(rrset_vector.begin() + 7, rrset_vector.begin() + 9,
+ back_inserter(additional));
+ additional.push_back(rrset_vector[3]);
+ additional.push_back(rrset_vector[0]);
+
+ // Create the message object into which the RRsets are put
+ Message message(Message::RENDER);
+ EXPECT_EQ(0, message.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(0, message.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(0, message.getRRCount(Message::SECTION_ADDITIONAL));
+
+ // ... and fill it.
+ DuplicateQuery query(&message, answer, authority, additional);
+ query.produceResponse();
+
+ // Check counts in each section. Note that these are RR counts,
+ // not RRset counts.
+ EXPECT_EQ(9, message.getRRCount(Message::SECTION_ANSWER));
+ EXPECT_EQ(6, message.getRRCount(Message::SECTION_AUTHORITY));
+ EXPECT_EQ(1, message.getRRCount(Message::SECTION_ADDITIONAL));
+
+ // ... and check that the RRsets are in the correct section
+ BOOST_STATIC_ASSERT(Message::SECTION_QUESTION == 0);
+ BOOST_STATIC_ASSERT(Message::SECTION_ANSWER == 1);
+ BOOST_STATIC_ASSERT(Message::SECTION_AUTHORITY == 2);
+ BOOST_STATIC_ASSERT(Message::SECTION_ADDITIONAL == 3);
+ Message::Section sections[] = {
+ Message::SECTION_QUESTION,
+ Message::SECTION_ANSWER,
+ Message::SECTION_AUTHORITY,
+ Message::SECTION_ADDITIONAL
+ };
+ for (int section = 1; section <= 3; ++section) {
+ for (int vecindex = 0; vecindex < rrset_vector.size(); ++vecindex) {
+ // Prepare error message in case an assertion fails (as the default
+ // message will only refer to the loop indexes).
+ stringstream ss;
+ ss << "section " << section << ", name "
+ << rrset_vector[vecindex]->getName().toText();
+ SCOPED_TRACE(ss.str());
+
+ // Check RRset is in the right section and not in the wrong section.
+ if (sections[section] == expected_section[vecindex]) {
+ EXPECT_TRUE(message.hasRRset(sections[section],
+ rrset_vector[vecindex]));
+ } else {
+ EXPECT_FALSE(message.hasRRset(sections[section],
+ rrset_vector[vecindex]));
+ }
+ }
+ }
+}
}
diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc
index e7f242e..711379e 100644
--- a/src/bin/resolver/resolver.cc
+++ b/src/bin/resolver/resolver.cc
@@ -15,6 +15,7 @@
#include <config.h>
#include <stdint.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <algorithm>
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index 8ce1ae0..a5c92ab 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -76,6 +76,27 @@ example_soa_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA())
default_questions = [example_axfr_question]
default_answers = [soa_rrset]
+def get_fake_time_time():
+ '''Returns a temporary replacement function for time.time(), which
+ always returns 0.1 more than the previous call. This is to make
+ sure these tests do not fail on systems where the time.time()
+ function has a high minimal accuracy.
+ This fake time.time() is usually set in place of the real one
+ where we need testing of get_running_time(). It is done is
+ as low a scope as possible, so as not to mess up unit test
+ framework time related tests. It must be set before
+ XfrinTransferState (or any class that initializes that) is
+ initialized.
+ And every time it is set up, in must be reset later (again, so
+ as not to mess up the framework's concept of time).
+ '''
+ fake_time = 0.0
+ def fake_time_time():
+ nonlocal fake_time
+ fake_time += 0.1
+ return fake_time
+ return fake_time_time
+
def check_diffs(assert_fn, expected, actual):
'''A helper function checking the differences made in the XFR session.
@@ -561,7 +582,7 @@ class TestXfrinIXFREnd(TestXfrinState):
def test_finish_message(self):
self.assertFalse(self.state.finish_message(self.conn))
-class TestXfrinIXFREnd(TestXfrinState):
+class TestXfrinIXFREndUpToDate(TestXfrinState):
def setUp(self):
super().setUp()
self.state = XfrinIXFRUptodate()
@@ -759,9 +780,15 @@ class TestXfrinConnection(unittest.TestCase):
class TestAXFR(TestXfrinConnection):
def setUp(self):
+ # replace time.time with a steadily increasing fake one
+ self.orig_time_time = time.time
+ time.time = get_fake_time_time()
super().setUp()
XfrinInitialSOA().set_xfrstate(self.conn, XfrinInitialSOA())
+ def tearDown(self):
+ time.time = self.orig_time_time
+
def __create_mock_tsig(self, key, error):
# This helper function creates a MockTSIGContext for a given key
# and TSIG error to be used as a result of verify (normally faked
@@ -1469,6 +1496,10 @@ class TestAXFR(TestXfrinConnection):
class TestIXFRResponse(TestXfrinConnection):
def setUp(self):
+ # replace time.time with a steadily increasing fake one
+ self.orig_time_time = time.time
+ time.time = get_fake_time_time()
+
super().setUp()
self.conn._query_id = self.conn.qid = 1035
self.conn._request_serial = isc.dns.Serial(1230)
@@ -1476,6 +1507,9 @@ class TestIXFRResponse(TestXfrinConnection):
self.conn._datasrc_client = MockDataSourceClient()
XfrinInitialSOA().set_xfrstate(self.conn, XfrinInitialSOA())
+ def tearDown(self):
+ time.time = self.orig_time_time
+
def test_ixfr_response(self):
'''A simplest form of IXFR response.
@@ -1670,8 +1704,14 @@ class TestIXFRSession(TestXfrinConnection):
the general logic flow.
'''
def setUp(self):
+ # replace time.time with a steadily increasing fake one
+ self.orig_time_time = time.time
+ time.time = get_fake_time_time()
super().setUp()
+ def tearDown(self):
+ time.time = self.orig_time_time
+
def test_do_xfrin(self):
def create_ixfr_response():
self.conn.reply_data = self.conn.create_response_data(
@@ -1758,6 +1798,9 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
self.empty_sqlite3db_obj = TESTDATA_OBJDIR + '/empty.sqlite3'
self.sqlite3db_cfg = "{ \"database_file\": \"" +\
self.sqlite3db_obj + "\"}"
+ # replace time.time with a steadily increasing fake one
+ self.orig_time_time = time.time
+ time.time = get_fake_time_time()
super().setUp()
if os.path.exists(self.sqlite3db_obj):
os.unlink(self.sqlite3db_obj)
@@ -1772,6 +1815,7 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
os.unlink(self.sqlite3db_obj)
if os.path.exists(self.empty_sqlite3db_obj):
os.unlink(self.empty_sqlite3db_obj)
+ time.time = self.orig_time_time
def get_zone_serial(self):
result, finder = self.conn._datasrc_client.find_zone(TEST_ZONE_NAME)
@@ -2741,8 +2785,14 @@ class TestFormatting(unittest.TestCase):
class TestXfrinTransferStats(unittest.TestCase):
def setUp(self):
+ # replace time.time with a steadily increasing fake one
+ self.orig_time_time = time.time
+ time.time = get_fake_time_time()
self.stats = XfrinTransferStats()
+ def tearDown(self):
+ time.time = self.orig_time_time
+
def zero_check(self):
# Checks whether all counters are zero
self.assertEqual(0, self.stats.message_count)
@@ -2795,7 +2845,6 @@ class TestXfrinTransferStats(unittest.TestCase):
zbps = self.stats.get_bytes_per_second()
self.assertEqual(0, zbps)
-
if __name__== "__main__":
try:
isc.log.resetUnitTestRootLogger()
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index 165560b..8f236ec 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -926,7 +926,7 @@ class XfroutServer:
self._notifier.dispatcher()
def send_notify(self, zone_name, zone_class):
- self._notifier.send_notify(zone_name, zone_class)
+ return self._notifier.send_notify(zone_name, zone_class)
def config_handler(self, new_config):
'''Update config data. TODO. Do error check'''
@@ -982,10 +982,16 @@ class XfroutServer:
elif cmd == notify_out.ZONE_NEW_DATA_READY_CMD:
zone_name = args.get('zone_name')
zone_class = args.get('zone_class')
- if zone_name and zone_class:
+ if not zone_class:
+ zone_class = str(RRClass.IN())
+ if zone_name:
logger.info(XFROUT_NOTIFY_COMMAND, zone_name, zone_class)
- self.send_notify(zone_name, zone_class)
- answer = create_answer(0)
+ if self.send_notify(zone_name, zone_class):
+ answer = create_answer(0)
+ else:
+ zonestr = notify_out.format_zone_str(Name(zone_name),
+ zone_class)
+ answer = create_answer(1, "Unknown zone: " + zonestr)
else:
answer = create_answer(1, "Bad command parameter:" + str(args))
diff --git a/src/bin/xfrout/xfrout.spec.pre.in b/src/bin/xfrout/xfrout.spec.pre.in
index ce8686e..30c9d56 100644
--- a/src/bin/xfrout/xfrout.spec.pre.in
+++ b/src/bin/xfrout/xfrout.spec.pre.in
@@ -71,6 +71,19 @@
"item_optional": true
}
]
+ },
+ { "command_name": "notify",
+ "command_description": "Send notifies for zone",
+ "command_args": [
+ { "item_name": "zone_name",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "" },
+ { "item_name": "zone_class",
+ "item_type": "string",
+ "item_optional": true,
+ "item_default": "IN"
+ } ]
}
]
}
diff --git a/src/lib/acl/ip_check.cc b/src/lib/acl/ip_check.cc
index 76aacca..7192064 100644
--- a/src/lib/acl/ip_check.cc
+++ b/src/lib/acl/ip_check.cc
@@ -12,6 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <sys/types.h>
#include <sys/socket.h>
#include <exceptions/exceptions.h>
diff --git a/src/lib/asiodns/dns_service.cc b/src/lib/asiodns/dns_service.cc
index 967ce15..d79363d 100644
--- a/src/lib/asiodns/dns_service.cc
+++ b/src/lib/asiodns/dns_service.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> // for some IPC/network system calls
@@ -25,9 +26,9 @@
#include <asio.hpp>
#include <dns_service.h>
#include <asiolink/io_service.h>
-#include <asiolink/io_service.h>
#include <tcp_server.h>
#include <udp_server.h>
+#include <sync_udp_server.h>
#include <log/dummylog.h>
@@ -66,11 +67,13 @@ public:
const asio::ip::address* v4addr,
const asio::ip::address* v6addr,
SimpleCallback* checkin, DNSLookup* lookup,
- DNSAnswer* answer);
+ DNSAnswer* answer,
+ const UDPVersion param_flags);
IOService& io_service_;
typedef boost::shared_ptr<UDPServer> UDPServerPtr;
+ typedef boost::shared_ptr<SyncUDPServer> SyncUDPServerPtr;
typedef boost::shared_ptr<TCPServer> TCPServerPtr;
typedef boost::shared_ptr<DNSServer> DNSServerPtr;
std::vector<DNSServerPtr> servers_;
@@ -85,7 +88,8 @@ public:
servers_.push_back(server);
}
- void addServer(uint16_t port, const asio::ip::address& address) {
+ void addServer(uint16_t port, const asio::ip::address& address,
+ const UDPVersion param_flags) {
try {
dlog(std::string("Initialize TCP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
TCPServerPtr tcpServer(new TCPServer(io_service_.get_io_service(),
@@ -93,10 +97,27 @@ public:
(*tcpServer)();
servers_.push_back(tcpServer);
dlog(std::string("Initialize UDP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
- UDPServerPtr udpServer(new UDPServer(io_service_.get_io_service(),
- address, port, checkin_, lookup_, answer_));
- (*udpServer)();
- servers_.push_back(udpServer);
+ // Use param_flags to generate diff UDPServers.
+ switch(param_flags) {
+ case SYNC_: {
+ SyncUDPServerPtr syncUdpServer(new SyncUDPServer(io_service_.get_io_service(),
+ address, port, checkin_, lookup_, answer_));
+ (*syncUdpServer)();
+ servers_.push_back(syncUdpServer);
+ break;
+ }
+ case ASYNC_: {
+ UDPServerPtr udpServer(new UDPServer(io_service_.get_io_service(),
+ address, port, checkin_, lookup_, answer_));
+ (*udpServer)();
+ servers_.push_back(udpServer);
+ break;
+ }
+ default:
+ // If nerther asyn UDPServer nor sync UDNServer, it throws.
+ isc_throw(IOError, "Bad UDPServer Version!");
+ break;
+ }
}
catch (const asio::system_error& err) {
// We need to catch and convert any ASIO level exceptions.
@@ -106,7 +127,8 @@ public:
err.what());
}
}
- void addServer(const char& port, const asio::ip::address& address) {
+ void addServer(const char& port, const asio::ip::address& address,
+ const UDPVersion param_flags) {
uint16_t portnum;
try {
// XXX: SunStudio with stlport4 doesn't reject some invalid
@@ -122,7 +144,7 @@ public:
isc_throw(IOError, "Invalid port number '" << &port << "': " <<
ex.what());
}
- addServer(portnum, address);
+ addServer(portnum, address,param_flags);
}
};
@@ -132,7 +154,8 @@ DNSServiceImpl::DNSServiceImpl(IOService& io_service,
const asio::ip::address* const v6addr,
SimpleCallback* checkin,
DNSLookup* lookup,
- DNSAnswer* answer) :
+ DNSAnswer* answer,
+ const UDPVersion param_flags):
io_service_(io_service),
checkin_(checkin),
lookup_(lookup),
@@ -140,10 +163,10 @@ DNSServiceImpl::DNSServiceImpl(IOService& io_service,
{
if (v4addr) {
- addServer(port, *v4addr);
+ addServer(port, *v4addr,param_flags);
}
if (v6addr) {
- addServer(port, *v6addr);
+ addServer(port, *v6addr,param_flags);
}
}
@@ -151,11 +174,12 @@ DNSService::DNSService(IOService& io_service,
const char& port, const char& address,
SimpleCallback* checkin,
DNSLookup* lookup,
- DNSAnswer* answer) :
+ DNSAnswer* answer,
+ const UDPVersion param_flags) :
impl_(new DNSServiceImpl(io_service, port, NULL, NULL, checkin, lookup,
- answer)), io_service_(io_service)
+ answer,param_flags)), io_service_(io_service)
{
- addServer(port, &address);
+ addServer(port, &address,param_flags);
}
DNSService::DNSService(IOService& io_service,
@@ -163,7 +187,8 @@ DNSService::DNSService(IOService& io_service,
const bool use_ipv4, const bool use_ipv6,
SimpleCallback* checkin,
DNSLookup* lookup,
- DNSAnswer* answer) :
+ DNSAnswer* answer,
+ const UDPVersion param_flags) :
impl_(NULL), io_service_(io_service)
{
const asio::ip::address v4addr_any =
@@ -172,13 +197,13 @@ DNSService::DNSService(IOService& io_service,
const asio::ip::address v6addr_any =
asio::ip::address(asio::ip::address_v6::any());
const asio::ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
- impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
+ impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer,param_flags);
}
DNSService::DNSService(IOService& io_service, SimpleCallback* checkin,
- DNSLookup* lookup, DNSAnswer *answer) :
+ DNSLookup* lookup, DNSAnswer *answer,const UDPVersion param_flags) :
impl_(new DNSServiceImpl(io_service, *"0", NULL, NULL, checkin, lookup,
- answer)), io_service_(io_service)
+ answer,param_flags)), io_service_(io_service)
{
}
@@ -187,21 +212,25 @@ DNSService::~DNSService() {
}
void
-DNSService::addServer(const char& port, const std::string& address) {
- impl_->addServer(port, convertAddr(address));
+DNSService::addServer(const char& port, const std::string& address,UDPVersion param_flags) {
+ impl_->addServer(port, convertAddr(address),param_flags);
}
void
-DNSService::addServer(uint16_t port, const std::string& address) {
- impl_->addServer(port, convertAddr(address));
+DNSService::addServer(uint16_t port, const std::string& address,UDPVersion param_flags) {
+ impl_->addServer(port, convertAddr(address),param_flags);
}
void DNSService::addServerTCPFromFD(int fd, int af) {
impl_->addServerFromFD<DNSServiceImpl::TCPServerPtr, TCPServer>(fd, af);
}
-void DNSService::addServerUDPFromFD(int fd, int af) {
- impl_->addServerFromFD<DNSServiceImpl::UDPServerPtr, UDPServer>(fd, af);
+void DNSService::addServerUDPFromFD(int fd, int af,const UDPVersion param_flags) {
+ if(SYNC_ == param_flags) {
+ impl_->addServerFromFD<DNSServiceImpl::SyncUDPServerPtr, SyncUDPServer>(fd, af);
+ } else if(ASYNC_ == param_flags) {
+ impl_->addServerFromFD<DNSServiceImpl::UDPServerPtr, UDPServer>(fd, af);
+ }
}
void
diff --git a/src/lib/asiodns/dns_service.h b/src/lib/asiodns/dns_service.h
index 66f8d33..66e0a11 100644
--- a/src/lib/asiodns/dns_service.h
+++ b/src/lib/asiodns/dns_service.h
@@ -27,6 +27,15 @@ class DNSLookup;
class DNSAnswer;
class DNSServiceImpl;
+
+/// Codes for UDPServers used in addServer()method.
+///
+/// Note: the codes only used in how to create the UDPServers.
+enum UDPVersion {
+ SYNC_ = 1, ///< used synchronous UDPServer
+ ASYNC_ = 2 ///< used asynchronous UDPServer
+};
+
/// \brief Handle DNS Queries
///
/// DNSService is the service that handles DNS queries and answers with
@@ -57,7 +66,8 @@ public:
/// \param answer The answer provider (see \c DNSAnswer)
DNSService(asiolink::IOService& io_service, const char& port,
const char& address, isc::asiolink::SimpleCallback* checkin,
- DNSLookup* lookup, DNSAnswer* answer);
+ DNSLookup* lookup, DNSAnswer* answer,
+ const UDPVersion param_flags = SYNC_);
/// \brief The constructor with a specific port on which the services
/// listen on.
///
@@ -75,19 +85,23 @@ public:
DNSService(asiolink::IOService& io_service, const char& port,
const bool use_ipv4, const bool use_ipv6,
isc::asiolink::SimpleCallback* checkin, DNSLookup* lookup,
- DNSAnswer* answer);
+ DNSAnswer* answer,
+ const UDPVersion param_flags = SYNC_);
/// \brief The constructor without any servers.
///
/// Use addServer() to add some servers.
DNSService(asiolink::IOService& io_service, isc::asiolink::SimpleCallback* checkin,
- DNSLookup* lookup, DNSAnswer* answer);
+ DNSLookup* lookup, DNSAnswer* answer,
+ const UDPVersion param_flags = SYNC_);
/// \brief The destructor.
~DNSService();
//@}
/// \brief Add another server to the service
- void addServer(uint16_t port, const std::string &address);
- void addServer(const char &port, const std::string &address);
+ void addServer(uint16_t port, const std::string &address,
+ const UDPVersion param_flags = SYNC_);
+ void addServer(const char &port, const std::string &address,
+ const UDPVersion param_flags = SYNC_);
/// \brief Add another TCP server/listener to the service from already
/// opened file descriptor
@@ -122,7 +136,7 @@ public:
/// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6.
/// \throw isc::asiolink::IOError when a low-level error happens, like the
/// fd is not a valid descriptor or it can't be listened on.
- void addServerUDPFromFD(int fd, int af);
+ void addServerUDPFromFD(int fd, int af,const UDPVersion param_flags = SYNC_);
/// \brief Remove all servers from the service
void clearServers();
diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc
index 65c1d64..73d8a4b 100644
--- a/src/lib/asiodns/io_fetch.cc
+++ b/src/lib/asiodns/io_fetch.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <stdint.h>
#include <sys/socket.h>
diff --git a/src/lib/asiodns/sync_udp_server.cc b/src/lib/asiodns/sync_udp_server.cc
index 52da3bf..fb53fba 100644
--- a/src/lib/asiodns/sync_udp_server.cc
+++ b/src/lib/asiodns/sync_udp_server.cc
@@ -26,6 +26,7 @@
#include <boost/bind.hpp>
+#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> // for some IPC/network system calls
diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc
index d116bdb..5a06857 100644
--- a/src/lib/asiodns/tcp_server.cc
+++ b/src/lib/asiodns/tcp_server.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> // for some IPC/network system calls
diff --git a/src/lib/asiodns/tests/io_service_unittest.cc b/src/lib/asiodns/tests/io_service_unittest.cc
index cc64022..9161fb3 100644
--- a/src/lib/asiodns/tests/io_service_unittest.cc
+++ b/src/lib/asiodns/tests/io_service_unittest.cc
@@ -116,3 +116,8 @@ TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
delete dns_service;
}
+TEST(IOServiceTest, BadUdpServerVersion) {
+ IOService io_service;
+ DNSService* dns_service = new DNSService(io_service, NULL, NULL, NULL);
+ EXPECT_THROW(dns_service->addServer(*TEST_SERVER_PORT, "127.0.0.1", UDPVersion(3)), IOError);
+}
diff --git a/src/lib/asiodns/udp_server.cc b/src/lib/asiodns/udp_server.cc
index 990949e..0a8649a 100644
--- a/src/lib/asiodns/udp_server.cc
+++ b/src/lib/asiodns/udp_server.cc
@@ -12,6 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> // for some IPC/network system calls
diff --git a/src/lib/asiolink/io_service.cc b/src/lib/asiolink/io_service.cc
index 76d5ee1..124a301 100644
--- a/src/lib/asiolink/io_service.cc
+++ b/src/lib/asiolink/io_service.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> // for some IPC/network system calls
diff --git a/src/lib/cache/tests/negative_cache_unittest.cc b/src/lib/cache/tests/negative_cache_unittest.cc
index 56d777d..4935e4a 100644
--- a/src/lib/cache/tests/negative_cache_unittest.cc
+++ b/src/lib/cache/tests/negative_cache_unittest.cc
@@ -52,14 +52,17 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
msg_nxdomain.makeResponse();
Name non_exist_qname("nonexist.example.com.");
- EXPECT_TRUE(cache->lookup(non_exist_qname, RRType::A(), RRClass::IN(), msg_nxdomain));
+ EXPECT_TRUE(cache->lookup(non_exist_qname, RRType::A(), RRClass::IN(),
+ msg_nxdomain));
RRsetIterator iter = msg_nxdomain.beginSection(Message::SECTION_AUTHORITY);
RRsetPtr rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record
const RRTTL& nxdomain_ttl1 = rrset_ptr->getTTL();
- EXPECT_EQ(nxdomain_ttl1.getValue(), 86400);
+ // May have already crossed seconds boundary
+ EXPECT_GE(nxdomain_ttl1.getValue(), 86399);
+ EXPECT_LE(nxdomain_ttl1.getValue(), 86400);
// SOA response for example.com
Message msg_example_com_soa(Message::PARSE);
@@ -68,16 +71,22 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
msg_example_com_soa.makeResponse();
Name soa_qname("example.com.");
- EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(), msg_example_com_soa));
+ EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(),
+ msg_example_com_soa));
iter = msg_example_com_soa.beginSection(Message::SECTION_ANSWER);
rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record in answer section
const RRTTL& soa_ttl = rrset_ptr->getTTL();
- EXPECT_EQ(soa_ttl.getValue(), 172800);
+ // May have already crossed seconds boundary
+ EXPECT_GE(soa_ttl.getValue(), 172799);
+ EXPECT_LE(soa_ttl.getValue(), 172800);
- sleep(1);
+ // Sleep for 2 seconds. 2 seconds to make sure the final range check
+ // does not overlap with the original ones (in which case this test
+ // would erroneously pass if the ttl value is not changed)
+ sleep(2);
// Query nonexist.example.com again
Message msg_nxdomain2(Message::PARSE);
@@ -90,7 +99,8 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
// The TTL should equal to the TTL of negative response SOA record
const RRTTL& nxdomain_ttl2 = rrset_ptr->getTTL();
- EXPECT_TRUE(86398 <= nxdomain_ttl2.getValue() && nxdomain_ttl2.getValue() <= 86399);
+ EXPECT_GE(nxdomain_ttl2.getValue(), 86397);
+ EXPECT_LE(nxdomain_ttl2.getValue(), 86398);
// No RRset in ANSWER section
EXPECT_TRUE(msg_nxdomain2.getRRCount(Message::SECTION_ANSWER) == 0);
// Check that only one SOA record exist in AUTHORITY section
@@ -103,13 +113,15 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
Message msg_example_com_soa2(Message::PARSE);
messageFromFile(msg_example_com_soa2, "message_example_com_soa.wire");
msg_example_com_soa2.makeResponse();
- EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(), msg_example_com_soa2));
+ EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(),
+ msg_example_com_soa2));
iter = msg_example_com_soa2.beginSection(Message::SECTION_ANSWER);
rrset_ptr = *iter;
const RRTTL& soa_ttl2 = rrset_ptr->getTTL();
// The TTL should equal to the TTL of SOA record in answer section
- EXPECT_TRUE(172798 <= soa_ttl2.getValue() && soa_ttl2.getValue() <= 172799);
+ EXPECT_GE(soa_ttl2.getValue(), 172797);
+ EXPECT_LE(soa_ttl2.getValue(), 172798);
}
TEST_F(NegativeCacheTest, testNXDOMAINWithoutSOA){
@@ -166,15 +178,16 @@ TEST_F(NegativeCacheTest, testNoerrorNodata){
msg_nodata.makeResponse();
Name example_dot_com("example.com.");
- EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(), msg_nodata));
+ EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(),
+ msg_nodata));
RRsetIterator iter = msg_nodata.beginSection(Message::SECTION_AUTHORITY);
RRsetPtr rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record
const RRTTL& nodata_ttl1 = rrset_ptr->getTTL();
- EXPECT_EQ(nodata_ttl1.getValue(), 86400);
-
+ EXPECT_GE(nodata_ttl1.getValue(), 86399);
+ EXPECT_LE(nodata_ttl1.getValue(), 86400);
// Normal SOA response for example.com
Message msg_example_com_soa(Message::PARSE);
@@ -183,21 +196,26 @@ TEST_F(NegativeCacheTest, testNoerrorNodata){
msg_example_com_soa.makeResponse();
Name soa_qname("example.com.");
- EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(), msg_example_com_soa));
+ EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(),
+ msg_example_com_soa));
iter = msg_example_com_soa.beginSection(Message::SECTION_ANSWER);
rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record in answer section
const RRTTL& soa_ttl = rrset_ptr->getTTL();
- EXPECT_EQ(soa_ttl.getValue(), 172800);
+ EXPECT_GE(soa_ttl.getValue(), 172799);
+ EXPECT_LE(soa_ttl.getValue(), 172800);
// Query MX record of example.com again
Message msg_nodata2(Message::PARSE);
messageFromFile(msg_nodata2, "message_nodata_with_soa.wire");
msg_nodata2.makeResponse();
- sleep(1);
+ // Sleep for 2 seconds. 2 seconds to make sure the final range check
+ // does not overlap with the original ones (in which case this test
+ // would erroneously pass if the ttl value is not changed)
+ sleep(2);
EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(), msg_nodata2));
@@ -209,9 +227,11 @@ TEST_F(NegativeCacheTest, testNoerrorNodata){
iter = msg_nodata2.beginSection(Message::SECTION_AUTHORITY);
rrset_ptr = *iter;
- // The TTL should equal to the TTL of negative response SOA record and counted down
+ // The TTL should equal to the TTL of negative response SOA record
+ // and counted down
const RRTTL& nodata_ttl2 = rrset_ptr->getTTL();
- EXPECT_TRUE(86398 <= nodata_ttl2.getValue() && nodata_ttl2.getValue() <= 86399);
+ EXPECT_GE(nodata_ttl2.getValue(), 86397);
+ EXPECT_LE(nodata_ttl2.getValue(), 86398);
}
TEST_F(NegativeCacheTest, testReferralResponse){
diff --git a/src/lib/datasrc/rbnode_rrset.h b/src/lib/datasrc/rbnode_rrset.h
index 3e5d20a..43814b4 100644
--- a/src/lib/datasrc/rbnode_rrset.h
+++ b/src/lib/datasrc/rbnode_rrset.h
@@ -141,6 +141,25 @@ public:
}
}
+ virtual bool lthan(const AbstractRRset& other) const {
+ // Like "isSameKind", this method is an optimisation for the case where
+ // there will only ever be one object containing a particular RRset,
+ // and if the objects are different, the RRset they represent are
+ // different.
+ //
+ // lthan() is only used as an ordering for objects like std::set.
+ // Therefore the only criteria is that two objects are consistently
+ // ordered in the same way. The quickest way to do this is to use
+ // a comparison based on the address of the objects.
+ const RBNodeRRset* rb = dynamic_cast<const RBNodeRRset*>(&other);
+ if (rb != NULL) {
+ return (this < rb);
+ } else {
+ return (AbstractRRset::lthan(other));
+ }
+ }
+
+
virtual unsigned int toWire(
isc::dns::AbstractMessageRenderer& renderer) const;
diff --git a/src/lib/datasrc/tests/rbnode_rrset_unittest.cc b/src/lib/datasrc/tests/rbnode_rrset_unittest.cc
index c653f44..0693070 100644
--- a/src/lib/datasrc/tests/rbnode_rrset_unittest.cc
+++ b/src/lib/datasrc/tests/rbnode_rrset_unittest.cc
@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <algorithm>
+#include <sstream>
#include <stdexcept>
#include <exceptions/exceptions.h>
@@ -155,6 +157,84 @@ TEST_F(RBNodeRRsetTest, isSameKind) {
EXPECT_FALSE(rrset_p.isSameKind(rrset_z));
}
+
+// Utility function to create an add an RRset to a vector of RRsets for the
+// "less" test. It's only purpose is to allow the RRset creation to be
+// written with arguments in an order that reflects the RRset ordering.
+void
+addRRset(std::vector<ConstRRsetPtr>& vec, const RRType& rrtype,
+ const RRClass& rrclass, const char* rrname)
+{
+ vec.push_back(ConstRRsetPtr(new RRset(Name(rrname), rrclass, rrtype,
+ RRTTL(3600))));
+}
+
+TEST_F(RBNodeRRsetTest, lthan) {
+ // Check values of type codes: this effectively documents the expected
+ // order of the rrsets created.
+ ASSERT_EQ(1, RRType::A().getCode());
+ ASSERT_EQ(2, RRType::NS().getCode());
+
+ ASSERT_EQ(1, RRClass::IN().getCode());
+ ASSERT_EQ(3, RRClass::CH().getCode());
+
+ // Create a vector of RRsets in ascending (conventional) sort order.
+ std::vector<ConstRRsetPtr> rrsets;
+ addRRset(rrsets, RRType::A(), RRClass::IN(), "alpha.com");
+ addRRset(rrsets, RRType::A(), RRClass::IN(), "beta.com");
+ addRRset(rrsets, RRType::A(), RRClass::CH(), "alpha.com");
+ addRRset(rrsets, RRType::A(), RRClass::CH(), "beta.com");
+
+ // ... and create eight RBNodeRRsets for the underlying objects (two
+ // sets of four - the reason becomes apparent below).
+ std::vector<ConstRRsetPtr> rbrrsets;
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < rrsets.size(); ++j) {
+ rbrrsets.push_back(ConstRRsetPtr(new RBNodeRRset(rrsets[j])));
+ }
+ }
+
+ // Using the first four of the RBNodeRRsets, check that they order
+ // correctly when compared with the standard RRsets.
+ for (int i = 0; i < rrsets.size(); ++i) {
+ for (int j = 0; j < rrsets.size(); ++j) {
+ stringstream ss;
+ ss << "Comparing RbNodeRRset[" << i << "] against RRset["
+ << j << "]";
+ SCOPED_TRACE(ss.str());
+ if (i < j) {
+ EXPECT_TRUE(rbrrsets[i]->lthan(*rrsets[j]));
+ } else {
+ EXPECT_FALSE(rbrrsets[i]->lthan(*rrsets[j]));
+ }
+ }
+ }
+
+ // Put the raw pointers of the eight RBNodeRRsets into a vector and
+ // sort in ascending order.
+ std::vector<const AbstractRRset*> rbptrs;
+ for (int i = 0; i < rbrrsets.size(); ++i) {
+ rbptrs.push_back(rbrrsets[i].get());
+ }
+ sort(rbptrs.begin(), rbptrs.end());
+
+ // Now iterate through and check the relationships. Addresses with lower
+ // indexes should sort lower than addresses with higher indexes, regardless
+ // of what they point to.
+ for (int i = 0; i < rbptrs.size(); ++i) {
+ for (int j = 0; j < rbptrs.size(); ++j) {
+ stringstream ss;
+ ss << "Comparing address[" << i << "] against address[" << j << "]";
+ SCOPED_TRACE(ss.str());
+ if (i < j) {
+ EXPECT_TRUE(rbptrs[i]->lthan(*rbptrs[j]));
+ } else {
+ EXPECT_FALSE(rbptrs[i]->lthan(*rbptrs[j]));
+ }
+ }
+ }
+}
+
// Note: although the next two tests are essentially the same and used common
// test code, they use different test data: the MessageRenderer produces
// compressed wire data whereas the OutputBuffer does not.
diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc
index 9a55f5f..c517fea 100644
--- a/src/lib/dns/rrset.cc
+++ b/src/lib/dns/rrset.cc
@@ -123,6 +123,35 @@ AbstractRRset::isSameKind(const AbstractRRset& other) const {
getClass() == other.getClass());
}
+bool
+AbstractRRset::lthan(const AbstractRRset& other) const {
+
+ // Check on type first...
+ const uint16_t my_type = getType().getCode();
+ const uint16_t other_type = other.getType().getCode();
+ if (my_type < other_type) {
+ return (true);
+
+ } else if (my_type == other_type) {
+ // Types equal, so check class
+ const uint16_t my_class = getClass().getCode();
+ const uint16_t other_class = other.getClass().getCode();
+ if (my_class < other_class) {
+ return (true);
+
+ } else if (my_class == other_class) {
+ // Class equal, so check name
+ return (getName().lthan(other.getName()));
+
+ } else {
+ return (false);
+ }
+
+ } else {
+ return (false);
+ }
+}
+
ostream&
operator<<(ostream& os, const AbstractRRset& rrset) {
os << rrset.toText();
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index 7ad555f..082e17d 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -483,7 +483,29 @@ public:
/// against.
virtual bool isSameKind(const AbstractRRset& other) const;
+ /// \brief Check if one RRset is "less" than another
+ ///
+ /// This method is needed for storing RRsets in STL containers such
+ /// as multisets. It applies an ordering based on
+ /// - Type
+ /// - Class
+ /// - Name
+ /// (Type and Class are ordered by the values associated with those
+ /// constants. Name is ordered according to case-insensitive comparison.)
+ ///
+ /// Note that unlike isSameKind, type and class are checked before name.
+ /// This is because with ordering based on A, B and C (in that order), the
+ /// algorithm needs to do two checks on A and B - a "less than" check and a
+ /// check for equality. It only needs to do a "less than" check on C.
+ /// equality. It only needs to do one check on C,
+ ///
+ /// \param other The other AbstractRRset to compare against.
+ ///
+ /// \return true if "this" is less than the given RRset according to
+ /// the criteria given.
+ virtual bool lthan(const AbstractRRset& other) const;
//@}
+
};
/// \brief The \c RdataIterator class is an abstract base class that
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc
index a10b515..9e0d5e9 100644
--- a/src/lib/dns/tests/rrset_unittest.cc
+++ b/src/lib/dns/tests/rrset_unittest.cc
@@ -13,6 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <stdexcept>
+#include <iostream>
#include <util/buffer.h>
#include <dns/messagerenderer.h>
@@ -126,6 +127,66 @@ TEST_F(RRsetTest, isSameKind) {
EXPECT_FALSE(rrset_w.isSameKind(rrset_p));
}
+// Utility function to create an add an RRset to a vector of RRsets for the
+// "less" test. It's only purpose is to allow the RRset creation to be
+// written with arguments in an order that reflects the RRset ordering.
+void
+addRRset(std::vector<ConstRRsetPtr>& vec, const RRType& rrtype,
+ const RRClass& rrclass, const char* rrname)
+{
+ vec.push_back(ConstRRsetPtr(new RRset(Name(rrname), rrclass, rrtype,
+ RRTTL(3600))));
+}
+
+TEST_F(RRsetTest, lthan) {
+ // Check values of type codes: this effectively documents the expected
+ // order of the rrsets created.
+ ASSERT_EQ(1, RRType::A().getCode());
+ ASSERT_EQ(2, RRType::NS().getCode());
+
+ ASSERT_EQ(1, RRClass::IN().getCode());
+ ASSERT_EQ(3, RRClass::CH().getCode());
+
+ // Create a vector of RRsets in ascending sort order.
+ std::vector<ConstRRsetPtr> rrsets;
+ addRRset(rrsets, RRType::A(), RRClass::IN(), "alpha.com");
+ addRRset(rrsets, RRType::A(), RRClass::IN(), "beta.com");
+ addRRset(rrsets, RRType::A(), RRClass::CH(), "alpha.com");
+ addRRset(rrsets, RRType::A(), RRClass::CH(), "beta.com");
+ addRRset(rrsets, RRType::NS(), RRClass::IN(), "alpha.com");
+ addRRset(rrsets, RRType::NS(), RRClass::IN(), "beta.com");
+ addRRset(rrsets, RRType::NS(), RRClass::CH(), "alpha.com");
+ addRRset(rrsets, RRType::NS(), RRClass::CH(), "beta.com");
+
+ // ... and do the checks. The ASSERT_ form is used to avoid a plethora
+ // of messages if there is an error. And if there is an error, supply
+ // a more informative message.
+ for (int i = 0; i < rrsets.size(); ++i) {
+ // Check that an RRset is not less than itself
+ ostringstream ossi;
+ ossi << "i = ("
+ << rrsets[i]->getType().toText() << ", "
+ << rrsets[i]->getClass().toText() << ", "
+ << rrsets[i]->getName().toText()
+ << ")";
+ ASSERT_FALSE(rrsets[i]->lthan(*rrsets[i])) << ossi.str();
+ for (int j = i + 1; j < rrsets.size(); ++j) {
+ // Check it against the remaining RRsets.
+ ostringstream ossj;
+ ossj << ", j = ("
+ << rrsets[j]->getType().toText() << ", "
+ << rrsets[j]->getClass().toText() << ", "
+ << rrsets[j]->getName().toText()
+ << ")";
+ ASSERT_TRUE(rrsets[i]->lthan(*rrsets[j]))
+ << ossi.str() << ossj.str();
+ ASSERT_FALSE(rrsets[j]->lthan(*rrsets[i]))
+ << ossi.str() << ossj.str();
+ }
+ }
+}
+
+
void
addRdataTestCommon(const RRset& rrset) {
EXPECT_EQ(2, rrset.getRdataCount());
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index 153a00a..6f3bec9 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -34,7 +34,7 @@ logger = isc.log.Logger("notify_out")
# initialized yet. see trac ticket #1103
from isc.dns import *
-ZONE_NEW_DATA_READY_CMD = 'zone_new_data_ready'
+ZONE_NEW_DATA_READY_CMD = 'notify'
_MAX_NOTIFY_NUM = 30
_MAX_NOTIFY_TRY_NUM = 5
_EVENT_NONE = 0
@@ -164,17 +164,19 @@ class NotifyOut:
the only interface for class NotifyOut which can be called
by other object.
Internally, the function only set the zone's notify-reply
- timeout to now, then notify message will be sent out. '''
+ timeout to now, then notify message will be sent out.
+ Returns False if the zone/class is not known, True if it is
+ (even if there are no slaves)'''
if zone_name[len(zone_name) - 1] != '.':
zone_name += '.'
zone_id = (zone_name, zone_class)
if zone_id not in self._notify_infos:
- return
+ return False
# Has no slave servers, skip it.
if (len(self._notify_infos[zone_id].notify_slaves) <= 0):
- return
+ return True
with self._lock:
if (self.notify_num >= _MAX_NOTIFY_NUM) or (zone_id in self._notifying_zones):
@@ -186,6 +188,7 @@ class NotifyOut:
self._notifying_zones.append(zone_id)
if not self._nonblock_event.isSet():
self._nonblock_event.set()
+ return True
def _dispatcher(self, started_event):
started_event.set() # Let the master know we are alive already
@@ -250,7 +253,9 @@ class NotifyOut:
self._thread.join()
# Clean up
+ self._write_sock.close()
self._write_sock = None
+ self._read_sock.close()
self._read_sock = None
self._thread = None
diff --git a/src/lib/python/isc/notify/tests/notify_out_test.py b/src/lib/python/isc/notify/tests/notify_out_test.py
index d64c203..1b3a4a1 100644
--- a/src/lib/python/isc/notify/tests/notify_out_test.py
+++ b/src/lib/python/isc/notify/tests/notify_out_test.py
@@ -114,38 +114,48 @@ class TestNotifyOut(unittest.TestCase):
notify_out._MAX_NOTIFY_NUM = 2
self._notify._nonblock_event.clear()
- self._notify.send_notify('example.net')
+ self.assertTrue(self._notify.send_notify('example.net'))
self.assertTrue(self._notify._nonblock_event.isSet())
self.assertEqual(self._notify.notify_num, 1)
self.assertEqual(self._notify._notifying_zones[0], ('example.net.', 'IN'))
- self._notify.send_notify('example.com')
+ self.assertTrue(self._notify.send_notify('example.com'))
self.assertEqual(self._notify.notify_num, 2)
self.assertEqual(self._notify._notifying_zones[1], ('example.com.', 'IN'))
# notify_num is equal to MAX_NOTIFY_NUM, append it to waiting_zones list.
self._notify._nonblock_event.clear()
- self._notify.send_notify('example.com', 'CH')
+ self.assertTrue(self._notify.send_notify('example.com', 'CH'))
# add waiting zones won't set nonblock_event.
self.assertFalse(self._notify._nonblock_event.isSet())
self.assertEqual(self._notify.notify_num, 2)
self.assertEqual(1, len(self._notify._waiting_zones))
# zone_id is already in notifying_zones list, append it to waiting_zones list.
- self._notify.send_notify('example.net')
+ self.assertTrue(self._notify.send_notify('example.net'))
self.assertEqual(2, len(self._notify._waiting_zones))
self.assertEqual(self._notify._waiting_zones[1], ('example.net.', 'IN'))
# zone_id is already in waiting_zones list, skip it.
- self._notify.send_notify('example.net')
+ self.assertTrue(self._notify.send_notify('example.net'))
self.assertEqual(2, len(self._notify._waiting_zones))
# has no slave masters, skip it.
- self._notify.send_notify('example.org.', 'CH')
+ self.assertTrue(self._notify.send_notify('example.org.', 'CH'))
self.assertEqual(self._notify.notify_num, 2)
self.assertEqual(2, len(self._notify._waiting_zones))
- self._notify.send_notify('example.org.')
+ self.assertTrue(self._notify.send_notify('example.org.'))
+ self.assertEqual(self._notify.notify_num, 2)
+ self.assertEqual(2, len(self._notify._waiting_zones))
+
+ # zone does not exist, should return False, and no change in other
+ # values
+ self.assertFalse(self._notify.send_notify('does.not.exist.'))
+ self.assertEqual(self._notify.notify_num, 2)
+ self.assertEqual(2, len(self._notify._waiting_zones))
+
+ self.assertFalse(self._notify.send_notify('example.net.', 'CH'))
self.assertEqual(self._notify.notify_num, 2)
self.assertEqual(2, len(self._notify._waiting_zones))
@@ -185,6 +195,11 @@ class TestNotifyOut(unittest.TestCase):
# Now make one socket be readable
self._notify._notify_infos[('example.net.', 'IN')].notify_timeout = time.time() + 10
self._notify._notify_infos[('example.com.', 'IN')].notify_timeout = time.time() + 10
+
+ if self._notify._read_sock is not None:
+ self._notify._read_sock.close()
+ if self._notify._write_sock is not None:
+ self._notify._write_sock.close()
self._notify._read_sock, self._notify._write_sock = socket.socketpair()
self._notify._write_sock.send(SOCK_DATA)
replied_zones, timeout_zones = self._notify._wait_for_notify_reply()
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index ea7d528..f7bb441 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/socket.h>
diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc
index 4e939fa..83ea052 100644
--- a/src/lib/resolve/tests/recursive_query_unittest.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
diff --git a/src/lib/server_common/tests/client_unittest.cc b/src/lib/server_common/tests/client_unittest.cc
index 287a926..c8db846 100644
--- a/src/lib/server_common/tests/client_unittest.cc
+++ b/src/lib/server_common/tests/client_unittest.cc
@@ -12,6 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
diff --git a/src/lib/testutils/srv_test.cc b/src/lib/testutils/srv_test.cc
index b28ad57..03aec01 100644
--- a/src/lib/testutils/srv_test.cc
+++ b/src/lib/testutils/srv_test.cc
@@ -14,6 +14,7 @@
#include <config.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <dns/message.h>
diff --git a/src/lib/testutils/testdata/.gitignore b/src/lib/testutils/testdata/.gitignore
index 3c239fc..1f61066 100644
--- a/src/lib/testutils/testdata/.gitignore
+++ b/src/lib/testutils/testdata/.gitignore
@@ -10,3 +10,5 @@
/shortanswer_fromWire.wire
/simplequery_fromWire.wire
/simpleresponse_fromWire.wire
+/test1.zone.copied
+/test2.zone.copied
diff --git a/src/lib/util/buffer.h b/src/lib/util/buffer.h
index a885db1..b8cc12d 100644
--- a/src/lib/util/buffer.h
+++ b/src/lib/util/buffer.h
@@ -380,9 +380,7 @@ public:
/// \param pos The position in the buffer to be returned.
uint8_t operator[](size_t pos) const
{
- if (pos >= size_) {
- isc_throw(InvalidBufferPosition, "read at invalid position");
- }
+ assert (pos < size_);
return (buffer_[pos]);
}
//@}
diff --git a/src/lib/util/tests/buffer_unittest.cc b/src/lib/util/tests/buffer_unittest.cc
index 666924e..8cccd28 100644
--- a/src/lib/util/tests/buffer_unittest.cc
+++ b/src/lib/util/tests/buffer_unittest.cc
@@ -182,7 +182,17 @@ TEST_F(BufferTest, outputBufferReadat) {
for (int i = 0; i < sizeof(testdata); i ++) {
EXPECT_EQ(testdata[i], obuffer[i]);
}
- EXPECT_THROW(obuffer[sizeof(testdata)], isc::util::InvalidBufferPosition);
+#ifdef EXPECT_DEATH
+ // We use assert now, so we check it dies
+ EXPECT_DEATH({
+ try {
+ obuffer[sizeof(testdata)];
+ } catch (...) {
+ // Prevent exceptions killing the application, we need
+ // to make sure it dies the real hard way
+ }
+ }, "");
+#endif
}
TEST_F(BufferTest, outputBufferClear) {
diff --git a/tests/lettuce/configurations/example.org.inmem.config b/tests/lettuce/configurations/example.org.inmem.config
new file mode 100644
index 0000000..fa5f954
--- /dev/null
+++ b/tests/lettuce/configurations/example.org.inmem.config
@@ -0,0 +1 @@
+{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "auth", "debuglevel": 99}]}, "Auth": {"database_file": "", "listen_on": [{"port": 47806, "address": "127.0.0.1"}], "datasources": [{"zones": [{"origin": "example.org", "file": "data/example.org"}], "type": "memory"}]}}
diff --git a/tests/lettuce/data/example.org b/tests/lettuce/data/example.org
new file mode 100644
index 0000000..20a93be
--- /dev/null
+++ b/tests/lettuce/data/example.org
@@ -0,0 +1,12 @@
+example.org. 3600 IN SOA ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
+example.org. 3600 IN NS ns1.example.org.
+example.org. 3600 IN NS ns2.example.org.
+example.org. 3600 IN MX 10 mail.example.org.
+www.example.org. 3600 IN A 192.0.2.1
+mail.example.org. 3600 IN A 192.0.2.10
+sub.example.org. 3600 IN NS ns.sub.example.org.
+ns.sub.example.org. 3600 IN A 192.0.2.101
+dname.example.org. 3600 IN DNAME dname.example.info.
+dname2.foo.example.org. 3600 IN DNAME dname2.example.info.
+ns1.example.org. 3600 IN A 192.0.2.3
+ns2.example.org. 3600 IN A 192.0.2.4
diff --git a/tests/lettuce/features/queries.feature b/tests/lettuce/features/queries.feature
new file mode 100644
index 0000000..b8f9b3d
--- /dev/null
+++ b/tests/lettuce/features/queries.feature
@@ -0,0 +1,81 @@
+Feature: Querying feature
+ This feature is a collection of non-specific querying tests;
+ for instance whether multiple queries in a row return consistent
+ answers.
+
+ Scenario: Repeated queries
+ Given I have bind10 running with configuration example.org.inmem.config
+ A query for www.example.org should have rcode NOERROR
+ The last query response should have flags qr aa rd
+ The last query response should have ancount 1
+ The last query response should have nscount 2
+ The last query response should have adcount 2
+
+ The answer section of the last query response should be
+ """
+ www.example.org. 3600 IN A 192.0.2.1
+ """
+ The authority section of the last query response should be
+ """
+ example.org. 3600 IN NS ns1.example.org.
+ example.org. 3600 IN NS ns2.example.org.
+ """
+ The additional section of the last query response should be
+ """
+ ns1.example.org. 3600 IN A 192.0.2.3
+ ns2.example.org. 3600 IN A 192.0.2.4
+ """
+
+ # Repeat of the above
+ A query for www.example.org should have rcode NOERROR
+ The last query response should have flags qr aa rd
+ The last query response should have ancount 1
+ The last query response should have nscount 2
+ The last query response should have adcount 2
+
+ The answer section of the last query response should be
+ """
+ www.example.org. 3600 IN A 192.0.2.1
+ """
+ The authority section of the last query response should be
+ """
+ example.org. 3600 IN NS ns1.example.org.
+ example.org. 3600 IN NS ns2.example.org.
+ """
+ The additional section of the last query response should be
+ """
+ ns1.example.org. 3600 IN A 192.0.2.3
+ ns2.example.org. 3600 IN A 192.0.2.4
+ """
+
+ # And now query something completely different
+ A query for nosuchname.example.org should have rcode NXDOMAIN
+ The last query response should have flags qr aa rd
+ The last query response should have ancount 0
+ The last query response should have nscount 1
+ The last query response should have adcount 0
+ The authority section of the last query response should be
+ """
+ example.org. 3600 IN SOA ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
+ """
+
+ Scenario: ANY query
+ Given I have bind10 running with configuration example.org.inmem.config
+ A query for example.org type ANY should have rcode NOERROR
+ The last query response should have flags qr aa rd
+ The last query response should have ancount 4
+ The last query response should have nscount 0
+ The last query response should have adcount 3
+ The answer section of the last query response should be
+ """
+ example.org. 3600 IN NS ns1.example.org.
+ example.org. 3600 IN NS ns2.example.org.
+ example.org. 3600 IN SOA ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
+ example.org. 3600 IN MX 10 mail.example.org.
+ """
+ The additional section of the last query response should be
+ """
+ ns1.example.org. 3600 IN A 192.0.2.3
+ ns2.example.org. 3600 IN A 192.0.2.4
+ mail.example.org. 3600 IN A 192.0.2.10
+ """
diff --git a/tools/git-obsolete-branch.py b/tools/git-obsolete-branch.py
new file mode 100755
index 0000000..70a7788
--- /dev/null
+++ b/tools/git-obsolete-branch.py
@@ -0,0 +1,198 @@
+#!/usr/bin/python
+#
+# 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.
+
+#
+# This script lists obsolete (fully merged) branches. It is useful for periodic
+# maintenance of our GIT tree.
+#
+# It is good idea to use following command before running this script:
+#
+# git pull
+# git remote prune origin
+#
+# This script requires python 2.7 or 3.
+#
+# I have limited experience in Python. If things are done in a strange or
+# uncommon way, there are no obscure reasons to do it that way, just plain
+# lack of experience.
+#
+# tomek
+
+import string
+import subprocess
+import sys
+from optparse import OptionParser
+
+class Branch:
+ MERGED = 1
+ NOTMERGED = 2
+ name = None
+ status = NOTMERGED
+ last_commit = None
+
+
+def branch_list_get(verbose):
+ """ Generates a list of available remote branches and
+ checks their status (merged/unmerged). A branch is merged
+ if all changes on that branch are also on master. """
+
+ # call git branch -r (list of remote branches)
+ txt_list = subprocess.check_output(["git", "branch", "-r"])
+
+ txt_list = txt_list.split(b"\n")
+
+ # we will store list of suitable branches here
+ out = []
+ for branch in txt_list:
+ # skip empty lines
+ if len(branch) == 0:
+ continue
+
+ # skip branches that are aliases (something -> something_else)
+ if branch.find(b"->") != -1:
+ continue
+
+ # don't complain about master
+ if branch == b"origin/master":
+ continue
+
+ branch_info = Branch()
+
+ # get branch name
+ branch_info.name = branch.strip(b" ")
+ branch_info.name = branch_info.name.decode("utf-8")
+
+ # check if branch is merged or not
+ if verbose:
+ print("Checking branch %s" % branch_info.name)
+
+ # get a diff with changes that are on that branch only
+ # i.e. all unmerged code.
+ cmd = ["git", "diff", "master..." + branch_info.name ]
+ diff = subprocess.check_output(cmd)
+ if len(diff) == 0:
+ # No diff? Then all changes from that branch are on master as well.
+ branch_info.status = Branch.MERGED
+
+ # let's get the last contributor with extra formatting
+ # see man git-log and search for PRETTY FORMATS.
+ # %ai = date, %ae = author e-mail, %an = author name
+ cmd = [ "git" , "log", "-n", "1", "--pretty=\"%ai,%ae,%an\"",
+ branch_info.name ]
+ offender = subprocess.check_output(cmd)
+ offender = offender.strip(b"\n\"")
+
+ # comment out this 2 lines to disable obfuscation
+ offender = offender.replace(b"@", b"(at)")
+ # Obfuscating a dot does not work too well for folks that use
+ # initials
+ #offender = offender.replace(b".", b"(dot)")
+
+ branch_info.last_commit = offender.decode("utf-8")
+
+ else:
+ # diff is not empty, so there is something to merge
+ branch_info.status = Branch.NOTMERGED
+
+ out.append(branch_info)
+ return out
+
+def branch_print(branches, csv, print_merged, print_notmerged, print_stats):
+ """ prints out list of branches with specified details (using
+ human-readable (or CSV) format. It is possible to specify,
+ which branches should be printed (merged, notmerged) and
+ also print out summary statistics """
+
+ # counters used for statistics
+ merged = 0
+ notmerged = 0
+
+ # compact list of merged/notmerged branches
+ merged_str = ""
+ notmerged_str = ""
+ for branch in branches:
+ if branch.status == Branch.MERGED:
+ merged = merged + 1
+ if not print_merged:
+ continue
+ if csv:
+ print("%s,merged,%s" % (branch.name, branch.last_commit) )
+ else:
+ merged_str = merged_str + " " + branch.name
+ else:
+ # NOT MERGED
+ notmerged = notmerged + 1
+ if not print_notmerged:
+ continue
+ if csv:
+ print("%s,notmerged,%s" % (branch.name, branch.last_commit) )
+ else:
+ notmerged_str = notmerged_str + " " + branch.name
+
+ if not csv:
+ if print_merged:
+ print("Merged branches : %s" % (merged_str))
+ if print_notmerged:
+ print("NOT merged branches: %s" % (notmerged_str))
+
+ if print_stats:
+ print("#----------")
+ print("#Merged : %d" % merged)
+ print("#Not merged: %d" % notmerged)
+
+
+def parse_args(args=sys.argv[1:], Parser=OptionParser):
+
+ parser = Parser(description="This script prints out merged and/or unmerged"
+ " branches of a GIT tree.")
+
+ parser.add_option("-c", "--csv", action="store_true",
+ default=False, help="generates CSV output")
+ parser.add_option("-u", "--unmerged", action="store_true",
+ default=False, help="lists unmerged branches")
+ parser.add_option("-m", "--skip-merged", action="store_true",
+ default=False, help="omits listing merged branches")
+ parser.add_option("-s", "--stats", action="store_true",
+ default=False, help="prints also statistics")
+
+ (options, args) = parser.parse_args(args)
+
+ if args:
+ parser.print_help()
+ sys.exit(1)
+
+ return options
+
+def main():
+ usage = """%prog
+ Lists all obsolete (fully merged into master) branches.
+ """
+
+ options = parse_args()
+ csv = options.csv
+ merged = not options.skip_merged
+ unmerged = options.unmerged
+ stats = options.stats
+
+ if csv:
+ print("branch name,status,date,last commit(mail),last commit(name)")
+
+ branch_list = branch_list_get(not csv)
+
+ branch_print(branch_list, csv, merged, unmerged, stats)
+
+if __name__ == '__main__':
+ main()
More information about the bind10-changes
mailing list