Browse Source

[1570] supported the case of DS query at child. dsBelowDelegation now passed.
added a couple of more related tests.

JINMEI Tatuya 13 years ago
parent
commit
0d1406f71c
3 changed files with 79 additions and 9 deletions
  1. 35 0
      src/bin/auth/query.cc
  2. 3 0
      src/bin/auth/query.h
  3. 41 9
      src/bin/auth/tests/query_unittest.cc

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

@@ -283,6 +283,9 @@ Query::process() {
     // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
     if (result.code != result::SUCCESS &&
         result.code != result::PARTIALMATCH) {
+        if (qtype_ == RRType::DS() && processDSAtChild()) {
+            return;
+        }
         response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
         response_.setRcode(Rcode::REFUSED());
         return;
@@ -436,5 +439,37 @@ Query::process() {
     }
 }
 
+bool
+Query::processDSAtChild() {
+    const DataSourceClient::FindResult zresult =
+        datasrc_client_.findZone(qname_);
+
+    if (zresult.code != result::SUCCESS) {
+        return (false);
+    }
+
+    // We are receiving a DS query at the child side of the owner name,
+    // where the DS isn't supposed to belong.  We should return a "no data"
+    // response as described in Section 3.1.4.1 of RFC4035 and Section
+    // 2.2.1.1 of RFC 3658.  find(DS) should result in NXRRSET, in which
+    // case (and if DNSSEC is required) we also add the proof for that,
+    // but even if find() returns an unexpected result, we don't bother.
+    // 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());
+    addSOA(*zresult.zone_finder);
+    const ZoneFinder::FindResult ds_result =
+        zresult.zone_finder->find(qname_, RRType::DS(), dnssec_opt_);
+    if (ds_result.code == ZoneFinder::NXRRSET) {
+        if (dnssec_) {
+            addNXRRsetProof(*zresult.zone_finder, ds_result);
+        }
+    }
+
+    return (true);
+}
+
 }
 }

+ 3 - 0
src/bin/auth/query.h

@@ -178,6 +178,9 @@ private:
     /// data for the query are to be found.
     void addAuthAdditional(isc::datasrc::ZoneFinder& finder);
 
+    /// TBD
+    bool processDSAtChild();
+
 public:
     /// Constructor from query parameters.
     ///

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

@@ -57,7 +57,6 @@ const char* const zone_ns_txt =
     "example.com. 3600 IN NS glue.delegation.example.com.\n"
     "example.com. 3600 IN NS noglue.example.com.\n"
     "example.com. 3600 IN NS example.net.\n";
-// TBD: CHECK IF IT IS REALLY USED
 const char* const zone_ds_txt =
     "example.com. 3600 IN DS 57855 5 1 "
         "B6DCD485719ADCA18E5F3D48A2331627FDD3 636B\n";
@@ -302,10 +301,20 @@ public:
     // answers when DNSSEC is required.
     void setNSEC3Flag(bool on) { use_nsec3_ = on; }
 
-    Name findPreviousName(const Name&) const {
+    virtual Name findPreviousName(const Name&) const {
         isc_throw(isc::NotImplemented, "Mock doesn't support previous name");
     }
 
+    // This method allows tests to insert new record in the middle of the test.
+    //
+    // \param record_txt textual RR representation of RR (such as soa_txt, etc)
+    void addRecord(const string& record_txt) {
+        stringstream record_stream;
+        record_stream << record_txt;
+        masterLoad(record_stream, origin_, rrclass_,
+                   boost::bind(&MockZoneFinder::loadRRset, this, _1));
+    }
+
 public:
     // We allow the tests to use these for convenience
     ConstRRsetPtr dname_rrset_; // could be used as an arbitrary bogus RRset
@@ -1662,21 +1671,44 @@ TEST_F(QueryTest, dsAboveDelegation) {
                    getCommonRRSIGText("A")).c_str());
 }
 
-// This one checks a DS record at the apex is not returned even if it exists,
-// as it is authoritative above the delegation and does not exist below it,
+// This one checks a DS record at the apex is not returned, as it is
+// authoritative above the delegation and does not exist below it,
 // 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, DISABLED_dsBelowDelegation) {
+TEST_F(QueryTest, dsBelowDelegation) {
     EXPECT_NO_THROW(Query(memory_client, Name("example.com"),
                           RRType::DS(), response, true).process());
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
-                   string(nsec_www_txt) + "\n" +
-                   string("www.example.com. 3600 IN RRSIG ") +
-                   getCommonRRSIGText("NSEC")).c_str(),
-                  NULL, mock_finder->getOrigin());
+                   string(nsec_apex_txt) + "\n" +
+                   string("example.com. 3600 IN RRSIG ") +
+                   getCommonRRSIGText("NSEC")).c_str(), NULL,
+                  mock_finder->getOrigin());
+}
+
+// Similar to the previous case, but even more pathological: the DS somehow
+// exists in the child zone.  The Query module should still return SOA.
+// 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());
+
+    responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
+                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                   getCommonRRSIGText("SOA")).c_str(), NULL,
+                  mock_finder->getOrigin());
+}
+
+// DS query received at a completely irrelevant (neither parent nor child)
+// 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();
+    responseCheck(response, Rcode::REFUSED(), 0, 0, 0, 0, NULL, NULL, NULL);
 }
 
 // The following are tentative tests until we really add tests for the