Parcourir la source

[trac497] added a Message::clearSection() and resolve::makeErrorMessage

clearSection is a convenience function to clear all RRsets in a message
used by makeErrorMessage, which is a helper function to quickly clear
any data built up in the answer so far, and set an error Rcode
Jelte Jansen il y a 14 ans
Parent
commit
cd6beb6ccd

+ 6 - 2
src/lib/asiolink/asiolink.cc

@@ -52,6 +52,7 @@ using namespace boost;
 
 // Is this something we can use in libdns++?
 namespace {
+    // TODO: remove
     class SectionInserter {
     public:
         SectionInserter(MessagePtr message, const Message::Section sect) :
@@ -65,6 +66,7 @@ namespace {
     };
 
 
+    // TODO: move to resolve.cc
     /// \brief Copies the parts relevant for a DNS answer to the
     /// target message
     ///
@@ -431,7 +433,8 @@ private:
     // Note that the footprint may change as this function may
     // need to append data to the answer we are building later.
     //
-    // returns true if we are done
+    // returns true if we are done (either we have an answer or an
+    //              error message)
     // returns false if we are not done
     bool handleRecursiveAnswer(const Message& incoming) {
         dlog("Handle response");
@@ -458,7 +461,8 @@ private:
                 // TODO: make SERVFAIL? clear currently read answers?
                 // just copy for now.
                 dlog("CNAME chain too long");
-                copyAnswerMessage(incoming, answer_message_);
+                isc::resolve::makeErrorMessage(answer_message_,
+                                               Rcode::SERVFAIL());
                 return true;
             }
 

+ 8 - 0
src/lib/dns/message.cc

@@ -338,6 +338,14 @@ Message::removeRRset(const Section section, RRsetIterator& iterator) {
     return (removed);
 }
 
+void
+Message::clearSection(const Section section) {
+    if (section >= MessageImpl::NUM_SECTIONS) {
+        isc_throw(OutOfRange, "Invalid message section: " << section);
+    }
+    impl_->rrsets_[section].clear();
+    impl_->counts_[section] = 0;
+}
 
 void
 Message::addQuestion(const QuestionPtr question) {

+ 5 - 0
src/lib/dns/message.h

@@ -483,6 +483,11 @@ public:
     /// found in the specified section.
     bool removeRRset(const Section section, RRsetIterator& iterator);
 
+    /// \brief Remove all RRSets from the given Section
+    ///
+    /// \param section Section to remove all rrsets from
+    void clearSection(const Section section);
+
     // The following methods are not currently implemented.
     //void removeQuestion(QuestionPtr question);
     // notyet:

+ 69 - 0
src/lib/dns/tests/message_unittest.cc

@@ -297,6 +297,75 @@ TEST_F(MessageTest, removeRRset) {
     EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
 }
 
+TEST_F(MessageTest, clearQuestionSection) {
+    QuestionPtr q(new Question(Name("www.example.com"), RRClass::IN(),
+                               RRType::A()));
+    message_render.addQuestion(q);
+    ASSERT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+
+    message_render.clearSection(Message::SECTION_QUESTION);
+    EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
+}
+
+
+TEST_F(MessageTest, clearAnswerSection) {
+    // Add two RRsets, check they are present, clear the section,
+    // check if they are gone.
+    message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
+    message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
+    ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+        RRClass::IN(), RRType::A()));
+    ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+        RRClass::IN(), RRType::AAAA()));
+    ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ANSWER));
+
+    message_render.clearSection(Message::SECTION_ANSWER);
+    EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+        RRClass::IN(), RRType::A()));
+    EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
+        RRClass::IN(), RRType::AAAA()));
+    EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
+}
+
+TEST_F(MessageTest, clearAuthoritySection) {
+    // Add two RRsets, check they are present, clear the section,
+    // check if they are gone.
+    message_render.addRRset(Message::SECTION_AUTHORITY, rrset_a);
+    message_render.addRRset(Message::SECTION_AUTHORITY, rrset_aaaa);
+    ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+        RRClass::IN(), RRType::A()));
+    ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+        RRClass::IN(), RRType::AAAA()));
+    ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_AUTHORITY));
+
+    message_render.clearSection(Message::SECTION_AUTHORITY);
+    EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+        RRClass::IN(), RRType::A()));
+    EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
+        RRClass::IN(), RRType::AAAA()));
+    EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
+}
+
+TEST_F(MessageTest, clearAdditionalSection) {
+    // Add two RRsets, check they are present, clear the section,
+    // check if they are gone.
+    message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_a);
+    message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_aaaa);
+    ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+        RRClass::IN(), RRType::A()));
+    ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+        RRClass::IN(), RRType::AAAA()));
+    ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+    message_render.clearSection(Message::SECTION_ADDITIONAL);
+    EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+        RRClass::IN(), RRType::A()));
+    EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
+        RRClass::IN(), RRType::AAAA()));
+    EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+}
+
+
 TEST_F(MessageTest, badBeginSection) {
     // valid cases are tested via other tests
     EXPECT_THROW(message_render.beginSection(Message::SECTION_QUESTION),

+ 1 - 1
src/lib/resolve/Makefile.am

@@ -10,7 +10,7 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 CLEANFILES = *.gcno *.gcda
 
 lib_LTLIBRARIES = libresolve.la
-libresolve_la_SOURCES = resolve.h
+libresolve_la_SOURCES = resolve.h resolve.cc
 libresolve_la_SOURCES += resolver_interface.h
 libresolve_la_SOURCES += resolver_callback.h resolver_callback.cc
 libresolve_la_SOURCES += response_classifier.cc response_classifier.h

+ 49 - 0
src/lib/resolve/resolve.cc

@@ -0,0 +1,49 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <resolve/resolve.h>
+
+using namespace isc::dns;
+
+namespace {
+    class SectionInserter {
+    public:
+        SectionInserter(MessagePtr message, const Message::Section sect) :
+            message_(message), section_(sect)
+        {}
+        void operator()(const RRsetPtr rrset) {
+            message_->addRRset(section_, rrset, true);
+        }
+        MessagePtr message_;
+        const Message::Section section_;
+    };
+}
+
+namespace isc {
+namespace resolve {
+
+void
+makeErrorMessage(MessagePtr answer_message,
+                 const Rcode::Rcode& error_code)
+{
+    answer_message->clearSection(Message::SECTION_ANSWER);
+    answer_message->clearSection(Message::SECTION_AUTHORITY);
+    answer_message->clearSection(Message::SECTION_ADDITIONAL);
+
+    answer_message->setRcode(error_code);
+}
+
+} // namespace resolve
+} // namespace isc
+

+ 26 - 0
src/lib/resolve/resolve.h

@@ -15,7 +15,33 @@
 #ifndef _ISC_RESOLVE_H
 #define _ISC_RESOLVE_H 1
 
+/// This file includes all other libresolve headers, and provides
+/// several helper functions used in resolving.
+
 #include <resolve/resolver_interface.h>
 #include <resolve/resolver_callback.h>
 #include <resolve/response_classifier.h>
+
+namespace isc {
+namespace resolve {
+
+/// \brief Create an error response
+///
+/// Clears the answer, authority, and additional section of the
+/// given MessagePtr and sets the given error code
+///
+/// Notes: Assuming you have already done initial preparations
+/// on the given answer message (copy the opcode, qid and question
+/// section), you can simply use this to create an error response.
+///
+/// \param answer_message The message to clear and place the error in
+/// \param question The question to add to the
+/// \param error_code The error Rcode
+void
+makeErrorMessage(isc::dns::MessagePtr answer_message,
+                 const isc::dns::Rcode::Rcode& error_code);
+
+} // namespace resolve
+} // namespace isc
+
 #endif // ISC_RESOLVE_H_

+ 1 - 0
src/lib/resolve/tests/Makefile.am

@@ -14,6 +14,7 @@ TESTS += run_unittests
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += resolve_unittest.cc
 run_unittests_SOURCES += resolver_callback_unittest.cc
 run_unittests_SOURCES += response_classifier_unittest.cc
 

+ 112 - 0
src/lib/resolve/tests/resolve_unittest.cc

@@ -0,0 +1,112 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <iostream>
+#include <gtest/gtest.h>
+
+#include <dns/message.h>
+#include <dns/question.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrttl.h>
+#include <dns/rdata.h>
+#include <resolve/resolve.h>
+
+using namespace isc::dns;
+
+namespace {
+
+class ResolveHelperFunctionsTest : public ::testing::Test {
+public:
+    ResolveHelperFunctionsTest() :
+        message_(new Message(Message::RENDER)),
+        question_(new Question(Name("www.example.com"), RRClass::IN(), RRType::A()))
+    {
+        message_->setOpcode(Opcode::QUERY());
+        message_->setRcode(Rcode::NOERROR());
+        message_->addQuestion(question_);
+    };
+
+    MessagePtr message_;
+    QuestionPtr question_;
+    
+};
+
+TEST_F(ResolveHelperFunctionsTest, makeErrorMessageEmptyMessage) {
+    ASSERT_EQ(Rcode::NOERROR(), message_->getRcode());
+    ASSERT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
+    ASSERT_EQ(0, message_->getRRCount(Message::SECTION_ANSWER));
+    ASSERT_EQ(0, message_->getRRCount(Message::SECTION_AUTHORITY));
+    ASSERT_EQ(0, message_->getRRCount(Message::SECTION_ADDITIONAL));
+
+    isc::resolve::makeErrorMessage(message_, Rcode::SERVFAIL());
+    EXPECT_EQ(Rcode::SERVFAIL(), message_->getRcode());
+    EXPECT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
+    EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(0, message_->getRRCount(Message::SECTION_AUTHORITY));
+    EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ADDITIONAL));
+}
+
+TEST_F(ResolveHelperFunctionsTest, makeErrorMessageNonEmptyMessage) {
+    // We could reuse the same rrset in the different sections,
+    // but to be sure, we create separate ones
+    RRsetPtr answer_rrset(new RRset(Name("www.example.com"),
+                                    RRClass::IN(), RRType::TXT(),
+                                    RRTTL(3600)));
+    answer_rrset->addRdata(rdata::createRdata(RRType::TXT(),
+                                              RRClass::IN(),
+                                              "Answer"));
+    message_->addRRset(Message::SECTION_ANSWER, answer_rrset);
+
+    RRsetPtr auth_rrset(new RRset(Name("www.example.com"),
+                                    RRClass::IN(), RRType::TXT(),
+                                    RRTTL(3600)));
+    auth_rrset->addRdata(rdata::createRdata(RRType::TXT(),
+                                              RRClass::IN(),
+                                              "Authority"));
+    auth_rrset->addRdata(rdata::createRdata(RRType::TXT(),
+                                              RRClass::IN(),
+                                              "Rdata"));
+    message_->addRRset(Message::SECTION_AUTHORITY, auth_rrset);
+
+    RRsetPtr add_rrset(new RRset(Name("www.example.com"),
+                                 RRClass::IN(), RRType::TXT(),
+                                 RRTTL(3600)));
+    add_rrset->addRdata(rdata::createRdata(RRType::TXT(),
+                                           RRClass::IN(),
+                                           "Additional"));
+    add_rrset->addRdata(rdata::createRdata(RRType::TXT(),
+                                           RRClass::IN(),
+                                           "Rdata"));
+    add_rrset->addRdata(rdata::createRdata(RRType::TXT(),
+                                           RRClass::IN(),
+                                           "fields."));
+    message_->addRRset(Message::SECTION_ADDITIONAL, add_rrset);
+
+    ASSERT_EQ(Rcode::NOERROR(), message_->getRcode());
+    ASSERT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
+    ASSERT_EQ(1, message_->getRRCount(Message::SECTION_ANSWER));
+    ASSERT_EQ(2, message_->getRRCount(Message::SECTION_AUTHORITY));
+    ASSERT_EQ(3, message_->getRRCount(Message::SECTION_ADDITIONAL));
+
+    isc::resolve::makeErrorMessage(message_, Rcode::FORMERR());
+    EXPECT_EQ(Rcode::FORMERR(), message_->getRcode());
+    EXPECT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
+    EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(0, message_->getRRCount(Message::SECTION_AUTHORITY));
+    EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ADDITIONAL));
+}
+
+
+} // Anonymous namespace