Browse Source

Merge branch 'master' of ssh://jreed@bind10.isc.org//var/bind10/git/bind10

Jeremy C. Reed 14 years ago
parent
commit
aeb98ed824
2 changed files with 131 additions and 11 deletions
  1. 14 0
      src/bin/auth/query.cc
  2. 117 11
      src/bin/auth/tests/query_unittest.cc

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

@@ -12,6 +12,9 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <vector>
+#include <boost/foreach.hpp>
+
 #include <dns/message.h>
 #include <dns/message.h>
 #include <dns/rcode.h>
 #include <dns/rcode.h>
 #include <dns/rdataclass.h>
 #include <dns/rdataclass.h>
@@ -37,6 +40,15 @@ Query::getAdditional(const Zone& zone, const RRset& rrset) const {
              const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
              const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
              findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
              findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
         }
         }
+    } else if (rrset.getType() == RRType::MX()) {
+        RdataIteratorPtr rdata_iterator = rrset.getRdataIterator();
+        for (RdataIteratorPtr rdata_iterator(rrset.getRdataIterator());
+            !rdata_iterator->isLast(); rdata_iterator->next())
+        {
+             const Rdata& rdata(rdata_iterator->getCurrent());
+             const generic::MX& mx(dynamic_cast<const generic::MX&>(rdata));
+             findAddrs(zone, mx.getMXName());
+        }
     }
     }
 }
 }
 
 
@@ -140,6 +152,7 @@ Query::process() const {
                 response_.addRRset(Message::SECTION_ANSWER,
                 response_.addRRset(Message::SECTION_ANSWER,
                     boost::const_pointer_cast<RRset>(db_result.rrset));
                     boost::const_pointer_cast<RRset>(db_result.rrset));
                 getAuthAdditional(*result.zone);
                 getAuthAdditional(*result.zone);
+                getAdditional(*result.zone, *db_result.rrset);
                 break;
                 break;
             case Zone::DELEGATION:
             case Zone::DELEGATION:
                 response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
                 response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
@@ -165,5 +178,6 @@ Query::process() const {
         }
         }
     }
     }
 }
 }
+
 }
 }
 }
 }

+ 117 - 11
src/bin/auth/tests/query_unittest.cc

@@ -49,13 +49,13 @@ RRsetPtr glue_aaaa_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
 RRsetPtr noglue_a_rrset(RRsetPtr(new RRset(Name("noglue.example.com"),
 RRsetPtr noglue_a_rrset(RRsetPtr(new RRset(Name("noglue.example.com"),
                                            RRClass::IN(), RRType::A(),
                                            RRClass::IN(), RRType::A(),
                                            RRTTL(3600))));
                                            RRTTL(3600))));
+RRsetPtr delegated_mx_a_rrset(RRsetPtr(new RRset(
+    Name("mx.delegation.example.com"), RRClass::IN(), RRType::A(),
+    RRTTL(3600))));
+
 // This is a mock Zone class for testing.
 // This is a mock Zone class for testing.
-// It is a derived class of Zone, and simply hardcode the results of find()
-// return SUCCESS for "www.example.com",
-// return NXDOMAIN for "nxdomain.example.com",
-// return NXRRSET for "nxrrset.example.com",
-// return CNAME for "cname.example.com",
-// otherwise return DNAME
+// It is a derived class of Zone, and simply hardcodes the results of find()
+// See the find() implementation if you want to know its content.
 class MockZone : public Zone {
 class MockZone : public Zone {
 public:
 public:
     MockZone(bool has_SOA = true, bool has_apex_NS = true) :
     MockZone(bool has_SOA = true, bool has_apex_NS = true) :
@@ -70,7 +70,11 @@ public:
                                        RRTTL(3600)))),
                                        RRTTL(3600)))),
         auth_ns_rrset(RRsetPtr(new RRset(Name("example.com"),
         auth_ns_rrset(RRsetPtr(new RRset(Name("example.com"),
                                          RRClass::IN(), RRType::NS(),
                                          RRClass::IN(), RRType::NS(),
-                                         RRTTL(3600))))
+                                         RRTTL(3600)))),
+        mx_cname_rrset_(new RRset(Name("cnamemailer.example.com"),
+            RRClass::IN(), RRType::CNAME(), RRTTL(3600))),
+        mx_rrset_(new RRset(Name("mx.example.com"), RRClass::IN(),
+            RRType::MX(), RRTTL(3600)))
     {
     {
         delegation_rrset->addRdata(rdata::generic::NS(
         delegation_rrset->addRdata(rdata::generic::NS(
                           Name("glue.ns.example.com")));
                           Name("glue.ns.example.com")));
@@ -88,6 +92,14 @@ public:
                           Name("noglue.example.com")));
                           Name("noglue.example.com")));
         auth_ns_rrset->addRdata(rdata::generic::NS(
         auth_ns_rrset->addRdata(rdata::generic::NS(
                           Name("example.net")));
                           Name("example.net")));
