Browse Source

Merge branch 'trac2521'

Conflicts:
	src/lib/dns/gen-rdatacode.py.in
Paul Selkirk 12 years ago
parent
commit
c6603decaa

+ 6 - 2
src/lib/dns/gen-rdatacode.py.in

@@ -1,6 +1,6 @@
 #!@PYTHON@
 
-# Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2010-2013  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
@@ -32,9 +32,11 @@ import sys
 #
 # Example:
 #     new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
-new_rdata_factory_users = [('a', 'in'), ('aaaa', 'in'),
+new_rdata_factory_users = [('a', 'in'),
+                           ('aaaa', 'in'),
                            ('afsdb', 'generic'),
                            ('cname', 'generic'),
+                           ('dhcid', 'in'),
                            ('dlv', 'generic'),
                            ('dname', 'generic'),
                            ('dnskey', 'generic'),
@@ -46,7 +48,9 @@ new_rdata_factory_users = [('a', 'in'), ('aaaa', 'in'),
                            ('nsec', 'generic'),
                            ('nsec3', 'generic'),
                            ('nsec3param', 'generic'),
+                           ('opt', 'generic'),
                            ('ptr', 'generic'),
+                           ('rrsig', 'generic'),
                            ('soa', 'generic'),
                            ('spf', 'generic'),
                            ('srv', 'in'),

+ 18 - 1
src/lib/dns/rdata/generic/opt_41.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -27,10 +27,26 @@ using namespace isc::util;
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
+/// \brief Constructor from string.
+///
+/// This constructor cannot be used, and always throws an exception.
+///
+/// \throw InvalidRdataText OPT RR cannot be constructed from text.
 OPT::OPT(const std::string&) {
     isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text");
 }
 
+/// \brief Constructor with a context of MasterLexer.
+///
+/// This constructor cannot be used, and always throws an exception.
+///
+/// \throw InvalidRdataText OPT RR cannot be constructed from text.
+OPT::OPT(MasterLexer&, const Name*,
+       MasterLoader::Options, MasterLoaderCallbacks&)
+{
+    isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text");
+}
+
 OPT::OPT(InputBuffer& buffer, size_t rdata_len) {
     // setPosition() will throw against a short buffer anyway, but it's safer
     // to check it explicitly here.
@@ -48,6 +64,7 @@ OPT::OPT(const OPT&) : Rdata() {
 
 std::string
 OPT::toText() const {
+    // OPT records do not have a text format.
     return ("");
 }
 

+ 115 - 27
src/lib/dns/rdata/generic/rrsig_46.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -26,9 +26,9 @@
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rrtype.h>
-#include <dns/rrttl.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
+#include <dns/rdata/generic/detail/lexer_util.h>
 
 #include <stdio.h>
 #include <time.h>
@@ -36,6 +36,7 @@
 using namespace std;
 using namespace isc::util;
 using namespace isc::util::encode;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -52,8 +53,8 @@ const size_t RRSIG_MINIMUM_LEN = 2 * sizeof(uint8_t) + 2 * sizeof(uint16_t) +
 struct RRSIGImpl {
     // straightforward representation of RRSIG RDATA fields
     RRSIGImpl(const RRType& covered, uint8_t algorithm, uint8_t labels,
-              uint32_t originalttl, uint32_t timeexpire, uint32_t timeinception,
-              uint16_t tag, const Name& signer,
+              uint32_t originalttl, uint32_t timeexpire,
+              uint32_t timeinception, uint16_t tag, const Name& signer,
               const vector<uint8_t>& signature) :
         covered_(covered), algorithm_(algorithm), labels_(labels),
         originalttl_(originalttl), timeexpire_(timeexpire),
@@ -72,38 +73,125 @@ struct RRSIGImpl {
     const vector<uint8_t> signature_;
 };
 
-RRSIG::RRSIG(const std::string& rrsig_str) :
-    impl_(NULL)
-{
-    istringstream iss(rrsig_str);
-    string covered_txt, signer_txt, expire_txt, inception_txt;
-    unsigned int algorithm, labels;
-    uint32_t originalttl;
-    uint16_t tag;
-    stringbuf signaturebuf;
-
-    iss >> covered_txt >> algorithm >> labels >> originalttl
-        >> expire_txt >> inception_txt >> tag >> signer_txt
-        >> &signaturebuf;
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid RRSIG text");
-    }
+// helper function for string and lexer constructors
+RRSIGImpl*
+RRSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) {
+    const RRType covered(lexer.getNextToken(MasterToken::STRING).getString());
+    const uint32_t algorithm =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
     if (algorithm > 0xff) {
         isc_throw(InvalidRdataText, "RRSIG algorithm out of range");
     }
+    const uint32_t labels =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
     if (labels > 0xff) {
         isc_throw(InvalidRdataText, "RRSIG labels out of range");
     }
-
-    const uint32_t timeexpire = timeFromText32(expire_txt);
-    const uint32_t timeinception = timeFromText32(inception_txt);
+    const uint32_t originalttl =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    const uint32_t timeexpire =
+        timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
+    const uint32_t timeinception =
+        timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
+    const uint32_t tag =
+        lexer.getNextToken(MasterToken::NUMBER).getNumber();
+    if (tag > 0xffff) {
+        isc_throw(InvalidRdataText, "RRSIG key tag out of range");
+    }
+    const Name& signer = createNameFromLexer(lexer, origin);
+
+    string signature_txt;
+    string signature_part;
+    // Whitespace is allowed within base64 text, so read to the end of input.
+    while (true) {
+        const MasterToken& token =
+            lexer.getNextToken(MasterToken::STRING, true);
+        if ((token.getType() == MasterToken::END_OF_FILE) ||
+            (token.getType() == MasterToken::END_OF_LINE)) {
+            break;
+        }
+        token.getString(signature_part);
+        signature_txt.append(signature_part);
+    }
+    lexer.ungetToken();
 
     vector<uint8_t> signature;
-    decodeBase64(signaturebuf.str(), signature);
+    // missing signature is okay
+    if (signature_txt.size() > 0) {
+        decodeBase64(signature_txt, signature);
+    }
 
-    impl_ = new RRSIGImpl(RRType(covered_txt), algorithm, labels,
-                          originalttl, timeexpire, timeinception, tag,
-                          Name(signer_txt), signature);
+    return (new RRSIGImpl(covered, algorithm, labels,
+                          originalttl, timeexpire, timeinception,
+                          static_cast<uint16_t>(tag), signer, signature));
+}
+
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid RRSIG RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The Signer's Name must be absolute since there's no parameter that
+/// specifies the origin name; if this is not absolute, \c MissingNameOrigin
+/// exception will be thrown.  This must not be represented as a quoted
+/// string.
+///
+/// See the construction that takes \c MasterLexer for other fields.
+///
+/// \throw Others Exception from the Name constructor.
+/// \throw InvalidRdataText Other general syntax errors.
+RRSIG::RRSIG(const std::string& rrsig_str) :
+    impl_(NULL)
+{
+    // We use auto_ptr here because if there is an exception in this
+    // constructor, the destructor is not called and there could be a
+    // leak of the RRSIGImpl that constructFromLexer() returns.
+    std::auto_ptr<RRSIGImpl> impl_ptr(NULL);
+
+    try {
+        std::istringstream iss(rrsig_str);
+        MasterLexer lexer;
+        lexer.pushSource(iss);
+
+        impl_ptr.reset(constructFromLexer(lexer, NULL));
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for RRSIG: "
+                      << rrsig_str);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct RRSIG from '" <<
+                  rrsig_str << "': " << ex.what());
+    }
+
+    impl_ = impl_ptr.release();
+}
+
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an RRSIG RDATA.  The Signer's Name fields can be non absolute if \c
+/// origin is non NULL, in which case \c origin is used to make it absolute.
+/// This must not be represented as a quoted string.
+///
+/// The Original TTL field is a valid decimal representation of an unsigned
+/// 32-bit integer. Note that alternate textual representations of \c RRTTL,
+/// such as "1H" for 3600 seconds, are not allowed here.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name constructor if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of Signer's Name when
+/// it is non absolute.
+RRSIG::RRSIG(MasterLexer& lexer, const Name* origin,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    impl_(constructFromLexer(lexer, origin))
+{
 }
 
 RRSIG::RRSIG(InputBuffer& buffer, size_t rdata_len) {

+ 10 - 2
src/lib/dns/rdata/generic/rrsig_46.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -18,7 +18,6 @@
 
 #include <dns/name.h>
 #include <dns/rrtype.h>
-#include <dns/rrttl.h>
 #include <dns/rdata.h>
 
 // BEGIN_HEADER_GUARD
@@ -32,6 +31,12 @@
 
 struct RRSIGImpl;
 
+/// \brief \c rdata::RRSIG class represents the RRSIG RDATA as defined %in
+/// RFC4034.
+///
+/// This class implements the basic interfaces inherited from the abstract
+/// \c rdata::Rdata class, and provides trivial accessors specific to the
+/// RRSIG RDATA.
 class RRSIG : public Rdata {
 public:
     // BEGIN_COMMON_MEMBERS
@@ -42,6 +47,9 @@ public:
     // specialized methods
     const RRType& typeCovered() const;
 private:
+    // helper function for string and lexer constructors
+    RRSIGImpl* constructFromLexer(MasterLexer& lexer, const Name* origin);
+
     RRSIGImpl* impl_;
 };
 

+ 56 - 34
src/lib/dns/rdata/in_1/dhcid_49.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -15,8 +15,6 @@
 #include <stdint.h>
 #include <string.h>
 
-#include <string>
-
 #include <exceptions/exceptions.h>
 
 #include <util/buffer.h>
@@ -28,53 +26,77 @@
 
 using namespace std;
 using namespace isc::util;
+using namespace isc::util::encode;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
+void
+DHCID::constructFromLexer(MasterLexer& lexer) {
+    string digest_txt = lexer.getNextToken(MasterToken::STRING).getString();
+
+    // Whitespace is allowed within base64 text, so read to the end of input.
+    string digest_part;
+    while (true) {
+        const MasterToken& token =
+            lexer.getNextToken(MasterToken::STRING, true);
+        if ((token.getType() == MasterToken::END_OF_FILE) ||
+            (token.getType() == MasterToken::END_OF_LINE)) {
+            break;
+        }
+        token.getString(digest_part);
+        digest_txt.append(digest_part);
+    }
+    lexer.ungetToken();
+
+    decodeBase64(digest_txt, digest_);
+}
+
 /// \brief Constructor from string.
 ///
 /// \param dhcid_str A base-64 representation of the DHCID binary data.
-/// The data is considered to be opaque, but a sanity check is performed.
-///
-/// <b>Exceptions</b>
 ///
-/// \c dhcid_str must be a valid  BASE-64 string, otherwise an exception
-/// of class \c isc::BadValue will be thrown;
-/// the binary data should consist of at leat of 3 octets as per RFC4701:
-///           < 2 octets >    Identifier type code
-///           < 1 octet >     Digest type code
-///           < n octets >    Digest (length depends on digest type)
-/// If the data is less than 3 octets (i.e. it cannot contain id type code and
-/// digest type code), an exception of class \c InvalidRdataLength is thrown.
+/// \throw InvalidRdataText if the string could not be parsed correctly.
 DHCID::DHCID(const std::string& dhcid_str) {
-    istringstream iss(dhcid_str);
-    stringbuf digestbuf;
-
-    iss >> &digestbuf;
-    isc::util::encode::decodeBase64(digestbuf.str(), digest_);
-
-    // RFC4701 states DNS software should consider the RDATA section to
-    // be opaque, but there must be at least three bytes in the data:
-    // < 2 octets >    Identifier type code
-    // < 1 octet >     Digest type code
-    if (digest_.size() < 3) {
-        isc_throw(InvalidRdataLength, "DHCID length " << digest_.size() <<
-                  " too short, need at least 3 bytes");
+    try {
+        std::istringstream iss(dhcid_str);
+        MasterLexer lexer;
+        lexer.pushSource(iss);
+
+        constructFromLexer(lexer);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for DHCID: "
+                      << dhcid_str);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct DHCID from '" <<
+                  dhcid_str << "': " << ex.what());
     }
 }
 
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of a DHCID RDATA.
+///
+/// \throw BadValue if the text is not valid base-64.
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+DHCID::DHCID(MasterLexer& lexer, const Name*,
+             MasterLoader::Options, MasterLoaderCallbacks&) {
+    constructFromLexer(lexer);
+}
+
 /// \brief Constructor from wire-format data.
 ///
 /// \param buffer A buffer storing the wire format data.
 /// \param rdata_len The length of the RDATA in bytes
-///
-/// <b>Exceptions</b>
-/// \c InvalidRdataLength is thrown if \c rdata_len is than minimum of 3 octets
 DHCID::DHCID(InputBuffer& buffer, size_t rdata_len) {
-    if (rdata_len < 3) {
-        isc_throw(InvalidRdataLength, "DHCID length " << rdata_len <<
-                  " too short, need at least 3 bytes");
+    if (rdata_len == 0) {
+        isc_throw(InvalidRdataLength, "Missing DHCID rdata");
     }
 
     digest_.resize(rdata_len);
@@ -112,7 +134,7 @@ DHCID::toWire(AbstractMessageRenderer& renderer) const {
 /// \return A string representation of \c DHCID.
 string
 DHCID::toText() const {
-    return (isc::util::encode::encodeBase64(digest_));
+    return (encodeBase64(digest_));
 }
 
 /// \brief Compare two instances of \c DHCID RDATA.

+ 4 - 1
src/lib/dns/rdata/in_1/dhcid_49.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -43,6 +43,9 @@ public:
     const std::vector<uint8_t>& getDigest() const;
 
 private:
+    // helper for string and lexer constructors
+    void constructFromLexer(MasterLexer& lexer);
+
     /// \brief Private data representation
     ///
     /// Opaque data at least 3 octets long as per RFC4701.

+ 2 - 2
src/lib/dns/tests/message_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -98,7 +98,7 @@ protected:
         rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
                                         RRType::RRSIG(), RRTTL(3600)));
         rrset_rrsig->addRdata(generic::RRSIG("AAAA 5 3 7200 20100322084538 "
-                                             "20100220084538 1 example.com "
+                                             "20100220084538 1 example.com. "
                                              "FAKEFAKEFAKEFAKE"));
         rrset_aaaa->addRRsig(rrset_rrsig);
     }

+ 70 - 23
src/lib/dns/tests/rdata_dhcid_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013  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
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <exceptions/exceptions.h>
+
 #include <util/buffer.h>
 #include <dns/rdataclass.h>
 #include <util/encode/base64.h>
@@ -23,6 +25,7 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 using namespace isc::util;
 using namespace isc::util::encode;
@@ -30,25 +33,69 @@ using namespace isc::dns::rdata;
 
 namespace {
 
-const string string_dhcid(
-                   "0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA=");
-
-const in::DHCID rdata_dhcid(string_dhcid);
-
 class Rdata_DHCID_Test : public RdataTest {
+protected:
+    Rdata_DHCID_Test() :
+        dhcid_txt("0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA="),
+        rdata_dhcid(dhcid_txt)
+    {}
+
+    void checkFromText_None(const string& rdata_str) {
+        checkFromText<in::DHCID, isc::Exception, isc::Exception>(
+            rdata_str, rdata_dhcid, false, false);
+    }
+
+    void checkFromText_BadValue(const string& rdata_str) {
+        checkFromText<in::DHCID, BadValue, BadValue>(
+            rdata_str, rdata_dhcid, true, true);
+    }
+
+    void checkFromText_LexerError(const string& rdata_str) {
+        checkFromText
+            <in::DHCID, InvalidRdataText, MasterLexer::LexerError>(
+                rdata_str, rdata_dhcid, true, true);
+    }
+
+    void checkFromText_BadString(const string& rdata_str) {
+        checkFromText
+            <in::DHCID, InvalidRdataText, isc::Exception>(
+                rdata_str, rdata_dhcid, true, false);
+    }
+
+    const string dhcid_txt;
+    const in::DHCID rdata_dhcid;
 };
 
-TEST_F(Rdata_DHCID_Test, createFromString) {
-    const in::DHCID rdata_dhcid2(string_dhcid);
-    EXPECT_EQ(0, rdata_dhcid2.compare(rdata_dhcid));
-}
+TEST_F(Rdata_DHCID_Test, fromText) {
+    EXPECT_EQ(dhcid_txt, rdata_dhcid.toText());
+
+    // Space in digest data is OK
+    checkFromText_None(
+            "0LIg0LvQtdGB0YMg 0YDQvtC00LjQu9Cw 0YHRjCDRkdC70L7R h9C60LA=");
+
+    // Multi-line digest data is OK, if enclosed in parentheses
+    checkFromText_None(
+            "( 0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw\n0YHRjCDRkdC70L7R h9C60LA= )");
 
-TEST_F(Rdata_DHCID_Test, badBase64) {
-    EXPECT_THROW(const in::DHCID rdata_dhcid_bad("00"), isc::BadValue);
+    // Trailing garbage. This should cause only the string constructor
+    // to fail, but the lexer constructor must be able to continue
+    // parsing from it.
+    checkFromText_BadString(
+            "0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA="
+            " ; comment\n"
+            "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=");
 }
 
-TEST_F(Rdata_DHCID_Test, badLength) {
-    EXPECT_THROW(const in::DHCID rdata_dhcid_bad("MDA="), InvalidRdataLength);
+TEST_F(Rdata_DHCID_Test, badText) {
+    // missing digest data
+    checkFromText_LexerError("");
+
+    // invalid base64
+    checkFromText_BadValue("EEeeeeeeEEEeeeeeeGaaahAAAAAAAAHHHHHHHHHHH!=");
+
+    // unterminated multi-line base64
+    checkFromText_LexerError(
+            "( 0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw\n0YHRjCDRkdC70L7R h9C60LA=");
 }
 
 TEST_F(Rdata_DHCID_Test, copy) {
@@ -60,17 +107,17 @@ TEST_F(Rdata_DHCID_Test, createFromWire) {
     EXPECT_EQ(0, rdata_dhcid.compare(
                   *rdataFactoryFromFile(RRType("DHCID"), RRClass("IN"),
                                         "rdata_dhcid_fromWire")));
+
+    InputBuffer buffer(NULL, 0);
+    EXPECT_THROW(in::DHCID(buffer, 0), InvalidRdataLength);
+
     // TBD: more tests
 }
 
 TEST_F(Rdata_DHCID_Test, createFromLexer) {
     EXPECT_EQ(0, rdata_dhcid.compare(
         *test::createRdataUsingLexer(RRType::DHCID(), RRClass::IN(),
-                                     string_dhcid)));
-
-    // Exceptions cause NULL to be returned.
-    EXPECT_FALSE(test::createRdataUsingLexer(RRType::DHCID(), RRClass::IN(),
-                                             "00"));
+                                     dhcid_txt)));
 }
 
 TEST_F(Rdata_DHCID_Test, toWireRenderer) {
@@ -92,13 +139,13 @@ TEST_F(Rdata_DHCID_Test, toWireBuffer) {
 }
 
 TEST_F(Rdata_DHCID_Test, toText) {
-    EXPECT_EQ(string_dhcid, rdata_dhcid.toText());
+    EXPECT_EQ(dhcid_txt, rdata_dhcid.toText());
 }
 
 TEST_F(Rdata_DHCID_Test, getDHCIDDigest) {
-    const string string_dhcid1(encodeBase64(rdata_dhcid.getDigest()));
+    const string dhcid_txt1(encodeBase64(rdata_dhcid.getDigest()));
 
-    EXPECT_EQ(string_dhcid, string_dhcid1);
+    EXPECT_EQ(dhcid_txt, dhcid_txt1);
 }
 
 TEST_F(Rdata_DHCID_Test, compare) {
@@ -117,6 +164,6 @@ TEST_F(Rdata_DHCID_Test, compare) {
     EXPECT_GT(rdata_dhcid3.compare(rdata_dhcid2), 0);
 
     // comparison attempt between incompatible RR types should be rejected
-    EXPECT_THROW(rdata_dhcid.compare(*rdata_nomatch), bad_cast); 
+    EXPECT_THROW(rdata_dhcid.compare(*rdata_nomatch), bad_cast);
 }
 }

+ 1 - 1
src/lib/dns/tests/rdata_opt_unittest.cc

@@ -84,6 +84,6 @@ TEST_F(Rdata_OPT_Test, compare) {
                                         "rdata_opt_fromWire", 2)));
 
     // comparison attempt between incompatible RR types should be rejected
-    EXPECT_THROW(rdata_opt.compare(*RdataTest::rdata_nomatch), bad_cast); 
+    EXPECT_THROW(rdata_opt.compare(*RdataTest::rdata_nomatch), bad_cast);
 }
 }

+ 210 - 23
src/lib/dns/tests/rdata_rrsig_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -36,7 +36,7 @@ using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_RRSIG_Test : public RdataTest {
-public:
+protected:
     Rdata_RRSIG_Test() :
         rrsig_txt("A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
                   "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
@@ -46,6 +46,49 @@ public:
         rdata_rrsig(rrsig_txt)
     {}
 
+    void checkFromText_None(const string& rdata_str) {
+        checkFromText<generic::RRSIG, isc::Exception, isc::Exception>(
+            rdata_str, rdata_rrsig, false, false);
+    }
+
+    void checkFromText_InvalidText(const string& rdata_str) {
+        checkFromText<generic::RRSIG, InvalidRdataText, InvalidRdataText>(
+            rdata_str, rdata_rrsig, true, true);
+    }
+
+    void checkFromText_InvalidType(const string& rdata_str) {
+        checkFromText<generic::RRSIG, InvalidRRType, InvalidRRType>(
+            rdata_str, rdata_rrsig, true, true);
+    }
+
+    void checkFromText_InvalidTime(const string& rdata_str) {
+        checkFromText<generic::RRSIG, InvalidTime, InvalidTime>(
+            rdata_str, rdata_rrsig, true, true);
+    }
+
+    void checkFromText_BadValue(const string& rdata_str) {
+        checkFromText<generic::RRSIG, BadValue, BadValue>(
+            rdata_str, rdata_rrsig, true, true);
+    }
+
+    void checkFromText_LexerError(const string& rdata_str) {
+        checkFromText
+            <generic::RRSIG, InvalidRdataText, MasterLexer::LexerError>(
+                rdata_str, rdata_rrsig, true, true);
+    }
+
+    void checkFromText_MissingOrigin(const string& rdata_str) {
+        checkFromText
+            <generic::RRSIG, MissingNameOrigin, MissingNameOrigin>(
+                rdata_str, rdata_rrsig, true, true);
+    }
+
+    void checkFromText_BadString(const string& rdata_str) {
+        checkFromText
+            <generic::RRSIG, InvalidRdataText, isc::Exception>(
+                rdata_str, rdata_rrsig, true, false);
+    }
+
     const string rrsig_txt;
     const generic::RRSIG rdata_rrsig;
 };
@@ -53,52 +96,196 @@ public:
 TEST_F(Rdata_RRSIG_Test, fromText) {
     EXPECT_EQ(rrsig_txt, rdata_rrsig.toText());
     EXPECT_EQ(isc::dns::RRType::A(), rdata_rrsig.typeCovered());
+
+    // Missing signature is OK
+    EXPECT_NO_THROW(const generic::RRSIG sig(
+              "A 5 4 43200 20100223214617 20100222214617 8496 isc.org."));
+
+    // Space in signature data is OK
+    checkFromText_None(
+              "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+              "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz "
+              "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/ "
+              "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU "
+              "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+
+    // Multi-line signature data is OK, if enclosed in parentheses
+    checkFromText_None(
+              "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+              "( evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz\n"
+              "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/\n"
+              "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU\n"
+              "f49t+sXKPzbipN9g+s1ZPiIyofc= )");
+
+    // Trailing garbage. This should cause only the string constructor
+    // to fail, but the lexer constructor must be able to continue
+    // parsing from it.
+    checkFromText_BadString(
+              "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+              "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+              "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+              "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+              "f49t+sXKPzbipN9g+s1ZPiIyofc= ; comment\n"
+              "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+              "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+              "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+              "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+              "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_missingFields) {
+    checkFromText_LexerError("A");
+    checkFromText_LexerError("A 5");
+    checkFromText_LexerError("A 5 4");
+    checkFromText_LexerError("A 5 4 43200");
+    checkFromText_LexerError("A 5 4 43200 20100223214617");
+    checkFromText_LexerError("A 5 4 43200 20100223214617 20100222214617");
+    checkFromText_LexerError("A 5 4 43200 20100223214617 20100222214617 "
+                              "8496");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_coveredType) {
+    checkFromText_InvalidType("SPORK");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_algorithm) {
+    checkFromText_InvalidText(
+                     "A 555 4 43200 "
+                     "20100223214617 20100222214617 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    checkFromText_LexerError(
+                     "A FIVE 4 43200 "
+                     "20100223214617 20100222214617 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
 }
 
-TEST_F(Rdata_RRSIG_Test, badText) {
-    EXPECT_THROW(const generic::RRSIG sig("SPORK"), InvalidRdataText);
-    EXPECT_THROW(const generic::RRSIG sig("A 555 4 43200 "
+TEST_F(Rdata_RRSIG_Test, badText_labels) {
+    checkFromText_InvalidText(
+                     "A 5 4444 43200 "
                      "20100223214617 20100222214617 8496 isc.org. "
                      "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
                      "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
                      "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-                     "f49t+sXKPzbipN9g+s1ZPiIyofc="), InvalidRdataText);
-    EXPECT_THROW(const generic::RRSIG sig("A 5 4444 43200 "
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    checkFromText_LexerError(
+                     "A 5 FOUR 43200 "
                      "20100223214617 20100222214617 8496 isc.org. "
                      "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
                      "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
                      "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-                     "f49t+sXKPzbipN9g+s1ZPiIyofc="), InvalidRdataText);
-    EXPECT_THROW(const generic::RRSIG sig("A 5 4 999999999999 "
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_ttl) {
+    checkFromText_LexerError(
+                     "A 5 4 999999999999 "
                      "20100223214617 20100222214617 8496 isc.org. "
                      "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
                      "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
                      "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-                     "f49t+sXKPzbipN9g+s1ZPiIyofc="), InvalidRdataText);
-    EXPECT_THROW(const generic::RRSIG sig("A 5 4 43200 "
-                     "20100223 20100227 8496 isc.org. "
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    checkFromText_LexerError(
+                     "A 5 4 TTL "
+                     "20100223214617 20100222214617 8496 isc.org. "
                      "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
                      "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
                      "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-                     "f49t+sXKPzbipN9g+s1ZPiIyofc="), InvalidTime);
-    EXPECT_THROW(const generic::RRSIG sig("A 5 4 43200 "
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+
+    // alternate form of TTL is not okay
+    checkFromText_LexerError(
+              "A 5 4 12H 20100223214617 20100222214617 8496 isc.org. "
+              "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz "
+              "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/ "
+              "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU "
+              "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_expiration) {
+    checkFromText_InvalidTime(
+                     "A 5 4 43200 "
+                     "201002232 20100222214617 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    checkFromText_InvalidTime(
+                     "A 5 4 43200 "
+                     "EXPIRATION 20100222214617 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_inception) {
+    checkFromText_InvalidTime(
+                     "A 5 4 43200 "
+                     "20100223214617 20100227 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    checkFromText_InvalidTime(
+                     "A 5 4 43200 "
+                     "20100223214617 INCEPTION 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_keytag) {
+    checkFromText_InvalidText(
+                     "A 5 4 43200 "
                      "20100223214617 20100222214617 999999 isc.org. "
                      "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
                      "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
                      "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-                     "f49t+sXKPzbipN9g+s1ZPiIyofc="), InvalidRdataText);
-    EXPECT_THROW(const generic::RRSIG sig(
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    checkFromText_LexerError(
                      "A 5 4 43200 "
-                     "20100223214617 20100222214617 8496 isc.org. "
-                     "EEeeeeeeEEEeeeeeeGaaahAAAAAAAAHHHHHHHHHHH!="),
-                 BadValue);     // bad base64 input
+                     "20100223214617 20100222214617 TAG isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+}
+
+TEST_F(Rdata_RRSIG_Test, badText_signer) {
+    checkFromText_MissingOrigin(
+                     "A 5 4 43200 "
+                     "20100223214617 20100222214617 8496 isc.org "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
 }
 
-TEST_F(Rdata_RRSIG_Test, DISABLED_badText) {
-    // this currently fails
+TEST_F(Rdata_RRSIG_Test, badText_signature) {
+    checkFromText_BadValue(
+                     "A 5 4 43200 "
+                     "20100223214617 20100222214617 8496 isc.org. "
+                     "EEeeeeeeEEEeeeeeeGaaahAAAAAAAAHHHHHHHHHHH!=");
+
     // no space between the tag and signer
-    EXPECT_THROW(generic::RRSIG("A 5 4 43200 20100223214617 20100222214617 "
-                                "8496isc.org. ofc="), InvalidRdataText);
+    checkFromText_LexerError(
+                     "A 5 4 43200 20100223214617 20100222214617 "
+                     "8496isc.org. ofc=");
+
+    // unterminated multi-line base64
+    checkFromText_LexerError(
+              "A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
+              "( evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz\n"
+              "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/\n"
+              "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU\n"
+              "f49t+sXKPzbipN9g+s1ZPiIyofc=");
 }
 
 TEST_F(Rdata_RRSIG_Test, createFromLexer) {

+ 3 - 3
src/lib/dns/tests/rrcollator_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  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
@@ -59,10 +59,10 @@ protected:
         txt_rdata_(createRdata(RRType::TXT(), rrclass_, "test")),
         sig_rdata1_(createRdata(RRType::RRSIG(), rrclass_,
                                 "A 5 3 3600 20000101000000 20000201000000 "
-                                "12345 example.com. FAKE\n")),
+                                "12345 example.com. FAKE")),
         sig_rdata2_(createRdata(RRType::RRSIG(), rrclass_,
                                 "NS 5 3 3600 20000101000000 20000201000000 "
-                                "12345 example.com. FAKE\n"))
+                                "12345 example.com. FAKE"))
     {}
 
     void checkRRset(const Name& expected_name, const RRClass& expected_class,

+ 2 - 2
src/lib/dns/tests/rrset_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2013  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
@@ -289,7 +289,7 @@ protected:
         rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
                                          RRType::RRSIG(), RRTTL(3600)));
         rrset_rrsig->addRdata(generic::RRSIG("AAAA 5 3 7200 20100322084538 "
-                                             "20100220084538 1 example.com "
+                                             "20100220084538 1 example.com. "
                                              "FAKEFAKEFAKEFAKE"));
         rrset_aaaa->addRRsig(rrset_rrsig);
     }