Browse Source

[1431] introduced FindResultFlags so that we can separate find result codes
themselves and special attributes. for now, provided a quick-hack wrapper
for auth::Query so we don't have to all data source implementations at once.

JINMEI Tatuya 13 years ago
parent
commit
2528257c4f
2 changed files with 123 additions and 41 deletions
  1. 53 33
      src/bin/auth/query.cc
  2. 70 8
      src/lib/datasrc/zone.h

+ 53 - 33
src/bin/auth/query.cc

@@ -30,6 +30,30 @@ using namespace isc::dns;
 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 {
 
@@ -69,8 +93,8 @@ Query::addAdditionalAddrs(ZoneFinder& zone, const Name& qname,
 
     // 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_);
@@ -80,7 +104,8 @@ Query::addAdditionalAddrs(ZoneFinder& zone, const Name& qname,
     // 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),
@@ -91,8 +116,9 @@ Query::addAdditionalAddrs(ZoneFinder& zone, const Name& qname,
 
 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());
@@ -147,9 +173,8 @@ Query::addNXDOMAINProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
     // 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");
@@ -173,8 +198,8 @@ 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.
     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");
@@ -191,13 +216,10 @@ Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
     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");
@@ -214,8 +236,9 @@ Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
 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 " <<
@@ -260,7 +283,7 @@ Query::process() {
         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
@@ -306,7 +329,6 @@ Query::process() {
             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
@@ -322,12 +344,11 @@ Query::process() {
 
             // 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.
@@ -357,7 +378,7 @@ Query::process() {
 
             // 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;
@@ -377,17 +398,16 @@ Query::process() {
             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:

+ 70 - 8
src/lib/datasrc/zone.h

@@ -142,19 +142,41 @@ public:
         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
@@ -165,11 +187,39 @@ public:
     /// 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.
@@ -375,7 +425,7 @@ public:
     ///
     /// 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.
     ///
@@ -451,6 +501,18 @@ inline ZoneFinder::FindOptions operator |(ZoneFinder::FindOptions a,
                                                  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;