+        mx_rrset_->addRdata(isc::dns::rdata::generic::MX(10,
+            Name("www.example.com")));
+        mx_rrset_->addRdata(isc::dns::rdata::generic::MX(20,
+            Name("mailer.example.org")));
+        mx_rrset_->addRdata(isc::dns::rdata::generic::MX(30,
+            Name("mx.delegation.example.com")));
+        mx_cname_rrset_->addRdata(rdata::generic::CNAME(
+            Name("mx.example.com")));
     }
     }
     virtual const isc::dns::Name& getOrigin() const;
     virtual const isc::dns::Name& getOrigin() const;
     virtual const isc::dns::RRClass& getClass() const;
     virtual const isc::dns::RRClass& getClass() const;
@@ -103,6 +115,8 @@ private:
     RRsetPtr delegation_rrset;
     RRsetPtr delegation_rrset;
     RRsetPtr cname_rrset;
     RRsetPtr cname_rrset;
     RRsetPtr auth_ns_rrset;
     RRsetPtr auth_ns_rrset;
+    RRsetPtr mx_cname_rrset_;
+    RRsetPtr mx_rrset_;
 };
 };
 
 
 const Name&
 const Name&
@@ -120,16 +134,18 @@ MockZone::find(const Name& name, const RRType& type,
                const FindOptions options) const
                const FindOptions options) const
 {
 {
     // hardcode the find results
     // hardcode the find results
-    if (name == Name("www.example.com")) {
+    if (name == Name("www.example.com") && type == RRType::A()) {
         return (FindResult(SUCCESS, a_rrset));
         return (FindResult(SUCCESS, a_rrset));
+    } else if (name == Name("www.example.com")) {
+        return (FindResult(NXRRSET, RRsetPtr()));
     } else if (name == Name("glue.ns.example.com") && type == RRType::A() &&
     } else if (name == Name("glue.ns.example.com") && type == RRType::A() &&
-        options == FIND_GLUE_OK) {
+        (options & FIND_GLUE_OK) != 0) {
         return (FindResult(SUCCESS, glue_a_rrset));
         return (FindResult(SUCCESS, glue_a_rrset));
     } else if (name == Name("noglue.example.com") && (type == RRType::A() ||
     } else if (name == Name("noglue.example.com") && (type == RRType::A() ||
         type == RRType::ANY())) {
         type == RRType::ANY())) {
         return (FindResult(SUCCESS, noglue_a_rrset));
         return (FindResult(SUCCESS, noglue_a_rrset));
     } else if (name == Name("glue.ns.example.com") && type == RRType::AAAA() &&
     } else if (name == Name("glue.ns.example.com") && type == RRType::AAAA() &&
-        options == FIND_GLUE_OK) {
+        (options & FIND_GLUE_OK) != 0) {
         return (FindResult(SUCCESS, glue_aaaa_rrset));
         return (FindResult(SUCCESS, glue_aaaa_rrset));
     } else if (name == Name("example.com") && type == RRType::SOA() &&
     } else if (name == Name("example.com") && type == RRType::SOA() &&
         has_SOA_)
         has_SOA_)
@@ -139,7 +155,14 @@ MockZone::find(const Name& name, const RRType& type,
         has_apex_NS_)
         has_apex_NS_)
     {
     {
         return (FindResult(SUCCESS, auth_ns_rrset));
         return (FindResult(SUCCESS, auth_ns_rrset));
-    } else if (name == Name("delegation.example.com")) {
+    } else if (name == Name("mx.delegation.example.com") &&
+        type == RRType::A() && (options & FIND_GLUE_OK) != 0)
+    {
+        return (FindResult(SUCCESS, delegated_mx_a_rrset));
+    } else if (name == Name("delegation.example.com") ||
+        name.compare(Name("delegation.example.com")).getRelation() ==
+        NameComparisonResult::SUBDOMAIN)
+    {
         return (FindResult(DELEGATION, delegation_rrset));
         return (FindResult(DELEGATION, delegation_rrset));
     } else if (name == Name("ns.example.com")) {
     } else if (name == Name("ns.example.com")) {
         return (FindResult(DELEGATION, ns_rrset));
         return (FindResult(DELEGATION, ns_rrset));
@@ -149,6 +172,10 @@ MockZone::find(const Name& name, const RRType& type,
         return (FindResult(NXRRSET, RRsetPtr()));
         return (FindResult(NXRRSET, RRsetPtr()));
     } else if ((name == Name("cname.example.com"))) {
     } else if ((name == Name("cname.example.com"))) {
         return (FindResult(CNAME, cname_rrset));
         return (FindResult(CNAME, cname_rrset));
+    } else if (name == Name("cnamemailer.example.com")) {
+        return (FindResult(CNAME, mx_cname_rrset_));
+    } else if (name == Name("mx.example.com")) {
+        return (FindResult(SUCCESS, mx_rrset_));
     } else {
     } else {
         return (FindResult(DNAME, RRsetPtr()));
         return (FindResult(DNAME, RRsetPtr()));
     }
     }
@@ -353,4 +380,83 @@ TEST_F(QueryTest, noMatchZone) {
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 }
 
 
+/*
+ * Test MX additional processing.
+ *
+ * The MX RRset has two RRs, one pointing to a known domain with
+ * A record, other to unknown out of zone one.
+ */
+TEST_F(QueryTest, MX) {
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    Name qname("mx.example.com");
+    Query mx_query(memory_datasrc, qname, RRType::MX(), response);
+    EXPECT_NO_THROW(mx_query.process());
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
+        Name("mx.example.com"), RRClass::IN(), RRType::MX()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+        Name("www.example.com"), RRClass::IN(), RRType::A()));
+    // We want to skip the additional ones related to authoritative
+    RRsetPtr ns;
+    for (SectionIterator<RRsetPtr> ai(response.beginSection(
+        Message::SECTION_AUTHORITY)); ai != response.endSection(
+        Message::SECTION_AUTHORITY); ++ai)
+    {
+        if ((*ai)->getName() == Name("example.com") && (*ai)->getType() ==
+            RRType::NS())
+        {
+            ns = *ai;
+            break;
+        }
+    }
+    /*
+     * In fact, the MX RRset mentions three names, but we don't know anything
+     * about one of them and one is under a zone cut, so we should have just
+     * one RRset (A for www.example.com)
+     */
+    // We can't use getRRCount, as it counts RRs, not RRsets
+    unsigned additional_count(0);
+    for (SectionIterator<RRsetPtr> ai(response.beginSection(
+        Message::SECTION_ADDITIONAL)); ai != response.endSection(
+        Message::SECTION_ADDITIONAL); ++ai)
+    {
+        // Skip the ones for the NS record
+        if (ns) {
+            for (RdataIteratorPtr nsi(ns->getRdataIterator()); !nsi->isLast();
+                nsi->next())
+            {
+                if ((*ai)->getName() ==
+                    dynamic_cast<const isc::dns::rdata::generic::NS&>(
+                    nsi->getCurrent()).getNSName())
+                {
+                    goto NS_ADDITIONAL_DATA;
+                }
+            }
+        }
+        // It is not related to the NS, then it must be related to the MX
+        ++additional_count;
+        EXPECT_EQ(Name("www.example.com"), (*ai)->getName());
+        EXPECT_EQ(RRType::A(), (*ai)->getType());
+        NS_ADDITIONAL_DATA:;
+    }
+    EXPECT_EQ(1, additional_count);
+}
+
+/*
+ * Test when we ask for MX and encounter an alias (CNAME in this case).
+ *
+ * This should not trigger the additional processing.
+ */
+TEST_F(QueryTest, MXAlias) {
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    Name qname("cnamemailer.example.com");
+    Query mx_query(memory_datasrc, qname, RRType::MX(), response);
+    EXPECT_NO_THROW(mx_query.process());
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    // We should not have the IP address in additional section
+    // Currently, the section should be completely empty
+    EXPECT_TRUE(response.beginSection(Message::SECTION_ADDITIONAL) ==
+        response.endSection(Message::SECTION_ADDITIONAL));
+}
+
 }
 }