Browse Source

[trac493] Add NODATA response processing

Ocean Wang 14 years ago
parent
commit
3cb71c8c16

+ 37 - 21
src/lib/cache/message_entry.cc

@@ -230,26 +230,12 @@ MessageEntry::parseSection(const isc::dns::Message& msg,
 void
 MessageEntry::parseNegativeResponseAuthoritySection(const isc::dns::Message& msg,
         uint32_t& soa_ttl,
-        uint16_t& rrset_count,
-        bool& found_soa)
+        uint16_t& rrset_count)
 {
-    RRsetIterator iter;
-    for(iter = msg.beginSection(Message::SECTION_AUTHORITY);
-            iter != msg.endSection(Message::SECTION_AUTHORITY);
-            ++iter){
-        RRsetPtr rrset_ptr = *iter;
-        if (rrset_ptr->getType() == RRType::SOA()){
-            found_soa = true;
-            break;
-        }
-    }
-    if(!found_soa){
-        return;
-    }
 
     // We found the SOA record, so we can cache the message and RRsets in the cache
     uint16_t count = 0;
-    for(iter = msg.beginSection(Message::SECTION_AUTHORITY);
+    for(RRsetIterator iter = msg.beginSection(Message::SECTION_AUTHORITY);
             iter != msg.endSection(Message::SECTION_AUTHORITY);
             ++iter){
         RRsetPtr rrset_ptr = *iter;
@@ -292,13 +278,15 @@ MessageEntry::initMessageEntry(const isc::dns::Message& msg) {
     } else {
         uint32_t min_ttl = MAX_UINT32;
         uint32_t soa_ttl = MAX_UINT32;
-        bool found_soa = false;
         uint16_t rrset_count = 0;
-        parseNegativeResponseAuthoritySection(msg, soa_ttl, rrset_count, found_soa);
-        // For negative response, if no soa RRset is found, dont cache it
-        if(!found_soa) {
+
+        // For negative response, if no soa RRset is found in authority section, dont cache it
+        if(!hasTheRecordInAuthoritySection(msg, RRType::SOA())){
             return;
         }
+
+        parseNegativeResponseAuthoritySection(msg, soa_ttl, rrset_count);
+
         authority_count_ = rrset_count;
         parseSection(msg, Message::SECTION_ANSWER, min_ttl, answer_count_);
         parseSection(msg, Message::SECTION_ADDITIONAL, min_ttl, additional_count_);
@@ -311,7 +299,35 @@ MessageEntry::initMessageEntry(const isc::dns::Message& msg) {
 bool
 MessageEntry::isNegativeResponse(const isc::dns::Message& msg)
 {
-    return msg.getRcode() == Rcode::NXDOMAIN();
+    if(msg.getRcode() == Rcode::NXDOMAIN()){
+        return true;
+    } else if (msg.getRcode() == Rcode::NOERROR()){
+        // no data in the answer section
+        if (msg.getRRCount(Message::SECTION_ANSWER) == 0){
+            // NODATA type 1/ type 2 (ref sec2.2 of RFC2308) 
+            if(hasTheRecordInAuthoritySection(msg, RRType::SOA())){
+                return true;
+            } else if (!hasTheRecordInAuthoritySection(msg, RRType::NS())){ // NODATA type 3 (sec2.2 of RFC2308)
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+bool
+MessageEntry::hasTheRecordInAuthoritySection(const isc::dns::Message& msg, const isc::dns::RRType& type)
+{
+    for(RRsetIterator iter = msg.beginSection(Message::SECTION_AUTHORITY);
+            iter != msg.endSection(Message::SECTION_AUTHORITY);
+            ++iter){
+        RRsetPtr rrset_ptr = *iter;
+        if (rrset_ptr->getType() == type){
+            return true;
+        }
+    }
+    return false;
 }
 
 } // namespace cache

+ 8 - 3
src/lib/cache/message_entry.h

@@ -124,11 +124,9 @@ protected:
     /// \param msg The message to parse the RRsets from
     /// \param soa_ttl Get the ttl of soa rrset in the authority section
     /// \param rrset_count the rrset count of the authority section
-    /// \param found_soa whether the soa RRset is found in the authority section
     void parseNegativeResponseAuthoritySection(const isc::dns::Message& msg,
             uint32_t& soa_ttl,
-            uint16_t& rrset_count,
-            bool& found_soa);
+            uint16_t& rrset_count);
 
     /// \brief Get RRset Trustworthiness
     ///        The algorithm refers to RFC2181 section 5.4.1
@@ -172,8 +170,15 @@ protected:
 private:
     /// \brief Check whetehr the message is a negative response(NXDOMAIN or NOERROR_NODATA)
     ///
+    /// \param msg The response message
     bool isNegativeResponse(const isc::dns::Message& msg);
 
+    /// \brief Check whether there is some type of record in Authority section
+    ///
+    /// \param msg The response message to be checked
+    /// \param type The RR type that need to check
+    bool hasTheRecordInAuthoritySection(const isc::dns::Message& msg, const isc::dns::RRType& type);
+
     std::string entry_name_; // The name for this entry(name + type)
     HashKey* hash_key_ptr_;  // the key for messag entry in hash table.
 

+ 49 - 0
src/lib/cache/tests/negative_cache_unittest.cc

@@ -115,4 +115,53 @@ TEST_F(NegativeCacheTest, testNXDOMAINWithoutSOA){
     EXPECT_FALSE(cache->lookup(non_exist_qname, RRType::A(), RRClass::IN(), msg_nxdomain));
 }
 
+TEST_F(NegativeCacheTest, testNoerrorNodata){
+    // NODATA/NOERROR response for MX type query of example.com
+    Message msg_nodata(Message::PARSE);
+    messageFromFile(msg_nodata, "message_nodata_with_soa.wire");
+    cache->update(msg_nodata);
+
+    msg_nodata.makeResponse();
+
+    Name example_dot_com("example.com.");
+    EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(), msg_nodata));
+
+    RRsetIterator iter = msg_nodata.beginSection(Message::SECTION_AUTHORITY);
+    RRsetPtr rrset_ptr = *iter;
+
+    // The TTL should equal to the TTL of SOA record
+    const RRTTL& nodata_ttl1 = rrset_ptr->getTTL();
+    EXPECT_EQ(nodata_ttl1.getValue(), 86400);
+
+
+    // Normal SOA response for example.com
+    Message msg_example_com_soa(Message::PARSE);
+    messageFromFile(msg_example_com_soa, "message_example_com_soa.wire");
+    cache->update(msg_example_com_soa);
+
+    msg_example_com_soa.makeResponse();
+    Name soa_qname("example.com.");
+    EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(), msg_example_com_soa));
+
+    iter = msg_example_com_soa.beginSection(Message::SECTION_ANSWER);
+    rrset_ptr = *iter;
+
+    // The TTL should equal to the TTL of SOA record in answer section
+    const RRTTL& soa_ttl = rrset_ptr->getTTL();
+    EXPECT_EQ(soa_ttl.getValue(), 172800);
+
+    // Query MX record of example.com again
+    Message msg_nodata2(Message::PARSE);
+    messageFromFile(msg_nodata2, "message_nodata_with_soa.wire");
+    msg_nodata2.makeResponse();
+
+    EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(), msg_nodata2));
+    iter = msg_nodata2.beginSection(Message::SECTION_AUTHORITY);
+    rrset_ptr = *iter;
+
+    // The TTL should equal to the TTL of negative response SOA record
+    const RRTTL& nodata_ttl2 = rrset_ptr->getTTL();
+    EXPECT_EQ(nodata_ttl2.getValue(), 86400);
+}
+
 }

+ 1 - 1
src/lib/cache/tests/testdata/message_example_com_soa.wire

@@ -30,7 +30,7 @@ c0 0c
 00 06
 # Class: IN (0x0001)
 00 01
-# Time to live: 2 days
+# Time to live: 2 days (172800s)
 00 02 a3 00
 # Data length: 49
 00 31