Browse Source

[2976] Basic implementation of fromWire test.

Marcin Siodelski 12 years ago
parent
commit
010bda2e96
2 changed files with 136 additions and 1 deletions
  1. 13 1
      src/bin/d2/d2_update_message.cc
  2. 123 0
      src/bin/d2/tests/d2_update_message_unittests.cc

+ 13 - 1
src/bin/d2/d2_update_message.cc

@@ -26,7 +26,9 @@ using namespace isc::dns;
 
 D2UpdateMessage::D2UpdateMessage(const bool parse)
     : message_(parse ? dns::Message::PARSE : dns::Message::RENDER) {
-    message_.setOpcode(Opcode(Opcode::UPDATE_CODE));
+    if (!parse) {
+        message_.setOpcode(Opcode(Opcode::UPDATE_CODE));
+    }
 }
 
 D2UpdateMessage::QRFlag
@@ -67,6 +69,16 @@ D2UpdateMessage::getRRCount(const UpdateMsgSection section) const {
     return (message_.getRRCount(ddnsToDnsSection(section)));
 }
 
+const dns::RRsetIterator
+D2UpdateMessage::beginSection(const UpdateMsgSection section) const {
+    return (message_.beginSection(ddnsToDnsSection(section)));
+}
+
+const dns::RRsetIterator
+D2UpdateMessage::endSection(const UpdateMsgSection section) const {
+    return (message_.endSection(ddnsToDnsSection(section)));
+}
+
 void
 D2UpdateMessage::setZone(const Name& zone, const RRClass& rrclass) {
     if (message_.getRRCount(dns::Message::SECTION_QUESTION) > 0) {

+ 123 - 0
src/bin/d2/tests/d2_update_message_unittests.cc

@@ -16,6 +16,7 @@
 
 #include <d2/d2_update_message.h>
 #include <dns/messagerenderer.h>
+#include <dns/rdataclass.h>
 #include <dns/rdata.h>
 #include <dns/rrttl.h>
 
@@ -74,6 +75,128 @@ public:
     }
 };
 
