using namespace isc::datasrc;
using namespace isc::dns::rdata;
+namespace {
+// This is a temporary wrapper to convert old format of FindResult to new
+// one, until we update all supported data source implementations.
+ZoneFinder::FindResult
+findWrapper(const ZoneFinder::FindResult& orig_result) {
+ ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
+ ZoneFinder::Result code = orig_result.code;
+ if (code == ZoneFinder::WILDCARD) {
+ code = ZoneFinder::SUCCESS;
+ flags = flags | ZoneFinder::RESULT_WILDCARD;
+ } else if (code == ZoneFinder::WILDCARD_CNAME) {
+ code = ZoneFinder::CNAME;
+ flags = flags | ZoneFinder::RESULT_WILDCARD;
+ } else if (code == ZoneFinder::WILDCARD_NXRRSET) {
+ code = ZoneFinder::NXRRSET;
+ flags = flags | ZoneFinder::RESULT_WILDCARD;
+ }
+ if (orig_result.rrset && orig_result.rrset->getType() == RRType::NSEC()) {
+ flags = flags | ZoneFinder::RESULT_NSEC_SIGNED;
+ }
+ return (ZoneFinder::FindResult(code, orig_result.rrset, flags));
+}
+}
+
namespace isc {
namespace auth {
// Find A rrset
if (qname_ != qname || qtype_ != RRType::A()) {
- ZoneFinder::FindResult a_result = zone.find(qname, RRType::A(),
- options | dnssec_opt_);
+ ZoneFinder::FindResult a_result =
+ findWrapper(zone.find(qname, RRType::A(), options | dnssec_opt_));
if (a_result.code == ZoneFinder::SUCCESS) {
response_.addRRset(Message::SECTION_ADDITIONAL,
boost::const_pointer_cast<RRset>(a_result.rrset), dnssec_);
// Find AAAA rrset
if (qname_ != qname || qtype_ != RRType::AAAA()) {
ZoneFinder::FindResult aaaa_result =
- zone.find(qname, RRType::AAAA(), options | dnssec_opt_);
+ findWrapper(zone.find(qname, RRType::AAAA(),
+ options | dnssec_opt_));
if (aaaa_result.code == ZoneFinder::SUCCESS) {
response_.addRRset(Message::SECTION_ADDITIONAL,
boost::const_pointer_cast<RRset>(aaaa_result.rrset),
void
Query::addSOA(ZoneFinder& finder) {
- ZoneFinder::FindResult soa_result(finder.find(finder.getOrigin(),
- RRType::SOA(), dnssec_opt_));
+ ZoneFinder::FindResult soa_result =
+ findWrapper(finder.find(finder.getOrigin(),
+ RRType::SOA(), dnssec_opt_));
if (soa_result.code != ZoneFinder::SUCCESS) {
isc_throw(NoSOA, "There's no SOA record in zone " <<
finder.getOrigin().toText());
// Confirm the wildcard doesn't exist (this should result in NXDOMAIN;
// otherwise we shouldn't have got NXDOMAIN for the original query in
// the first place).
- const ZoneFinder::FindResult fresult = finder.find(wildname,
- RRType::NSEC(),
- dnssec_opt_);
+ const ZoneFinder::FindResult fresult =
+ findWrapper(finder.find(wildname, RRType::NSEC(), dnssec_opt_));
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
isc_throw(BadNSEC, "Unexpected result for wildcard NXDOMAIN proof");
// substitution. Confirm that by specifying NO_WILDCARD. It should result
// in NXDOMAIN and an NSEC RR that proves it should be returned.
const ZoneFinder::FindResult fresult =
- finder.find(qname_, RRType::NSEC(),
- dnssec_opt_ | ZoneFinder::NO_WILDCARD);
+ findWrapper(finder.find(qname_, RRType::NSEC(),
+ dnssec_opt_ | ZoneFinder::NO_WILDCARD));
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
isc_throw(BadNSEC, "Unexpected result for wildcard proof");
if (nsec->getRdataCount() == 0) {
isc_throw(BadNSEC, "NSEC for WILDCARD_NXRRSET is empty");
}
- // Add this NSEC RR to authority section.
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<RRset>(nsec), dnssec_);
const ZoneFinder::FindResult fresult =
- finder.find(qname_, RRType::NSEC(),
- dnssec_opt_ | ZoneFinder::NO_WILDCARD);
+ findWrapper(finder.find(qname_, RRType::NSEC(),
+ dnssec_opt_ | ZoneFinder::NO_WILDCARD));
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
isc_throw(BadNSEC, "Unexpected result for no match QNAME proof");
void
Query::addAuthAdditional(ZoneFinder& finder) {
// Fill in authority and addtional sections.
- ZoneFinder::FindResult ns_result = finder.find(finder.getOrigin(),
- RRType::NS(), dnssec_opt_);
+ ZoneFinder::FindResult ns_result =
+ findWrapper(finder.find(finder.getOrigin(), RRType::NS(),
+ dnssec_opt_));
// zone origin name should have NS records
if (ns_result.code != ZoneFinder::SUCCESS) {
isc_throw(NoApexNS, "There's no apex NS records in zone " <<
find = boost::bind(&ZoneFinder::find, &zfinder, qname_, qtype_,
dnssec_opt_);
}
- ZoneFinder::FindResult db_result(find());
+ ZoneFinder::FindResult db_result(findWrapper(find()));
switch (db_result.code) {
case ZoneFinder::DNAME: {
// First, put the dname into the answer
break;
}
case ZoneFinder::CNAME:
- case ZoneFinder::WILDCARD_CNAME:
/*
* We don't do chaining yet. Therefore handling a CNAME is
* mostly the same as handling SUCCESS, but we didn't get
// If the answer is a result of wildcard substitution,
// add a proof that there's no closer name.
- if (dnssec_ && db_result.code == ZoneFinder::WILDCARD_CNAME) {
+ if (dnssec_ && db_result.isWildcard()) {
addWildcardProof(*result.zone_finder);
}
break;
case ZoneFinder::SUCCESS:
- case ZoneFinder::WILDCARD:
if (qtype_is_any) {
// If quety type is ANY, insert all RRs under the domain
// into answer section.
// If the answer is a result of wildcard substitution,
// add a proof that there's no closer name.
- if (dnssec_ && db_result.code == ZoneFinder::WILDCARD) {
+ if (dnssec_ && db_result.isWildcard()) {
addWildcardProof(*result.zone_finder);
}
break;
break;
case ZoneFinder::NXRRSET:
addSOA(*result.zone_finder);
- if (dnssec_ && db_result.rrset) {
- response_.addRRset(Message::SECTION_AUTHORITY,
- boost::const_pointer_cast<RRset>(
- db_result.rrset),
- dnssec_);
- }
- break;
- case ZoneFinder::WILDCARD_NXRRSET:
- addSOA(*result.zone_finder);
- if (dnssec_ && db_result.rrset) {
- addWildcardNXRRSETProof(zfinder, db_result.rrset);
+ if (dnssec_) {
+ if (db_result.isNSECSigned()) {
+ response_.addRRset(Message::SECTION_AUTHORITY,
+ boost::const_pointer_cast<RRset>(
+ db_result.rrset),
+ dnssec_);
+ if (db_result.isWildcard()) {
+ addWildcardNXRRSETProof(zfinder, db_result.rrset);
+ }
+ }
}
break;
default:
WILDCARD_NXRRSET ///< NXRRSET on wildcard, for DNSSEC
};
+ /// Special attribute flags on the result of the \c find() method
+ ///
+ /// The flag values defined here are intended to signal to the caller
+ /// that it may need special handling on the result. This is particularly
+ /// of concern when DNSSEC is requested. For example, for negative
+ /// responses the caller would want to know whether the zone is signed
+ /// with NSEC or NSEC3 so that it can subsequently provide necessary
+ /// proof of the result.
+ ///
+ /// The caller is generally expected to get access to the information
+ /// via read-only getter methods of \c FindResult so that it won't rely
+ /// on specific details of the representation of the flags. So these
+ /// definitions are basically only meaningful for data source
+ /// implementations.
+ enum FindResultFlags {
+ RESULT_DEFAULT = 0, ///< The default flags
+ RESULT_WILDCARD = 1, ///< find() resulted in a wildcard match
+ RESULT_NSEC_SIGNED = 2, ///< The zone is signed with NSEC RRs
+ RESULT_NSEC3_SIGNED = 4 ///< The zone is signed with NSEC3 RRs
+ };
+
/// A helper structure to represent the search result of \c find().
///
/// This is a straightforward tuple of the result code and a pointer
- /// to the found RRset to represent the result of \c find()
- /// (there will be more members in the future - see the class
- /// description).
+ /// (and optionally special flags) to the found RRset to represent the
+ /// result of \c find() (there will be more members in the future -
+ /// see the class description).
/// We use this in order to avoid overloading the return value for both
/// the result code ("success" or "not found") and the found object,
/// i.e., avoid using \c NULL to mean "not found", etc.
///
/// This is a simple value class whose internal state never changes,
- /// so for convenience we allow the applications to refer to the members
- /// directly.
+ /// so for convenience we allow the applications to refer to some of the
+ /// members directly. For others we provide read-only accessor methods
+ /// to hide specific representation.
///
/// Note: we should eventually include a notion of "zone node", which
/// corresponds to a particular domain name of the zone, so that we can
/// optimize including the NSEC for no-wildcard proof (FWIW NSD does that).
struct FindResult {
FindResult(Result param_code,
- const isc::dns::ConstRRsetPtr param_rrset) :
- code(param_code), rrset(param_rrset)
+ const isc::dns::ConstRRsetPtr param_rrset,
+ FindResultFlags param_flags = RESULT_DEFAULT) :
+ code(param_code), rrset(param_rrset), flags(param_flags)
{}
const Result code;
const isc::dns::ConstRRsetPtr rrset;
+
+ /// Return true iff find() results in a wildcard match.
+ bool isWildcard() const { return ((flags & RESULT_WILDCARD) != 0); }
+
+ /// Return true when the underlying zone is signed with NSEC.
+ ///
+ /// The \c find() implementation allow this to return false if
+ /// \c FIND_DNSSEC isn't specified regardless of whether the zone
+ /// is signed or which of NSEC/NSEC3 is used.
+ ///
+ /// When this is returned, the implementation of find() must ensure
+ /// that \c rrset be a valid NSEC RRset as described in \c find()
+ /// documentation.
+ bool isNSECSigned() const {
+ return ((flags & RESULT_NSEC_SIGNED) != 0);
+ }
+
+ /// Return true when the underlying zone is signed with NSEC3.
+ ///
+ /// The \c find() implementation allow this to return false if
+ /// \c FIND_DNSSEC isn't specified regardless of whether the zone
+ /// is signed or which of NSEC/NSEC3 is used.
+ bool isNSEC3Signed() const {
+ return ((flags & RESULT_NSEC3_SIGNED) != 0);
+ }
+ private:
+ FindResultFlags flags;
};
/// Find options.
///
/// When looking for NSEC3, this method retrieves NSEC3 parameters from
/// the corresponding zone to calculate hash values. Actual implementation
- /// of how to do this will defer in different data sources. If the
+ /// of how to do this will differ in different data sources. If the
/// NSEC3 parameters are not available \c DataSourceError exception
/// will be thrown.
///
static_cast<unsigned>(b)));
}
+/// \brief Operator to combine FindResultFlags
+///
+/// Similar to the same operator for \c FindOptions. Refer to the description
+/// of that function.
+inline ZoneFinder::FindResultFlags operator |(
+ ZoneFinder::FindResultFlags a,
+ ZoneFinder::FindResultFlags b)
+{
+ return (static_cast<ZoneFinder::FindResultFlags>(
+ static_cast<unsigned>(a) | static_cast<unsigned>(b)));
+}
+
/// \brief A pointer-like type pointing to a \c ZoneFinder object.
typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;