diff options
Diffstat (limited to 'src/lib/dns/rdata')
75 files changed, 10538 insertions, 0 deletions
diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc new file mode 100644 index 0000000..a80d742 --- /dev/null +++ b/src/lib/dns/rdata/any_255/tsig_250.cc @@ -0,0 +1,567 @@ +// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> +#include <sstream> +#include <vector> + +#include <boost/lexical_cast.hpp> + +#include <util/buffer.h> +#include <util/encode/base64.h> + +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rcode.h> +#include <dns/tsigkey.h> +#include <dns/tsigerror.h> +#include <dns/rdata/generic/detail/lexer_util.h> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using namespace isc::util::encode; +using namespace isc::dns; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +// straightforward representation of TSIG RDATA fields +struct TSIGImpl { + TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge, + vector<uint8_t>& mac, uint16_t original_id, uint16_t error, + vector<uint8_t>& other_data) : + algorithm_(algorithm), time_signed_(time_signed), fudge_(fudge), + mac_(mac), original_id_(original_id), error_(error), + other_data_(other_data) + {} + TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge, + size_t macsize, const void* mac, uint16_t original_id, + uint16_t error, size_t other_len, const void* other_data) : + algorithm_(algorithm), time_signed_(time_signed), fudge_(fudge), + mac_(static_cast<const uint8_t*>(mac), + static_cast<const uint8_t*>(mac) + macsize), + original_id_(original_id), error_(error), + other_data_(static_cast<const uint8_t*>(other_data), + static_cast<const uint8_t*>(other_data) + other_len) + {} + template <typename Output> + void toWireCommon(Output& output) const; + + const Name algorithm_; + const uint64_t time_signed_; + const uint16_t fudge_; + const vector<uint8_t> mac_; + const uint16_t original_id_; + const uint16_t error_; + const vector<uint8_t> other_data_; +}; + +// helper function for string and lexer constructors +TSIGImpl* +TSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) { + const Name& algorithm = + createNameFromLexer(lexer, origin ? origin : &Name::ROOT_NAME()); + const Name& canonical_algorithm_name = + (algorithm == TSIGKey::HMACMD5_SHORT_NAME()) ? + TSIGKey::HMACMD5_NAME() : algorithm; + + const string& time_txt = + lexer.getNextToken(MasterToken::STRING).getString(); + uint64_t time_signed; + try { + time_signed = boost::lexical_cast<uint64_t>(time_txt); + } catch (const boost::bad_lexical_cast&) { + isc_throw(InvalidRdataText, "Invalid TSIG Time"); + } + if ((time_signed >> 48) != 0) { + isc_throw(InvalidRdataText, "TSIG Time out of range"); + } + + const uint32_t fudge = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (fudge > 0xffff) { + isc_throw(InvalidRdataText, "TSIG Fudge out of range"); + } + const uint32_t macsize = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (macsize > 0xffff) { + isc_throw(InvalidRdataText, "TSIG MAC Size out of range"); + } + + const string& mac_txt = (macsize > 0) ? + lexer.getNextToken(MasterToken::STRING).getString() : ""; + vector<uint8_t> mac; + decodeBase64(mac_txt, mac); + if (mac.size() != macsize) { + isc_throw(InvalidRdataText, "TSIG MAC Size and data are inconsistent"); + } + + const uint32_t orig_id = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (orig_id > 0xffff) { + isc_throw(InvalidRdataText, "TSIG Original ID out of range"); + } + + const string& error_txt = + lexer.getNextToken(MasterToken::STRING).getString(); + uint32_t error = 0; + // XXX: In the initial implementation we hardcode the mnemonics. + // We'll soon generalize this. + if (error_txt == "NOERROR") { + error = Rcode::NOERROR_CODE; + } else if (error_txt == "BADSIG") { + error = TSIGError::BAD_SIG_CODE; + } else if (error_txt == "BADKEY") { + error = TSIGError::BAD_KEY_CODE; + } else if (error_txt == "BADTIME") { + error = TSIGError::BAD_TIME_CODE; + } else if (error_txt == "BADMODE") { + error = TSIGError::BAD_MODE_CODE; + } else if (error_txt == "BADNAME") { + error = TSIGError::BAD_NAME_CODE; + } else if (error_txt == "BADALG") { + error = TSIGError::BAD_ALG_CODE; + } else if (error_txt == "BADTRUNC") { + error = TSIGError::BAD_TRUNC_CODE; + } else { + /// we cast to uint32_t and range-check, because casting directly to + /// uint16_t will convert negative numbers to large positive numbers + try { + error = boost::lexical_cast<uint32_t>(error_txt); + } catch (const boost::bad_lexical_cast&) { + isc_throw(InvalidRdataText, "Invalid TSIG Error"); + } + if (error > 0xffff) { + isc_throw(InvalidRdataText, "TSIG Error out of range"); + } + } + + const uint32_t otherlen = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (otherlen > 0xffff) { + isc_throw(InvalidRdataText, "TSIG Other Len out of range"); + } + const string otherdata_txt = (otherlen > 0) ? + lexer.getNextToken(MasterToken::STRING).getString() : ""; + vector<uint8_t> other_data; + decodeBase64(otherdata_txt, other_data); + if (other_data.size() != otherlen) { + isc_throw(InvalidRdataText, + "TSIG Other Data length does not match Other Len"); + } + // RFC2845 says Other Data is "empty unless Error == BADTIME". + // However, we don't enforce that. + + return (new TSIGImpl(canonical_algorithm_name, time_signed, fudge, mac, + orig_id, error, other_data)); +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid TSIG 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. +/// +/// \c tsig_str must be formatted as follows: +/// \code <Algorithm Name> <Time Signed> <Fudge> <MAC Size> [<MAC>] +/// <Original ID> <Error> <Other Len> [<Other Data>] +/// \endcode +/// +/// Note that, since the Algorithm Name field is defined to be "in domain name +/// syntax", but it is not actually a domain name, it does not have to be +/// fully qualified. +/// +/// The Error field is an unsigned 16-bit decimal integer or a valid mnemonic +/// as specified in RFC2845. Currently, "NOERROR", "BADSIG", "BADKEY", and +/// "BADTIME" are supported (case sensitive). In future versions other +/// representations that are compatible with the DNS RCODE may be supported. +/// +/// The MAC and Other Data fields are base-64 encoded strings that do not +/// contain space characters. +/// If the MAC Size field is 0, the MAC field must not appear in \c tsig_str. +/// If the Other Len field is 0, the Other Data field must not appear in +/// \c tsig_str. +/// The decoded data of the MAC field is MAC Size bytes of binary stream. +/// The decoded data of the Other Data field is Other Len bytes of binary +/// stream. +/// +/// An example of valid string is: +/// \code "hmac-sha256. 853804800 300 3 AAAA 2845 0 0" \endcode +/// In this example Other Data is missing because Other Len is 0. +/// +/// Note that RFC2845 does not define the standard presentation format +/// of %TSIG RR, so the above syntax is implementation specific. +/// This is, however, compatible with the format acceptable to BIND 9's +/// RDATA parser. +/// +/// \throw Others Exception from the Name constructors. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// \throw BadValue if MAC or Other Data is not validly encoded in base-64. +/// +/// \param tsig_str A string containing the RDATA to be created +TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) { + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the TSIGImpl that constructFromLexer() returns. + std::unique_ptr<TSIGImpl> impl_ptr; + + try { + std::istringstream ss(tsig_str); + MasterLexer lexer; + lexer.pushSource(ss); + + impl_ptr.reset(constructFromLexer(lexer, NULL)); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Extra input text for TSIG: " << tsig_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct TSIG from '" << tsig_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 TSIG RDATA. +/// +/// See \c TSIG::TSIG(const std::string&) for description of the +/// expected RDATA fields. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +TSIG::TSIG(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer, origin)) +{ +} + +/// \brief Constructor from wire-format data. +/// +/// When a read operation on \c buffer fails (e.g., due to a corrupted +/// message) a corresponding exception from the \c InputBuffer class will +/// be thrown. +/// If the wire-format data does not begin with a valid domain name, +/// a corresponding exception from the \c Name class will be thrown. +/// In addition, this constructor internally involves resource allocation, +/// and if it fails a corresponding standard exception will be thrown. +/// +/// According to RFC3597, the Algorithm field must be a non compressed form +/// of domain name. But this implementation accepts a %TSIG RR even if that +/// field is compressed. +/// +/// \param buffer A buffer storing the wire format data. +/// \param rdata_len The length of the RDATA in bytes, normally expected +/// to be the value of the RDLENGTH field of the corresponding RR. +/// But this constructor does not use this parameter; if necessary, the caller +/// must check consistency between the length parameter and the actual +/// RDATA length. +TSIG::TSIG(InputBuffer& buffer, size_t) : + impl_(NULL) +{ + Name algorithm(buffer); + + uint8_t time_signed_buf[6]; + buffer.readData(time_signed_buf, sizeof(time_signed_buf)); + const uint64_t time_signed = + (static_cast<uint64_t>(time_signed_buf[0]) << 40 | + static_cast<uint64_t>(time_signed_buf[1]) << 32 | + static_cast<uint64_t>(time_signed_buf[2]) << 24 | + static_cast<uint64_t>(time_signed_buf[3]) << 16 | + static_cast<uint64_t>(time_signed_buf[4]) << 8 | + static_cast<uint64_t>(time_signed_buf[5])); + + const uint16_t fudge = buffer.readUint16(); + + const uint16_t mac_size = buffer.readUint16(); + vector<uint8_t> mac(mac_size); + if (mac_size > 0) { + buffer.readData(&mac[0], mac_size); + } + + const uint16_t original_id = buffer.readUint16(); + const uint16_t error = buffer.readUint16(); + + const uint16_t other_len = buffer.readUint16(); + vector<uint8_t> other_data(other_len); + if (other_len > 0) { + buffer.readData(&other_data[0], other_len); + } + + const Name& canonical_algorithm_name = + (algorithm == TSIGKey::HMACMD5_SHORT_NAME()) ? + TSIGKey::HMACMD5_NAME() : algorithm; + impl_ = new TSIGImpl(canonical_algorithm_name, time_signed, fudge, mac, + original_id, error, other_data); +} + +TSIG::TSIG(const Name& algorithm, uint64_t time_signed, uint16_t fudge, + uint16_t mac_size, const void* mac, uint16_t original_id, + uint16_t error, uint16_t other_len, const void* other_data) : + impl_(NULL) +{ + // Time Signed is a 48-bit value. + if ((time_signed >> 48) != 0) { + isc_throw(OutOfRange, "TSIG Time Signed is too large: " << + time_signed); + } + if ((mac_size == 0 && mac != NULL) || (mac_size > 0 && mac == NULL)) { + isc_throw(InvalidParameter, "TSIG MAC size and data inconsistent"); + } + if ((other_len == 0 && other_data != NULL) || + (other_len > 0 && other_data == NULL)) { + isc_throw(InvalidParameter, + "TSIG Other data length and data inconsistent"); + } + const Name& canonical_algorithm_name = + (algorithm == TSIGKey::HMACMD5_SHORT_NAME()) ? + TSIGKey::HMACMD5_NAME() : algorithm; + impl_ = new TSIGImpl(canonical_algorithm_name, time_signed, fudge, mac_size, + mac, original_id, error, other_len, other_data); +} + +/// \brief The copy constructor. +/// +/// It internally allocates a resource, and if it fails a corresponding +/// standard exception will be thrown. +/// This constructor never throws an exception otherwise. +TSIG::TSIG(const TSIG& source) : Rdata(), impl_(new TSIGImpl(*source.impl_)) +{} + +TSIG& +TSIG::operator=(const TSIG& source) { + if (this == &source) { + return (*this); + } + + TSIGImpl* newimpl = new TSIGImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +TSIG::~TSIG() { + delete impl_; +} + +/// \brief Convert the \c TSIG to a string. +/// +/// The output of this method is formatted as described in the "from string" +/// constructor (\c TSIG(const std::string&))). +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// +/// \return A \c string object that represents the \c TSIG object. +std::string +TSIG::toText() const { + string result; + + result += impl_->algorithm_.toText() + " " + + lexical_cast<string>(impl_->time_signed_) + " " + + lexical_cast<string>(impl_->fudge_) + " " + + lexical_cast<string>(impl_->mac_.size()) + " "; + if (!impl_->mac_.empty()) { + result += encodeBase64(impl_->mac_) + " "; + } + result += lexical_cast<string>(impl_->original_id_) + " "; + result += TSIGError(impl_->error_).toText() + " "; + result += lexical_cast<string>(impl_->other_data_.size()); + if (!impl_->other_data_.empty()) { + result += " " + encodeBase64(impl_->other_data_); + } + + return (result); +} + +// Common sequence of toWire() operations used for the two versions of +// toWire(). +template <typename Output> +void +TSIGImpl::toWireCommon(Output& output) const { + output.writeUint16(time_signed_ >> 32); + output.writeUint32(time_signed_ & 0xffffffff); + output.writeUint16(fudge_); + const uint16_t mac_size = mac_.size(); + output.writeUint16(mac_size); + if (mac_size > 0) { + output.writeData(&mac_[0], mac_size); + } + output.writeUint16(original_id_); + output.writeUint16(error_); + const uint16_t other_len = other_data_.size(); + output.writeUint16(other_len); + if (other_len > 0) { + output.writeData(&other_data_[0], other_len); + } +} + +/// \brief Render the \c TSIG in the wire format without name compression. +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param buffer An output buffer to store the wire data. +void +TSIG::toWire(OutputBuffer& buffer) const { + impl_->algorithm_.toWire(buffer); + impl_->toWireCommon<OutputBuffer>(buffer); +} + +/// \brief Render the \c TSIG in the wire format with taking into account +/// compression. +/// +/// As specified in RFC3597, the Algorithm field (a domain name) will not +/// be compressed. However, the domain name could be a target of compression +/// of other compressible names (though pretty unlikely), the offset +/// information of the algorithm name may be recorded in \c renderer. +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param renderer DNS message rendering context that encapsulates the +/// output buffer and name compression information. +void +TSIG::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(impl_->algorithm_, false); + impl_->toWireCommon<AbstractMessageRenderer>(renderer); +} + +// A helper function commonly used for TSIG::compare(). +int +vectorComp(const vector<uint8_t>& v1, const vector<uint8_t>& v2) { + const size_t this_size = v1.size(); + const size_t other_size = v2.size(); + if (this_size != other_size) { + return (this_size < other_size ? -1 : 1); + } + if (this_size > 0) { + return (memcmp(&v1[0], &v2[0], this_size)); + } + return (0); +} + +/// \brief Compare two instances of \c TSIG RDATA. +/// +/// This method compares \c this and the \c other \c TSIG objects +/// in terms of the DNSSEC sorting order as defined in RFC4034, and returns +/// the result as an integer. +/// +/// This method is expected to be used in a polymorphic way, and the +/// parameter to compare against is therefore of the abstract \c Rdata class. +/// However, comparing two \c Rdata objects of different RR types +/// is meaningless, and \c other must point to a \c TSIG object; +/// otherwise, the standard \c bad_cast exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param other the right-hand operand to compare against. +/// \return < 0 if \c this would be sorted before \c other. +/// \return 0 if \c this is identical to \c other in terms of sorting order. +/// \return > 0 if \c this would be sorted after \c other. +int +TSIG::compare(const Rdata& other) const { + const TSIG& other_tsig = dynamic_cast<const TSIG&>(other); + + const int ncmp = compareNames(impl_->algorithm_, + other_tsig.impl_->algorithm_); + if (ncmp != 0) { + return (ncmp); + } + + if (impl_->time_signed_ != other_tsig.impl_->time_signed_) { + return (impl_->time_signed_ < other_tsig.impl_->time_signed_ ? -1 : 1); + } + if (impl_->fudge_ != other_tsig.impl_->fudge_) { + return (impl_->fudge_ < other_tsig.impl_->fudge_ ? -1 : 1); + } + const int vcmp = vectorComp(impl_->mac_, other_tsig.impl_->mac_); + if (vcmp != 0) { + return (vcmp); + } + if (impl_->original_id_ != other_tsig.impl_->original_id_) { + return (impl_->original_id_ < other_tsig.impl_->original_id_ ? -1 : 1); + } + if (impl_->error_ != other_tsig.impl_->error_) { + return (impl_->error_ < other_tsig.impl_->error_ ? -1 : 1); + } + return (vectorComp(impl_->other_data_, other_tsig.impl_->other_data_)); +} + +const Name& +TSIG::getAlgorithm() const { + return (impl_->algorithm_); +} + +uint64_t +TSIG::getTimeSigned() const { + return (impl_->time_signed_); +} + +uint16_t +TSIG::getFudge() const { + return (impl_->fudge_); +} + +uint16_t +TSIG::getMACSize() const { + return (impl_->mac_.size()); +} + +const void* +TSIG::getMAC() const { + if (!impl_->mac_.empty()) { + return (&impl_->mac_[0]); + } else { + return (NULL); + } +} + +uint16_t +TSIG::getOriginalID() const { + return (impl_->original_id_); +} + +uint16_t +TSIG::getError() const { + return (impl_->error_); +} + +uint16_t +TSIG::getOtherLen() const { + return (impl_->other_data_.size()); +} + +const void* +TSIG::getOtherData() const { + if (!impl_->other_data_.empty()) { + return (&impl_->other_data_[0]); + } else { + return (NULL); + } +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/any_255/tsig_250.h b/src/lib/dns/rdata/any_255/tsig_250.h new file mode 100644 index 0000000..63c2234 --- /dev/null +++ b/src/lib/dns/rdata/any_255/tsig_250.h @@ -0,0 +1,148 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct TSIGImpl; + +/// \brief \c rdata::TSIG class represents the TSIG RDATA as defined %in +/// RFC2845. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// TSIG RDATA. +class TSIG : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Constructor from RDATA field parameters. + /// + /// The parameters are a straightforward mapping of %TSIG RDATA + /// fields as defined %in RFC2845, but there are some implementation + /// specific notes as follows. + /// + /// \c algorithm is a \c Name object that specifies the algorithm. + /// For example, if the algorithm is HMAC-SHA256, \c algorithm would be + /// \c Name("hmac-sha256"). + /// + /// \c time_signed corresponds to the Time Signed field, which is of + /// 48-bit unsigned integer type, and therefore cannot exceed 2^48-1; + /// otherwise, an exception of type \c OutOfRange will be thrown. + /// + /// \c mac_size and \c mac correspond to the MAC Size and MAC fields, + /// respectively. When the MAC field is empty, \c mac must be NULL. + /// \c mac_size and \c mac must be consistent %in that \c mac_size is 0 if + /// and only if \c mac is NULL; otherwise an exception of type + /// InvalidParameter will be thrown. + /// + /// The same restriction applies to \c other_len and \c other_data, + /// which correspond to the Other Len and Other Data fields, respectively. + /// + /// This constructor internally involves resource allocation, and if + /// it fails, a corresponding standard exception will be thrown. + TSIG(const Name& algorithm, uint64_t time_signed, uint16_t fudge, + uint16_t mac_size, const void* mac, uint16_t original_id, + uint16_t error, uint16_t other_len, const void* other_data); + + /// \brief Assignment operator. + /// + /// It internally allocates a resource, and if it fails a corresponding + /// standard exception will be thrown. + /// This operator never throws an exception otherwise. + /// + /// This operator provides the strong exception guarantee: When an + /// exception is thrown the content of the assignment target will be + /// intact. + TSIG& operator=(const TSIG& source); + + /// \brief The destructor. + ~TSIG(); + + /// \brief Return the algorithm name. + /// + /// This method never throws an exception. + const Name& getAlgorithm() const; + + /// \brief Return the value of the Time Signed field. + /// + /// The returned value does not exceed 2^48-1. + /// + /// This method never throws an exception. + uint64_t getTimeSigned() const; + + /// \brief Return the value of the Fudge field. + /// + /// This method never throws an exception. + uint16_t getFudge() const; + + /// \brief Return the value of the MAC Size field. + /// + /// This method never throws an exception. + uint16_t getMACSize() const; + + /// \brief Return the value of the MAC field. + /// + /// If the MAC field is empty, it returns NULL. + /// Otherwise, the memory region beginning at the address returned by + /// this method is valid up to the bytes specified by the return value + /// of \c getMACSize(). + /// The memory region is only valid while the corresponding \c TSIG + /// object is valid. The caller must hold the \c TSIG object while + /// it needs to refer to the region or it must make a local copy of the + /// region. + /// + /// This method never throws an exception. + const void* getMAC() const; + + /// \brief Return the value of the Original ID field. + /// + /// This method never throws an exception. + uint16_t getOriginalID() const; + + /// \brief Return the value of the Error field. + /// + /// This method never throws an exception. + uint16_t getError() const; + + /// \brief Return the value of the Other Len field. + /// + /// This method never throws an exception. + uint16_t getOtherLen() const; + + /// \brief Return the value of the Other Data field. + /// + /// The same note as \c getMAC() applies. + /// + /// This method never throws an exception. + const void* getOtherData() const; +private: + TSIGImpl* constructFromLexer(MasterLexer& lexer, const Name* origin); + + TSIGImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/ch_3/a_1.cc b/src/lib/dns/rdata/ch_3/a_1.cc new file mode 100644 index 0000000..cd4c824 --- /dev/null +++ b/src/lib/dns/rdata/ch_3/a_1.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +using namespace std; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +A::A(const std::string&) { + // TBD +} + +A::A(MasterLexer&, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) +{ + // TBD +} + +A::A(InputBuffer&, size_t) { + // TBD +} + +A::A(const A&) : Rdata() { + // TBD +} + +void +A::toWire(OutputBuffer&) const { + // TBD +} + +void +A::toWire(AbstractMessageRenderer&) const { + // TBD +} + +string +A::toText() const { + // TBD + isc_throw(InvalidRdataText, "Not implemented yet"); +} + +int +A::compare(const Rdata&) const { + return (0); // dummy. TBD +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/ch_3/a_1.h b/src/lib/dns/rdata/ch_3/a_1.h new file mode 100644 index 0000000..6f319b9 --- /dev/null +++ b/src/lib/dns/rdata/ch_3/a_1.h @@ -0,0 +1,32 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class A : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/afsdb_18.cc b/src/lib/dns/rdata/generic/afsdb_18.cc new file mode 100644 index 0000000..5e82b03 --- /dev/null +++ b/src/lib/dns/rdata/generic/afsdb_18.cc @@ -0,0 +1,201 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> +#include <sstream> + +#include <util/buffer.h> +#include <util/strutil.h> + +#include <dns/name.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +#include <boost/lexical_cast.hpp> + +#include <dns/rdata/generic/detail/lexer_util.h> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// \c afsdb_str must be formatted as follows: +/// \code <subtype> <server name> +/// \endcode +/// where server name field must represent a valid domain name. +/// +/// An example of valid string is: +/// \code "1 server.example.com." \endcode +/// +/// <b>Exceptions</b> +/// +/// \exception InvalidRdataText The number of RDATA fields (must be 2) is +/// incorrect. +/// \exception std::bad_alloc Memory allocation fails. +/// \exception Other The constructor of the \c Name class will throw if the +/// names in the string is invalid. +AFSDB::AFSDB(const std::string& afsdb_str) : + subtype_(0), server_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(afsdb_str); + MasterLexer lexer; + lexer.pushSource(ss); + + createFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for AFSDB: " + << afsdb_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct AFSDB from '" << + afsdb_str << "': " << ex.what()); + } +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of an AFSDB RDATA. The SERVER field can be non-absolute if \c origin +/// is non-NULL, in which case \c origin is used to make it absolute. +/// It must not be represented as a quoted string. +/// +/// The SUBTYPE field must be a valid decimal representation of an +/// unsigned 16-bit integer. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of SERVER when it +/// is non-absolute. +AFSDB::AFSDB(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + subtype_(0), server_(".") +{ + createFromLexer(lexer, origin); +} + +void +AFSDB::createFromLexer(MasterLexer& lexer, const Name* origin) +{ + const uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid AFSDB subtype: " << num); + } + subtype_ = static_cast<uint16_t>(num); + + server_ = createNameFromLexer(lexer, origin); +} + +/// \brief Constructor from wire-format data. +/// +/// This constructor doesn't check the validity of the second parameter (rdata +/// length) for parsing. +/// If necessary, the caller will check consistency. +/// +/// \exception std::bad_alloc Memory allocation fails. +/// \exception Other The constructor of the \c Name class will throw if the +/// names in the wire is invalid. +AFSDB::AFSDB(InputBuffer& buffer, size_t) : + subtype_(buffer.readUint16()), server_(buffer) +{} + +/// \brief Copy constructor. +/// +/// \exception std::bad_alloc Memory allocation fails in copying internal +/// member variables (this should be very rare). +AFSDB::AFSDB(const AFSDB& other) : + Rdata(), subtype_(other.subtype_), server_(other.server_) +{} + +AFSDB& +AFSDB::operator=(const AFSDB& source) { + subtype_ = source.subtype_; + server_ = source.server_; + + return (*this); +} + +/// \brief Convert the \c AFSDB to a string. +/// +/// The output of this method is formatted as described in the "from string" +/// constructor (\c AFSDB(const std::string&))). +/// +/// \exception std::bad_alloc Internal resource allocation fails. +/// +/// \return A \c string object that represents the \c AFSDB object. +string +AFSDB::toText() const { + return (lexical_cast<string>(subtype_) + " " + server_.toText()); +} + +/// \brief Render the \c AFSDB in the wire format without name compression. +/// +/// \exception std::bad_alloc Internal resource allocation fails. +/// +/// \param buffer An output buffer to store the wire data. +void +AFSDB::toWire(OutputBuffer& buffer) const { + buffer.writeUint16(subtype_); + server_.toWire(buffer); +} + +/// \brief Render the \c AFSDB in the wire format with taking into account +/// compression. +/// +/// As specified in RFC3597, TYPE AFSDB is not "well-known", the server +/// field (domain name) will not be compressed. +/// +/// \exception std::bad_alloc Internal resource allocation fails. +/// +/// \param renderer DNS message rendering context that encapsulates the +/// output buffer and name compression information. +void +AFSDB::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeUint16(subtype_); + renderer.writeName(server_, false); +} + +/// \brief Compare two instances of \c AFSDB RDATA. +/// +/// See documentation in \c Rdata. +int +AFSDB::compare(const Rdata& other) const { + const AFSDB& other_afsdb = dynamic_cast<const AFSDB&>(other); + if (subtype_ < other_afsdb.subtype_) { + return (-1); + } else if (subtype_ > other_afsdb.subtype_) { + return (1); + } + + return (compareNames(server_, other_afsdb.server_)); +} + +const Name& +AFSDB::getServer() const { + return (server_); +} + +uint16_t +AFSDB::getSubtype() const { + return (subtype_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/afsdb_18.h b/src/lib/dns/rdata/generic/afsdb_18.h new file mode 100644 index 0000000..2fd8fba --- /dev/null +++ b/src/lib/dns/rdata/generic/afsdb_18.h @@ -0,0 +1,68 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +/// \brief \c rdata::AFSDB class represents the AFSDB RDATA as defined %in +/// RFC1183. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// AFSDB RDATA. +class AFSDB : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Assignment operator. + /// + /// This method never throws an exception. + AFSDB& operator=(const AFSDB& source); + /// + /// Specialized methods + /// + + /// \brief Return the value of the server field. + /// + /// \return A reference to a \c Name class object corresponding to the + /// internal server name. + /// + /// This method never throws an exception. + const Name& getServer() const; + + /// \brief Return the value of the subtype field. + /// + /// This method never throws an exception. + uint16_t getSubtype() const; + +private: + void createFromLexer(MasterLexer& lexer, const Name* origin); + + uint16_t subtype_; + Name server_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: 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 0000000..7f8b455 --- /dev/null +++ b/src/lib/dns/rdata/generic/caa_257.cc @@ -0,0 +1,298 @@ +// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#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 unique_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::unique_ptr<CAAImpl> impl_ptr; + + 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 0000000..0e81e71 --- /dev/null +++ b/src/lib/dns/rdata/generic/caa_257.h @@ -0,0 +1,64 @@ +// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// 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/cname_5.cc b/src/lib/dns/rdata/generic/cname_5.cc new file mode 100644 index 0000000..71cb4dc --- /dev/null +++ b/src/lib/dns/rdata/generic/cname_5.cc @@ -0,0 +1,125 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#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/lexer_util.h> + +using namespace std; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// The given string must represent a valid CNAME 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 CNAME must be absolute since there's no parameter that specifies +/// the origin name; if it is not absolute, \c MissingNameOrigin +/// exception will be thrown. These must not be represented as a quoted +/// string. +/// +/// \throw Others Exception from the Name and RRTTL constructors. +/// \throw InvalidRdataText Other general syntax errors. +CNAME::CNAME(const std::string& namestr) : + // Fill in dummy name and replace it soon below. + cname_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(namestr); + MasterLexer lexer; + lexer.pushSource(ss); + + cname_ = createNameFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for CNAME: " + << namestr); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct CNAME from '" << + namestr << "': " << ex.what()); + } +} + +CNAME::CNAME(InputBuffer& buffer, size_t) : + Rdata(), cname_(buffer) +{ + // we don't need rdata_len for parsing. if necessary, the caller will + // check consistency. +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of a CNAME RDATA. The CNAME field can be +/// non-absolute if \c origin is non-NULL, in which case \c origin is +/// used to make it absolute. It must not be represented as a quoted +/// string. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of CNAME when it +/// is non-absolute. +CNAME::CNAME(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + cname_(createNameFromLexer(lexer, origin)) +{} + +CNAME::CNAME(const CNAME& other) : + Rdata(), cname_(other.cname_) +{} + +CNAME::CNAME(const Name& cname) : + cname_(cname) +{} + +void +CNAME::toWire(OutputBuffer& buffer) const { + cname_.toWire(buffer); +} + +void +CNAME::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(cname_); +} + +string +CNAME::toText() const { + return (cname_.toText()); +} + +int +CNAME::compare(const Rdata& other) const { + const CNAME& other_cname = dynamic_cast<const CNAME&>(other); + + return (compareNames(cname_, other_cname.cname_)); +} + +const Name& +CNAME::getCname() const { + return (cname_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/cname_5.h b/src/lib/dns/rdata/generic/cname_5.h new file mode 100644 index 0000000..2149340 --- /dev/null +++ b/src/lib/dns/rdata/generic/cname_5.h @@ -0,0 +1,39 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class CNAME : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + // CNAME specific methods + CNAME(const Name& cname); + const Name& getCname() const; +private: + Name cname_; +}; + +// 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 new file mode 100644 index 0000000..8eee8c0 --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/char_string.cc @@ -0,0 +1,264 @@ +// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> + +#include <dns/exceptions.h> +#include <dns/rdata.h> +#include <dns/master_lexer.h> +#include <dns/rdata/generic/detail/char_string.h> +#include <util/buffer.h> + +#include <boost/lexical_cast.hpp> + +#include <cassert> +#include <cctype> +#include <cstring> +#include <vector> + +#include <stdint.h> + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { + +namespace { +// Convert a DDD form to the corresponding integer +int +decimalToNumber(const char* s, const char* s_end) { + if (s_end - s < 3) { + isc_throw(InvalidRdataText, "Escaped digits too short"); + } + + const std::string num_str(s, s + 3); + try { + const int i = boost::lexical_cast<int>(num_str); + if (i > 255) { + isc_throw(InvalidRdataText, "Escaped digits too large: " + << num_str); + } + return (i); + } catch (const boost::bad_lexical_cast&) { + isc_throw(InvalidRdataText, + "Invalid form for escaped digits: " << num_str); + } +} +} + +void +stringToCharString(const MasterToken::StringRegion& str_region, + CharString& result) +{ + // make a space for the 1-byte length field; filled in at the end + result.push_back(0); + + 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); + assert(n >= 3); + 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 '\\'"); + } + if (result.size() > MAX_CHARSTRING_LEN + 1) { // '+ 1' due to the len field + isc_throw(CharStringTooLong, "character-string is too long: " << + (result.size() - 1) << "(+1) characters"); + } + 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; + for (CharString::const_iterator it = char_string.begin() + 1; + 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); +} + +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) { + return (0); + } + if (self.size() == 0) { + return (-1); + } + if (other.size() == 0) { + return (1); + } + const size_t self_len = self[0]; + const size_t other_len = other[0]; + const size_t cmp_len = std::min(self_len, other_len); + if (cmp_len == 0) { + if (self_len < other_len) { + return (-1); + } else if (self_len > other_len) { + return (1); + } else { + return (0); + } + } + const int cmp = std::memcmp(&self[1], &other[1], 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); + } +} + +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) { + if (rdata_len < 1 || buffer.getLength() - buffer.getPosition() < 1) { + isc_throw(isc::dns::DNSMessageFORMERR, + "insufficient data to read character-string length"); + } + const uint8_t len = buffer.readUint8(); + if (rdata_len < len + 1) { + isc_throw(isc::dns::DNSMessageFORMERR, + "character string length is too large: " << + static_cast<int>(len)); + } + if (buffer.getLength() - buffer.getPosition() < len) { + isc_throw(isc::dns::DNSMessageFORMERR, + "not enough data in buffer to read character-string of len" + << static_cast<int>(len)); + } + + target.resize(len + 1); + target[0] = len; + buffer.readData(&target[0] + 1, len); + + return (len + 1); +} + +} // end of detail +} // end of generic +} // end of rdata +} // end of dns +} // end of isc diff --git a/src/lib/dns/rdata/generic/detail/char_string.h b/src/lib/dns/rdata/generic/detail/char_string.h new file mode 100644 index 0000000..2ad12fb --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/char_string.h @@ -0,0 +1,140 @@ +// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DNS_RDATA_CHARSTRING_H +#define DNS_RDATA_CHARSTRING_H 1 + +#include <dns/master_lexer.h> + +#include <string> +#include <vector> +#include <algorithm> +#include <stdint.h> + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { + +/// \brief Type for DNS character string. +/// +/// A character string can contain any unsigned 8-bit value, so this cannot +/// 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 +/// textual representation of a valid DNS character-string, and dumps +/// the corresponding binary sequence in the given placeholder (passed +/// via the \c result parameter). It handles escape notations of +/// character-strings with a backslash ('\'), and checks the length +/// restriction. +/// +/// \throw CharStringTooLong The resulting binary data are too large for a +/// valid character-string. +/// \throw InvalidRdataText Other 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 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 +/// character string into a textual string representation, escaping any +/// special characters in the process. For example, characters like +/// double-quotes, semi-colon and backspace are prefixed with backspace +/// character, and characters not in the printable range of [0x20, 0x7e] +/// (inclusive) are converted to the \xxx 3-digit decimal +/// representation. +/// +/// \param char_string The \c CharString to convert. +/// \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 +/// \param other The CharString 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 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 +/// format) and places the result in the given \c CharString object. +/// Since this is expected to be used in message parsing, the exception it +/// raises is of that type. +/// +/// On success, the buffer position is advanced to the end of the char-string, +/// and the number of bytes read is returned. +/// +/// \param buffer The buffer to read from. +/// \param rdata_len The total size of the rr's rdata currently being read +/// (used for integrity checks in the wire data) +/// \param target The \c CharString where the result will be stored. Any +/// existing data in the target will be overwritten. +/// \throw DNSMessageFORMERR If the available data is not enough to read +/// the character-string, or if the character-string length is out of bounds +/// \return The number of bytes read +size_t bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len, + CharString& target); + + +} // namespace detail +} // namespace generic +} // namespace rdata +} // namespace dns +} // namespace isc +#endif // DNS_RDATA_CHARSTRING_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/detail/ds_like.h b/src/lib/dns/rdata/generic/detail/ds_like.h new file mode 100644 index 0000000..4d8c2ea --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/ds_like.h @@ -0,0 +1,277 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DS_LIKE_H +#define DS_LIKE_H 1 + +#include <stdint.h> + +#include <iostream> +#include <sstream> +#include <string> +#include <vector> + +#include <boost/lexical_cast.hpp> + +#include <exceptions/exceptions.h> + +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { + +/// \brief \c rdata::DSLikeImpl class represents the DS-like RDATA for DS +/// and DLV types. +/// +/// This class implements the basic interfaces inherited by the DS and DLV +/// classes from the abstract \c rdata::Rdata class, and provides trivial +/// accessors to DS-like RDATA. +template <class Type, uint16_t typeCode> class DSLikeImpl { + // Common sequence of toWire() operations used for the two versions of + // toWire(). + template <typename Output> + void + toWireCommon(Output& output) const { + output.writeUint16(tag_); + output.writeUint8(algorithm_); + output.writeUint8(digest_type_); + output.writeData(&digest_[0], digest_.size()); + } + +public: + /// \brief Constructor from string. + /// + /// The given string must represent a valid DS-like 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 tag field must be a valid decimal representation of an + /// unsigned 16-bit integer. The protocol and algorithm fields must + /// be valid decimal representations of unsigned 8-bit integers + /// respectively. The digest field may contain whitespace. + /// + /// \throw InvalidRdataText if any fields are out of their valid range. + /// + /// \param ds_str A string containing the RDATA to be created + DSLikeImpl(const std::string& ds_str) { + try { + std::istringstream ss(ds_str); + MasterLexer lexer; + lexer.pushSource(ss); + + constructFromLexer(lexer); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Extra input text for " << RRType(typeCode) << ": " + << ds_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct " << RRType(typeCode) << " from '" << + ds_str << "': " << ex.what()); + } + } + + /// \brief Constructor with a context of MasterLexer. + /// + /// The \c lexer should point to the beginning of valid textual + /// representation of a DS-like RDATA. + /// + /// The tag field must be a valid decimal representation of an + /// unsigned 16-bit integer. The protocol and algorithm fields must + /// be valid decimal representations of unsigned 8-bit integers + /// respectively. + /// + /// \throw MasterLexer::LexerError General parsing error such as + /// missing field. + /// \throw InvalidRdataText if any fields are out of their valid range. + /// + /// \param lexer A \c MasterLexer object parsing a master file for the + /// RDATA to be created + DSLikeImpl(MasterLexer& lexer, const Name*, MasterLoader::Options, + MasterLoaderCallbacks&) + { + constructFromLexer(lexer); + } + +private: + void constructFromLexer(MasterLexer& lexer) { + const uint32_t tag = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (tag > 0xffff) { + isc_throw(InvalidRdataText, + "Invalid " << RRType(typeCode) << " tag: " << tag); + } + + const uint32_t algorithm = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (algorithm > 0xff) { + isc_throw(InvalidRdataText, + "Invalid " << RRType(typeCode) << " algorithm: " + << algorithm); + } + + const uint32_t digest_type = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (digest_type > 0xff) { + isc_throw(InvalidRdataText, + "Invalid " << RRType(typeCode) << " digest type: " + << digest_type); + } + + std::string digest; + while (true) { + const MasterToken& token = lexer.getNextToken(); + if (token.getType() != MasterToken::STRING) { + break; + } + digest.append(token.getString()); + } + + lexer.ungetToken(); + + if (digest.size() == 0) { + isc_throw(InvalidRdataText, + "Missing " << RRType(typeCode) << " digest"); + } + + tag_ = tag; + algorithm_ = algorithm; + digest_type_ = digest_type; + decodeHex(digest, digest_); + } + +public: + /// \brief Constructor from wire-format data. + /// + /// \param buffer A buffer storing the wire format data. + /// \param rdata_len The length of the RDATA in bytes, normally expected + /// to be the value of the RDLENGTH field of the corresponding RR. + /// + /// <b>Exceptions</b> + /// + /// \c InvalidRdataLength is thrown if the input data is too short for the + /// type. + DSLikeImpl(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len < 4) { + isc_throw(InvalidRdataLength, RRType(typeCode) << " too short"); + } + + tag_ = buffer.readUint16(); + algorithm_ = buffer.readUint8(); + digest_type_ = buffer.readUint8(); + + rdata_len -= 4; + digest_.resize(rdata_len); + buffer.readData(&digest_[0], rdata_len); + } + + /// \brief The copy constructor. + /// + /// Trivial for now, we could've used the default one. + DSLikeImpl(const DSLikeImpl& source) : + tag_(source.tag_), + algorithm_(source.algorithm_), + digest_type_(source.digest_type_), + digest_(source.digest_) + {} + + /// \brief Convert the DS-like data to a string. + /// + /// \return A \c string object that represents the DS-like data. + std::string + toText() const { + using namespace boost; + return (lexical_cast<string>(static_cast<int>(tag_)) + + " " + lexical_cast<string>(static_cast<int>(algorithm_)) + + " " + lexical_cast<string>(static_cast<int>(digest_type_)) + + " " + encodeHex(digest_)); + } + + /// \brief Render the DS-like data in the wire format to an OutputBuffer + /// object. + /// + /// \param buffer An output buffer to store the wire data. + void + toWire(OutputBuffer& buffer) const { + toWireCommon(buffer); + } + + /// \brief Render the DS-like data in the wire format to an + /// AbstractMessageRenderer object. + /// + /// \param renderer A renderer object to send the wire data to. + void + toWire(AbstractMessageRenderer& renderer) const { + toWireCommon(renderer); + } + + /// \brief Compare two instances of DS-like RDATA. + /// + /// It is up to the caller to make sure that \c other is an object of the + /// same \c DSLikeImpl class. + /// + /// \param other the right-hand operand to compare against. + /// \return < 0 if \c this would be sorted before \c other. + /// \return 0 if \c this is identical to \c other in terms of sorting + /// order. + /// \return > 0 if \c this would be sorted after \c other. + int + compare(const DSLikeImpl& other_ds) const { + if (tag_ != other_ds.tag_) { + return (tag_ < other_ds.tag_ ? -1 : 1); + } + if (algorithm_ != other_ds.algorithm_) { + return (algorithm_ < other_ds.algorithm_ ? -1 : 1); + } + if (digest_type_ != other_ds.digest_type_) { + return (digest_type_ < other_ds.digest_type_ ? -1 : 1); + } + + size_t this_len = digest_.size(); + size_t other_len = other_ds.digest_.size(); + size_t cmplen = min(this_len, other_len); + int cmp = memcmp(&digest_[0], &other_ds.digest_[0], cmplen); + if (cmp != 0) { + return (cmp); + } else { + return ((this_len == other_len) + ? 0 : (this_len < other_len) ? -1 : 1); + } + } + + /// \brief Accessors + uint16_t + getTag() const { + return (tag_); + } + +private: + // straightforward representation of DS RDATA fields + uint16_t tag_; + uint8_t algorithm_; + uint8_t digest_type_; + std::vector<uint8_t> digest_; +}; + +} +} +} +} +} +#endif // DS_LIKE_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/detail/lexer_util.h b/src/lib/dns/rdata/generic/detail/lexer_util.h new file mode 100644 index 0000000..29b6c31 --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/lexer_util.h @@ -0,0 +1,62 @@ +// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DNS_RDATA_LEXER_UTIL_H +#define DNS_RDATA_LEXER_UTIL_H 1 + +#include <dns/name.h> +#include <dns/master_lexer.h> + +/// \file lexer_util.h +/// \brief Utilities for extracting RDATA fields from lexer. +/// +/// This file intends to define convenient small routines that can be +/// commonly used in the RDATA implementation to build RDATA fields from +/// a \c MasterLexer. + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { + +/// \brief Construct a Name object using a master lexer and optional origin. +/// +/// This is a convenient shortcut of commonly used code pattern that would +/// be used to build RDATA that contain a domain name field. +/// +/// Note that this function throws an exception against invalid input. +/// The (direct or indirect) caller's responsibility needs to expect and +/// handle exceptions appropriately. +/// +/// \throw MasterLexer::LexerError The next token from lexer is not string. +/// \throw Other Exceptions from the \c Name class constructor if the next +/// string token from the lexer does not represent a valid name. +/// +/// \param lexer A \c MasterLexer object. Its next token is expected to be +/// a string that represent a domain name. +/// \param origin If non NULL, specifies the origin of the name to be +/// constructed. +/// +/// \return A new Name object that corresponds to the next string token of +/// the \c lexer. +inline Name +createNameFromLexer(MasterLexer& lexer, const Name* origin) { + const MasterToken::StringRegion& str_region = + lexer.getNextToken(MasterToken::STRING).getStringRegion(); + return (Name(str_region.beg, str_region.len, origin)); +} + +} // namespace detail +} // namespace generic +} // namespace rdata +} // namespace dns +} // namespace isc +#endif // DNS_RDATA_LEXER_UTIL_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/detail/nsec3param_common.cc b/src/lib/dns/rdata/generic/detail/nsec3param_common.cc new file mode 100644 index 0000000..efe488a --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/nsec3param_common.cc @@ -0,0 +1,115 @@ +// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> + +#include <util/encode/hex.h> +#include <util/buffer.h> + +#include <dns/exceptions.h> +#include <dns/rdata.h> +#include <dns/rdata/generic/detail/nsec3param_common.h> + +#include <boost/lexical_cast.hpp> + +#include <sstream> +#include <vector> +#include <stdint.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { +namespace nsec3 { + +ParseNSEC3ParamResult +parseNSEC3ParamFromLexer(const char* const rrtype_name, + MasterLexer& lexer, vector<uint8_t>& salt) +{ + const uint32_t hashalg = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (hashalg > 0xff) { + isc_throw(InvalidRdataText, rrtype_name << + " hash algorithm out of range: " << hashalg); + } + + const uint32_t flags = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (flags > 0xff) { + isc_throw(InvalidRdataText, rrtype_name << " flags out of range: " << + flags); + } + + const uint32_t iterations = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (iterations > 0xffff) { + isc_throw(InvalidRdataText, rrtype_name << + " iterations out of range: " << iterations); + } + + const string salthex = + lexer.getNextToken(MasterToken::STRING).getString(); + + // Salt is up to 255 bytes, and space is not allowed in the HEX encoding, + // so the encoded string cannot be longer than the double of max length + // of the actual salt. + if (salthex.size() > 255 * 2) { + isc_throw(InvalidRdataText, rrtype_name << " salt is too long: " + << salthex.size() << " (encoded) bytes"); + } + if (salthex != "-") { // "-" means a 0-length salt + decodeHex(salthex, salt); + } + + return (ParseNSEC3ParamResult(hashalg, flags, iterations)); +} + +ParseNSEC3ParamResult +parseNSEC3ParamWire(const char* const rrtype_name, + InputBuffer& buffer, + size_t& rdata_len, std::vector<uint8_t>& salt) +{ + // NSEC3/NSEC3PARAM RR must have at least 5 octets: + // hash algorithm(1), flags(1), iteration(2), saltlen(1) + if (rdata_len < 5) { + isc_throw(DNSMessageFORMERR, rrtype_name << " too short, length: " + << rdata_len); + } + + const uint8_t hashalg = buffer.readUint8(); + const uint8_t flags = buffer.readUint8(); + const uint16_t iterations = buffer.readUint16(); + + const uint8_t saltlen = buffer.readUint8(); + rdata_len -= 5; + if (rdata_len < saltlen) { + isc_throw(DNSMessageFORMERR, rrtype_name << + " salt length is too large: " << + static_cast<unsigned int>(saltlen)); + } + + salt.resize(saltlen); + if (saltlen > 0) { + buffer.readData(&salt[0], saltlen); + rdata_len -= saltlen; + } + + return (ParseNSEC3ParamResult(hashalg, flags, iterations)); +} + +} // end of nsec3 +} // end of detail +} // end of generic +} // end of rdata +} // end of dns +} // end of isc diff --git a/src/lib/dns/rdata/generic/detail/nsec3param_common.h b/src/lib/dns/rdata/generic/detail/nsec3param_common.h new file mode 100644 index 0000000..89b2596 --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/nsec3param_common.h @@ -0,0 +1,123 @@ +// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef NSEC3PARAM_COMMON_H +#define NSEC3PARAM_COMMON_H 1 + +#include <dns/master_lexer.h> + +#include <util/buffer.h> + +#include <stdint.h> +#include <vector> + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { +namespace nsec3 { + +/// \file +/// +/// This helper module provides some utilities that handle NSEC3 and +/// NSEC3PARAM RDATA. They share the first few fields, and some operations +/// on these fields are sufficiently complicated, so it would make sense to +/// consolidate the processing logic into a single implementation module. +/// +/// The functions defined here are essentially private and are only expected +/// to be called from the \c NSEC3 and \c NSEC3PARAM class implementations. + +/// \brief Result values of the utilities. +/// +/// This structure encapsulates a tuple of NSEC3/NSEC3PARAM algorithm, +/// flags and iterations field values. This is used as the return value +/// of the utility functions defined in this module so the caller can +/// use it for constructing the corresponding RDATA. +struct ParseNSEC3ParamResult { + ParseNSEC3ParamResult(uint8_t param_algorithm, uint8_t param_flags, + uint16_t param_iterations) : + algorithm(param_algorithm), flags(param_flags), + iterations(param_iterations) + {} + const uint8_t algorithm; + const uint8_t flags; + const uint16_t iterations; +}; + +/// \brief Convert textual representation of NSEC3 parameters. +/// +/// This function takes an input MasterLexer that points at a complete +/// textual representation of an NSEC3 or NSEC3PARAM RDATA and parses it +/// extracting the hash algorithm, flags, iterations, and salt fields. +/// +/// The first three fields are returned as the return value of this function. +/// The salt will be stored in the given vector. The vector is expected +/// to be empty, but if not, the existing content will be overridden. +/// +/// On successful return the given MasterLexer will reach the end of the +/// salt field. +/// +/// \exception isc::BadValue The salt is not a valid hex string. +/// \exception InvalidRdataText The given RDATA is otherwise invalid for +/// NSEC3 or NSEC3PARAM fields. +/// \exception MasterLexer::LexerError There was a syntax error reading +/// a field from the MasterLexer. +/// +/// \param rrtype_name Either "NSEC3" or "NSEC3PARAM"; used as part of +/// exception messages. +/// \param lexer The MasterLexer to read NSEC3 parameter fields from. +/// \param salt A placeholder for the salt field value of the RDATA. +/// Expected to be empty, but it's not checked (and will be overridden). +/// +/// \return The hash algorithm, flags, iterations in the form of +/// ParseNSEC3ParamResult. +ParseNSEC3ParamResult parseNSEC3ParamFromLexer(const char* const rrtype_name, + isc::dns::MasterLexer& lexer, + std::vector<uint8_t>& salt); + +/// \brief Extract NSEC3 parameters from wire-format data. +/// +/// This function takes an input buffer that stores wire-format NSEC3 or +/// NSEC3PARAM RDATA and parses it extracting the hash algorithm, flags, +/// iterations, and salt fields. +/// +/// The first three fields are returned as the return value of this function. +/// The salt will be stored in the given vector. The vector is expected +/// to be empty, but if not, the existing content will be overridden. +/// +/// On successful return the input buffer will point to the end of the +/// salt field; rdata_len will be the length of the rest of RDATA +/// (in the case of a valid NSEC3PARAM, it should be 0). +/// +/// \exception DNSMessageFORMERR The wire data is invalid. +/// +/// \param rrtype_name Either "NSEC3" or "NSEC3PARAM"; used as part of +/// exception messages. +/// \param buffer An input buffer that stores wire-format RDATA. It must +/// point to the beginning of the data. +/// \param rdata_len The total length of the RDATA. +/// \param salt A placeholder for the salt field value of the RDATA. +/// Expected to be empty, but it's not checked (and will be overridden). +/// +/// \return The hash algorithm, flags, iterations in the form of +/// ParseNSEC3ParamResult. +ParseNSEC3ParamResult parseNSEC3ParamWire(const char* const rrtype_name, + isc::util::InputBuffer& buffer, + size_t& rdata_len, + std::vector<uint8_t>& salt); +} +} +} +} +} +} + +#endif // NSEC3PARAM_COMMON_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/detail/nsec_bitmap.cc b/src/lib/dns/rdata/generic/detail/nsec_bitmap.cc new file mode 100644 index 0000000..d02c11d --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/nsec_bitmap.cc @@ -0,0 +1,169 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> + +#include <dns/exceptions.h> +#include <dns/rdata.h> +#include <dns/rrtype.h> + +#include <cassert> +#include <sstream> +#include <vector> +#include <cstring> +#include <stdint.h> + +using namespace std; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { +namespace nsec { +void +checkRRTypeBitmaps(const char* const rrtype_name, + const vector<uint8_t>& typebits) +{ + bool first = true; + unsigned int lastblock = 0; + const size_t total_len = typebits.size(); + size_t i = 0; + + while (i < total_len) { + if (i + 2 > total_len) { + isc_throw(DNSMessageFORMERR, rrtype_name << + " RDATA from wire: incomplete bit map field"); + } + const unsigned int block = typebits[i]; + const size_t len = typebits[i + 1]; + // Check that bitmap window blocks are in the correct order. + if (!first && block <= lastblock) { + isc_throw(DNSMessageFORMERR, rrtype_name << + " RDATA from wire: Disordered window blocks found: " + << lastblock << " then " << block); + } + // Check for legal length + if (len < 1 || len > 32) { + isc_throw(DNSMessageFORMERR, rrtype_name << + " RDATA from wire: Invalid bitmap length: " << len); + } + // Check for overflow. + i += 2; + if (i + len > total_len) { + isc_throw(DNSMessageFORMERR, rrtype_name << + " RDATA from wire: bitmap length too large: " << len); + } + // The last octet of the bitmap must be non zero. + if (typebits[i + len - 1] == 0) { + isc_throw(DNSMessageFORMERR, rrtype_name << + " RDATA from wire: bitmap ending an all-zero byte"); + } + + i += len; + lastblock = block; + first = false; + } +} + +void +buildBitmapsFromLexer(const char* const rrtype_name, + MasterLexer& lexer, vector<uint8_t>& typebits, + bool allow_empty) +{ + uint8_t bitmap[8 * 1024]; // 64k bits + memset(bitmap, 0, sizeof(bitmap)); + + bool have_rrtypes = false; + std::string type_str; + 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 is now assured to be of type STRING. + + have_rrtypes = true; + token.getString(type_str); + try { + const int code = RRType(type_str).getCode(); + bitmap[code / 8] |= (0x80 >> (code % 8)); + } catch (const InvalidRRType&) { + isc_throw(InvalidRdataText, "Invalid RRtype in " + << rrtype_name << " bitmap: " << type_str); + } + } + + lexer.ungetToken(); + + if (!have_rrtypes) { + if (allow_empty) { + return; + } + isc_throw(InvalidRdataText, + rrtype_name << + " record does not end with RR type mnemonic"); + } + + for (int window = 0; window < 256; ++window) { + int octet; + for (octet = 31; octet >= 0; octet--) { + if (bitmap[window * 32 + octet] != 0) { + break; + } + } + if (octet < 0) { + continue; + } + typebits.push_back(window); + typebits.push_back(octet + 1); + for (int i = 0; i <= octet; ++i) { + typebits.push_back(bitmap[window * 32 + i]); + } + } +} + +void +bitmapsToText(const vector<uint8_t>& typebits, ostringstream& oss) { + // In the following loop we use string::at() rather than operator[]. + // Since the index calculation is a bit complicated, it will be safer + // and easier to find a bug (if any). Note that this conversion method + // is generally not expected to be very efficient, so the slight overhead + // of at() should be acceptable. + const size_t typebits_len = typebits.size(); + size_t len = 0; + for (size_t i = 0; i < typebits_len; i += len) { + assert(i + 2 <= typebits.size()); + const unsigned int block = typebits.at(i); + len = typebits.at(i + 1); + assert(len > 0 && len <= 32); + i += 2; + for (size_t j = 0; j < len; ++j) { + if (typebits.at(i + j) == 0) { + continue; + } + for (size_t k = 0; k < 8; ++k) { + if ((typebits.at(i + j) & (0x80 >> k)) == 0) { + continue; + } + const unsigned int t = block * 256 + j * 8 + k; + assert(t < 65536); + oss << " " << RRType(t); + } + } + } +} +} +} +} +} +} +} diff --git a/src/lib/dns/rdata/generic/detail/nsec_bitmap.h b/src/lib/dns/rdata/generic/detail/nsec_bitmap.h new file mode 100644 index 0000000..4e073a0 --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/nsec_bitmap.h @@ -0,0 +1,103 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef NSECBITMAP_H +#define NSECBITMAP_H 1 + +#include <dns/master_lexer.h> + +#include <stdint.h> + +#include <sstream> +#include <vector> + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { +namespace nsec { + +/// \file +/// +/// This helper module provides some utilities that handle NSEC and NSEC3 +/// type bitmaps. The format and processing of the type bitmaps are generally +/// the same for these two RRs, so it would make sense to consolidate +/// the processing logic into a single implementation module. +/// +/// The functions defined here are essentially private and are only expected +/// to be called from the \c NSEC and \c NSEC3 class implementations. + +/// \brief Check if a given "type bitmap" for NSEC/NSEC3 is valid. +/// +/// This function checks given wire format data (stored in a +/// \c std::vector) is a valid type bitmaps used for the NSEC and NSEC3 RRs +/// according to RFC4034 and RFC5155. +/// +/// \exception DNSMessageFORMERR The bitmap is not valid. +/// +/// \param rrtype_name Either "NSEC" or "NSEC3"; used as part of exception +/// messages. +/// \param typebits The type bitmaps in wire format. The size of vector +/// is the total length of the bitmaps. +void checkRRTypeBitmaps(const char* const rrtype_name, + const std::vector<uint8_t>& typebits); + +/// \brief Convert textual sequence of RR types read from a lexer into +/// type bitmaps. +/// +/// See the other variant above for description. If \c allow_empty is +/// true and there are no mnemonics, \c typebits is left untouched. +/// +/// \exception InvalidRdataText Data read from the given lexer does not +/// meet the assumption (e.g. including invalid form of RR type, not +/// ending with an RR type string). +/// +/// \param rrtype_name Either "NSEC" or "NSEC3"; used as part of exception +/// messages. +/// \param lexer MasterLexer that provides consists of a complete +/// sequence of textual lexemes of RR types for which the corresponding +/// bits are set. +/// \param typebits A placeholder for the resulting bitmaps. Expected to be +/// empty, but it's not checked. +/// \param allow_empty If true, the function simply returns if no RR +/// type mnemonics are found. Otherwise, it throws an exception if no RR +/// type mnemonics are found. +void buildBitmapsFromLexer(const char* const rrtype_name, + isc::dns::MasterLexer& lexer, + std::vector<uint8_t>& typebits, + bool allow_empty = false); + +/// \brief Convert type bitmaps to textual sequence of RR types. +/// +/// This function converts wire-format data of type bitmaps for NSEC/NSEC3 +/// into a sequence of corresponding RR type strings, and inserts them +/// into the given output stream with separating them by a single space +/// character. +/// +/// This function assumes the given bitmaps are valid in terms of RFC4034 +/// and RFC5155 (in practice, it assumes it's from a validly constructed +/// NSEC or NSEC3 object); if it detects a format error, it aborts the +/// program with assert(). +/// +/// \param typebits The type bitmaps in wire format. The size of vector +/// is the total length of the bitmaps. +/// \param oss The output stream to which the converted RR type sequence +/// are to be inserted. +void bitmapsToText(const std::vector<uint8_t>& typebits, + std::ostringstream& oss); +} +} +} +} +} +} + +#endif // NSECBITMAP_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/detail/txt_like.h b/src/lib/dns/rdata/generic/detail/txt_like.h new file mode 100644 index 0000000..5801b09 --- /dev/null +++ b/src/lib/dns/rdata/generic/detail/txt_like.h @@ -0,0 +1,237 @@ +// Copyright (C) 2011-2015,2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef TXT_LIKE_H +#define TXT_LIKE_H 1 + +#include <dns/master_lexer.h> +#include <dns/rdata/generic/detail/char_string.h> + +#include <stdint.h> + +#include <string> +#include <sstream> +#include <vector> + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { +namespace detail { + +/// \brief \c rdata::TXTLikeImpl class represents the TXT-like RDATA for TXT +/// and SPF types. +/// +/// This class implements the basic interfaces inherited by the TXT and SPF +/// classes from the abstract \c rdata::Rdata class, and provides trivial +/// accessors to TXT-like RDATA. +template<class Type, uint16_t typeCode>class TXTLikeImpl { +public: + /// \brief Constructor from wire-format data. + /// + /// \param buffer A buffer storing the wire format data. + /// \param rdata_len The length of the RDATA in bytes, normally expected + /// to be the value of the RDLENGTH field of the corresponding RR. + /// + /// <b>Exceptions</b> + /// + /// \c InvalidRdataLength is thrown if rdata_len exceeds the maximum. + /// \c DNSMessageFORMERR is thrown if the RR is malformed. + TXTLikeImpl(util::InputBuffer& buffer, size_t rdata_len) { + if (rdata_len > MAX_RDLENGTH) { + isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len); + } + + if (rdata_len == 0) { // note that this couldn't happen in the loop. + isc_throw(DNSMessageFORMERR, "Error in parsing " << + RRType(typeCode) << " RDATA: 0-length character string"); + } + + do { + const uint8_t len = buffer.readUint8(); + if (rdata_len < len + 1) { + isc_throw(DNSMessageFORMERR, "Error in parsing " << + RRType(typeCode) << + " RDATA: character string length is too large: " << + static_cast<int>(len)); + } + std::vector<uint8_t> data(len + 1); + data[0] = len; + buffer.readData(&data[0] + 1, len); + string_list_.push_back(data); + + rdata_len -= (len + 1); + } while (rdata_len > 0); + } + + /// \brief Constructor from string. + /// + /// \throw CharStringTooLong the parameter string length exceeds maximum. + /// \throw InvalidRdataText the method cannot process the parameter data + explicit TXTLikeImpl(const std::string& txtstr) { + std::istringstream ss(txtstr); + MasterLexer lexer; + lexer.pushSource(ss); + + try { + buildFromTextHelper(lexer); + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "Failed to construct " << + RRType(typeCode) << " RDATA from '" << txtstr << + "': extra new line"); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct " << + RRType(typeCode) << " RDATA from '" << txtstr << "': " + << ex.what()); + } + } + + /// \brief Constructor using the master lexer. + /// + /// \throw CharStringTooLong the parameter string length exceeds maximum. + /// \throw InvalidRdataText the method cannot process the parameter data + /// + /// \param lexer A \c MasterLexer object parsing a master file for this + /// RDATA. + TXTLikeImpl(MasterLexer& lexer) { + buildFromTextHelper(lexer); + } + +private: + void buildFromTextHelper(MasterLexer& lexer) { + while (true) { + const MasterToken& token = lexer.getNextToken( + MasterToken::QSTRING, true); + if (token.getType() != MasterToken::STRING && + token.getType() != MasterToken::QSTRING) { + break; + } + string_list_.push_back(std::vector<uint8_t>()); + stringToCharString(token.getStringRegion(), string_list_.back()); + } + + // Let upper layer handle eol/eof. + lexer.ungetToken(); + + if (string_list_.empty()) { + isc_throw(InvalidRdataText, "Failed to construct " << + RRType(typeCode) << " RDATA: empty input"); + } + } + +public: + /// \brief The copy constructor. + /// + /// Trivial for now, we could've used the default one. + TXTLikeImpl(const TXTLikeImpl& other) : + string_list_(other.string_list_) + {} + + /// \brief Render the TXT-like data in the wire format to an OutputBuffer + /// object. + /// + /// \param buffer An output buffer to store the wire data. + void + toWire(util::OutputBuffer& buffer) const { + for (std::vector<std::vector<uint8_t> >::const_iterator it = + string_list_.begin(); + it != string_list_.end(); + ++it) + { + buffer.writeData(&(*it)[0], (*it).size()); + } + } + + /// \brief Render the TXT-like data in the wire format to an + /// AbstractMessageRenderer object. + /// + /// \param buffer An output AbstractMessageRenderer to send the wire data + /// to. + void + toWire(AbstractMessageRenderer& renderer) const { + for (std::vector<std::vector<uint8_t> >::const_iterator it = + string_list_.begin(); + it != string_list_.end(); + ++it) + { + renderer.writeData(&(*it)[0], (*it).size()); + } + } + + /// \brief Convert the TXT-like data to a string. + /// + /// \return A \c string object that represents the TXT-like data. + std::string + toText() const { + std::string s; + + for (std::vector<std::vector<uint8_t> >::const_iterator it = + string_list_.begin(); it != string_list_.end(); ++it) + { + if (!s.empty()) { + s.push_back(' '); + } + s.push_back('"'); + s.append(charStringToString(*it)); + s.push_back('"'); + } + + return (s); + } + + /// \brief Compare two instances of TXT-like RDATA. + /// + /// It is up to the caller to make sure that \c other is an object of the + /// same \c TXTLikeImpl class. + /// + /// \param other the right-hand operand to compare against. + /// \return < 0 if \c this would be sorted before \c other. + /// \return 0 if \c this is identical to \c other in terms of sorting + /// order. + /// \return > 0 if \c this would be sorted after \c other. + int + compare(const TXTLikeImpl& other) const { + // This implementation is not efficient. Revisit this (TBD). + OutputBuffer this_buffer(0); + toWire(this_buffer); + uint8_t const* const this_data = (uint8_t const*)this_buffer.getData(); + const size_t this_len = this_buffer.getLength(); + + OutputBuffer other_buffer(0); + other.toWire(other_buffer); + uint8_t const* const other_data + = (uint8_t const*)other_buffer.getData(); + const size_t other_len = other_buffer.getLength(); + + const size_t cmplen = min(this_len, other_len); + const int cmp = memcmp(this_data, other_data, cmplen); + + if (cmp != 0) { + return (cmp); + } else { + return ((this_len == other_len) ? 0 : + (this_len < other_len) ? -1 : 1); + } + } + +private: + /// Note: this is a prototype version; we may reconsider + /// this representation later. + std::vector<std::vector<uint8_t> > string_list_; +}; + +} // namespace detail +} // namespace generic +} // namespace rdata +} // namespace dns +} // namespace isc + +#endif // TXT_LIKE_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/dlv_32769.cc b/src/lib/dns/rdata/generic/dlv_32769.cc new file mode 100644 index 0000000..66303b7 --- /dev/null +++ b/src/lib/dns/rdata/generic/dlv_32769.cc @@ -0,0 +1,120 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#include <util/buffer.h> +#include <util/encode/hex.h> + +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +#include <dns/rdata/generic/detail/ds_like.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; +using namespace isc::dns::rdata::generic::detail; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// A copy of the implementation object is allocated and constructed. +DLV::DLV(const std::string& ds_str) : + impl_(new DLVImpl(ds_str)) +{} + +/// \brief Constructor from wire-format data. +/// +/// A copy of the implementation object is allocated and constructed. +DLV::DLV(InputBuffer& buffer, size_t rdata_len) : + impl_(new DLVImpl(buffer, rdata_len)) +{} + +DLV::DLV(MasterLexer& lexer, const Name* origin, MasterLoader::Options options, + MasterLoaderCallbacks& callbacks) : + impl_(new DLVImpl(lexer, origin, options, callbacks)) +{} + +/// \brief Copy constructor +/// +/// A copy of the implementation object is allocated and constructed. +DLV::DLV(const DLV& source) : + Rdata(), impl_(new DLVImpl(*source.impl_)) +{} + +/// \brief Assignment operator +/// +/// PIMPL-induced logic +DLV& +DLV::operator=(const DLV& source) { + if (this == &source) { + return (*this); + } + + DLVImpl* newimpl = new DLVImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +/// \brief Destructor +/// +/// Deallocates an internal resource. +DLV::~DLV() { + delete impl_; +} + +/// \brief Convert the \c DLV to a string. +/// +/// A pass-thru to the corresponding implementation method. +string +DLV::toText() const { + return (impl_->toText()); +} + +/// \brief Render the \c DLV in the wire format to a OutputBuffer object +/// +/// A pass-thru to the corresponding implementation method. +void +DLV::toWire(OutputBuffer& buffer) const { + impl_->toWire(buffer); +} + +/// \brief Render the \c DLV in the wire format to a AbstractMessageRenderer +/// object +/// +/// A pass-thru to the corresponding implementation method. +void +DLV::toWire(AbstractMessageRenderer& renderer) const { + impl_->toWire(renderer); +} + +/// \brief Compare two instances of \c DLV RDATA. +/// +/// The type check is performed here. Otherwise, a pass-thru to the +/// corresponding implementation method. +int +DLV::compare(const Rdata& other) const { + const DLV& other_ds = dynamic_cast<const DLV&>(other); + + return (impl_->compare(*other_ds.impl_)); +} + +/// \brief Tag accessor +uint16_t +DLV::getTag() const { + return (impl_->getTag()); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/dlv_32769.h b/src/lib/dns/rdata/generic/dlv_32769.h new file mode 100644 index 0000000..26523de --- /dev/null +++ b/src/lib/dns/rdata/generic/dlv_32769.h @@ -0,0 +1,69 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +namespace detail { +template <class Type, uint16_t typeCode> class DSLikeImpl; +} + +/// \brief \c rdata::generic::DLV class represents the DLV RDATA as defined in +/// RFC4431. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// DLV RDATA. +class DLV : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Assignment operator. + /// + /// It internally allocates a resource, and if it fails a corresponding + /// standard exception will be thrown. + /// This operator never throws an exception otherwise. + /// + /// This operator provides the strong exception guarantee: When an + /// exception is thrown the content of the assignment target will be + /// intact. + DLV& operator=(const DLV& source); + + /// \brief The destructor. + ~DLV(); + + /// \brief Return the value of the Tag field. + /// + /// This method never throws an exception. + uint16_t getTag() const; +private: + typedef detail::DSLikeImpl<DLV, 32769> DLVImpl; + DLVImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/dname_39.cc b/src/lib/dns/rdata/generic/dname_39.cc new file mode 100644 index 0000000..9ee669b --- /dev/null +++ b/src/lib/dns/rdata/generic/dname_39.cc @@ -0,0 +1,127 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#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/lexer_util.h> + +using namespace std; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// The given string must represent a valid DNAME 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 TARGET must be absolute since there's no parameter that specifies +/// the origin name; if it is not absolute, \c MissingNameOrigin +/// exception will be thrown. These must not be represented as a quoted +/// string. +/// +/// \throw Others Exception from the Name and RRTTL constructors. +/// \throw InvalidRdataText Other general syntax errors. +DNAME::DNAME(const std::string& namestr) : + // Fill in dummy name and replace it soon below. + dname_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(namestr); + MasterLexer lexer; + lexer.pushSource(ss); + + dname_ = createNameFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for DNAME: " + << namestr); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct DNAME from '" << + namestr << "': " << ex.what()); + } +} + +DNAME::DNAME(InputBuffer& buffer, size_t) : + dname_(buffer) +{ + // we don't need rdata_len for parsing. if necessary, the caller will + // check consistency. +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of a DNAME RDATA. The TARGET field can be +/// non-absolute if \c origin is non-NULL, in which case \c origin is +/// used to make it absolute. It must not be represented as a quoted +/// string. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of TARGET when it +/// is non-absolute. +DNAME::DNAME(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + dname_(createNameFromLexer(lexer, origin)) +{} + +DNAME::DNAME(const DNAME& other) : + Rdata(), dname_(other.dname_) +{} + +DNAME::DNAME(const Name& dname) : + dname_(dname) +{} + +void +DNAME::toWire(OutputBuffer& buffer) const { + dname_.toWire(buffer); +} + +void +DNAME::toWire(AbstractMessageRenderer& renderer) const { + // Type DNAME is not "well-known", and name compression must be disabled + // per RFC3597. + renderer.writeName(dname_, false); +} + +string +DNAME::toText() const { + return (dname_.toText()); +} + +int +DNAME::compare(const Rdata& other) const { + const DNAME& other_dname = dynamic_cast<const DNAME&>(other); + + return (compareNames(dname_, other_dname.dname_)); +} + +const Name& +DNAME::getDname() const { + return (dname_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/dname_39.h b/src/lib/dns/rdata/generic/dname_39.h new file mode 100644 index 0000000..998fea0 --- /dev/null +++ b/src/lib/dns/rdata/generic/dname_39.h @@ -0,0 +1,39 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class DNAME : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + // DNAME specific methods + DNAME(const Name& dname); + const Name& getDname() const; +private: + Name dname_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/dnskey_48.cc b/src/lib/dns/rdata/generic/dnskey_48.cc new file mode 100644 index 0000000..7bea847 --- /dev/null +++ b/src/lib/dns/rdata/generic/dnskey_48.cc @@ -0,0 +1,316 @@ +// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <iostream> +#include <string> +#include <sstream> +#include <vector> + +#include <boost/lexical_cast.hpp> +#include <boost/foreach.hpp> + +#include <util/encode/base64.h> +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +#include <memory> + +#include <stdio.h> +#include <time.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct DNSKEYImpl { + // straightforward representation of DNSKEY RDATA fields + DNSKEYImpl(uint16_t flags, uint8_t protocol, uint8_t algorithm, + const vector<uint8_t>& keydata) : + flags_(flags), protocol_(protocol), algorithm_(algorithm), + keydata_(keydata) + {} + + uint16_t flags_; + uint8_t protocol_; + uint8_t algorithm_; + const vector<uint8_t> keydata_; +}; + +/// \brief Constructor from string. +/// +/// The given string must represent a valid DNSKEY 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 Protocol and Algorithm fields must be within their valid +/// ranges. The Public Key field must be present and must contain a +/// Base64 encoding of the public key. Whitespace is allowed within the +/// Base64 text. +/// +/// It is okay for the key data to be missing. Note: BIND 9 also accepts +/// DNSKEY missing key data. While the RFC is silent in this case, and it +/// may be debatable what an implementation should do, but since this field +/// is algorithm dependent and this implementations doesn't reject unknown +/// algorithms, it's lenient here. +/// +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param dnskey_str A string containing the RDATA to be created +DNSKEY::DNSKEY(const std::string& dnskey_str) : + impl_(NULL) +{ + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the DNSKEYImpl that constructFromLexer() returns. + std::unique_ptr<DNSKEYImpl> impl_ptr; + + try { + std::istringstream ss(dnskey_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 DNSKEY: " << dnskey_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct DNSKEY from '" << dnskey_str << "': " + << ex.what()); + } + + impl_ = impl_ptr.release(); +} + +/// \brief Constructor from InputBuffer. +/// +/// The passed buffer must contain a valid DNSKEY RDATA. +/// +/// The Protocol and Algorithm fields are not checked for unknown +/// values. It is okay for the key data to be missing (see the description +/// of the constructor from string). +DNSKEY::DNSKEY(InputBuffer& buffer, size_t rdata_len) : + impl_(NULL) +{ + if (rdata_len < 4) { + isc_throw(InvalidRdataLength, "DNSKEY too short: " << rdata_len); + } + + const uint16_t flags = buffer.readUint16(); + const uint16_t protocol = buffer.readUint8(); + const uint16_t algorithm = buffer.readUint8(); + + rdata_len -= 4; + + vector<uint8_t> keydata; + // If key data is missing, it's OK. See the API documentation of the + // constructor. + if (rdata_len > 0) { + keydata.resize(rdata_len); + buffer.readData(&keydata[0], rdata_len); + } + + impl_ = new DNSKEYImpl(flags, protocol, algorithm, keydata); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of an DNSKEY RDATA. +/// +/// See \c DNSKEY::DNSKEY(const std::string&) for description of the +/// expected RDATA fields. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +DNSKEY::DNSKEY(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(NULL) +{ + impl_ = constructFromLexer(lexer); +} + +DNSKEYImpl* +DNSKEY::constructFromLexer(MasterLexer& lexer) { + const uint32_t flags = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (flags > 0xffff) { + isc_throw(InvalidRdataText, + "DNSKEY flags out of range: " << flags); + } + + const uint32_t protocol = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (protocol > 0xff) { + isc_throw(InvalidRdataText, + "DNSKEY protocol out of range: " << protocol); + } + + const uint32_t algorithm = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (algorithm > 0xff) { + isc_throw(InvalidRdataText, + "DNSKEY algorithm out of range: " << algorithm); + } + + std::string keydata_str; + std::string keydata_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 is now assured to be of type STRING. + + token.getString(keydata_substr); + keydata_str.append(keydata_substr); + } + + lexer.ungetToken(); + + vector<uint8_t> keydata; + // If key data is missing, it's OK. See the API documentation of the + // constructor. + if (keydata_str.size() > 0) { + decodeBase64(keydata_str, keydata); + } + + return (new DNSKEYImpl(flags, protocol, algorithm, keydata)); +} + +DNSKEY::DNSKEY(const DNSKEY& source) : + Rdata(), impl_(new DNSKEYImpl(*source.impl_)) +{} + +DNSKEY& +DNSKEY::operator=(const DNSKEY& source) { + if (this == &source) { + return (*this); + } + + DNSKEYImpl* newimpl = new DNSKEYImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +DNSKEY::~DNSKEY() { + delete impl_; +} + +string +DNSKEY::toText() const { + return (boost::lexical_cast<string>(static_cast<int>(impl_->flags_)) + + " " + boost::lexical_cast<string>(static_cast<int>(impl_->protocol_)) + + " " + boost::lexical_cast<string>(static_cast<int>(impl_->algorithm_)) + + " " + encodeBase64(impl_->keydata_)); +} + +void +DNSKEY::toWire(OutputBuffer& buffer) const { + buffer.writeUint16(impl_->flags_); + buffer.writeUint8(impl_->protocol_); + buffer.writeUint8(impl_->algorithm_); + buffer.writeData(&impl_->keydata_[0], impl_->keydata_.size()); +} + +void +DNSKEY::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeUint16(impl_->flags_); + renderer.writeUint8(impl_->protocol_); + renderer.writeUint8(impl_->algorithm_); + renderer.writeData(&impl_->keydata_[0], impl_->keydata_.size()); +} + +int +DNSKEY::compare(const Rdata& other) const { + const DNSKEY& other_dnskey = dynamic_cast<const DNSKEY&>(other); + + if (impl_->flags_ != other_dnskey.impl_->flags_) { + return (impl_->flags_ < other_dnskey.impl_->flags_ ? -1 : 1); + } + if (impl_->protocol_ != other_dnskey.impl_->protocol_) { + return (impl_->protocol_ < other_dnskey.impl_->protocol_ ? -1 : 1); + } + if (impl_->algorithm_ != other_dnskey.impl_->algorithm_) { + return (impl_->algorithm_ < other_dnskey.impl_->algorithm_ ? -1 : 1); + } + + const size_t this_len = impl_->keydata_.size(); + const size_t other_len = other_dnskey.impl_->keydata_.size(); + const size_t cmplen = min(this_len, other_len); + if (cmplen == 0) { + return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1); + } + const int cmp = memcmp(&impl_->keydata_[0], + &other_dnskey.impl_->keydata_[0], cmplen); + if (cmp != 0) { + return (cmp); + } else { + return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1); + } +} + +uint16_t +DNSKEY::getTag() const { + if (impl_->algorithm_ == 1) { + // See RFC 4034 appendix B.1 for why the key data must contain + // at least 4 bytes with RSA/MD5: 3 trailing bytes to extract + // the tag from, and 1 byte of exponent length subfield before + // modulus. + const int len = impl_->keydata_.size(); + if (len < 4) { + isc_throw(isc::OutOfRange, + "DNSKEY keydata too short for tag extraction"); + } + + return ((impl_->keydata_[len - 3] << 8) + impl_->keydata_[len - 2]); + } + + uint32_t ac = impl_->flags_; + ac += (impl_->protocol_ << 8); + ac += impl_->algorithm_; + + const size_t size = impl_->keydata_.size(); + for (size_t i = 0; i < size; i ++) { + ac += (i & 1) ? impl_->keydata_[i] : (impl_->keydata_[i] << 8); + } + ac += (ac >> 16) & 0xffff; + return (ac & 0xffff); +} + +uint16_t +DNSKEY::getFlags() const { + return (impl_->flags_); +} + +uint8_t +DNSKEY::getAlgorithm() const { + return (impl_->algorithm_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/dnskey_48.h b/src/lib/dns/rdata/generic/dnskey_48.h new file mode 100644 index 0000000..a5e9efa --- /dev/null +++ b/src/lib/dns/rdata/generic/dnskey_48.h @@ -0,0 +1,60 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> +#include <dns/master_lexer.h> + +// BEGIN_HEADER_GUARD + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct DNSKEYImpl; + +class DNSKEY : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + DNSKEY& operator=(const DNSKEY& source); + ~DNSKEY(); + + /// + /// Specialized methods + /// + + /// \brief Returns the key tag + /// + /// \throw isc::OutOfRange if the key data for RSA/MD5 is too short + /// to support tag extraction. + uint16_t getTag() const; + + uint16_t getFlags() const; + uint8_t getAlgorithm() const; + +private: + DNSKEYImpl* constructFromLexer(isc::dns::MasterLexer& lexer); + + DNSKEYImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/ds_43.cc b/src/lib/dns/rdata/generic/ds_43.cc new file mode 100644 index 0000000..48c421c --- /dev/null +++ b/src/lib/dns/rdata/generic/ds_43.cc @@ -0,0 +1,90 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#include <util/buffer.h> +#include <util/encode/hex.h> + +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +#include <dns/rdata/generic/detail/ds_like.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; +using namespace isc::dns::rdata::generic::detail; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +DS::DS(const std::string& ds_str) : + impl_(new DSImpl(ds_str)) +{} + +DS::DS(InputBuffer& buffer, size_t rdata_len) : + impl_(new DSImpl(buffer, rdata_len)) +{} + +DS::DS(MasterLexer& lexer, const Name* origin, MasterLoader::Options options, + MasterLoaderCallbacks& callbacks) : + impl_(new DSImpl(lexer, origin, options, callbacks)) +{} + +DS::DS(const DS& source) : + Rdata(), impl_(new DSImpl(*source.impl_)) +{} + +DS& +DS::operator=(const DS& source) { + if (this == &source) { + return (*this); + } + + DSImpl* newimpl = new DSImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +DS::~DS() { + delete impl_; +} + +string +DS::toText() const { + return (impl_->toText()); +} + +void +DS::toWire(OutputBuffer& buffer) const { + impl_->toWire(buffer); +} + +void +DS::toWire(AbstractMessageRenderer& renderer) const { + impl_->toWire(renderer); +} + +int +DS::compare(const Rdata& other) const { + const DS& other_ds = dynamic_cast<const DS&>(other); + + return (impl_->compare(*other_ds.impl_)); +} + +uint16_t +DS::getTag() const { + return (impl_->getTag()); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/ds_43.h b/src/lib/dns/rdata/generic/ds_43.h new file mode 100644 index 0000000..a20e349 --- /dev/null +++ b/src/lib/dns/rdata/generic/ds_43.h @@ -0,0 +1,69 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +namespace detail { +template <class Type, uint16_t typeCode> class DSLikeImpl; +} + +/// \brief \c rdata::generic::DS class represents the DS RDATA as defined in +/// RFC3658. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// DS RDATA. +class DS : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Assignment operator. + /// + /// It internally allocates a resource, and if it fails a corresponding + /// standard exception will be thrown. + /// This operator never throws an exception otherwise. + /// + /// This operator provides the strong exception guarantee: When an + /// exception is thrown the content of the assignment target will be + /// intact. + DS& operator=(const DS& source); + + /// \brief The destructor. + ~DS(); + + /// \brief Return the value of the Tag field. + /// + /// This method never throws an exception. + uint16_t getTag() const; +private: + typedef detail::DSLikeImpl<DS, 43> DSImpl; + DSImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/hinfo_13.cc b/src/lib/dns/rdata/generic/hinfo_13.cc new file mode 100644 index 0000000..3bda219 --- /dev/null +++ b/src/lib/dns/rdata/generic/hinfo_13.cc @@ -0,0 +1,151 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> +#include <dns/exceptions.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/char_string.h> +#include <util/buffer.h> + +using namespace std; +using namespace isc::util; +using namespace isc::dns; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +class HINFOImpl { +public: + HINFOImpl(const std::string& hinfo_str) { + std::istringstream ss(hinfo_str); + MasterLexer lexer; + lexer.pushSource(ss); + + try { + parseHINFOData(lexer); + // Should be at end of data now + if (lexer.getNextToken(MasterToken::QSTRING, true).getType() != + MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Invalid HINFO text format: too many fields."); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct HINFO RDATA from " + << hinfo_str << "': " << ex.what()); + } + } + + HINFOImpl(InputBuffer& buffer, size_t rdata_len) { + rdata_len -= detail::bufferToCharString(buffer, rdata_len, cpu); + rdata_len -= detail::bufferToCharString(buffer, rdata_len, os); + if (rdata_len != 0) { + isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " << + "HINFO RDATA: bytes left at end: " << + static_cast<int>(rdata_len)); + } + } + + HINFOImpl(MasterLexer& lexer) + { + parseHINFOData(lexer); + } + +private: + void + parseHINFOData(MasterLexer& lexer) { + MasterToken token = lexer.getNextToken(MasterToken::QSTRING); + stringToCharString(token.getStringRegion(), cpu); + token = lexer.getNextToken(MasterToken::QSTRING); + stringToCharString(token.getStringRegion(), os); + } + +public: + detail::CharString cpu; + detail::CharString os; +}; + +HINFO::HINFO(const std::string& hinfo_str) : impl_(new HINFOImpl(hinfo_str)) +{} + + +HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) : + impl_(new HINFOImpl(buffer, rdata_len)) +{} + +HINFO::HINFO(const HINFO& source): + Rdata(), impl_(new HINFOImpl(*source.impl_)) +{ +} + +HINFO::HINFO(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(new HINFOImpl(lexer)) +{} + +HINFO& +HINFO::operator=(const HINFO& source) +{ + impl_.reset(new HINFOImpl(*source.impl_)); + return (*this); +} + +HINFO::~HINFO() { +} + +std::string +HINFO::toText() const { + string result; + result += "\""; + result += detail::charStringToString(impl_->cpu); + result += "\" \""; + result += detail::charStringToString(impl_->os); + result += "\""; + return (result); +} + +void +HINFO::toWire(OutputBuffer& buffer) const { + toWireHelper(buffer); +} + +void +HINFO::toWire(AbstractMessageRenderer& renderer) const { + toWireHelper(renderer); +} + +int +HINFO::compare(const Rdata& other) const { + const HINFO& other_hinfo = dynamic_cast<const HINFO&>(other); + + const int cmp = compareCharStrings(impl_->cpu, other_hinfo.impl_->cpu); + if (cmp != 0) { + return (cmp); + } + return (compareCharStrings(impl_->os, other_hinfo.impl_->os)); +} + +const std::string +HINFO::getCPU() const { + return (detail::charStringToString(impl_->cpu)); +} + +const std::string +HINFO::getOS() const { + return (detail::charStringToString(impl_->os)); +} + +template <typename T> +void +HINFO::toWireHelper(T& outputer) const { + outputer.writeData(&impl_->cpu[0], impl_->cpu.size()); + outputer.writeData(&impl_->os[0], impl_->os.size()); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/hinfo_13.h b/src/lib/dns/rdata/generic/hinfo_13.h new file mode 100644 index 0000000..acceb14 --- /dev/null +++ b/src/lib/dns/rdata/generic/hinfo_13.h @@ -0,0 +1,64 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD +#include <stdint.h> + +#include <string> + +#include <boost/scoped_ptr.hpp> +#include <boost/noncopyable.hpp> + +#include <dns/name.h> +#include <dns/rdata.h> +#include <util/buffer.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class HINFOImpl; + +/// \brief \c HINFO class represents the HINFO rdata defined in +/// RFC1034, RFC1035 +/// +/// This class implements the basic interfaces inherited from the +/// \c rdata::Rdata class, and provides accessors specific to the +/// HINFO rdata. +class HINFO : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + // HINFO specific methods + ~HINFO(); + + HINFO& operator=(const HINFO&); + + const std::string getCPU() const; + const std::string getOS() const; + +private: + /// Helper template function for toWire() + /// + /// \param outputer Where to write data in + template <typename T> + void toWireHelper(T& outputer) const; + + boost::scoped_ptr<HINFOImpl> impl_; +}; + + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/minfo_14.cc b/src/lib/dns/rdata/generic/minfo_14.cc new file mode 100644 index 0000000..d3dfd1e --- /dev/null +++ b/src/lib/dns/rdata/generic/minfo_14.cc @@ -0,0 +1,173 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> +#include <sstream> + +#include <util/buffer.h> + +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/lexer_util.h> + +using namespace std; +using namespace isc::dns; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// \c minfo_str must be formatted as follows: +/// \code <rmailbox name> <emailbox name> +/// \endcode +/// where both fields must represent a valid domain name. +/// +/// An example of valid string is: +/// \code "rmail.example.com. email.example.com." \endcode +/// +/// \throw InvalidRdataText The number of RDATA fields (must be 2) is +/// incorrect. +/// \throw std::bad_alloc Memory allocation for names fails. +/// \throw Other The constructor of the \c Name class will throw if the +/// names in the string is invalid. +MINFO::MINFO(const std::string& minfo_str) : + // We cannot construct both names in the initialization list due to the + // necessary text processing, so we have to initialize them with a dummy + // name and replace them later. + rmailbox_(Name::ROOT_NAME()), emailbox_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(minfo_str); + MasterLexer lexer; + lexer.pushSource(ss); + + rmailbox_ = createNameFromLexer(lexer, NULL); + emailbox_ = createNameFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for MINFO: " + << minfo_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct MINFO from '" << + minfo_str << "': " << ex.what()); + } +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of an MINFO RDATA. The RMAILBOX and EMAILBOX fields can be non-absolute +/// if \c origin is non-NULL, in which case \c origin is used to make them +/// absolute. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and constructors if construction of +/// textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of SERVER when it +/// is non-absolute. +MINFO::MINFO(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + rmailbox_(createNameFromLexer(lexer, origin)), + emailbox_(createNameFromLexer(lexer, origin)) +{ +} + +/// \brief Constructor from wire-format data. +/// +/// This constructor doesn't check the validity of the second parameter (rdata +/// length) for parsing. +/// If necessary, the caller will check consistency. +/// +/// \throw std::bad_alloc Memory allocation for names fails. +/// \throw Other The constructor of the \c Name class will throw if the +/// names in the wire is invalid. +MINFO::MINFO(InputBuffer& buffer, size_t) : + rmailbox_(buffer), emailbox_(buffer) +{} + +/// \brief Copy constructor. +/// +/// \throw std::bad_alloc Memory allocation fails in copying internal +/// member variables (this should be very rare). +MINFO::MINFO(const MINFO& other) : + Rdata(), rmailbox_(other.rmailbox_), emailbox_(other.emailbox_) +{} + +/// \brief Convert the \c MINFO to a string. +/// +/// The output of this method is formatted as described in the "from string" +/// constructor (\c MINFO(const std::string&))). +/// +/// \throw std::bad_alloc Internal resource allocation fails. +/// +/// \return A \c string object that represents the \c MINFO object. +std::string +MINFO::toText() const { + return (rmailbox_.toText() + " " + emailbox_.toText()); +} + +/// \brief Render the \c MINFO in the wire format without name compression. +/// +/// \throw std::bad_alloc Internal resource allocation fails. +/// +/// \param buffer An output buffer to store the wire data. +void +MINFO::toWire(OutputBuffer& buffer) const { + rmailbox_.toWire(buffer); + emailbox_.toWire(buffer); +} + +MINFO& +MINFO::operator=(const MINFO& source) { + rmailbox_ = source.rmailbox_; + emailbox_ = source.emailbox_; + + return (*this); +} + +/// \brief Render the \c MINFO in the wire format with taking into account +/// compression. +/// +/// As specified in RFC3597, TYPE MINFO is "well-known", the rmailbox and +/// emailbox fields (domain names) will be compressed. +/// +/// \throw std::bad_alloc Internal resource allocation fails. +/// +/// \param renderer DNS message rendering context that encapsulates the +/// output buffer and name compression information. +void +MINFO::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(rmailbox_); + renderer.writeName(emailbox_); +} + +/// \brief Compare two instances of \c MINFO RDATA. +/// +/// See documentation in \c Rdata. +int +MINFO::compare(const Rdata& other) const { + const MINFO& other_minfo = dynamic_cast<const MINFO&>(other); + + const int cmp = compareNames(rmailbox_, other_minfo.rmailbox_); + if (cmp != 0) { + return (cmp); + } + return (compareNames(emailbox_, other_minfo.emailbox_)); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/minfo_14.h b/src/lib/dns/rdata/generic/minfo_14.h new file mode 100644 index 0000000..ce9f43d --- /dev/null +++ b/src/lib/dns/rdata/generic/minfo_14.h @@ -0,0 +1,74 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +/// \brief \c rdata::generic::MINFO class represents the MINFO RDATA as +/// defined in RFC1035. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// MINFO RDATA. +class MINFO : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Define the assignment operator. + /// + /// \exception std::bad_alloc Memory allocation fails in copying + /// internal member variables (this should be very rare). + MINFO& operator=(const MINFO& source); + + /// \brief Return the value of the rmailbox field. + /// + /// \throw std::bad_alloc If resource allocation for the returned + /// \c Name fails. + /// + /// \note + /// Unlike the case of some other RDATA classes (such as + /// \c NS::getNSName()), this method constructs a new \c Name object + /// and returns it, instead of returning a reference to a \c Name object + /// internally maintained in the class (which is a private member). + /// This is based on the observation that this method will be rarely + /// used and even when it's used it will not be in a performance context + /// (for example, a recursive resolver won't need this field in its + /// resolution process). By returning a new object we have flexibility + /// of changing the internal representation without the risk of changing + /// the interface or method property. + /// The same note applies to the \c getEmailbox() method. + Name getRmailbox() const { return (rmailbox_); } + + /// \brief Return the value of the emailbox field. + /// + /// \throw std::bad_alloc If resource allocation for the returned + /// \c Name fails. + Name getEmailbox() const { return (emailbox_); } + +private: + Name rmailbox_; + Name emailbox_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/mx_15.cc b/src/lib/dns/rdata/generic/mx_15.cc new file mode 100644 index 0000000..bbe8abc --- /dev/null +++ b/src/lib/dns/rdata/generic/mx_15.cc @@ -0,0 +1,160 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#include <boost/lexical_cast.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/lexer_util.h> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +MX::MX(InputBuffer& buffer, size_t) : + preference_(buffer.readUint16()), mxname_(buffer) +{ + // we don't need rdata_len for parsing. if necessary, the caller will + // check consistency. +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid MX 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 EXCHANGE name must be absolute since there's no parameter that +/// specifies the origin name; if it is not absolute, \c MissingNameOrigin +/// exception will be thrown. It must not be represented as a quoted +/// string. +/// +/// See the construction that takes \c MasterLexer for other fields. +/// +/// \throw Others Exception from the Name and RRTTL constructors. +/// \throw InvalidRdataText Other general syntax errors. +MX::MX(const std::string& mx_str) : + // Fill in dummy name and replace them soon below. + preference_(0), mxname_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(mx_str); + MasterLexer lexer; + lexer.pushSource(ss); + + constructFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for MX: " + << mx_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct MX from '" << + mx_str << "': " << ex.what()); + } +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of an MX RDATA. The EXCHANGE field can be non-absolute if \c origin +/// is non-NULL, in which case \c origin is used to make it absolute. +/// It must not be represented as a quoted string. +/// +/// The PREFERENCE field must be a valid decimal representation of an +/// unsigned 16-bit integer. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of EXCHANGE when it +/// is non-absolute. +MX::MX(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + preference_(0), mxname_(Name::ROOT_NAME()) +{ + constructFromLexer(lexer, origin); +} + +void +MX::constructFromLexer(MasterLexer& lexer, const Name* origin) { + const uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid MX preference: " << num); + } + preference_ = static_cast<uint16_t>(num); + + mxname_ = createNameFromLexer(lexer, origin); +} + +MX::MX(uint16_t preference, const Name& mxname) : + preference_(preference), mxname_(mxname) +{} + +MX::MX(const MX& other) : + Rdata(), preference_(other.preference_), mxname_(other.mxname_) +{} + +void +MX::toWire(OutputBuffer& buffer) const { + buffer.writeUint16(preference_); + mxname_.toWire(buffer); +} + +void +MX::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeUint16(preference_); + renderer.writeName(mxname_); +} + +string +MX::toText() const { + return (lexical_cast<string>(preference_) + " " + mxname_.toText()); +} + +int +MX::compare(const Rdata& other) const { + const MX& other_mx = dynamic_cast<const MX&>(other); + + if (preference_ < other_mx.preference_) { + return (-1); + } else if (preference_ > other_mx.preference_) { + return (1); + } + + return (compareNames(mxname_, other_mx.mxname_)); +} + +const Name& +MX::getMXName() const { + return (mxname_); +} + +uint16_t +MX::getMXPref() const { + return (preference_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/mx_15.h b/src/lib/dns/rdata/generic/mx_15.h new file mode 100644 index 0000000..b688f88 --- /dev/null +++ b/src/lib/dns/rdata/generic/mx_15.h @@ -0,0 +1,52 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class MX : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + MX(uint16_t preference, const Name& mxname); + + /// + /// Specialized methods + /// + const Name& getMXName() const; + uint16_t getMXPref() const; + +private: + void constructFromLexer(isc::dns::MasterLexer& lexer, + const isc::dns::Name* origin); + + /// Note: this is a prototype version; we may reconsider + /// this representation later. + uint16_t preference_; + Name mxname_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/naptr_35.cc b/src/lib/dns/rdata/generic/naptr_35.cc new file mode 100644 index 0000000..aa2d7f5 --- /dev/null +++ b/src/lib/dns/rdata/generic/naptr_35.cc @@ -0,0 +1,256 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.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> +#include <exceptions/exceptions.h> + +#include <string> +#include <boost/lexical_cast.hpp> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using namespace isc::dns; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +class NAPTRImpl { +public: + NAPTRImpl() : order(0), preference(0), replacement(".") {} + + NAPTRImpl(InputBuffer& buffer, size_t rdata_len) : replacement(".") { + if (rdata_len < 4 || buffer.getLength() - buffer.getPosition() < 4) { + isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " + "NAPTR RDATA wire format: insufficient length "); + } + order = buffer.readUint16(); + preference = buffer.readUint16(); + rdata_len -= 4; + + rdata_len -= detail::bufferToCharString(buffer, rdata_len, flags); + rdata_len -= detail::bufferToCharString(buffer, rdata_len, services); + rdata_len -= detail::bufferToCharString(buffer, rdata_len, regexp); + replacement = Name(buffer); + if (rdata_len < 1) { + isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " + "NAPTR RDATA wire format: missing replacement name"); + } + rdata_len -= replacement.getLength(); + + if (rdata_len != 0) { + isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " << + "NAPTR RDATA: bytes left at end: " << + static_cast<int>(rdata_len)); + } + } + + NAPTRImpl(const std::string& naptr_str) : replacement(".") { + std::istringstream ss(naptr_str); + MasterLexer lexer; + lexer.pushSource(ss); + + try { + parseNAPTRData(lexer); + // Should be at end of data now + if (lexer.getNextToken(MasterToken::QSTRING, true).getType() != + MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Invalid NAPTR text format: too many fields."); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct NAPTR RDATA from " + << naptr_str << "': " << ex.what()); + } + } + + NAPTRImpl(MasterLexer& lexer) : replacement(".") + { + parseNAPTRData(lexer); + } + +private: + void + parseNAPTRData(MasterLexer& lexer) { + MasterToken token = lexer.getNextToken(MasterToken::NUMBER); + if (token.getNumber() > 65535) { + isc_throw(InvalidRdataText, + "Invalid NAPTR text format: order out of range: " + << token.getNumber()); + } + order = token.getNumber(); + token = lexer.getNextToken(MasterToken::NUMBER); + if (token.getNumber() > 65535) { + isc_throw(InvalidRdataText, + "Invalid NAPTR text format: preference out of range: " + << token.getNumber()); + } + preference = token.getNumber(); + + token = lexer.getNextToken(MasterToken::QSTRING); + stringToCharString(token.getStringRegion(), flags); + token = lexer.getNextToken(MasterToken::QSTRING); + stringToCharString(token.getStringRegion(), services); + token = lexer.getNextToken(MasterToken::QSTRING); + stringToCharString(token.getStringRegion(), regexp); + + token = lexer.getNextToken(MasterToken::STRING); + replacement = Name(token.getString()); + } + + +public: + uint16_t order; + uint16_t preference; + detail::CharString flags; + detail::CharString services; + detail::CharString regexp; + Name replacement; +}; + +NAPTR::NAPTR(InputBuffer& buffer, size_t rdata_len) : + impl_(new NAPTRImpl(buffer, rdata_len)) +{} + +NAPTR::NAPTR(const std::string& naptr_str) : impl_(new NAPTRImpl(naptr_str)) +{} + +NAPTR::NAPTR(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(new NAPTRImpl(lexer)) +{} + +NAPTR::NAPTR(const NAPTR& naptr) : Rdata(), + impl_(new NAPTRImpl(*naptr.impl_)) +{} + +NAPTR& +NAPTR::operator=(const NAPTR& source) +{ + impl_.reset(new NAPTRImpl(*source.impl_)); + return (*this); +} + +NAPTR::~NAPTR() { +} + +void +NAPTR::toWire(OutputBuffer& buffer) const { + toWireHelper(buffer); + impl_->replacement.toWire(buffer); +} + +void +NAPTR::toWire(AbstractMessageRenderer& renderer) const { + toWireHelper(renderer); + // Type NAPTR is not "well-known", and name compression must be disabled + // per RFC3597. + renderer.writeName(impl_->replacement, false); +} + +string +NAPTR::toText() const { + string result; + result += lexical_cast<string>(impl_->order); + result += " "; + result += lexical_cast<string>(impl_->preference); + result += " \""; + result += detail::charStringToString(impl_->flags); + result += "\" \""; + result += detail::charStringToString(impl_->services); + result += "\" \""; + result += detail::charStringToString(impl_->regexp); + result += "\" "; + result += impl_->replacement.toText(); + return (result); +} + +int +NAPTR::compare(const Rdata& other) const { + const NAPTR other_naptr = dynamic_cast<const NAPTR&>(other); + + if (impl_->order < other_naptr.impl_->order) { + return (-1); + } else if (impl_->order > other_naptr.impl_->order) { + return (1); + } + + if (impl_->preference < other_naptr.impl_->preference) { + return (-1); + } else if (impl_->preference > other_naptr.impl_->preference) { + return (1); + } + + const int fcmp = detail::compareCharStrings(impl_->flags, + other_naptr.impl_->flags); + if (fcmp != 0) { + return (fcmp); + } + + const int scmp = detail::compareCharStrings(impl_->services, + other_naptr.impl_->services); + if (scmp != 0) { + return (scmp); + } + + const int rcmp = detail::compareCharStrings(impl_->regexp, + other_naptr.impl_->regexp); + if (rcmp != 0) { + return (rcmp); + } + + return (compareNames(impl_->replacement, other_naptr.impl_->replacement)); +} + +uint16_t +NAPTR::getOrder() const { + return (impl_->order); +} + +uint16_t +NAPTR::getPreference() const { + return (impl_->preference); +} + +const std::string +NAPTR::getFlags() const { + return (detail::charStringToString(impl_->flags)); +} + +const std::string +NAPTR::getServices() const { + return (detail::charStringToString(impl_->services)); +} + +const std::string +NAPTR::getRegexp() const { + return (detail::charStringToString(impl_->regexp)); +} + +const Name& +NAPTR::getReplacement() const { + return (impl_->replacement); +} + +template <typename T> +void +NAPTR::toWireHelper(T& outputer) const { + outputer.writeUint16(impl_->order); + outputer.writeUint16(impl_->preference); + + outputer.writeData(&impl_->flags[0], impl_->flags.size()); + outputer.writeData(&impl_->services[0], impl_->services.size()); + outputer.writeData(&impl_->regexp[0], impl_->regexp.size()); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/naptr_35.h b/src/lib/dns/rdata/generic/naptr_35.h new file mode 100644 index 0000000..c77b95d --- /dev/null +++ b/src/lib/dns/rdata/generic/naptr_35.h @@ -0,0 +1,64 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <boost/scoped_ptr.hpp> + +#include <dns/name.h> +#include <dns/rdata.h> +#include <util/buffer.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class NAPTRImpl; + +/// \brief \c NAPTR class represents the NAPTR rdata defined in +/// RFC2915, RFC2168 and RFC3403 +/// +/// This class implements the basic interfaces inherited from the +/// \c rdata::Rdata class, and provides accessors specific to the +/// NAPTR rdata. +class NAPTR : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + // NAPTR specific methods + ~NAPTR(); + + NAPTR& operator=(const NAPTR& source); + + uint16_t getOrder() const; + uint16_t getPreference() const; + const std::string getFlags() const; + const std::string getServices() const; + const std::string getRegexp() const; + const Name& getReplacement() const; +private: + /// Helper template function for toWire() + /// + /// \param outputer Where to write data in + template <typename T> + void toWireHelper(T& outputer) const; + + boost::scoped_ptr<NAPTRImpl> impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/ns_2.cc b/src/lib/dns/rdata/generic/ns_2.cc new file mode 100644 index 0000000..7c1fd01 --- /dev/null +++ b/src/lib/dns/rdata/generic/ns_2.cc @@ -0,0 +1,121 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#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/lexer_util.h> + +using namespace std; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// The given string must represent a valid NS 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 NSDNAME must be absolute since there's no parameter that +/// specifies the origin name; if it is not absolute, \c +/// MissingNameOrigin exception will be thrown. These must not be +/// represented as a quoted string. +/// +/// \throw Others Exception from the Name and RRTTL constructors. +/// \throw InvalidRdataText Other general syntax errors. +NS::NS(const std::string& namestr) : + // Fill in dummy name and replace them soon below. + nsname_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(namestr); + MasterLexer lexer; + lexer.pushSource(ss); + + nsname_ = createNameFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for NS: " + << namestr); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct NS from '" << + namestr << "': " << ex.what()); + } +} + +NS::NS(InputBuffer& buffer, size_t) : + nsname_(buffer) +{ + // we don't need rdata_len for parsing. if necessary, the caller will + // check consistency. +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of an NS RDATA. The NSDNAME field can be +/// non-absolute if \c origin is non-NULL, in which case \c origin is +/// used to make it absolute. It must not be represented as a quoted +/// string. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of NSDNAME when it +/// is non-absolute. +NS::NS(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + nsname_(createNameFromLexer(lexer, origin)) +{} + +NS::NS(const NS& other) : + Rdata(), nsname_(other.nsname_) +{} + +void +NS::toWire(OutputBuffer& buffer) const { + nsname_.toWire(buffer); +} + +void +NS::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(nsname_); +} + +string +NS::toText() const { + return (nsname_.toText()); +} + +int +NS::compare(const Rdata& other) const { + const NS& other_ns = dynamic_cast<const NS&>(other); + + return (compareNames(nsname_, other_ns.nsname_)); +} + +const Name& +NS::getNSName() const { + return (nsname_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/ns_2.h b/src/lib/dns/rdata/generic/ns_2.h new file mode 100644 index 0000000..18c3cf6 --- /dev/null +++ b/src/lib/dns/rdata/generic/ns_2.h @@ -0,0 +1,43 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class NS : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + /// + /// Specialized constructor + /// + explicit NS(const Name& nsname) : nsname_(nsname) {} + /// + /// Specialized methods + /// + const Name& getNSName() const; +private: + Name nsname_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/nsec3_50.cc b/src/lib/dns/rdata/generic/nsec3_50.cc new file mode 100644 index 0000000..e99c109 --- /dev/null +++ b/src/lib/dns/rdata/generic/nsec3_50.cc @@ -0,0 +1,343 @@ +// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <iostream> +#include <iomanip> +#include <string> +#include <sstream> +#include <vector> +#include <cassert> + +#include <boost/lexical_cast.hpp> + +#include <util/encode/base32hex.h> +#include <util/encode/hex.h> +#include <util/buffer.h> + +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/nsec_bitmap.h> +#include <dns/rdata/generic/detail/nsec3param_common.h> + +#include <memory> + +#include <stdio.h> +#include <time.h> + +using namespace std; +using namespace isc::dns::rdata::generic::detail::nsec; +using namespace isc::dns::rdata::generic::detail::nsec3; +using namespace isc::util::encode; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct NSEC3Impl { + // straightforward representation of NSEC3 RDATA fields + NSEC3Impl(uint8_t hashalg, uint8_t flags, uint16_t iterations, + vector<uint8_t>salt, vector<uint8_t>next, + vector<uint8_t> typebits) : + hashalg_(hashalg), flags_(flags), iterations_(iterations), + salt_(salt), next_(next), typebits_(typebits) + {} + + const uint8_t hashalg_; + const uint8_t flags_; + const uint16_t iterations_; + const vector<uint8_t> salt_; + const vector<uint8_t> next_; + const vector<uint8_t> typebits_; +}; + +/// \brief Constructor from string. +/// +/// The given string must represent a valid NSEC3 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 Hash Algorithm, Flags and Iterations fields must be within their +/// valid ranges. The Salt field may contain "-" to indicate that the +/// salt is of length 0. The Salt field must not contain any whitespace. +/// The type mnemonics must be valid, and separated by whitespace. If +/// any invalid mnemonics are found, InvalidRdataText exception is +/// thrown. +/// +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param nsec3_str A string containing the RDATA to be created +NSEC3::NSEC3(const std::string& nsec3_str) : + impl_(NULL) +{ + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the NSEC3Impl that constructFromLexer() returns. + std::unique_ptr<NSEC3Impl> impl_ptr; + + try { + std::istringstream ss(nsec3_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 NSEC3: " << nsec3_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct NSEC3 from '" << nsec3_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 NSEC3 RDATA. +/// +/// See \c NSEC3::NSEC3(const std::string&) for description of the +/// expected RDATA fields. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +NSEC3::NSEC3(MasterLexer& lexer, const Name*, MasterLoader::Options, + MasterLoaderCallbacks&) : + impl_(NULL) +{ + impl_ = constructFromLexer(lexer); +} + +NSEC3Impl* +NSEC3::constructFromLexer(MasterLexer& lexer) { + vector<uint8_t> salt; + const ParseNSEC3ParamResult params = + parseNSEC3ParamFromLexer("NSEC3", lexer, salt); + + const string& nexthash = + lexer.getNextToken(MasterToken::STRING).getString(); + if (*nexthash.rbegin() == '=') { + isc_throw(InvalidRdataText, "NSEC3 hash has padding: " << nexthash); + } + + vector<uint8_t> next; + decodeBase32Hex(nexthash, next); + if (next.size() > 255) { + isc_throw(InvalidRdataText, "NSEC3 hash is too long: " + << next.size() << " bytes"); + } + + vector<uint8_t> typebits; + // For NSEC3 empty bitmap is possible and allowed. + buildBitmapsFromLexer("NSEC3", lexer, typebits, true); + return (new NSEC3Impl(params.algorithm, params.flags, params.iterations, + salt, next, typebits)); +} + +NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len) : + impl_(NULL) +{ + vector<uint8_t> salt; + const ParseNSEC3ParamResult params = + parseNSEC3ParamWire("NSEC3", buffer, rdata_len, salt); + + if (rdata_len < 1) { + isc_throw(DNSMessageFORMERR, "NSEC3 too short to contain hash length, " + "length: " << rdata_len + salt.size() + 5); + } + const uint8_t nextlen = buffer.readUint8(); + --rdata_len; + if (nextlen == 0 || rdata_len < nextlen) { + isc_throw(DNSMessageFORMERR, "NSEC3 invalid hash length: " << + static_cast<unsigned int>(nextlen)); + } + + vector<uint8_t> next(nextlen); + buffer.readData(&next[0], nextlen); + rdata_len -= nextlen; + + vector<uint8_t> typebits(rdata_len); + if (rdata_len > 0) { + // Read and parse the bitmaps only when they exist; empty bitmap + // is possible for NSEC3. + buffer.readData(&typebits[0], rdata_len); + checkRRTypeBitmaps("NSEC3", typebits); + } + + impl_ = new NSEC3Impl(params.algorithm, params.flags, params.iterations, + salt, next, typebits); +} + +NSEC3::NSEC3(const NSEC3& source) : + Rdata(), impl_(new NSEC3Impl(*source.impl_)) +{} + +NSEC3& +NSEC3::operator=(const NSEC3& source) { + if (this == &source) { + return (*this); + } + + NSEC3Impl* newimpl = new NSEC3Impl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +NSEC3::~NSEC3() { + delete impl_; +} + +string +NSEC3::toText() const { + ostringstream s; + bitmapsToText(impl_->typebits_, s); + + using boost::lexical_cast; + return (lexical_cast<string>(static_cast<int>(impl_->hashalg_)) + + " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) + + " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) + + " " + (impl_->salt_.empty() ? "-" : encodeHex(impl_->salt_)) + + " " + encodeBase32Hex(impl_->next_) + s.str()); +} + +template <typename OUTPUT_TYPE> +void +toWireHelper(const NSEC3Impl& impl, OUTPUT_TYPE& output) { + output.writeUint8(impl.hashalg_); + output.writeUint8(impl.flags_); + output.writeUint16(impl.iterations_); + output.writeUint8(impl.salt_.size()); + if (!impl.salt_.empty()) { + output.writeData(&impl.salt_[0], impl.salt_.size()); + } + assert(!impl.next_.empty()); + output.writeUint8(impl.next_.size()); + output.writeData(&impl.next_[0], impl.next_.size()); + if (!impl.typebits_.empty()) { + output.writeData(&impl.typebits_[0], impl.typebits_.size()); + } +} + +void +NSEC3::toWire(OutputBuffer& buffer) const { + toWireHelper(*impl_, buffer); +} + +void +NSEC3::toWire(AbstractMessageRenderer& renderer) const { + toWireHelper(*impl_, renderer); +} + +namespace { +// This is a helper subroutine for compare(). It compares two binary +// data stored in vector<uint8_t> objects based on the "Canonical RR Ordering" +// as defined in Section 6.3 of RFC4034, that is, the data are treated +// "as a left-justified unsigned octet sequence in which the absence of an +// octet sorts before a zero octet." +// +// If check_length_first is true, it treats the compared data as if they +// began with a single-octet "length" field whose value is the size of the +// corresponding vector. In this case, if the sizes of the two vectors are +// different the shorter one is always considered the "smaller"; the contents +// of the vector don't matter. +// +// This function returns: +// -1 if v1 is considered smaller than v2 +// 1 if v1 is considered larger than v2 +// 0 otherwise +int +compareVectors(const vector<uint8_t>& v1, const vector<uint8_t>& v2, + bool check_length_first = true) +{ + const size_t len1 = v1.size(); + const size_t len2 = v2.size(); + if (check_length_first && len1 != len2) { + return (len1 - len2); + } + const size_t cmplen = min(len1, len2); + const int cmp = cmplen == 0 ? 0 : memcmp(&v1.at(0), &v2.at(0), cmplen); + if (cmp != 0) { + return (cmp); + } else { + return (len1 - len2); + } +} +} + +int +NSEC3::compare(const Rdata& other) const { + const NSEC3& other_nsec3 = dynamic_cast<const NSEC3&>(other); + + if (impl_->hashalg_ != other_nsec3.impl_->hashalg_) { + return (impl_->hashalg_ < other_nsec3.impl_->hashalg_ ? -1 : 1); + } + if (impl_->flags_ != other_nsec3.impl_->flags_) { + return (impl_->flags_ < other_nsec3.impl_->flags_ ? -1 : 1); + } + if (impl_->iterations_ != other_nsec3.impl_->iterations_) { + return (impl_->iterations_ < other_nsec3.impl_->iterations_ ? -1 : 1); + } + + int cmp = compareVectors(impl_->salt_, other_nsec3.impl_->salt_); + if (cmp != 0) { + return (cmp); + } + cmp = compareVectors(impl_->next_, other_nsec3.impl_->next_); + if (cmp != 0) { + return (cmp); + } + // Note that bitmap doesn't have a dedicated length field, so we shouldn't + // terminate the comparison just because the lengths are different. + return (compareVectors(impl_->typebits_, other_nsec3.impl_->typebits_, + false)); +} + +uint8_t +NSEC3::getHashalg() const { + return (impl_->hashalg_); +} + +uint8_t +NSEC3::getFlags() const { + return (impl_->flags_); +} + +uint16_t +NSEC3::getIterations() const { + return (impl_->iterations_); +} + +const vector<uint8_t>& +NSEC3::getSalt() const { + return (impl_->salt_); +} + +const vector<uint8_t>& +NSEC3::getNext() const { + return (impl_->next_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/nsec3_50.h b/src/lib/dns/rdata/generic/nsec3_50.h new file mode 100644 index 0000000..cf73624 --- /dev/null +++ b/src/lib/dns/rdata/generic/nsec3_50.h @@ -0,0 +1,54 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> +#include <dns/master_lexer.h> + +// BEGIN_HEADER_GUARD + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct NSEC3Impl; + +class NSEC3 : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + NSEC3& operator=(const NSEC3& source); + ~NSEC3(); + + uint8_t getHashalg() const; + uint8_t getFlags() const; + uint16_t getIterations() const; + const std::vector<uint8_t>& getSalt() const; + const std::vector<uint8_t>& getNext() const; + +private: + NSEC3Impl* constructFromLexer(isc::dns::MasterLexer& lexer); + + NSEC3Impl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/nsec3param_51.cc b/src/lib/dns/rdata/generic/nsec3param_51.cc new file mode 100644 index 0000000..2d28a69 --- /dev/null +++ b/src/lib/dns/rdata/generic/nsec3param_51.cc @@ -0,0 +1,232 @@ +// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <util/buffer.h> +#include <util/encode/hex.h> + +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/nsec3param_common.h> + +#include <boost/lexical_cast.hpp> + +#include <memory> +#include <string> +#include <sstream> +#include <vector> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct NSEC3PARAMImpl { + // straightforward representation of NSEC3PARAM RDATA fields + NSEC3PARAMImpl(uint8_t hashalg, uint8_t flags, uint16_t iterations, + const vector<uint8_t>& salt) : + hashalg_(hashalg), flags_(flags), iterations_(iterations), salt_(salt) + {} + + const uint8_t hashalg_; + const uint8_t flags_; + const uint16_t iterations_; + const vector<uint8_t> salt_; +}; + +/// \brief Constructor from string. +/// +/// The given string must represent a valid NSEC3PARAM 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 Hash Algorithm, Flags and Iterations fields must be within their +/// valid ranges. The Salt field may contain "-" to indicate that the +/// salt is of length 0. The Salt field must not contain any whitespace. +/// +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param nsec3param_str A string containing the RDATA to be created +NSEC3PARAM::NSEC3PARAM(const std::string& nsec3param_str) : + impl_(NULL) +{ + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the NSEC3PARAMImpl that constructFromLexer() returns. + std::unique_ptr<NSEC3PARAMImpl> impl_ptr; + + try { + std::istringstream ss(nsec3param_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 NSEC3PARAM: " << nsec3param_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct NSEC3PARAM from '" << nsec3param_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 NSEC3PARAM RDATA. +/// +/// See \c NSEC3PARAM::NSEC3PARAM(const std::string&) for description of +/// the expected RDATA fields. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +NSEC3PARAM::NSEC3PARAM(MasterLexer& lexer, const Name*, MasterLoader::Options, + MasterLoaderCallbacks&) : + impl_(NULL) +{ + impl_ = constructFromLexer(lexer); +} + +NSEC3PARAMImpl* +NSEC3PARAM::constructFromLexer(MasterLexer& lexer) { + vector<uint8_t> salt; + const ParseNSEC3ParamResult params = + parseNSEC3ParamFromLexer("NSEC3PARAM", lexer, salt); + + return (new NSEC3PARAMImpl(params.algorithm, params.flags, + params.iterations, salt)); +} + +NSEC3PARAM::NSEC3PARAM(InputBuffer& buffer, size_t rdata_len) : + impl_(NULL) +{ + vector<uint8_t> salt; + const ParseNSEC3ParamResult params = + parseNSEC3ParamWire("NSEC3PARAM", buffer, rdata_len, salt); + + impl_ = new NSEC3PARAMImpl(params.algorithm, params.flags, + params.iterations, salt); +} + +NSEC3PARAM::NSEC3PARAM(const NSEC3PARAM& source) : + Rdata(), impl_(new NSEC3PARAMImpl(*source.impl_)) +{} + +NSEC3PARAM& +NSEC3PARAM::operator=(const NSEC3PARAM& source) { + if (this == &source) { + return (*this); + } + + NSEC3PARAMImpl* newimpl = new NSEC3PARAMImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +NSEC3PARAM::~NSEC3PARAM() { + delete impl_; +} + +string +NSEC3PARAM::toText() const { + using boost::lexical_cast; + return (lexical_cast<string>(static_cast<int>(impl_->hashalg_)) + + " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) + + " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) + + " " + (impl_->salt_.empty() ? "-" : encodeHex(impl_->salt_))); +} + +template <typename OUTPUT_TYPE> +void +toWireHelper(const NSEC3PARAMImpl& impl, OUTPUT_TYPE& output) { + output.writeUint8(impl.hashalg_); + output.writeUint8(impl.flags_); + output.writeUint16(impl.iterations_); + output.writeUint8(impl.salt_.size()); + if (!impl.salt_.empty()) { + output.writeData(&impl.salt_[0], impl.salt_.size()); + } +} + +void +NSEC3PARAM::toWire(OutputBuffer& buffer) const { + toWireHelper(*impl_, buffer); +} + +void +NSEC3PARAM::toWire(AbstractMessageRenderer& renderer) const { + toWireHelper(*impl_, renderer); +} + +int +NSEC3PARAM::compare(const Rdata& other) const { + const NSEC3PARAM& other_param = dynamic_cast<const NSEC3PARAM&>(other); + + if (impl_->hashalg_ != other_param.impl_->hashalg_) { + return (impl_->hashalg_ < other_param.impl_->hashalg_ ? -1 : 1); + } + if (impl_->flags_ != other_param.impl_->flags_) { + return (impl_->flags_ < other_param.impl_->flags_ ? -1 : 1); + } + if (impl_->iterations_ != other_param.impl_->iterations_) { + return (impl_->iterations_ < other_param.impl_->iterations_ ? -1 : 1); + } + + const size_t this_len = impl_->salt_.size(); + const size_t other_len = other_param.impl_->salt_.size(); + if (this_len != other_len) { + return (this_len - other_len); + } + const size_t cmplen = min(this_len, other_len); + const int cmp = (cmplen == 0) ? 0 : + memcmp(&impl_->salt_.at(0), &other_param.impl_->salt_.at(0), cmplen); + if (cmp != 0) { + return (cmp); + } else { + return (this_len - other_len); + } +} + +uint8_t +NSEC3PARAM::getHashalg() const { + return (impl_->hashalg_); +} + +uint8_t +NSEC3PARAM::getFlags() const { + return (impl_->flags_); +} + +uint16_t +NSEC3PARAM::getIterations() const { + return (impl_->iterations_); +} + +const vector<uint8_t>& +NSEC3PARAM::getSalt() const { + return (impl_->salt_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/nsec3param_51.h b/src/lib/dns/rdata/generic/nsec3param_51.h new file mode 100644 index 0000000..1c7bf03 --- /dev/null +++ b/src/lib/dns/rdata/generic/nsec3param_51.h @@ -0,0 +1,56 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> +#include <dns/master_lexer.h> + +// BEGIN_HEADER_GUARD + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct NSEC3PARAMImpl; + +class NSEC3PARAM : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + NSEC3PARAM& operator=(const NSEC3PARAM& source); + ~NSEC3PARAM(); + + /// + /// Specialized methods + /// + uint8_t getHashalg() const; + uint8_t getFlags() const; + uint16_t getIterations() const; + const std::vector<uint8_t>& getSalt() const; + +private: + NSEC3PARAMImpl* constructFromLexer(isc::dns::MasterLexer& lexer); + + NSEC3PARAMImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/nsec_47.cc b/src/lib/dns/rdata/generic/nsec_47.cc new file mode 100644 index 0000000..f8af0e0 --- /dev/null +++ b/src/lib/dns/rdata/generic/nsec_47.cc @@ -0,0 +1,216 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <iostream> +#include <string> +#include <sstream> +#include <vector> + +#include <util/encode/base64.h> +#include <util/buffer.h> +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/nsec_bitmap.h> +#include <dns/rdata/generic/detail/lexer_util.h> + +#include <stdio.h> +#include <time.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; +using namespace isc::dns::rdata::generic::detail::nsec; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct NSECImpl { + // straightforward representation of NSEC RDATA fields + NSECImpl(const Name& next, vector<uint8_t> typebits) : + nextname_(next), typebits_(typebits) + {} + + Name nextname_; + vector<uint8_t> typebits_; +}; + +/// \brief Constructor from string. +/// +/// The given string must represent a valid NSEC 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 Next Domain Name field must be absolute since there's no +/// parameter that specifies the origin name; if it is not absolute, +/// \c MissingNameOrigin exception will be thrown. This must not be +/// represented as a quoted string. +/// +/// The type mnemonics must be valid, and separated by whitespace. If +/// any invalid mnemonics are found, InvalidRdataText exception is +/// thrown. +/// +/// \throw MissingNameOrigin Thrown when the Next Domain Name is not absolute. +/// \throw InvalidRdataText if any fields are out of their valid range. +/// +/// \param nsec_str A string containing the RDATA to be created +NSEC::NSEC(const std::string& nsec_str) : + impl_(NULL) +{ + try { + std::istringstream ss(nsec_str); + MasterLexer lexer; + lexer.pushSource(ss); + + const Name origin_name(createNameFromLexer(lexer, NULL)); + + vector<uint8_t> typebits; + buildBitmapsFromLexer("NSEC", lexer, typebits); + + impl_ = new NSECImpl(origin_name, typebits); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Extra input text for NSEC: " << nsec_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct NSEC from '" << nsec_str << "': " + << ex.what()); + } +} + +NSEC::NSEC(InputBuffer& buffer, size_t rdata_len) { + const size_t pos = buffer.getPosition(); + const Name nextname(buffer); + + // rdata_len must be sufficiently large to hold non empty bitmap. + if (rdata_len <= buffer.getPosition() - pos) { + isc_throw(DNSMessageFORMERR, + "NSEC RDATA from wire too short: " << rdata_len << "bytes"); + } + rdata_len -= (buffer.getPosition() - pos); + + vector<uint8_t> typebits(rdata_len); + buffer.readData(&typebits[0], rdata_len); + checkRRTypeBitmaps("NSEC", typebits); + + impl_ = new NSECImpl(nextname, typebits); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of an NSEC RDATA. +/// +/// The Next Domain Name field can be non-absolute if \c origin is +/// non-NULL, in which case \c origin is used to make it absolute. It +/// must not be represented as a quoted string. +/// +/// The type mnemonics must be valid, and separated by whitespace. If +/// any invalid mnemonics are found, InvalidRdataText exception is +/// thrown. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw MissingNameOrigin Thrown when the Next Domain Name is not +/// absolute and \c origin is NULL. +/// \throw InvalidRdataText if any fields are out of their valid range. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin The origin to use with a relative Next Domain Name +/// field +NSEC::NSEC(MasterLexer& lexer, const Name* origin, MasterLoader::Options, + MasterLoaderCallbacks&) +{ + const Name next_name(createNameFromLexer(lexer, origin)); + + vector<uint8_t> typebits; + buildBitmapsFromLexer("NSEC", lexer, typebits); + + impl_ = new NSECImpl(next_name, typebits); +} + +NSEC::NSEC(const NSEC& source) : + Rdata(), impl_(new NSECImpl(*source.impl_)) +{} + +NSEC& +NSEC::operator=(const NSEC& source) { + if (this == &source) { + return (*this); + } + + NSECImpl* newimpl = new NSECImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +NSEC::~NSEC() { + delete impl_; +} + +string +NSEC::toText() const { + ostringstream s; + s << impl_->nextname_; + bitmapsToText(impl_->typebits_, s); + return (s.str()); +} + +void +NSEC::toWire(OutputBuffer& buffer) const { + impl_->nextname_.toWire(buffer); + buffer.writeData(&impl_->typebits_[0], impl_->typebits_.size()); +} + +void +NSEC::toWire(AbstractMessageRenderer& renderer) const { + // Type NSEC is not "well-known", and name compression must be disabled + // per RFC3597. + renderer.writeName(impl_->nextname_, false); + renderer.writeData(&impl_->typebits_[0], impl_->typebits_.size()); +} + +const Name& +NSEC::getNextName() const { + return (impl_->nextname_); +} + +int +NSEC::compare(const Rdata& other) const { + const NSEC& other_nsec = dynamic_cast<const NSEC&>(other); + + int cmp = compareNames(impl_->nextname_, other_nsec.impl_->nextname_); + if (cmp != 0) { + return (cmp); + } + + const size_t this_len = impl_->typebits_.size(); + const size_t other_len = other_nsec.impl_->typebits_.size(); + const size_t cmplen = min(this_len, other_len); + cmp = memcmp(&impl_->typebits_[0], &other_nsec.impl_->typebits_[0], + cmplen); + if (cmp != 0) { + return (cmp); + } else { + return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1); + } +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/nsec_47.h b/src/lib/dns/rdata/generic/nsec_47.h new file mode 100644 index 0000000..299d381 --- /dev/null +++ b/src/lib/dns/rdata/generic/nsec_47.h @@ -0,0 +1,53 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> + +// BEGIN_HEADER_GUARD + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct NSECImpl; + +class NSEC : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + NSEC& operator=(const NSEC& source); + ~NSEC(); + + // specialized methods + + /// Return the next domain name. + /// + /// \exception std::bad_alloc Resource allocation failure in name copy. + /// + /// \return The next domain name field in the form of \c Name object. + const Name& getNextName() const; + +private: + NSECImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/opt_41.cc b/src/lib/dns/rdata/generic/opt_41.cc new file mode 100644 index 0000000..40cb1c7 --- /dev/null +++ b/src/lib/dns/rdata/generic/opt_41.cc @@ -0,0 +1,219 @@ +// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#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&) : + impl_(NULL) +{ + isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text"); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// This constructor cannot be used, and always throws an exception. +/// +/// \throw InvalidRdataText OPT RR cannot be constructed from text. +OPT::OPT(MasterLexer&, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(NULL) +{ + isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text"); +} + +OPT::OPT(InputBuffer& buffer, size_t rdata_len) : + impl_(NULL) +{ + std::unique_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); + } + + OPTImpl* newimpl = new OPTImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +OPT::~OPT() { + delete impl_; +} + +std::string +OPT::toText() const { + isc_throw(isc::InvalidOperation, + "OPT RRs do not have a presentation format"); +} + +void +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& 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&) 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)); + if (length != 0) { + 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 new file mode 100644 index 0000000..0c00aed --- /dev/null +++ b/src/lib/dns/rdata/generic/opt_41.h @@ -0,0 +1,90 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/rdata.h> + +#include <boost/shared_ptr.hpp> + +#include <vector> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// 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& 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 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: + OPTImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/ptr_12.cc b/src/lib/dns/rdata/generic/ptr_12.cc new file mode 100644 index 0000000..b3596e8 --- /dev/null +++ b/src/lib/dns/rdata/generic/ptr_12.cc @@ -0,0 +1,123 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#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/lexer_util.h> + +using namespace std; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// The given string must represent a valid PTR 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 PTRDNAME must be absolute since there's no parameter that +/// specifies the origin name; if it is not absolute, \c +/// MissingNameOrigin exception will be thrown. These must not be +/// represented as a quoted string. +/// +/// \throw Others Exception from the Name and RRTTL constructors. +/// \throw InvalidRdataText Other general syntax errors. +PTR::PTR(const std::string& type_str) : + // Fill in dummy name and replace them soon below. + ptr_name_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(type_str); + MasterLexer lexer; + lexer.pushSource(ss); + + ptr_name_ = createNameFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for PTR: " + << type_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct PTR from '" << + type_str << "': " << ex.what()); + } +} + +PTR::PTR(InputBuffer& buffer, size_t) : + ptr_name_(buffer) +{ + // we don't need rdata_len for parsing. if necessary, the caller will + // check consistency. +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of a PTR RDATA. The PTRDNAME field can be +/// non-absolute if \c origin is non-NULL, in which case \c origin is +/// used to make it absolute. It must not be represented as a quoted +/// string. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of PTRDNAME when it +/// is non-absolute. +PTR::PTR(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + ptr_name_(createNameFromLexer(lexer, origin)) +{} + +PTR::PTR(const PTR& source) : + Rdata(), ptr_name_(source.ptr_name_) +{} + +std::string +PTR::toText() const { + return (ptr_name_.toText()); +} + +void +PTR::toWire(OutputBuffer& buffer) const { + ptr_name_.toWire(buffer); +} + +void +PTR::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(ptr_name_); +} + +int +PTR::compare(const Rdata& other) const { + // The compare method normally begins with this dynamic cast. + const PTR& other_ptr = dynamic_cast<const PTR&>(other); + + return (compareNames(ptr_name_, other_ptr.ptr_name_)); + +} + +const Name& +PTR::getPTRName() const { + return (ptr_name_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/ptr_12.h b/src/lib/dns/rdata/generic/ptr_12.h new file mode 100644 index 0000000..e562ef7 --- /dev/null +++ b/src/lib/dns/rdata/generic/ptr_12.h @@ -0,0 +1,44 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class PTR : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// + /// Specialized constructor + /// + explicit PTR(const Name& ptr_name) : ptr_name_(ptr_name) {} + /// + /// Specialized methods + /// + const Name& getPTRName() const; +private: + Name ptr_name_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/rp_17.cc b/src/lib/dns/rdata/generic/rp_17.cc new file mode 100644 index 0000000..43bf647 --- /dev/null +++ b/src/lib/dns/rdata/generic/rp_17.cc @@ -0,0 +1,160 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> +#include <sstream> + +#include <util/buffer.h> + +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/lexer_util.h> + +using namespace std; +using namespace isc::dns; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief Constructor from string. +/// +/// \c rp_str must be formatted as follows: +/// \code <mailbox name> <text name> +/// \endcode +/// where both fields must represent a valid domain name. +/// +/// \throw InvalidRdataText The number of RDATA fields (must be 2) is +/// incorrect. +/// \throw std::bad_alloc Memory allocation for names fails. +/// \throw Other The constructor of the \c Name class will throw if the +/// given name is invalid. +RP::RP(const std::string& rp_str) : + // We cannot construct both names in the initialization list due to the + // necessary text processing, so we have to initialize them with a dummy + // name and replace them later. + mailbox_(Name::ROOT_NAME()), text_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(rp_str); + MasterLexer lexer; + lexer.pushSource(ss); + + mailbox_ = createNameFromLexer(lexer, NULL); + text_ = createNameFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for RP: " + << rp_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct RP from '" << + rp_str << "': " << ex.what()); + } +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of an RP RDATA. The MAILBOX and TEXT fields can be non-absolute if \c +/// origin is non-NULL, in which case \c origin is used to make them absolute. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and constructors if construction of +/// textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of SERVER when it +/// is non-absolute. +RP::RP(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + mailbox_(createNameFromLexer(lexer, origin)), + text_(createNameFromLexer(lexer, origin)) +{ +} + +/// \brief Constructor from wire-format data. +/// +/// This constructor doesn't check the validity of the second parameter (rdata +/// length) for parsing. +/// If necessary, the caller will check consistency. +/// +/// \throw std::bad_alloc Memory allocation for names fails. +/// \throw Other The constructor of the \c Name class will throw if the +/// names in the wire is invalid. +RP::RP(InputBuffer& buffer, size_t) : mailbox_(buffer), text_(buffer) { +} + +/// \brief Copy constructor. +/// +/// \throw std::bad_alloc Memory allocation fails in copying internal +/// member variables (this should be very rare). +RP::RP(const RP& other) : + Rdata(), mailbox_(other.mailbox_), text_(other.text_) +{} + +/// \brief Convert the \c RP to a string. +/// +/// The output of this method is formatted as described in the "from string" +/// constructor (\c RP(const std::string&))). +/// +/// \throw std::bad_alloc Internal resource allocation fails. +/// +/// \return A \c string object that represents the \c RP object. +std::string +RP::toText() const { + return (mailbox_.toText() + " " + text_.toText()); +} + +/// \brief Render the \c RP in the wire format without name compression. +/// +/// \throw std::bad_alloc Internal resource allocation fails. +/// +/// \param buffer An output buffer to store the wire data. +void +RP::toWire(OutputBuffer& buffer) const { + mailbox_.toWire(buffer); + text_.toWire(buffer); +} + +/// \brief Render the \c RP in the wire format with taking into account +/// compression. +/// +// Type RP is not "well-known", and name compression must be disabled +// per RFC3597. +/// +/// \throw std::bad_alloc Internal resource allocation fails. +/// +/// \param renderer DNS message rendering context that encapsulates the +/// output buffer and name compression information. +void +RP::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(mailbox_, false); + renderer.writeName(text_, false); +} + +/// \brief Compare two instances of \c RP RDATA. +/// +/// See documentation in \c Rdata. +int +RP::compare(const Rdata& other) const { + const RP& other_rp = dynamic_cast<const RP&>(other); + + const int cmp = compareNames(mailbox_, other_rp.mailbox_); + if (cmp != 0) { + return (cmp); + } + return (compareNames(text_, other_rp.text_)); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/rp_17.h b/src/lib/dns/rdata/generic/rp_17.h new file mode 100644 index 0000000..9536ee9 --- /dev/null +++ b/src/lib/dns/rdata/generic/rp_17.h @@ -0,0 +1,78 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +/// \brief \c rdata::generic::RP class represents the RP RDATA as defined in +/// RFC1183. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// RP RDATA. +class RP : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// We use the default copy constructor and assignment operator. + + /// \brief Constructor from RDATA field parameters. + /// + /// The parameters are a straightforward mapping of %RP RDATA + /// fields as defined in RFC1183. + RP(const Name& mailbox, const Name& text) : + mailbox_(mailbox), text_(text) + {} + + /// \brief Return the value of the mailbox field. + /// + /// \throw std::bad_alloc If resource allocation for the returned + /// \c Name fails. + /// + /// \note + /// Unlike the case of some other RDATA classes (such as + /// \c NS::getNSName()), this method constructs a new \c Name object + /// and returns it, instead of returning a reference to a \c Name object + /// internally maintained in the class (which is a private member). + /// This is based on the observation that this method will be rarely used + /// and even when it's used it will not be in a performance context + /// (for example, a recursive resolver won't need this field in its + /// resolution process). By returning a new object we have flexibility of + /// changing the internal representation without the risk of changing + /// the interface or method property. + /// The same note applies to the \c getText() method. + Name getMailbox() const { return (mailbox_); } + + /// \brief Return the value of the text field. + /// + /// \throw std::bad_alloc If resource allocation for the returned + /// \c Name fails. + Name getText() const { return (text_); } + +private: + Name mailbox_; + Name text_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/rrsig_46.cc b/src/lib/dns/rdata/generic/rrsig_46.cc new file mode 100644 index 0000000..de92c67 --- /dev/null +++ b/src/lib/dns/rdata/generic/rrsig_46.cc @@ -0,0 +1,334 @@ +// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <vector> + +#include <boost/lexical_cast.hpp> + +#include <util/encode/base64.h> +#include <util/buffer.h> +#include <util/time_utilities.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/lexer_util.h> + +#include <stdio.h> +#include <time.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +namespace { +// This is the minimum necessary length of all wire-format RRSIG RDATA: +// - two 8-bit fields (algorithm and labels) +// - two 16-bit fields (covered and tag) +// - three 32-bit fields (original TTL, expire and inception) +const size_t RRSIG_MINIMUM_LEN = 2 * sizeof(uint8_t) + 2 * sizeof(uint16_t) + + 3 * sizeof(uint32_t); +} + +struct RRSIGImpl { + // straightforward representation of RRSIG RDATA fields + RRSIGImpl(const RRType& covered, uint8_t algorithm, uint8_t labels, + uint32_t originalttl, uint32_t timeexpire, + uint32_t timeinception, uint16_t tag, const Name& signer, + const vector<uint8_t>& signature) : + covered_(covered), algorithm_(algorithm), labels_(labels), + originalttl_(originalttl), timeexpire_(timeexpire), + timeinception_(timeinception), tag_(tag), signer_(signer), + signature_(signature) + {} + + const RRType covered_; + uint8_t algorithm_; + uint8_t labels_; + uint32_t originalttl_; + uint32_t timeexpire_; + uint32_t timeinception_; + uint16_t tag_; + const Name signer_; + const vector<uint8_t> signature_; +}; + +// helper function for string and lexer constructors +RRSIGImpl* +RRSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) { + const RRType covered(lexer.getNextToken(MasterToken::STRING).getString()); + const uint32_t algorithm = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (algorithm > 0xff) { + isc_throw(InvalidRdataText, "RRSIG algorithm out of range"); + } + const uint32_t labels = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (labels > 0xff) { + isc_throw(InvalidRdataText, "RRSIG labels out of range"); + } + const uint32_t originalttl = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + const uint32_t timeexpire = + timeFromText32(lexer.getNextToken(MasterToken::STRING).getString()); + const uint32_t timeinception = + timeFromText32(lexer.getNextToken(MasterToken::STRING).getString()); + const uint32_t tag = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (tag > 0xffff) { + isc_throw(InvalidRdataText, "RRSIG key tag out of range"); + } + const Name& signer = createNameFromLexer(lexer, origin); + + string signature_txt; + string signature_part; + // Whitespace is allowed within base64 text, so read to the end of input. + while (true) { + const MasterToken& token = + lexer.getNextToken(MasterToken::STRING, true); + if ((token.getType() == MasterToken::END_OF_FILE) || + (token.getType() == MasterToken::END_OF_LINE)) { + break; + } + token.getString(signature_part); + signature_txt.append(signature_part); + } + lexer.ungetToken(); + + vector<uint8_t> signature; + // missing signature is okay + if (signature_txt.size() > 0) { + decodeBase64(signature_txt, signature); + } + + return (new RRSIGImpl(covered, algorithm, labels, + originalttl, timeexpire, timeinception, + static_cast<uint16_t>(tag), signer, signature)); +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid RRSIG RDATA. There can be extra +/// space characters at the beginning or end of the text (which are simply +/// ignored), but other extra text, including a new line, will make the +/// construction fail with an exception. +/// +/// The Signer's Name must be absolute since there's no parameter that +/// specifies the origin name; if this is not absolute, \c MissingNameOrigin +/// exception will be thrown. This must not be represented as a quoted +/// string. +/// +/// See the construction that takes \c MasterLexer for other fields. +/// +/// \throw Others Exception from the Name constructor. +/// \throw InvalidRdataText Other general syntax errors. +RRSIG::RRSIG(const std::string& rrsig_str) : + impl_(NULL) +{ + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the RRSIGImpl that constructFromLexer() returns. + std::unique_ptr<RRSIGImpl> impl_ptr; + + try { + std::istringstream iss(rrsig_str); + MasterLexer lexer; + lexer.pushSource(iss); + + impl_ptr.reset(constructFromLexer(lexer, NULL)); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for RRSIG: " + << rrsig_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct RRSIG from '" << + rrsig_str << "': " << ex.what()); + } + + impl_ = impl_ptr.release(); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of an RRSIG RDATA. The Signer's Name fields can be non absolute if \c +/// origin is non NULL, in which case \c origin is used to make it absolute. +/// This must not be represented as a quoted string. +/// +/// The Original TTL field is a valid decimal representation of an unsigned +/// 32-bit integer. Note that alternate textual representations of \c RRTTL, +/// such as "1H" for 3600 seconds, are not allowed here. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name constructor if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of Signer's Name when +/// it is non absolute. +RRSIG::RRSIG(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer, origin)) +{ +} + +RRSIG::RRSIG(InputBuffer& buffer, size_t rdata_len) { + size_t pos = buffer.getPosition(); + + if (rdata_len < RRSIG_MINIMUM_LEN) { + isc_throw(InvalidRdataLength, "RRSIG too short"); + } + + RRType covered(buffer); + uint8_t algorithm = buffer.readUint8(); + uint8_t labels = buffer.readUint8(); + uint32_t originalttl = buffer.readUint32(); + uint32_t timeexpire = buffer.readUint32(); + uint32_t timeinception = buffer.readUint32(); + uint16_t tag = buffer.readUint16(); + Name signer(buffer); + + // rdata_len must be sufficiently large to hold non empty signature data. + if (rdata_len <= buffer.getPosition() - pos) { + isc_throw(InvalidRdataLength, "RRSIG too short"); + } + rdata_len -= (buffer.getPosition() - pos); + + vector<uint8_t> signature(rdata_len); + buffer.readData(&signature[0], rdata_len); + + impl_ = new RRSIGImpl(covered, algorithm, labels, + originalttl, timeexpire, timeinception, tag, + signer, signature); +} + +RRSIG::RRSIG(const RRSIG& source) : + Rdata(), impl_(new RRSIGImpl(*source.impl_)) +{} + +RRSIG& +RRSIG::operator=(const RRSIG& source) { + if (this == &source) { + return (*this); + } + + RRSIGImpl* newimpl = new RRSIGImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +RRSIG::~RRSIG() { + delete impl_; +} + +string +RRSIG::toText() const { + return (impl_->covered_.toText() + + " " + boost::lexical_cast<string>(static_cast<int>(impl_->algorithm_)) + + " " + boost::lexical_cast<string>(static_cast<int>(impl_->labels_)) + + " " + boost::lexical_cast<string>(impl_->originalttl_) + + " " + timeToText32(impl_->timeexpire_) + + " " + timeToText32(impl_->timeinception_) + + " " + boost::lexical_cast<string>(impl_->tag_) + + " " + impl_->signer_.toText() + + " " + encodeBase64(impl_->signature_)); +} + +void +RRSIG::toWire(OutputBuffer& buffer) const { + impl_->covered_.toWire(buffer); + buffer.writeUint8(impl_->algorithm_); + buffer.writeUint8(impl_->labels_); + buffer.writeUint32(impl_->originalttl_); + buffer.writeUint32(impl_->timeexpire_); + buffer.writeUint32(impl_->timeinception_); + buffer.writeUint16(impl_->tag_); + impl_->signer_.toWire(buffer); + buffer.writeData(&impl_->signature_[0], impl_->signature_.size()); +} + +void +RRSIG::toWire(AbstractMessageRenderer& renderer) const { + impl_->covered_.toWire(renderer); + renderer.writeUint8(impl_->algorithm_); + renderer.writeUint8(impl_->labels_); + renderer.writeUint32(impl_->originalttl_); + renderer.writeUint32(impl_->timeexpire_); + renderer.writeUint32(impl_->timeinception_); + renderer.writeUint16(impl_->tag_); + renderer.writeName(impl_->signer_, false); + renderer.writeData(&impl_->signature_[0], impl_->signature_.size()); +} + +int +RRSIG::compare(const Rdata& other) const { + const RRSIG& other_rrsig = dynamic_cast<const RRSIG&>(other); + + if (impl_->covered_.getCode() != other_rrsig.impl_->covered_.getCode()) { + return (impl_->covered_.getCode() < + other_rrsig.impl_->covered_.getCode() ? -1 : 1); + } + if (impl_->algorithm_ != other_rrsig.impl_->algorithm_) { + return (impl_->algorithm_ < other_rrsig.impl_->algorithm_ ? -1 : 1); + } + if (impl_->labels_ != other_rrsig.impl_->labels_) { + return (impl_->labels_ < other_rrsig.impl_->labels_ ? -1 : 1); + } + if (impl_->originalttl_ != other_rrsig.impl_->originalttl_) { + return (impl_->originalttl_ < other_rrsig.impl_->originalttl_ ? + -1 : 1); + } + if (impl_->timeexpire_ != other_rrsig.impl_->timeexpire_) { + return (impl_->timeexpire_ < other_rrsig.impl_->timeexpire_ ? + -1 : 1); + } + if (impl_->timeinception_ != other_rrsig.impl_->timeinception_) { + return (impl_->timeinception_ < other_rrsig.impl_->timeinception_ ? + -1 : 1); + } + if (impl_->tag_ != other_rrsig.impl_->tag_) { + return (impl_->tag_ < other_rrsig.impl_->tag_ ? -1 : 1); + } + + int cmp = compareNames(impl_->signer_, other_rrsig.impl_->signer_); + if (cmp != 0) { + return (cmp); + } + + size_t this_len = impl_->signature_.size(); + size_t other_len = other_rrsig.impl_->signature_.size(); + size_t cmplen = min(this_len, other_len); + cmp = memcmp(&impl_->signature_[0], &other_rrsig.impl_->signature_[0], + cmplen); + if (cmp != 0) { + return (cmp); + } else { + return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1); + } +} + +const RRType& +RRSIG::typeCovered() const { + return (impl_->covered_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/rrsig_46.h b/src/lib/dns/rdata/generic/rrsig_46.h new file mode 100644 index 0000000..aca26ba --- /dev/null +++ b/src/lib/dns/rdata/generic/rrsig_46.h @@ -0,0 +1,54 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rdata.h> + +// BEGIN_HEADER_GUARD + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct RRSIGImpl; + +/// \brief \c rdata::RRSIG class represents the RRSIG RDATA as defined %in +/// RFC4034. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// RRSIG RDATA. +class RRSIG : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + RRSIG& operator=(const RRSIG& source); + ~RRSIG(); + + // specialized methods + const RRType& typeCovered() const; +private: + // helper function for string and lexer constructors + RRSIGImpl* constructFromLexer(MasterLexer& lexer, const Name* origin); + + RRSIGImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/soa_6.cc b/src/lib/dns/rdata/generic/soa_6.cc new file mode 100644 index 0000000..ee4e43d --- /dev/null +++ b/src/lib/dns/rdata/generic/soa_6.cc @@ -0,0 +1,210 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <dns/name.h> +#include <dns/master_lexer.h> +#include <dns/master_loader.h> +#include <dns/master_loader_callbacks.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +#include <dns/rdata/generic/detail/lexer_util.h> + +#include <boost/static_assert.hpp> +#include <boost/lexical_cast.hpp> + +#include <string> +#include <sstream> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +SOA::SOA(InputBuffer& buffer, size_t) : + mname_(buffer), rname_(buffer) +{ + // we don't need rdata_len for parsing. if necessary, the caller will + // check consistency. + buffer.readData(numdata_, sizeof(numdata_)); +} + +namespace { +void +fillParameters(MasterLexer& lexer, uint8_t numdata[20]) { + // Copy serial, refresh, retry, expire, minimum. We accept the extended + // TTL-compatible style for the latter four. + OutputBuffer buffer(20); + buffer.writeUint32(lexer.getNextToken(MasterToken::NUMBER).getNumber()); + for (int i = 0; i < 4; ++i) { + buffer.writeUint32(RRTTL(lexer.getNextToken(MasterToken::STRING). + getString()).getValue()); + } + memcpy(numdata, buffer.getData(), buffer.getLength()); +} +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid SOA 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 MNAME and RNAME must be absolute since there's no parameter that +/// specifies the origin name; if these are not absolute, \c MissingNameOrigin +/// exception will be thrown. These must not be represented as a quoted +/// string. +/// +/// See the construction that takes \c MasterLexer for other fields. +/// +/// \throw Others Exception from the Name and RRTTL constructors. +/// \throw InvalidRdataText Other general syntax errors. +SOA::SOA(const std::string& soastr) : + // Fill in dummy name and replace them soon below. + mname_(Name::ROOT_NAME()), rname_(Name::ROOT_NAME()) +{ + try { + std::istringstream ss(soastr); + MasterLexer lexer; + lexer.pushSource(ss); + + mname_ = createNameFromLexer(lexer, NULL); + rname_ = createNameFromLexer(lexer, NULL); + fillParameters(lexer, numdata_); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for SOA: " + << soastr); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct SOA from '" << + soastr << "': " << ex.what()); + } +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of an SOA RDATA. The MNAME and RNAME fields can be non absolute if +/// \c origin is non NULL, in which case \c origin is used to make them +/// absolute. These must not be represented as a quoted string. +/// +/// The REFRESH, RETRY, EXPIRE, and MINIMUM fields can be either a valid +/// decimal representation of an unsigned 32-bit integer or other +/// valid textual representation of \c RRTTL such as "1H" (which means 3600). +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of MNAME and RNAME when +/// they are non absolute. +SOA::SOA(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + mname_(createNameFromLexer(lexer, origin)), + rname_(createNameFromLexer(lexer, origin)) +{ + fillParameters(lexer, numdata_); +} + +SOA::SOA(const Name& mname, const Name& rname, uint32_t serial, + uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) : + mname_(mname), rname_(rname) +{ + OutputBuffer b(20); + b.writeUint32(serial); + b.writeUint32(refresh); + b.writeUint32(retry); + b.writeUint32(expire); + b.writeUint32(minimum); + assert(b.getLength() == sizeof(numdata_)); + memcpy(numdata_, b.getData(), sizeof(numdata_)); +} + +SOA::SOA(const SOA& other) : + Rdata(), mname_(other.mname_), rname_(other.rname_) +{ + memcpy(numdata_, other.numdata_, sizeof(numdata_)); +} + +void +SOA::toWire(OutputBuffer& buffer) const { + mname_.toWire(buffer); + rname_.toWire(buffer); + buffer.writeData(numdata_, sizeof(numdata_)); +} + +void +SOA::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(mname_); + renderer.writeName(rname_); + renderer.writeData(numdata_, sizeof(numdata_)); +} + +Serial +SOA::getSerial() const { + InputBuffer b(numdata_, sizeof(numdata_)); + return (Serial(b.readUint32())); +} + +uint32_t +SOA::getMinimum() const { + // Make sure the buffer access is safe. + BOOST_STATIC_ASSERT(sizeof(numdata_) == + sizeof(uint32_t) * 4 + sizeof(uint32_t)); + + InputBuffer b(&numdata_[sizeof(uint32_t) * 4], sizeof(uint32_t)); + return (b.readUint32()); +} + +string +SOA::toText() const { + InputBuffer b(numdata_, sizeof(numdata_)); + uint32_t serial = b.readUint32(); + uint32_t refresh = b.readUint32(); + uint32_t retry = b.readUint32(); + uint32_t expire = b.readUint32(); + uint32_t minimum = b.readUint32(); + + return (mname_.toText() + " " + rname_.toText() + " " + + lexical_cast<string>(serial) + " " + + lexical_cast<string>(refresh) + " " + + lexical_cast<string>(retry) + " " + + lexical_cast<string>(expire) + " " + + lexical_cast<string>(minimum)); +} + +int +SOA::compare(const Rdata& other) const { + const SOA& other_soa = dynamic_cast<const SOA&>(other); + + int order = compareNames(mname_, other_soa.mname_); + if (order != 0) { + return (order); + } + + order = compareNames(rname_, other_soa.rname_); + if (order != 0) { + return (order); + } + + return (memcmp(numdata_, other_soa.numdata_, sizeof(numdata_))); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/soa_6.h b/src/lib/dns/rdata/generic/soa_6.h new file mode 100644 index 0000000..50a062e --- /dev/null +++ b/src/lib/dns/rdata/generic/soa_6.h @@ -0,0 +1,51 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/serial.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class SOA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + SOA(const Name& mname, const Name& rname, uint32_t serial, + uint32_t refresh, uint32_t retry, uint32_t expire, + uint32_t minimum); + + /// \brief Returns the serial stored in the SOA. + Serial getSerial() const; + + /// brief Returns the minimum TTL field value of the SOA. + uint32_t getMinimum() const; +private: + /// Note: this is a prototype version; we may reconsider + /// this representation later. + Name mname_; + Name rname_; + /// serial, refresh, retry, expire, minimum, stored in network byte order + uint8_t numdata_[20]; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/spf_99.cc b/src/lib/dns/rdata/generic/spf_99.cc new file mode 100644 index 0000000..f25585a --- /dev/null +++ b/src/lib/dns/rdata/generic/spf_99.cc @@ -0,0 +1,139 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <stdint.h> +#include <string.h> + +#include <string> +#include <vector> + +#include <util/buffer.h> +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class. The semantics of the class is provided by +/// a copy of instantiated TXTLikeImpl class common to both TXT and SPF. +#include <dns/rdata/generic/detail/txt_like.h> + +using namespace std; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +/// \brief The assignment operator +/// +/// It internally allocates a resource, and if it fails a corresponding +/// standard exception will be thrown. +/// This method never throws an exception otherwise. +SPF& +SPF::operator=(const SPF& source) { + if (this == &source) { + return (*this); + } + + SPFImpl* newimpl = new SPFImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +/// \brief The destructor +SPF::~SPF() { + delete impl_; +} + +/// \brief Constructor from wire-format data. +/// +/// It internally allocates a resource, and if it fails a corresponding +/// standard exception will be thrown. +SPF::SPF(InputBuffer& buffer, size_t rdata_len) : + impl_(new SPFImpl(buffer, rdata_len)) +{} + +/// \brief Constructor using the master lexer. +/// +/// This implementation only uses the \c lexer parameters; others are +/// ignored. +/// +/// \throw CharStringTooLong the parameter string length exceeds maximum. +/// \throw InvalidRdataText the method cannot process the parameter data +/// +/// \param lexer A \c MasterLexer object parsing a master file for this +/// RDATA. +SPF::SPF(MasterLexer& lexer, const Name*, MasterLoader::Options, + MasterLoaderCallbacks&) : + impl_(new SPFImpl(lexer)) +{} + +/// \brief Constructor from string. +/// +/// It internally allocates a resource, and if it fails a corresponding +/// standard exception will be thrown. +SPF::SPF(const std::string& txtstr) : + impl_(new SPFImpl(txtstr)) +{} + +/// \brief Copy constructor +/// +/// It internally allocates a resource, and if it fails a corresponding +/// standard exception will be thrown. +SPF::SPF(const SPF& other) : + Rdata(), impl_(new SPFImpl(*other.impl_)) +{} + +/// \brief Render the \c SPF in the wire format to a OutputBuffer object +/// +/// \return is the return of the corresponding implementation method. +void +SPF::toWire(OutputBuffer& buffer) const { + impl_->toWire(buffer); +} + +/// \brief Render the \c SPF in the wire format to an AbstractMessageRenderer +/// object +/// +/// \return is the return of the corresponding implementation method. +void +SPF::toWire(AbstractMessageRenderer& renderer) const { + impl_->toWire(renderer); +} + +/// \brief Convert the \c SPF to a string. +/// +/// \return is the return of the corresponding implementation method. +string +SPF::toText() const { + return (impl_->toText()); +} + +/// \brief Compare two instances of \c SPF RDATA. +/// +/// This method compares \c this and the \c other \c SPF objects. +/// +/// This method is expected to be used in a polymorphic way, and the +/// parameter to compare against is therefore of the abstract \c Rdata class. +/// However, comparing two \c Rdata objects of different RR types +/// is meaningless, and \c other must point to a \c SPF object; +/// otherwise, the standard \c bad_cast exception will be thrown. +/// +/// \param other the right-hand operand to compare against. +/// \return is the return of the corresponding implementation method. +int +SPF::compare(const Rdata& other) const { + const SPF& other_txt = dynamic_cast<const SPF&>(other); + + return (impl_->compare(*other_txt.impl_)); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/spf_99.h b/src/lib/dns/rdata/generic/spf_99.h new file mode 100644 index 0000000..3a84d9d --- /dev/null +++ b/src/lib/dns/rdata/generic/spf_99.h @@ -0,0 +1,72 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +namespace detail { +template<class Type, uint16_t typeCode> class TXTLikeImpl; +} + +/// \brief \c rdata::SPF class represents the SPF RDATA as defined %in +/// RFC4408. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class. The semantics of the class is provided by +/// a copy of instantiated TXTLikeImpl class common to both TXT and SPF. +class SPF : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Assignment operator. + /// + /// It internally allocates a resource, and if it fails a corresponding + /// standard exception will be thrown. + /// This operator never throws an exception otherwise. + /// + /// This operator provides the strong exception guarantee: When an + /// exception is thrown the content of the assignment target will be + /// intact. + SPF& operator=(const SPF& source); + + /// \brief The destructor. + ~SPF(); + + /// + /// Specialized methods + /// + + /// \brief Return a reference to the data strings + /// + /// This method never throws an exception. + const std::vector<std::vector<uint8_t> >& getString() const; + +private: + typedef isc::dns::rdata::generic::detail::TXTLikeImpl<SPF, 99> SPFImpl; + SPFImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/sshfp_44.cc b/src/lib/dns/rdata/generic/sshfp_44.cc new file mode 100644 index 0000000..a08a17f --- /dev/null +++ b/src/lib/dns/rdata/generic/sshfp_44.cc @@ -0,0 +1,298 @@ +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#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> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using namespace isc::util::encode; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct SSHFPImpl { + // straightforward representation of SSHFP RDATA fields + SSHFPImpl(uint8_t algorithm, uint8_t fingerprint_type, + const vector<uint8_t>& fingerprint) : + algorithm_(algorithm), + fingerprint_type_(fingerprint_type), + fingerprint_(fingerprint) + {} + + uint8_t algorithm_; + uint8_t fingerprint_type_; + const vector<uint8_t> fingerprint_; +}; + +// helper function for string and lexer constructors +SSHFPImpl* +SSHFP::constructFromLexer(MasterLexer& lexer) { + const uint32_t algorithm = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (algorithm > 255) { + isc_throw(InvalidRdataText, "SSHFP algorithm number out of range"); + } + + const uint32_t fingerprint_type = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (fingerprint_type > 255) { + isc_throw(InvalidRdataText, "SSHFP fingerprint type out of range"); + } + + std::string fingerprint_str; + std::string fingerprint_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(fingerprint_substr); + fingerprint_str.append(fingerprint_substr); + } + lexer.ungetToken(); + + vector<uint8_t> fingerprint; + // If fingerprint is missing, it's OK. See the API documentation of the + // constructor. + if (fingerprint_str.size() > 0) { + 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)); +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid SSHFP 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 Algorithm and Fingerprint Type fields must be within their valid +/// ranges, but are not constrained to the values defined in RFC4255. +/// +/// The Fingerprint field may be absent, but if present it must contain a +/// 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, 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) : + impl_(NULL) +{ + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the SSHFPImpl that constructFromLexer() returns. + std::unique_ptr<SSHFPImpl> impl_ptr; + + try { + std::istringstream ss(sshfp_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 SSHFP: " + << sshfp_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct SSHFP from '" << + sshfp_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 SSHFP RDATA. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \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 +SSHFP::SSHFP(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer)) +{ +} + +/// \brief Constructor from InputBuffer. +/// +/// The passed buffer must contain a valid SSHFP RDATA. +/// +/// The Algorithm and Fingerprint Type fields are not checked for unknown +/// values. It is okay for the fingerprint data to be missing (see the +/// description of the constructor from string). +SSHFP::SSHFP(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len < 2) { + isc_throw(InvalidRdataLength, "SSHFP record too short"); + } + + const uint8_t algorithm = buffer.readUint8(); + const uint8_t fingerprint_type = buffer.readUint8(); + + vector<uint8_t> fingerprint; + rdata_len -= 2; + if (rdata_len > 0) { + fingerprint.resize(rdata_len); + buffer.readData(&fingerprint[0], rdata_len); + } + + impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint); +} + +SSHFP::SSHFP(uint8_t algorithm, uint8_t fingerprint_type, + const string& fingerprint_txt) : + impl_(NULL) +{ + vector<uint8_t> fingerprint; + try { + decodeHex(fingerprint_txt, fingerprint); + } catch (const isc::BadValue& e) { + isc_throw(InvalidRdataText, "Bad SSHFP fingerprint: " << e.what()); + } + + impl_ = new SSHFPImpl(algorithm, fingerprint_type, fingerprint); +} + +SSHFP::SSHFP(const SSHFP& other) : + Rdata(), impl_(new SSHFPImpl(*other.impl_)) +{} + +SSHFP& +SSHFP::operator=(const SSHFP& source) { + if (this == &source) { + return (*this); + } + + SSHFPImpl* newimpl = new SSHFPImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +SSHFP::~SSHFP() { + delete impl_; +} + +void +SSHFP::toWire(OutputBuffer& buffer) const { + buffer.writeUint8(impl_->algorithm_); + buffer.writeUint8(impl_->fingerprint_type_); + + if (!impl_->fingerprint_.empty()) { + buffer.writeData(&impl_->fingerprint_[0], + impl_->fingerprint_.size()); + } +} + +void +SSHFP::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeUint8(impl_->algorithm_); + renderer.writeUint8(impl_->fingerprint_type_); + + if (!impl_->fingerprint_.empty()) { + renderer.writeData(&impl_->fingerprint_[0], + impl_->fingerprint_.size()); + } +} + +string +SSHFP::toText() const { + return (lexical_cast<string>(static_cast<int>(impl_->algorithm_)) + " " + + lexical_cast<string>(static_cast<int>(impl_->fingerprint_type_)) + + (impl_->fingerprint_.empty() ? "" : + " " + encodeHex(impl_->fingerprint_))); +} + +int +SSHFP::compare(const Rdata& other) const { + const SSHFP& other_sshfp = dynamic_cast<const SSHFP&>(other); + + if (impl_->algorithm_ < other_sshfp.impl_->algorithm_) { + return (-1); + } else if (impl_->algorithm_ > other_sshfp.impl_->algorithm_) { + return (1); + } + + if (impl_->fingerprint_type_ < other_sshfp.impl_->fingerprint_type_) { + return (-1); + } else if (impl_->fingerprint_type_ > + other_sshfp.impl_->fingerprint_type_) { + return (1); + } + + const size_t this_len = impl_->fingerprint_.size(); + const size_t other_len = other_sshfp.impl_->fingerprint_.size(); + const size_t cmplen = min(this_len, other_len); + + if (cmplen > 0) { + const int cmp = memcmp(&impl_->fingerprint_[0], + &other_sshfp.impl_->fingerprint_[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 +SSHFP::getAlgorithmNumber() const { + return (impl_->algorithm_); +} + +uint8_t +SSHFP::getFingerprintType() const { + return (impl_->fingerprint_type_); +} + +const std::vector<uint8_t>& +SSHFP::getFingerprint() const { + return (impl_->fingerprint_); +} + +size_t +SSHFP::getFingerprintLength() const { + return (impl_->fingerprint_.size()); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/sshfp_44.h b/src/lib/dns/rdata/generic/sshfp_44.h new file mode 100644 index 0000000..4eae696 --- /dev/null +++ b/src/lib/dns/rdata/generic/sshfp_44.h @@ -0,0 +1,56 @@ +// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct SSHFPImpl; + +class SSHFP : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + SSHFP(uint8_t algorithm, uint8_t fingerprint_type, + const std::string& fingerprint); + SSHFP& operator=(const SSHFP& source); + ~SSHFP(); + + /// + /// Specialized methods + /// + uint8_t getAlgorithmNumber() const; + uint8_t getFingerprintType() const; + const std::vector<uint8_t>& getFingerprint() const; + size_t getFingerprintLength() const; + +private: + SSHFPImpl* constructFromLexer(MasterLexer& lexer); + + SSHFPImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/generic/tkey_249.cc b/src/lib/dns/rdata/generic/tkey_249.cc new file mode 100644 index 0000000..435a345 --- /dev/null +++ b/src/lib/dns/rdata/generic/tkey_249.cc @@ -0,0 +1,613 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> +#include <sstream> +#include <vector> + +#include <boost/lexical_cast.hpp> + +#include <util/buffer.h> +#include <util/encode/base64.h> +#include <util/time_utilities.h> + +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rcode.h> +#include <dns/rdata/generic/detail/lexer_util.h> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; +using namespace isc::util::encode; +using namespace isc::dns; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +const uint16_t TKEY::GSS_API_MODE = 3; + +// straightforward representation of TKEY RDATA fields +struct TKEYImpl { + /// \brief Constructor from RDATA field parameters. + /// + /// \param algorithm The DNS name of the algorithm e.g. gss-tsig. + /// \param inception The inception time (in seconds since 1970). + /// \param expire The expire time (in seconds since 1970). + /// \param mode The mode e.g. Diffie-Hellman (2) or GSS-API (3). + /// \param error The error code (extended error space shared with TSIG). + /// \param key The key (can be empty). + /// \param other_data The other data (can be and usually is empty). + TKEYImpl(const Name& algorithm, uint32_t inception, uint32_t expire, + uint16_t mode, uint16_t error, vector<uint8_t>& key, + vector<uint8_t>& other_data) : + algorithm_(algorithm), inception_(inception), expire_(expire), + mode_(mode), error_(error), key_(key), other_data_(other_data) + {} + + /// \brief Constructor from RDATA field parameters. + /// + /// \param algorithm The DNS name of the algorithm e.g. gss-tsig. + /// \param inception The inception time (in seconds since 1970). + /// \param expire The expire time (in seconds since 1970). + /// \param mode The mode e.g. Diffie-Hellman (2) or GSS-API (3). + /// \param error The error code (extended error space shared with TSIG). + /// \param key_len The key length (0 means no key). + /// \param key The key (can be 0). + /// \param other_len The other data length (0 means no other data). + /// \param other_data The other data (can be and usually is 0). + TKEYImpl(const Name& algorithm, uint32_t inception, uint32_t expire, + uint16_t mode, uint16_t error, size_t key_len, + const void* key, size_t other_len, const void* other_data) : + algorithm_(algorithm), inception_(inception), expire_(expire), + mode_(mode), error_(error), + key_(key_len > 0 ? + vector<uint8_t>(static_cast<const uint8_t*>(key), + static_cast<const uint8_t*>(key) + key_len) : + vector<uint8_t>(key_len)), + other_data_(other_len > 0 ? + vector<uint8_t>(static_cast<const uint8_t*>(other_data), + static_cast<const uint8_t*>(other_data) + + other_len) : + vector<uint8_t>(other_len)) + {} + + /// \brief Common part of toWire methods. + /// \tparam Output \c OutputBuffer or \c AbstractMessageRenderer. + template <typename Output> + void toWireCommon(Output& output) const; + + /// \brief The DNS name of the algorithm e.g. gss-tsig. + const Name algorithm_; + + /// \brief The inception time (in seconds since 1970). + const uint32_t inception_; + + /// \brief The expire time (in seconds since 1970). + const uint32_t expire_; + + /// \brief The mode e.g. Diffie-Hellman (2) or GSS-API (3). + const uint16_t mode_; + + /// \brief The error code (extended error space shared with TSIG). + const uint16_t error_; + + /// \brief The key (can be empty). + const vector<uint8_t> key_; + + /// \brief The other data (can be and usually is empty). + const vector<uint8_t> other_data_; +}; + +// helper function for string and lexer constructors +TKEYImpl* +TKEY::constructFromLexer(MasterLexer& lexer, const Name* origin) { + const Name& algorithm = + createNameFromLexer(lexer, origin ? origin : &Name::ROOT_NAME()); + + const uint32_t inception = + timeFromText32(lexer.getNextToken(MasterToken::STRING).getString()); + + const uint32_t expire = + timeFromText32(lexer.getNextToken(MasterToken::STRING).getString()); + + /// The mode is either a mnemonic (only one is defined: GSS-API) or + /// a number. + const string& mode_txt = + lexer.getNextToken(MasterToken::STRING).getString(); + uint32_t mode = 0; + if (mode_txt == "GSS-API") { + mode = GSS_API_MODE; + } else { + /// we cast to uint32_t and range-check, because casting directly to + /// uint16_t will convert negative numbers to large positive numbers + try { + mode = boost::lexical_cast<uint32_t>(mode_txt); + } catch (const boost::bad_lexical_cast&) { + isc_throw(InvalidRdataText, "Invalid TKEY Mode"); + } + if (mode > 0xffff) { + isc_throw(InvalidRdataText, "TKEY Mode out of range"); + } + } + + const string& error_txt = + lexer.getNextToken(MasterToken::STRING).getString(); + uint32_t error = 0; + // XXX: In the initial implementation we hardcode the mnemonics. + // We'll soon generalize this. + if (error_txt == "NOERROR") { + error = Rcode::NOERROR_CODE; + } else if (error_txt == "BADSIG") { + error = TSIGError::BAD_SIG_CODE; + } else if (error_txt == "BADKEY") { + error = TSIGError::BAD_KEY_CODE; + } else if (error_txt == "BADTIME") { + error = TSIGError::BAD_TIME_CODE; + } else if (error_txt == "BADMODE") { + error = TSIGError::BAD_MODE_CODE; + } else if (error_txt == "BADNAME") { + error = TSIGError::BAD_NAME_CODE; + } else if (error_txt == "BADALG") { + error = TSIGError::BAD_ALG_CODE; + } else if (error_txt == "BADTRUNC") { + error = TSIGError::BAD_TRUNC_CODE; + } else { + /// we cast to uint32_t and range-check, because casting directly to + /// uint16_t will convert negative numbers to large positive numbers + try { + error = boost::lexical_cast<uint32_t>(error_txt); + } catch (const boost::bad_lexical_cast&) { + isc_throw(InvalidRdataText, "Invalid TKEY Error"); + } + if (error > 0xffff) { + isc_throw(InvalidRdataText, "TKEY Error out of range"); + } + } + + const uint32_t keylen = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (keylen > 0xffff) { + isc_throw(InvalidRdataText, "TKEY Key Len out of range"); + } + const string keydata_txt = (keylen > 0) ? + lexer.getNextToken(MasterToken::STRING).getString() : ""; + vector<uint8_t> key_data; + decodeBase64(keydata_txt, key_data); + if (key_data.size() != keylen) { + isc_throw(InvalidRdataText, + "TKEY Key Data length does not match Other Len"); + } + + const uint32_t otherlen = + lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (otherlen > 0xffff) { + isc_throw(InvalidRdataText, "TKEY Other Len out of range"); + } + const string otherdata_txt = (otherlen > 0) ? + lexer.getNextToken(MasterToken::STRING).getString() : ""; + vector<uint8_t> other_data; + decodeBase64(otherdata_txt, other_data); + if (other_data.size() != otherlen) { + isc_throw(InvalidRdataText, + "TKEY Other Data length does not match Other Len"); + } + // RFC2845 says Other Data is "empty unless Error == BADTIME". + // However, we don't enforce that. + + return (new TKEYImpl(algorithm, inception, expire, mode, error, + key_data, other_data)); +} + +/// \brief Constructor from string. +/// +/// The given string must represent a valid TKEY 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. +/// +/// \c tkey_str must be formatted as follows: +/// \code <Algorithm Name> <Inception> <Expire> <Mode> <Error> +/// <Key Len> [<Key Data>] <Other Len> [<Other Data>] +/// \endcode +/// +/// Note that, since the Algorithm Name field is defined to be "in domain name +/// syntax", but it is not actually a domain name, it does not have to be +/// fully qualified. +/// +/// The Mode field is an unsigned 16-bit decimal integer as specified +/// in RFC2930 or a common mnemonic. Currently only "GSS-API" (case sensitive) +/// is supported ("Diffie-Hellman" is not). +/// +/// The Error field is an unsigned 16-bit decimal integer or a valid mnemonic +/// as specified in RFC2845. Currently, "NOERROR", "BADSIG", "BADKEY", +/// "BADTIME", "BADMODE", "BADNAME", and "BADALG" are supported +/// (case sensitive). In future versions other representations that +/// are compatible with the DNS RCODE may be supported. +/// +/// The Key Data and Other Data fields are base-64 encoded strings that do not +/// contain space characters. +/// If the Key Len field is 0, the Key Data field must not appear in +/// \c tkey_str. +/// If the Other Len field is 0, the Other Data field must not appear in +/// \c tkey_str. +/// The decoded data of the Key Data field is Key Len bytes of binary stream. +/// The decoded data of the Other Data field is Other Len bytes of binary +/// stream. +/// +/// An example of valid string is: +/// \code "gss-tsig. 20210501120000 20210501130000 0 3 aabbcc 0" \endcode +/// In this example Other Data is missing because Other Len is 0. +/// +/// Note that RFC2930 does not define the standard presentation format +/// of %TKEY RR, so the above syntax is implementation specific. +/// This is, however, compatible with the format acceptable to BIND 9's +/// RDATA parser. +/// +/// \throw Others Exception from the Name constructors. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// \throw BadValue if Key Data or Other Data is not validly encoded +/// in base-64. +/// +/// \param tkey_str A string containing the RDATA to be created +TKEY::TKEY(const std::string& tkey_str) : impl_(0) { + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the TKEYImpl that constructFromLexer() returns. + std::unique_ptr<TKEYImpl> impl_ptr; + + try { + std::istringstream ss(tkey_str); + MasterLexer lexer; + lexer.pushSource(ss); + + impl_ptr.reset(constructFromLexer(lexer, 0)); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Extra input text for TKEY: " << tkey_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct TKEY from '" << tkey_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 TKEY RDATA. +/// +/// See \c TKEY::TKEY(const std::string&) for description of the +/// expected RDATA fields. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +TKEY::TKEY(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer, origin)) +{ +} + +/// \brief Constructor from wire-format data. +/// +/// When a read operation on \c buffer fails (e.g., due to a corrupted +/// message) a corresponding exception from the \c InputBuffer class will +/// be thrown. +/// If the wire-format data does not begin with a valid domain name, +/// a corresponding exception from the \c Name class will be thrown. +/// In addition, this constructor internally involves resource allocation, +/// and if it fails a corresponding standard exception will be thrown. +/// +/// According to RFC3597, the Algorithm field must be a non compressed form +/// of domain name. But this implementation accepts a %TKEY RR even if that +/// field is compressed. +/// +/// \param buffer A buffer storing the wire format data. +/// \param rdata_len The length of the RDATA in bytes, normally expected +/// to be the value of the RDLENGTH field of the corresponding RR. +/// But this constructor does not use this parameter; if necessary, the caller +/// must check consistency between the length parameter and the actual +/// RDATA length. +TKEY::TKEY(InputBuffer& buffer, size_t) : + impl_(0) +{ + Name algorithm(buffer); + + const uint32_t inception = buffer.readUint32(); + + const uint32_t expire = buffer.readUint32(); + + const uint16_t mode = buffer.readUint16(); + + const uint16_t error = buffer.readUint16(); + + const uint16_t key_len = buffer.readUint16(); + vector<uint8_t> key(key_len); + if (key_len > 0) { + buffer.readData(&key[0], key_len); + } + + const uint16_t other_len = buffer.readUint16(); + vector<uint8_t> other_data(other_len); + if (other_len > 0) { + buffer.readData(&other_data[0], other_len); + } + + impl_ = new TKEYImpl(algorithm, inception, expire, mode, error, + key, other_data); +} + +TKEY::TKEY(const Name& algorithm, uint32_t inception, uint32_t expire, + uint16_t mode, uint16_t error, uint16_t key_len, + const void* key, uint16_t other_len, const void* other_data) : + impl_(0) +{ + if ((key_len == 0 && key != 0) || (key_len > 0 && key == 0)) { + isc_throw(InvalidParameter, "TKEY Key length and data inconsistent"); + } + if ((other_len == 0 && other_data != 0) || + (other_len > 0 && other_data == 0)) { + isc_throw(InvalidParameter, + "TKEY Other data length and data inconsistent"); + } + impl_ = new TKEYImpl(algorithm, inception, expire, mode, error, + key_len, key, other_len, other_data); +} + +/// \brief The copy constructor. +/// +/// It internally allocates a resource, and if it fails a corresponding +/// standard exception will be thrown. +/// This constructor never throws an exception otherwise. +TKEY::TKEY(const TKEY& source) : Rdata(), impl_(new TKEYImpl(*source.impl_)) +{} + +TKEY& +TKEY::operator=(const TKEY& source) { + if (this == &source) { + return (*this); + } + + TKEYImpl* newimpl = new TKEYImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +TKEY::~TKEY() { + delete impl_; +} + +/// \brief Convert the \c TKEY to a string. +/// +/// The output of this method is formatted as described in the "from string" +/// constructor (\c TKEY(const std::string&))). +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// +/// \return A \c string object that represents the \c TKEY object. +std::string +TKEY::toText() const { + string result; + + result += impl_->algorithm_.toText() + " " + + timeToText32(impl_->inception_) + " " + + timeToText32(impl_->expire_) + " "; + if (impl_->mode_ == GSS_API_MODE) { + result += "GSS-API "; + } else { + result += lexical_cast<string>(impl_->mode_) + " "; + } + result += TSIGError(impl_->error_).toText() + " " + + lexical_cast<string>(impl_->key_.size()) + " "; + if (!impl_->key_.empty()) { + result += encodeBase64(impl_->key_) + " "; + } + result += lexical_cast<string>(impl_->other_data_.size()); + if (!impl_->other_data_.empty()) { + result += " " + encodeBase64(impl_->other_data_); + } + + return (result); +} + +// Common sequence of toWire() operations used for the two versions of +// toWire(). +template <typename Output> +void +TKEYImpl::toWireCommon(Output& output) const { + output.writeUint32(inception_); + output.writeUint32(expire_); + output.writeUint16(mode_); + output.writeUint16(error_); + const uint16_t key_len = key_.size(); + output.writeUint16(key_len); + if (key_len > 0) { + output.writeData(&key_[0], key_len); + } + const uint16_t other_len = other_data_.size(); + output.writeUint16(other_len); + if (other_len > 0) { + output.writeData(&other_data_[0], other_len); + } +} + +/// \brief Render the \c TKEY in the wire format without name compression. +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param buffer An output buffer to store the wire data. +void +TKEY::toWire(OutputBuffer& buffer) const { + impl_->algorithm_.toWire(buffer); + impl_->toWireCommon<OutputBuffer>(buffer); +} + +/// \brief Render the \c TKEY in the wire format with taking into account +/// compression. +/// +/// As specified in RFC3597, the Algorithm field (a domain name) will not +/// be compressed. However, the domain name could be a target of compression +/// of other compressible names (though pretty unlikely), the offset +/// information of the algorithm name may be recorded in \c renderer. +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param renderer DNS message rendering context that encapsulates the +/// output buffer and name compression information. +void +TKEY::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeName(impl_->algorithm_, false); + impl_->toWireCommon<AbstractMessageRenderer>(renderer); +} + +// A helper function commonly used for TKEY::compare(). +int +vectorComp(const vector<uint8_t>& v1, const vector<uint8_t>& v2) { + const size_t this_size = v1.size(); + const size_t other_size = v2.size(); + if (this_size != other_size) { + return (this_size < other_size ? -1 : 1); + } + if (this_size > 0) { + return (memcmp(&v1[0], &v2[0], this_size)); + } + return (0); +} + +/// \brief Compare two instances of \c TKEY RDATA. +/// +/// This method compares \c this and the \c other \c TKEY objects +/// in terms of the DNSSEC sorting order as defined in RFC4034, and returns +/// the result as an integer. +/// +/// This method is expected to be used in a polymorphic way, and the +/// parameter to compare against is therefore of the abstract \c Rdata class. +/// However, comparing two \c Rdata objects of different RR types +/// is meaningless, and \c other must point to a \c TKEY object; +/// otherwise, the standard \c bad_cast exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param other the right-hand operand to compare against. +/// \return < 0 if \c this would be sorted before \c other. +/// \return 0 if \c this is identical to \c other in terms of sorting order. +/// \return > 0 if \c this would be sorted after \c other. +int +TKEY::compare(const Rdata& other) const { + const TKEY& other_tkey = dynamic_cast<const TKEY&>(other); + + const int ncmp = compareNames(impl_->algorithm_, + other_tkey.impl_->algorithm_); + if (ncmp != 0) { + return (ncmp); + } + + if (impl_->inception_ != other_tkey.impl_->inception_) { + return (impl_->inception_ < other_tkey.impl_->inception_ ? -1 : 1); + } + if (impl_->expire_ != other_tkey.impl_->expire_) { + return (impl_->expire_ < other_tkey.impl_->expire_ ? -1 : 1); + } + if (impl_->mode_ != other_tkey.impl_->mode_) { + return (impl_->mode_ < other_tkey.impl_->mode_ ? -1 : 1); + } + if (impl_->error_ != other_tkey.impl_->error_) { + return (impl_->error_ < other_tkey.impl_->error_ ? -1 : 1); + } + + const int vcmp = vectorComp(impl_->key_, other_tkey.impl_->key_); + if (vcmp != 0) { + return (vcmp); + } + return (vectorComp(impl_->other_data_, other_tkey.impl_->other_data_)); +} + +const Name& +TKEY::getAlgorithm() const { + return (impl_->algorithm_); +} + +uint32_t +TKEY::getInception() const { + return (impl_->inception_); +} + +string +TKEY::getInceptionDate() const { + return (timeToText32(impl_->inception_)); +} + +uint32_t +TKEY::getExpire() const { + return (impl_->expire_); +} + +string +TKEY::getExpireDate() const { + return (timeToText32(impl_->expire_)); +} + +uint16_t +TKEY::getMode() const { + return (impl_->mode_); +} + +uint16_t +TKEY::getError() const { + return (impl_->error_); +} + +uint16_t +TKEY::getKeyLen() const { + return (impl_->key_.size()); +} + +const void* +TKEY::getKey() const { + if (!impl_->key_.empty()) { + return (&impl_->key_[0]); + } else { + return (0); + } +} + +uint16_t +TKEY::getOtherLen() const { + return (impl_->other_data_.size()); +} + +const void* +TKEY::getOtherData() const { + if (!impl_->other_data_.empty()) { + return (&impl_->other_data_[0]); + } else { + return (0); + } +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/tkey_249.h b/src/lib/dns/rdata/generic/tkey_249.h new file mode 100644 index 0000000..d630121 --- /dev/null +++ b/src/lib/dns/rdata/generic/tkey_249.h @@ -0,0 +1,142 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct TKEYImpl; + +/// \brief \c rdata::TKEY class represents the TKEY RDATA as defined %in +/// RFC2930. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// TKEY RDATA. +class TKEY : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Constructor from RDATA field parameters. + /// + /// The parameters are a straightforward mapping of %TKEY RDATA + /// fields as defined %in RFC2930. + /// + /// This RR is pretty close to the TSIG RR with 32 bit timestamps, + /// or the RRSIG RR with a second "other" data field. + /// + /// This constructor internally involves resource allocation, and if + /// it fails, a corresponding standard exception will be thrown. + /// + /// \param algorithm The DNS name of the algorithm e.g. gss-tsig. + /// \param inception The inception time (in seconds since 1970). + /// \param expire The expire time (in seconds since 1970). + /// \param mode The mode e.g. Diffie-Hellman (2) or GSS-API (3). + /// \param error The error code (extended error space shared with TSIG). + /// \param key_len The key length (0 means no key). + /// \param key The key (can be 0). + /// \param other_len The other data length (0 means no other data). + /// \param other_data The other data (can be and usually is 0). + TKEY(const Name& algorithm, uint32_t inception, uint32_t expire, + uint16_t mode, uint16_t error, uint16_t key_len, + const void* key, uint16_t other_len, const void* other_data); + + /// \brief Assignment operator. + /// + /// It internally allocates a resource, and if it fails a corresponding + /// standard exception will be thrown. + /// This operator never throws an exception otherwise. + /// + /// This operator provides the strong exception guarantee: When an + /// exception is thrown the content of the assignment target will be + /// intact. + TKEY& operator=(const TKEY& source); + + /// \brief The destructor. + ~TKEY(); + + /// \brief Return the algorithm name. + /// + /// This method never throws an exception. + const Name& getAlgorithm() const; + + /// \brief Return the value of the Inception field as a number. + /// + /// This method never throws an exception. + uint32_t getInception() const; + + /// \brief Return the value of the Inception field as a string. + std::string getInceptionDate() const; + + /// \brief Return the value of the Expire field as a number. + /// + /// This method never throws an exception. + uint32_t getExpire() const; + + /// \brief Return the value of the Expire field as a string. + std::string getExpireDate() const; + + /// \brief Return the value of the Mode field. + /// + /// This method never throws an exception. + uint16_t getMode() const; + + /// \brief Return the value of the Error field. + /// + /// This method never throws an exception. + uint16_t getError() const; + + /// \brief Return the value of the Key Len field. + /// + /// This method never throws an exception. + uint16_t getKeyLen() const; + + /// \brief Return the value of the Key field. + /// + /// This method never throws an exception. + const void* getKey() const; + + /// \brief Return the value of the Other Len field. + /// + /// This method never throws an exception. + uint16_t getOtherLen() const; + + /// \brief Return the value of the Other Data field. + /// + /// The same note as \c getMAC() applies. + /// + /// This method never throws an exception. + const void* getOtherData() const; + + /// \brief The GSS_API constant for the Mode field. + static const uint16_t GSS_API_MODE; + +private: + TKEYImpl* constructFromLexer(MasterLexer& lexer, const Name* origin); + + TKEYImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: 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 0000000..330b7a2 --- /dev/null +++ b/src/lib/dns/rdata/generic/tlsa_52.cc @@ -0,0 +1,342 @@ +// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#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 0000000..007aa43 --- /dev/null +++ b/src/lib/dns/rdata/generic/tlsa_52.h @@ -0,0 +1,57 @@ +// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// 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/generic/txt_16.cc b/src/lib/dns/rdata/generic/txt_16.cc new file mode 100644 index 0000000..52d6b64 --- /dev/null +++ b/src/lib/dns/rdata/generic/txt_16.cc @@ -0,0 +1,95 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <stdint.h> +#include <string.h> + +#include <string> +#include <vector> + +#include <util/buffer.h> +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/txt_like.h> + +using namespace std; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +TXT& +TXT::operator=(const TXT& source) { + if (this == &source) { + return (*this); + } + + TXTImpl* newimpl = new TXTImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +TXT::~TXT() { + delete impl_; +} + +TXT::TXT(InputBuffer& buffer, size_t rdata_len) : + impl_(new TXTImpl(buffer, rdata_len)) +{} + +/// \brief Constructor using the master lexer. +/// +/// This implementation only uses the \c lexer parameters; others are +/// ignored. +/// +/// \throw CharStringTooLong the parameter string length exceeds maximum. +/// \throw InvalidRdataText the method cannot process the parameter data +/// +/// \param lexer A \c MasterLexer object parsing a master file for this +/// RDATA. +TXT::TXT(MasterLexer& lexer, const Name*, MasterLoader::Options, + MasterLoaderCallbacks&) : + impl_(new TXTImpl(lexer)) +{} + +TXT::TXT(const std::string& txtstr) : + impl_(new TXTImpl(txtstr)) +{} + +TXT::TXT(const TXT& other) : + Rdata(), impl_(new TXTImpl(*other.impl_)) +{} + +void +TXT::toWire(OutputBuffer& buffer) const { + impl_->toWire(buffer); +} + +void +TXT::toWire(AbstractMessageRenderer& renderer) const { + impl_->toWire(renderer); +} + +string +TXT::toText() const { + return (impl_->toText()); +} + +int +TXT::compare(const Rdata& other) const { + const TXT& other_txt = dynamic_cast<const TXT&>(other); + + return (impl_->compare(*other_txt.impl_)); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/generic/txt_16.h b/src/lib/dns/rdata/generic/txt_16.h new file mode 100644 index 0000000..83979c4 --- /dev/null +++ b/src/lib/dns/rdata/generic/txt_16.h @@ -0,0 +1,46 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +namespace detail { +template<class Type, uint16_t typeCode> class TXTLikeImpl; +} + +class TXT : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + TXT& operator=(const TXT& source); + ~TXT(); + +private: + typedef isc::dns::rdata::generic::detail::TXTLikeImpl<TXT, 16> TXTImpl; + TXTImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/hs_4/a_1.cc b/src/lib/dns/rdata/hs_4/a_1.cc new file mode 100644 index 0000000..cd4c824 --- /dev/null +++ b/src/lib/dns/rdata/hs_4/a_1.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +using namespace std; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +A::A(const std::string&) { + // TBD +} + +A::A(MasterLexer&, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) +{ + // TBD +} + +A::A(InputBuffer&, size_t) { + // TBD +} + +A::A(const A&) : Rdata() { + // TBD +} + +void +A::toWire(OutputBuffer&) const { + // TBD +} + +void +A::toWire(AbstractMessageRenderer&) const { + // TBD +} + +string +A::toText() const { + // TBD + isc_throw(InvalidRdataText, "Not implemented yet"); +} + +int +A::compare(const Rdata&) const { + return (0); // dummy. TBD +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/hs_4/a_1.h b/src/lib/dns/rdata/hs_4/a_1.h new file mode 100644 index 0000000..6f319b9 --- /dev/null +++ b/src/lib/dns/rdata/hs_4/a_1.h @@ -0,0 +1,32 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class A : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/in_1/a_1.cc b/src/lib/dns/rdata/in_1/a_1.cc new file mode 100644 index 0000000..c6585b9 --- /dev/null +++ b/src/lib/dns/rdata/in_1/a_1.cc @@ -0,0 +1,174 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <stdint.h> +#include <string.h> + +#include <cerrno> +#include <cstring> +#include <string> + +#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards +#include <sys/socket.h> // for AF_INET/AF_INET6 + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> + +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/master_lexer.h> +#include <dns/master_loader_callbacks.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +using namespace std; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +namespace { +void +convertToIPv4Addr(const char* src, size_t src_len, uint32_t* dst) { + // This check specifically rejects invalid input that begins with valid + // address text followed by a nul character (and possibly followed by + // further garbage). It cannot be detected by inet_pton(). + // + // Note that this is private subroutine of the in::A constructors, which + // pass std::string.size() or StringRegion::len as src_len, so it should + // be equal to strlen() unless there's an intermediate nul character. + if (src_len != strlen(src)) { + isc_throw(InvalidRdataText, + "Bad IN/A RDATA text: unexpected nul in string: '" + << src << "'"); + } + const int result = inet_pton(AF_INET, src, dst); + if (result == 0) { + isc_throw(InvalidRdataText, "Bad IN/A RDATA text: '" << src << "'"); + } else if (result < 0) { + isc_throw(isc::Unexpected, + "Unexpected failure in parsing IN/A RDATA text: '" + << src << "': " << std::strerror(errno)); + } +} +} + +/// \brief Constructor from string. +/// +/// The given string must be a valid textual representation of an IPv4 +/// address as specified in RFC1035, that is, four decimal numbers separated +/// by dots without any embedded spaces. Note that it excludes abbreviated +/// forms such as "10.1" to mean "10.0.0.1". +/// +/// Internally, this implementation uses the standard inet_pton() library +/// function for the AF_INET family to parse and convert the textual +/// representation. While standard compliant implementations of this function +/// should accept exactly what this constructor expects, specific +/// implementation may behave differently, in which case this constructor +/// will simply accept the result of inet_pton(). In any case, the user of +/// the class shouldn't assume such specific implementation behavior of +/// inet_pton(). +/// +/// No extra character should be contained in \c addrstr other than the +/// textual address. These include spaces and the nul character. +/// +/// \throw InvalidRdata The text extracted by the lexer isn't recognized as +/// a valid IPv4 address. +/// \throw Unexpected Unexpected system error in conversion (this should be +/// very rare). +/// +/// \param addrstr Textual representation of IPv4 address to be used as the +/// RDATA. +A::A(const std::string& addrstr) { + convertToIPv4Addr(addrstr.c_str(), addrstr.size(), &addr_); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of a class IN A RDATA. +/// +/// The acceptable form of the textual address is generally the same as the +/// string version of the constructor, but this version accepts beginning +/// spaces and trailing spaces or other characters. Trailing non space +/// characters would be considered an invalid form in an RR representation, +/// but handling such errors is not the responsibility of this constructor. +/// It also accepts other unusual syntax that would be considered valid +/// in the context of DNS master file; for example, it accepts an IPv4 +/// address surrounded by parentheses, such as "(192.0.2.1)", although it's +/// very unlikely to be used for this type of RDATA. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw InvalidRdata The text extracted by the lexer isn't recognized as +/// a valid IPv4 address. +/// \throw Unexpected Unexpected system error in conversion (this should be +/// very rare). +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +A::A(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) +{ + const MasterToken& token = lexer.getNextToken(MasterToken::STRING); + convertToIPv4Addr(token.getStringRegion().beg, token.getStringRegion().len, + &addr_); +} + +A::A(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len != sizeof(addr_)) { + isc_throw(DNSMessageFORMERR, + "IN/A RDATA construction from wire failed: Invalid length: " + << rdata_len); + } + if (buffer.getLength() - buffer.getPosition() < sizeof(addr_)) { + isc_throw(DNSMessageFORMERR, + "IN/A RDATA construction from wire failed: " + "insufficient buffer length: " + << buffer.getLength() - buffer.getPosition()); + } + buffer.readData(&addr_, sizeof(addr_)); +} + +/// \brief Copy constructor. +A::A(const A& other) : Rdata(), addr_(other.addr_) +{} + +void +A::toWire(OutputBuffer& buffer) const { + buffer.writeData(&addr_, sizeof(addr_)); +} + +void +A::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeData(&addr_, sizeof(addr_)); +} + +/// \brief Return a textual form of the underlying IPv4 address of the RDATA. +string +A::toText() const { + char addr_string[sizeof("255.255.255.255")]; + + if (inet_ntop(AF_INET, &addr_, addr_string, sizeof(addr_string)) == NULL) { + isc_throw(Unexpected, + "Failed to convert IN/A RDATA to textual IPv4 address"); + } + + return (addr_string); +} + +/// \brief Compare two in::A RDATAs. +/// +/// In effect, it compares the two RDATA as an unsigned 32-bit integer. +int +A::compare(const Rdata& other) const { + const A& other_a = dynamic_cast<const A&>(other); + return (memcmp(&addr_, &other_a.addr_, sizeof(addr_))); +} +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/in_1/a_1.h b/src/lib/dns/rdata/in_1/a_1.h new file mode 100644 index 0000000..9aaeea8 --- /dev/null +++ b/src/lib/dns/rdata/in_1/a_1.h @@ -0,0 +1,38 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class A : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + //We can use the default destructor. + //virtual ~A() {} + // notyet: + //const struct in_addr& getAddress() const { return (addr_); } +private: + uint32_t addr_; // raw IPv4 address (network byte order) +}; +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/in_1/aaaa_28.cc b/src/lib/dns/rdata/in_1/aaaa_28.cc new file mode 100644 index 0000000..c967935 --- /dev/null +++ b/src/lib/dns/rdata/in_1/aaaa_28.cc @@ -0,0 +1,153 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> +#include <util/buffer.h> +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/master_lexer.h> +#include <dns/master_loader.h> + +#include <stdint.h> +#include <string.h> + +#include <cerrno> +#include <cstring> +#include <string> + +#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards +#include <sys/socket.h> // for AF_INET/AF_INET6 + +using namespace std; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +namespace { +void +convertToIPv6Addr(const char* src, size_t src_len, void* dst) { + // See a_1.cc for this check. + if (src_len != strlen(src)) { + isc_throw(InvalidRdataText, + "Bad IN/AAAA RDATA text: unexpected nul in string: '" + << src << "'"); + } + const int result = inet_pton(AF_INET6, src, dst); + if (result == 0) { + isc_throw(InvalidRdataText, "Bad IN/AAAA RDATA text: '" << src << "'"); + } else if (result < 0) { + isc_throw(isc::Unexpected, + "Unexpected failure in parsing IN/AAAA RDATA text: '" + << src << "': " << std::strerror(errno)); + } +} +} + +/// \brief Constructor from string. +/// +/// The given string must be a valid textual representation of an IPv6 +/// address as specified in RFC1886. +/// +/// No extra character should be contained in \c addrstr other than the +/// textual address. These include spaces and the nul character. +/// +/// \throw InvalidRdata The text extracted by the lexer isn't recognized as +/// a valid IPv6 address. +/// \throw Unexpected Unexpected system error in conversion (this should be +/// very rare). +/// +/// \param addrstr Textual representation of IPv6 address to be used as the +/// RDATA. +AAAA::AAAA(const std::string& addrstr) { + convertToIPv6Addr(addrstr.c_str(), addrstr.size(), addr_); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of a class IN AAAA RDATA. +/// +/// The acceptable form of the textual address is generally the same as the +/// string version of the constructor, but this version is slightly more +/// flexible. See the similar constructor of \c in::A class; the same +/// notes apply here. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw InvalidRdata The text extracted by the lexer isn't recognized as +/// a valid IPv6 address. +/// \throw Unexpected Unexpected system error in conversion (this should be +/// very rare). +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +AAAA::AAAA(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) +{ + const MasterToken& token = lexer.getNextToken(MasterToken::STRING); + convertToIPv6Addr(token.getStringRegion().beg, token.getStringRegion().len, + addr_); +} + +/// \brief Copy constructor. +AAAA::AAAA(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len != sizeof(addr_)) { + isc_throw(DNSMessageFORMERR, + "IN/AAAA RDATA construction from wire failed: " + "Invalid length: " << rdata_len); + } + if (buffer.getLength() - buffer.getPosition() < sizeof(addr_)) { + isc_throw(DNSMessageFORMERR, + "IN/AAAA RDATA construction from wire failed: " + "insufficient buffer length: " + << buffer.getLength() - buffer.getPosition()); + } + buffer.readData(&addr_, sizeof(addr_)); +} + +AAAA::AAAA(const AAAA& other) : Rdata() { + memcpy(addr_, other.addr_, sizeof(addr_)); +} + +/// \brief Return a textual form of the underlying IPv6 address of the RDATA. +void +AAAA::toWire(OutputBuffer& buffer) const { + buffer.writeData(&addr_, sizeof(addr_)); +} + +void +AAAA::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeData(&addr_, sizeof(addr_)); +} + +string +AAAA::toText() const { + char addr_string[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + + if (inet_ntop(AF_INET6, &addr_, addr_string, sizeof(addr_string)) + == NULL) { + isc_throw(Unexpected, + "Failed to convert IN/AAAA RDATA to textual IPv6 address"); + } + + return (string(addr_string)); +} + +/// \brief Compare two in::AAAA RDATAs. +/// +/// In effect, it compares the two RDATA as an unsigned 128-bit integer. +int +AAAA::compare(const Rdata& other) const { + const AAAA& other_a = dynamic_cast<const AAAA&>(other); + return (memcmp(&addr_, &other_a.addr_, sizeof(addr_))); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/in_1/aaaa_28.h b/src/lib/dns/rdata/in_1/aaaa_28.h new file mode 100644 index 0000000..a5cabf4 --- /dev/null +++ b/src/lib/dns/rdata/in_1/aaaa_28.h @@ -0,0 +1,38 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <string> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +class AAAA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + // notyet: + //const struct in6_addr& getAddress() const { return (addr_); } +private: + uint8_t addr_[16]; // raw IPv6 address (network byte order) +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/in_1/dhcid_49.cc b/src/lib/dns/rdata/in_1/dhcid_49.cc new file mode 100644 index 0000000..57c79c2 --- /dev/null +++ b/src/lib/dns/rdata/in_1/dhcid_49.cc @@ -0,0 +1,161 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <stdint.h> +#include <string.h> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <util/encode/base64.h> +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::encode; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +void +DHCID::constructFromLexer(MasterLexer& lexer) { + string digest_txt = lexer.getNextToken(MasterToken::STRING).getString(); + + // Whitespace is allowed within base64 text, so read to the end of input. + string digest_part; + while (true) { + const MasterToken& token = + lexer.getNextToken(MasterToken::STRING, true); + if ((token.getType() == MasterToken::END_OF_FILE) || + (token.getType() == MasterToken::END_OF_LINE)) { + break; + } + token.getString(digest_part); + digest_txt.append(digest_part); + } + lexer.ungetToken(); + + decodeBase64(digest_txt, digest_); +} + +/// \brief Constructor from string. +/// +/// \param dhcid_str A base-64 representation of the DHCID binary data. +/// +/// \throw InvalidRdataText if the string could not be parsed correctly. +DHCID::DHCID(const std::string& dhcid_str) { + try { + std::istringstream iss(dhcid_str); + MasterLexer lexer; + lexer.pushSource(iss); + + constructFromLexer(lexer); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for DHCID: " + << dhcid_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct DHCID from '" << + dhcid_str << "': " << ex.what()); + } +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of a DHCID RDATA. +/// +/// \throw BadValue if the text is not valid base-64. +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +DHCID::DHCID(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) { + constructFromLexer(lexer); +} + +/// \brief Constructor from wire-format data. +/// +/// \param buffer A buffer storing the wire format data. +/// \param rdata_len The length of the RDATA in bytes +DHCID::DHCID(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len == 0) { + isc_throw(InvalidRdataLength, "Missing DHCID rdata"); + } + + digest_.resize(rdata_len); + buffer.readData(&digest_[0], rdata_len); +} + +/// \brief The copy constructor. +/// +/// This trivial copy constructor never throws an exception. +DHCID::DHCID(const DHCID& other) : Rdata(), digest_(other.digest_) +{} + +/// \brief Render the \c DHCID in the wire format. +/// +/// \param buffer An output buffer to store the wire data. +void +DHCID::toWire(OutputBuffer& buffer) const { + buffer.writeData(&digest_[0], digest_.size()); +} + +/// \brief Render the \c DHCID in the wire format into a +/// \c MessageRenderer object. +/// +/// \param renderer DNS message rendering context that encapsulates the +/// output buffer in which the \c DHCID is to be stored. +void +DHCID::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeData(&digest_[0], digest_.size()); +} + +/// \brief Convert the \c DHCID to a string. +/// +/// This method returns a \c std::string object representing the \c DHCID. +/// +/// \return A string representation of \c DHCID. +string +DHCID::toText() const { + return (encodeBase64(digest_)); +} + +/// \brief Compare two instances of \c DHCID RDATA. +/// +/// See documentation in \c Rdata. +int +DHCID::compare(const Rdata& other) const { + const DHCID& other_dhcid = dynamic_cast<const DHCID&>(other); + + size_t this_len = digest_.size(); + size_t other_len = other_dhcid.digest_.size(); + size_t cmplen = min(this_len, other_len); + int cmp = memcmp(&digest_[0], &other_dhcid.digest_[0], cmplen); + if (cmp != 0) { + return (cmp); + } else { + return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1); + } +} + +/// \brief Accessor method to get the DHCID digest +/// +/// \return A reference to the binary DHCID data +const std::vector<uint8_t>& +DHCID::getDigest() const { + return (digest_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/in_1/dhcid_49.h b/src/lib/dns/rdata/in_1/dhcid_49.h new file mode 100644 index 0000000..7f79602 --- /dev/null +++ b/src/lib/dns/rdata/in_1/dhcid_49.h @@ -0,0 +1,53 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> +#include <vector> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +/// \brief \c rdata::DHCID class represents the DHCID RDATA as defined %in +/// RFC4701. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// DHCID RDATA. +class DHCID : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Return the digest. + /// + /// This method never throws an exception. + const std::vector<uint8_t>& getDigest() const; + +private: + // helper for string and lexer constructors + void constructFromLexer(MasterLexer& lexer); + + /// \brief Private data representation + /// + /// Opaque data at least 3 octets long as per RFC4701. + /// + std::vector<uint8_t> digest_; +}; +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/in_1/srv_33.cc b/src/lib/dns/rdata/in_1/srv_33.cc new file mode 100644 index 0000000..a8a050c --- /dev/null +++ b/src/lib/dns/rdata/in_1/srv_33.cc @@ -0,0 +1,298 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <iostream> +#include <sstream> + +#include <boost/lexical_cast.hpp> + +#include <util/buffer.h> +#include <util/strutil.h> + +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> + +#include <dns/rdata/generic/detail/lexer_util.h> + +using namespace std; +using namespace isc::util; +using namespace isc::util::str; +using isc::dns::rdata::generic::detail::createNameFromLexer; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct SRVImpl { + // straightforward representation of SRV RDATA fields + SRVImpl(uint16_t priority, uint16_t weight, uint16_t port, + const Name& target) : + priority_(priority), weight_(weight), port_(port), + target_(target) + {} + + uint16_t priority_; + uint16_t weight_; + uint16_t port_; + Name target_; +}; + +/// \brief Constructor from string. +/// +/// The given string must represent a valid SRV 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 TARGET name must be absolute since there's no parameter that +/// specifies the origin name; if it is not absolute, \c MissingNameOrigin +/// exception will be thrown. It must not be represented as a quoted +/// string. +/// +/// See the construction that takes \c MasterLexer for other fields. +/// +/// \throw Others Exception from the Name and RRTTL constructors. +/// \throw InvalidRdataText Other general syntax errors. +SRV::SRV(const std::string& srv_str) : + impl_(NULL) +{ + try { + std::istringstream ss(srv_str); + MasterLexer lexer; + lexer.pushSource(ss); + + uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid SRV priority in: " << srv_str); + } + const uint16_t priority = static_cast<uint16_t>(num); + + num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid SRV weight in: " << srv_str); + } + const uint16_t weight = static_cast<uint16_t>(num); + + num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid SRV port in: " << srv_str); + } + const uint16_t port = static_cast<uint16_t>(num); + + const Name targetname = createNameFromLexer(lexer, NULL); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, "extra input text for SRV: " + << srv_str); + } + + impl_ = new SRVImpl(priority, weight, port, targetname); + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct SRV from '" << + srv_str << "': " << ex.what()); + } +} + +/// \brief Constructor from wire-format data. +/// +/// When a read operation on \c buffer fails (e.g., due to a corrupted +/// message) a corresponding exception from the \c InputBuffer class will +/// be thrown. +/// If the wire-format data does not end with a valid domain name, +/// a corresponding exception from the \c Name class will be thrown. +/// In addition, this constructor internally involves resource allocation, +/// and if it fails a corresponding standard exception will be thrown. +/// +/// According to RFC2782, the Target field must be a non compressed form +/// of domain name. But this implementation accepts a %SRV RR even if that +/// field is compressed as suggested in RFC3597. +/// +/// \param buffer A buffer storing the wire format data. +/// \param rdata_len The length of the RDATA in bytes, normally expected +/// to be the value of the RDLENGTH field of the corresponding RR. +SRV::SRV(InputBuffer& buffer, size_t rdata_len) { + if (rdata_len < 6) { + isc_throw(InvalidRdataLength, "SRV too short"); + } + + const uint16_t priority = buffer.readUint16(); + const uint16_t weight = buffer.readUint16(); + const uint16_t port = buffer.readUint16(); + const Name targetname(buffer); + + impl_ = new SRVImpl(priority, weight, port, targetname); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual representation +/// of an SRV RDATA. The TARGET field can be non-absolute if \c origin +/// is non-NULL, in which case \c origin is used to make it absolute. +/// It must not be represented as a quoted string. +/// +/// The PRIORITY, WEIGHT and PORT fields must each be a valid decimal +/// representation of an unsigned 16-bit integers respectively. +/// +/// \throw MasterLexer::LexerError General parsing error such as missing field. +/// \throw Other Exceptions from the Name and RRTTL constructors if +/// construction of textual fields as these objects fail. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +/// \param origin If non NULL, specifies the origin of TARGET when it +/// is non-absolute. +SRV::SRV(MasterLexer& lexer, const Name* origin, + MasterLoader::Options, MasterLoaderCallbacks&) +{ + uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid SRV priority: " << num); + } + const uint16_t priority = static_cast<uint16_t>(num); + + num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid SRV weight: " << num); + } + const uint16_t weight = static_cast<uint16_t>(num); + + num = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (num > 65535) { + isc_throw(InvalidRdataText, "Invalid SRV port: " << num); + } + const uint16_t port = static_cast<uint16_t>(num); + + const Name targetname = createNameFromLexer(lexer, origin); + + impl_ = new SRVImpl(priority, weight, port, targetname); +} + +/// \brief The copy constructor. +/// +/// It internally allocates a resource, and if it fails a corresponding +/// standard exception will be thrown. +/// This constructor never throws an exception otherwise. +SRV::SRV(const SRV& source) : + Rdata(), impl_(new SRVImpl(*source.impl_)) +{} + +SRV& +SRV::operator=(const SRV& source) { + if (this == &source) { + return (*this); + } + + SRVImpl* newimpl = new SRVImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +SRV::~SRV() { + delete impl_; +} + +/// \brief Convert the \c SRV to a string. +/// +/// The output of this method is formatted as described in the "from string" +/// constructor (\c SRV(const std::string&))). +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// +/// \return A \c string object that represents the \c SRV object. +string +SRV::toText() const { + using boost::lexical_cast; + return (lexical_cast<string>(impl_->priority_) + + " " + lexical_cast<string>(impl_->weight_) + + " " + lexical_cast<string>(impl_->port_) + + " " + impl_->target_.toText()); +} + +/// \brief Render the \c SRV in the wire format without name compression. +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param buffer An output buffer to store the wire data. +void +SRV::toWire(OutputBuffer& buffer) const { + buffer.writeUint16(impl_->priority_); + buffer.writeUint16(impl_->weight_); + buffer.writeUint16(impl_->port_); + impl_->target_.toWire(buffer); +} + +/// \brief Render the \c SRV in the wire format with taking into account +/// compression. +/// +/// As specified in RFC2782, the Target field (a domain name) will not be +/// compressed. However, the domain name could be a target of compression +/// of other compressible names (though pretty unlikely), the offset +/// information of the algorithm name may be recorded in \c renderer. +/// +/// If internal resource allocation fails, a corresponding +/// standard exception will be thrown. +/// This method never throws an exception otherwise. +/// +/// \param renderer DNS message rendering context that encapsulates the +/// output buffer and name compression information. +void +SRV::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeUint16(impl_->priority_); + renderer.writeUint16(impl_->weight_); + renderer.writeUint16(impl_->port_); + renderer.writeName(impl_->target_, false); +} + +/// \brief Compare two instances of \c SRV RDATA. +/// +/// See documentation in \c Rdata. +int +SRV::compare(const Rdata& other) const { + const SRV& other_srv = dynamic_cast<const SRV&>(other); + + if (impl_->priority_ != other_srv.impl_->priority_) { + return (impl_->priority_ < other_srv.impl_->priority_ ? -1 : 1); + } + if (impl_->weight_ != other_srv.impl_->weight_) { + return (impl_->weight_ < other_srv.impl_->weight_ ? -1 : 1); + } + if (impl_->port_ != other_srv.impl_->port_) { + return (impl_->port_ < other_srv.impl_->port_ ? -1 : 1); + } + + return (compareNames(impl_->target_, other_srv.impl_->target_)); +} + +uint16_t +SRV::getPriority() const { + return (impl_->priority_); +} + +uint16_t +SRV::getWeight() const { + return (impl_->weight_); +} + +uint16_t +SRV::getPort() const { + return (impl_->port_); +} + +const Name& +SRV::getTarget() const { + return (impl_->target_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/in_1/srv_33.h b/src/lib/dns/rdata/in_1/srv_33.h new file mode 100644 index 0000000..aca210e --- /dev/null +++ b/src/lib/dns/rdata/in_1/srv_33.h @@ -0,0 +1,85 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <stdint.h> + +#include <dns/name.h> +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +struct SRVImpl; + +/// \brief \c rdata::SRV class represents the SRV RDATA as defined %in +/// RFC2782. +/// +/// This class implements the basic interfaces inherited from the abstract +/// \c rdata::Rdata class, and provides trivial accessors specific to the +/// SRV RDATA. +class SRV : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // END_COMMON_MEMBERS + + /// \brief Assignment operator. + /// + /// It internally allocates a resource, and if it fails a corresponding + /// standard exception will be thrown. + /// This operator never throws an exception otherwise. + /// + /// This operator provides the strong exception guarantee: When an + /// exception is thrown the content of the assignment target will be + /// intact. + SRV& operator=(const SRV& source); + + /// \brief The destructor. + ~SRV(); + + /// + /// Specialized methods + /// + + /// \brief Return the value of the priority field. + /// + /// This method never throws an exception. + uint16_t getPriority() const; + + /// \brief Return the value of the weight field. + /// + /// This method never throws an exception. + uint16_t getWeight() const; + + /// \brief Return the value of the port field. + /// + /// This method never throws an exception. + uint16_t getPort() const; + + /// \brief Return the value of the target field. + /// + /// \return A reference to a \c Name class object corresponding to the + /// internal target name. + /// + /// This method never throws an exception. + const Name& getTarget() const; + +private: + SRVImpl* impl_; +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdata/template.cc b/src/lib/dns/rdata/template.cc new file mode 100644 index 0000000..d205855 --- /dev/null +++ b/src/lib/dns/rdata/template.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <string> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rrtype.h> + +using namespace std; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +// To add RDATA implementation of a new RR type (say "MyType"), copy this +// template into the appropriate subdirectory with the appropriate name +// (see template.h). +// Then define (at least) the following common methods (that are inherited +// from the base abstract class). +// If you added member functions specific to this derived class, you'll need +// to implement them here, of course. + +MyType::MyType(MasterLexer& lexer, const Name* origin, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks) +{ +} + +MyType::MyType(const string& type_str) { +} + +MyType::MyType(InputBuffer& buffer, size_t rdata_len) { +} + +MyType::MyType(const MyType& source) { +} + +std::string +MyType::toText() const { +} + +void +MyType::toWire(OutputBuffer& buffer) const { +} + +void +MyType::toWire(AbstractMessageRenderer& renderer) const { +} + +int +MyType::compare(const Rdata&) const { + // The compare method normally begins with this dynamic cast. + // cppcheck-suppress unreadVariable + // const MyType& other_mytype = dynamic_cast<const MyType&>(other); + // ... + return (0); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE diff --git a/src/lib/dns/rdata/template.h b/src/lib/dns/rdata/template.h new file mode 100644 index 0000000..d74790e --- /dev/null +++ b/src/lib/dns/rdata/template.h @@ -0,0 +1,54 @@ +// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// BEGIN_HEADER_GUARD + +#include <string> + +#include <dns/rdata.h> + +// BEGIN_ISC_NAMESPACE + +// BEGIN_COMMON_DECLARATIONS +// END_COMMON_DECLARATIONS + +// BEGIN_RDATA_NAMESPACE + +// To add RDATA class definition of a new RR type (say "MyType"), copy this +// file to an appropriate subdirectory (if it's class-independent type, it +// should go to "generic/", if it's IN-class specific, it should be in +// "in_1/", and so on). The copied file should be named as type_nn.h where +// "type" is textual representation (all lower cased) of the RR type, and "nn" +// is the 16-bit type code of the RR type. +// Normally, you'll need to define some specific member variables in the +// "RR-type specific members" space (please make them private). In addition, +// you may want to define some specific member functions, either public or +// private (or, though unlikely for a leaf class, protected). +// +// Note: do not remove the comment lines beginning with "BEGIN_" and "END_". +// These are markers used by a script for auto-generating build-able source +// files. +// +// On completion of implementing a new type of Rdata, remove the corresponding +// entry from the meta_types dictionary of gen-rdatacode.py.in. Otherwise +// it will cause build failure. + +class MyType : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + // Do not remove the BEGIN_xxx and END_xxx comment lines. + // END_COMMON_MEMBERS +private: + // RR-type specific members are here. +}; + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE +// END_HEADER_GUARD + +// Local Variables: +// mode: c++ +// End: |