+// This test verifies that the DNS message is properly decoded from the
+// wire format.
+TEST_F(D2UpdateMessageTest, fromWire) {
+    // The following table holds the DNS response in on-wire format.
+    // This message comprises the following sections:
+    // - HEADER
+    // - PREREQUISITE section with one RR
+    // - UPDATE section with 1 RR.
+    // Such a response may be generated by the DNS server as a result
+    // of copying the contents of the REQUEST message sent by DDNS client.
+    const uint8_t bin_msg[] = {
+        // HEADER section starts here (see RFC 2136, section 2).
+        0x05, 0xAF, // ID=0x05AF
+        0xA8, 0x6,  // QR=1, Opcode=6, RCODE=YXDOMAIN
+        0x0, 0x1,   // ZOCOUNT=1
+        0x0, 0x2,   // PRCOUNT=2
+        0x0, 0x1,   // UPCOUNT=1
+        0x0, 0x0,   // ADCOUNT=0
+
+        // Zone section starts here. The The first field comprises
+        // the Zone name encoded as a set of labels, each preceded
+        // by a length of the following label. The whole Zone name is
+        // terminated with a NULL char.
+        // For Zone section format see (RFC 2136, section 2.3).
+        0x7, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example (0x7 is a length)
+        0x3, 0x63, 0x6F, 0x6D, //.com. (0x3 is a length)
+        0x0,      // NULL character terminates the Zone name.
+        0x0, 0x6, // ZTYPE='SOA'
+        0x0, 0x1, // ZCLASS='IN'
+
+        // Prerequisite section starts here. This section comprises two
+        // prerequisites:
+        // - 'Name is not in use'
+        // - 'Name is in use'
+        // See RFC 2136, section 2.4 for the format of Prerequisite section.
+        // Each prerequisite RR starts with its name. It is expressed in the
+        // compressed format as described in RFC 1035, section 4.1.4. The first
+        // label is expressed as in case of non-compressed name. It is preceded
+        // by the length value. The following two bytes are the pointer to the
+        // offset in the message where 'example.com' was used. That is, in the
+        // Zone name at offset 12. Pointer starts with two bits set - they
+        // mark start of the pointer.
+
+        // First prerequisite. NONE class indicates that the update requires
+        // that the name 'foo.example.com' is not use/
+        0x03, 0x66, 0x6F, 0x6F, // foo.
+        0xC0, 0x0C,             // pointer to example.com.
+        0x0, 0x1C,              // TYPE=AAAA
+        0x0, 0xFE,              // CLASS=NONE
+        0x0, 0x0, 0x0, 0x0,     // TTL=0
+        0x0, 0x0,               // RDLENGTH=0
+
+        // Second prerequisite. ANY class indicates tha the update requires
+        // that the name 'bar.example.com' exists.
+        0x03, 0x62, 0x61, 0x72, // bar.
+        0xC0, 0x0C,             // pointer to example.com.
+        0x0, 0x1C,              // TYPE=AAAA
+        0x0, 0xFF,              // CLASS=ANY
+        0x0, 0x0, 0x0, 0x0,     // TTL=0
+        0x0, 0x0,               // RDLENGTH=0
+
+        // Update section starts here. The format of this section conforms to
+        // RFC 2136, section 2.5. The name of the RR is again expressed in
+        // compressed format. The two pointer bytes point to the offset in the
+        // message where 'foo.example.com' was used already - 29.
+        0xC0, 0x1D,             // pointer to foo.example.com.
+        0x0, 0x1C,              // TYPE=AAAA
+        0x0, 0x1,               // CLASS=IN
+        0xAA, 0xBB, 0xCC, 0xDD, // TTL=0xAABBCCDD
+        0x0, 0x10,              // RDLENGTH=16
+        // The following 16 bytes of RDATA hold IPv6 address: 2001:db8:1::1.
+        0x20, 0x01, 0x0D, 0xB8, 0x00, 0x01, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+    };
+    InputBuffer buf(bin_msg, sizeof(bin_msg));
+
+    D2UpdateMessage msg(true);
+
+    ASSERT_NO_THROW(msg.fromWire(buf));
+
+    EXPECT_EQ(0x05AF, msg.getQid());
+    EXPECT_EQ(D2UpdateMessage::RESPONSE, msg.getQRFlag());
+    EXPECT_EQ(Rcode::YXDOMAIN_CODE, msg.getRcode().getCode());
+    ASSERT_EQ(1, msg.getRRCount(D2UpdateMessage::SECTION_ZONE));
+    // Zone section is TBD
+
+    ASSERT_EQ(2, msg.getRRCount(D2UpdateMessage::SECTION_PREREQUISITE));
+    RRsetIterator rrset_it = msg.beginSection(D2UpdateMessage::SECTION_PREREQUISITE);
+    RRsetPtr prereq1 = *rrset_it;
+    ASSERT_TRUE(prereq1);
+    EXPECT_EQ("foo.example.com.", prereq1->getName().toText());
+    EXPECT_EQ(RRType::AAAA().getCode(), prereq1->getType().getCode());
+    EXPECT_EQ(RRClass::NONE().getCode(), prereq1->getClass().getCode());
+    EXPECT_EQ(0, prereq1->getTTL().getValue());
+    EXPECT_EQ(0, prereq1->getRdataCount());
+
+    // Move to next prerequisite section.
+    ++rrset_it;
+
+    RRsetPtr prereq2 = *rrset_it;
+    ASSERT_TRUE(prereq2);
+    EXPECT_EQ("bar.example.com.", prereq2->getName().toText());
+    EXPECT_EQ(RRType::AAAA().getCode(), prereq2->getType().getCode());
+    EXPECT_EQ(RRClass::ANY().getCode(), prereq2->getClass().getCode());
+    EXPECT_EQ(0, prereq2->getTTL().getValue());
+    EXPECT_EQ(0, prereq2->getRdataCount());
+
+    ASSERT_EQ(1, msg.getRRCount(D2UpdateMessage::SECTION_UPDATE));
+    rrset_it = msg.beginSection(D2UpdateMessage::SECTION_UPDATE);
+    RRsetPtr update = *rrset_it;
+    ASSERT_TRUE(update);
+    EXPECT_EQ("foo.example.com.", update->getName().toText());
+    EXPECT_EQ(RRType::AAAA().getCode(), update->getType().getCode());
+    EXPECT_EQ(RRClass::IN().getCode(), update->getClass().getCode());
+    EXPECT_EQ(0xAABBCCDD, update->getTTL().getValue());
+    ASSERT_EQ(1, update->getRdataCount());
+    RdataIteratorPtr rdata_it = update->getRdataIterator();
+    ASSERT_TRUE(rdata_it);
+    in::AAAA rdata_ref("2001:db8:1::1");
+    EXPECT_EQ(0, rdata_ref.compare(rdata_it->getCurrent()));
+}
+
 // This test verifies that the wire format of the message is produced
 // in the render mode.
 TEST_F(D2UpdateMessageTest, toWire) {