diff options
author | Mukund Sivaraman <muks@isc.org> | 2014-02-20 04:07:25 +0100 |
---|---|---|
committer | Mukund Sivaraman <muks@isc.org> | 2014-02-20 04:07:25 +0100 |
commit | cdcedf7fadf4f3021b86be152a6b009f3be8fcc0 (patch) | |
tree | d5233d90d66f985d21b539e98849ede767beabc7 /src/lib/dns | |
parent | [2534] Support some minor cases for quoted character strings (compatibility w... (diff) | |
parent | Merge branch 'trac2000' (diff) | |
download | kea-cdcedf7fadf4f3021b86be152a6b009f3be8fcc0.tar.xz kea-cdcedf7fadf4f3021b86be152a6b009f3be8fcc0.zip |
Merge branch 'master' into trac2534
Diffstat (limited to 'src/lib/dns')
125 files changed, 4728 insertions, 853 deletions
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am index bda4e85333..7691d31324 100644 --- a/src/lib/dns/Makefile.am +++ b/src/lib/dns/Makefile.am @@ -70,12 +70,16 @@ EXTRA_DIST += rdata/generic/spf_99.cc EXTRA_DIST += rdata/generic/spf_99.h EXTRA_DIST += rdata/generic/sshfp_44.cc EXTRA_DIST += rdata/generic/sshfp_44.h +EXTRA_DIST += rdata/generic/tlsa_52.cc +EXTRA_DIST += rdata/generic/tlsa_52.h EXTRA_DIST += rdata/generic/txt_16.cc EXTRA_DIST += rdata/generic/txt_16.h EXTRA_DIST += rdata/generic/minfo_14.cc EXTRA_DIST += rdata/generic/minfo_14.h EXTRA_DIST += rdata/generic/afsdb_18.cc EXTRA_DIST += rdata/generic/afsdb_18.h +EXTRA_DIST += rdata/generic/caa_257.cc +EXTRA_DIST += rdata/generic/caa_257.h EXTRA_DIST += rdata/hs_4/a_1.cc EXTRA_DIST += rdata/hs_4/a_1.h EXTRA_DIST += rdata/in_1/a_1.cc @@ -135,6 +139,7 @@ libb10_dns___la_SOURCES += master_loader.h libb10_dns___la_SOURCES += rrset_collection_base.h libb10_dns___la_SOURCES += rrset_collection.h rrset_collection.cc libb10_dns___la_SOURCES += zone_checker.h zone_checker.cc +libb10_dns___la_SOURCES += rdata_pimpl_holder.h libb10_dns___la_SOURCES += rdata/generic/detail/char_string.h libb10_dns___la_SOURCES += rdata/generic/detail/char_string.cc libb10_dns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h @@ -158,7 +163,7 @@ rrclass.h: rrclass-placeholder.h rrtype.h: rrtype-placeholder.h rrparamregistry.cc: rrparamregistry-placeholder.cc -s-rdatacode: Makefile +s-rdatacode: Makefile $(EXTRA_DIST) $(PYTHON) ./gen-rdatacode.py touch $@ diff --git a/src/lib/dns/exceptions.h b/src/lib/dns/exceptions.h index 070b152c2b..21030b49c2 100644 --- a/src/lib/dns/exceptions.h +++ b/src/lib/dns/exceptions.h @@ -30,10 +30,34 @@ namespace dns { /// class Rcode; // forward declaration -class DNSProtocolError : public isc::Exception { +class Exception : public isc::Exception { public: - DNSProtocolError(const char* file, size_t line, const char* what) : + Exception(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) {} +}; + +/// +/// \brief Base class for all sorts of text parse errors. +/// +class DNSTextError : public isc::dns::Exception { +public: + DNSTextError(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// \brief Base class for name parser exceptions. +/// +class NameParserException : public DNSTextError { +public: + NameParserException(const char* file, size_t line, const char* what) : + DNSTextError(file, line, what) {} +}; + +class DNSProtocolError : public isc::dns::Exception { +public: + DNSProtocolError(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} virtual const Rcode& getRcode() const = 0; }; @@ -50,6 +74,7 @@ public: DNSProtocolError(file, line, what) {} virtual const Rcode& getRcode() const; }; + } } #endif // DNS_EXCEPTIONS_H diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in index 3fd3b33112..1cb1e37da1 100755 --- a/src/lib/dns/gen-rdatacode.py.in +++ b/src/lib/dns/gen-rdatacode.py.in @@ -41,9 +41,9 @@ meta_types = { '10': 'null', '11': 'wks', '19': 'x25', '21': 'rt', '22': 'nsap', '23': 'nsap-ptr', '24': 'sig', '20': 'isdn', '25': 'key', '26': 'px', '27': 'gpos', '29': 'loc', '36': 'kx', '37': 'cert', '42': 'apl', - '45': 'ipseckey', '52': 'tlsa', '55': 'hip', '103': 'unspec', + '45': 'ipseckey', '55': 'hip', '103': 'unspec', '104': 'nid', '105': 'l32', '106': 'l64', '107': 'lp', '249': 'tkey', - '253': 'mailb', '256': 'uri', '257': 'caa' + '253': 'mailb', '256': 'uri' } # Classes that don't have any known types. This is a dict from type code # values (as string) to textual mnemonic. diff --git a/src/lib/dns/labelsequence.cc b/src/lib/dns/labelsequence.cc index f5f6a95a1b..91af63372d 100644 --- a/src/lib/dns/labelsequence.cc +++ b/src/lib/dns/labelsequence.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2014 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 <config.h> + #include <dns/labelsequence.h> #include <dns/name_internal.h> #include <exceptions/exceptions.h> @@ -24,24 +26,34 @@ namespace isc { namespace dns { LabelSequence::LabelSequence(const void* buf) { +#ifdef ENABLE_DEBUG + // In non-debug mode, derefencing the NULL pointer further below + // will lead to a crash, so disabling this check is not + // unsafe. Except for a programming mistake, this case should not + // happen. if (buf == NULL) { isc_throw(BadValue, "Null pointer passed to LabelSequence constructor"); } +#endif const uint8_t* bp = reinterpret_cast<const uint8_t*>(buf); - first_label_ = 0; const uint8_t offsets_len = *bp++; + +#ifdef ENABLE_DEBUG if (offsets_len == 0 || offsets_len > Name::MAX_LABELS) { isc_throw(BadValue, "Bad offsets len in serialized LabelSequence data: " << static_cast<unsigned int>(offsets_len)); } +#endif + last_label_ = offsets_len - 1; offsets_ = bp; data_ = bp + offsets_len; +#ifdef ENABLE_DEBUG // Check the integrity on the offsets and the name data const uint8_t* dp = data_; for (size_t cur_offset = 0; cur_offset < offsets_len; ++cur_offset) { @@ -52,6 +64,7 @@ LabelSequence::LabelSequence(const void* buf) { } dp += (1 + *dp); } +#endif } LabelSequence::LabelSequence(const LabelSequence& src, diff --git a/src/lib/dns/master_lexer.h b/src/lib/dns/master_lexer.h index 650368181c..33c0567b08 100644 --- a/src/lib/dns/master_lexer.h +++ b/src/lib/dns/master_lexer.h @@ -15,7 +15,7 @@ #ifndef MASTER_LEXER_H #define MASTER_LEXER_H 1 -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> #include <istream> #include <string> @@ -325,10 +325,10 @@ public: /// /// The \c token_ member variable (read-only) is set to a \c MasterToken /// object of type ERROR indicating the reason for the error. - class LexerError : public Exception { + class LexerError : public isc::dns::Exception { public: LexerError(const char* file, size_t line, MasterToken error_token) : - Exception(file, line, error_token.getErrorText().c_str()), + isc::dns::Exception(file, line, error_token.getErrorText().c_str()), token_(error_token) {} const MasterToken token_; diff --git a/src/lib/dns/master_loader.cc b/src/lib/dns/master_loader.cc index 6b6e091489..80b1053432 100644 --- a/src/lib/dns/master_loader.cc +++ b/src/lib/dns/master_loader.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2014 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 @@ -21,14 +21,16 @@ #include <dns/rrtype.h> #include <dns/rdata.h> -#include <boost/scoped_ptr.hpp> +#include <boost/format.hpp> #include <boost/algorithm/string/predicate.hpp> // for iequals +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> #include <string> #include <memory> #include <vector> -#include <boost/algorithm/string/predicate.hpp> // for iequals -#include <boost/shared_ptr.hpp> + +#include <cstdio> // for sscanf() using std::string; using std::auto_ptr; @@ -54,9 +56,34 @@ public: } // end unnamed namespace +/// \brief Private implementation class for the \c MasterLoader +/// +/// This class is used internally by the \c MasterLoader and is not +/// publicly visible. It is present to avoid polluting the public API +/// with internal implementation details of the \c MasterLoader. // cppcheck-suppress noConstructor class MasterLoader::MasterLoaderImpl { public: + /// \brief Constructor. + /// + /// \param master_file Path to the file to load. + /// \param zone_origin The origin of zone to be expected inside + /// the master file. Currently unused, but it is expected to + /// be used for some validation. + /// \param zone_class The class of zone to be expected inside the + /// master file. + /// \param callbacks The callbacks by which it should report problems. + /// Usually, the callback carries a filename and line number of the + /// input where the problem happens. There's a special case of empty + /// filename and zero line in case the opening of the top-level master + /// file fails. + /// \param add_callback The callback which would be called with each + /// loaded RR. + /// \param options Options for the parsing, which is bitwise-or of + /// the Options values or DEFAULT. If the MANY_ERRORS option is + /// included, the parser tries to continue past errors. If it + /// is not included, it stops at first encountered error. + /// \throw std::bad_alloc when there's not enough memory. MasterLoaderImpl(const char* master_file, const Name& zone_origin, const RRClass& zone_class, @@ -81,6 +108,16 @@ public: rr_count_(0) {} + /// \brief Wrapper around \c MasterLexer::pushSource() (file version) + /// + /// This method is used as a wrapper around the lexer's + /// \c pushSource() to also save the current origin and the last + /// seen name (to be restored upon \c popSource()). It also calls + /// \c pushSource(). See \c doInclude() implementation for more + /// details. + /// + /// \param filename Path to the file to push as a new source. + /// \param current_origin The current origin name to save. void pushSource(const std::string& filename, const Name& current_origin) { std::string error; if (!lexer_.pushSource(filename.c_str(), &error)) { @@ -98,17 +135,35 @@ public: previous_name_ = false; } + /// \brief Wrapper around \c MasterLexer::pushSource() (stream version) + /// + /// Similar to \c pushSource(). This method need not save the + /// current origin as it is not used with $INCLUDE processing. + /// + /// \param stream The input stream to use as a new source. void pushStreamSource(std::istream& stream) { lexer_.pushSource(stream); initialized_ = true; } + /// \brief Implementation of \c MasterLoader::loadIncremental() + /// + /// See \c MasterLoader::loadIncremental() for details. bool loadIncremental(size_t count_limit); + /// \brief Return the total size of the input sources pushed so + /// far. See \c MasterLexer::getTotalSourceSize(). size_t getSize() const { return (lexer_.getTotalSourceSize()); } + + /// \brief Return the line number being parsed in the pushed input + /// sources. See \c MasterLexer::getPosition(). size_t getPosition() const { return (lexer_.getPosition()); } private: + /// \brief Report an error using the callbacks that were supplied + /// during \c MasterLoader construction. Note that this method also + /// throws \c MasterLoaderError exception if necessary, so the + /// caller need not throw it. void reportError(const std::string& filename, size_t line, const std::string& reason) { @@ -123,6 +178,12 @@ private: } } + /// \brief Wrapper around \c MasterLexer::popSource() + /// + /// This method is used as a wrapper around the lexer's + /// \c popSource() to also restore the current origin and the last + /// seen name (at time of push). It also calls \c popSource(). See + /// \c doInclude() implementation for more details. bool popSource() { if (lexer_.getSourceCount() == 1) { return (false); @@ -141,14 +202,43 @@ private: return (true); } - // Get a string token. Handle it as error if it is not string. + /// \brief Get a string token. Handle it as error if it is not string. const string getString() { lexer_.getNextToken(MasterToken::STRING).getString(string_token_); return (string_token_); } + /// \brief Parse the initial token at the beginning of a line in a + /// master file (or stream). + /// + /// A helper method of \c loadIncremental(), parsing the first token + /// of a new line. If it looks like an RR, detect its owner name + /// and return a string token for the next field of the RR. + /// + /// Otherwise, return either \c END_OF_LINE or \c END_OF_FILE token + /// depending on whether the loader continues to the next line or + /// completes the load, respectively. Other corner cases including + /// $-directive handling is done here. + /// + /// For unexpected errors, it throws an exception, which will be + /// handled in \c loadIncremental(). MasterToken handleInitialToken(); + /// \brief Helper method for \c doGenerate(). + /// + /// This is a helper method for \c doGenerate() that processes the + /// LHS or RHS for a single iteration in the range that is requested + /// by the $GENERATE directive and returns a generated string (that + /// is used to build a name (LHS) or RDATA (RHS) for an RR). See the + /// commented implementation for details. + std::string generateForIter(const std::string& str, const int it); + + /// \brief Process the $GENERATE directive. + /// + /// See the commented implementation for details. + void doGenerate(); + + /// \brief Process the $ORIGIN directive. void doOrigin(bool is_optional) { // Parse and create the new origin. It is relative to the previous // one. @@ -181,6 +271,7 @@ private: } } + /// \brief Process the $INCLUDE directive. void doInclude() { // First, get the filename to include const string @@ -201,11 +292,16 @@ private: pushSource(filename, current_origin); } - // A helper method for loadIncremental(). It parses part of an RR - // until it finds the RR type field. If TTL or RR class is - // specified before the RR type, it also recognizes and validates - // them. explicit_ttl will be set to true if this method finds a - // valid TTL field. + /// \brief Parse RR fields (TTL, CLASS and TYPE). + /// + /// A helper method for \c loadIncremental(). It parses part of an + /// RR until it finds the RR type field. If TTL or RR class is + /// specified before the RR type, it also recognizes and validates + /// them. + /// + /// \param explicit_ttl will be set to true if this method finds a + /// valid TTL field. + /// \param rrparam_token Pass the current (parsed) token here. RRType parseRRParams(bool& explicit_ttl, MasterToken rrparam_token) { // Find TTL, class and type. Both TTL and class are // optional and may occur in any order if they exist. TTL @@ -245,20 +341,25 @@ private: return (RRType(rrparam_token.getString())); } - // Upper limit check when recognizing a specific TTL value from the - // zone file ($TTL, the RR's TTL field, or the SOA minimum). RFC2181 - // Section 8 limits the range of TTL values to 2^31-1 (0x7fffffff), - // and prohibits transmitting a TTL field exceeding this range. We - // guarantee that by limiting the value at the time of zone - // parsing/loading, following what BIND 9 does. Resetting it to 0 - // at this point may not be exactly what the RFC states (depending on - // the meaning of 'received'), but the end result would be the same (i.e., - // the guarantee on transmission). Again, we follow the BIND 9's behavior - // here. - // - // post_parsing is true iff this method is called after parsing the entire - // RR and the lexer is positioned at the next line. It's just for - // calculating the accurate source line when callback is necessary. + /// \brief Check and limit TTL to maximum value. + /// + /// Upper limit check when recognizing a specific TTL value from the + /// zone file ($TTL, the RR's TTL field, or the SOA minimum). RFC2181 + /// Section 8 limits the range of TTL values to 2^31-1 (0x7fffffff), + /// and prohibits transmitting a TTL field exceeding this range. We + /// guarantee that by limiting the value at the time of zone + /// parsing/loading, following what BIND 9 does. Resetting it to 0 + /// at this point may not be exactly what the RFC states (depending on + /// the meaning of 'received'), but the end result would be the same (i.e., + /// the guarantee on transmission). Again, we follow the BIND 9's behavior + /// here. + /// + /// \param ttl the TTL to check. If it is larger than the maximum + /// allowed, it is set to 0. + /// \param post_parsing should be true iff this method is called + /// after parsing the entire RR and the lexer is positioned at the + /// next line. It's just for calculating the accurate source line + /// when callback is necessary. void limitTTL(RRTTL& ttl, bool post_parsing) { if (ttl > RRTTL::MAX_TTL()) { const size_t src_line = lexer_.getSourceLine() - @@ -270,19 +371,25 @@ private: } } - // Set/reset the default TTL. This should be from either $TTL or SOA - // minimum TTL (it's the caller's responsibility; this method doesn't - // care about where it comes from). see LimitTTL() for parameter - // post_parsing. + /// \brief Set/reset the default TTL. + /// + /// This should be from either $TTL or SOA minimum TTL (it's the + /// caller's responsibility; this method doesn't care about where it + /// comes from). See \c limitTTL() for parameter post_parsing. void setDefaultTTL(const RRTTL& ttl, bool post_parsing) { assignTTL(default_ttl_, ttl); limitTTL(*default_ttl_, post_parsing); } - // Try to set/reset the current TTL from candidate TTL text. It's possible - // it does not actually represent a TTL (which is not immediately - // considered an error). Return true iff it's recognized as a valid TTL - // (and only in which case the current TTL is set). + /// \brief Try to set/reset the current TTL from candidate TTL text. + /// + /// It's possible it that the text does not actually represent a TTL + /// (which is not immediately considered an error). Returns \c true + /// iff it's recognized as a valid TTL (and only in which case the + /// current TTL is set). + /// + /// \param ttl_txt The text to parse as a TTL. + /// \return true if a TTL was parsed (and set as the current TTL). bool setCurrentTTL(const string& ttl_txt) { // We use the factory version instead of RRTTL constructor as we // need to expect cases where ttl_txt does not actually represent a TTL @@ -296,14 +403,15 @@ private: return (false); } - // Determine the TTL of the current RR based on the given parsing context. - // - // explicit_ttl is true iff the TTL is explicitly specified for that RR - // (in which case current_ttl_ is set to that TTL). - // rrtype is the type of the current RR, and rdata is its RDATA. They - // only matter if the type is SOA and no available TTL is known. In this - // case the minimum TTL of the SOA will be used as the TTL of that SOA - // and the default TTL for subsequent RRs. + /// \brief Determine the TTL of the current RR based on the given + /// parsing context. + /// + /// \c explicit_ttl is true iff the TTL is explicitly specified for that RR + /// (in which case current_ttl_ is set to that TTL). + /// \c rrtype is the type of the current RR, and \c rdata is its RDATA. They + /// only matter if the type is SOA and no available TTL is known. In this + /// case the minimum TTL of the SOA will be used as the TTL of that SOA + /// and the default TTL for subsequent RRs. const RRTTL& getCurrentTTL(bool explicit_ttl, const RRType& rrtype, const rdata::ConstRdataPtr& rdata) { // We've completed parsing the full of RR, and the lexer is already @@ -342,12 +450,19 @@ private: return (*current_ttl_); } + /// \brief Handle a $DIRECTIVE + /// + /// This method is called when a $DIRECTIVE is encountered in the + /// input stream. void handleDirective(const char* directive, size_t length) { if (iequals(directive, "INCLUDE")) { doInclude(); } else if (iequals(directive, "ORIGIN")) { doOrigin(false); eatUntilEOL(true); + } else if (iequals(directive, "GENERATE")) { + doGenerate(); + eatUntilEOL(true); } else if (iequals(directive, "TTL")) { setDefaultTTL(RRTTL(getString()), false); eatUntilEOL(true); @@ -357,6 +472,7 @@ private: } } + /// \brief Skip tokens until end-of-line. void eatUntilEOL(bool reportExtra) { // We want to continue. Try to read until the end of line for (;;) { @@ -437,15 +553,320 @@ public: size_t rr_count_; // number of RRs successfully loaded }; -// A helper method of loadIncremental, parsing the first token of a new line. -// If it looks like an RR, detect its owner name and return a string token for -// the next field of the RR. -// Otherwise, return either END_OF_LINE or END_OF_FILE token depending on -// whether the loader continues to the next line or completes the load, -// respectively. Other corner cases including $-directive handling is done -// here. -// For unexpected errors, it throws an exception, which will be handled in -// loadIncremental. +namespace { // begin unnamed namespace + +/// \brief Generate a dotted nibble sequence. +/// +/// This method generates a dotted nibble sequence and returns it as a +/// string. The nibbles are appended from the least significant digit +/// (in hex representation of \c num) to the most significant digit with +/// dots ('.') to separate the digits. If \c width is non-zero and the +/// dotted nibble sequence has not filled the requested width, the rest +/// of the width is filled with a dotted nibble sequence of 0 nibbles. +/// +/// Some sample representations: +/// +/// num = 0x1234, width = 0 +/// "4.3.2.1" +/// +/// num = 0x1234, width = 1 +/// "4.3.2.1" +/// +/// num = 0x1234, width = 8 +/// "4.3.2.1" +/// +/// num = 0x1234, width = 9 +/// "4.3.2.1." +/// +/// num = 0x1234, width = 10 +/// "4.3.2.1.0" +/// +/// num = 0x1234, width = 11 +/// "4.3.2.1.0." +/// +/// num = 0xabcd, width = 0, uppercase = true +/// "D.C.B.A" +/// +/// num = 0, width = 0 +/// "0" +/// +/// num = 0, width = 1 +/// "0" +/// +/// num = 0, width = 2 +/// "0." +/// +/// num = 0, width = 3 +/// "0.0" +/// +/// \param num The number for which the dotted nibble sequence should be +/// generated. +/// \param width The width of the generated string. This is only +/// meaningful when it is larger than the dotted nibble sequence +/// representation of \c num. +/// \param uppercase Whether to use uppercase characters in nibble +/// sequence. +/// \return A string containing the dotted nibble sequence. +std::string +genNibbles(int num, unsigned int width, bool uppercase) { + static const char *hex = "0123456789abcdef0123456789ABCDEF"; + std::string rstr; + + do { + char ch = hex[(num & 0x0f) + (uppercase ? 16 : 0)]; + num >>= 4; + rstr.push_back(ch); + + if (width > 0) { + --width; + } + + // If width is non zero then we need to add a label separator. + // If value is non zero then we need to add another label and + // that requires a label separator. + if (width > 0 || num != 0) { + rstr.push_back('.'); + + if (width > 0) { + --width; + } + } + } while ((num != 0) || (width > 0)); + + return (rstr); +} + +} // end unnamed namespace + +std::string +MasterLoader::MasterLoaderImpl::generateForIter(const std::string& str, + const int num) +{ + std::string rstr; + + for (std::string::const_iterator it = str.begin(); it != str.end();) { + switch (*it) { + case '$': + // This is the case when the '$' character is encountered in + // the LHS or RHS. A computed value is added in its place in + // the generated string. + ++it; + if ((it != str.end()) && (*it == '$')) { + rstr.push_back('$'); + ++it; + continue; + } + + // 'it' can be equal to str.end() here, but it is handled + // correctly. + if (*it != '{') { + // There is no modifier (between {}), so just copy the + // passed number into the generated string. + rstr += boost::str(boost::format("%d") % num); + } else { + // There is a modifier (between {}). Parse it and handle + // the various cases below. + const char* scan_str = + str.c_str() + std::distance(str.begin(), it); + int offset = 0; + unsigned int width; + char base[2] = {'d', 0}; // char plus null byte + // cppcheck-suppress invalidscanf + const int n = sscanf(scan_str, "{%d,%u,%1[doxXnN]}", + &offset, &width, base); + switch (n) { + case 1: + // Only 1 item was matched (the offset). Copy (num + + // offset) into the generated string. + rstr += boost::str(boost::format("%d") % (num + offset)); + break; + + case 2: { + // 2 items were matched (the offset and width). Copy + // (num + offset) and format it according to the width + // into the generated string. + const std::string fmt = + boost::str(boost::format("%%0%ud") % width); + rstr += boost::str(boost::format(fmt) % (num + offset)); + break; + } + + case 3: + // 3 items were matched (offset, width and base). + if ((base[0] == 'n') || (base[0] == 'N')) { + // The base is requesting nibbles. Format it + // specially (see genNibbles() documentation). + rstr += genNibbles(num + offset, width, (base[0] == 'N')); + } else { + // The base is not requesting nibbles. Copy (num + + // offset) and format it according to the width + // and base into the generated string. + const std::string fmt = + boost::str(boost::format("%%0%u%c") % width % base[0]); + rstr += boost::str(boost::format(fmt) % (num + offset)); + } + break; + + default: + // Any other case in the modifiers is an error. + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + "Invalid $GENERATE format modifiers"); + return (""); + } + + // Find the closing brace. Careful that 'it' can be equal + // to str.end() here. + while ((it != str.end()) && (*it != '}')) { + ++it; + } + // Skip past the closing brace (if there is one). + if (it != str.end()) { + ++it; + } + } + break; + + case '\\': + // This is the case when the '\' character is encountered in + // the LHS or RHS. The '\' and the following character are + // copied as-is into the generated string. This is usually + // used for escaping the $ character. + rstr.push_back(*it); + ++it; + if (it == str.end()) { + continue; + } + rstr.push_back(*it); + ++it; + break; + + default: + // This is the default case that handles all other + // characters. They are copied as-is into the generated + // string. + rstr.push_back(*it); + ++it; + break; + } + } + + return (rstr); +} + +void +MasterLoader::MasterLoaderImpl::doGenerate() { + // Parse the range token + const MasterToken& range_token = lexer_.getNextToken(MasterToken::STRING); + if (range_token.getType() != MasterToken::STRING) { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + "Invalid $GENERATE syntax"); + return; + } + const std::string range = range_token.getString(); + + // Parse the LHS token + const MasterToken& lhs_token = lexer_.getNextToken(MasterToken::STRING); + if (lhs_token.getType() != MasterToken::STRING) { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + "Invalid $GENERATE syntax"); + return; + } + const std::string lhs = lhs_token.getString(); + + // Parse the TTL, RR class and RR type tokens. Note that TTL and RR + // class may come in any order, or may be missing (either or + // both). If TTL is missing, we expect that it was either specified + // explicitly using $TTL, or is implicitly known from a previous RR, + // or that this is the SOA RR from which the MINIMUM field is + // used. It's unlikely that $GENERATE will be used with an SOA RR, + // but it's possible. The parsing happens within the parseRRParams() + // helper method which is called below. + const MasterToken& param_token = lexer_.getNextToken(MasterToken::STRING); + if (param_token.getType() != MasterToken::STRING) { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + "Invalid $GENERATE syntax"); + return; + } + + bool explicit_ttl = false; + const RRType rrtype = parseRRParams(explicit_ttl, param_token); + + // Parse the RHS token. It can be a quoted string. + const MasterToken& rhs_token = lexer_.getNextToken(MasterToken::QSTRING); + if ((rhs_token.getType() != MasterToken::QSTRING) && + (rhs_token.getType() != MasterToken::STRING)) + { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + "Invalid $GENERATE syntax"); + return; + } + const std::string rhs = rhs_token.getString(); + + // Range can be one of two forms: start-stop or start-stop/step. If + // the first form is used, then step is set to 1. All of start, stop + // and step must be positive. + unsigned int start; + unsigned int stop; + unsigned int step; + // cppcheck-suppress invalidscanf + const int n = sscanf(range.c_str(), "%u-%u/%u", &start, &stop, &step); + if ((n < 2) || (stop < start)) { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + "$GENERATE: invalid range: " + range); + return; + } + + if (n == 2) { + step = 1; + } + + // Generate and add the records. + for (int i = start; i <= stop; i += step) { + // Get generated strings for LHS and RHS. LHS goes to form the + // name, RHS goes to form the RDATA of the RR. + const std::string generated_name = generateForIter(lhs, i); + const std::string generated_rdata = generateForIter(rhs, i); + if (generated_name.empty() || generated_rdata.empty()) { + // The error should have been sent to the callbacks already + // by generateForIter(). + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + "$GENERATE error"); + return; + } + + // generateForIter() can return a string with a trailing '.' in + // case of a nibble representation. So we cannot use the + // relative Name constructor. We use concatenate() which is + // expensive, but keeps the generated LHS-based Name within the + // active origin. + last_name_.reset + (new Name(Name(generated_name).concatenate(active_origin_))); + previous_name_ = true; + + const rdata::RdataPtr rdata = + rdata::createRdata(rrtype, zone_class_, generated_rdata); + // In case we get NULL, it means there was error creating the + // Rdata. The errors should have been reported by callbacks_ + // already. We need to decide if we want to continue or not. + if (rdata) { + add_callback_(*last_name_, zone_class_, rrtype, + getCurrentTTL(explicit_ttl, rrtype, rdata), + rdata); + // Good, we added another one + ++rr_count_; + } else { + seen_error_ = true; + if (!many_errors_) { + ok_ = false; + complete_ = true; + // We don't have the exact error here, but it was + // reported by the error callback. + isc_throw(MasterLoaderError, "Invalid RR data"); + } + } + } +} + MasterToken MasterLoader::MasterLoaderImpl::handleInitialToken() { const MasterToken& initial_token = @@ -576,15 +997,19 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) { isc_throw(MasterLoaderError, "Invalid RR data"); } } - } catch (const MasterLoaderError&) { - // This is a hack. We exclude the MasterLoaderError from the - // below case. Once we restrict the below to some smaller - // exception, we should remove this. - throw; - } catch (const isc::Exception& e) { - // TODO: Once we do #2518, catch only the DNSTextError here, - // not isc::Exception. The rest should be just simply - // propagated. + } catch (const isc::dns::DNSTextError& e) { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + e.what()); + eatUntilEOL(false); + } catch (const MasterLexer::ReadError& e) { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + e.what()); + eatUntilEOL(false); + } catch (const MasterLexer::LexerError& e) { + reportError(lexer_.getSourceName(), lexer_.getSourceLine(), + e.what()); + eatUntilEOL(false); + } catch (const InternalException& e) { reportError(lexer_.getSourceName(), lexer_.getSourceLine(), e.what()); eatUntilEOL(false); diff --git a/src/lib/dns/message.cc b/src/lib/dns/message.cc index 2bc337ad6f..33cd07b2dc 100644 --- a/src/lib/dns/message.cc +++ b/src/lib/dns/message.cc @@ -604,13 +604,8 @@ Message::addQuestion(const Question& question) { } void -Message::toWire(AbstractMessageRenderer& renderer) { - impl_->toWire(renderer, NULL); -} - -void -Message::toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx) { - impl_->toWire(renderer, &tsig_ctx); +Message::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) { + impl_->toWire(renderer, tsig_ctx); } void @@ -620,6 +615,10 @@ Message::parseHeader(InputBuffer& buffer) { "Message parse attempted in non parse mode"); } + if (impl_->header_parsed_) { + return; + } + if ((buffer.getLength() - buffer.getPosition()) < HEADERLEN) { isc_throw(MessageTooShort, "Malformed DNS message (short length): " << buffer.getLength() - buffer.getPosition()); @@ -645,9 +644,11 @@ Message::fromWire(InputBuffer& buffer, ParseOptions options) { "Message parse attempted in non parse mode"); } - if (!impl_->header_parsed_) { - parseHeader(buffer); - } + // Clear any old parsed data + clear(Message::PARSE); + + buffer.setPosition(0); + parseHeader(buffer); impl_->counts_[SECTION_QUESTION] = impl_->parseQuestion(buffer); impl_->counts_[SECTION_ANSWER] = diff --git a/src/lib/dns/message.h b/src/lib/dns/message.h index aaa0d76982..3afad1f27a 100644 --- a/src/lib/dns/message.h +++ b/src/lib/dns/message.h @@ -21,7 +21,7 @@ #include <string> #include <ostream> -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> #include <dns/edns.h> #include <dns/question.h> @@ -41,10 +41,10 @@ class TSIGRecord; /// message parser encounters a short length of data that don't even contain /// the full header section. /// -class MessageTooShort : public Exception { +class MessageTooShort : public isc::dns::Exception { public: MessageTooShort(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; /// @@ -52,10 +52,10 @@ public: /// is being constructed for an incompatible section. Specifically, this /// happens RRset iterator is being constructed for a Question section. /// -class InvalidMessageSection : public Exception { +class InvalidMessageSection : public isc::dns::Exception { public: InvalidMessageSection(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; /// @@ -63,10 +63,10 @@ public: /// class method is called that is prohibited for the current mode of /// the message. /// -class InvalidMessageOperation : public Exception { +class InvalidMessageOperation : public isc::dns::Exception { public: InvalidMessageOperation(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; /// @@ -74,10 +74,10 @@ public: /// smaller than the standard default maximum (DEFAULT_MAX_UDPSIZE) is /// being specified for the message. /// -class InvalidMessageUDPSize : public Exception { +class InvalidMessageUDPSize : public isc::dns::Exception { public: InvalidMessageUDPSize(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; typedef uint16_t qid_t; @@ -550,29 +550,18 @@ public: std::string toText() const; /// \brief Render the message in wire formant into a message renderer - /// object. + /// object with (or without) TSIG. /// /// This \c Message must be in the \c RENDER mode and both \c Opcode and /// \c Rcode must have been set beforehand; otherwise, an exception of /// class \c InvalidMessageOperation will be thrown. /// - /// \note The renderer's internal buffers and data are automatically - /// cleared, keeping the length limit and the compression mode intact. - /// In case truncation is triggered, the renderer is cleared completely. - /// - /// \param renderer DNS message rendering context that encapsulates the - /// output buffer and name compression information. - void toWire(AbstractMessageRenderer& renderer); - - /// \brief Render the message in wire formant into a message renderer - /// object with TSIG. - /// - /// This method is similar to the other version of \c toWire(), but - /// it will also add a TSIG RR with (in many cases) the TSIG MAC for - /// the message along with the given TSIG context (\c tsig_ctx). - /// The TSIG RR will be placed at the end of \c renderer. - /// \c tsig_ctx will be updated based on the fact it was used for signing - /// and with the latest MAC. + /// If a non-NULL \c tsig_ctx is passed, it will also add a TSIG RR + /// with (in many cases) the TSIG MAC for the message along with the + /// given TSIG context (\c tsig_ctx). The TSIG RR will be placed at + /// the end of \c renderer. The \c TSIGContext at \c tsig_ctx will + /// be updated based on the fact it was used for signing and with + /// the latest MAC. /// /// \exception InvalidMessageOperation The message is not in the Render /// mode, or either Rcode or Opcode is not set. @@ -589,10 +578,12 @@ public: /// cleared, keeping the length limit and the compression mode intact. /// In case truncation is triggered, the renderer is cleared completely. /// - /// \param renderer See the other version + /// \param renderer DNS message rendering context that encapsulates the + /// output buffer and name compression information. /// \param tsig_ctx A TSIG context that is to be used for signing the /// message - void toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx); + void toWire(AbstractMessageRenderer& renderer, + TSIGContext* tsig_ctx = NULL); /// Parse options. /// @@ -607,6 +598,10 @@ public: }; /// \brief Parse the header section of the \c Message. + /// + /// NOTE: If the header has already been parsed by a previous call + /// to this method, this method simply returns (i.e., it does not + /// read from the \c buffer). void parseHeader(isc::util::InputBuffer& buffer); /// \brief (Re)build a \c Message object from wire-format data. @@ -642,7 +637,8 @@ public: /// \exception std::bad_alloc Memory allocation failure /// \exception Others \c Name, \c Rdata, and \c EDNS classes can also throw /// - /// \param buffer A input buffer object that stores the wire data + /// \param buffer A input buffer object that stores the wire + /// data. This method reads from position 0 in the passed buffer. /// \param options Parse options void fromWire(isc::util::InputBuffer& buffer, ParseOptions options = PARSE_DEFAULT); diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h index 02c868f039..7c750e3afc 100644 --- a/src/lib/dns/name.h +++ b/src/lib/dns/name.h @@ -20,7 +20,7 @@ #include <string> #include <vector> -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> namespace isc { namespace util { @@ -32,15 +32,6 @@ namespace dns { class AbstractMessageRenderer; /// -/// \brief Base class for name parser exceptions. -/// -class NameParserException : public Exception { -public: - NameParserException(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} -}; - -/// /// \brief A standard DNS module exception that is thrown if the name parser /// encounters an empty label in the middle of a name. /// diff --git a/src/lib/dns/nsec3hash.cc b/src/lib/dns/nsec3hash.cc index 0e03798268..4e6fea1ee7 100644 --- a/src/lib/dns/nsec3hash.cc +++ b/src/lib/dns/nsec3hash.cc @@ -29,8 +29,10 @@ #include <util/hash/sha1.h> #include <dns/name.h> +#include <dns/labelsequence.h> #include <dns/nsec3hash.h> #include <dns/rdataclass.h> +#include <dns/name_internal.h> using namespace std; using namespace isc::util; @@ -84,6 +86,7 @@ public: } virtual std::string calculate(const Name& name) const; + virtual std::string calculate(const LabelSequence& ls) const; virtual bool match(const generic::NSEC3& nsec3) const; virtual bool match(const generic::NSEC3PARAM& nsec3param) const; @@ -91,6 +94,8 @@ public: const vector<uint8_t>& salt) const; private: + std::string calculateForWiredata(const uint8_t* data, size_t length) const; + const uint8_t algorithm_; const uint16_t iterations_; uint8_t* salt_data_; @@ -116,19 +121,33 @@ iterateSHA1(SHA1Context* ctx, const uint8_t* input, size_t inlength, } string -NSEC3HashRFC5155::calculate(const Name& name) const { +NSEC3HashRFC5155::calculateForWiredata(const uint8_t* data, + size_t length) const +{ // We first need to normalize the name by converting all upper case // characters in the labels to lower ones. - obuf_.clear(); - Name name_copy(name); - name_copy.downcase(); - name_copy.toWire(obuf_); + + uint8_t name_buf[256]; + assert(length < sizeof (name_buf)); + + const uint8_t *p1 = data; + uint8_t *p2 = name_buf; + while (*p1 != 0) { + char len = *p1; + + *p2++ = *p1++; + while (len--) { + *p2++ = isc::dns::name::internal::maptolower[*p1++]; + } + } + + *p2 = *p1; uint8_t* const digest = &digest_[0]; assert(digest_.size() == SHA1_HASHSIZE); - iterateSHA1(&sha1_ctx_, static_cast<const uint8_t*>(obuf_.getData()), - obuf_.getLength(), salt_data_, salt_length_, digest); + iterateSHA1(&sha1_ctx_, name_buf, length, + salt_data_, salt_length_, digest); for (unsigned int n = 0; n < iterations_; ++n) { iterateSHA1(&sha1_ctx_, digest, SHA1_HASHSIZE, salt_data_, salt_length_, digest); @@ -137,6 +156,25 @@ NSEC3HashRFC5155::calculate(const Name& name) const { return (encodeBase32Hex(digest_)); } +string +NSEC3HashRFC5155::calculate(const Name& name) const { + obuf_.clear(); + name.toWire(obuf_); + + return (calculateForWiredata(static_cast<const uint8_t*>(obuf_.getData()), + obuf_.getLength())); +} + +string +NSEC3HashRFC5155::calculate(const LabelSequence& ls) const { + assert(ls.isAbsolute()); + + size_t length; + const uint8_t* data = ls.getData(&length); + + return (calculateForWiredata(data, length)); +} + bool NSEC3HashRFC5155::match(uint8_t algorithm, uint16_t iterations, const vector<uint8_t>& salt) const diff --git a/src/lib/dns/nsec3hash.h b/src/lib/dns/nsec3hash.h index f1ca1a3c2c..b58f0c9417 100644 --- a/src/lib/dns/nsec3hash.h +++ b/src/lib/dns/nsec3hash.h @@ -23,6 +23,7 @@ namespace isc { namespace dns { class Name; +class LabelSequence; namespace rdata { namespace generic { @@ -122,26 +123,40 @@ public: /// (SHA-1) is supported /// \param iterations the number of iterations /// \param salt_data the salt data as a byte array - /// \param salt_data_length the length of the salt data + /// \param salt_length the length of the salt data static NSEC3Hash* create(uint8_t algorithm, uint16_t iterations, const uint8_t* salt_data, size_t salt_length); /// \brief The destructor. virtual ~NSEC3Hash() {} - /// \brief Calculate the NSEC3 hash. + /// \brief Calculate the NSEC3 hash (Name variant). /// /// This method calculates the NSEC3 hash value for the given \c name /// with the hash parameters (algorithm, iterations and salt) given at /// construction, and returns the value as a base32hex-encoded string /// (without containing any white spaces). All US-ASCII letters in the - /// string will be upper cased. + /// string will be lower cased. /// /// \param name The domain name for which the hash value is to be /// calculated. /// \return Base32hex-encoded string of the hash value. virtual std::string calculate(const Name& name) const = 0; + /// \brief Calculate the NSEC3 hash (LabelSequence variant). + /// + /// This method calculates the NSEC3 hash value for the given + /// absolute LabelSequence \c ls with the hash parameters + /// (algorithm, iterations and salt) given at construction, and + /// returns the value as a base32hex-encoded string (without + /// containing any white spaces). All US-ASCII letters in the + /// string will be lower cased. + /// + /// \param ls The absolute label sequence for which the hash value + /// is to be calculated. + /// \return Base32hex-encoded string of the hash value. + virtual std::string calculate(const LabelSequence& ls) const = 0; + /// \brief Match given NSEC3 parameters with that of the hash. /// /// This method compares NSEC3 parameters used for hash calculation @@ -233,7 +248,7 @@ public: /// (SHA-1) is supported /// \param iterations the number of iterations /// \param salt_data the salt data as a byte array - /// \param salt_data_length the length of the salt data + /// \param salt_length the length of the salt data virtual NSEC3Hash* create(uint8_t algorithm, uint16_t iterations, const uint8_t* salt_data, size_t salt_length) const = 0; diff --git a/src/lib/dns/python/message_python.cc b/src/lib/dns/python/message_python.cc index 4dfee249b6..d86754b8e8 100644 --- a/src/lib/dns/python/message_python.cc +++ b/src/lib/dns/python/message_python.cc @@ -696,10 +696,10 @@ Message_toWire(s_Message* self, PyObject* args) { PyObject* mr; PyObject* tsig_ctx = NULL; - if (PyArg_ParseTuple(args, "O!|O!", &messagerenderer_type, &mr, - &tsigcontext_type, &tsig_ctx)) { + if (PyArg_ParseTuple(args, "O!|O", &messagerenderer_type, &mr, + &tsig_ctx)) { try { - if (tsig_ctx == NULL) { + if ((tsig_ctx == NULL) || (tsig_ctx == Py_None)) { self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr)); } else { self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr), @@ -726,7 +726,7 @@ Message_toWire(s_Message* self, PyObject* args) { } PyErr_Clear(); PyErr_SetString(PyExc_TypeError, - "toWire argument must be a MessageRenderer"); + "Bad to_wire() arguments were passed"); return (NULL); } diff --git a/src/lib/dns/python/name_python.cc b/src/lib/dns/python/name_python.cc index 2799db9fde..ecdae841c3 100644 --- a/src/lib/dns/python/name_python.cc +++ b/src/lib/dns/python/name_python.cc @@ -537,6 +537,7 @@ namespace python { // Initialization and addition of these go in the module init at the // end // +PyObject* po_NameParserException; PyObject* po_EmptyLabel; PyObject* po_TooLongName; PyObject* po_TooLongLabel; @@ -544,7 +545,6 @@ PyObject* po_BadLabelType; PyObject* po_BadEscape; PyObject* po_IncompleteName; PyObject* po_InvalidBufferPosition; -PyObject* po_DNSMessageFORMERR; // // Definition of enums diff --git a/src/lib/dns/python/name_python.h b/src/lib/dns/python/name_python.h index d18c0d9385..2cce9994cc 100644 --- a/src/lib/dns/python/name_python.h +++ b/src/lib/dns/python/name_python.h @@ -23,6 +23,7 @@ class Name; namespace python { +extern PyObject* po_NameParserException; extern PyObject* po_EmptyLabel; extern PyObject* po_TooLongName; extern PyObject* po_TooLongLabel; @@ -30,7 +31,6 @@ extern PyObject* po_BadLabelType; extern PyObject* po_BadEscape; extern PyObject* po_IncompleteName; extern PyObject* po_InvalidBufferPosition; -extern PyObject* po_DNSMessageFORMERR; // // Declaration of enums diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc index 30dc09089c..b0bda22c4b 100644 --- a/src/lib/dns/python/pydnspp.cc +++ b/src/lib/dns/python/pydnspp.cc @@ -28,6 +28,7 @@ #include <Python.h> #include <structmember.h> +#include <dns/exceptions.h> #include <dns/message.h> #include <dns/opcode.h> #include <dns/tsig.h> @@ -152,8 +153,14 @@ initModulePart_Message(PyObject* mod) { PyErr_NewException("pydnspp.InvalidMessageUDPSize", NULL, NULL); PyObjectContainer(po_InvalidMessageUDPSize).installToModule( mod, "InvalidMessageUDPSize"); + po_DNSMessageFORMERR = + PyErr_NewException("pydnspp.DNSMessageFORMERR", + po_DNSProtocolError, NULL); + PyObjectContainer(po_DNSMessageFORMERR).installToModule( + mod, "DNSMessageFORMERR"); po_DNSMessageBADVERS = - PyErr_NewException("pydnspp.DNSMessageBADVERS", NULL, NULL); + PyErr_NewException("pydnspp.DNSMessageBADVERS", + po_DNSProtocolError, NULL); PyObjectContainer(po_DNSMessageBADVERS).installToModule( mod, "DNSMessageBADVERS"); po_UnknownNSEC3HashAlgorithm = @@ -243,36 +250,40 @@ initModulePart_Name(PyObject* mod) { // Add the exceptions to the module try { - po_EmptyLabel = PyErr_NewException("pydnspp.EmptyLabel", NULL, NULL); + po_NameParserException = + PyErr_NewException("pydnspp.NameParserException", + po_DNSTextError, NULL); + PyObjectContainer(po_NameParserException) + .installToModule(mod, "NameParserException"); + + po_EmptyLabel = PyErr_NewException("pydnspp.EmptyLabel", + po_NameParserException, NULL); PyObjectContainer(po_EmptyLabel).installToModule(mod, "EmptyLabel"); - po_TooLongName = PyErr_NewException("pydnspp.TooLongName", NULL, NULL); + po_TooLongName = PyErr_NewException("pydnspp.TooLongName", + po_NameParserException, NULL); PyObjectContainer(po_TooLongName).installToModule(mod, "TooLongName"); - po_TooLongLabel = PyErr_NewException("pydnspp.TooLongLabel", NULL, NULL); + po_TooLongLabel = PyErr_NewException("pydnspp.TooLongLabel", + po_NameParserException, NULL); PyObjectContainer(po_TooLongLabel).installToModule(mod, "TooLongLabel"); - po_BadLabelType = PyErr_NewException("pydnspp.BadLabelType", NULL, NULL); + po_BadLabelType = PyErr_NewException("pydnspp.BadLabelType", + po_NameParserException, NULL); PyObjectContainer(po_BadLabelType).installToModule(mod, "BadLabelType"); - po_BadEscape = PyErr_NewException("pydnspp.BadEscape", NULL, NULL); + po_BadEscape = PyErr_NewException("pydnspp.BadEscape", + po_NameParserException, NULL); PyObjectContainer(po_BadEscape).installToModule(mod, "BadEscape"); - po_IncompleteName = PyErr_NewException("pydnspp.IncompleteName", NULL, - NULL); + po_IncompleteName = PyErr_NewException("pydnspp.IncompleteName", + po_NameParserException, NULL); PyObjectContainer(po_IncompleteName).installToModule(mod, "IncompleteName"); po_InvalidBufferPosition = PyErr_NewException("pydnspp.InvalidBufferPosition", NULL, NULL); PyObjectContainer(po_InvalidBufferPosition).installToModule( mod, "InvalidBufferPosition"); - - // This one could have gone into the message_python.cc file, but is - // already needed here. - po_DNSMessageFORMERR = PyErr_NewException("pydnspp.DNSMessageFORMERR", - NULL, NULL); - PyObjectContainer(po_DNSMessageFORMERR).installToModule( - mod, "DNSMessageFORMERR"); } catch (const std::exception& ex) { const std::string ex_what = "Unexpected failure in Name initialization: " + @@ -865,14 +876,31 @@ PyInit_pydnspp(void) { PyObjectContainer(po_IscException).installToModule(mod, "IscException"); po_InvalidOperation = PyErr_NewException("pydnspp.InvalidOperation", - NULL, NULL); - PyObjectContainer(po_InvalidOperation).installToModule( - mod, "InvalidOperation"); + po_IscException, NULL); + PyObjectContainer(po_InvalidOperation) + .installToModule(mod, "InvalidOperation"); po_InvalidParameter = PyErr_NewException("pydnspp.InvalidParameter", - NULL, NULL); - PyObjectContainer(po_InvalidParameter).installToModule( - mod, "InvalidParameter"); + po_IscException, NULL); + PyObjectContainer(po_InvalidParameter) + .installToModule(mod, "InvalidParameter"); + + // Add DNS exceptions + po_DNSException = PyErr_NewException("pydnspp.DNSException", + po_IscException, NULL); + PyObjectContainer(po_DNSException) + .installToModule(mod, "DNSException"); + + po_DNSTextError = PyErr_NewException("pydnspp.DNSTextError", + po_DNSException, NULL); + PyObjectContainer(po_DNSTextError) + .installToModule(mod, "DNSTextError"); + + po_DNSProtocolError = PyErr_NewException("pydnspp.DNSProtocolError", + po_DNSException, NULL); + PyObjectContainer(po_DNSProtocolError) + .installToModule(mod, "DNSProtocolError"); + } catch (const std::exception& ex) { const std::string ex_what = "Unexpected failure in pydnspp initialization: " + diff --git a/src/lib/dns/python/pydnspp_common.cc b/src/lib/dns/python/pydnspp_common.cc index 4250db7601..c95f87765e 100644 --- a/src/lib/dns/python/pydnspp_common.cc +++ b/src/lib/dns/python/pydnspp_common.cc @@ -50,7 +50,11 @@ PyObject* po_IscException; PyObject* po_InvalidOperation; PyObject* po_InvalidParameter; -// For our own isc::dns::Exception +// For DNS exceptions +PyObject* po_DNSException; +PyObject* po_DNSTextError; +PyObject* po_DNSProtocolError; +PyObject* po_DNSMessageFORMERR; PyObject* po_DNSMessageBADVERS; diff --git a/src/lib/dns/python/pydnspp_common.h b/src/lib/dns/python/pydnspp_common.h index 9c27cfdae1..77191dc576 100644 --- a/src/lib/dns/python/pydnspp_common.h +++ b/src/lib/dns/python/pydnspp_common.h @@ -34,6 +34,10 @@ extern PyObject* po_InvalidOperation; extern PyObject* po_InvalidParameter; // For our own isc::dns::Exception +extern PyObject* po_DNSException; +extern PyObject* po_DNSTextError; +extern PyObject* po_DNSProtocolError; +extern PyObject* po_DNSMessageFORMERR; extern PyObject* po_DNSMessageBADVERS; // This function reads 'bytes' from a sequence diff --git a/src/lib/dns/python/rdata_python.cc b/src/lib/dns/python/rdata_python.cc index 20f67c8d7e..4b5200255f 100644 --- a/src/lib/dns/python/rdata_python.cc +++ b/src/lib/dns/python/rdata_python.cc @@ -25,6 +25,7 @@ #include "rrclass_python.h" #include "messagerenderer_python.h" #include "name_python.h" +#include "pydnspp_common.h" using namespace isc::dns; using namespace isc::dns::python; @@ -104,9 +105,9 @@ Rdata_init(PyObject* self_p, PyObject* args, PyObject*) { const char* s; const char* data; Py_ssize_t len; - s_Rdata* self(static_cast<s_Rdata*>(self_p)); - try { + s_Rdata* self = static_cast<s_Rdata*>(self_p); + // Create from string if (PyArg_ParseTuple(args, "O!O!s", &rrtype_type, &rrtype, &rrclass_type, &rrclass, diff --git a/src/lib/dns/python/rrset_python.cc b/src/lib/dns/python/rrset_python.cc index de5925a431..4d864d1d8a 100644 --- a/src/lib/dns/python/rrset_python.cc +++ b/src/lib/dns/python/rrset_python.cc @@ -53,6 +53,7 @@ int RRset_init(s_RRset* self, PyObject* args); void RRset_destroy(s_RRset* self); PyObject* RRset_getRdataCount(PyObject* self, PyObject* args); +PyObject* RRset_getLength(PyObject* self, PyObject* args); PyObject* RRset_getName(PyObject* self, PyObject* args); PyObject* RRset_getClass(PyObject* self, PyObject* args); PyObject* RRset_getType(PyObject* self, PyObject* args); @@ -70,6 +71,8 @@ PyObject* RRset_removeRRsig(PyObject* self, PyObject* args); PyMethodDef RRset_methods[] = { { "get_rdata_count", RRset_getRdataCount, METH_NOARGS, "Returns the number of rdata fields." }, + { "get_length", RRset_getLength, METH_NOARGS, + "Returns the wire format length of the RRset." }, { "get_name", RRset_getName, METH_NOARGS, "Returns the name of the RRset, as a Name object." }, { "get_class", RRset_getClass, METH_NOARGS, @@ -136,6 +139,18 @@ RRset_getRdataCount(PyObject* self, PyObject*) { } PyObject* +RRset_getLength(PyObject* self, PyObject*) { + try { + return (Py_BuildValue("H", static_cast<const s_RRset*>(self)->cppobj-> + getLength())); + } catch (const EmptyRRset& ers) { + PyErr_Clear(); + PyErr_SetString(po_EmptyRRset, ers.what()); + return (NULL); + } +} + +PyObject* RRset_getName(PyObject* self, PyObject*) { try { return (createNameObject(static_cast<const s_RRset*>(self)->cppobj-> @@ -236,9 +251,9 @@ PyObject* RRset_toWire(PyObject* self_p, PyObject* args) { PyObject* bytes; PyObject* mr; - const s_RRset* self(static_cast<const s_RRset*>(self_p)); try { + const s_RRset* self = static_cast<const s_RRset*>(self_p); if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) { PyObject* bytes_o = bytes; diff --git a/src/lib/dns/python/tests/Makefile.am b/src/lib/dns/python/tests/Makefile.am index 4574303408..8fe8bb7667 100644 --- a/src/lib/dns/python/tests/Makefile.am +++ b/src/lib/dns/python/tests/Makefile.am @@ -6,6 +6,7 @@ PYTESTS += name_python_test.py PYTESTS += nsec3hash_python_test.py PYTESTS += question_python_test.py PYTESTS += opcode_python_test.py +PYTESTS += pydnspp_python_test.py PYTESTS += rcode_python_test.py PYTESTS += rdata_python_test.py PYTESTS += rrclass_python_test.py diff --git a/src/lib/dns/python/tests/message_python_test.py b/src/lib/dns/python/tests/message_python_test.py index 996ef8970c..6f017dfec3 100644 --- a/src/lib/dns/python/tests/message_python_test.py +++ b/src/lib/dns/python/tests/message_python_test.py @@ -371,6 +371,13 @@ class MessageTest(unittest.TestCase): self.__common_tsigmessage_setup() self.__common_tsig_checks("message_toWire2.wire") + def test_to_wire_with_tsig_none(self): + message_render = create_message() + renderer = MessageRenderer() + message_render.to_wire(renderer, None) + self.assertEqual(b'\x105\x85\x00\x00\x01\x00\x02\x00\x00\x00\x00\x04test\x07example\x03com\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\xc0\x00\x02\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\xc0\x00\x02\x02', + renderer.get_data()) + def test_to_wire_with_edns_tsig(self): fix_current_time(0x4db60d1f) self.r.set_qid(0x6cd) diff --git a/src/lib/dns/python/tests/name_python_test.py b/src/lib/dns/python/tests/name_python_test.py index 8ea2e3520a..8160716896 100644 --- a/src/lib/dns/python/tests/name_python_test.py +++ b/src/lib/dns/python/tests/name_python_test.py @@ -14,7 +14,7 @@ # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -# Tests for the messagerenderer part of the pydnspp module +# Tests for the name part of the pydnspp module # import unittest @@ -97,6 +97,16 @@ class NameTest(unittest.TestCase): self.assertRaises(DNSMessageFORMERR, Name, b, 0) self.assertRaises(IndexError, Name, b, -1) + def test_exception_hierarchy(self): + self.assertTrue(isinstance(EmptyLabel(), NameParserException)) + self.assertTrue(isinstance(TooLongLabel(), NameParserException)) + self.assertTrue(isinstance(BadLabelType(), NameParserException)) + self.assertTrue(isinstance(BadEscape(), NameParserException)) + self.assertTrue(isinstance(TooLongName(), NameParserException)) + self.assertTrue(isinstance(IncompleteName(), NameParserException)) + + self.assertTrue(isinstance(NameParserException(), DNSTextError)) + def test_at(self): self.assertEqual(7, self.name1.at(0)) self.assertEqual(101, self.name1.at(1)) diff --git a/src/lib/dns/python/tests/pydnspp_python_test.py b/src/lib/dns/python/tests/pydnspp_python_test.py new file mode 100644 index 0000000000..574fc00e00 --- /dev/null +++ b/src/lib/dns/python/tests/pydnspp_python_test.py @@ -0,0 +1,34 @@ +# Copyright (C) 2014 Internet Systems Consortium. +# +# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM +# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# INTERNET SYSTEMS CONSORTIUM 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. + +# +# Tests for the common part of the pydnspp module +# + +import unittest +import os +from pydnspp import * + +class CommonTest(unittest.TestCase): + def test_exception_hierarchy(self): + self.assertTrue(isinstance(InvalidOperation(), IscException)) + self.assertTrue(isinstance(InvalidParameter(), IscException)) + + self.assertTrue(isinstance(DNSException(), IscException)) + self.assertTrue(isinstance(DNSTextError(), DNSException)) + self.assertTrue(isinstance(DNSProtocolError(), DNSException)) + +if __name__ == '__main__': + unittest.main() diff --git a/src/lib/dns/python/tests/rrset_python_test.py b/src/lib/dns/python/tests/rrset_python_test.py index 9592b42021..d848d278b6 100644 --- a/src/lib/dns/python/tests/rrset_python_test.py +++ b/src/lib/dns/python/tests/rrset_python_test.py @@ -45,6 +45,24 @@ class TestModuleSpec(unittest.TestCase): self.assertEqual(i, self.rrset_a_empty.get_rdata_count()) self.rrset_a_empty.add_rdata(Rdata(RRType("A"), RRClass("IN"), "192.0.2.1")) + def test_get_length(self): + # Empty RRset should throw + self.assertRaises(EmptyRRset, self.rrset_a_empty.get_length); + + # Unless it is type ANY or NONE: + # test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets + # TYPE field = 2 octets + # CLASS field = 2 octets + # TTL field = 4 octets + # RDLENGTH field = 2 octets + # Total = 18 + 2 + 2 + 4 + 2 = 28 octets + self.assertEqual(28, self.rrset_any_a_empty.get_length()) + + # Single A RR: + # 28 octets (above) + 4 octets (A RDATA) = 32 octets + # With 2 A RRs: + self.assertEqual(32 + 32, self.rrset_a.get_length()) + def test_get_name(self): self.assertEqual(self.test_name, self.rrset_a.get_name()) self.assertEqual(self.test_domain, self.rrset_ns.get_name()) diff --git a/src/lib/dns/python/tsig_python.cc b/src/lib/dns/python/tsig_python.cc index abb77334f6..c5b5421dcc 100644 --- a/src/lib/dns/python/tsig_python.cc +++ b/src/lib/dns/python/tsig_python.cc @@ -334,14 +334,21 @@ PyTSIGContext_Check(PyObject* obj) { return (PyObject_TypeCheck(obj, &tsigcontext_type)); } -TSIGContext& +TSIGContext* PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj) { if (tsigcontext_obj == NULL) { isc_throw(PyCPPWrapperException, "obj argument NULL in TSIGContext PyObject conversion"); } + + if (!PyTSIGContext_Check(tsigcontext_obj)) { + isc_throw(TSIGContextError, + "obj argument is of wrong type in TSIGContext " + "PyObject conversion"); + } + s_TSIGContext* tsigcontext = static_cast<s_TSIGContext*>(tsigcontext_obj); - return (*tsigcontext->cppobj); + return (tsigcontext->cppobj); } } // namespace python diff --git a/src/lib/dns/python/tsig_python.h b/src/lib/dns/python/tsig_python.h index 0bd57d70c0..bbef56be10 100644 --- a/src/lib/dns/python/tsig_python.h +++ b/src/lib/dns/python/tsig_python.h @@ -36,8 +36,8 @@ extern PyObject* po_TSIGContextError; /// \return true if the object is of type TSIGContext, false otherwise bool PyTSIGContext_Check(PyObject* obj); -/// \brief Returns a reference to the TSIGContext object contained within the given -/// Python object. +/// \brief Returns a pointer to the TSIGContext object contained within +/// the given Python object. /// /// \note The given object MUST be of type TSIGContext; this can be checked with /// either the right call to ParseTuple("O!"), or with PyTSIGContext_Check() @@ -46,7 +46,7 @@ bool PyTSIGContext_Check(PyObject* obj); /// may be destroyed, the caller must copy it itself. /// /// \param tsigcontext_obj The tsigcontext object to convert -TSIGContext& PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj); +TSIGContext* PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj); } // namespace python diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc index f42c349f2d..a34f8870fe 100644 --- a/src/lib/dns/rdata.cc +++ b/src/lib/dns/rdata.cc @@ -15,6 +15,7 @@ #include <exceptions/exceptions.h> #include <util/buffer.h> +#include <util/encode/hex.h> #include <dns/name.h> #include <dns/messagerenderer.h> @@ -46,6 +47,15 @@ namespace isc { namespace dns { namespace rdata { +uint16_t +Rdata::getLength() const { + OutputBuffer obuffer(0); + + toWire(obuffer); + + return (obuffer.getLength()); +} + // XXX: we need to specify std:: for string to help doxygen match the // function signature with that given in the header file. RdataPtr @@ -211,94 +221,100 @@ Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) { impl_ = new GenericImpl(data); } -void -Generic::constructHelper(const std::string& rdata_string) { - istringstream iss(rdata_string); - string unknown_mark; - iss >> unknown_mark; - if (unknown_mark != "\\#") { +GenericImpl* +Generic::constructFromLexer(MasterLexer& lexer) { + const MasterToken& token = lexer.getNextToken(MasterToken::STRING); + if (token.getString() != "\\#") { isc_throw(InvalidRdataText, - "Missing the special token (\\#) for generic RDATA encoding"); + "Missing the special token (\\#) for " + "unknown RDATA encoding"); } - // RDLENGTH: read into a string so that we can easily reject invalid tokens - string rdlen_txt; - iss >> rdlen_txt; - istringstream iss_rdlen(rdlen_txt); - int32_t rdlen; - iss_rdlen >> rdlen; - if (iss_rdlen.rdstate() != ios::eofbit) { - isc_throw(InvalidRdataText, - "Invalid representation for a generic RDLENGTH"); + // Initialize with an absurd value. + uint32_t rdlen = 65536; + + try { + rdlen = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataLength, + "Unknown RDATA length is invalid"); } - if (rdlen < 0 || rdlen > 0xffff) { - isc_throw(InvalidRdataLength, "RDATA length is out of range"); + + if (rdlen > 65535) { + isc_throw(InvalidRdataLength, + "Unknown RDATA length is out of range: " << rdlen); } - iss >> ws; // skip any white spaces - // Hexadecimal encoding of RDATA: each segment must consist of an even - // number of hex digits. vector<uint8_t> data; - while (!iss.eof() && data.size() < rdlen) { - // extract two characters, which should compose a single byte of data. - char buf[2]; - iss.read(buf, sizeof(buf)); - if ((iss.rdstate() & (ios::badbit | ios::failbit)) != 0) { - isc_throw(InvalidRdataText, - "Invalid hex encoding of generic RDATA"); + + if (rdlen > 0) { + string hex_txt; + string hex_part; + // Whitespace is allowed within hex data, 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)) { + // Unget the last read token as createRdata() expects us + // to leave it at the end-of-line or end-of-file when we + // return. + lexer.ungetToken(); + break; + } + token.getString(hex_part); + hex_txt.append(hex_part); } - // convert it to a single byte integer as a hex digit. - istringstream iss_byte(string(buf, sizeof(buf))); - unsigned int ch; - iss_byte >> hex >> ch; - if (iss_byte.rdstate() != ios::eofbit) { + try { + isc::util::encode::decodeHex(hex_txt, data); + } catch (const isc::BadValue& ex) { isc_throw(InvalidRdataText, - "Invalid hex encoding of generic RDATA"); + "Invalid hex encoding of generic RDATA: " << ex.what()); } - data.push_back(ch); - iss >> ws; // skip spaces - } - - if (!iss.eof()) { - isc_throw(InvalidRdataLength, - "RDLENGTH is too small for generic RDATA"); } if (data.size() != rdlen) { isc_throw(InvalidRdataLength, - "Generic RDATA code doesn't match RDLENGTH"); + "Size of unknown RDATA hex data doesn't match RDLENGTH: " + << data.size() << " vs. " << rdlen); } - impl_ = new GenericImpl(data); -} - -Generic::Generic(const std::string& rdata_string) { - constructHelper(rdata_string); + return (new GenericImpl(data)); } -Generic::Generic(MasterLexer& lexer, const Name*, - MasterLoader::Options, - MasterLoaderCallbacks&) +Generic::Generic(const std::string& rdata_string) : + impl_(NULL) { - std::string s; + // 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 GenericImpl that constructFromLexer() returns. + std::auto_ptr<GenericImpl> impl_ptr(NULL); - while (true) { - const MasterToken& token = lexer.getNextToken(); - if ((token.getType() == MasterToken::END_OF_FILE) || - (token.getType() == MasterToken::END_OF_LINE)) { - lexer.ungetToken(); // let the upper layer handle the end-of token - break; - } + try { + std::istringstream ss(rdata_string); + MasterLexer lexer; + lexer.pushSource(ss); - if (!s.empty()) { - s += " "; - } + impl_ptr.reset(constructFromLexer(lexer)); - s += token.getString(); + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for unknown RDATA: " + << rdata_string); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct unknown RDATA " + "from '" << rdata_string << "': " << ex.what()); } - constructHelper(s); + impl_ = impl_ptr.release(); +} + +Generic::Generic(MasterLexer& lexer, const Name*, + MasterLoader::Options, + MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer)) +{ } Generic::~Generic() { diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h index 3fe0c74dd2..eb07937650 100644 --- a/src/lib/dns/rdata.h +++ b/src/lib/dns/rdata.h @@ -19,7 +19,7 @@ #include <dns/master_loader.h> #include <dns/master_loader_callbacks.h> -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> #include <boost/shared_ptr.hpp> @@ -42,20 +42,20 @@ namespace rdata { /// \brief A standard DNS module exception that is thrown if RDATA parser /// encounters an invalid or inconsistent data length. /// -class InvalidRdataLength : public Exception { +class InvalidRdataLength : public DNSTextError { public: InvalidRdataLength(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + DNSTextError(file, line, what) {} }; /// /// \brief A standard DNS module exception that is thrown if RDATA parser /// fails to recognize a given textual representation. /// -class InvalidRdataText : public Exception { +class InvalidRdataText : public DNSTextError { public: InvalidRdataText(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + DNSTextError(file, line, what) {} }; /// @@ -63,10 +63,10 @@ public: /// encounters a character-string (as defined in RFC1035) exceeding /// the maximum allowable length (\c MAX_CHARSTRING_LEN). /// -class CharStringTooLong : public Exception { +class CharStringTooLong : public DNSTextError { public: CharStringTooLong(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + DNSTextError(file, line, what) {} }; // Forward declaration to define RdataPtr. @@ -221,6 +221,21 @@ public: /// \return > 0 if \c this would be sorted after \c other. virtual int compare(const Rdata& other) const = 0; //@} + + /// \brief Get the wire format length of an Rdata. + /// + /// IMPLEMENTATION NOTE: Currently this base class implementation is + /// non-optimal as it renders the wire data to a buffer and returns + /// the buffer's length. What would perform better is to add + /// implementations of \c getLength() method to every RDATA + /// type. This is why this method is virtual. Once all Rdata types + /// have \c getLength() implementations, this base class + /// implementation must be removed and the method should become a + /// pure interface. + /// + /// \return The length of the wire format representation of the + /// RDATA. + virtual uint16_t getLength() const; }; namespace generic { @@ -378,7 +393,7 @@ public: //@} private: - void constructHelper(const std::string& rdata_string); + GenericImpl* constructFromLexer(MasterLexer& lexer); GenericImpl* impl_; }; diff --git a/src/lib/dns/rdata/generic/caa_257.cc b/src/lib/dns/rdata/generic/caa_257.cc new file mode 100644 index 0000000000..7d46a57662 --- /dev/null +++ b/src/lib/dns/rdata/generic/caa_257.cc @@ -0,0 +1,306 @@ +// Copyright (C) 2014 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 <config.h> + +#include <boost/lexical_cast.hpp> +#include <boost/algorithm/string.hpp> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <dns/name.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +#include <dns/rdata/generic/detail/char_string.h> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct CAAImpl { + // straightforward representation of CAA RDATA fields + CAAImpl(uint8_t flags, const std::string& tag, + const detail::CharStringData& value) : + flags_(flags), + tag_(tag), + value_(value) + { + if ((sizeof(flags) + 1 + tag_.size() + value_.size()) > 65535) { + isc_throw(InvalidRdataLength, + "CAA Value field is too large: " << value_.size()); + } + } + + uint8_t flags_; + const std::string tag_; + const detail::CharStringData value_; +}; + +// helper function for string and lexer constructors +CAAImpl* +CAA::constructFromLexer(MasterLexer& lexer) { + const uint32_t flags = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (flags > 255) { + isc_throw(InvalidRdataText, + "CAA flags field out of range"); + } + + // Tag field must not be empty. + const std::string tag = + lexer.getNextToken(MasterToken::STRING).getString(); + if (tag.empty()) { + isc_throw(InvalidRdataText, "CAA tag field is empty"); + } else if (tag.size() > 255) { + isc_throw(InvalidRdataText, + "CAA tag field is too large: " << tag.size()); + } + + // Value field may be empty. + detail::CharStringData value; + MasterToken token = lexer.getNextToken(MasterToken::QSTRING, true); + if ((token.getType() != MasterToken::END_OF_FILE) && + (token.getType() != MasterToken::END_OF_LINE)) + { + detail::stringToCharStringData(token.getStringRegion(), value); + } + + return (new CAAImpl(flags, tag, value)); +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid CAA 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 Flags, Tag and Value fields must be within their valid ranges, +/// but are not constrained to the values defined in RFC6844. The Tag +/// field must not be empty. +/// +/// \throw InvalidRdataText if any fields are missing, out of their +/// valid ranges, incorrect, or empty. +/// +/// \param caa_str A string containing the RDATA to be created +CAA::CAA(const string& caa_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 CAAImpl that constructFromLexer() returns. + std::auto_ptr<CAAImpl> impl_ptr(NULL); + + try { + std::istringstream ss(caa_str); + MasterLexer lexer; + lexer.pushSource(ss); + + impl_ptr.reset(constructFromLexer(lexer)); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for CAA: " + << caa_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct CAA from '" << + caa_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 CAA RDATA. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing +/// field. +/// \throw InvalidRdataText Fields are out of their valid ranges, +/// incorrect, or empty. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +CAA::CAA(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer)) +{ +} + +/// \brief Constructor from InputBuffer. +/// +/// The passed buffer must contain a valid CAA RDATA. +/// +/// The Flags, Tag and Value fields must be within their valid ranges, +/// but are not constrained to the values defined in RFC6844. The Tag +/// field must not be empty. +CAA::CAA(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len < 2) { + isc_throw(InvalidRdataLength, "CAA record too short"); + } + + const uint8_t flags = buffer.readUint8(); + const uint8_t tag_length = buffer.readUint8(); + rdata_len -= 2; + if (tag_length == 0) { + isc_throw(InvalidRdataText, "CAA tag field is empty"); + } + + if (rdata_len < tag_length) { + isc_throw(InvalidRdataLength, + "RDATA is too short for CAA tag field"); + } + + std::vector<uint8_t> tag_vec(tag_length); + buffer.readData(&tag_vec[0], tag_length); + std::string tag(tag_vec.begin(), tag_vec.end()); + rdata_len -= tag_length; + + detail::CharStringData value; + value.resize(rdata_len); + if (rdata_len > 0) { + buffer.readData(&value[0], rdata_len); + } + + impl_ = new CAAImpl(flags, tag, value); +} + +CAA::CAA(uint8_t flags, const std::string& tag, const std::string& value) : + impl_(NULL) +{ + if (tag.empty()) { + isc_throw(isc::InvalidParameter, + "CAA tag field is empty"); + } else if (tag.size() > 255) { + isc_throw(isc::InvalidParameter, + "CAA tag field is too large: " << tag.size()); + } + + MasterToken::StringRegion region; + region.beg = &value[0]; // note std ensures this works even if str is empty + region.len = value.size(); + + detail::CharStringData value_vec; + detail::stringToCharStringData(region, value_vec); + + impl_ = new CAAImpl(flags, tag, value_vec); +} + +CAA::CAA(const CAA& other) : + Rdata(), impl_(new CAAImpl(*other.impl_)) +{} + +CAA& +CAA::operator=(const CAA& source) { + if (this == &source) { + return (*this); + } + + CAAImpl* newimpl = new CAAImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +CAA::~CAA() { + delete impl_; +} + +void +CAA::toWire(OutputBuffer& buffer) const { + buffer.writeUint8(impl_->flags_); + + // The constructors must ensure that the tag field is not empty. + assert(!impl_->tag_.empty()); + buffer.writeUint8(impl_->tag_.size()); + buffer.writeData(&impl_->tag_[0], impl_->tag_.size()); + + if (!impl_->value_.empty()) { + buffer.writeData(&impl_->value_[0], + impl_->value_.size()); + } +} + +void +CAA::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeUint8(impl_->flags_); + + // The constructors must ensure that the tag field is not empty. + assert(!impl_->tag_.empty()); + renderer.writeUint8(impl_->tag_.size()); + renderer.writeData(&impl_->tag_[0], impl_->tag_.size()); + + if (!impl_->value_.empty()) { + renderer.writeData(&impl_->value_[0], + impl_->value_.size()); + } +} + +std::string +CAA::toText() const { + std::string result; + + result = lexical_cast<std::string>(static_cast<int>(impl_->flags_)); + result += " " + impl_->tag_; + result += " \"" + detail::charStringDataToString(impl_->value_) + "\""; + + return (result); +} + +int +CAA::compare(const Rdata& other) const { + const CAA& other_caa = dynamic_cast<const CAA&>(other); + + if (impl_->flags_ < other_caa.impl_->flags_) { + return (-1); + } else if (impl_->flags_ > other_caa.impl_->flags_) { + return (1); + } + + // Do a case-insensitive compare of the tag strings. + const int result = boost::ilexicographical_compare + <std::string, std::string>(impl_->tag_, other_caa.impl_->tag_); + if (result != 0) { + return (result); + } + + return (detail::compareCharStringDatas(impl_->value_, + other_caa.impl_->value_)); +} + +uint8_t +CAA::getFlags() const { + return (impl_->flags_); +} + +const std::string& +CAA::getTag() const { + return (impl_->tag_); +} + +const std::vector<uint8_t>& +CAA::getValue() const { + return (impl_->value_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/caa_257.h b/src/lib/dns/rdata/generic/caa_257.h new file mode 100644 index 0000000000..47a1369c97 --- /dev/null +++ b/src/lib/dns/rdata/generic/caa_257.h @@ -0,0 +1,72 @@ +// Copyright (C) 2014 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. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <dns/name.h> +#include <dns/rdata.h> + +#include <string> +#include <vector> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct CAAImpl; + +class CAA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + CAA(uint8_t flags, const std::string& tag, const std::string& value); + CAA& operator=(const CAA& source); + ~CAA(); + + /// + /// Specialized methods + /// + + /// \brief Return the Flags field of the CAA RDATA. + uint8_t getFlags() const; + + /// \brief Return the Tag field of the CAA RDATA. + const std::string& getTag() const; + + /// \brief Return the Value field of the CAA RDATA. + /// + /// Note: The const reference which is returned is valid only during + /// the lifetime of this \c generic::CAA object. It should not be + /// used afterwards. + const std::vector<uint8_t>& getValue() const; + +private: + CAAImpl* constructFromLexer(MasterLexer& lexer); + + CAAImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/detail/char_string.cc b/src/lib/dns/rdata/generic/detail/char_string.cc index 4c8965a10b..328fa7b406 100644 --- a/src/lib/dns/rdata/generic/detail/char_string.cc +++ b/src/lib/dns/rdata/generic/detail/char_string.cc @@ -93,6 +93,39 @@ stringToCharString(const MasterToken::StringRegion& str_region, result[0] = result.size() - 1; } +void +stringToCharStringData(const MasterToken::StringRegion& str_region, + CharStringData& result) +{ + bool escape = false; + const char* s = str_region.beg; + const char* const s_end = str_region.beg + str_region.len; + + for (size_t n = str_region.len; n != 0; --n, ++s) { + int c = (*s & 0xff); + if (escape && std::isdigit(c) != 0) { + c = decimalToNumber(s, s_end); + // decimalToNumber() already throws if (s_end - s) is less + // than 3, so the following assertion is unnecessary. But we + // assert it anyway. 'n' is an unsigned type (size_t) and + // can underflow. + assert(n >= 3); + // 'n' and 's' are also updated by 1 in the for statement's + // expression, so we update them by 2 instead of 3 here. + n -= 2; + s += 2; + } else if (!escape && c == '\\') { + escape = true; + continue; + } + escape = false; + result.push_back(c); + } + if (escape) { // terminated by non-escaped '\' + isc_throw(InvalidRdataText, "character-string ends with '\\'"); + } +} + std::string charStringToString(const CharString& char_string) { std::string s; @@ -116,6 +149,29 @@ charStringToString(const CharString& char_string) { return (s); } +std::string +charStringDataToString(const CharStringData& char_string) { + std::string s; + for (CharString::const_iterator it = char_string.begin(); + it != char_string.end(); ++it) { + const uint8_t ch = *it; + if ((ch < 0x20) || (ch >= 0x7f)) { + // convert to escaped \xxx (decimal) format + s.push_back('\\'); + s.push_back('0' + ((ch / 100) % 10)); + s.push_back('0' + ((ch / 10) % 10)); + s.push_back('0' + (ch % 10)); + continue; + } + if ((ch == '"') || (ch == ';') || (ch == '\\')) { + s.push_back('\\'); + } + s.push_back(ch); + } + + return (s); +} + int compareCharStrings(const detail::CharString& self, const detail::CharString& other) { if (self.size() == 0 && other.size() == 0) { @@ -144,6 +200,34 @@ int compareCharStrings(const detail::CharString& self, } } +int compareCharStringDatas(const detail::CharStringData& self, + const detail::CharStringData& other) { + if (self.size() == 0 && other.size() == 0) { + return (0); + } + if (self.size() == 0) { + return (-1); + } + if (other.size() == 0) { + return (1); + } + const size_t self_len = self.size(); + const size_t other_len = other.size(); + const size_t cmp_len = std::min(self_len, other_len); + const int cmp = std::memcmp(&self[0], &other[0], cmp_len); + if (cmp < 0) { + return (-1); + } else if (cmp > 0) { + return (1); + } else if (self_len < other_len) { + return (-1); + } else if (self_len > other_len) { + return (1); + } else { + return (0); + } +} + size_t bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len, CharString& target) { diff --git a/src/lib/dns/rdata/generic/detail/char_string.h b/src/lib/dns/rdata/generic/detail/char_string.h index 8e3e2944d0..01fccadc59 100644 --- a/src/lib/dns/rdata/generic/detail/char_string.h +++ b/src/lib/dns/rdata/generic/detail/char_string.h @@ -34,6 +34,9 @@ namespace detail { /// be the bare char basis. typedef std::vector<uint8_t> CharString; +/// \brief Type for DNS character string without the length prefix. +typedef std::vector<uint8_t> CharStringData; + /// \brief Convert a DNS character-string into corresponding binary data. /// /// This helper function takes a string object that is expected to be a @@ -53,6 +56,20 @@ typedef std::vector<uint8_t> CharString; void stringToCharString(const MasterToken::StringRegion& str_region, CharString& result); +/// \brief Convert a DNS character-string into corresponding binary data. +/// +/// This method functions similar to \c stringToCharString() except it +/// does not include the 1-octet length prefix in the \c result, and the +/// result is not limited to MAX_CHARSTRING_LEN octets. +/// +/// \throw InvalidRdataText Upon syntax errors. +/// +/// \brief str_region A string that represents a character-string. +/// \brief result A placeholder vector where the resulting data are to be +/// stored. Expected to be empty, but it's not checked. +void stringToCharStringData(const MasterToken::StringRegion& str_region, + CharStringData& result); + /// \brief Convert a CharString into a textual DNS character-string. /// /// This method converts a binary 8-bit representation of a DNS @@ -67,6 +84,15 @@ void stringToCharString(const MasterToken::StringRegion& str_region, /// \return A string representation of \c char_string. std::string charStringToString(const CharString& char_string); +/// \brief Convert a CharStringData into a textual DNS character-string. +/// +/// Reverse of \c stringToCharStringData(). See \c stringToCharString() +/// vs. \c stringToCharStringData(). +/// +/// \param char_string The \c CharStringData to convert. +/// \return A string representation of \c char_string. +std::string charStringDataToString(const CharStringData& char_string); + /// \brief Compare two CharString objects /// /// \param self The CharString field to compare @@ -77,6 +103,17 @@ std::string charStringToString(const CharString& char_string); /// 0 if \c self and \c other are equal int compareCharStrings(const CharString& self, const CharString& other); +/// \brief Compare two CharStringData objects +/// +/// \param self The CharStringData field to compare +/// \param other The CharStringData field to compare to +/// +/// \return -1 if \c self would be sorted before \c other +/// 1 if \c self would be sorted after \c other +/// 0 if \c self and \c other are equal +int compareCharStringDatas(const CharStringData& self, + const CharStringData& other); + /// \brief Convert a buffer containing a character-string to CharString /// /// This method reads one character-string from the given buffer (in wire diff --git a/src/lib/dns/rdata/generic/opt_41.cc b/src/lib/dns/rdata/generic/opt_41.cc index 136bdf931a..6b292e9fa1 100644 --- a/src/lib/dns/rdata/generic/opt_41.cc +++ b/src/lib/dns/rdata/generic/opt_41.cc @@ -14,25 +14,68 @@ #include <config.h> -#include <string> - #include <util/buffer.h> #include <dns/messagerenderer.h> #include <dns/rdata.h> #include <dns/rdataclass.h> +#include <boost/foreach.hpp> + +#include <string> +#include <string.h> + using namespace std; using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE +/// \brief Constructor. +OPT::PseudoRR::PseudoRR(uint16_t code, + boost::shared_ptr<std::vector<uint8_t> >& data) : + code_(code), + data_(data) +{ +} + +uint16_t +OPT::PseudoRR::getCode() const { + return (code_); +} + +const uint8_t* +OPT::PseudoRR::getData() const { + return (&(*data_)[0]); +} + +uint16_t +OPT::PseudoRR::getLength() const { + return (data_->size()); +} + +struct OPTImpl { + OPTImpl() : + rdlength_(0) + {} + + uint16_t rdlength_; + std::vector<OPT::PseudoRR> pseudo_rrs_; +}; + +/// \brief Default constructor. +OPT::OPT() : + impl_(new OPTImpl) +{ +} + /// \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&) { +OPT::OPT(const std::string&) : + impl_(NULL) +{ isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text"); } @@ -42,50 +85,141 @@ OPT::OPT(const std::string&) { /// /// \throw InvalidRdataText OPT RR cannot be constructed from text. OPT::OPT(MasterLexer&, const Name*, - MasterLoader::Options, MasterLoaderCallbacks&) + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(NULL) { 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. - if (buffer.getLength() - buffer.getPosition() < rdata_len) { - isc_throw(InvalidRdataLength, "RDLEN of OPT is too large"); +OPT::OPT(InputBuffer& buffer, size_t rdata_len) : + impl_(NULL) +{ + std::auto_ptr<OPTImpl> impl_ptr(new OPTImpl); + + while (true) { + if (rdata_len == 0) { + break; + } + + if (rdata_len < 4) { + isc_throw(InvalidRdataLength, + "Pseudo OPT RR record too short: " + << rdata_len << " bytes"); + } + + const uint16_t option_code = buffer.readUint16(); + const uint16_t option_length = buffer.readUint16(); + rdata_len -= 4; + + if (static_cast<uint16_t>(impl_ptr->rdlength_ + option_length) < + impl_ptr->rdlength_) + { + isc_throw(InvalidRdataText, + "Option length " << option_length + << " would overflow OPT RR RDLEN (currently " + << impl_ptr->rdlength_ << ")."); + } + + if (rdata_len < option_length) { + isc_throw(InvalidRdataLength, "Corrupt pseudo OPT RR record"); + } + + boost::shared_ptr<std::vector<uint8_t> > + option_data(new std::vector<uint8_t>(option_length)); + buffer.readData(&(*option_data)[0], option_length); + impl_ptr->pseudo_rrs_.push_back(PseudoRR(option_code, option_data)); + impl_ptr->rdlength_ += option_length; + rdata_len -= option_length; + } + + impl_ = impl_ptr.release(); +} + +OPT::OPT(const OPT& other) : + Rdata(), impl_(new OPTImpl(*other.impl_)) +{ +} + +OPT& +OPT::operator=(const OPT& source) { + if (this == &source) { + return (*this); } - // This simple implementation ignores any options - buffer.setPosition(buffer.getPosition() + rdata_len); + OPTImpl* newimpl = new OPTImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); } -OPT::OPT(const OPT&) : Rdata() { - // there's nothing to copy in this simple implementation. +OPT::~OPT() { + delete impl_; } std::string OPT::toText() const { - // OPT records do not have a text format. - return (""); + isc_throw(isc::InvalidOperation, + "OPT RRs do not have a presentation format"); } void -OPT::toWire(OutputBuffer&) const { - // nothing to do, as this simple version doesn't support any options. +OPT::toWire(OutputBuffer& buffer) const { + BOOST_FOREACH(const PseudoRR& pseudo_rr, impl_->pseudo_rrs_) { + buffer.writeUint16(pseudo_rr.getCode()); + const uint16_t length = pseudo_rr.getLength(); + buffer.writeUint16(length); + if (length > 0) { + buffer.writeData(pseudo_rr.getData(), length); + } + } } void -OPT::toWire(AbstractMessageRenderer&) const { - // nothing to do, as this simple version doesn't support any options. +OPT::toWire(AbstractMessageRenderer& renderer) const { + BOOST_FOREACH(const PseudoRR& pseudo_rr, impl_->pseudo_rrs_) { + renderer.writeUint16(pseudo_rr.getCode()); + const uint16_t length = pseudo_rr.getLength(); + renderer.writeUint16(length); + if (length > 0) { + renderer.writeData(pseudo_rr.getData(), length); + } + } } int -OPT::compare(const Rdata& other) const { - //const OPT& other_opt = dynamic_cast<const OPT&>(other); - // right now we don't need other_opt: - static_cast<void>(dynamic_cast<const OPT&>(other)); - +OPT::compare(const Rdata&) const { + isc_throw(isc::InvalidOperation, + "It is meaningless to compare a set of OPT pseudo RRs; " + "they have unspecified order"); return (0); } +void +OPT::appendPseudoRR(uint16_t code, const uint8_t* data, uint16_t length) { + // See if it overflows 16-bit length field. We only worry about the + // pseudo-RR length here, not the whole message length (which should + // be checked and enforced elsewhere). + if (static_cast<uint16_t>(impl_->rdlength_ + length) < + impl_->rdlength_) + { + isc_throw(isc::InvalidParameter, + "Option length " << length + << " would overflow OPT RR RDLEN (currently " + << impl_->rdlength_ << ")."); + } + + boost::shared_ptr<std::vector<uint8_t> > + option_data(new std::vector<uint8_t>(length)); + std::memcpy(&(*option_data)[0], data, length); + impl_->pseudo_rrs_.push_back(PseudoRR(code, option_data)); + impl_->rdlength_ += length; +} + +const std::vector<OPT::PseudoRR>& +OPT::getPseudoRRs() const { + return (impl_->pseudo_rrs_); +} + // END_RDATA_NAMESPACE // END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/opt_41.h b/src/lib/dns/rdata/generic/opt_41.h index 0cb7043cca..cc51977e3a 100644 --- a/src/lib/dns/rdata/generic/opt_41.h +++ b/src/lib/dns/rdata/generic/opt_41.h @@ -18,6 +18,10 @@ #include <dns/rdata.h> +#include <boost/shared_ptr.hpp> + +#include <vector> + // BEGIN_ISC_NAMESPACE // BEGIN_COMMON_DECLARATIONS @@ -25,15 +29,64 @@ // BEGIN_RDATA_NAMESPACE +struct OPTImpl; + class OPT : public Rdata { public: // BEGIN_COMMON_MEMBERS // END_COMMON_MEMBERS // The default constructor makes sense for OPT as it can be empty. - OPT() {} + OPT(); + OPT& operator=(const OPT& source); + ~OPT(); + + /// \brief A class representing a pseudo RR (or option) within an + /// OPT RR (see RFC 6891). + class PseudoRR { + public: + /// \brief Constructor. + /// \param code The OPTION-CODE field of the pseudo RR. + /// \param data The OPTION-DATA field of the pseudo + /// RR. OPTION-LENGTH is set to the length of this vector. + PseudoRR(uint16_t code, + boost::shared_ptr<std::vector<uint8_t> >& data); + + /// \brief Return the option code of this pseudo RR. + uint16_t getCode() const; + + /// \brief Return the option data of this pseudo RR. + const uint8_t* getData() const; + + /// \brief Return the length of the option data of this + /// pseudo RR. + uint16_t getLength() const; + + private: + uint16_t code_; + boost::shared_ptr<std::vector<uint8_t> > data_; + }; + + /// \brief Append a pseudo RR (option) in this OPT RR. + /// + /// \param code The OPTION-CODE field of the pseudo RR. + /// \param data The OPTION-DATA field of the pseudo RR. + /// \param length The size of the \c data argument. OPTION-LENGTH is + /// set to this size. + /// \throw \c isc::InvalidParameter if this pseudo RR would cause + /// the OPT RDATA to overflow its RDLENGTH. + void appendPseudoRR(uint16_t code, const uint8_t* data, uint16_t length); + + /// \brief Return a vector of the pseudo RRs (options) in this + /// OPT RR. + /// + /// Note: The returned reference is only valid during the lifetime + /// of this \c generic::OPT object. It should not be used + /// afterwards. + const std::vector<PseudoRR>& getPseudoRRs() const; + private: - // RR-type specific members are here. + OPTImpl* impl_; }; // END_RDATA_NAMESPACE diff --git a/src/lib/dns/rdata/generic/sshfp_44.cc b/src/lib/dns/rdata/generic/sshfp_44.cc index 2865ed18c8..4c1e83274a 100644 --- a/src/lib/dns/rdata/generic/sshfp_44.cc +++ b/src/lib/dns/rdata/generic/sshfp_44.cc @@ -14,8 +14,6 @@ #include <config.h> -#include <string> - #include <boost/lexical_cast.hpp> #include <exceptions/exceptions.h> @@ -38,7 +36,7 @@ using namespace isc::util::encode; struct SSHFPImpl { // straightforward representation of SSHFP RDATA fields SSHFPImpl(uint8_t algorithm, uint8_t fingerprint_type, - vector<uint8_t>& fingerprint) : + const vector<uint8_t>& fingerprint) : algorithm_(algorithm), fingerprint_type_(fingerprint_type), fingerprint_(fingerprint) @@ -82,7 +80,11 @@ SSHFP::constructFromLexer(MasterLexer& lexer) { // If fingerprint is missing, it's OK. See the API documentation of the // constructor. if (fingerprint_str.size() > 0) { - decodeHex(fingerprint_str, fingerprint); + try { + decodeHex(fingerprint_str, fingerprint); + } catch (const isc::BadValue& e) { + isc_throw(InvalidRdataText, "Bad SSHFP fingerprint: " << e.what()); + } } return (new SSHFPImpl(algorithm, fingerprint_type, fingerprint)); @@ -102,8 +104,9 @@ SSHFP::constructFromLexer(MasterLexer& lexer) { /// valid hex encoding of the fingerprint. For compatibility with BIND 9, /// whitespace is allowed in the hex text (RFC4255 is silent on the matter). /// -/// \throw InvalidRdataText if any fields are missing, out of their valid -/// ranges, or incorrect. +/// \throw InvalidRdataText if any fields are missing, are out of their +/// valid ranges or are incorrect, or if the fingerprint is not a valid +/// hex string. /// /// \param sshfp_str A string containing the RDATA to be created SSHFP::SSHFP(const string& sshfp_str) : @@ -128,9 +131,6 @@ SSHFP::SSHFP(const string& sshfp_str) : } catch (const MasterLexer::LexerError& ex) { isc_throw(InvalidRdataText, "Failed to construct SSHFP from '" << sshfp_str << "': " << ex.what()); - } catch (const isc::BadValue& e) { - isc_throw(InvalidRdataText, - "Bad SSHFP fingerprint: " << e.what()); } impl_ = impl_ptr.release(); @@ -142,9 +142,8 @@ SSHFP::SSHFP(const string& sshfp_str) : /// of an SSHFP RDATA. /// /// \throw MasterLexer::LexerError General parsing error such as missing field. -/// \throw InvalidRdataText Fields are out of their valid range, or are -/// incorrect. -/// \throw BadValue Fingerprint is not a valid hex string. +/// \throw InvalidRdataText Fields are out of their valid range or are +/// incorrect, or if the fingerprint is not a valid hex string. /// /// \param lexer A \c MasterLexer object parsing a master file for the /// RDATA to be created @@ -293,8 +292,13 @@ SSHFP::getFingerprintType() const { return (impl_->fingerprint_type_); } +const std::vector<uint8_t>& +SSHFP::getFingerprint() const { + return (impl_->fingerprint_); +} + size_t -SSHFP::getFingerprintLen() const { +SSHFP::getFingerprintLength() const { return (impl_->fingerprint_.size()); } diff --git a/src/lib/dns/rdata/generic/sshfp_44.h b/src/lib/dns/rdata/generic/sshfp_44.h index 28ce0f3d22..85ae8067c5 100644 --- a/src/lib/dns/rdata/generic/sshfp_44.h +++ b/src/lib/dns/rdata/generic/sshfp_44.h @@ -17,6 +17,7 @@ #include <stdint.h> #include <string> +#include <vector> #include <dns/name.h> #include <dns/rdata.h> @@ -45,7 +46,8 @@ public: /// uint8_t getAlgorithmNumber() const; uint8_t getFingerprintType() const; - size_t getFingerprintLen() const; + const std::vector<uint8_t>& getFingerprint() const; + size_t getFingerprintLength() const; private: SSHFPImpl* constructFromLexer(MasterLexer& lexer); diff --git a/src/lib/dns/rdata/generic/tlsa_52.cc b/src/lib/dns/rdata/generic/tlsa_52.cc new file mode 100644 index 0000000000..774bdef6cf --- /dev/null +++ b/src/lib/dns/rdata/generic/tlsa_52.cc @@ -0,0 +1,350 @@ +// Copyright (C) 2014 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 <config.h> + +#include <boost/lexical_cast.hpp> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <util/encode/hex.h> +#include <dns/name.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata_pimpl_holder.h> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using namespace isc::util::encode; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct TLSAImpl { + // straightforward representation of TLSA RDATA fields + TLSAImpl(uint8_t certificate_usage, uint8_t selector, + uint8_t matching_type, const vector<uint8_t>& data) : + certificate_usage_(certificate_usage), + selector_(selector), + matching_type_(matching_type), + data_(data) + {} + + uint8_t certificate_usage_; + uint8_t selector_; + uint8_t matching_type_; + const vector<uint8_t> data_; +}; + +// helper function for string and lexer constructors +TLSAImpl* +TLSA::constructFromLexer(MasterLexer& lexer) { + const uint32_t certificate_usage = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (certificate_usage > 255) { + isc_throw(InvalidRdataText, + "TLSA certificate usage field out of range"); + } + + const uint32_t selector = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (selector > 255) { + isc_throw(InvalidRdataText, + "TLSA selector field out of range"); + } + + const uint32_t matching_type = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (matching_type > 255) { + isc_throw(InvalidRdataText, + "TLSA matching type field out of range"); + } + + std::string certificate_assoc_data; + std::string data_substr; + 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(data_substr); + certificate_assoc_data.append(data_substr); + } + lexer.ungetToken(); + + if (certificate_assoc_data.empty()) { + isc_throw(InvalidRdataText, "Empty TLSA certificate association data"); + } + + vector<uint8_t> data; + try { + decodeHex(certificate_assoc_data, data); + } catch (const isc::BadValue& e) { + isc_throw(InvalidRdataText, + "Bad TLSA certificate association data: " << e.what()); + } + + return (new TLSAImpl(certificate_usage, selector, matching_type, data)); +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid TLSA 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 Certificate Usage, Selector and Matching Type fields must be +/// within their valid ranges, but are not constrained to the values +/// defined in RFC6698. +/// +/// The Certificate Association Data Field field may be absent, but if +/// present it must contain a valid hex encoding of the data. Whitespace +/// is allowed in the hex text. +/// +/// \throw InvalidRdataText if any fields are missing, out of their +/// valid ranges, or are incorrect, or Certificate Association Data is +/// not a valid hex string. +/// +/// \param tlsa_str A string containing the RDATA to be created +TLSA::TLSA(const string& tlsa_str) : + impl_(NULL) +{ + // We use a smart pointer here because if there is an exception in + // this constructor, the destructor is not called and there could be + // a leak of the TLSAImpl that constructFromLexer() returns. + RdataPimplHolder<TLSAImpl> impl_ptr; + + try { + std::istringstream ss(tlsa_str); + MasterLexer lexer; + lexer.pushSource(ss); + + impl_ptr.reset(constructFromLexer(lexer)); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for TLSA: " + << tlsa_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct TLSA from '" << + tlsa_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 TLSA RDATA. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw InvalidRdataText Fields are out of their valid range, or are +/// incorrect, or Certificate Association Data is not a valid hex string. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +TLSA::TLSA(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer)) +{ +} + +/// \brief Constructor from InputBuffer. +/// +/// The passed buffer must contain a valid TLSA RDATA. +/// +/// The Certificate Usage, Selector and Matching Type fields must be +/// within their valid ranges, but are not constrained to the values +/// defined in RFC6698. It is okay for the certificate association data +/// to be missing (see the description of the constructor from string). +TLSA::TLSA(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len < 3) { + isc_throw(InvalidRdataLength, "TLSA record too short"); + } + + const uint8_t certificate_usage = buffer.readUint8(); + const uint8_t selector = buffer.readUint8(); + const uint8_t matching_type = buffer.readUint8(); + + vector<uint8_t> data; + rdata_len -= 3; + + if (rdata_len == 0) { + isc_throw(InvalidRdataLength, + "Empty TLSA certificate association data"); + } + + data.resize(rdata_len); + buffer.readData(&data[0], rdata_len); + + impl_ = new TLSAImpl(certificate_usage, selector, matching_type, data); +} + +TLSA::TLSA(uint8_t certificate_usage, uint8_t selector, + uint8_t matching_type, const std::string& certificate_assoc_data) : + impl_(NULL) +{ + if (certificate_assoc_data.empty()) { + isc_throw(InvalidRdataText, "Empty TLSA certificate association data"); + } + + vector<uint8_t> data; + try { + decodeHex(certificate_assoc_data, data); + } catch (const isc::BadValue& e) { + isc_throw(InvalidRdataText, + "Bad TLSA certificate association data: " << e.what()); + } + + impl_ = new TLSAImpl(certificate_usage, selector, matching_type, data); +} + +TLSA::TLSA(const TLSA& other) : + Rdata(), impl_(new TLSAImpl(*other.impl_)) +{} + +TLSA& +TLSA::operator=(const TLSA& source) { + if (this == &source) { + return (*this); + } + + TLSAImpl* newimpl = new TLSAImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +TLSA::~TLSA() { + delete impl_; +} + +void +TLSA::toWire(OutputBuffer& buffer) const { + buffer.writeUint8(impl_->certificate_usage_); + buffer.writeUint8(impl_->selector_); + buffer.writeUint8(impl_->matching_type_); + + // The constructors must ensure that the certificate association + // data field is not empty. + assert(!impl_->data_.empty()); + buffer.writeData(&impl_->data_[0], impl_->data_.size()); +} + +void +TLSA::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeUint8(impl_->certificate_usage_); + renderer.writeUint8(impl_->selector_); + renderer.writeUint8(impl_->matching_type_); + + // The constructors must ensure that the certificate association + // data field is not empty. + assert(!impl_->data_.empty()); + renderer.writeData(&impl_->data_[0], impl_->data_.size()); +} + +string +TLSA::toText() const { + // The constructors must ensure that the certificate association + // data field is not empty. + assert(!impl_->data_.empty()); + + return (lexical_cast<string>(static_cast<int>(impl_->certificate_usage_)) + " " + + lexical_cast<string>(static_cast<int>(impl_->selector_)) + " " + + lexical_cast<string>(static_cast<int>(impl_->matching_type_)) + " " + + encodeHex(impl_->data_)); +} + +int +TLSA::compare(const Rdata& other) const { + const TLSA& other_tlsa = dynamic_cast<const TLSA&>(other); + + if (impl_->certificate_usage_ < other_tlsa.impl_->certificate_usage_) { + return (-1); + } else if (impl_->certificate_usage_ > + other_tlsa.impl_->certificate_usage_) { + return (1); + } + + if (impl_->selector_ < other_tlsa.impl_->selector_) { + return (-1); + } else if (impl_->selector_ > other_tlsa.impl_->selector_) { + return (1); + } + + if (impl_->matching_type_ < other_tlsa.impl_->matching_type_) { + return (-1); + } else if (impl_->matching_type_ > + other_tlsa.impl_->matching_type_) { + return (1); + } + + const size_t this_len = impl_->data_.size(); + const size_t other_len = other_tlsa.impl_->data_.size(); + const size_t cmplen = min(this_len, other_len); + + if (cmplen > 0) { + const int cmp = memcmp(&impl_->data_[0], + &other_tlsa.impl_->data_[0], + cmplen); + if (cmp != 0) { + return (cmp); + } + } + + if (this_len == other_len) { + return (0); + } else if (this_len < other_len) { + return (-1); + } else { + return (1); + } +} + +uint8_t +TLSA::getCertificateUsage() const { + return (impl_->certificate_usage_); +} + +uint8_t +TLSA::getSelector() const { + return (impl_->selector_); +} + +uint8_t +TLSA::getMatchingType() const { + return (impl_->matching_type_); +} + +const std::vector<uint8_t>& +TLSA::getData() const { + return (impl_->data_); +} + +size_t +TLSA::getDataLength() const { + return (impl_->data_.size()); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/tlsa_52.h b/src/lib/dns/rdata/generic/tlsa_52.h new file mode 100644 index 0000000000..7d8c69a3d1 --- /dev/null +++ b/src/lib/dns/rdata/generic/tlsa_52.h @@ -0,0 +1,65 @@ +// Copyright (C) 2014 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. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <dns/name.h> +#include <dns/rdata.h> + +#include <string> +#include <vector> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct TLSAImpl; + +class TLSA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + TLSA(uint8_t certificate_usage, uint8_t selector, + uint8_t matching_type, const std::string& certificate_assoc_data); + TLSA& operator=(const TLSA& source); + ~TLSA(); + + /// + /// Specialized methods + /// + uint8_t getCertificateUsage() const; + uint8_t getSelector() const; + uint8_t getMatchingType() const; + const std::vector<uint8_t>& getData() const; + size_t getDataLength() const; + +private: + TLSAImpl* constructFromLexer(MasterLexer& lexer); + + TLSAImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata_pimpl_holder.h b/src/lib/dns/rdata_pimpl_holder.h new file mode 100644 index 0000000000..2705dd854d --- /dev/null +++ b/src/lib/dns/rdata_pimpl_holder.h @@ -0,0 +1,60 @@ +// Copyright (C) 2014 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. + +#ifndef DNS_RDATA_PIMPL_HOLDER_H +#define DNS_RDATA_PIMPL_HOLDER_H 1 + +#include <boost/noncopyable.hpp> + +#include <cstddef> // for NULL + +namespace isc { +namespace dns { +namespace rdata { + +template <typename T> +class RdataPimplHolder : boost::noncopyable { +public: + RdataPimplHolder(T* obj = NULL) : + obj_(obj) + {} + + ~RdataPimplHolder() { + delete obj_; + } + + void reset(T* obj = NULL) { + delete obj_; + obj_ = obj; + } + + T* get() { + return (obj_); + } + + T* release() { + T* obj = obj_; + obj_ = NULL; + return (obj); + } + +private: + T* obj_; +}; + +} // namespace rdata +} // namespace dns +} // namespace isc + +#endif // DNS_RDATA_PIMPL_HOLDER_H diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h index b4f1851aa4..709057e818 100644 --- a/src/lib/dns/rrclass-placeholder.h +++ b/src/lib/dns/rrclass-placeholder.h @@ -20,7 +20,7 @@ #include <string> #include <ostream> -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> #include <boost/optional.hpp> @@ -39,20 +39,20 @@ class AbstractMessageRenderer; /// \brief A standard DNS module exception that is thrown if an RRClass object /// is being constructed from an unrecognized string. /// -class InvalidRRClass : public Exception { +class InvalidRRClass : public DNSTextError { public: InvalidRRClass(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + DNSTextError(file, line, what) {} }; /// /// \brief A standard DNS module exception that is thrown if an RRClass object /// is being constructed from a incomplete (too short) wire-format data. /// -class IncompleteRRClass : public Exception { +class IncompleteRRClass : public isc::dns::Exception { public: IncompleteRRClass(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; /// diff --git a/src/lib/dns/rrparamregistry.h b/src/lib/dns/rrparamregistry.h index 1d59e019db..3e30a360e5 100644 --- a/src/lib/dns/rrparamregistry.h +++ b/src/lib/dns/rrparamregistry.h @@ -21,7 +21,7 @@ #include <boost/shared_ptr.hpp> -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> #include <dns/rdata.h> @@ -35,20 +35,20 @@ struct RRParamRegistryImpl; /// \brief A standard DNS module exception that is thrown if a new RR type is /// being registered with a different type string. /// -class RRTypeExists : public Exception { +class RRTypeExists : public isc::dns::Exception { public: RRTypeExists(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; /// /// \brief A standard DNS module exception that is thrown if a new RR class is /// being registered with a different type string. /// -class RRClassExists : public Exception { +class RRClassExists : public isc::dns::Exception { public: RRClassExists(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; namespace rdata { diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc index 8dfe884dac..b3da32c9de 100644 --- a/src/lib/dns/rrset.cc +++ b/src/lib/dns/rrset.cc @@ -254,6 +254,11 @@ BasicRRset::addRdata(const Rdata& rdata) { AbstractRRset::addRdata(rdata); } +void +BasicRRset::addRdata(const std::string& rdata_str) { + addRdata(createRdata(getType(), getClass(), rdata_str)); +} + unsigned int BasicRRset::getRdataCount() const { return (impl_->rdatalist_.size()); @@ -289,6 +294,50 @@ BasicRRset::toText() const { return (AbstractRRset::toText()); } +uint16_t +BasicRRset::getLength() const { + uint16_t length = 0; + RdataIteratorPtr it = getRdataIterator(); + + if (it->isLast()) { + // empty rrsets are only allowed for classes ANY and NONE + if (getClass() != RRClass::ANY() && + getClass() != RRClass::NONE()) { + isc_throw(EmptyRRset, "getLength() is attempted for an empty RRset"); + } + + // For an empty RRset, write the name, type, class and TTL once, + // followed by empty rdata. + length += getName().getLength(); + length += 2; // TYPE field + length += 2; // CLASS field + length += 4; // TTL field + length += 2; // RDLENGTH field (=0 in wire format) + + return (length); + } + + do { + // This is a size_t as some of the following additions may + // overflow due to a programming mistake somewhere. + size_t rrlen = 0; + + rrlen += getName().getLength(); + rrlen += 2; // TYPE field + rrlen += 2; // CLASS field + rrlen += 4; // TTL field + rrlen += 2; // RDLENGTH field + rrlen += it->getCurrent().getLength(); + + assert(length + rrlen < 65536); + length += rrlen; + + it->next(); + } while (!it->isLast()); + + return (length); +} + unsigned int BasicRRset::toWire(OutputBuffer& buffer) const { return (AbstractRRset::toWire(buffer)); @@ -322,6 +371,21 @@ RRset::getRRsigDataCount() const { } } +uint16_t +RRset::getLength() const { + uint16_t length = BasicRRset::getLength(); + + if (rrsig_) { + const uint16_t rrsigs_length = rrsig_->getLength(); + // the uint16_ts are promoted to ints during addition below, so + // it won't overflow a 16-bit register. + assert(length + rrsigs_length < 65536); + length += rrsigs_length; + } + + return (length); +} + unsigned int RRset::toWire(OutputBuffer& buffer) const { unsigned int rrs_written = BasicRRset::toWire(buffer); diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h index eb8fa6ed0c..c474ac6427 100644 --- a/src/lib/dns/rrset.h +++ b/src/lib/dns/rrset.h @@ -20,7 +20,7 @@ #include <boost/shared_ptr.hpp> -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> #include <dns/rdata.h> #include <dns/rrtype.h> @@ -36,10 +36,10 @@ namespace dns { /// \brief A standard DNS module exception that is thrown if an RRset object /// does not contain any RDATA where required. /// -class EmptyRRset : public Exception { +class EmptyRRset : public isc::dns::Exception { public: EmptyRRset(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; // forward declarations @@ -206,6 +206,20 @@ public: /// \return The number of \c Rdata objects contained. virtual unsigned int getRdataCount() const = 0; + /// \brief Get the wire format length of the \c AbstractRRset. + /// + /// This method returns the wire format length of the + /// \c AbstractRRset, which is calculated by summing the individual + /// lengths of the various fields that make up each RR. + /// + /// NOTE: When including name lengths, the allocation for + /// uncompressed name wire format representation is used. + /// + /// \return The length of the wire format representation of the + /// \c AbstractRRset. + /// \throw \c EmptyRRset if the \c AbstractRRset is empty. + virtual uint16_t getLength() const = 0; + /// \brief Returns the owner name of the \c RRset. /// /// \return A reference to a \c Name class object corresponding to the @@ -376,10 +390,27 @@ public: /// Still, this version would offer a more intuitive interface and is /// provided as such. /// + /// NOTE: Because a new Rdata object is constructed, this method can + /// throw a std::bad_cast exception if this RRset's class is NONE, + /// or if some other error occurs. If you want to be able to add + /// RDATA to an RRset whose class is NONE, please use the other + /// variant of \c addRdata() which accepts a \c ConstRdataPtr + /// argument. + /// /// \param rdata A reference to a \c rdata::RdataPtr (derived) class /// object, a copy of which is to be added to the \c RRset. virtual void addRdata(const rdata::Rdata& rdata) = 0; + /// \brief Add an RDATA to the RRset (string version). + /// + /// This method constructs an Rdata object from the the given + /// \c rdata_str in presentation format and adds it to the \c RRset. + /// + /// \param rdata_str RDATA string in presentation format. + /// \throw InvalidRdataText if the \c rdata_str is invalid for this + /// \c RRset. + virtual void addRdata(const std::string& rdata_str) = 0; + /// \brief Return an iterator to go through all RDATA stored in the /// \c RRset. /// @@ -642,6 +673,13 @@ public: /// \return The number of \c Rdata objects contained. virtual unsigned int getRdataCount() const; + /// \brief Get the wire format length of the \c BasicRRset. + /// + /// \return The length of the wire format representation of the + /// \c BasicRRset. + /// \throw \c EmptyRRset if the \c BasicRRset is empty. + virtual uint16_t getLength() const; + /// \brief Returns the owner name of the \c RRset. /// /// This method never throws an exception. @@ -727,6 +765,13 @@ public: /// See \c AbstractRRset::addRdata(const rdata::Rdata&). virtual void addRdata(const rdata::Rdata& rdata); + /// \brief Add an RDATA to the RRset (string version). + /// + /// \param rdata_str RDATA string in presentation format. + /// \throw InvalidRdataText if the \c rdata_str is invalid for this + /// \c RRset. + virtual void addRdata(const std::string& rdata_str); + /// \brief Return an iterator to go through all RDATA stored in the /// \c BasicRRset. /// @@ -813,6 +858,13 @@ public: virtual ~RRset(); + /// \brief Get the wire format length of the \c RRset. + /// + /// \return The length of the wire format representation of the + /// \c RRset. + /// \throw \c EmptyRRset if the \c RRset is empty. + virtual uint16_t getLength() const; + /// \brief Render the RRset in the wire format with name compression and /// truncation handling. /// diff --git a/src/lib/dns/rrttl.cc b/src/lib/dns/rrttl.cc index 73ac2599de..e6ce007bac 100644 --- a/src/lib/dns/rrttl.cc +++ b/src/lib/dns/rrttl.cc @@ -42,14 +42,15 @@ myIsalpha(char c) { struct Unit { char unit; uint32_t multiply; + uint32_t max_allowed; }; Unit units[] = { - { 'S', 1 }, - { 'M', 60 }, - { 'H', 60 * 60 }, - { 'D', 24 * 60 * 60 }, - { 'W', 7 * 24 * 60 * 60 } + { 'S', 1, 0xffffffff / 1 }, + { 'M', 60, 0xffffffff / 60 }, + { 'H', 60 * 60, 0xffffffff / (60 * 60) }, + { 'D', 24 * 60 * 60, 0xffffffff / (24 * 60 * 60) }, + { 'W', 7 * 24 * 60 * 60, 0xffffffff / (7 * 24 * 60 * 60) } }; } @@ -66,11 +67,9 @@ parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) { } return (false); } - // We use a larger data type during the computation. This is because - // some compilers don't fail when out of range, so we check the range - // ourselves later. - int64_t val = 0; + // We use a larger data type to handle negative number cases. + uint64_t val = 0; const string::const_iterator end = ttlstr.end(); string::const_iterator pos = ttlstr.begin(); @@ -92,7 +91,7 @@ parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) { } else { // Case without any units at all. Just convert and store // it. - val = boost::lexical_cast<int64_t>(ttlstr); + val = boost::lexical_cast<uint64_t>(ttlstr); break; } } @@ -100,11 +99,13 @@ parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) { units_mode = true; // Find the unit and get the size. uint32_t multiply = 1; // initialize to silence compiler warnings + uint32_t max_allowed = 0xffffffff; bool found = false; for (size_t i = 0; i < sizeof(units) / sizeof(*units); ++i) { if (toupper(*unit) == units[i].unit) { found = true; multiply = units[i].multiply; + max_allowed = units[i].max_allowed; break; } } @@ -122,15 +123,25 @@ parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) { } return (false); } - const int64_t value = boost::lexical_cast<int64_t>(string(pos, - unit)); + const uint64_t value = + boost::lexical_cast<uint64_t>(string(pos, unit)); + if (value > max_allowed) { + if (error_txt != NULL) { + *error_txt = "Part of TTL out of range: " + ttlstr; + } + return (false); + } + + // seconds cannot be out of range at this point. + const uint64_t seconds = value * multiply; + assert(seconds <= 0xffffffff); + // Add what we found - val += multiply * value; + val += seconds; // Check the partial value is still in range (the value can only // grow, so if we get out of range now, it won't get better, so // there's no need to continue). - if (value < 0 || value > 0xffffffff || val < 0 || - val > 0xffffffff) { + if (val < seconds || val > 0xffffffff) { if (error_txt != NULL) { *error_txt = "Part of TTL out of range: " + ttlstr; } @@ -146,9 +157,10 @@ parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) { return (false); } - if (val >= 0 && val <= 0xffffffff) { + if (val <= 0xffffffff) { ttlval = val; } else { + // This could be due to negative numbers in input, etc. if (error_txt != NULL) { *error_txt = "TTL out of range: " + ttlstr; } diff --git a/src/lib/dns/rrttl.h b/src/lib/dns/rrttl.h index 35403b6294..ffa3467970 100644 --- a/src/lib/dns/rrttl.h +++ b/src/lib/dns/rrttl.h @@ -15,7 +15,7 @@ #ifndef RRTTL_H #define RRTTL_H 1 -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> #include <boost/optional.hpp> @@ -36,20 +36,20 @@ class AbstractMessageRenderer; /// \brief A standard DNS module exception that is thrown if an RRTTL object /// is being constructed from an unrecognized string. /// -class InvalidRRTTL : public Exception { +class InvalidRRTTL : public DNSTextError { public: InvalidRRTTL(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + DNSTextError(file, line, what) {} }; /// /// \brief A standard DNS module exception that is thrown if an RRTTL object /// is being constructed from a incomplete (too short) wire-format data. /// -class IncompleteRRTTL : public Exception { +class IncompleteRRTTL : public isc::dns::Exception { public: IncompleteRRTTL(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; /// diff --git a/src/lib/dns/rrtype-placeholder.h b/src/lib/dns/rrtype-placeholder.h index 5541635caa..46167e45dc 100644 --- a/src/lib/dns/rrtype-placeholder.h +++ b/src/lib/dns/rrtype-placeholder.h @@ -20,7 +20,7 @@ #include <string> #include <ostream> -#include <exceptions/exceptions.h> +#include <dns/exceptions.h> // Solaris x86 defines DS in <sys/regset.h>, which gets pulled in by Boost #if defined(__sun) && defined(DS) @@ -42,20 +42,20 @@ class AbstractMessageRenderer; /// \brief A standard DNS module exception that is thrown if an RRType object /// is being constructed from an unrecognized string. /// -class InvalidRRType : public Exception { +class InvalidRRType : public DNSTextError { public: InvalidRRType(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + DNSTextError(file, line, what) {} }; /// /// \brief A standard DNS module exception that is thrown if an RRType object /// is being constructed from a incomplete (too short) wire-format data. /// -class IncompleteRRType : public Exception { +class IncompleteRRType : public isc::dns::Exception { public: IncompleteRRType(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} + isc::dns::Exception(file, line, what) {} }; /// diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am index 5029681a32..415700a5f1 100644 --- a/src/lib/dns/tests/Makefile.am +++ b/src/lib/dns/tests/Makefile.am @@ -21,6 +21,7 @@ TESTS = if HAVE_GTEST TESTS += run_unittests run_unittests_SOURCES = unittest_util.h unittest_util.cc +run_unittests_SOURCES += dns_exceptions_unittest.cc run_unittests_SOURCES += edns_unittest.cc run_unittests_SOURCES += master_lexer_inputsource_unittest.cc run_unittests_SOURCES += labelsequence_unittest.cc @@ -38,7 +39,9 @@ run_unittests_SOURCES += opcode_unittest.cc run_unittests_SOURCES += rcode_unittest.cc run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc run_unittests_SOURCES += rdatafields_unittest.cc +run_unittests_SOURCES += rdata_pimpl_holder_unittest.cc run_unittests_SOURCES += rdata_char_string_unittest.cc +run_unittests_SOURCES += rdata_char_string_data_unittest.cc run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc run_unittests_SOURCES += rdata_txt_like_unittest.cc @@ -59,10 +62,12 @@ run_unittests_SOURCES += rdata_nsec3param_like_unittest.cc run_unittests_SOURCES += rdata_rrsig_unittest.cc run_unittests_SOURCES += rdata_rp_unittest.cc run_unittests_SOURCES += rdata_srv_unittest.cc +run_unittests_SOURCES += rdata_tlsa_unittest.cc run_unittests_SOURCES += rdata_minfo_unittest.cc run_unittests_SOURCES += rdata_tsig_unittest.cc run_unittests_SOURCES += rdata_naptr_unittest.cc run_unittests_SOURCES += rdata_hinfo_unittest.cc +run_unittests_SOURCES += rdata_caa_unittest.cc run_unittests_SOURCES += rrset_unittest.cc run_unittests_SOURCES += question_unittest.cc run_unittests_SOURCES += rrparamregistry_unittest.cc diff --git a/src/lib/dns/tests/dns_exceptions_unittest.cc b/src/lib/dns/tests/dns_exceptions_unittest.cc new file mode 100644 index 0000000000..905e2caa76 --- /dev/null +++ b/src/lib/dns/tests/dns_exceptions_unittest.cc @@ -0,0 +1,69 @@ +// Copyright (C) 2014 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 <dns/exceptions.h> + +#include <gtest/gtest.h> + +namespace { // begin unnamed namespace + +TEST(DNSExceptionsTest, checkExceptionsHierarchy) { + EXPECT_NO_THROW({ + const isc::dns::Exception exception("", 0, ""); + const isc::Exception& exception_cast = + dynamic_cast<const isc::Exception&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::DNSTextError exception("", 0, ""); + const isc::dns::Exception& exception_cast = + dynamic_cast<const isc::dns::Exception&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::NameParserException exception("", 0, ""); + const isc::dns::DNSTextError& exception_cast = + dynamic_cast<const isc::dns::DNSTextError&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::DNSMessageFORMERR exception("", 0, ""); + const isc::dns::DNSProtocolError& exception_cast = + dynamic_cast<const isc::dns::DNSProtocolError&>(exception); + const isc::dns::Exception& exception_cast2 = + dynamic_cast<const isc::dns::Exception&>(exception); + // to avoid compiler warning + exception_cast.what(); + exception_cast2.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::DNSMessageBADVERS exception("", 0, ""); + const isc::dns::DNSProtocolError& exception_cast = + dynamic_cast<const isc::dns::DNSProtocolError&>(exception); + const isc::dns::Exception& exception_cast2 = + dynamic_cast<const isc::dns::Exception&>(exception); + // to avoid compiler warning + exception_cast.what(); + exception_cast2.what(); + }); +} + +} // end unnamed namespace diff --git a/src/lib/dns/tests/edns_unittest.cc b/src/lib/dns/tests/edns_unittest.cc index de2d2447dd..3fffc6ff4f 100644 --- a/src/lib/dns/tests/edns_unittest.cc +++ b/src/lib/dns/tests/edns_unittest.cc @@ -31,12 +31,14 @@ #include <gtest/gtest.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; const uint8_t EDNS::SUPPORTED_VERSION; @@ -159,8 +161,8 @@ TEST_F(EDNSTest, toWireRenderer) { EXPECT_EQ(1, edns_base.toWire(renderer, Rcode::NOERROR().getExtendedCode())); UnitTestUtil::readWireData("edns_toWire1.wire", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); // Typical case, enabling DNSSEC renderer.clear(); @@ -169,8 +171,8 @@ TEST_F(EDNSTest, toWireRenderer) { EXPECT_EQ(1, edns_base.toWire(renderer, Rcode::NOERROR().getExtendedCode())); UnitTestUtil::readWireData("edns_toWire2.wire", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); // Non-0 extended Rcode renderer.clear(); @@ -179,8 +181,8 @@ TEST_F(EDNSTest, toWireRenderer) { EXPECT_EQ(1, edns_base.toWire(renderer, Rcode::BADVERS().getExtendedCode())); UnitTestUtil::readWireData("edns_toWire3.wire", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); // Uncommon UDP buffer size renderer.clear(); @@ -190,8 +192,8 @@ TEST_F(EDNSTest, toWireRenderer) { EXPECT_EQ(1, edns_base.toWire(renderer, Rcode::NOERROR().getExtendedCode())); UnitTestUtil::readWireData("edns_toWire4.wire", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); // From RR with unknown flag. If used for toWire(), the unknown flag // should disappear. @@ -201,8 +203,8 @@ TEST_F(EDNSTest, toWireRenderer) { *opt_rdata).toWire(renderer, Rcode::NOERROR().getExtendedCode())); UnitTestUtil::readWireData("edns_toWire2.wire", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); // If the available length in the renderer is not sufficient for the OPT // RR, it shouldn't be inserted. @@ -222,8 +224,8 @@ TEST_F(EDNSTest, toWireBuffer) { EXPECT_EQ(1, edns_base.toWire(obuffer, Rcode::NOERROR().getExtendedCode())); UnitTestUtil::readWireData("edns_toWire1.wire", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(), - obuffer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + obuffer.getData(), obuffer.getLength()); } TEST_F(EDNSTest, createFromRR) { diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc index a3ac767b4f..c211a4b897 100644 --- a/src/lib/dns/tests/labelsequence_unittest.cc +++ b/src/lib/dns/tests/labelsequence_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2014 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 <config.h> + #include <util/buffer.h> #include <dns/labelsequence.h> @@ -853,6 +855,10 @@ TEST_F(LabelSequenceTest, serialize) { isc::BadValue); } +#ifdef ENABLE_DEBUG + +// These checks are enabled only in debug mode in the LabelSequence +// class. TEST_F(LabelSequenceTest, badDeserialize) { EXPECT_THROW(LabelSequence(NULL), isc::BadValue); const uint8_t zero_offsets[] = { 0 }; @@ -879,6 +885,8 @@ TEST_F(LabelSequenceTest, badDeserialize) { EXPECT_THROW(LabelSequence ls(offsets_noincrease), isc::BadValue); } +#endif + namespace { // Helper function; repeatedly calls diff --git a/src/lib/dns/tests/master_loader_unittest.cc b/src/lib/dns/tests/master_loader_unittest.cc index 4caa3a1988..09fc3529ac 100644 --- a/src/lib/dns/tests/master_loader_unittest.cc +++ b/src/lib/dns/tests/master_loader_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2014 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 @@ -123,7 +123,9 @@ public: EXPECT_EQ(rrttl, current->getTTL()); ASSERT_EQ(1, current->getRdataCount()); EXPECT_EQ(0, isc::dns::rdata::createRdata(type, RRClass::IN(), data)-> - compare(current->getRdataIterator()->getCurrent())); + compare(current->getRdataIterator()->getCurrent())) + << data << " vs. " + << current->getRdataIterator()->getCurrent().toText(); } void checkBasicRRs() { @@ -307,6 +309,481 @@ TEST_F(MasterLoaderTest, origin) { } } +TEST_F(MasterLoaderTest, generate) { + // Various forms of the directive + const char* generates[] = { + "$generate", + "$GENERATE", + "$Generate", + "$GeneratE", + "\"$GENERATE\"", + NULL + }; + for (const char** generate = generates; *generate != NULL; ++generate) { + SCOPED_TRACE(*generate); + + clear(); + const string directive = *generate; + const string input = + "$ORIGIN example.org.\n" + "before.example.org. 3600 IN A 192.0.2.0\n" + + directive + " 3-5 host$ A 192.0.2.$\n" + + "after.example.org. 3600 IN A 192.0.2.255\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + // The "before" and "after" scaffolding below checks that no + // extra records are added by $GENERATE outside the requested + // range. + checkRR("before.example.org", RRType::A(), "192.0.2.0"); + checkRR("host3.example.org", RRType::A(), "192.0.2.3"); + checkRR("host4.example.org", RRType::A(), "192.0.2.4"); + checkRR("host5.example.org", RRType::A(), "192.0.2.5"); + checkRR("after.example.org", RRType::A(), "192.0.2.255"); + } +} + +TEST_F(MasterLoaderTest, generateRelativeLHS) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 1-2 @ 3600 NS ns$.example.org.\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("example.org", RRType::NS(), "ns1.example.org."); + checkRR("example.org", RRType::NS(), "ns2.example.org."); +} + +TEST_F(MasterLoaderTest, generateInFront) { + // $ is in the front + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 9-10 $host 3600 TXT \"$ pomegranate\"\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("9host.example.org", RRType::TXT(), "9 pomegranate"); + checkRR("10host.example.org", RRType::TXT(), "10 pomegranate"); +} + +TEST_F(MasterLoaderTest, generateInMiddle) { + // $ is in the middle + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 9-10 num$-host 3600 TXT \"This is $ pomegranate\"\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("num9-host.example.org", RRType::TXT(), "This is 9 pomegranate"); + checkRR("num10-host.example.org", RRType::TXT(), "This is 10 pomegranate"); +} + +TEST_F(MasterLoaderTest, generateAtEnd) { + // $ is at the end + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 9-10 num$-host 3600 TXT Pomegranate$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("num9-host.example.org", RRType::TXT(), "Pomegranate9"); + checkRR("num10-host.example.org", RRType::TXT(), "Pomegranate10"); +} + +TEST_F(MasterLoaderTest, generateStripsQuotes) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 1-2 @ 3600 MX \"$ mx$.example.org.\"\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("example.org", RRType::MX(), "1 mx1.example.org."); + checkRR("example.org", RRType::MX(), "2 mx2.example.org."); +} + +TEST_F(MasterLoaderTest, generateWithDoublePlaceholder) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 9-10 host$ 3600 TXT \"This is $$ pomegranate\"\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("host9.example.org", RRType::TXT(), "This is $ pomegranate"); + checkRR("host10.example.org", RRType::TXT(), "This is $ pomegranate"); +} + +TEST_F(MasterLoaderTest, generateWithEscape) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 9-10 host$ 3600 TXT \"This is \\$\\pomegranate\"\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("host9.example.org", RRType::TXT(), "This is \\$\\pomegranate"); + checkRR("host10.example.org", RRType::TXT(), "This is \\$\\pomegranate"); +} + +TEST_F(MasterLoaderTest, generateWithParams) { + const string input = + "$ORIGIN example.org.\n" + "$TTL 3600\n" + "$GENERATE 2-3 host$ A 192.0.2.$\n" + "$GENERATE 5-6 host$ 3600 A 192.0.2.$\n" + "$GENERATE 8-9 host$ IN A 192.0.2.$\n" + "$GENERATE 11-12 host$ IN 3600 A 192.0.2.$\n" + "$GENERATE 14-15 host$ 3600 IN A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("host2.example.org", RRType::A(), "192.0.2.2"); + checkRR("host3.example.org", RRType::A(), "192.0.2.3"); + + checkRR("host5.example.org", RRType::A(), "192.0.2.5"); + checkRR("host6.example.org", RRType::A(), "192.0.2.6"); + + checkRR("host8.example.org", RRType::A(), "192.0.2.8"); + checkRR("host9.example.org", RRType::A(), "192.0.2.9"); + + checkRR("host11.example.org", RRType::A(), "192.0.2.11"); + checkRR("host12.example.org", RRType::A(), "192.0.2.12"); + + checkRR("host14.example.org", RRType::A(), "192.0.2.14"); + checkRR("host15.example.org", RRType::A(), "192.0.2.15"); +} + +TEST_F(MasterLoaderTest, generateWithStep) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 2-9/2 host$ 3600 A 192.0.2.$\n" + "$GENERATE 12-21/3 host$ 3600 A 192.0.2.$\n" + "$GENERATE 30-31/1 host$ 3600 A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("host2.example.org", RRType::A(), "192.0.2.2"); + checkRR("host4.example.org", RRType::A(), "192.0.2.4"); + checkRR("host6.example.org", RRType::A(), "192.0.2.6"); + checkRR("host8.example.org", RRType::A(), "192.0.2.8"); + + checkRR("host12.example.org", RRType::A(), "192.0.2.12"); + checkRR("host15.example.org", RRType::A(), "192.0.2.15"); + checkRR("host18.example.org", RRType::A(), "192.0.2.18"); + checkRR("host21.example.org", RRType::A(), "192.0.2.21"); + + checkRR("host30.example.org", RRType::A(), "192.0.2.30"); + checkRR("host31.example.org", RRType::A(), "192.0.2.31"); +} + +TEST_F(MasterLoaderTest, generateWithModifiers) { + const string input = + "$ORIGIN example.org.\n" + "$TTL 3600\n" + + // Use a positive delta of 1 in the LHS and a negative delta of + // -1 in the RHS + "$GENERATE 2-9/2 host${1} A 192.0.2.${-1}\n" + + "$GENERATE 10-12 host${0,4} A 192.0.2.$\n" + "$GENERATE 14-15 host${0,4,d} A 192.0.2.$\n" + + // Names are case-insensitive, so we use TXT's RDATA to check + // case with hex representation. + "$GENERATE 30-31 host$ TXT \"Value ${0,4,x}\"\n" + "$GENERATE 42-43 host$ TXT \"Value ${0,4,X}\"\n" + + // Octal does not use any alphabets + "$GENERATE 45-46 host${0,4,o} A 192.0.2.$\n" + + // Here, the LHS has a trailing dot (which would result in an + // out-of-zone name), but that should be handled as a relative + // name. + "$GENERATE 90-92 ${0,8,n} A 192.0.2.$\n" + + // Here, the LHS has no trailing dot, and results in the same + // number of labels as width=8 above. + "$GENERATE 94-96 ${0,7,n} A 192.0.2.$\n" + + // Names are case-insensitive, so we use TXT's RDATA to check + // case with nibble representation. + "$GENERATE 106-107 host$ TXT \"Value ${0,9,n}\"\n" + "$GENERATE 109-110 host$ TXT \"Value ${0,9,N}\"\n" + + // Junk type will not parse and 'd' is assumed. No error is + // generated (this is to match BIND 9 behavior). + "$GENERATE 200-201 host${0,4,j} A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + + checkRR("host3.example.org", RRType::A(), "192.0.2.1"); + checkRR("host5.example.org", RRType::A(), "192.0.2.3"); + checkRR("host7.example.org", RRType::A(), "192.0.2.5"); + checkRR("host9.example.org", RRType::A(), "192.0.2.7"); + + checkRR("host0010.example.org", RRType::A(), "192.0.2.10"); + checkRR("host0011.example.org", RRType::A(), "192.0.2.11"); + checkRR("host0012.example.org", RRType::A(), "192.0.2.12"); + + checkRR("host0014.example.org", RRType::A(), "192.0.2.14"); + checkRR("host0015.example.org", RRType::A(), "192.0.2.15"); + + checkRR("host30.example.org", RRType::TXT(), "Value 001e"); + checkRR("host31.example.org", RRType::TXT(), "Value 001f"); + + checkRR("host42.example.org", RRType::TXT(), "Value 002A"); + checkRR("host43.example.org", RRType::TXT(), "Value 002B"); + + checkRR("host0055.example.org", RRType::A(), "192.0.2.45"); + checkRR("host0056.example.org", RRType::A(), "192.0.2.46"); + + checkRR("a.5.0.0.example.org", RRType::A(), "192.0.2.90"); + checkRR("b.5.0.0.example.org", RRType::A(), "192.0.2.91"); + checkRR("c.5.0.0.example.org", RRType::A(), "192.0.2.92"); + + checkRR("e.5.0.0.example.org", RRType::A(), "192.0.2.94"); + checkRR("f.5.0.0.example.org", RRType::A(), "192.0.2.95"); + checkRR("0.6.0.0.example.org", RRType::A(), "192.0.2.96"); + + checkRR("host106.example.org", RRType::TXT(), "Value a.6.0.0.0"); + checkRR("host107.example.org", RRType::TXT(), "Value b.6.0.0.0"); + checkRR("host109.example.org", RRType::TXT(), "Value D.6.0.0.0"); + checkRR("host110.example.org", RRType::TXT(), "Value E.6.0.0.0"); + + checkRR("host0200.example.org", RRType::A(), "192.0.2.200"); + checkRR("host0201.example.org", RRType::A(), "192.0.2.201"); +} + +TEST_F(MasterLoaderTest, generateWithNoModifiers) { + const string input = + "$ORIGIN example.org.\n" + "$TTL 3600\n" + "$GENERATE 10-12 host${} A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + ASSERT_EQ(2, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "Invalid $GENERATE format modifiers", 3); + checkCallbackMessage(errors_.at(1), + "$GENERATE error", 3); +} + +TEST_F(MasterLoaderTest, generateWithBadModifiers) { + const string input = + "$ORIGIN example.org.\n" + "$TTL 3600\n" + "$GENERATE 10-12 host${GARBAGE} A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + ASSERT_EQ(2, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "Invalid $GENERATE format modifiers", 3); + checkCallbackMessage(errors_.at(1), + "$GENERATE error", 3); +} + +TEST_F(MasterLoaderTest, generateMissingRange) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "unexpected end of input", 2); +} + +TEST_F(MasterLoaderTest, generateMissingLHS) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 2-4\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "unexpected end of input", 2); +} + +TEST_F(MasterLoaderTest, generateMissingType) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 2-4 host$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "unexpected end of input", 2); +} + +TEST_F(MasterLoaderTest, generateMissingRHS) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 2-4 host$ A\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "unexpected end of input", 2); +} + +TEST_F(MasterLoaderTest, generateWithBadRangeSyntax) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE ABCD host$ 3600 A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "$GENERATE: invalid range: ABCD", 2); +} + +TEST_F(MasterLoaderTest, generateWithInvalidRange) { + // start > stop + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 2-1 host$ 3600 A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "$GENERATE: invalid range: 2-1", 2); +} + +TEST_F(MasterLoaderTest, generateWithInvalidClass) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 1-2 host$ 3600 CH A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "Class mismatch: CH vs. IN", 2); +} + +TEST_F(MasterLoaderTest, generateWithNoAvailableTTL) { + const string input = + "$ORIGIN example.org.\n" + "$GENERATE 1-2 host$ A 192.0.2.$\n"; + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_FALSE(loader_->loadedSucessfully()); + EXPECT_EQ(1, errors_.size()); // For the broken GENERATE + EXPECT_TRUE(warnings_.empty()); + + checkCallbackMessage(errors_.at(0), + "no TTL specified; load rejected", 2); +} + // Test the source is correctly popped even after error TEST_F(MasterLoaderTest, popAfterError) { const string include_str = "$include " TEST_DATA_SRCDIR @@ -952,4 +1429,19 @@ TEST_F(MasterLoaderTest, previousInInclude) { checkARR("www.example.org"); } +TEST_F(MasterLoaderTest, numericOwnerName) { + const string input("$ORIGIN example.org.\n" + "1 3600 IN A 192.0.2.1\n"); + stringstream ss(input); + setLoader(ss, Name("example.org."), RRClass::IN(), + MasterLoader::MANY_ERRORS); + + loader_->load(); + EXPECT_TRUE(loader_->loadedSucessfully()); + EXPECT_TRUE(errors_.empty()); + EXPECT_TRUE(warnings_.empty()); + + checkRR("1.example.org", RRType::A(), "192.0.2.1"); +} + } diff --git a/src/lib/dns/tests/message_unittest.cc b/src/lib/dns/tests/message_unittest.cc index 8aaebaa183..00b8a5bd5f 100644 --- a/src/lib/dns/tests/message_unittest.cc +++ b/src/lib/dns/tests/message_unittest.cc @@ -41,13 +41,15 @@ #include <gtest/gtest.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; // // Note: we need more tests, including: @@ -217,10 +219,9 @@ TEST_F(MessageTest, fromWireWithTSIG) { EXPECT_EQ(TSIGKey::HMACMD5_NAME(), tsig_rr->getRdata().getAlgorithm()); EXPECT_EQ(0x4da8877a, tsig_rr->getRdata().getTimeSigned()); EXPECT_EQ(TSIGContext::DEFAULT_FUDGE, tsig_rr->getRdata().getFudge()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - tsig_rr->getRdata().getMAC(), - tsig_rr->getRdata().getMACSize(), - expected_mac, sizeof(expected_mac)); + matchWireData(expected_mac, sizeof(expected_mac), + tsig_rr->getRdata().getMAC(), + tsig_rr->getRdata().getMACSize()); EXPECT_EQ(0, tsig_rr->getRdata().getError()); EXPECT_EQ(0, tsig_rr->getRdata().getOtherLen()); EXPECT_EQ(static_cast<void*>(NULL), tsig_rr->getRdata().getOtherData()); @@ -572,12 +573,10 @@ TEST_F(MessageTest, parseHeader) { message_parse.endSection(Message::SECTION_ADDITIONAL)); } -TEST_F(MessageTest, fromWire) { - // fromWire() isn't allowed in the render mode. - EXPECT_THROW(factoryFromFile(message_render, "message_fromWire1"), - InvalidMessageOperation); - - factoryFromFile(message_parse, "message_fromWire1"); +void +checkMessageFromWire(const Message& message_parse, + const Name& test_name) +{ EXPECT_EQ(0x1035, message_parse.getQid()); EXPECT_EQ(Opcode::QUERY(), message_parse.getOpcode()); EXPECT_EQ(Rcode::NOERROR(), message_parse.getRcode()); @@ -608,6 +607,37 @@ TEST_F(MessageTest, fromWire) { EXPECT_TRUE(it->isLast()); } + +TEST_F(MessageTest, fromWire) { + // fromWire() isn't allowed in the render mode. + EXPECT_THROW(factoryFromFile(message_render, "message_fromWire1"), + InvalidMessageOperation); + + factoryFromFile(message_parse, "message_fromWire1"); + checkMessageFromWire(message_parse, test_name); +} + +TEST_F(MessageTest, fromWireMultiple) { + // Parse from wire multiple times. + factoryFromFile(message_parse, "message_fromWire1"); + factoryFromFile(message_parse, "message_fromWire1"); + factoryFromFile(message_parse, "message_fromWire1"); + factoryFromFile(message_parse, "message_fromWire1"); + checkMessageFromWire(message_parse, test_name); + + // Calling parseHeader() directly before fromWire() should not cause + // any problems. + received_data.clear(); + UnitTestUtil::readWireData("message_fromWire1", received_data); + + InputBuffer buffer(&received_data[0], received_data.size()); + message_parse.parseHeader(buffer); + message_parse.fromWire(buffer); + message_parse.parseHeader(buffer); + message_parse.fromWire(buffer); + checkMessageFromWire(message_parse, test_name); +} + TEST_F(MessageTest, fromWireShortBuffer) { // We trim a valid message (ending with an SOA RR) for one byte. // fromWire() should throw an exception while parsing the trimmed RR. @@ -729,8 +759,8 @@ TEST_F(MessageTest, toWire) { message_render.toWire(renderer); vector<unsigned char> data; UnitTestUtil::readWireData("message_toWire1", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageTest, toWireSigned) { @@ -766,8 +796,8 @@ TEST_F(MessageTest, toWireSigned) { message_render.toWire(renderer); vector<unsigned char> data; UnitTestUtil::readWireData("message_toWire6", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageTest, toWireSignedAndTruncated) { @@ -810,8 +840,8 @@ TEST_F(MessageTest, toWireSignedAndTruncated) { message_render.toWire(renderer); vector<unsigned char> data; UnitTestUtil::readWireData("message_toWire7", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageTest, toWireInParseMode) { @@ -864,12 +894,11 @@ commonTSIGToWireCheck(Message& message, MessageRenderer& renderer, message.addRRset(Message::SECTION_ANSWER, ans_rrset); } - message.toWire(renderer, tsig_ctx); + message.toWire(renderer, &tsig_ctx); vector<unsigned char> expected_data; UnitTestUtil::readWireData(expected_file, expected_data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), - &expected_data[0], expected_data.size()); + matchWireData(&expected_data[0], expected_data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageTest, toWireWithTSIG) { @@ -997,7 +1026,7 @@ TEST_F(MessageTest, toWireTSIGTruncation3) { message_render.addQuestion(Question(Name("www.example.com"), RRClass::IN(), RRType(i))); } - message_render.toWire(renderer, tsig_ctx); + message_render.toWire(renderer, &tsig_ctx); // Check the rendered data by parsing it. We only check it has the // TC bit on, has the correct number of questions, and has a TSIG RR. diff --git a/src/lib/dns/tests/messagerenderer_unittest.cc b/src/lib/dns/tests/messagerenderer_unittest.cc index 582c164b6c..2b4da59ca1 100644 --- a/src/lib/dns/tests/messagerenderer_unittest.cc +++ b/src/lib/dns/tests/messagerenderer_unittest.cc @@ -19,6 +19,7 @@ #include <dns/messagerenderer.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> #include <gtest/gtest.h> @@ -33,6 +34,7 @@ using isc::dns::LabelSequence; using isc::dns::MessageRenderer; using isc::util::OutputBuffer; using boost::lexical_cast; +using isc::util::unittests::matchWireData; namespace { class MessageRendererTest : public ::testing::Test { @@ -56,8 +58,8 @@ TEST_F(MessageRendererTest, writeIntger) { renderer.writeUint16(data16); expected_size += sizeof(data16); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &testdata[1], sizeof(data16)); + matchWireData(&testdata[1], sizeof(data16), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, writeName) { @@ -65,8 +67,8 @@ TEST_F(MessageRendererTest, writeName) { renderer.writeName(Name("a.example.com.")); renderer.writeName(Name("b.example.com.")); renderer.writeName(Name("a.example.org.")); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, writeNameInLargeBuffer) { @@ -77,11 +79,9 @@ TEST_F(MessageRendererTest, writeNameInLargeBuffer) { renderer.writeName(Name("a.example.com.")); renderer.writeName(Name("a.example.com.")); renderer.writeName(Name("b.example.com.")); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t*>(renderer.getData()) + - offset, - renderer.getLength() - offset, - &data[0], data.size()); + matchWireData(&data[0], data.size(), + static_cast<const uint8_t*>(renderer.getData()) + offset, + renderer.getLength() - offset); } TEST_F(MessageRendererTest, writeNameWithUncompressed) { @@ -89,8 +89,8 @@ TEST_F(MessageRendererTest, writeNameWithUncompressed) { renderer.writeName(Name("a.example.com.")); renderer.writeName(Name("b.example.com."), false); renderer.writeName(Name("b.example.com.")); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, writeNamePointerChain) { @@ -98,8 +98,8 @@ TEST_F(MessageRendererTest, writeNamePointerChain) { renderer.writeName(Name("a.example.com.")); renderer.writeName(Name("b.example.com.")); renderer.writeName(Name("b.example.com.")); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, compressMode) { @@ -126,8 +126,8 @@ TEST_F(MessageRendererTest, writeNameCaseCompress) { // this should match the first name in terms of compression: renderer.writeName(Name("b.exAmple.CoM.")); renderer.writeName(Name("a.example.org.")); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, writeNameCaseSensitiveCompress) { @@ -138,8 +138,8 @@ TEST_F(MessageRendererTest, writeNameCaseSensitiveCompress) { renderer.writeName(Name("a.example.com.")); renderer.writeName(Name("b.eXample.com.")); renderer.writeName(Name("c.eXample.com.")); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, writeNameMixedCaseCompress) { @@ -171,11 +171,10 @@ TEST_F(MessageRendererTest, writeRootName) { renderer.writeName(Name(".")); renderer.writeName(example_name); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t*>(renderer.getData()), - renderer.getLength(), - static_cast<const uint8_t*>(expected.getData()), - expected.getLength()); + matchWireData(static_cast<const uint8_t*>(expected.getData()), + expected.getLength(), + static_cast<const uint8_t*>(renderer.getData()), + renderer.getLength()); } TEST_F(MessageRendererTest, writeNameLabelSequence1) { @@ -192,8 +191,8 @@ TEST_F(MessageRendererTest, writeNameLabelSequence1) { // example.com. renderer.writeName(ls1); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, writeNameLabelSequence2) { @@ -207,8 +206,8 @@ TEST_F(MessageRendererTest, writeNameLabelSequence2) { // a.example.com (without root .) renderer.writeName(ls1); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, writeNameLabelSequence3) { @@ -235,8 +234,8 @@ TEST_F(MessageRendererTest, writeNameLabelSequence3) { // example renderer.writeName(ls1); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(MessageRendererTest, setBuffer) { diff --git a/src/lib/dns/tests/name_unittest.cc b/src/lib/dns/tests/name_unittest.cc index 10d1e550cc..bb8320e543 100644 --- a/src/lib/dns/tests/name_unittest.cc +++ b/src/lib/dns/tests/name_unittest.cc @@ -25,6 +25,7 @@ #include <dns/messagerenderer.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> #include <gtest/gtest.h> @@ -32,6 +33,7 @@ using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; +using isc::util::unittests::matchWireData; // // XXX: these are defined as class static constants, but some compilers @@ -137,9 +139,8 @@ NameTest::compareInWireFormat(const Name& name_actual, name_actual.toWire(buffer_actual); name_expected.toWire(buffer_expected); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - buffer_actual.getData(), buffer_actual.getLength(), - buffer_expected.getData(), buffer_expected.getLength()); + matchWireData(buffer_expected.getData(), buffer_expected.getLength(), + buffer_actual.getData(), buffer_actual.getLength()); } TEST_F(NameTest, nonlocalObject) { @@ -164,6 +165,64 @@ checkBadTextName(const string& txt) { NameParserException); } +TEST_F(NameTest, checkExceptionsHierarchy) { + EXPECT_NO_THROW({ + const isc::dns::EmptyLabel exception("", 0, ""); + const isc::dns::NameParserException& exception_cast = + dynamic_cast<const isc::dns::NameParserException&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::TooLongName exception("", 0, ""); + const isc::dns::NameParserException& exception_cast = + dynamic_cast<const isc::dns::NameParserException&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::TooLongLabel exception("", 0, ""); + const isc::dns::NameParserException& exception_cast = + dynamic_cast<const isc::dns::NameParserException&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::BadLabelType exception("", 0, ""); + const isc::dns::NameParserException& exception_cast = + dynamic_cast<const isc::dns::NameParserException&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::BadEscape exception("", 0, ""); + const isc::dns::NameParserException& exception_cast = + dynamic_cast<const isc::dns::NameParserException&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::IncompleteName exception("", 0, ""); + const isc::dns::NameParserException& exception_cast = + dynamic_cast<const isc::dns::NameParserException&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); + + EXPECT_NO_THROW({ + const isc::dns::MissingNameOrigin exception("", 0, ""); + const isc::dns::NameParserException& exception_cast = + dynamic_cast<const isc::dns::NameParserException&>(exception); + // to avoid compiler warning + exception_cast.what(); + }); +} + TEST_F(NameTest, fromText) { vector<string> strnames; strnames.push_back("www.example.com"); @@ -454,8 +513,8 @@ TEST_F(NameTest, toWireBuffer) { UnitTestUtil::readWireData(string("01610376697803636f6d00"), data); Name("a.vix.com.").toWire(buffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &data[0], data.size(), - buffer.getData(), buffer.getLength()); + matchWireData(&data[0], data.size(), + buffer.getData(), buffer.getLength()); } // @@ -468,8 +527,8 @@ TEST_F(NameTest, toWireRenderer) { UnitTestUtil::readWireData(string("01610376697803636f6d00"), data); Name("a.vix.com.").toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &data[0], data.size(), - renderer.getData(), renderer.getLength()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } // @@ -628,9 +687,8 @@ TEST_F(NameTest, at) { } example_name.toWire(buffer_expected); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &data[0], data.size(), buffer_expected.getData(), - buffer_expected.getLength()); + matchWireData(&data[0], data.size(), + buffer_expected.getData(), buffer_expected.getLength()); // Out-of-range access: should trigger an exception. EXPECT_THROW(example_name.at(example_name.getLength()), OutOfRange); diff --git a/src/lib/dns/tests/nsec3hash_unittest.cc b/src/lib/dns/tests/nsec3hash_unittest.cc index 4ef0c7b70c..44f8096ae4 100644 --- a/src/lib/dns/tests/nsec3hash_unittest.cc +++ b/src/lib/dns/tests/nsec3hash_unittest.cc @@ -19,6 +19,7 @@ #include <boost/scoped_ptr.hpp> #include <dns/nsec3hash.h> +#include <dns/labelsequence.h> #include <dns/rdataclass.h> #include <util/encode/hex.h> @@ -92,6 +93,18 @@ calculateCheck(NSEC3Hash& hash) { // Check case-insensitiveness EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", hash.calculate(Name("EXAMPLE"))); + + // Repeat for the LabelSequence variant. + + // A couple of normal cases from the RFC5155 example. + EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", + hash.calculate(LabelSequence(Name("example")))); + EXPECT_EQ("35MTHGPGCU1QG68FAB165KLNSNK3DPVL", + hash.calculate(LabelSequence(Name("a.example")))); + + // Check case-insensitiveness + EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", + hash.calculate(LabelSequence(Name("EXAMPLE")))); } TEST_F(NSEC3HashTest, calculate) { @@ -113,13 +126,16 @@ TEST_F(NSEC3HashTest, calculate) { EXPECT_EQ("CK0POJMG874LJREF7EFN8430QVIT8BSM", NSEC3HashPtr(NSEC3Hash::create(generic::NSEC3PARAM("1 0 0 -"))) ->calculate(Name("com"))); + EXPECT_EQ("CK0POJMG874LJREF7EFN8430QVIT8BSM", + NSEC3HashPtr(NSEC3Hash::create(generic::NSEC3PARAM("1 0 0 -"))) + ->calculate(LabelSequence(Name("com")))); // Using unusually large iterations, something larger than the 8-bit range. // (expected hash value generated by BIND 9's dnssec-signzone) EXPECT_EQ("COG6A52MJ96MNMV3QUCAGGCO0RHCC2Q3", NSEC3HashPtr(NSEC3Hash::create( generic::NSEC3PARAM("1 0 256 AABBCCDD"))) - ->calculate(Name("example.org"))); + ->calculate(LabelSequence(Name("example.org")))); } // Common checks for match cases @@ -169,6 +185,9 @@ class TestNSEC3Hash : public NSEC3Hash { virtual string calculate(const Name&) const { return ("00000000000000000000000000000000"); } + virtual string calculate(const LabelSequence&) const { + return ("00000000000000000000000000000000"); + } virtual bool match(const generic::NSEC3PARAM&) const { return (true); } @@ -207,6 +226,8 @@ TEST_F(NSEC3HashTest, setCreator) { // Re-check an existing case using the default creator/hash implementation EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", test_hash->calculate(Name("example"))); + EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", + test_hash->calculate(LabelSequence(Name("example")))); // Replace the creator, and confirm the hash values are faked TestNSEC3HashCreator test_creator; @@ -215,12 +236,16 @@ TEST_F(NSEC3HashTest, setCreator) { test_hash.reset(NSEC3Hash::create(generic::NSEC3PARAM("1 0 12 aabbccdd"))); EXPECT_EQ("00000000000000000000000000000000", test_hash->calculate(Name("example"))); + EXPECT_EQ("00000000000000000000000000000000", + test_hash->calculate(LabelSequence(Name("example")))); // Same for hash from NSEC3 RDATA test_hash.reset(NSEC3Hash::create(generic::NSEC3 ("1 0 12 aabbccdd " + string(nsec3_common)))); EXPECT_EQ("00000000000000000000000000000000", test_hash->calculate(Name("example"))); + EXPECT_EQ("00000000000000000000000000000000", + test_hash->calculate(LabelSequence(Name("example")))); // If we set a special flag big (0x80) on creation, it will act like the // default creator. @@ -228,17 +253,23 @@ TEST_F(NSEC3HashTest, setCreator) { "1 128 12 aabbccdd"))); EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", test_hash->calculate(Name("example"))); + EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", + test_hash->calculate(LabelSequence(Name("example")))); test_hash.reset(NSEC3Hash::create(generic::NSEC3 ("1 128 12 aabbccdd " + string(nsec3_common)))); EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", test_hash->calculate(Name("example"))); + EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", + test_hash->calculate(LabelSequence(Name("example")))); // Reset the creator to default, and confirm that setNSEC3HashCreator(NULL); test_hash.reset(NSEC3Hash::create(generic::NSEC3PARAM("1 0 12 aabbccdd"))); EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", test_hash->calculate(Name("example"))); + EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", + test_hash->calculate(LabelSequence(Name("example")))); } } // end namespace diff --git a/src/lib/dns/tests/question_unittest.cc b/src/lib/dns/tests/question_unittest.cc index d1214a1238..8e1667f5c9 100644 --- a/src/lib/dns/tests/question_unittest.cc +++ b/src/lib/dns/tests/question_unittest.cc @@ -28,11 +28,13 @@ #include <gtest/gtest.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class QuestionTest : public ::testing::Test { @@ -100,16 +102,16 @@ TEST_F(QuestionTest, toWireBuffer) { test_question1.toWire(obuffer); test_question2.toWire(obuffer); UnitTestUtil::readWireData("question_toWire1", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(), - obuffer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + obuffer.getData(), obuffer.getLength()); } TEST_F(QuestionTest, toWireRenderer) { test_question1.toWire(renderer); test_question2.toWire(renderer); UnitTestUtil::readWireData("question_toWire2", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); } TEST_F(QuestionTest, toWireTruncated) { diff --git a/src/lib/dns/tests/rdata_afsdb_unittest.cc b/src/lib/dns/tests/rdata_afsdb_unittest.cc index 9a628cd178..6e933f5d59 100644 --- a/src/lib/dns/tests/rdata_afsdb_unittest.cc +++ b/src/lib/dns/tests/rdata_afsdb_unittest.cc @@ -24,12 +24,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; const char* const afsdb_text = "1 afsdb.example.com."; const char* const afsdb_text2 = "0 root.example.com."; @@ -155,9 +157,8 @@ TEST_F(Rdata_AFSDB_Test, toWireBuffer) { UnitTestUtil::readWireData("rdata_afsdb_toWire1.wire", expected_wire); // then compare them - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - &expected_wire[0], expected_wire.size()); + matchWireData(&expected_wire[0], expected_wire.size(), + obuffer.getData(), obuffer.getLength()); // clear buffer for the next test obuffer.clear(); @@ -170,9 +171,8 @@ TEST_F(Rdata_AFSDB_Test, toWireBuffer) { UnitTestUtil::readWireData("rdata_afsdb_toWire2.wire", expected_wire); // then compare them - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - &expected_wire[0], expected_wire.size()); + matchWireData(&expected_wire[0], expected_wire.size(), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_AFSDB_Test, toWireRenderer) { @@ -187,9 +187,8 @@ TEST_F(Rdata_AFSDB_Test, toWireRenderer) { UnitTestUtil::readWireData("rdata_afsdb_toWire1.wire", expected_wire); // then compare them - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - &expected_wire[0], expected_wire.size()); + matchWireData(&expected_wire[0], expected_wire.size(), + renderer.getData(), renderer.getLength()); // clear renderer for the next test renderer.clear(); @@ -202,9 +201,8 @@ TEST_F(Rdata_AFSDB_Test, toWireRenderer) { UnitTestUtil::readWireData("rdata_afsdb_toWire2.wire", expected_wire); // then compare them - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - &expected_wire[0], expected_wire.size()); + matchWireData(&expected_wire[0], expected_wire.size(), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_AFSDB_Test, toText) { diff --git a/src/lib/dns/tests/rdata_caa_unittest.cc b/src/lib/dns/tests/rdata_caa_unittest.cc new file mode 100644 index 0000000000..b88aba31e7 --- /dev/null +++ b/src/lib/dns/tests/rdata_caa_unittest.cc @@ -0,0 +1,327 @@ +// Copyright (C) 2014 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 <algorithm> +#include <string> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rrclass.h> +#include <dns/rrtype.h> + +#include <gtest/gtest.h> + +#include <dns/tests/unittest_util.h> +#include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> + +#include <boost/algorithm/string.hpp> + +using namespace std; +using namespace isc; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; + +namespace { +class Rdata_CAA_Test : public RdataTest { +protected: + Rdata_CAA_Test() : + caa_txt("0 issue \"ca.example.net\""), + rdata_caa(caa_txt) + {} + + void checkFromText_None(const string& rdata_str) { + checkFromText<generic::CAA, isc::Exception, isc::Exception>( + rdata_str, rdata_caa, false, false); + } + + void checkFromText_InvalidText(const string& rdata_str) { + checkFromText<generic::CAA, InvalidRdataText, InvalidRdataText>( + rdata_str, rdata_caa, true, true); + } + + void checkFromText_LexerError(const string& rdata_str) { + checkFromText + <generic::CAA, InvalidRdataText, MasterLexer::LexerError>( + rdata_str, rdata_caa, true, true); + } + + void checkFromText_BadString(const string& rdata_str) { + checkFromText + <generic::CAA, InvalidRdataText, isc::Exception>( + rdata_str, rdata_caa, true, false); + } + + const string caa_txt; + const generic::CAA rdata_caa; +}; + +const uint8_t rdata_caa_wiredata[] = { + // flags + 0x00, + // tag length + 0x5, + // tag + 'i', 's', 's', 'u', 'e', + // value + 'c', 'a', '.', 'e', 'x', 'a', 'm', 'p', 'l', 'e', + '.', 'n', 'e', 't' +}; + +TEST_F(Rdata_CAA_Test, createFromText) { + // Basic test + checkFromText_None(caa_txt); + + // With different spacing + checkFromText_None("0 issue \"ca.example.net\""); + + // Combination of lowercase and uppercase + checkFromText_None("0 IssUE \"ca.example.net\""); + + // string constructor throws if there's extra text, + // but lexer constructor doesn't + checkFromText_BadString(caa_txt + "\n" + caa_txt); + + // Missing value field + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue")); +} + +TEST_F(Rdata_CAA_Test, fields) { + // Some of these may not be RFC conformant, but we relax the check + // in our code to work with other field values that may show up in + // the future. + EXPECT_NO_THROW(const generic::CAA rdata_caa2("1 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("2 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("3 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("128 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("255 issue \"ca.example.net\"")); + + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 foo \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 bar \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 12345 \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 w0x1y2z3 \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 relaxed-too \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 RELAXED.too \"ca.example.net\"")); + + // No value (this is redundant to the last test case in the + // .createFromText test + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue")); + + // > 255 would be broken + EXPECT_THROW(const generic::CAA rdata_caa2("256 issue \"ca.example.net\""), + InvalidRdataText); + + // Missing tag actually passes because it parses the value as tag + // and assumes that the value is empty instead. + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 \"ca.example.net\"")); + + // Tag is too long + const std::string tag(256, 'a'); + const std::string rdata_txt("0 " + tag + " \"ca.example.net\""); + EXPECT_THROW(const generic::CAA rdata_caa2(rdata_txt), InvalidRdataText); +} + +TEST_F(Rdata_CAA_Test, characterStringValue) { + const generic::CAA rdata_caa_unquoted("0 issue ca.example.net"); + EXPECT_EQ(0, rdata_caa_unquoted.compare(rdata_caa)); + + const generic::CAA rdata_caa_escape_X("0 issue ca.e\\xample.net"); + EXPECT_EQ(0, rdata_caa_escape_X.compare(rdata_caa)); + + const generic::CAA rdata_caa_escape_DDD("0 issue ca.e\\120ample.net"); + EXPECT_EQ(0, rdata_caa_escape_DDD.compare(rdata_caa)); + + const generic::CAA rdata_caa_multiline("0 issue (\nca.example.net)"); + EXPECT_EQ(0, rdata_caa_multiline.compare(rdata_caa)); +} + +TEST_F(Rdata_CAA_Test, badText) { + checkFromText_LexerError("0"); + checkFromText_LexerError("ZERO issue \"ca.example.net\""); + EXPECT_THROW(const generic::CAA rdata_caa2(caa_txt + " extra text"), + InvalidRdataText); + + // Yes, this is redundant to the last test cases in the .fields test + checkFromText_InvalidText("2345 issue \"ca.example.net\""); + + // negative values are trapped in the lexer rather than the + // constructor + checkFromText_LexerError("-2 issue \"ca.example.net\""); +} + +TEST_F(Rdata_CAA_Test, copyAndAssign) { + // Copy construct + generic::CAA rdata_caa2(rdata_caa); + EXPECT_EQ(0, rdata_caa.compare(rdata_caa2)); + + // Assignment, mainly to confirm it doesn't cause disruption. + rdata_caa2 = rdata_caa; + EXPECT_EQ(0, rdata_caa.compare(rdata_caa2)); +} + +TEST_F(Rdata_CAA_Test, createFromWire) { + // Basic test + EXPECT_EQ(0, rdata_caa.compare( + *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire1.wire"))); + + // Combination of lowercase and uppercase + EXPECT_EQ(0, rdata_caa.compare( + *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire2.wire"))); + + // Value field is empty + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire3.wire")); + + // Tag field is empty + EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire4.wire"), + InvalidRdataText); + + // Value field is shorter than rdata len + EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire5"), + InvalidBufferPosition); + + // all RDATA is missing + EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire6"), + InvalidBufferPosition); +} + +TEST_F(Rdata_CAA_Test, createFromParams) { + const generic::CAA rdata_caa2(0, "issue", "ca.example.net"); + EXPECT_EQ(0, rdata_caa2.compare(rdata_caa)); + + const generic::CAA rdata_caa4(0, "issue", "ca.e\\xample.net"); + EXPECT_EQ(0, rdata_caa4.compare(rdata_caa)); + + const generic::CAA rdata_caa5(0, "issue", "ca.e\\120ample.net"); + EXPECT_EQ(0, rdata_caa5.compare(rdata_caa)); + + // Tag is empty + EXPECT_THROW(const generic::CAA rdata_caa3(0, "", "ca.example.net"), + isc::InvalidParameter); + + // Tag is too long + const std::string tag(256, 'a'); + EXPECT_THROW(const generic::CAA rdata_caa3(0, tag, "ca.example.net"), + isc::InvalidParameter); + + // Value is too long + const std::string value(65536, 'a'); + EXPECT_THROW(const generic::CAA rdata_caa3(0, "issue", value), + InvalidRdataLength); +} + +TEST_F(Rdata_CAA_Test, toText) { + EXPECT_TRUE(boost::iequals(caa_txt, rdata_caa.toText())); + + const string caa_txt2("1 issue \"\""); + const generic::CAA rdata_caa2(caa_txt2); + EXPECT_TRUE(boost::iequals(caa_txt2, rdata_caa2.toText())); +} + +TEST_F(Rdata_CAA_Test, toWire) { + obuffer.clear(); + rdata_caa.toWire(obuffer); + + matchWireData(rdata_caa_wiredata, sizeof(rdata_caa_wiredata), + obuffer.getData(), obuffer.getLength()); +} + +TEST_F(Rdata_CAA_Test, compare) { + // Equality test is repeated from createFromWire tests above. + EXPECT_EQ(0, rdata_caa.compare( + *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire1.wire"))); + + const generic::CAA rdata_caa2("1 issue \"ca.example.net\""); + + EXPECT_EQ(1, rdata_caa2.compare(rdata_caa)); + EXPECT_EQ(-1, rdata_caa.compare(rdata_caa2)); +} + +TEST_F(Rdata_CAA_Test, getFlags) { + EXPECT_EQ(0, rdata_caa.getFlags()); +} + +TEST_F(Rdata_CAA_Test, getTag) { + EXPECT_EQ("issue", rdata_caa.getTag()); +} + +TEST_F(Rdata_CAA_Test, getValue) { + const uint8_t value_data[] = { + 'c', 'a', '.', + 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', + 'n', 'e', 't' + }; + + const std::vector<uint8_t>& value = rdata_caa.getValue(); + matchWireData(value_data, sizeof(value_data), + &value[0], value.size()); +} + +TEST_F(Rdata_CAA_Test, emptyValueFromWire) { + const uint8_t rdf_wiredata[] = { + // flags + 0x00, + // tag length + 0x5, + // tag + 'i', 's', 's', 'u', 'e' + }; + + const generic::CAA rdf = + dynamic_cast<const generic::CAA&> + (*rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire3.wire")); + + EXPECT_EQ(0, rdf.getFlags()); + EXPECT_EQ("issue", rdf.getTag()); + + obuffer.clear(); + rdf.toWire(obuffer); + + matchWireData(rdf_wiredata, sizeof(rdf_wiredata), + obuffer.getData(), obuffer.getLength()); +} + +TEST_F(Rdata_CAA_Test, emptyValueFromString) { + const generic::CAA rdata_caa2("0 issue"); + const uint8_t rdata_caa2_wiredata[] = { + // flags + 0x00, + // tag length + 0x5, + // tag + 'i', 's', 's', 'u', 'e' + }; + + EXPECT_EQ(0, rdata_caa2.getFlags()); + EXPECT_EQ("issue", rdata_caa2.getTag()); + + obuffer.clear(); + rdata_caa2.toWire(obuffer); + + matchWireData(rdata_caa2_wiredata, sizeof(rdata_caa2_wiredata), + obuffer.getData(), obuffer.getLength()); +} +} diff --git a/src/lib/dns/tests/rdata_char_string_data_unittest.cc b/src/lib/dns/tests/rdata_char_string_data_unittest.cc new file mode 100644 index 0000000000..88a00a9b56 --- /dev/null +++ b/src/lib/dns/tests/rdata_char_string_data_unittest.cc @@ -0,0 +1,187 @@ +// Copyright (C) 2014 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 <util/unittests/wiredata.h> + +#include <dns/exceptions.h> +#include <dns/rdata.h> +#include <dns/rdata/generic/detail/char_string.h> +#include <util/buffer.h> + +#include <gtest/gtest.h> + +#include <string> +#include <vector> + +using namespace isc::dns; +using namespace isc::dns::rdata; +using isc::dns::rdata::generic::detail::CharStringData; +using isc::dns::rdata::generic::detail::stringToCharStringData; +using isc::dns::rdata::generic::detail::charStringDataToString; +using isc::dns::rdata::generic::detail::compareCharStringDatas; +using isc::util::unittests::matchWireData; + +namespace { +const uint8_t test_charstr[] = { + 'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g' +}; + +class CharStringDataTest : public ::testing::Test { +protected: + CharStringDataTest() : + // char-string representation for test data using two types of escape + // ('r' = 114) + test_str("Test\\ St\\114ing") + { + str_region.beg = &test_str[0]; + str_region.len = test_str.size(); + } + CharStringData chstr; // place holder + const std::string test_str; + MasterToken::StringRegion str_region; +}; + +MasterToken::StringRegion +createStringRegion(const std::string& str) { + MasterToken::StringRegion region; + region.beg = &str[0]; // note std ensures this works even if str is empty + region.len = str.size(); + return (region); +} + +TEST_F(CharStringDataTest, normalConversion) { + uint8_t tmp[3]; // placeholder for expected sequence + + stringToCharStringData(str_region, chstr); + matchWireData(test_charstr, sizeof(test_charstr), &chstr[0], chstr.size()); + + // Empty string + chstr.clear(); + stringToCharStringData(createStringRegion(""), chstr); + EXPECT_TRUE(chstr.empty()); + + // Possible largest char string + chstr.clear(); + std::string long_str(255, 'x'); + stringToCharStringData(createStringRegion(long_str), chstr); + std::vector<uint8_t> expected; + expected.insert(expected.end(), long_str.begin(), long_str.end()); + matchWireData(&expected[0], expected.size(), &chstr[0], chstr.size()); + + // Escaped '\' + chstr.clear(); + tmp[0] = '\\'; + stringToCharStringData(createStringRegion("\\\\"), chstr); + matchWireData(tmp, 1, &chstr[0], chstr.size()); + + // Boundary values for \DDD + chstr.clear(); + tmp[0] = 0; + stringToCharStringData(createStringRegion("\\000"), chstr); + matchWireData(tmp, 1, &chstr[0], chstr.size()); + + chstr.clear(); + stringToCharStringData(createStringRegion("\\255"), chstr); + tmp[0] = 255; + matchWireData(tmp, 1, &chstr[0], chstr.size()); + + // Another digit follows DDD; it shouldn't cause confusion + chstr.clear(); + stringToCharStringData(createStringRegion("\\2550"), chstr); + tmp[1] = '0'; + matchWireData(tmp, 2, &chstr[0], chstr.size()); +} + +TEST_F(CharStringDataTest, badConversion) { + // input string ending with (non escaped) '\' + chstr.clear(); + EXPECT_THROW(stringToCharStringData(createStringRegion("foo\\"), chstr), + InvalidRdataText); +} + +TEST_F(CharStringDataTest, badDDD) { + // Check various type of bad form of \DDD + + // Not a number + EXPECT_THROW(stringToCharStringData(createStringRegion("\\1a2"), chstr), + InvalidRdataText); + EXPECT_THROW(stringToCharStringData(createStringRegion("\\12a"), chstr), + InvalidRdataText); + + // Not in the range of uint8_t + EXPECT_THROW(stringToCharStringData(createStringRegion("\\256"), chstr), + InvalidRdataText); + + // Short buffer + EXPECT_THROW(stringToCharStringData(createStringRegion("\\42"), chstr), + InvalidRdataText); +} + +const struct TestData { + const char *data; + const char *expected; +} conversion_data[] = { + {"Test\"Test", "Test\\\"Test"}, + {"Test;Test", "Test\\;Test"}, + {"Test\\Test", "Test\\\\Test"}, + {"Test\x1fTest", "Test\\031Test"}, + {"Test ~ Test", "Test ~ Test"}, + {"Test\x7fTest", "Test\\127Test"}, + {NULL, NULL} +}; + +TEST_F(CharStringDataTest, charStringDataToString) { + for (const TestData* cur = conversion_data; cur->data != NULL; ++cur) { + uint8_t idata[32]; + size_t length = std::strlen(cur->data); + ASSERT_LT(length, sizeof(idata)); + std::memcpy(idata, cur->data, length); + const CharStringData test_data(idata, idata + length); + EXPECT_EQ(cur->expected, charStringDataToString(test_data)); + } +} + +TEST_F(CharStringDataTest, compareCharStringData) { + CharStringData charstr; + CharStringData charstr2; + CharStringData charstr_small1; + CharStringData charstr_small2; + CharStringData charstr_large1; + CharStringData charstr_large2; + CharStringData charstr_empty; + + stringToCharStringData(createStringRegion("test string"), charstr); + stringToCharStringData(createStringRegion("test string"), charstr2); + stringToCharStringData(createStringRegion("test strin"), charstr_small1); + stringToCharStringData(createStringRegion("test strina"), charstr_small2); + stringToCharStringData(createStringRegion("test stringa"), charstr_large1); + stringToCharStringData(createStringRegion("test strinz"), charstr_large2); + + EXPECT_EQ(0, compareCharStringDatas(charstr, charstr2)); + EXPECT_EQ(0, compareCharStringDatas(charstr2, charstr)); + EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small1)); + EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small2)); + EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large1)); + EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large2)); + EXPECT_EQ(-1, compareCharStringDatas(charstr_small1, charstr)); + EXPECT_EQ(-1, compareCharStringDatas(charstr_small2, charstr)); + EXPECT_EQ(1, compareCharStringDatas(charstr_large1, charstr)); + EXPECT_EQ(1, compareCharStringDatas(charstr_large2, charstr)); + + EXPECT_EQ(-1, compareCharStringDatas(charstr_empty, charstr)); + EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_empty)); + EXPECT_EQ(0, compareCharStringDatas(charstr_empty, charstr_empty)); +} + +} // unnamed namespace diff --git a/src/lib/dns/tests/rdata_cname_unittest.cc b/src/lib/dns/tests/rdata_cname_unittest.cc index 5f602f011e..6e706e0a8d 100644 --- a/src/lib/dns/tests/rdata_cname_unittest.cc +++ b/src/lib/dns/tests/rdata_cname_unittest.cc @@ -24,12 +24,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_CNAME_Test : public RdataTest { @@ -115,20 +117,18 @@ TEST_F(Rdata_CNAME_Test, createFromLexer) { TEST_F(Rdata_CNAME_Test, toWireBuffer) { rdata_cname.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_cname, sizeof(wiredata_cname)); + matchWireData(wiredata_cname, sizeof(wiredata_cname), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_CNAME_Test, toWireRenderer) { rdata_cname.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_cname, sizeof(wiredata_cname)); + matchWireData(wiredata_cname, sizeof(wiredata_cname), + renderer.getData(), renderer.getLength()); + rdata_cname2.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_cname2, sizeof(wiredata_cname2)); + matchWireData(wiredata_cname2, sizeof(wiredata_cname2), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_CNAME_Test, toText) { diff --git a/src/lib/dns/tests/rdata_dhcid_unittest.cc b/src/lib/dns/tests/rdata_dhcid_unittest.cc index 77baccd893..5bc1d1ef4f 100644 --- a/src/lib/dns/tests/rdata_dhcid_unittest.cc +++ b/src/lib/dns/tests/rdata_dhcid_unittest.cc @@ -22,14 +22,16 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::util::encode; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { @@ -125,8 +127,8 @@ TEST_F(Rdata_DHCID_Test, toWireRenderer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_dhcid_toWire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_DHCID_Test, toWireBuffer) { @@ -134,8 +136,8 @@ TEST_F(Rdata_DHCID_Test, toWireBuffer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_dhcid_toWire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(), - obuffer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_DHCID_Test, toText) { diff --git a/src/lib/dns/tests/rdata_dname_unittest.cc b/src/lib/dns/tests/rdata_dname_unittest.cc index 7209e36e61..9e13a168ca 100644 --- a/src/lib/dns/tests/rdata_dname_unittest.cc +++ b/src/lib/dns/tests/rdata_dname_unittest.cc @@ -24,12 +24,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_DNAME_Test : public RdataTest { @@ -117,20 +119,18 @@ TEST_F(Rdata_DNAME_Test, createFromLexer) { TEST_F(Rdata_DNAME_Test, toWireBuffer) { rdata_dname.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_dname, sizeof(wiredata_dname)); + matchWireData(wiredata_dname, sizeof(wiredata_dname), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_DNAME_Test, toWireRenderer) { rdata_dname.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_dname, sizeof(wiredata_dname)); + matchWireData(wiredata_dname, sizeof(wiredata_dname), + renderer.getData(), renderer.getLength()); + rdata_dname2.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_dname2, sizeof(wiredata_dname2)); + matchWireData(wiredata_dname2, sizeof(wiredata_dname2), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_DNAME_Test, toText) { diff --git a/src/lib/dns/tests/rdata_dnskey_unittest.cc b/src/lib/dns/tests/rdata_dnskey_unittest.cc index 872dc2af95..0c77735d17 100644 --- a/src/lib/dns/tests/rdata_dnskey_unittest.cc +++ b/src/lib/dns/tests/rdata_dnskey_unittest.cc @@ -27,13 +27,15 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_DNSKEY_Test : public RdataTest { @@ -155,9 +157,9 @@ TEST_F(Rdata_DNSKEY_Test, toWireRenderer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_dnskey_fromWire.wire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(renderer.getData()) + 2, - renderer.getLength() - 2, &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + static_cast<const uint8_t *>(renderer.getData()) + 2, + renderer.getLength() - 2); } TEST_F(Rdata_DNSKEY_Test, toWireBuffer) { @@ -165,9 +167,8 @@ TEST_F(Rdata_DNSKEY_Test, toWireBuffer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_dnskey_fromWire.wire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_DNSKEY_Test, createFromWire) { diff --git a/src/lib/dns/tests/rdata_ds_like_unittest.cc b/src/lib/dns/tests/rdata_ds_like_unittest.cc index ae6a360f5b..e278f1ffcb 100644 --- a/src/lib/dns/tests/rdata_ds_like_unittest.cc +++ b/src/lib/dns/tests/rdata_ds_like_unittest.cc @@ -26,12 +26,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { // hacks to make templates work @@ -148,11 +150,9 @@ TYPED_TEST(Rdata_DS_LIKE_Test, toWireRenderer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_ds_fromWire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t*> - (this->renderer.getData()) + 2, - this->renderer.getLength() - 2, - &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + static_cast<const uint8_t*>(this->renderer.getData()) + 2, + this->renderer.getLength() - 2); } TYPED_TEST(Rdata_DS_LIKE_Test, toWireBuffer) { diff --git a/src/lib/dns/tests/rdata_hinfo_unittest.cc b/src/lib/dns/tests/rdata_hinfo_unittest.cc index 7be2cb6026..887848e2b2 100644 --- a/src/lib/dns/tests/rdata_hinfo_unittest.cc +++ b/src/lib/dns/tests/rdata_hinfo_unittest.cc @@ -24,13 +24,15 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; using namespace isc::dns::rdata::generic; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_HINFO_Test : public RdataTest { @@ -113,19 +115,18 @@ TEST_F(Rdata_HINFO_Test, toText) { TEST_F(Rdata_HINFO_Test, toWire) { HINFO hinfo(hinfo_str); - hinfo.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(), - obuffer.getLength(), hinfo_rdata, sizeof(hinfo_rdata)); + hinfo.toWire(obuffer); + matchWireData(hinfo_rdata, sizeof (hinfo_rdata), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_HINFO_Test, toWireRenderer) { HINFO hinfo(hinfo_str); hinfo.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), hinfo_rdata, - sizeof(hinfo_rdata)); + matchWireData(hinfo_rdata, sizeof (hinfo_rdata), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_HINFO_Test, compare) { diff --git a/src/lib/dns/tests/rdata_in_a_unittest.cc b/src/lib/dns/tests/rdata_in_a_unittest.cc index 3f65641f50..c940075409 100644 --- a/src/lib/dns/tests/rdata_in_a_unittest.cc +++ b/src/lib/dns/tests/rdata_in_a_unittest.cc @@ -27,17 +27,19 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> #include <sstream> #include <arpa/inet.h> #include <sys/socket.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_IN_A_Test : public RdataTest { @@ -121,16 +123,14 @@ TEST_F(Rdata_IN_A_Test, createFromWire) { TEST_F(Rdata_IN_A_Test, toWireBuffer) { rdata_in_a.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_in_a, sizeof(wiredata_in_a)); + matchWireData(wiredata_in_a, sizeof (wiredata_in_a), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_IN_A_Test, toWireRenderer) { rdata_in_a.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_in_a, sizeof(wiredata_in_a)); + matchWireData(wiredata_in_a, sizeof (wiredata_in_a), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_IN_A_Test, toText) { diff --git a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc index 82f75a897c..ff92d07d87 100644 --- a/src/lib/dns/tests/rdata_in_aaaa_unittest.cc +++ b/src/lib/dns/tests/rdata_in_aaaa_unittest.cc @@ -24,12 +24,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_IN_AAAA_Test : public RdataTest { @@ -117,16 +119,14 @@ TEST_F(Rdata_IN_AAAA_Test, createFromLexer) { TEST_F(Rdata_IN_AAAA_Test, toWireBuffer) { rdata_in_aaaa.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_in_aaaa, sizeof(wiredata_in_aaaa)); + matchWireData(wiredata_in_aaaa, sizeof (wiredata_in_aaaa), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_IN_AAAA_Test, toWireRenderer) { rdata_in_aaaa.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_in_aaaa, sizeof(wiredata_in_aaaa)); + matchWireData(wiredata_in_aaaa, sizeof (wiredata_in_aaaa), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_IN_AAAA_Test, toText) { diff --git a/src/lib/dns/tests/rdata_minfo_unittest.cc b/src/lib/dns/tests/rdata_minfo_unittest.cc index 3ce6a6cd49..8addb29c69 100644 --- a/src/lib/dns/tests/rdata_minfo_unittest.cc +++ b/src/lib/dns/tests/rdata_minfo_unittest.cc @@ -26,12 +26,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::util; using namespace isc::dns; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_MINFO_Test : public RdataTest { @@ -177,33 +179,30 @@ TEST_F(Rdata_MINFO_Test, toWireBuffer) { rdata_minfo.toWire(obuffer); vector<unsigned char> data; UnitTestUtil::readWireData("rdata_minfo_toWireUncompressed1.wire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(obuffer.getData()), - obuffer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + obuffer.getData(), obuffer.getLength()); obuffer.clear(); rdata_minfo2.toWire(obuffer); vector<unsigned char> data2; UnitTestUtil::readWireData("rdata_minfo_toWireUncompressed2.wire", data2); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(obuffer.getData()), - obuffer.getLength(), &data2[0], data2.size()); + matchWireData(&data2[0], data2.size(), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_MINFO_Test, toWireRenderer) { rdata_minfo.toWire(renderer); vector<unsigned char> data; UnitTestUtil::readWireData("rdata_minfo_toWire1.wire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(renderer.getData()), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); + renderer.clear(); rdata_minfo2.toWire(renderer); vector<unsigned char> data2; UnitTestUtil::readWireData("rdata_minfo_toWire2.wire", data2); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(renderer.getData()), - renderer.getLength(), &data2[0], data2.size()); + matchWireData(&data2[0], data2.size(), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_MINFO_Test, toText) { diff --git a/src/lib/dns/tests/rdata_mx_unittest.cc b/src/lib/dns/tests/rdata_mx_unittest.cc index 6e4eaba41f..926374aae0 100644 --- a/src/lib/dns/tests/rdata_mx_unittest.cc +++ b/src/lib/dns/tests/rdata_mx_unittest.cc @@ -23,12 +23,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_MX_Test : public RdataTest { @@ -101,8 +103,8 @@ TEST_F(Rdata_MX_Test, toWireRenderer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_mx_toWire1", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_MX_Test, toWireBuffer) { @@ -111,8 +113,8 @@ TEST_F(Rdata_MX_Test, toWireBuffer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_mx_toWire2", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(), - obuffer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_MX_Test, toText) { diff --git a/src/lib/dns/tests/rdata_naptr_unittest.cc b/src/lib/dns/tests/rdata_naptr_unittest.cc index d828e73ea2..982bf76505 100644 --- a/src/lib/dns/tests/rdata_naptr_unittest.cc +++ b/src/lib/dns/tests/rdata_naptr_unittest.cc @@ -24,13 +24,15 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; using namespace isc::dns::rdata::generic; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_NAPTR_Test : public RdataTest { @@ -165,19 +167,18 @@ TEST_F(Rdata_NAPTR_Test, createFromLexer) { TEST_F(Rdata_NAPTR_Test, toWire) { NAPTR naptr(naptr_str); - naptr.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(), - obuffer.getLength(), naptr_rdata, sizeof(naptr_rdata)); + naptr.toWire(obuffer); + matchWireData(naptr_rdata, sizeof(naptr_rdata), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_NAPTR_Test, toWireRenderer) { NAPTR naptr(naptr_str); naptr.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), naptr_rdata, - sizeof(naptr_rdata)); + matchWireData(naptr_rdata, sizeof(naptr_rdata), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_NAPTR_Test, toText) { diff --git a/src/lib/dns/tests/rdata_ns_unittest.cc b/src/lib/dns/tests/rdata_ns_unittest.cc index 53eb6700c3..305149c481 100644 --- a/src/lib/dns/tests/rdata_ns_unittest.cc +++ b/src/lib/dns/tests/rdata_ns_unittest.cc @@ -24,12 +24,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_NS_Test : public RdataTest { @@ -118,20 +120,18 @@ TEST_F(Rdata_NS_Test, createFromLexer) { TEST_F(Rdata_NS_Test, toWireBuffer) { rdata_ns.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_ns, sizeof(wiredata_ns)); + matchWireData(wiredata_ns, sizeof(wiredata_ns), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_NS_Test, toWireRenderer) { rdata_ns.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_ns, sizeof(wiredata_ns)); + matchWireData(wiredata_ns, sizeof(wiredata_ns), + renderer.getData(), renderer.getLength()); + rdata_ns2.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_ns2, sizeof(wiredata_ns2)); + matchWireData(wiredata_ns2, sizeof(wiredata_ns2), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_NS_Test, toText) { diff --git a/src/lib/dns/tests/rdata_nsec3param_like_unittest.cc b/src/lib/dns/tests/rdata_nsec3param_like_unittest.cc index 23d6d0ed68..ea38e7c475 100644 --- a/src/lib/dns/tests/rdata_nsec3param_like_unittest.cc +++ b/src/lib/dns/tests/rdata_nsec3param_like_unittest.cc @@ -22,14 +22,17 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> #include <string> #include <vector> using namespace std; -using isc::UnitTestUtil; using namespace isc::dns; using namespace isc::dns::rdata; +using namespace isc::util; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { @@ -230,8 +233,8 @@ toWireCheck(RRType rrtype, OUTPUT_TYPE& output, const string& data_file) { output.clear(); output.writeUint16(rdlen); createRdata(rrtype, RRClass::IN(), buffer, rdlen)->toWire(output); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, output.getData(), - output.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + output.getData(), output.getLength()); } TYPED_TEST(NSEC3PARAMLikeTest, toWire) { diff --git a/src/lib/dns/tests/rdata_nsec3param_unittest.cc b/src/lib/dns/tests/rdata_nsec3param_unittest.cc index 4fccbf311b..9f121cc928 100644 --- a/src/lib/dns/tests/rdata_nsec3param_unittest.cc +++ b/src/lib/dns/tests/rdata_nsec3param_unittest.cc @@ -27,13 +27,15 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_NSEC3PARAM_Test : public RdataTest { @@ -170,9 +172,9 @@ TEST_F(Rdata_NSEC3PARAM_Test, toWireRenderer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_nsec3param_fromWire1", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(renderer.getData()) + 2, - renderer.getLength() - 2, &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + static_cast<const uint8_t *>(renderer.getData()) + 2, + renderer.getLength() - 2); } TEST_F(Rdata_NSEC3PARAM_Test, toWireBuffer) { @@ -180,9 +182,8 @@ TEST_F(Rdata_NSEC3PARAM_Test, toWireBuffer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_nsec3param_fromWire1", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_NSEC3PARAM_Test, getHashAlg) { diff --git a/src/lib/dns/tests/rdata_nsec_unittest.cc b/src/lib/dns/tests/rdata_nsec_unittest.cc index 810e2cc3d0..dcbc1f312f 100644 --- a/src/lib/dns/tests/rdata_nsec_unittest.cc +++ b/src/lib/dns/tests/rdata_nsec_unittest.cc @@ -26,12 +26,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_NSEC_Test : public RdataTest { @@ -90,9 +92,9 @@ TEST_F(Rdata_NSEC_Test, toWireRenderer_NSEC) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_nsec_fromWire1", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(renderer.getData()) + 2, - renderer.getLength() - 2, &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + static_cast<const uint8_t *>(renderer.getData()) + 2, + renderer.getLength() - 2); } TEST_F(Rdata_NSEC_Test, toWireBuffer_NSEC) { diff --git a/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc b/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc index fbb256a151..9c2420075a 100644 --- a/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc +++ b/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc @@ -23,6 +23,7 @@ #include <gtest/gtest.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> #include <boost/lexical_cast.hpp> @@ -30,10 +31,12 @@ #include <vector> using namespace std; -using boost::lexical_cast; -using isc::UnitTestUtil; using namespace isc::dns; using namespace isc::dns::rdata; +using namespace isc::util; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; +using boost::lexical_cast; namespace { @@ -253,16 +256,16 @@ TEST_F(NSEC3BitmapTest, emptyMap) { OutputBuffer obuffer(0); obuffer.writeUint16(rdlen); empty_nsec3.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(), - obuffer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + obuffer.getData(), obuffer.getLength()); // Same for MessageRenderer. obuffer.clear(); MessageRenderer renderer; renderer.writeUint16(rdlen); empty_nsec3.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } } diff --git a/src/lib/dns/tests/rdata_opt_unittest.cc b/src/lib/dns/tests/rdata_opt_unittest.cc index 20ccfe4994..9d09a60656 100644 --- a/src/lib/dns/tests/rdata_opt_unittest.cc +++ b/src/lib/dns/tests/rdata_opt_unittest.cc @@ -23,19 +23,28 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_OPT_Test : public RdataTest { // there's nothing to specialize }; -const generic::OPT rdata_opt; +const uint8_t rdata_opt_wiredata[] = { + // Option code + 0x00, 0x2a, + // Option length + 0x00, 0x03, + // Option data + 0x00, 0x01, 0x02 +}; TEST_F(Rdata_OPT_Test, createFromText) { // OPT RR cannot be created from text. @@ -46,14 +55,28 @@ TEST_F(Rdata_OPT_Test, createFromWire) { // Valid cases: in the simple implementation with no supported options, // we can only check these don't throw. EXPECT_NO_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass("CLASS4096"), - "rdata_opt_fromWire")); + "rdata_opt_fromWire1")); EXPECT_NO_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::CH(), - "rdata_opt_fromWire", 2)); + "rdata_opt_fromWire1", 2)); - // short buffer case. + // Short RDLEN. This throws InvalidRdataLength even if subsequent + // pseudo RRs cause RDLEN size to be exhausted. EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(), - "rdata_opt_fromWire", 11), + "rdata_opt_fromWire2"), InvalidRdataLength); + EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(), + "rdata_opt_fromWire3"), + InvalidRdataLength); + // Option lengths can add up and overflow RDLEN. Unlikely when + // parsed from wire data, but we'll check for it anyway. + EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(), + "rdata_opt_fromWire4"), + InvalidRdataText); + + // short buffer case. + EXPECT_THROW(rdataFactoryFromFile(RRType::OPT(), RRClass::IN(), + "rdata_opt_fromWire1", 11), + InvalidBufferPosition); } TEST_F(Rdata_OPT_Test, createFromLexer) { @@ -64,26 +87,118 @@ TEST_F(Rdata_OPT_Test, createFromLexer) { } TEST_F(Rdata_OPT_Test, toWireBuffer) { + const generic::OPT rdata_opt = + dynamic_cast<const generic::OPT&> + (*rdataFactoryFromFile(RRType("OPT"), RRClass("IN"), + "rdata_opt_fromWire1", 2)); + + obuffer.clear(); rdata_opt.toWire(obuffer); - EXPECT_EQ(0, obuffer.getLength()); + + matchWireData(rdata_opt_wiredata, sizeof(rdata_opt_wiredata), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_OPT_Test, toWireRenderer) { + const generic::OPT rdata_opt = + dynamic_cast<const generic::OPT&> + (*rdataFactoryFromFile(RRType("OPT"), RRClass("IN"), + "rdata_opt_fromWire1", 2)); + + renderer.clear(); rdata_opt.toWire(renderer); - EXPECT_EQ(0, obuffer.getLength()); + + matchWireData(rdata_opt_wiredata, sizeof(rdata_opt_wiredata), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_OPT_Test, toText) { - EXPECT_EQ("", rdata_opt.toText()); + // empty OPT + const generic::OPT rdata_opt; + + EXPECT_THROW(rdata_opt.toText(), + isc::InvalidOperation); } TEST_F(Rdata_OPT_Test, compare) { - // This simple implementation always returns "true" - EXPECT_EQ(0, rdata_opt.compare( + // empty OPT + const generic::OPT rdata_opt; + + EXPECT_THROW(rdata_opt.compare( *rdataFactoryFromFile(RRType::OPT(), RRClass::CH(), - "rdata_opt_fromWire", 2))); + "rdata_opt_fromWire1", 2)), + isc::InvalidOperation); + + // comparison attempt between incompatible RR types also results in + // isc::InvalidOperation. + EXPECT_THROW(rdata_opt.compare(*RdataTest::rdata_nomatch), + isc::InvalidOperation); +} + +TEST_F(Rdata_OPT_Test, appendPseudoRR) { + generic::OPT rdata_opt; + + // Append empty option data + rdata_opt.appendPseudoRR(0x0042, NULL, 0); + + // Append simple option data + const uint8_t option_data[] = {'H', 'e', 'l', 'l', 'o'}; + rdata_opt.appendPseudoRR(0x0043, option_data, sizeof(option_data)); + + // Duplicate option codes are okay. + rdata_opt.appendPseudoRR(0x0042, option_data, sizeof(option_data)); + + // When option length may overflow RDLEN, append should throw. + const std::vector<uint8_t> buffer((1 << 16) - 1); + EXPECT_THROW(rdata_opt.appendPseudoRR(0x0044, &buffer[0], buffer.size()), + isc::InvalidParameter); + + const uint8_t rdata_opt_wiredata2[] = { + // OPTION #1 + // ` Option code + 0x00, 0x42, + // ` Option length + 0x00, 0x00, + + // OPTION #2 + // ` Option code + 0x00, 0x43, + // ` Option length + 0x00, 0x05, + // ` Option data + 'H', 'e', 'l', 'l', 'o', + + // OPTION #3 + // ` Option code + 0x00, 0x42, + // ` Option length + 0x00, 0x05, + // ` Option data + 'H', 'e', 'l', 'l', 'o' + }; + + obuffer.clear(); + rdata_opt.toWire(obuffer); + + matchWireData(rdata_opt_wiredata2, sizeof(rdata_opt_wiredata2), + obuffer.getData(), obuffer.getLength()); +} + +TEST_F(Rdata_OPT_Test, getPseudoRRs) { + const generic::OPT rdf = + dynamic_cast<const generic::OPT&> + (*rdataFactoryFromFile(RRType("OPT"), RRClass("IN"), + "rdata_opt_fromWire1", 2)); + + const std::vector<generic::OPT::PseudoRR>& rrs = rdf.getPseudoRRs(); + ASSERT_FALSE(rrs.empty()); + EXPECT_EQ(1, rrs.size()); + EXPECT_EQ(0x2a, rrs.at(0).getCode()); + EXPECT_EQ(3, rrs.at(0).getLength()); - // comparison attempt between incompatible RR types should be rejected - EXPECT_THROW(rdata_opt.compare(*RdataTest::rdata_nomatch), bad_cast); + const uint8_t expected_data[] = {0x00, 0x01, 0x02}; + const uint8_t* actual_data = rrs.at(0).getData(); + EXPECT_EQ(0, std::memcmp(expected_data, actual_data, + sizeof(expected_data))); } } diff --git a/src/lib/dns/tests/rdata_pimpl_holder_unittest.cc b/src/lib/dns/tests/rdata_pimpl_holder_unittest.cc new file mode 100644 index 0000000000..96a03ba5ea --- /dev/null +++ b/src/lib/dns/tests/rdata_pimpl_holder_unittest.cc @@ -0,0 +1,62 @@ +// Copyright (C) 2014 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 <dns/rdata_pimpl_holder.h> + +#include <gtest/gtest.h> + +using namespace isc::dns::rdata; + +namespace { + +TEST(RdataPimplHolderTest, all) { + // Let's check with an integer + int* i1 = new int(42); + RdataPimplHolder<int> holder1(i1); + // The same pointer must be returned. + EXPECT_EQ(i1, holder1.get()); + // Obviously the value should match too. + EXPECT_EQ(42, *holder1.get()); + // We don't explictly delete i or holder1, so it should not leak + // anything when the test is done (checked by Valgrind). + + // The following cases are similar: + + // Test no-argument reset() + int* i2 = new int(43); + RdataPimplHolder<int> holder2(i2); + holder2.reset(); + EXPECT_EQ(NULL, holder2.get()); + + // Test reset() with argument + int* i3 = new int(44); + int* i4 = new int(45); + RdataPimplHolder<int> holder3(i3); + EXPECT_EQ(i3, holder3.get()); + holder3.reset(i4); + EXPECT_EQ(i4, holder3.get()); + EXPECT_EQ(45, *holder3.get()); + + // Test release() + RdataPimplHolder<int> holder4(new int(46)); + EXPECT_NE(static_cast<void*>(NULL), holder4.get()); + EXPECT_EQ(46, *holder4.get()); + int* i5 = holder4.release(); + EXPECT_EQ(NULL, holder4.get()); + EXPECT_NE(static_cast<void*>(NULL), i5); + EXPECT_EQ(46, *i5); + delete i5; +} + +} diff --git a/src/lib/dns/tests/rdata_ptr_unittest.cc b/src/lib/dns/tests/rdata_ptr_unittest.cc index 5d6d37db91..d6a99f77f9 100644 --- a/src/lib/dns/tests/rdata_ptr_unittest.cc +++ b/src/lib/dns/tests/rdata_ptr_unittest.cc @@ -24,12 +24,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; // // This test currently simply copies the NS RDATA tests. @@ -118,20 +120,18 @@ TEST_F(Rdata_PTR_Test, createFromLexer) { TEST_F(Rdata_PTR_Test, toWireBuffer) { rdata_ptr.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_ptr, sizeof(wiredata_ptr)); + matchWireData(wiredata_ptr, sizeof(wiredata_ptr), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_PTR_Test, toWireRenderer) { rdata_ptr.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_ptr, sizeof(wiredata_ptr)); + matchWireData(wiredata_ptr, sizeof(wiredata_ptr), + renderer.getData(), renderer.getLength()); + rdata_ptr2.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_ptr2, sizeof(wiredata_ptr2)); + matchWireData(wiredata_ptr2, sizeof(wiredata_ptr2), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_PTR_Test, toText) { diff --git a/src/lib/dns/tests/rdata_rp_unittest.cc b/src/lib/dns/tests/rdata_rp_unittest.cc index 38bec04211..d8de028926 100644 --- a/src/lib/dns/tests/rdata_rp_unittest.cc +++ b/src/lib/dns/tests/rdata_rp_unittest.cc @@ -22,12 +22,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::util; using namespace isc::dns; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_RP_Test : public RdataTest { @@ -157,9 +159,8 @@ TEST_F(Rdata_RP_Test, toWireBuffer) { rdata_rp.toWire(obuffer); // then compare them - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - &expected_wire[0], expected_wire.size()); + matchWireData(&expected_wire[0], expected_wire.size(), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_RP_Test, toWireRenderer) { @@ -172,9 +173,8 @@ TEST_F(Rdata_RP_Test, toWireRenderer) { renderer.writeName(Name("a.example.com")); renderer.writeName(Name("b.example.net")); generic::RP(mailbox_name, Name("rp-text.example.net")).toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - &expected_wire[0], expected_wire.size()); + matchWireData(&expected_wire[0], expected_wire.size(), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_RP_Test, toText) { diff --git a/src/lib/dns/tests/rdata_rrsig_unittest.cc b/src/lib/dns/tests/rdata_rrsig_unittest.cc index 2d075ece97..67ead3c713 100644 --- a/src/lib/dns/tests/rdata_rrsig_unittest.cc +++ b/src/lib/dns/tests/rdata_rrsig_unittest.cc @@ -25,16 +25,57 @@ #include <gtest/gtest.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> #include <dns/tests/rdata_unittest.h> -using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { + +const uint8_t wiredata_rrsig[] = { + // type covered = A + 0x00, 0x01, + // algorithm = 5 + 0x05, + // labels = 4 + 0x04, + // original TTL = 43200 (0x0000a8c0) + 0x00, 0x00, 0xa8, 0xc0, + // signature expiration = 1266961577 (0x4b844ca9) + 0x4b, 0x84, 0x4c, 0xa9, + // signature inception = 1266875177 (0x4b82fb29) + 0x4b, 0x82, 0xfb, 0x29, + // key tag = 8496 (0x2130) + 0x21, 0x30, + // signer's name (isc.org.) + // 3 i s c 3 o r g 0 + 0x03, 0x69, 0x73, 0x63, 0x03, 0x6f, 0x72, 0x67, 0x00, + // signature data follows + 0x7a, 0xfc, 0x61, 0x94, 0x6c, + 0x75, 0xde, 0x6a, 0x4a, 0x2d, 0x59, 0x0a, 0xb2, + 0x3a, 0x46, 0xcf, 0x27, 0x12, 0xe6, 0xdc, 0x2d, + 0x22, 0x8c, 0x4e, 0x9a, 0x53, 0x75, 0xe3, 0x0f, + 0x6d, 0xe4, 0x08, 0x33, 0x18, 0x19, 0xb3, 0x76, + 0x21, 0x9d, 0x2c, 0x8a, 0xc5, 0x69, 0xba, 0xab, + 0xef, 0x66, 0x9f, 0xda, 0xb5, 0x2a, 0xf9, 0x40, + 0xc1, 0x28, 0xc5, 0x97, 0xba, 0x3c, 0x19, 0x4d, + 0x95, 0x13, 0xc2, 0xcd, 0xf6, 0xb1, 0x59, 0x5d, + 0x0c, 0xf9, 0x3f, 0x35, 0xbb, 0x9a, 0x70, 0x93, + 0x36, 0xe5, 0xf4, 0x17, 0x7e, 0xfe, 0x66, 0x3b, + 0x70, 0x1f, 0xed, 0x33, 0xa8, 0xa3, 0x0d, 0xc0, + 0x8c, 0xc6, 0x95, 0x1b, 0xd8, 0x9c, 0x8c, 0x25, + 0xb4, 0x57, 0x9e, 0x56, 0x71, 0x64, 0x14, 0x7f, + 0x8f, 0x6d, 0xfa, 0xc5, 0xca, 0x3f, 0x36, 0xe2, + 0xa4, 0xdf, 0x60, 0xfa, 0xcd, 0x59, 0x3e, 0x22, + 0x32, 0xa1, 0xf7 +}; + class Rdata_RRSIG_Test : public RdataTest { protected: Rdata_RRSIG_Test() : @@ -299,13 +340,17 @@ TEST_F(Rdata_RRSIG_Test, createFromLexer) { } TEST_F(Rdata_RRSIG_Test, toWireRenderer) { - // FIXME: This doesn't check the result. rdata_rrsig.toWire(renderer); + + matchWireData(wiredata_rrsig, sizeof(wiredata_rrsig), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_RRSIG_Test, toWireBuffer) { - // FIXME: This doesn't check the result. rdata_rrsig.toWire(obuffer); + + matchWireData(wiredata_rrsig, sizeof(wiredata_rrsig), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_RRSIG_Test, createFromWire) { diff --git a/src/lib/dns/tests/rdata_soa_unittest.cc b/src/lib/dns/tests/rdata_soa_unittest.cc index 11412e14d1..f74c66d956 100644 --- a/src/lib/dns/tests/rdata_soa_unittest.cc +++ b/src/lib/dns/tests/rdata_soa_unittest.cc @@ -23,12 +23,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_SOA_Test : public RdataTest { @@ -179,9 +181,9 @@ TEST_F(Rdata_SOA_Test, toWireRenderer) { vector<unsigned char> data; UnitTestUtil::readWireData("rdata_soa_fromWire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(renderer.getData()) + 2, - renderer.getLength() - 2, &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + static_cast<const uint8_t *>(renderer.getData()) + 2, + renderer.getLength() - 2); } TEST_F(Rdata_SOA_Test, toWireBuffer) { @@ -189,9 +191,9 @@ TEST_F(Rdata_SOA_Test, toWireBuffer) { rdata_soa.toWire(obuffer); vector<unsigned char> data; UnitTestUtil::readWireData("rdata_soa_toWireUncompressed.wire", data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - static_cast<const uint8_t *>(obuffer.getData()) + 2, - obuffer.getLength() - 2, &data[2], data.size() - 2); + matchWireData(&data[2], data.size() - 2, + static_cast<const uint8_t *>(obuffer.getData()) + 2, + obuffer.getLength() - 2); } TEST_F(Rdata_SOA_Test, toText) { diff --git a/src/lib/dns/tests/rdata_srv_unittest.cc b/src/lib/dns/tests/rdata_srv_unittest.cc index 6ca0c7fe7a..8608c48710 100644 --- a/src/lib/dns/tests/rdata_srv_unittest.cc +++ b/src/lib/dns/tests/rdata_srv_unittest.cc @@ -24,12 +24,14 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_SRV_Test : public RdataTest { @@ -159,26 +161,24 @@ TEST_F(Rdata_SRV_Test, createFromLexer) { TEST_F(Rdata_SRV_Test, toWireBuffer) { rdata_srv.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_srv, sizeof(wiredata_srv)); + matchWireData(wiredata_srv, sizeof(wiredata_srv), + obuffer.getData(), obuffer.getLength()); + obuffer.clear(); rdata_srv2.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_srv2, sizeof(wiredata_srv2)); + matchWireData(wiredata_srv2, sizeof(wiredata_srv2), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_SRV_Test, toWireRenderer) { rdata_srv.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_srv, sizeof(wiredata_srv)); + matchWireData(wiredata_srv, sizeof(wiredata_srv), + renderer.getData(), renderer.getLength()); + renderer.clear(); rdata_srv2.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_srv2, sizeof(wiredata_srv2)); + matchWireData(wiredata_srv2, sizeof(wiredata_srv2), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_SRV_Test, toText) { diff --git a/src/lib/dns/tests/rdata_sshfp_unittest.cc b/src/lib/dns/tests/rdata_sshfp_unittest.cc index b85dfa5ebe..cb8640af1a 100644 --- a/src/lib/dns/tests/rdata_sshfp_unittest.cc +++ b/src/lib/dns/tests/rdata_sshfp_unittest.cc @@ -26,14 +26,17 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> + #include <boost/algorithm/string.hpp> -using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_SSHFP_Test : public RdataTest { @@ -59,11 +62,6 @@ protected: rdata_str, rdata_sshfp, true, true); } - void checkFromText_BadValue(const string& rdata_str) { - checkFromText<generic::SSHFP, InvalidRdataText, BadValue>( - rdata_str, rdata_sshfp, true, true); - } - void checkFromText_BadString(const string& rdata_str) { checkFromText <generic::SSHFP, InvalidRdataText, isc::Exception>( @@ -138,8 +136,8 @@ TEST_F(Rdata_SSHFP_Test, badText) { checkFromText_LexerError("1"); checkFromText_LexerError("ONE 2 123456789abcdef67890123456789abcdef67890"); checkFromText_LexerError("1 TWO 123456789abcdef67890123456789abcdef67890"); - checkFromText_BadValue("1 2 BUCKLEMYSHOE"); - checkFromText_BadValue(sshfp_txt + " extra text"); + checkFromText_InvalidText("1 2 BUCKLEMYSHOE"); + checkFromText_InvalidText(sshfp_txt + " extra text"); // yes, these are redundant to the last test cases in algorithmTypes checkFromText_InvalidText( @@ -232,12 +230,11 @@ TEST_F(Rdata_SSHFP_Test, toWire) { this->obuffer.clear(); rdata_sshfp.toWire(this->obuffer); - EXPECT_EQ(22, this->obuffer.getLength()); + EXPECT_EQ(sizeof (rdata_sshfp_wiredata), + this->obuffer.getLength()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), - this->obuffer.getLength(), - rdata_sshfp_wiredata, sizeof(rdata_sshfp_wiredata)); + matchWireData(rdata_sshfp_wiredata, sizeof(rdata_sshfp_wiredata), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_SSHFP_Test, compare) { @@ -254,8 +251,20 @@ TEST_F(Rdata_SSHFP_Test, getFingerprintType) { EXPECT_EQ(1, rdata_sshfp.getFingerprintType()); } -TEST_F(Rdata_SSHFP_Test, getFingerprintLen) { - EXPECT_EQ(20, rdata_sshfp.getFingerprintLen()); +TEST_F(Rdata_SSHFP_Test, getFingerprint) { + const std::vector<uint8_t>& fingerprint = + rdata_sshfp.getFingerprint(); + + EXPECT_EQ(rdata_sshfp.getFingerprintLength(), + fingerprint.size()); + for (int i = 0; i < fingerprint.size(); ++i) { + EXPECT_EQ(rdata_sshfp_wiredata[i + 2], + fingerprint.at(i)); + } +} + +TEST_F(Rdata_SSHFP_Test, getFingerprintLength) { + EXPECT_EQ(20, rdata_sshfp.getFingerprintLength()); } TEST_F(Rdata_SSHFP_Test, emptyFingerprintFromWire) { @@ -273,17 +282,15 @@ TEST_F(Rdata_SSHFP_Test, emptyFingerprintFromWire) { EXPECT_EQ(4, rdf.getAlgorithmNumber()); EXPECT_EQ(9, rdf.getFingerprintType()); - EXPECT_EQ(0, rdf.getFingerprintLen()); + EXPECT_EQ(0, rdf.getFingerprintLength()); this->obuffer.clear(); rdf.toWire(this->obuffer); EXPECT_EQ(2, this->obuffer.getLength()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), - this->obuffer.getLength(), - rdf_wiredata, sizeof(rdf_wiredata)); + matchWireData(rdf_wiredata, sizeof(rdf_wiredata), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_SSHFP_Test, emptyFingerprintFromString) { @@ -297,16 +304,14 @@ TEST_F(Rdata_SSHFP_Test, emptyFingerprintFromString) { EXPECT_EQ(5, rdata_sshfp2.getAlgorithmNumber()); EXPECT_EQ(6, rdata_sshfp2.getFingerprintType()); - EXPECT_EQ(0, rdata_sshfp2.getFingerprintLen()); + EXPECT_EQ(0, rdata_sshfp2.getFingerprintLength()); this->obuffer.clear(); rdata_sshfp2.toWire(this->obuffer); EXPECT_EQ(2, this->obuffer.getLength()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), - this->obuffer.getLength(), - rdata_sshfp2_wiredata, sizeof(rdata_sshfp2_wiredata)); + matchWireData(rdata_sshfp2_wiredata, sizeof(rdata_sshfp2_wiredata), + obuffer.getData(), obuffer.getLength()); } } diff --git a/src/lib/dns/tests/rdata_tlsa_unittest.cc b/src/lib/dns/tests/rdata_tlsa_unittest.cc new file mode 100644 index 0000000000..30b608b244 --- /dev/null +++ b/src/lib/dns/tests/rdata_tlsa_unittest.cc @@ -0,0 +1,282 @@ +// Copyright (C) 2014 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 <algorithm> +#include <string> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rrclass.h> +#include <dns/rrtype.h> + +#include <gtest/gtest.h> + +#include <dns/tests/unittest_util.h> +#include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> + +#include <boost/algorithm/string.hpp> + +using namespace std; +using namespace isc; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; + +namespace { +class Rdata_TLSA_Test : public RdataTest { +protected: + Rdata_TLSA_Test() : + tlsa_txt("0 0 1 d2abde240d7cd3ee6b4b28c54df034b9" + "7983a1d16e8a410e4561cb106618e971"), + rdata_tlsa(tlsa_txt) + {} + + void checkFromText_None(const string& rdata_str) { + checkFromText<generic::TLSA, isc::Exception, isc::Exception>( + rdata_str, rdata_tlsa, false, false); + } + + void checkFromText_InvalidText(const string& rdata_str) { + checkFromText<generic::TLSA, InvalidRdataText, InvalidRdataText>( + rdata_str, rdata_tlsa, true, true); + } + + void checkFromText_LexerError(const string& rdata_str) { + checkFromText + <generic::TLSA, InvalidRdataText, MasterLexer::LexerError>( + rdata_str, rdata_tlsa, true, true); + } + + void checkFromText_BadString(const string& rdata_str) { + checkFromText + <generic::TLSA, InvalidRdataText, isc::Exception>( + rdata_str, rdata_tlsa, true, false); + } + + const string tlsa_txt; + const generic::TLSA rdata_tlsa; +}; + +const uint8_t rdata_tlsa_wiredata[] = { + // certificate usage + 0x00, + // selector + 0x00, + // matching type + 0x01, + // certificate association data + 0xd2, 0xab, 0xde, 0x24, 0x0d, 0x7c, 0xd3, 0xee, + 0x6b, 0x4b, 0x28, 0xc5, 0x4d, 0xf0, 0x34, 0xb9, + 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e, + 0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71 +}; + +TEST_F(Rdata_TLSA_Test, createFromText) { + // Basic test + checkFromText_None(tlsa_txt); + + // With different spacing + checkFromText_None("0 0 1 d2abde240d7cd3ee6b4b28c54df034b9" + "7983a1d16e8a410e4561cb106618e971"); + + // Combination of lowercase and uppercase + checkFromText_None("0 0 1 D2ABDE240D7CD3EE6B4B28C54DF034B9" + "7983a1d16e8a410e4561cb106618e971"); + + // spacing in the certificate association data field + checkFromText_None("0 0 1 d2abde240d7cd3ee6b4b28c54df034b9" + " 7983a1d16e8a410e4561cb106618e971"); + + // multi-line certificate association data field + checkFromText_None("0 0 1 ( d2abde240d7cd3ee6b4b28c54df034b9\n" + " 7983a1d16e8a410e4561cb106618e971 )"); + + // string constructor throws if there's extra text, + // but lexer constructor doesn't + checkFromText_BadString(tlsa_txt + "\n" + tlsa_txt); +} + +TEST_F(Rdata_TLSA_Test, fields) { + // Some of these may not be RFC conformant, but we relax the check + // in our code to work with other field values that may show up in + // the future. + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("1 0 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("2 0 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("3 0 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("128 0 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("255 0 1 12ab")); + + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 1 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 2 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 3 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 128 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 255 1 12ab")); + + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 0 1 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 0 2 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 0 3 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 0 128 12ab")); + EXPECT_NO_THROW(const generic::TLSA rdata_tlsa("0 0 255 12ab")); + + // > 255 would be broken + EXPECT_THROW(const generic::TLSA rdata_tlsa("256 0 1 12ab"), + InvalidRdataText); + EXPECT_THROW(const generic::TLSA rdata_tlsa("0 256 1 12ab"), + InvalidRdataText); + EXPECT_THROW(const generic::TLSA rdata_tlsa("0 0 256 12ab"), + InvalidRdataText); +} + +TEST_F(Rdata_TLSA_Test, badText) { + checkFromText_LexerError("1"); + checkFromText_LexerError("ONE 2 3 123456789abcdef67890123456789abcdef67890"); + checkFromText_LexerError("1 TWO 3 123456789abcdef67890123456789abcdef67890"); + checkFromText_LexerError("1 2 THREE 123456789abcdef67890123456789abcdef67890"); + checkFromText_InvalidText("1 2 3 BAABAABLACKSHEEP"); + checkFromText_InvalidText(tlsa_txt + " extra text"); + + // yes, these are redundant to the last test cases in the .fields + // test + checkFromText_InvalidText( + "2345 1 2 123456789abcdef67890123456789abcdef67890"); + checkFromText_InvalidText( + "3 1234 4 123456789abcdef67890123456789abcdef67890"); + checkFromText_InvalidText( + "5 6 1234 123456789abcdef67890123456789abcdef67890"); + + // negative values are trapped in the lexer rather than the + // constructor + checkFromText_LexerError("-2 0 1 123456789abcdef67890123456789abcdef67890"); + checkFromText_LexerError("0 -2 1 123456789abcdef67890123456789abcdef67890"); + checkFromText_LexerError("0 0 -2 123456789abcdef67890123456789abcdef67890"); +} + +TEST_F(Rdata_TLSA_Test, copyAndAssign) { + // Copy construct + generic::TLSA rdata_tlsa2(rdata_tlsa); + EXPECT_EQ(0, rdata_tlsa.compare(rdata_tlsa2)); + + // Assignment, mainly to confirm it doesn't cause disruption. + rdata_tlsa2 = rdata_tlsa; + EXPECT_EQ(0, rdata_tlsa.compare(rdata_tlsa2)); +} + +TEST_F(Rdata_TLSA_Test, createFromWire) { + // Basic test + EXPECT_EQ(0, rdata_tlsa.compare( + *rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire"))); + // Combination of lowercase and uppercase + EXPECT_EQ(0, rdata_tlsa.compare( + *rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire2"))); + // certificate_usage=0, selector=0, matching_type=1 + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire3.wire")); + + // certificate_usage=255, selector=0, matching_type=1 + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire4.wire")); + + // certificate_usage=0, selector=255, matching_type=1 + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire5.wire")); + + // certificate_usage=0, selector=0, matching_type=255 + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire6.wire")); + + // certificate_usage=3, selector=1, matching_type=2 + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire7.wire")); + + // short certificate association data + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire8.wire")); + + // certificate association data is shorter than rdata len + EXPECT_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire9"), + InvalidBufferPosition); + + // certificate association data is missing + EXPECT_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire10"), + InvalidBufferPosition); + + // certificate association data is empty + EXPECT_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire12"), + InvalidRdataLength); + + // all RDATA is missing + EXPECT_THROW(rdataFactoryFromFile(RRType("TLSA"), RRClass("IN"), + "rdata_tlsa_fromWire11"), + InvalidBufferPosition); +} + +TEST_F(Rdata_TLSA_Test, createFromParams) { + const generic::TLSA rdata_tlsa2( + 0, 0, 1, "d2abde240d7cd3ee6b4b28c54df034b9" + "7983a1d16e8a410e4561cb106618e971"); + EXPECT_EQ(0, rdata_tlsa2.compare(rdata_tlsa)); + + // empty certificate association data should throw + EXPECT_THROW(const generic::TLSA rdata_tlsa2(0, 0, 1, ""), + InvalidRdataText); +} + +TEST_F(Rdata_TLSA_Test, toText) { + EXPECT_TRUE(boost::iequals(tlsa_txt, rdata_tlsa.toText())); +} + +TEST_F(Rdata_TLSA_Test, toWire) { + this->obuffer.clear(); + rdata_tlsa.toWire(this->obuffer); + + EXPECT_EQ(sizeof (rdata_tlsa_wiredata), + this->obuffer.getLength()); + + matchWireData(rdata_tlsa_wiredata, sizeof(rdata_tlsa_wiredata), + obuffer.getData(), obuffer.getLength()); +} + +TEST_F(Rdata_TLSA_Test, compare) { + const generic::TLSA rdata_tlsa2("0 0 0 d2abde240d7cd3ee6b4b28c54df034b9" + "7983a1d16e8a410e4561cb106618e971"); + EXPECT_EQ(-1, rdata_tlsa2.compare(rdata_tlsa)); + EXPECT_EQ(1, rdata_tlsa.compare(rdata_tlsa2)); +} + +TEST_F(Rdata_TLSA_Test, getCertificateUsage) { + EXPECT_EQ(0, rdata_tlsa.getCertificateUsage()); +} + +TEST_F(Rdata_TLSA_Test, getSelector) { + EXPECT_EQ(0, rdata_tlsa.getSelector()); +} + +TEST_F(Rdata_TLSA_Test, getMatchingType) { + EXPECT_EQ(1, rdata_tlsa.getMatchingType()); +} + +TEST_F(Rdata_TLSA_Test, getDataLength) { + EXPECT_EQ(32, rdata_tlsa.getDataLength()); +} +} diff --git a/src/lib/dns/tests/rdata_tsig_unittest.cc b/src/lib/dns/tests/rdata_tsig_unittest.cc index 270a1b284a..ab8fa273bf 100644 --- a/src/lib/dns/tests/rdata_tsig_unittest.cc +++ b/src/lib/dns/tests/rdata_tsig_unittest.cc @@ -29,32 +29,34 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> -using isc::UnitTestUtil; using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class Rdata_TSIG_Test : public RdataTest { protected: Rdata_TSIG_Test() : - // no MAC or Other Data + // no MAC or Other Data valid_text1("hmac-md5.sig-alg.reg.int. 1286779327 300 " "0 16020 BADKEY 0"), - // MAC but no Other Data + // MAC but no Other Data valid_text2("hmac-sha256. 1286779327 300 12 " "FAKEFAKEFAKEFAKE 16020 BADSIG 0"), - // MAC and Other Data + // MAC and Other Data valid_text3("hmac-sha1. 1286779327 300 12 " "FAKEFAKEFAKEFAKE 16020 BADTIME 6 FAKEFAKE"), - // MAC and Other Data (with Error that doesn't expect Other Data) + // MAC and Other Data (with Error that doesn't expect Other Data) valid_text4("hmac-sha1. 1286779327 300 12 " "FAKEFAKEFAKEFAKE 16020 BADSIG 6 FAKEFAKE"), - // numeric error code + // numeric error code valid_text5("hmac-sha256. 1286779327 300 12 " "FAKEFAKEFAKEFAKE 16020 2845 0"), rdata_tsig(valid_text1) @@ -204,9 +206,8 @@ fromWireCommonChecks(const any::TSIG& tsig) { EXPECT_EQ(300, tsig.getFudge()); vector<uint8_t> expect_mac(32, 'x'); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &expect_mac[0], expect_mac.size(), - tsig.getMAC(), tsig.getMACSize()); + matchWireData(&expect_mac[0], expect_mac.size(), + tsig.getMAC(), tsig.getMACSize()); EXPECT_EQ(2845, tsig.getOriginalID()); @@ -234,9 +235,8 @@ TEST_F(Rdata_TSIG_Test, createFromWireWithOtherData) { expect_data[3] = ((otherdata >> 16) & 0xff); expect_data[4] = ((otherdata >> 8) & 0xff); expect_data[5] = (otherdata & 0xff); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &expect_data[0], expect_data.size(), - tsig.getOtherData(), tsig.getOtherLen()); + matchWireData(&expect_data[0], expect_data.size(), + tsig.getOtherData(), tsig.getOtherLen()); } TEST_F(Rdata_TSIG_Test, createFromWireWithoutMAC) { @@ -351,27 +351,24 @@ Rdata_TSIG_Test::toWireCommonChecks(Output& output) const { // read the expected wire format data and trim the RDLEN part. UnitTestUtil::readWireData("rdata_tsig_toWire1.wire", expect_data); expect_data.erase(expect_data.begin(), expect_data.begin() + 2); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &expect_data[0], expect_data.size(), - output.getData(), output.getLength()); + matchWireData(&expect_data[0], expect_data.size(), + output.getData(), output.getLength()); expect_data.clear(); output.clear(); any::TSIG(valid_text2).toWire(output); UnitTestUtil::readWireData("rdata_tsig_toWire2.wire", expect_data); expect_data.erase(expect_data.begin(), expect_data.begin() + 2); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &expect_data[0], expect_data.size(), - output.getData(), output.getLength()); + matchWireData(&expect_data[0], expect_data.size(), + output.getData(), output.getLength()); expect_data.clear(); output.clear(); any::TSIG(valid_text3).toWire(output); UnitTestUtil::readWireData("rdata_tsig_toWire3.wire", expect_data); expect_data.erase(expect_data.begin(), expect_data.begin() + 2); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &expect_data[0], expect_data.size(), - output.getData(), output.getLength()); + matchWireData(&expect_data[0], expect_data.size(), + output.getData(), output.getLength()); } TEST_F(Rdata_TSIG_Test, toWireBuffer) { @@ -388,9 +385,8 @@ TEST_F(Rdata_TSIG_Test, toWireRenderer) { renderer.writeUint16(42); // RDLEN rdata_tsig.toWire(renderer); UnitTestUtil::readWireData("rdata_tsig_toWire4.wire", expect_data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &expect_data[0], expect_data.size(), - renderer.getData(), renderer.getLength()); + matchWireData(&expect_data[0], expect_data.size(), + renderer.getData(), renderer.getLength()); // check algorithm can be used as a compression target. expect_data.clear(); @@ -399,9 +395,8 @@ TEST_F(Rdata_TSIG_Test, toWireRenderer) { rdata_tsig.toWire(renderer); renderer.writeName(Name("hmac-md5.sig-alg.reg.int")); UnitTestUtil::readWireData("rdata_tsig_toWire5.wire", expect_data); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - &expect_data[0], expect_data.size(), - renderer.getData(), renderer.getLength()); + matchWireData(&expect_data[0], expect_data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_TSIG_Test, toText) { diff --git a/src/lib/dns/tests/rdata_txt_like_unittest.cc b/src/lib/dns/tests/rdata_txt_like_unittest.cc index 2a83ea9892..e5283273ae 100644 --- a/src/lib/dns/tests/rdata_txt_like_unittest.cc +++ b/src/lib/dns/tests/rdata_txt_like_unittest.cc @@ -21,6 +21,8 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> + #include <gtest/gtest.h> #include <boost/bind.hpp> @@ -29,11 +31,12 @@ #include <sstream> #include <vector> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { @@ -133,31 +136,31 @@ TYPED_TEST(Rdata_TXT_LIKE_Test, createFromText) { // Null character-string. this->obuffer.clear(); TypeParam(string("\"\"")).toWire(this->obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), this->obuffer.getLength(), - wiredata_nulltxt, sizeof(wiredata_nulltxt)); + matchWireData(wiredata_nulltxt, sizeof(wiredata_nulltxt), + this->obuffer.getData(), this->obuffer.getLength()); + this->obuffer.clear(); TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS, this->loader_cb). toWire(this->obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), this->obuffer.getLength(), - wiredata_nulltxt, sizeof(wiredata_nulltxt)); + matchWireData(wiredata_nulltxt, sizeof(wiredata_nulltxt), + this->obuffer.getData(), this->obuffer.getLength()); + EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType()); // Longest possible character-string. this->obuffer.clear(); TypeParam(string(255, 'a')).toWire(this->obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), this->obuffer.getLength(), - &this->wiredata_longesttxt[0], - this->wiredata_longesttxt.size()); + matchWireData(&this->wiredata_longesttxt[0], + this->wiredata_longesttxt.size(), + this->obuffer.getData(), this->obuffer.getLength()); + this->obuffer.clear(); TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS, this->loader_cb). toWire(this->obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), this->obuffer.getLength(), - &this->wiredata_longesttxt[0], - this->wiredata_longesttxt.size()); + matchWireData(&this->wiredata_longesttxt[0], + this->wiredata_longesttxt.size(), + this->obuffer.getData(), this->obuffer.getLength()); + EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType()); // Too long text for a valid character-string. @@ -268,10 +271,8 @@ TYPED_TEST(Rdata_TXT_LIKE_Test, createFromWire) { sizeof(wiredata_txt_like)); expected_data.insert(expected_data.end(), wiredata_txt_like, wiredata_txt_like + sizeof(wiredata_txt_like)); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), - this->obuffer.getLength(), - &expected_data[0], expected_data.size()); + matchWireData(&expected_data[0], expected_data.size(), + this->obuffer.getData(), this->obuffer.getLength()); // Largest length of data. There's nothing special, but should be // constructed safely, and the content should be identical to the original @@ -283,11 +284,8 @@ TYPED_TEST(Rdata_TXT_LIKE_Test, createFromWire) { TypeParam largest_txt_like(ibuffer, largest_txt_like_data.size()); this->obuffer.clear(); largest_txt_like.toWire(this->obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), - this->obuffer.getLength(), - &largest_txt_like_data[0], - largest_txt_like_data.size()); + matchWireData(&largest_txt_like_data[0], largest_txt_like_data.size(), + this->obuffer.getData(), this->obuffer.getLength()); // rdlen parameter is out of range. This is a rare event because we'd // normally call the constructor via a polymorphic wrapper, where the @@ -315,18 +313,14 @@ TYPED_TEST(Rdata_TXT_LIKE_Test, createFromLexer) { TYPED_TEST(Rdata_TXT_LIKE_Test, toWireBuffer) { this->rdata_txt_like.toWire(this->obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->obuffer.getData(), - this->obuffer.getLength(), - wiredata_txt_like, sizeof(wiredata_txt_like)); + matchWireData(wiredata_txt_like, sizeof(wiredata_txt_like), + this->obuffer.getData(), this->obuffer.getLength()); } TYPED_TEST(Rdata_TXT_LIKE_Test, toWireRenderer) { this->rdata_txt_like.toWire(this->renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - this->renderer.getData(), - this->renderer.getLength(), - wiredata_txt_like, sizeof(wiredata_txt_like)); + matchWireData(wiredata_txt_like, sizeof(wiredata_txt_like), + this->renderer.getData(), this->renderer.getLength()); } TYPED_TEST(Rdata_TXT_LIKE_Test, toText) { diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc index 3839fbd24f..f29b61cf56 100644 --- a/src/lib/dns/tests/rdata_unittest.cc +++ b/src/lib/dns/tests/rdata_unittest.cc @@ -28,14 +28,17 @@ #include <dns/tests/unittest_util.h> #include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> + #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace isc { namespace dns { @@ -211,6 +214,14 @@ TEST_F(RdataTest, createRdataWithLexer) { "file does not end with newline"); } +TEST_F(RdataTest, getLength) { + const in::AAAA aaaa_rdata("2001:db8::1"); + EXPECT_EQ(16, aaaa_rdata.getLength()); + + const generic::TXT txt_rdata("Hello World"); + EXPECT_EQ(12, txt_rdata.getLength()); +} + } } } @@ -290,14 +301,14 @@ TEST_F(Rdata_Unknown_Test, createFromText) { // the length should be 16-bit unsigned integer EXPECT_THROW(generic::Generic("\\# 65536 a1b2c30d"), InvalidRdataLength); EXPECT_THROW(generic::Generic("\\# -1 a1b2c30d"), InvalidRdataLength); - EXPECT_THROW(generic::Generic("\\# 1.1 a1"), InvalidRdataText); + EXPECT_THROW(generic::Generic("\\# 1.1 a1"), InvalidRdataLength); EXPECT_THROW(generic::Generic("\\# 0a 00010203040506070809"), - InvalidRdataText); + InvalidRdataLength); // should reject if the special token is missing. EXPECT_THROW(generic::Generic("4 a1b2c30d"), InvalidRdataText); // the special token, the RDLENGTH and the data must be space separated. EXPECT_THROW(generic::Generic("\\#0"), InvalidRdataText); - EXPECT_THROW(generic::Generic("\\# 1ff"), InvalidRdataText); + EXPECT_THROW(generic::Generic("\\# 1ff"), InvalidRdataLength); } TEST_F(Rdata_Unknown_Test, createFromWire) { @@ -393,16 +404,14 @@ TEST_F(Rdata_Unknown_Test, toText) { TEST_F(Rdata_Unknown_Test, toWireBuffer) { rdata_unknown.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata_unknown, sizeof(wiredata_unknown)); + matchWireData(wiredata_unknown, sizeof(wiredata_unknown), + obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_Unknown_Test, toWireRenderer) { rdata_unknown.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata_unknown, sizeof(wiredata_unknown)); + matchWireData(wiredata_unknown, sizeof(wiredata_unknown), + renderer.getData(), renderer.getLength()); } TEST_F(Rdata_Unknown_Test, compare) { diff --git a/src/lib/dns/tests/rdata_unittest.h b/src/lib/dns/tests/rdata_unittest.h index 04af07c2fe..8c7f954eeb 100644 --- a/src/lib/dns/tests/rdata_unittest.h +++ b/src/lib/dns/tests/rdata_unittest.h @@ -27,8 +27,6 @@ #include <string> #include <sstream> -using namespace isc::util; - namespace isc { namespace dns { namespace rdata { @@ -77,7 +75,7 @@ protected: } } - OutputBuffer obuffer; + isc::util::OutputBuffer obuffer; MessageRenderer renderer; /// This is an RDATA object of some "unknown" RR type so that it can be /// used to test the compare() method against a well-known RR type. diff --git a/src/lib/dns/tests/rdatafields_unittest.cc b/src/lib/dns/tests/rdatafields_unittest.cc index ef83ed4b26..a6bead79bb 100644 --- a/src/lib/dns/tests/rdatafields_unittest.cc +++ b/src/lib/dns/tests/rdatafields_unittest.cc @@ -24,14 +24,17 @@ #include <dns/rdatafields.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> + #include <gtest/gtest.h> -using isc::UnitTestUtil; using namespace std; using namespace isc::dns; using namespace isc::dns::rdata; +using isc::UnitTestUtil; using isc::util::OutputBuffer; using isc::util::InputBuffer; +using isc::util::unittests::matchWireData; namespace { class RdataFieldsTest : public ::testing::Test { @@ -67,23 +70,21 @@ RdataFieldsTest::constructCommonTests(const RdataFields& fields, const uint8_t* const expected_data, const size_t expected_data_len) { - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data, - expected_data_len, fields.getData(), - fields.getDataLength()); + matchWireData(expected_data, expected_data_len, + fields.getData(), fields.getDataLength()); + EXPECT_EQ(sizeof(RdataFields::FieldSpec), fields.getFieldSpecDataSize()); EXPECT_EQ(1, fields.getFieldCount()); EXPECT_EQ(RdataFields::DATA, fields.getFieldSpec(0).type); EXPECT_EQ(4, fields.getFieldSpec(0).len); fields.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data, - expected_data_len, obuffer.getData(), - obuffer.getLength()); + matchWireData(expected_data, expected_data_len, + obuffer.getData(), obuffer.getLength()); fields.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, expected_data, - expected_data_len, renderer.getData(), - renderer.getLength()); + matchWireData(expected_data, expected_data_len, + renderer.getData(), renderer.getLength()); } TEST_F(RdataFieldsTest, constructFromRdata) { @@ -112,17 +113,15 @@ RdataFieldsTest::constructCommonTestsNS(const RdataFields& fields) { UnitTestUtil::readWireData("rdatafields1.wire", expected_wire); other_name.toWire(obuffer); fields.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], - expected_wire.size(), obuffer.getData(), - obuffer.getLength()); + matchWireData(&expected_wire[0], expected_wire.size(), + obuffer.getData(), obuffer.getLength()); expected_wire.clear(); UnitTestUtil::readWireData("rdatafields2.wire", expected_wire); other_name.toWire(renderer); fields.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], - expected_wire.size(), renderer.getData(), - renderer.getLength()); + matchWireData(&expected_wire[0], expected_wire.size(), + renderer.getData(), renderer.getLength()); } TEST_F(RdataFieldsTest, constructFromRdataNS) { @@ -150,14 +149,12 @@ RdataFieldsTest::constructCommonTestsTXT(const RdataFields& fields) { EXPECT_EQ(expected_wire.size(), fields.getFieldSpec(0).len); fields.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], - expected_wire.size(), obuffer.getData(), - obuffer.getLength()); + matchWireData(&expected_wire[0], expected_wire.size(), + obuffer.getData(), obuffer.getLength()); fields.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], - expected_wire.size(), renderer.getData(), - renderer.getLength()); + matchWireData(&expected_wire[0], expected_wire.size(), + renderer.getData(), renderer.getLength()); } TEST_F(RdataFieldsTest, constructFromRdataTXT) { @@ -208,9 +205,8 @@ RdataFieldsTest::constructCommonTestsRRSIG(const RdataFields& fields) { obuffer.writeUint16(fields.getDataLength()); fields.toWire(obuffer); other_name.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], - expected_wire.size(), obuffer.getData(), - obuffer.getLength()); + matchWireData(&expected_wire[0], expected_wire.size(), + obuffer.getData(), obuffer.getLength()); expected_wire.clear(); UnitTestUtil::readWireData("rdatafields6.wire", expected_wire); @@ -218,9 +214,8 @@ RdataFieldsTest::constructCommonTestsRRSIG(const RdataFields& fields) { renderer.writeUint16(fields.getDataLength()); fields.toWire(renderer); // the signer field won't be compressed other_name.toWire(renderer); // but will be used as a compression target - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &expected_wire[0], - expected_wire.size(), renderer.getData(), - renderer.getLength()); + matchWireData(&expected_wire[0], expected_wire.size(), + renderer.getData(), renderer.getLength()); } TEST_F(RdataFieldsTest, constructFromRdataRRSIG) { diff --git a/src/lib/dns/tests/rrclass_unittest.cc b/src/lib/dns/tests/rrclass_unittest.cc index b79aedff5f..c20125e0b5 100644 --- a/src/lib/dns/tests/rrclass_unittest.cc +++ b/src/lib/dns/tests/rrclass_unittest.cc @@ -19,6 +19,7 @@ #include <dns/rrclass.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> #include <boost/scoped_ptr.hpp> @@ -27,6 +28,7 @@ using namespace isc; using namespace isc::dns; using namespace isc::util; using boost::scoped_ptr; +using isc::util::unittests::matchWireData; namespace { class RRClassTest : public ::testing::Test { @@ -115,9 +117,8 @@ TEST_F(RRClassTest, toWireBuffer) { rrclass_0x8000.toWire(obuffer); rrclass_max.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata, sizeof(wiredata)); + matchWireData(wiredata, sizeof (wiredata), + obuffer.getData(), obuffer.getLength()); } TEST_F(RRClassTest, toWireRenderer) { @@ -127,9 +128,8 @@ TEST_F(RRClassTest, toWireRenderer) { rrclass_0x8000.toWire(renderer); rrclass_max.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata, sizeof(wiredata)); + matchWireData(wiredata, sizeof (wiredata), + renderer.getData(), renderer.getLength()); } TEST_F(RRClassTest, wellKnownClasss) { diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc index da3eb52267..fc75b7731c 100644 --- a/src/lib/dns/tests/rrset_unittest.cc +++ b/src/lib/dns/tests/rrset_unittest.cc @@ -23,18 +23,19 @@ #include <dns/rrset.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> #include <gtest/gtest.h> #include <stdexcept> #include <sstream> -using isc::UnitTestUtil; - using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class RRsetTest : public ::testing::Test { @@ -130,7 +131,7 @@ TEST_F(RRsetTest, isSameKind) { void addRdataTestCommon(const RRset& rrset) { - EXPECT_EQ(2, rrset.getRdataCount()); + ASSERT_EQ(2, rrset.getRdataCount()); RdataIteratorPtr it = rrset.getRdataIterator(); // cursor is set to the 1st EXPECT_FALSE(it->isLast()); @@ -157,14 +158,34 @@ TEST_F(RRsetTest, addRdataPtr) { rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(), rrset_a_empty.getClass(), "192.0.2.2")); + addRdataTestCommon(rrset_a_empty); +} - addRdataTestCommon(rrset_a); - +TEST_F(RRsetTest, addRdataPtrMismatched) { // Pointer version of addRdata() doesn't type check and does allow to //add a different type of Rdata as a result. + + // Type mismatch rrset_a_empty.addRdata(createRdata(RRType::NS(), RRClass::IN(), "ns.example.com.")); - EXPECT_EQ(3, rrset_a_empty.getRdataCount()); + EXPECT_EQ(1, rrset_a_empty.getRdataCount()); + + // Class mismatch + rrset_ch_txt.addRdata(createRdata(RRType::TXT(), RRClass::IN(), + "Test String")); + EXPECT_EQ(1, rrset_ch_txt.getRdataCount()); +} + +TEST_F(RRsetTest, addRdataString) { + rrset_a_empty.addRdata("192.0.2.1"); + rrset_a_empty.addRdata("192.0.2.2"); + + addRdataTestCommon(rrset_a_empty); + + // String version of addRdata() will throw for bad RDATA for + // RRType::A(). + EXPECT_THROW(rrset_a_empty.addRdata("ns.example.com."), InvalidRdataText); + addRdataTestCommon(rrset_a_empty); } TEST_F(RRsetTest, iterator) { @@ -204,12 +225,36 @@ TEST_F(RRsetTest, toText) { rrset_none_a_empty.toText()); } +TEST_F(RRsetTest, getLength) { + // Empty RRset should throw + EXPECT_THROW(rrset_a_empty.getLength(), EmptyRRset); + + // Unless it is type ANY or NONE: + // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets + // TYPE field = 2 octets + // CLASS field = 2 octets + // TTL field = 4 octets + // RDLENGTH field = 2 octets + // Total = 18 + 2 + 2 + 4 + 2 = 28 octets + EXPECT_EQ(28, rrset_any_a_empty.getLength()); + EXPECT_EQ(28, rrset_none_a_empty.getLength()); + + // RRset with single RDATA + // 28 (above) + 4 octets (A RDATA) = 32 octets + rrset_a_empty.addRdata(in::A("192.0.2.1")); + EXPECT_EQ(32, rrset_a_empty.getLength()); + + // 2 A RRs + rrset_a_empty.addRdata(in::A("192.0.2.2")); + EXPECT_EQ(32 + 32, rrset_a_empty.getLength()); +} + TEST_F(RRsetTest, toWireBuffer) { rrset_a.toWire(buffer); UnitTestUtil::readWireData("rrset_toWire1", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(), - buffer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + buffer.getData(), buffer.getLength()); // toWire() cannot be performed for an empty RRset except when // class=ANY or class=NONE. @@ -222,14 +267,15 @@ TEST_F(RRsetTest, toWireBuffer) { rrset_any_a_empty.toWire(buffer); wiredata.clear(); UnitTestUtil::readWireData("rrset_toWire3", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(), - buffer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + buffer.getData(), buffer.getLength()); + buffer.clear(); rrset_none_a_empty.toWire(buffer); wiredata.clear(); UnitTestUtil::readWireData("rrset_toWire4", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(), - buffer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + buffer.getData(), buffer.getLength()); } TEST_F(RRsetTest, toWireRenderer) { @@ -239,8 +285,8 @@ TEST_F(RRsetTest, toWireRenderer) { rrset_ns.toWire(renderer); UnitTestUtil::readWireData("rrset_toWire2", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); // toWire() cannot be performed for an empty RRset except when // class=ANY or class=NONE. @@ -253,15 +299,15 @@ TEST_F(RRsetTest, toWireRenderer) { rrset_any_a_empty.toWire(renderer); wiredata.clear(); UnitTestUtil::readWireData("rrset_toWire3", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); renderer.clear(); rrset_none_a_empty.toWire(renderer); wiredata.clear(); UnitTestUtil::readWireData("rrset_toWire4", wiredata); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(), - renderer.getLength(), &wiredata[0], wiredata.size()); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); } // test operator<<. We simply confirm it appends the result of toText(). @@ -365,4 +411,38 @@ TEST_F(RRsetRRSIGTest, toText) { "20100322084538 20100220084538 1 example.com. FAKEFAKEFAKEFAKE\n", rrset_aaaa->toText()); } + +TEST_F(RRsetRRSIGTest, getLength) { + // A RR + // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets + // TYPE field = 2 octets + // CLASS field = 2 octets + // TTL field = 4 octets + // RDLENGTH field = 2 octets + // A RDATA = 4 octets + // Total = 18 + 2 + 2 + 4 + 2 + 4 = 32 octets + + // 2 A RRs + EXPECT_EQ(32 + 32, rrset_a->getLength()); + + // RRSIG + // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets + // TYPE field = 2 octets + // CLASS field = 2 octets + // TTL field = 4 octets + // RDLENGTH field = 2 octets + // RRSIG RDATA = 40 octets + // Total = 18 + 2 + 2 + 4 + 2 + 40 = 68 octets + RRsetPtr my_rrsig(new RRset(test_name, RRClass::IN(), + RRType::RRSIG(), RRTTL(3600))); + my_rrsig->addRdata(generic::RRSIG("A 4 3 3600 " + "20000101000000 20000201000000 " + "12345 example.com. FAKEFAKEFAKE")); + EXPECT_EQ(68, my_rrsig->getLength()); + + // RRset with attached RRSIG + rrset_a->addRRsig(my_rrsig); + + EXPECT_EQ(32 + 32 + 68, rrset_a->getLength()); +} } diff --git a/src/lib/dns/tests/rrttl_unittest.cc b/src/lib/dns/tests/rrttl_unittest.cc index c849c444ca..23b7c2d9ce 100644 --- a/src/lib/dns/tests/rrttl_unittest.cc +++ b/src/lib/dns/tests/rrttl_unittest.cc @@ -19,6 +19,7 @@ #include <dns/rrttl.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> #include <boost/scoped_ptr.hpp> @@ -27,6 +28,7 @@ using namespace isc; using namespace isc::dns; using namespace isc::util; using boost::scoped_ptr; +using isc::util::unittests::matchWireData; namespace { class RRTTLTest : public ::testing::Test { @@ -193,9 +195,8 @@ TEST_F(RRTTLTest, toWireBuffer) { ttl_32bit.toWire(obuffer); ttl_max.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata, sizeof(wiredata)); + matchWireData(wiredata, sizeof(wiredata), + obuffer.getData(), obuffer.getLength()); } TEST_F(RRTTLTest, toWireRenderer) { @@ -205,9 +206,8 @@ TEST_F(RRTTLTest, toWireRenderer) { ttl_32bit.toWire(renderer); ttl_max.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata, sizeof(wiredata)); + matchWireData(wiredata, sizeof(wiredata), + renderer.getData(), renderer.getLength()); } TEST_F(RRTTLTest, equal) { diff --git a/src/lib/dns/tests/rrtype_unittest.cc b/src/lib/dns/tests/rrtype_unittest.cc index ee302a1c41..84d52a9131 100644 --- a/src/lib/dns/tests/rrtype_unittest.cc +++ b/src/lib/dns/tests/rrtype_unittest.cc @@ -19,11 +19,13 @@ #include <dns/rrtype.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; +using isc::util::unittests::matchWireData; namespace { class RRTypeTest : public ::testing::Test { @@ -107,9 +109,8 @@ TEST_F(RRTypeTest, toWireBuffer) { rrtype_0x8000.toWire(obuffer); rrtype_max.toWire(obuffer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - obuffer.getData(), obuffer.getLength(), - wiredata, sizeof(wiredata)); + matchWireData(wiredata, sizeof(wiredata), + obuffer.getData(), obuffer.getLength()); } TEST_F(RRTypeTest, toWireRenderer) { @@ -119,9 +120,8 @@ TEST_F(RRTypeTest, toWireRenderer) { rrtype_0x8000.toWire(renderer); rrtype_max.toWire(renderer); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - wiredata, sizeof(wiredata)); + matchWireData(wiredata, sizeof(wiredata), + renderer.getData(), renderer.getLength()); } TEST_F(RRTypeTest, wellKnownTypes) { diff --git a/src/lib/dns/tests/testdata/.gitignore b/src/lib/dns/tests/testdata/.gitignore index a0a14f4a19..f18ac2fb8c 100644 --- a/src/lib/dns/tests/testdata/.gitignore +++ b/src/lib/dns/tests/testdata/.gitignore @@ -87,6 +87,12 @@ /rdata_sshfp_fromWire6.wire /rdata_sshfp_fromWire7.wire /rdata_sshfp_fromWire8.wire +/rdata_tlsa_fromWire3.wire +/rdata_tlsa_fromWire4.wire +/rdata_tlsa_fromWire5.wire +/rdata_tlsa_fromWire6.wire +/rdata_tlsa_fromWire7.wire +/rdata_tlsa_fromWire8.wire /rdata_tsig_fromWire1.wire /rdata_tsig_fromWire2.wire /rdata_tsig_fromWire3.wire @@ -105,6 +111,10 @@ /rdata_txt_fromWire3.wire /rdata_txt_fromWire4.wire /rdata_txt_fromWire5.wire +/rdata_caa_fromWire1.wire +/rdata_caa_fromWire2.wire +/rdata_caa_fromWire3.wire +/rdata_caa_fromWire4.wire /rdatafields1.wire /rdatafields2.wire /rdatafields3.wire diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am index b6d7e35ada..fadf30eb60 100644 --- a/src/lib/dns/tests/testdata/Makefile.am +++ b/src/lib/dns/tests/testdata/Makefile.am @@ -56,6 +56,9 @@ BUILT_SOURCES += rdata_afsdb_toWire1.wire rdata_afsdb_toWire2.wire BUILT_SOURCES += rdata_soa_toWireUncompressed.wire BUILT_SOURCES += rdata_txt_fromWire2.wire rdata_txt_fromWire3.wire BUILT_SOURCES += rdata_txt_fromWire4.wire rdata_txt_fromWire5.wire +BUILT_SOURCES += rdata_tlsa_fromWire3.wire rdata_tlsa_fromWire4.wire +BUILT_SOURCES += rdata_tlsa_fromWire5.wire rdata_tlsa_fromWire6.wire +BUILT_SOURCES += rdata_tlsa_fromWire7.wire rdata_tlsa_fromWire8.wire BUILT_SOURCES += rdata_tsig_fromWire1.wire rdata_tsig_fromWire2.wire BUILT_SOURCES += rdata_tsig_fromWire3.wire rdata_tsig_fromWire4.wire BUILT_SOURCES += rdata_tsig_fromWire5.wire rdata_tsig_fromWire6.wire @@ -64,6 +67,8 @@ BUILT_SOURCES += rdata_tsig_fromWire9.wire BUILT_SOURCES += rdata_tsig_toWire1.wire rdata_tsig_toWire2.wire BUILT_SOURCES += rdata_tsig_toWire3.wire rdata_tsig_toWire4.wire BUILT_SOURCES += rdata_tsig_toWire5.wire +BUILT_SOURCES += rdata_caa_fromWire1.wire rdata_caa_fromWire2.wire +BUILT_SOURCES += rdata_caa_fromWire3.wire rdata_caa_fromWire4.wire BUILT_SOURCES += tsigrecord_toWire1.wire tsigrecord_toWire2.wire BUILT_SOURCES += tsig_verify1.wire tsig_verify2.wire tsig_verify3.wire BUILT_SOURCES += tsig_verify4.wire tsig_verify5.wire tsig_verify6.wire @@ -127,7 +132,9 @@ EXTRA_DIST += rdata_nsec3_fromWire10.spec rdata_nsec3_fromWire11.spec EXTRA_DIST += rdata_nsec3_fromWire12.spec rdata_nsec3_fromWire13.spec EXTRA_DIST += rdata_nsec3_fromWire14.spec rdata_nsec3_fromWire15.spec EXTRA_DIST += rdata_nsec3_fromWire16.spec rdata_nsec3_fromWire17.spec -EXTRA_DIST += rdata_opt_fromWire rdata_rrsig_fromWire1 +EXTRA_DIST += rdata_opt_fromWire1 rdata_opt_fromWire2 +EXTRA_DIST += rdata_opt_fromWire3 rdata_opt_fromWire4 +EXTRA_DIST += rdata_rrsig_fromWire1 EXTRA_DIST += rdata_rrsig_fromWire2.spec EXTRA_DIST += rdata_rp_fromWire1.spec rdata_rp_fromWire2.spec EXTRA_DIST += rdata_rp_fromWire3.spec rdata_rp_fromWire4.spec @@ -159,6 +166,12 @@ EXTRA_DIST += rrcode16_fromWire1 rrcode16_fromWire2 EXTRA_DIST += rrcode32_fromWire1 rrcode32_fromWire2 EXTRA_DIST += rrset_toWire1 rrset_toWire2 EXTRA_DIST += rrset_toWire3 rrset_toWire4 +EXTRA_DIST += rdata_tlsa_fromWire rdata_tlsa_fromWire2 +EXTRA_DIST += rdata_tlsa_fromWire3.spec rdata_tlsa_fromWire4.spec +EXTRA_DIST += rdata_tlsa_fromWire5.spec rdata_tlsa_fromWire6.spec +EXTRA_DIST += rdata_tlsa_fromWire7.spec rdata_tlsa_fromWire8.spec +EXTRA_DIST += rdata_tlsa_fromWire9 rdata_tlsa_fromWire10 +EXTRA_DIST += rdata_tlsa_fromWire11 rdata_tlsa_fromWire12 EXTRA_DIST += rdata_tsig_fromWire1.spec rdata_tsig_fromWire2.spec EXTRA_DIST += rdata_tsig_fromWire3.spec rdata_tsig_fromWire4.spec EXTRA_DIST += rdata_tsig_fromWire5.spec rdata_tsig_fromWire6.spec @@ -167,6 +180,9 @@ EXTRA_DIST += rdata_tsig_fromWire9.spec EXTRA_DIST += rdata_tsig_toWire1.spec rdata_tsig_toWire2.spec EXTRA_DIST += rdata_tsig_toWire3.spec rdata_tsig_toWire4.spec EXTRA_DIST += rdata_tsig_toWire5.spec +EXTRA_DIST += rdata_caa_fromWire1.spec rdata_caa_fromWire2.spec +EXTRA_DIST += rdata_caa_fromWire3.spec rdata_caa_fromWire4.spec +EXTRA_DIST += rdata_caa_fromWire5 rdata_caa_fromWire6 EXTRA_DIST += tsigrecord_toWire1.spec tsigrecord_toWire2.spec EXTRA_DIST += tsig_verify1.spec tsig_verify2.spec tsig_verify3.spec EXTRA_DIST += tsig_verify4.spec tsig_verify5.spec tsig_verify6.spec diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec new file mode 100644 index 0000000000..d21987c7eb --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec @@ -0,0 +1,6 @@ +# +# The simplest form of CAA: all default parameters +# +[custom] +sections: caa +[caa] diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec new file mode 100644 index 0000000000..867e43d048 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec @@ -0,0 +1,7 @@ +# +# Mixed case CAA tag field. +# +[custom] +sections: caa +[caa] +tag: 'ISSue' diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec new file mode 100644 index 0000000000..9297151df0 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec @@ -0,0 +1,7 @@ +# +# Missing CAA value field. +# +[custom] +sections: caa +[caa] +value: '' diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec new file mode 100644 index 0000000000..53e16b12a3 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec @@ -0,0 +1,7 @@ +# +# Missing CAA value field. +# +[custom] +sections: caa +[caa] +tag: '' diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire5 b/src/lib/dns/tests/testdata/rdata_caa_fromWire5 new file mode 100644 index 0000000000..123011fdb3 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_caa_fromWire5 @@ -0,0 +1,6 @@ +# Test where CAA value field is shorter than the RDATA length + +# CAA RDATA, RDLEN=32 +0020 +# FLAGS=0 TAG=c VALUE=ca.example.net +00 01 63 63612e6578616d706c652e6e6574 diff --git a/src/lib/dns/tests/testdata/rdata_caa_fromWire6 b/src/lib/dns/tests/testdata/rdata_caa_fromWire6 new file mode 100644 index 0000000000..1a35a1aef7 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_caa_fromWire6 @@ -0,0 +1,4 @@ +# Test where RDATA is completely missing + +# CAA RDATA, RDLEN=32 +0020 diff --git a/src/lib/dns/tests/testdata/rdata_opt_fromWire b/src/lib/dns/tests/testdata/rdata_opt_fromWire deleted file mode 100644 index 0ca5f6aa0e..0000000000 --- a/src/lib/dns/tests/testdata/rdata_opt_fromWire +++ /dev/null @@ -1,16 +0,0 @@ -# -# various kinds of OPT RDATA stored in an input buffer -# -# empty RDATA (which is okay) -# -# 0 1 (bytes) - 00 00 -# -# an OPT RR containing an NSID Option -# code=3 len=3 ID value (opaque) -# 2 3 4 5 6 7 8 9 10 - 00 07 00 03 00 03 00 01 02 -# -# short buffer (this can be tested only at the end of the buffer) -# 1 2 3 4 5 - 00 04 c0 00 02 diff --git a/src/lib/dns/tests/testdata/rdata_opt_fromWire1 b/src/lib/dns/tests/testdata/rdata_opt_fromWire1 new file mode 100644 index 0000000000..f2eb680d0f --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_opt_fromWire1 @@ -0,0 +1,15 @@ +# Various kinds of OPT RDATA stored in an input buffer +# +# Empty RDATA (which is okay) +# +# 0 1 (bytes) + 00 00 +# +# An OPT RR containing an NSID Option +# code=3 len=3 ID value (opaque) +# 2 3 4 5 6 7 8 9 10 + 00 07 00 2a 00 03 00 01 02 +# +# Short buffer (this can be tested only at the end of the buffer) +# 1 2 3 4 5 + 00 04 c0 00 02 diff --git a/src/lib/dns/tests/testdata/rdata_opt_fromWire2 b/src/lib/dns/tests/testdata/rdata_opt_fromWire2 new file mode 100644 index 0000000000..2c5a11fe54 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_opt_fromWire2 @@ -0,0 +1,4 @@ +# Short RDATA length +# +# OPT RDATA, RDLEN=1 +0001 diff --git a/src/lib/dns/tests/testdata/rdata_opt_fromWire3 b/src/lib/dns/tests/testdata/rdata_opt_fromWire3 new file mode 100644 index 0000000000..52db1d8c33 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_opt_fromWire3 @@ -0,0 +1,8 @@ +# Short RDATA length (in second pseudo RR) +# +# OPT RDATA, RDLEN=8 +0008 +# Pseudo RR 1 of size 7 (code=3, len=3) +00 03 00 03 00 01 02 +# Pseudo RR 2 of size 7 exhausts RDLEN (code=4, len=3) +00 04 00 03 00 01 02 diff --git a/src/lib/dns/tests/testdata/rdata_opt_fromWire4 b/src/lib/dns/tests/testdata/rdata_opt_fromWire4 new file mode 100644 index 0000000000..a302127b1a --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_opt_fromWire4 @@ -0,0 +1,9 @@ +# Sum of option lengths would overflow RDLEN +# +# OPT RDATA, RDLEN=14 (0x000e) +000e +# Pseudo RR 1 (code=3, len=3) +00 03 00 03 00 01 02 +# Pseudo RR 2 (code=4, len=65535 overflows RDLEN) +00 04 ff ff 00 01 02 +# Rest of option data is omitted... diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire new file mode 100644 index 0000000000..38e279ceca --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire @@ -0,0 +1,4 @@ +# TLSA RDATA, RDLEN=35 +0023 +# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=... +00 00 01 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire10 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire10 new file mode 100644 index 0000000000..67cecb15de --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire10 @@ -0,0 +1,6 @@ +# Test where certificate association data is missing. + +# TLSA RDATA, RDLEN=35 +0023 +# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=(missing) +00 00 01 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire11 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire11 new file mode 100644 index 0000000000..4b8ec930e2 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire11 @@ -0,0 +1,4 @@ +# Test where RDATA is completely missing + +# TLSA RDATA, RDLEN=35 +0023 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire12 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire12 new file mode 100644 index 0000000000..71c7b9ceb5 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire12 @@ -0,0 +1,4 @@ +# TLSA RDATA, RDLEN=3 +0003 +# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=(none) +03 01 02 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire2 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire2 new file mode 100644 index 0000000000..36ce27806f --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire2 @@ -0,0 +1,4 @@ +# TLSA RDATA, RDLEN=35 +0023 +# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=... +00 00 01 d2abde240d7cd3ee6b4b28c54df034b97983A1D16E8A410E4561CB106618E971 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.spec new file mode 100644 index 0000000000..39c8057d6a --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire3.spec @@ -0,0 +1,7 @@ +# +# TLSA RDATA +# +[custom] +sections: tlsa +[tlsa] +certificate_usage: 0 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.spec new file mode 100644 index 0000000000..d97ae6a9e8 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire4.spec @@ -0,0 +1,7 @@ +# +# TLSA RDATA +# +[custom] +sections: tlsa +[tlsa] +certificate_usage: 255 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.spec new file mode 100644 index 0000000000..cc3e296b84 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire5.spec @@ -0,0 +1,7 @@ +# +# TLSA RDATA +# +[custom] +sections: tlsa +[tlsa] +selector: 255 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.spec new file mode 100644 index 0000000000..eed0ab90a6 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire6.spec @@ -0,0 +1,7 @@ +# +# TLSA RDATA +# +[custom] +sections: tlsa +[tlsa] +matching_type: 255 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.spec new file mode 100644 index 0000000000..576df1ef36 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire7.spec @@ -0,0 +1,9 @@ +# +# TLSA RDATA +# +[custom] +sections: tlsa +[tlsa] +certificate_usage: 3 +selector: 1 +matching_type: 2 diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.spec b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.spec new file mode 100644 index 0000000000..ef5c108dff --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire8.spec @@ -0,0 +1,7 @@ +# +# TLSA RDATA +# +[custom] +sections: tlsa +[tlsa] +certificate_association_data: '0123' diff --git a/src/lib/dns/tests/testdata/rdata_tlsa_fromWire9 b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire9 new file mode 100644 index 0000000000..fc4560af51 --- /dev/null +++ b/src/lib/dns/tests/testdata/rdata_tlsa_fromWire9 @@ -0,0 +1,7 @@ +# Test where certificate association data length is smaller than what +# RDATA length indicates. + +# TLSA RDATA, RDLEN=64 +0040 +# CERTIFICATE_USAGE=0 SELECTOR=0 MATCHING_TYPE=1 CERTIFICATE_ASSOCIATION_DATA=(32 bytes) +00 00 01 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971 diff --git a/src/lib/dns/tests/tsig_unittest.cc b/src/lib/dns/tests/tsig_unittest.cc index 458a6e0cf3..6348e9cbb5 100644 --- a/src/lib/dns/tests/tsig_unittest.cc +++ b/src/lib/dns/tests/tsig_unittest.cc @@ -40,6 +40,7 @@ #include <dns/tsigrecord.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> using namespace std; using namespace isc; @@ -48,6 +49,7 @@ using namespace isc::util; using namespace isc::util::encode; using namespace isc::dns::rdata; using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; // See dnssectime.cc namespace isc { @@ -188,7 +190,7 @@ TSIGTest::createMessageAndSign(uint16_t id, const Name& qname, (ctx->getState() == TSIGContext::INIT) ? TSIGContext::SENT_REQUEST : TSIGContext::SENT_RESPONSE; - message.toWire(renderer, *ctx); + message.toWire(renderer, ctx); message.clear(Message::PARSE); InputBuffer buffer(renderer.getData(), renderer.getLength()); @@ -224,15 +226,14 @@ commonSignChecks(ConstTSIGRecordPtr tsig, uint16_t expected_qid, EXPECT_EQ(expected_timesigned, tsig_rdata.getTimeSigned()); EXPECT_EQ(300, tsig_rdata.getFudge()); EXPECT_EQ(expected_maclen, tsig_rdata.getMACSize()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - tsig_rdata.getMAC(), tsig_rdata.getMACSize(), - expected_mac, expected_maclen); + matchWireData(expected_mac, expected_maclen, + tsig_rdata.getMAC(), tsig_rdata.getMACSize()); + EXPECT_EQ(expected_qid, tsig_rdata.getOriginalID()); EXPECT_EQ(expected_error, tsig_rdata.getError()); EXPECT_EQ(expected_otherlen, tsig_rdata.getOtherLen()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - tsig_rdata.getOtherData(), tsig_rdata.getOtherLen(), - expected_otherdata, expected_otherlen); + matchWireData(expected_otherdata, expected_otherlen, + tsig_rdata.getOtherData(), tsig_rdata.getOtherLen()); } void diff --git a/src/lib/dns/tests/tsigkey_unittest.cc b/src/lib/dns/tests/tsigkey_unittest.cc index eaf4040d44..8a9d86f73a 100644 --- a/src/lib/dns/tests/tsigkey_unittest.cc +++ b/src/lib/dns/tests/tsigkey_unittest.cc @@ -23,10 +23,12 @@ #include <dns/tsigkey.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> using namespace std; using namespace isc::dns; using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class TSIGKeyTest : public ::testing::Test { @@ -72,15 +74,16 @@ TEST_F(TSIGKeyTest, construct) { secret.c_str(), secret.size()); EXPECT_EQ(key_name, key.getKeyName()); EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), key.getAlgorithmName()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret.c_str(), - secret.size(), key.getSecret(), key.getSecretLength()); + matchWireData(secret.c_str(), secret.size(), + key.getSecret(), key.getSecretLength()); TSIGKey key_short_md5(key_name, TSIGKey::HMACMD5_SHORT_NAME(), secret.c_str(), secret.size()); - EXPECT_EQ(key_name, key.getKeyName()); - EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), key.getAlgorithmName()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret.c_str(), - secret.size(), key.getSecret(), key.getSecretLength()); + EXPECT_EQ(key_name, key_short_md5.getKeyName()); + EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), + key_short_md5.getAlgorithmName()); + matchWireData(secret.c_str(), secret.size(), + key_short_md5.getSecret(), key_short_md5.getSecretLength()); // "unknown" algorithm is only accepted with empty secret. EXPECT_THROW(TSIGKey(key_name, Name("unknown-alg"), @@ -113,9 +116,8 @@ void compareTSIGKeys(const TSIGKey& expect, const TSIGKey& actual) { EXPECT_EQ(expect.getKeyName(), actual.getKeyName()); EXPECT_EQ(expect.getAlgorithmName(), actual.getAlgorithmName()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - expect.getSecret(), expect.getSecretLength(), - actual.getSecret(), actual.getSecretLength()); + matchWireData(expect.getSecret(), expect.getSecretLength(), + actual.getSecret(), actual.getSecretLength()); } TEST_F(TSIGKeyTest, copyConstruct) { @@ -249,9 +251,8 @@ TEST_F(TSIGKeyRingTest, find) { EXPECT_EQ(TSIGKeyRing::SUCCESS, result1.code); EXPECT_EQ(key_name, result1.key->getKeyName()); EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result1.key->getAlgorithmName()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret, secret_len, - result1.key->getSecret(), - result1.key->getSecretLength()); + matchWireData(secret, secret_len, + result1.key->getSecret(), result1.key->getSecretLength()); // If either key name or algorithm doesn't match, search should fail. const TSIGKeyRing::FindResult result2 = @@ -268,9 +269,8 @@ TEST_F(TSIGKeyRingTest, find) { EXPECT_EQ(TSIGKeyRing::SUCCESS, result4.code); EXPECT_EQ(key_name, result4.key->getKeyName()); EXPECT_EQ(TSIGKey::HMACSHA256_NAME(), result4.key->getAlgorithmName()); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, secret, secret_len, - result4.key->getSecret(), - result4.key->getSecretLength()); + matchWireData(secret, secret_len, + result4.key->getSecret(), result4.key->getSecretLength()); } TEST_F(TSIGKeyRingTest, findFromSome) { diff --git a/src/lib/dns/tests/tsigrecord_unittest.cc b/src/lib/dns/tests/tsigrecord_unittest.cc index 532681ac2d..9c08fe0dfe 100644 --- a/src/lib/dns/tests/tsigrecord_unittest.cc +++ b/src/lib/dns/tests/tsigrecord_unittest.cc @@ -29,12 +29,14 @@ #include <dns/tsigrecord.h> #include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> using namespace std; using namespace isc::util; using namespace isc::dns; using namespace isc::dns::rdata; using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; namespace { class TSIGRecordTest : public ::testing::Test { @@ -108,16 +110,14 @@ TEST_F(TSIGRecordTest, fromParams) { TEST_F(TSIGRecordTest, recordToWire) { UnitTestUtil::readWireData("tsigrecord_toWire1.wire", data); EXPECT_EQ(1, test_record.toWire(renderer)); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); // Same test for a dumb buffer buffer.clear(); EXPECT_EQ(1, test_record.toWire(buffer)); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - buffer.getData(), buffer.getLength(), - &data[0], data.size()); + matchWireData(&data[0], data.size(), + buffer.getData(), buffer.getLength()); } TEST_F(TSIGRecordTest, recordToOLongToWire) { @@ -139,9 +139,8 @@ TEST_F(TSIGRecordTest, recordToWireAfterNames) { renderer.writeName(TSIGKey::HMACMD5_NAME()); renderer.writeName(Name("foo.example.com")); EXPECT_EQ(1, test_record.toWire(renderer)); - EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - renderer.getData(), renderer.getLength(), - &data[0], data.size()); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); } TEST_F(TSIGRecordTest, toText) { diff --git a/src/lib/dns/tests/unittest_util.cc b/src/lib/dns/tests/unittest_util.cc index 66d49a8af4..bf4c8cbf33 100644 --- a/src/lib/dns/tests/unittest_util.cc +++ b/src/lib/dns/tests/unittest_util.cc @@ -132,33 +132,6 @@ UnitTestUtil::readWireData(const string& datastr, } ::testing::AssertionResult -UnitTestUtil::matchWireData(const char*, const char*, const char*, const char*, - const void* data1, size_t len1, - const void* data2, size_t len2) -{ - ::testing::Message msg; - size_t cmplen = min(len1, len2); - - for (size_t i = 0; i < cmplen; i++) { - int ch1 = static_cast<const uint8_t*>(data1)[i]; - int ch2 = static_cast<const uint8_t*>(data2)[i]; - if (ch1 != ch2) { - msg << "Wire data mismatch at " << i << "th byte\n" - << " Actual: " << ch1 << "\n" - << "Expected: " << ch2 << "\n"; - return (::testing::AssertionFailure(msg)); - } - } - if (len1 != len2) { - msg << "Wire data mismatch in length:\n" - << " Actual: " << len1 << "\n" - << "Expected: " << len2 << "\n"; - return (::testing::AssertionFailure(msg)); - } - return (::testing::AssertionSuccess()); -} - -::testing::AssertionResult UnitTestUtil::matchName(const char*, const char*, const isc::dns::Name& name1, const isc::dns::Name& name2) diff --git a/src/lib/dns/tests/unittest_util.h b/src/lib/dns/tests/unittest_util.h index f50df14ab2..1d65f8d8bc 100644 --- a/src/lib/dns/tests/unittest_util.h +++ b/src/lib/dns/tests/unittest_util.h @@ -46,28 +46,6 @@ public: std::vector<unsigned char>& data); /// - /// Compare len1 bytes of data1 with len2 bytes of data2 as binary data. - /// - /// If they don't match report the point of mismatch in the google test - /// format. This method is expected to be used from the EXPECT_PRED_FORMAT4 - /// macro of google test as follows: - /// \code EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, - /// actual_data, actual_data_len, - /// expected_data, expected_data_len); \endcode - /// Parameters from dataexp1 to lenexp2 are passed via the macro but will - /// be ignored by this method. - /// Note: newer versions of google test supports the direct use of - /// AssertionResult with the EXPECT_TRUE macro, which would be more - /// intuitive, but to be as compatible as possible we use the more primitive - /// macro, i.e., EXPECT_PRED_FORMAT4. - /// - static ::testing::AssertionResult - matchWireData(const char* dataexp1, const char* lenexp1, - const char* dataexp2, const char* lenexp2, - const void* data1, size_t len1, - const void* data2, size_t len2); - - /// /// Compare two names. /// /// This check method uses \c Name::compare() for comparison, which performs diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc index d7ffcf8fa7..b6e1716d67 100644 --- a/src/lib/dns/tsig.cc +++ b/src/lib/dns/tsig.cc @@ -79,7 +79,7 @@ struct TSIGContext::TSIGContextImpl { key_.getSecret(), key_.getSecretLength(), key_.getAlgorithm()), deleteHMAC); - } catch (const Exception&) { + } catch (const isc::Exception&) { return; } digest_len_ = hmac_->getOutputLength(); @@ -289,20 +289,20 @@ TSIGContext::getTSIGLength() const { // // The space required for an TSIG record is: // - // n1 bytes for the (key) name - // 2 bytes for the type - // 2 bytes for the class - // 4 bytes for the ttl - // 2 bytes for the rdlength - // n2 bytes for the algorithm name - // 6 bytes for the time signed - // 2 bytes for the fudge - // 2 bytes for the MAC size - // x bytes for the MAC - // 2 bytes for the original id - // 2 bytes for the error - // 2 bytes for the other data length - // y bytes for the other data (at most) + // n1 bytes for the (key) name + // 2 bytes for the type + // 2 bytes for the class + // 4 bytes for the ttl + // 2 bytes for the rdlength + // n2 bytes for the algorithm name + // 6 bytes for the time signed + // 2 bytes for the fudge + // 2 bytes for the MAC size + // x bytes for the MAC + // 2 bytes for the original id + // 2 bytes for the error + // 2 bytes for the other data length + // y bytes for the other data (at most) // --------------------------------- // 26 + n1 + n2 + x + y bytes // diff --git a/src/lib/dns/tsigkey.cc b/src/lib/dns/tsigkey.cc index 24a6f579bd..862d3005eb 100644 --- a/src/lib/dns/tsigkey.cc +++ b/src/lib/dns/tsigkey.cc @@ -141,7 +141,7 @@ TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) { impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, algorithm, secret.empty() ? NULL : &secret[0], secret.size()); - } catch (const Exception& e) { + } catch (const isc::Exception& e) { // 'reduce' the several types of exceptions name parsing and // Base64 decoding can throw to just the InvalidParameter isc_throw(InvalidParameter, e.what()); |