Browse Source

[1573] add DS record to authority

When DNSSEC is requested, and the DS exists
Jelte Jansen 13 years ago
parent
commit
177c449a61
3 changed files with 74 additions and 4 deletions
  1. 15 0
      src/bin/auth/query.cc
  2. 11 0
      src/bin/auth/query.h
  3. 48 4
      src/bin/auth/tests/query_unittest.cc

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

@@ -244,6 +244,16 @@ Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
                            dnssec_);
     }
 }
+
+void
+Query::addDS(ZoneFinder &zone, const Name& dname) {
+    ZoneFinder::FindResult ds_result =
+        zone.find(dname, RRType::DS(), dnssec_opt_);
+    if (ds_result.code == ZoneFinder::SUCCESS) {
+        response_.addRRset(Message::SECTION_AUTHORITY,
+                boost::const_pointer_cast<RRset>(ds_result.rrset), dnssec_);
+    }
+}
     
 void
 Query::addAuthAdditional(ZoneFinder& finder) {
@@ -399,6 +409,11 @@ Query::process() {
             response_.addRRset(Message::SECTION_AUTHORITY,
                 boost::const_pointer_cast<RRset>(db_result.rrset),
                 dnssec_);
+            // If DNSSEC is requested, see whether there is a DS
+            // record for this delegation.
+            if (dnssec_) {
+                addDS(*result.zone_finder, db_result.rrset->getName());
+            }
             addAdditional(*result.zone_finder, *db_result.rrset);
             break;
         case ZoneFinder::NXDOMAIN:

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

@@ -71,6 +71,17 @@ private:
     ///
     void addSOA(isc::datasrc::ZoneFinder& finder);
 
+    /// \brief Adds the DS rrset for the given name, if available
+    ///
+    /// This is intended to be called when returning a delegation, and
+    /// if DNSSEC data is requested. If the DS record is not found, nothing
+    /// happens.
+    ///
+    /// \param zone The ZoneFinder The zonefinder where the delegation was
+    ///               found
+    /// \param ds_name The name of the delegation RRset
+    void addDS(isc::datasrc::ZoneFinder& zone, const isc::dns::Name& ds_name);
+
     /// Add NSEC RRs that prove an NXDOMAIN result.
     ///
     /// This corresponds to Section 3.1.3.2 of RFC 4035.

+ 48 - 4
src/bin/auth/tests/query_unittest.cc

@@ -66,6 +66,9 @@ const char* const delegation_txt =
     "delegation.example.com. 3600 IN NS noglue.example.com.\n"
     "delegation.example.com. 3600 IN NS cname.example.com.\n"
     "delegation.example.com. 3600 IN NS example.org.\n";
+const char* const delegation_ds_txt =
+    "delegation.example.com. 3600 IN DS 12345 8 2 "
+    "764501411DE58E8618945054A3F620B36202E115D015A7773F4B78E0F952CECA\n";
 const char* const mx_txt =
     "mx.example.com. 3600 IN MX 10 www.example.com.\n"
     "mx.example.com. 3600 IN MX 20 mailer.example.org.\n"
@@ -200,9 +203,9 @@ public:
     {
         stringstream zone_stream;
         zone_stream << soa_txt << zone_ns_txt << ns_addrs_txt <<
-            delegation_txt << mx_txt << www_a_txt << cname_txt <<
-            cname_nxdom_txt << cname_out_txt << dname_txt << dname_a_txt <<
-            other_zone_rrs << no_txt << nz_txt <<
+            delegation_txt << delegation_ds_txt << mx_txt << www_a_txt <<
+            cname_txt << cname_nxdom_txt << cname_out_txt << dname_txt <<
+            dname_a_txt << other_zone_rrs << no_txt << nz_txt <<
             nsec_apex_txt << nsec_mx_txt << nsec_no_txt << nsec_nz_txt <<
             nsec_nxdomain_txt << nsec_www_txt << nonsec_a_txt <<
             wild_txt << nsec_wild_txt << cnamewild_txt << nsec_cnamewild_txt <<
@@ -277,6 +280,7 @@ public:
 public:
     // We allow the tests to use these for convenience
     ConstRRsetPtr delegation_rrset_;
+    ConstRRsetPtr delegation_ds_rrset_;
     ConstRRsetPtr empty_nsec_rrset_;
 
 private:
@@ -300,6 +304,13 @@ private:
         if (rrset->getName() == delegation_name_ &&
             rrset->getType() == RRType::NS()) {
             delegation_rrset_ = rrset;
+        } else if (rrset->getName() == delegation_name_ &&
+            rrset->getType() == RRType::DS()) {
+            delegation_ds_rrset_ = rrset;
+            // Like NSEC(3), by nature it should have an RRSIG.
+            rrset->addRRsig(RdataPtr(new generic::RRSIG(
+                                         getCommonRRSIGText(rrset->getType().
+                                                            toText()))));
         } else if (rrset->getName() == dname_name_ &&
             rrset->getType() == RRType::DNAME()) {
             dname_rrset_ = rrset;
@@ -437,7 +448,11 @@ MockZoneFinder::find(const Name& name, const RRType& type,
         (name == delegation_name_ ||
          name.compare(delegation_name_).getRelation() ==
          NameComparisonResult::SUBDOMAIN)) {
-        return (FindResult(DELEGATION, delegation_rrset_));
+        if (type != RRType::DS()) {
+            return (FindResult(DELEGATION, delegation_rrset_));
+        } else {
+            return (FindResult(SUCCESS, delegation_ds_rrset_));
+        }
     // And under DNAME
     } else if (name.compare(dname_name_).getRelation() ==
         NameComparisonResult::SUBDOMAIN) {
@@ -864,6 +879,35 @@ TEST_F(QueryTest, delegation) {
                   NULL, delegation_txt, ns_addrs_txt);
 }
 
+TEST_F(QueryTest, secureDelegation) {
+    // find match rrset, omit additional data which has already been provided
+    // in the answer section from the additional.
+    EXPECT_NO_THROW(Query(memory_client, Name("foo.delegation.example.com"),
+                          qtype, response, true).process());
+
+    // Should now contain RRSIG and DS record as well.
+    responseCheck(response, Rcode::NOERROR(), 0, 0, 6, 6,
+                  NULL,
+                  (string(delegation_txt) +
+                   string(delegation_ds_txt) +
+                   string("delegation.example.com. 3600 IN RRSIG ") +
+                   getCommonRRSIGText("DS")).c_str(),
+                  // No easy way to get these strings, so entered them
+                  // manually
+                  "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
+                  "glue.delegation.example.com. 3600 IN RRSIG A 5 3 3600 "
+                    "20000101000000 20000201000000 12345 example.com. "
+                    "FAKEFAKEFAKE\n"
+                  "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n"
+                  "glue.delegation.example.com. 3600 IN RRSIG AAAA 5 3 3600 "
+                    "20000101000000 20000201000000 12345 example.com. "
+                    "FAKEFAKEFAKE\n"
+                  "noglue.example.com. 3600 IN A 192.0.2.53\n"
+                  "noglue.example.com. 3600 IN RRSIG A 5 3 3600 20000101000000 "
+                  "20000201000000 12345 example.com. FAKEFAKEFAKE\n");
+}
+
+
 TEST_F(QueryTest, nxdomain) {
     EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
                           response).process());