Browse Source

[1570] added another grandparent case: the server is auth of the child, too.

JINMEI Tatuya 13 years ago
parent
commit
3007ba9ef2
2 changed files with 74 additions and 9 deletions
  1. 8 0
      src/bin/auth/query.cc
  2. 66 9
      src/bin/auth/tests/query_unittest.cc

+ 8 - 0
src/bin/auth/query.cc

@@ -406,6 +406,14 @@ Query::process() {
             }
             break;
         case ZoneFinder::DELEGATION:
+            // If a DS query resulted in delegation, we also need to check
+            // 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()) {
+                return;
+            }
+
             response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
             response_.addRRset(Message::SECTION_AUTHORITY,
                 boost::const_pointer_cast<RRset>(db_result.rrset),

+ 66 - 9
src/bin/auth/tests/query_unittest.cc

@@ -202,6 +202,27 @@ getCommonRRSIGText(const string& type) {
                    "example.com. FAKEFAKEFAKE"));
 }
 
+// A helper callback of masterLoad() used in InMemoryZoneFinderTest.
+void
+setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
+    *(*it) = rrset;
+    ++it;
+}
+
+// A helper function that converts a textual form of a single RR into a
+// RRsetPtr object.  If it's SOA, origin must be set to its owner name;
+// otherwise masterLoad() will reject it.
+RRsetPtr
+textToRRset(const string& text_rrset, const Name& origin = Name::ROOT_NAME()) {
+    stringstream ss(text_rrset);
+    RRsetPtr rrset;
+    vector<RRsetPtr*> rrsets;
+    rrsets.push_back(&rrset);
+    masterLoad(ss, origin, RRClass::IN(),
+               boost::bind(setRRset, _1, rrsets.begin()));
+    return (rrset);
+}
+
 // This is a mock Zone Finder class for testing.
 // It is a derived class of ZoneFinder for the convenient of tests.
 // Its find() method emulates the common behavior of protocol compliant
@@ -1613,20 +1634,40 @@ TEST_F(QueryTest, findNSEC3) {
 // an authoritative answer, not a delegation. This is as described in
 // RFC 4035, section 3.1.4.1.
 
-// This mock finder is used for some DS-query test(s) to check if the lookup
-// takes place at the parent zone, not at this (broken) zone.
-class BrokenChildZoneFinder : public MockZoneFinder {
+// This mock finder is used for some DS-query tests to emulate the situation
+// where the server has authority for the child side of DS.  Only limited
+// methods are expected to called on this class object in these tests, which
+// are overridden below.
+class ChildZoneFinder : public MockZoneFinder {
 public:
-    BrokenChildZoneFinder(const Name& origin) :
+    ChildZoneFinder(const Name& origin) :
         MockZoneFinder(), origin_(origin)
     {}
     virtual isc::dns::Name getOrigin() const { return (origin_); }
-    virtual FindResult find(const isc::dns::Name&,
-                            const isc::dns::RRType&,
+    virtual FindResult find(const isc::dns::Name& name,
+                            const isc::dns::RRType& type,
                             const FindOptions)
     {
-        isc_throw(isc::Unexpected,
-                  "BrokenChildZoneFinder::find shouldn't be called");
+        if (name != origin_) {
+            isc_throw(isc::Unexpected, "Non origin name is asked for "
+                      "ChildZoneFinder: " << name);
+        }
+        if (type == RRType::SOA()) {
+            RRsetPtr soa = textToRRset(origin_.toText() + " 3600 IN SOA . . "
+                                       "0 0 0 0 0\n", origin_);
+            soa->addRRsig(RdataPtr(new generic::RRSIG(
+                                       getCommonRRSIGText("SOA"))));
+            return (FindResult(SUCCESS, soa));
+        }
+        if (type == RRType::DS()) {
+            RRsetPtr nsec = textToRRset(origin_.toText() + " 3600 IN NSEC " +
+                                        origin_.toText() + " SOA NSEC RRSIG");
+            nsec->addRRsig(RdataPtr(new generic::RRSIG(
+                                        getCommonRRSIGText("NSEC"))));
+            return (FindResult(NXRRSET, nsec, RESULT_NSEC_SIGNED));
+        }
+        isc_throw(isc::Unexpected, "Unexpected RR type is asked for "
+                  "ChildZoneFinder: " << type);
     }
 private:
     const Name origin_;
@@ -1634,7 +1675,7 @@ private:
 
 TEST_F(QueryTest, dsAboveDelegation) {
     // Pretending to have authority for the child zone, too.
-    memory_client.addZone(ZoneFinderPtr(new BrokenChildZoneFinder(
+    memory_client.addZone(ZoneFinderPtr(new ChildZoneFinder(
                                             Name("delegation.example.com"))));
 
     // The following will succeed only if the search goes to the parent
@@ -1704,6 +1745,22 @@ TEST_F(QueryTest, dsAtGrandParent) {
                   ns_addrs_and_sig_txt.c_str());
 }
 
+TEST_F(QueryTest, dsAtGrandParentAndChild) {
+    // Pretending to have authority for the grandchild zone, too.
+    const Name childname("grand.delegation.example.com");
+    memory_client.addZone(ZoneFinderPtr(
+                              new ChildZoneFinder(childname)));
+    Query(memory_client, childname, RRType::DS(), response, true).process();
+    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 " +
+                   getCommonRRSIGText("SOA") + "\n" +
+                   childname.toText() + " 3600 IN NSEC " +
+                   childname.toText() + " SOA NSEC RRSIG\n" +
+                   childname.toText() + " 3600 IN RRSIG " +
+                   getCommonRRSIGText("NSEC")).c_str(), NULL, childname);
+}
+
 // The following are tentative tests until we really add tests for the
 // query logic for these cases.  At that point it's probably better to
 // clean them up.