BIND 10 master, updated. 6ecf994e0d3580064d6c8a490dfba1a02e9930ee [master] Merge branch 'trac1305'
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Oct 19 20:50:44 UTC 2011
The branch, master has been updated
via 6ecf994e0d3580064d6c8a490dfba1a02e9930ee (commit)
via 9ebdb058e61cae1dda642fcb00ced7b7554b44fb (commit)
via b88c94b7119650217408d800847dfbbbcea7306c (commit)
via 419b9d48771946a1b0b75b7412cd2da3e7f81a5a (commit)
via acab4a018b927cf5887b6de8135dbae0d2dcdbff (commit)
via ce532896000ddcc026045a08ddb9ae2b96ae7ba9 (commit)
via ddf232dc82203a777e0a59aa9b8252aaf5117548 (commit)
via 41c8d6f1170f06e1da8908666444c88b08906f1e (commit)
via 14909927e06d884129baf8baf7fd8760b2dea196 (commit)
via 4a345eca2184ebccec3a17902056d03f5d00e540 (commit)
via 6217a55056c1e2e6fa8d82357d86b218de43ded4 (commit)
via 32012c8148dbf25fea0a490bd8453fcfb3854cbb (commit)
from 6a54cfb961dae9f44120ae2da4bd4c3693f9ea49 (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 6ecf994e0d3580064d6c8a490dfba1a02e9930ee
Merge: 6a54cfb 9ebdb05
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Oct 19 13:48:05 2011 -0700
[master] Merge branch 'trac1305'
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/database.cc | 15 ++-
src/lib/datasrc/tests/database_unittest.cc | 137 ++++++++++++++++++----
src/lib/datasrc/zone.h | 93 +++++++++++----
src/lib/python/isc/datasrc/datasrc.cc | 4 +
src/lib/python/isc/datasrc/finder_inc.cc | 57 ++++++----
src/lib/python/isc/datasrc/tests/datasrc_test.py | 24 ++++
6 files changed, 257 insertions(+), 73 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index e476297..d35f6e8 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -417,7 +417,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
size_t last_known(origin_label_count);
const size_t current_label_count(name.getLabelCount());
// This is how many labels we remove to get origin
- size_t remove_labels(current_label_count - origin_label_count);
+ const size_t remove_labels(current_label_count - origin_label_count);
// Now go trough all superdomains from origin down
for (int i(remove_labels); i > 0; --i) {
@@ -508,13 +508,18 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
arg(accessor_->getDBName()).arg(name);
records_found = true;
get_cover = dnssec_data;
+ } else if ((options & NO_WILDCARD) != 0) {
+ // If wildcard check is disabled, the search will ultimately
+ // terminate with NXDOMAIN. If DNSSEC is enabled, flag that
+ // we need to get the NSEC records to prove this.
+ if (dnssec_data) {
+ get_cover = true;
+ }
} else {
// It's not empty non-terminal. So check for wildcards.
// We remove labels one by one and look for the wildcard there.
// Go up to first non-empty domain.
-
- remove_labels = current_label_count - last_known;
- for (size_t i(1); i <= remove_labels; ++ i) {
+ for (size_t i(1); i <= current_label_count - last_known; ++i) {
// Construct the name with *
const Name superdomain(name.split(i));
const string wildcard("*." + superdomain.toText());
@@ -553,7 +558,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
if (cni != found.second.end() &&
type != RRType::CNAME()) {
result_rrset = cni->second;
- result_status = CNAME;
+ result_status = WILDCARD_CNAME;
} else if (nsi != found.second.end()) {
result_rrset = nsi->second;
result_status = DELEGATION;
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index 8cd70ef..de6b5fa 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -175,8 +175,11 @@ const char* const TEST_RECORDS[][5] = {
{"*.delegatedwild.example.org.", "A", "3600", "", "192.0.2.5"},
{"wild.*.foo.example.org.", "A", "3600", "", "192.0.2.5"},
{"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},
+ {"wild.*.foo.*.bar.example.org.", "NSEC", "3600", "",
+ "brokenns1.example.org. A NSEC"},
{"bao.example.org.", "NSEC", "3600", "", "wild.*.foo.*.bar.example.org. NSEC"},
{"*.cnamewild.example.org.", "CNAME", "3600", "", "www.example.org."},
+ {"*.dnamewild.example.org.", "DNAME", "3600", "", "dname.example.com."},
{"*.nswild.example.org.", "NS", "3600", "", "ns.example.com."},
// For NSEC empty non-terminal
{"l.example.org.", "NSEC", "3600", "", "empty.nonterminal.example.org. NSEC"},
@@ -258,9 +261,16 @@ private:
* implementation of the optional functionality.
*/
class MockAccessor : public NopAccessor {
- // Type of mock database "row"s
- typedef std::map<std::string, std::vector< std::vector<std::string> > >
- Domains;
+ // Type of mock database "row"s. This is a map whose keys are the
+ // own names. We internally sort them by the name comparison order.
+ struct NameCompare : public binary_function<string, string, bool> {
+ bool operator()(const string& n1, const string& n2) const {
+ return (Name(n1).compare(Name(n2)).getOrder() < 0);
+ }
+ };
+ typedef std::map<std::string,
+ std::vector< std::vector<std::string> >,
+ NameCompare > Domains;
public:
MockAccessor() : rollbacked_(false) {
@@ -554,30 +564,36 @@ public:
virtual std::string findPreviousName(int id, const std::string& rname)
const
{
- // Hardcoded for now, but we could compute it from the data
- // Maybe do it when it is needed some time in future?
if (id == -1) {
isc_throw(isc::NotImplemented, "Test not implemented behaviour");
- } else if (id == 42) {
- if (rname == "org.example.nonterminal.") {
- return ("l.example.org.");
- } else if (rname == "org.example.aa.") {
- return ("example.org.");
- } else if (rname == "org.example.www2." ||
- rname == "org.example.www1.") {
- return ("www.example.org.");
- } else if (rname == "org.example.badnsec2.") {
+ } else if (id == READONLY_ZONE_ID) {
+ // For some specific names we intentionally return broken or
+ // unexpected result.
+ if (rname == "org.example.badnsec2.") {
return ("badnsec1.example.org.");
} else if (rname == "org.example.brokenname.") {
return ("brokenname...example.org.");
- } else if (rname == "org.example.bar.*.") {
- return ("bao.example.org.");
} else if (rname == "org.example.notimplnsec." ||
rname == "org.example.wild.here.") {
isc_throw(isc::NotImplemented, "Not implemented in this test");
- } else {
+ }
+
+ // For the general case, we search for the first name N in the
+ // domains that meets N >= reverse(rname) using lower_bound.
+ // The "previous name" is the name of the previous entry of N.
+ // Note that Domains are internally sorted by the Name comparison
+ // order. Due to the API requirement we are given a reversed
+ // name (rname), so we need to reverse it again to convert it
+ // to the original name.
+ Domains::const_iterator it(readonly_records_->lower_bound(
+ Name(rname).reverse().toText()));
+ if (it == readonly_records_->begin()) {
isc_throw(isc::Unexpected, "Unexpected name");
}
+ if (it == readonly_records_->end()) {
+ return ((*readonly_records_->rbegin()).first);
+ }
+ return ((*(--it)).first);
} else {
isc_throw(isc::Unexpected, "Unknown zone ID");
}
@@ -1027,8 +1043,8 @@ doFindTest(ZoneFinder& finder,
const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
{
SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
- ZoneFinder::FindResult result =
- finder.find(name, type, NULL, options);
+ const ZoneFinder::FindResult result = finder.find(name, type, NULL,
+ options);
ASSERT_EQ(expected_result, result.code) << name << " " << type;
if (!expected_rdatas.empty() && result.rrset) {
checkRRset(result.rrset, expected_name != Name(".") ? expected_name :
@@ -1595,21 +1611,21 @@ TYPED_TEST(DatabaseClientTest, wildcard) {
"bar.example.org",
NULL
};
+ // Unless FIND_DNSSEC is specified, this is no different from other
+ // NXRRSET case.
for (const char** name(negative_names); *name != NULL; ++ name) {
doFindTest(*finder, isc::dns::Name(*name), this->qtype_,
this->qtype_, this->rrttl_, ZoneFinder::NXRRSET,
this->expected_rdatas_, this->expected_sig_rdatas_);
- // FIXME: What should be returned in this case? How does the
- // DNSSEC logic handle it?
}
+ // With FIND_DNSSEC, it should result in WILDCARD_NXRRSET.
const char* negative_dnssec_names[] = {
"a.bar.example.org.",
"foo.baz.bar.example.org.",
"a.foo.bar.example.org.",
NULL
};
-
this->expected_rdatas_.clear();
this->expected_rdatas_.push_back("wild.*.foo.*.bar.example.org. NSEC");
this->expected_sig_rdatas_.clear();
@@ -1620,15 +1636,27 @@ TYPED_TEST(DatabaseClientTest, wildcard) {
Name("bao.example.org."), ZoneFinder::FIND_DNSSEC);
}
- // Some strange things in the wild node
+ // CNAME on a wildcard. Maybe not so common, but not disallowed.
this->expected_rdatas_.clear();
this->expected_rdatas_.push_back("www.example.org.");
this->expected_sig_rdatas_.clear();
doFindTest(*finder, isc::dns::Name("a.cnamewild.example.org."),
isc::dns::RRType::TXT(), isc::dns::RRType::CNAME(),
- this->rrttl_, ZoneFinder::CNAME,
+ this->rrttl_, ZoneFinder::WILDCARD_CNAME,
this->expected_rdatas_, this->expected_sig_rdatas_);
+ // DNAME on a wildcard. In our implementation we ignore DNAMEs on a
+ // wildcard, but at a higher level we say the behavior is "unspecified".
+ // rfc2672bis strongly discourages the mixture of DNAME and wildcard
+ // (with SHOULD NOT).
+ this->expected_rdatas_.clear();
+ this->expected_sig_rdatas_.clear();
+ doFindTest(*finder, Name("a.dnamewild.example.org."),
+ this->qtype_, this->qtype_, this->rrttl_,
+ ZoneFinder::WILDCARD_NXRRSET, this->expected_rdatas_,
+ this->expected_sig_rdatas_);
+
+ // Some strange things in the wild node
this->expected_rdatas_.clear();
this->expected_rdatas_.push_back("ns.example.com.");
doFindTest(*finder, isc::dns::Name("a.nswild.example.org."),
@@ -1637,6 +1665,67 @@ TYPED_TEST(DatabaseClientTest, wildcard) {
this->expected_rdatas_, this->expected_sig_rdatas_);
}
+TYPED_TEST(DatabaseClientTest, noWildcard) {
+ // Tests with the NO_WILDCARD flag.
+
+ shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+
+ // This would match *.wild.example.org, but with NO_WILDCARD should
+ // result in NXDOMAIN.
+ this->expected_rdatas_.push_back("cancel.here.wild.example.org. A "
+ "NSEC RRSIG");
+ this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+ "20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE");
+ doFindTest(*finder, isc::dns::Name("a.wild.example.org"),
+ RRType::NSEC(), RRType::NSEC(), this->rrttl_,
+ ZoneFinder::NXDOMAIN, this->expected_rdatas_,
+ this->expected_sig_rdatas_, Name("*.wild.example.org."),
+ ZoneFinder::FIND_DNSSEC | ZoneFinder::NO_WILDCARD);
+
+ // Should be the same without FIND_DNSSEC (but in this case no RRsets
+ // will be returned)
+ doFindTest(*finder, isc::dns::Name("a.wild.example.org"),
+ RRType::NSEC(), RRType::NSEC(), this->rrttl_,
+ ZoneFinder::NXDOMAIN, this->empty_rdatas_,
+ this->empty_rdatas_, Name::ROOT_NAME(), // name is dummy
+ ZoneFinder::NO_WILDCARD);
+
+ // Same for wildcard empty non terminal.
+ this->expected_rdatas_.clear();
+ this->expected_rdatas_.push_back("brokenns1.example.org. A NSEC");
+ doFindTest(*finder, isc::dns::Name("a.bar.example.org"),
+ RRType::NSEC(), RRType::NSEC(), this->rrttl_,
+ ZoneFinder::NXDOMAIN, this->expected_rdatas_,
+ this->empty_rdatas_, Name("wild.*.foo.*.bar.example.org"),
+ ZoneFinder::FIND_DNSSEC | ZoneFinder::NO_WILDCARD);
+
+ // Search for a wildcard name with NO_WILDCARD. There should be no
+ // difference. This is, for example, necessary to provide non existence
+ // of matching wildcard for isnx.nonterminal.example.org.
+ this->expected_rdatas_.clear();
+ this->expected_rdatas_.push_back("empty.nonterminal.example.org. NSEC");
+ doFindTest(*finder, isc::dns::Name("*.nonterminal.example.org"),
+ RRType::NSEC(), RRType::NSEC(), this->rrttl_,
+ ZoneFinder::NXDOMAIN, this->expected_rdatas_,
+ this->empty_rdatas_, Name("l.example.org"),
+ ZoneFinder::FIND_DNSSEC | ZoneFinder::NO_WILDCARD);
+
+ // On the other hand, if there's exact match for the wildcard name
+ // it should be found regardless of NO_WILDCARD.
+ this->expected_rdatas_.clear();
+ this->expected_rdatas_.push_back("192.0.2.5");
+ this->expected_sig_rdatas_.clear();
+ this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 "
+ "20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE");
+ doFindTest(*finder, isc::dns::Name("*.wild.example.org"),
+ this->qtype_, this->qtype_, this->rrttl_,
+ ZoneFinder::SUCCESS, this->expected_rdatas_,
+ this->expected_sig_rdatas_, Name("*.wild.example.org"),
+ ZoneFinder::NO_WILDCARD);
+}
+
TYPED_TEST(DatabaseClientTest, NXRRSET_NSEC) {
// The domain exists, but doesn't have this RRType
// So we should get its NSEC
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index c83b14b..fa1c744 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -63,32 +63,70 @@ public:
/// actually the best wildcard we have). Data sources that don't
/// support DNSSEC don't need to distinguish them.
///
- /// In case of NXRRSET related results, the returned NSEC record
- /// belongs to the domain which would provide the result if it
- /// contained the correct type (in case of NXRRSET, it is the queried
- /// domain, in case of WILDCARD_NXRRSET, it is the wildcard domain
- /// that matched the query name). In case of an empty nonterminal,
- /// an NSEC is provided for the interval where the empty nonterminal
- /// lives. The end of the interval is the subdomain causing existence
- /// of the empty nonterminal (if there's sub.x.example.com, and no record
- /// in x.example.com, then x.example.com exists implicitly - is the empty
- /// nonterminal and sub.x.example.com is the subdomain causing it).
+ /// In case of CNAME, if the CNAME is a wildcard (i.e., its owner name
+ /// starts with the label "*"), WILDCARD_CNAME will be returned instead
+ /// of CNAME.
+ ///
+ /// In case of NXDOMAIN, the returned NSEC covers the queried domain
+ /// that proves that the query name does not exist in the zone. Note that
+ /// this does not necessarily prove it doesn't even match a wildcard
+ /// (even if the result of NXDOMAIN can only happen when there's no
+ /// matching wildcard either). It is caller's responsibility to provide
+ /// a proof that there is no matching wildcard if that proof is necessary.
+ ///
+ /// Various variants of "no data" cases are complicated, when involves
+ /// DNSSEC and wildcard processing. Referring to Section 3.1.3 of
+ /// RFC4035, we need to consider the following cases:
+ /// -# (Normal) no data: there is a matching non-wildcard name with a
+ /// different RR type. This is the "No Data" case of the RFC.
+ /// -# (Normal) empty non terminal: there is no matching (exact or
+ /// wildcard) name, but there is a subdomain with an RR of the query
+ /// name. This is one case of "Name Error" of the RFC.
+ /// -# Wildcard empty non terminal: similar to 2a, but the empty name
+ /// is a wildcard, and matches the query name by wildcard expansion.
+ /// This is a special case of "Name Error" of the RFC.
+ /// -# Wildcard no data: there is no exact match name, but there is a
+ /// wildcard name that matches the query name with a different type
+ /// of RR. This is the "Wildcard No Data" case of the RFC.
+ ///
+ /// In any case, \c find() will result in \c NXRRSET with no RRset
+ /// unless the \c FIND_DNSSEC option is specified. The rest of the
+ /// discussion only applies to the case where this option is specified.
+ ///
+ /// In case 1, \c find() will result in NXRRSET, and return NSEC of the
+ /// matching name.
+ ///
+ /// In case 2, \c find() will result in NXRRSET, and return NSEC for the
+ /// interval where the empty nonterminal lives. The end of the interval
+ /// is the subdomain causing existence of the empty nonterminal (if
+ /// there's sub.x.example.com, and no record in x.example.com, then
+ /// x.example.com exists implicitly - is the empty nonterminal and
+ /// sub.x.example.com is the subdomain causing it). Note that this NSEC
+ /// proves not only the existence of empty non terminal name but also
+ /// the non existence of possibly matching wildcard name, because
+ /// there can be no better wildcard match than the exact matching empty
+ /// name.
+ ///
+ /// In case 3, \c find() will result in WILDCARD_NXRRSET, and return NSEC
+ /// for the interval where the wildcard empty nonterminal lives.
+ /// Cases 2 and 3 are especially complicated and confusing. See the
+ /// examples below.
+ ///
+ /// In case 4, \c find() will result in WILDCARD_NXRRSET, and return
+ /// NSEC of the matching wildcard name.
///
/// Examples: if zone "example.com" has the following record:
/// \code
- /// a.b.example.com. NSEC c.example.com.
+ /// a.example.com. NSEC a.b.example.com.
/// \endcode
- /// a call to \c find() for "b.example.com." will result in NXRRSET,
- /// and if the FIND_DNSSEC option is set this NSEC will be returned.
+ /// a call to \c find() for "b.example.com." with the FIND_DNSSEC option
+ /// will result in NXRRSET, and this NSEC will be returned.
/// Likewise, if zone "example.org" has the following record,
/// \code
- /// x.*.example.org. NSEC a.example.org.
+ /// a.example.org. NSEC x.*.b.example.org.
/// \endcode
- /// a call to \c find() for "y.example.org" will result in
- /// WILDCARD_NXRRSET (*.example.org is an empty nonterminal wildcard node),
- /// and if the FIND_DNSSEC option is set this NSEC will be returned.
- ///
- /// In case of NXDOMAIN, the returned NSEC covers the queried domain.
+ /// a call to \c find() for "y.b.example.org" with FIND_DNSSEC will
+ /// result in NXRRSET_NXRRSET, and this NSEC will be returned.
enum Result {
SUCCESS, ///< An exact match is found.
DELEGATION, ///< The search encounters a zone cut.
@@ -97,6 +135,7 @@ public:
CNAME, ///< The search encounters and returns a CNAME RR
DNAME, ///< The search encounters and returns a DNAME RR
WILDCARD, ///< Succes by wildcard match, for DNSSEC
+ WILDCARD_CNAME, ///< CNAME on wildcard, search returns CNAME, for DNSSEC
WILDCARD_NXRRSET ///< NXRRSET on wildcard, for DNSSEC
};
@@ -138,10 +177,11 @@ public:
enum FindOptions {
FIND_DEFAULT = 0, ///< The default options
FIND_GLUE_OK = 1, ///< Allow search under a zone cut
- FIND_DNSSEC = 2 ///< Require DNSSEC data in the answer
+ FIND_DNSSEC = 2, ///< Require DNSSEC data in the answer
///< (RRSIG, NSEC, etc.). The implementation
///< is allowed to include it even if it is
///< not set.
+ NO_WILDCARD = 4 ///< Do not try wildcard matching.
};
///
@@ -181,6 +221,7 @@ public:
/// for the data that best matches the given name and type.
/// This method is expected to be "intelligent", and identifies the
/// best possible answer for the search key. Specifically,
+ ///
/// - If the search name belongs under a zone cut, it returns the code
/// of \c DELEGATION and the NS RRset at the zone cut.
/// - If there is no matching name, it returns the code of \c NXDOMAIN,
@@ -199,12 +240,14 @@ public:
/// - If the target isn't NULL, all RRsets under the domain are inserted
/// there and SUCCESS (or NXDOMAIN, in case of empty domain) is returned
/// instead of normall processing. This is intended to handle ANY query.
- /// \note: this behavior is controversial as we discussed in
- /// https://lists.isc.org/pipermail/bind10-dev/2011-January/001918.html
- /// We should revisit the interface before we heavily rely on it.
+ ///
+ /// \note This behavior is controversial as we discussed in
+ /// https://lists.isc.org/pipermail/bind10-dev/2011-January/001918.html
+ /// We should revisit the interface before we heavily rely on it.
///
/// The \c options parameter specifies customized behavior of the search.
/// Their semantics is as follows (they are or bit-field):
+ ///
/// - \c FIND_GLUE_OK Allow search under a zone cut. By default the search
/// will stop once it encounters a zone cut. If this option is specified
/// it remembers information about the highest zone cut and continues
@@ -216,6 +259,10 @@ public:
/// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
/// returned with the answer. It is allowed for the data source to
/// include them even when not requested.
+ /// - \c NO_WILDCARD Do not try wildcard matching. This option is of no
+ /// use for normal lookups; it's intended to be used to get a DNSSEC
+ /// proof of the non existence of any matching wildcard or non existence
+ /// of an exact match when a wildcard match is found.
///
/// A derived version of this method may involve internal resource
/// allocation, especially for constructing the resulting RRset, and may
diff --git a/src/lib/python/isc/datasrc/datasrc.cc b/src/lib/python/isc/datasrc/datasrc.cc
index 7676104..6ab29d8 100644
--- a/src/lib/python/isc/datasrc/datasrc.cc
+++ b/src/lib/python/isc/datasrc/datasrc.cc
@@ -132,6 +132,8 @@ initModulePart_ZoneFinder(PyObject* mod) {
Py_BuildValue("I", ZoneFinder::WILDCARD));
installClassVariable(zonefinder_type, "WILDCARD_NXRRSET",
Py_BuildValue("I", ZoneFinder::WILDCARD_NXRRSET));
+ installClassVariable(zonefinder_type, "WILDCARD_CNAME",
+ Py_BuildValue("I", ZoneFinder::WILDCARD_CNAME));
installClassVariable(zonefinder_type, "FIND_DEFAULT",
Py_BuildValue("I", ZoneFinder::FIND_DEFAULT));
@@ -139,6 +141,8 @@ initModulePart_ZoneFinder(PyObject* mod) {
Py_BuildValue("I", ZoneFinder::FIND_GLUE_OK));
installClassVariable(zonefinder_type, "FIND_DNSSEC",
Py_BuildValue("I", ZoneFinder::FIND_DNSSEC));
+ installClassVariable(zonefinder_type, "NO_WILDCARD",
+ Py_BuildValue("I", ZoneFinder::NO_WILDCARD));
} catch (const std::exception& ex) {
const std::string ex_what =
"Unexpected failure in ZoneFinder initialization: " +
diff --git a/src/lib/python/isc/datasrc/finder_inc.cc b/src/lib/python/isc/datasrc/finder_inc.cc
index bc8e62c..4a00e78 100644
--- a/src/lib/python/isc/datasrc/finder_inc.cc
+++ b/src/lib/python/isc/datasrc/finder_inc.cc
@@ -42,11 +42,20 @@ Return the RR class of the zone.\n\
\n\
";
+// Main changes from the C++ doxygen version:
+// - Return type: use tuple instead of the dedicated FindResult type
+// - NULL->None
+// - exceptions
const char* const ZoneFinder_find_doc = "\
-find(name, type, target=NULL, options=FIND_DEFAULT) -> (code, FindResult)\n\
+find(name, type, target=None, options=FIND_DEFAULT) -> (integer, RRset)\n\
\n\
Search the zone for a given pair of domain name and RR type.\n\
\n\
+Each derived version of this method searches the underlying backend\n\
+for the data that best matches the given name and type. This method is\n\
+expected to be \"intelligent\", and identifies the best possible\n\
+answer for the search key. Specifically,\n\
+\n\
- If the search name belongs under a zone cut, it returns the code of\n\
DELEGATION and the NS RRset at the zone cut.\n\
- If there is no matching name, it returns the code of NXDOMAIN, and,\n\
@@ -62,40 +71,46 @@ Search the zone for a given pair of domain name and RR type.\n\
and the code of SUCCESS will be returned.\n\
- If the search name matches a delegation point of DNAME, it returns\n\
the code of DNAME and that DNAME RR.\n\
-- If the result was synthesized by a wildcard match, it returns the\n\
- code WILDCARD and the synthesized RRset\n\
-- If the query matched a wildcard name, but not its type, it returns the\n\
- code WILDCARD_NXRRSET, and None\n\
-- If the target is a list, all RRsets under the domain are inserted\n\
+- If the target isn't None, all RRsets under the domain are inserted\n\
there and SUCCESS (or NXDOMAIN, in case of empty domain) is returned\n\
instead of normall processing. This is intended to handle ANY query.\n\
- : this behavior is controversial as we discussed in\n\
- https://lists.isc.org/pipermail/bind10-dev/2011-January/001918.html\n\
- We should revisit the interface before we heavily rely on it. The\n\
- options parameter specifies customized behavior of the search. Their\n\
- semantics is as follows:\n\
- (This feature is disable at this time)\n\
-- GLUE_OK Allow search under a zone cut. By default the search will\n\
- stop once it encounters a zone cut. If this option is specified it\n\
- remembers information about the highest zone cut and continues the\n\
- search until it finds an exact match for the given name or it\n\
+\n\
+Note: This behavior is controversial as we discussed in\n\
+https://lists.isc.org/pipermail/bind10-dev/2011-January/001918.html We\n\
+should revisit the interface before we heavily rely on it.\n\
+\n\
+The options parameter specifies customized behavior of the search.\n\
+Their semantics is as follows (they are or bit-field):\n\
+\n\
+- FIND_GLUE_OK Allow search under a zone cut. By default the search\n\
+ will stop once it encounters a zone cut. If this option is specified\n\
+ it remembers information about the highest zone cut and continues\n\
+ the search until it finds an exact match for the given name or it\n\
detects there is no exact match. If an exact match is found, RRsets\n\
for that name are searched just like the normal case; otherwise, if\n\
the search has encountered a zone cut, DELEGATION with the\n\
information of the highest zone cut will be returned.\n\
+- FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are\n\
+ returned with the answer. It is allowed for the data source to\n\
+ include them even when not requested.\n\
+- NO_WILDCARD Do not try wildcard matching. This option is of no use\n\
+ for normal lookups; it's intended to be used to get a DNSSEC proof\n\
+ of the non existence of any matching wildcard or non existence of an\n\
+ exact match when a wildcard match is found.\n\
+\n\
\n\
-This method raises an isc.datasrc.Error exception if there is an internal\n\
-error in the datasource.\n\
+This method raises an isc.datasrc.Error exception if there is an\n\
+internal error in the datasource.\n\
\n\
Parameters:\n\
name The domain name to be searched for.\n\
type The RR type to be searched for.\n\
- target If target is not NULL, insert all RRs under the domain\n\
+ target If target is not None, insert all RRs under the domain\n\
into it.\n\
options The search options.\n\
\n\
-Return Value(s): A tuple of a result code an a FindResult object enclosing\n\
-the search result (see above).\n\
+Return Value(s): A tuple of a result code (integer) and an RRset object\n\
+enclosing the search result (see above).\n\
";
const char* const ZoneFinder_find_previous_name_doc = "\
diff --git a/src/lib/python/isc/datasrc/tests/datasrc_test.py b/src/lib/python/isc/datasrc/tests/datasrc_test.py
index 75a0cfb..15fa347 100644
--- a/src/lib/python/isc/datasrc/tests/datasrc_test.py
+++ b/src/lib/python/isc/datasrc/tests/datasrc_test.py
@@ -15,6 +15,7 @@
import isc.log
import isc.datasrc
+from isc.datasrc import ZoneFinder
import isc.dns
import unittest
import os
@@ -191,6 +192,29 @@ class DataSrcClient(unittest.TestCase):
# can't construct directly
self.assertRaises(TypeError, isc.datasrc.ZoneFinder)
+ def test_findoptions(self):
+ '''A simple test to confirm no option is specified by default.
+
+ '''
+ self.assertFalse(ZoneFinder.FIND_DEFAULT & ZoneFinder.FIND_GLUE_OK)
+ self.assertFalse(ZoneFinder.FIND_DEFAULT & ZoneFinder.FIND_DNSSEC)
+ self.assertFalse(ZoneFinder.FIND_DEFAULT & ZoneFinder.NO_WILDCARD)
+
+ def test_findresults(self):
+ '''A simple test to confirm result codes are (defined and) different
+ for some combinations.
+
+ '''
+ self.assertNotEqual(ZoneFinder.SUCCESS, ZoneFinder.DELEGATION)
+ self.assertNotEqual(ZoneFinder.DELEGATION, ZoneFinder.NXDOMAIN)
+ self.assertNotEqual(ZoneFinder.NXDOMAIN, ZoneFinder.NXRRSET)
+ self.assertNotEqual(ZoneFinder.NXRRSET, ZoneFinder.CNAME)
+ self.assertNotEqual(ZoneFinder.CNAME, ZoneFinder.DNAME)
+ self.assertNotEqual(ZoneFinder.DNAME, ZoneFinder.WILDCARD)
+ self.assertNotEqual(ZoneFinder.WILDCARD, ZoneFinder.WILDCARD_CNAME)
+ self.assertNotEqual(ZoneFinder.WILDCARD_CNAME,
+ ZoneFinder.WILDCARD_NXRRSET)
+
def test_find(self):
dsc = isc.datasrc.DataSourceClient("sqlite3", READ_ZONE_DB_CONFIG)
More information about the bind10-changes
mailing list