diff options
Diffstat (limited to '')
82 files changed, 22039 insertions, 0 deletions
diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc new file mode 100644 index 0000000..357ccc7 --- /dev/null +++ b/src/lib/dns/rdata.cc @@ -0,0 +1,408 @@ +// 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 <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <util/encode/hex.h> + +#include <dns/name.h> +#include <dns/messagerenderer.h> +#include <dns/master_lexer.h> +#include <dns/rdata.h> +#include <dns/rrparamregistry.h> +#include <dns/rrtype.h> + +#include <boost/lexical_cast.hpp> +#include <boost/shared_ptr.hpp> + +#include <algorithm> +#include <cctype> +#include <string> +#include <sstream> +#include <iomanip> +#include <ios> +#include <ostream> +#include <vector> + +#include <stdint.h> +#include <string.h> + +using namespace std; +using boost::lexical_cast; +using namespace isc::util; + +namespace isc { +namespace dns { +namespace rdata { + +uint16_t +Rdata::getLength() const { + OutputBuffer obuffer(0); + + toWire(obuffer); + + return (obuffer.getLength()); +} + +// XXX: we need to specify std:: for string to help doxygen match the +// function signature with that given in the header file. +RdataPtr +createRdata(const RRType& rrtype, const RRClass& rrclass, + const std::string& rdata_string) +{ + return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, + rdata_string)); +} + +RdataPtr +createRdata(const RRType& rrtype, const RRClass& rrclass, + isc::util::InputBuffer& buffer, size_t len) +{ + if (len > MAX_RDLENGTH) { + isc_throw(InvalidRdataLength, "RDLENGTH too large"); + } + + size_t old_pos = buffer.getPosition(); + + RdataPtr rdata = + RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, buffer, + len); + + if (buffer.getPosition() - old_pos != len) { + isc_throw(InvalidRdataLength, "RDLENGTH mismatch: " << + buffer.getPosition() - old_pos << " != " << len); + } + + return (rdata); +} + +RdataPtr +createRdata(const RRType& rrtype, const RRClass& rrclass, const Rdata& source) +{ + return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, + source)); +} + +namespace { +void +fromtextError(bool& error_issued, const MasterLexer& lexer, + MasterLoaderCallbacks& callbacks, + const MasterToken* token, const char* reason) +{ + // Don't be too noisy if there are many issues for single RDATA + if (error_issued) { + return; + } + error_issued = true; + + if (token == NULL) { + callbacks.error(lexer.getSourceName(), lexer.getSourceLine(), + "createRdata from text failed: " + string(reason)); + return; + } + + switch (token->getType()) { + case MasterToken::STRING: + case MasterToken::QSTRING: + callbacks.error(lexer.getSourceName(), lexer.getSourceLine(), + "createRdata from text failed near '" + + token->getString() + "': " + string(reason)); + break; + case MasterToken::ERROR: + callbacks.error(lexer.getSourceName(), lexer.getSourceLine(), + "createRdata from text failed: " + + token->getErrorText()); + break; + default: + // This case shouldn't happen based on how we use MasterLexer in + // createRdata(), so we could assert() that here. But since it + // depends on detailed behavior of other classes, we treat the case + // in a bit less harsh way. + isc_throw(Unexpected, "bug: createRdata() saw unexpected token type"); + } +} +} + +RdataPtr +createRdata(const RRType& rrtype, const RRClass& rrclass, + MasterLexer& lexer, const Name* origin, + MasterLoader::Options options, + MasterLoaderCallbacks& callbacks) +{ + RdataPtr rdata; + + bool error_issued = false; + try { + rdata = RRParamRegistry::getRegistry().createRdata( + rrtype, rrclass, lexer, origin, options, callbacks); + } catch (const MasterLexer::LexerError& error) { + fromtextError(error_issued, lexer, callbacks, &error.token_, ""); + } catch (const Exception& ex) { + // Catching all isc::Exception is too broad, but right now we don't + // have better granularity. When we complete #2518 we can make this + // finer. + fromtextError(error_issued, lexer, callbacks, NULL, ex.what()); + } + // Other exceptions mean a serious implementation bug or fatal system + // error; it doesn't make sense to catch and try to recover from them + // here. Just propagate. + + // Consume to end of line / file. + // Call callback via fromtextError once if there was an error. + do { + const MasterToken& token = lexer.getNextToken(); + switch (token.getType()) { + case MasterToken::END_OF_LINE: + return (rdata); + case MasterToken::END_OF_FILE: + callbacks.warning(lexer.getSourceName(), lexer.getSourceLine(), + "file does not end with newline"); + return (rdata); + default: + rdata.reset(); // we'll return NULL + fromtextError(error_issued, lexer, callbacks, &token, + "extra input text"); + // Continue until we see EOL or EOF + } + } while (true); + + // We shouldn't reach here + assert(false); + return (RdataPtr()); // add explicit return to silence some compilers +} + +int +compareNames(const Name& n1, const Name& n2) { + size_t len1 = n1.getLength(); + size_t len2 = n2.getLength(); + size_t cmplen = min(len1, len2); + + for (size_t i = 0; i < cmplen; ++i) { + uint8_t c1 = tolower(n1.at(i)); + uint8_t c2 = tolower(n2.at(i)); + if (c1 < c2) { + return (-1); + } else if (c1 > c2) { + return (1); + } + } + + return ((len1 == len2) ? 0 : (len1 < len2) ? -1 : 1); +} + +namespace generic { +struct GenericImpl { + GenericImpl(const vector<uint8_t>& data) : data_(data) {} + vector<uint8_t> data_; +}; + +Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) { + if (rdata_len > MAX_RDLENGTH) { + isc_throw(InvalidRdataLength, "RDLENGTH too large"); + } + + vector<uint8_t> data(rdata_len); + if (rdata_len > 0) { + buffer.readData(&data[0], rdata_len); + } + + impl_ = new GenericImpl(data); +} + +GenericImpl* +Generic::constructFromLexer(MasterLexer& lexer) { + const MasterToken& token = lexer.getNextToken(MasterToken::STRING); + if (token.getString() != "\\#") { + isc_throw(InvalidRdataText, + "Missing the special token (\\#) for " + "unknown RDATA encoding"); + } + + // Initialize with an absurd value. + uint32_t rdlen = 65536; + + try { + rdlen = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + } catch (const MasterLexer::LexerError&) { + isc_throw(InvalidRdataLength, + "Unknown RDATA length is invalid"); + } + + if (rdlen > 65535) { + isc_throw(InvalidRdataLength, + "Unknown RDATA length is out of range: " << rdlen); + } + + vector<uint8_t> data; + + if (rdlen > 0) { + string hex_txt; + string hex_part; + // Whitespace is allowed within hex data, so read to the end of input. + while (true) { + const MasterToken& token = + lexer.getNextToken(MasterToken::STRING, true); + if ((token.getType() == MasterToken::END_OF_FILE) || + (token.getType() == MasterToken::END_OF_LINE)) { + // Unget the last read token as createRdata() expects us + // to leave it at the end-of-line or end-of-file when we + // return. + lexer.ungetToken(); + break; + } + token.getString(hex_part); + hex_txt.append(hex_part); + } + + try { + isc::util::encode::decodeHex(hex_txt, data); + } catch (const isc::BadValue& ex) { + isc_throw(InvalidRdataText, + "Invalid hex encoding of generic RDATA: " << ex.what()); + } + } + + if (data.size() != rdlen) { + isc_throw(InvalidRdataLength, + "Size of unknown RDATA hex data doesn't match RDLENGTH: " + << data.size() << " vs. " << rdlen); + } + + return (new GenericImpl(data)); +} + +Generic::Generic(const std::string& rdata_string) : + 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 GenericImpl that constructFromLexer() returns. + std::unique_ptr<GenericImpl> impl_ptr; + + try { + std::istringstream ss(rdata_string); + 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 unknown RDATA: " + << rdata_string); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, "Failed to construct unknown RDATA " + "from '" << rdata_string << "': " << ex.what()); + } + + impl_ = impl_ptr.release(); +} + +Generic::Generic(MasterLexer& lexer, const Name*, + MasterLoader::Options, + MasterLoaderCallbacks&) : + impl_(constructFromLexer(lexer)) +{ +} + +Generic::~Generic() { + delete impl_; +} + +Generic::Generic(const Generic& source) : + Rdata(), impl_(new GenericImpl(*source.impl_)) +{} + +Generic& +// Our check is better than the usual if (this == &source), +// but cppcheck doesn't recognize it. +// cppcheck-suppress operatorEqToSelf +Generic::operator=(const Generic& source) { + if (impl_ == source.impl_) { + return (*this); + } + + GenericImpl* newimpl = new GenericImpl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +namespace { +class UnknownRdataDumper { +public: + UnknownRdataDumper(ostringstream& oss) : oss_(&oss) {} + void operator()(const unsigned char d) + { + *oss_ << setw(2) << static_cast<unsigned int>(d); + } +private: + ostringstream* oss_; +}; +} + +string +Generic::toText() const { + ostringstream oss; + + oss << "\\# " << impl_->data_.size() << " "; + oss.fill('0'); + oss << right << hex; + for_each(impl_->data_.begin(), impl_->data_.end(), UnknownRdataDumper(oss)); + + return (oss.str()); +} + +void +Generic::toWire(isc::util::OutputBuffer& buffer) const { + buffer.writeData(&impl_->data_[0], impl_->data_.size()); +} + +void +Generic::toWire(AbstractMessageRenderer& renderer) const { + renderer.writeData(&impl_->data_[0], impl_->data_.size()); +} + +namespace { +inline int +compare_internal(const GenericImpl& lhs, const GenericImpl& rhs) { + size_t this_len = lhs.data_.size(); + size_t other_len = rhs.data_.size(); + size_t len = (this_len < other_len) ? this_len : other_len; + int cmp; + + // TODO: is there a need to check len - should we just assert? + // (Depends if it is possible for rdata to have zero length) + if ((len != 0) && + ((cmp = memcmp(&lhs.data_[0], &rhs.data_[0], len)) != 0)) { + return (cmp); + } else { + return ((this_len == other_len) ? 0 : + (this_len < other_len) ? -1 : 1); + } +} +} + +int +Generic::compare(const Rdata& other) const { + const Generic& other_rdata = dynamic_cast<const Generic&>(other); + + return (compare_internal(*impl_, *other_rdata.impl_)); +} + +std::ostream& +operator<<(std::ostream& os, const Generic& rdata) { + return (os << rdata.toText()); +} +} // end of namespace generic + +} // end of namespace rdata +} +} diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h new file mode 100644 index 0000000..a6515ef --- /dev/null +++ b/src/lib/dns/rdata.h @@ -0,0 +1,582 @@ +// 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/. + +#ifndef RDATA_H +#define RDATA_H 1 + +#include <dns/master_lexer.h> +#include <dns/master_loader.h> +#include <dns/master_loader_callbacks.h> + +#include <dns/exceptions.h> + +#include <boost/shared_ptr.hpp> + +#include <stdint.h> + +namespace isc { +namespace util { +class InputBuffer; +class OutputBuffer; +} +namespace dns { +class AbstractMessageRenderer; +class RRType; +class RRClass; +class Name; + +namespace rdata { + +/// +/// \brief A standard DNS module exception that is thrown if RDATA parser +/// encounters an invalid or inconsistent data length. +/// +class InvalidRdataLength : public DNSTextError { +public: + InvalidRdataLength(const char* file, size_t line, const char* what) : + DNSTextError(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if RDATA parser +/// fails to recognize a given textual representation. +/// +class InvalidRdataText : public DNSTextError { +public: + InvalidRdataText(const char* file, size_t line, const char* what) : + DNSTextError(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if RDATA parser +/// encounters a character-string (as defined in RFC1035) exceeding +/// the maximum allowable length (\c MAX_CHARSTRING_LEN). +/// +class CharStringTooLong : public DNSTextError { +public: + CharStringTooLong(const char* file, size_t line, const char* what) : + DNSTextError(file, line, what) {} +}; + +// Forward declaration to define RdataPtr. +class Rdata; + +/// +/// The \c RdataPtr type is a pointer-like type, pointing to an +/// object of some concrete derived class of \c Rdata. +/// +typedef boost::shared_ptr<Rdata> RdataPtr; +typedef boost::shared_ptr<const Rdata> ConstRdataPtr; + +/// \brief Possible maximum length of RDATA, which is the maximum unsigned +/// 16 bit value. +const size_t MAX_RDLENGTH = 65535; + +/// \brief The maximum allowable length of character-string containing in +/// RDATA as defined in RFC1035, not including the 1-byte length field. +const unsigned int MAX_CHARSTRING_LEN = 255; + +/// \brief The \c Rdata class is an abstract base class that provides +/// a set of common interfaces to manipulate concrete RDATA objects. +/// +/// Generally, a separate derived class directly inherited from the base +/// \c Rdata class is defined for each well known RDATA. +/// Each of such classes will define the common logic based on the +/// corresponding protocol standard. +/// +/// Since some types of RRs are class specific and the corresponding RDATA +/// may have different semantics (e.g. type A for class IN and type A for +/// class CH have different representations and semantics), we separate +/// \c Rdata derived classes for such RR types in different namespaces. +/// The namespace of types specific to a class is named the lower-cased class +/// name; for example, RDATA of class IN-specific types are defined in the +/// \c in namespace, and RDATA of class CH-specific types are defined in +/// the \c ch namespace, and so on. +/// The derived classes are named using the RR type name (upper cased) such as +/// \c A or \c AAAA. +/// Thus RDATA of type A RR for class IN and CH are defined as \c in::A and +/// \c ch::A, respectively. +/// Many other RR types are class independent; the derived \c Rdata classes +/// for such RR types are defined in the \c generic namespace. Examples are +/// \c generic::NS and \c generic::SOA. +/// +/// If applications need to refer to these derived classes, it is generally +/// recommended to prepend at least some part of the namespace because the +/// same class name can be used in different namespaces. +/// So, instead of doing +/// \code using namespace isc::dns::rdata::in; +/// A& rdata_type_a; \endcode +/// it is advisable to prepend at least \c in from the namespace: +/// \code using namespace isc::dns::rdata; +/// in::A& rdata_type_a; \endcode +/// +/// In many cases, however, an application doesn't have to care about such +/// derived classes. +/// For instance, to parse an incoming DNS message an application wouldn't +/// have to perform type specific operation unless the application is +/// specifically concerned about a particular type. +/// So, this API generally handles \c Rdata in a polymorphic way through +/// a pointer or reference to this base abstract class. +class Rdata { + /// + /// \name Constructors and Destructor + /// + /// Note: The copy constructor and the assignment operator are intentionally + /// defined as private. Concrete classes should generally specialize their + /// own versions of these methods. + //@{ +protected: + /// The default constructor. + /// + /// This is intentionally defined as \c protected as this base class should + /// never be instantiated (except as part of a derived class). In many + /// cases, the derived class wouldn't define a public default constructor + /// either, because an \c Rdata object without concrete data isn't + /// meaningful. + Rdata() {} +private: + Rdata(const Rdata& source); + void operator=(const Rdata& source); +public: + /// The destructor. + virtual ~Rdata() {}; + //@} + + /// + /// \name Converter methods + /// + //@{ + /// \brief Convert an \c Rdata to a string. + /// + /// This method returns a \c std::string object representing the \c Rdata. + /// + /// This is a pure virtual method without the definition; the actual + /// representation is specific to each derived concrete class and + /// should be explicitly defined in the derived class. + /// + /// \return A string representation of \c Rdata. + virtual std::string toText() const = 0; + + /// \brief Render the \c Rdata in the wire format into a buffer. + /// + /// This is a pure virtual method without the definition; the actual + /// conversion is specific to each derived concrete class and + /// should be explicitly defined in the derived class. + /// + /// \param buffer An output buffer to store the wire data. + virtual void toWire(isc::util::OutputBuffer& buffer) const = 0; + + /// \brief Render the \c Rdata in the wire format into a + /// \c MessageRenderer object. + /// + /// This is a pure virtual method without the definition; the actual + /// conversion is specific to each derived concrete class and + /// should be explicitly defined in the derived class. + /// + /// \param renderer DNS message rendering context that encapsulates the + /// output buffer in which the \c Rdata is to be stored. + virtual void toWire(AbstractMessageRenderer& renderer) const = 0; + //@} + + /// + /// \name Comparison method + /// + //@{ + /// \brief Compare two instances of \c Rdata. + /// + /// This method compares \c this and the \c other Rdata objects + /// in terms of the DNSSEC sorting order as defined in RFC4034, and returns + /// the result as an integer. + /// + /// This is a pure virtual method without the definition; the actual + /// comparison logic is specific to each derived concrete class and + /// should be explicitly defined in the derived class. + /// + /// Specific implementations of this method must confirm that \c this + /// and the \c other are objects of the same concrete derived class of + /// \c Rdata. This is normally done by \c dynamic_cast in the + /// implementation. It also means if the assumption isn't met + /// an exception of class \c std::bad_cast will be thrown. + /// + /// Here is an implementation choice: instead of relying on + /// \c dynamic_cast, we could first convert the data into wire-format + /// and compare the pair as opaque data. This would be more polymorphic, + /// but might involve significant overhead, especially for a large size + /// of RDATA. + /// + /// \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. + virtual int compare(const Rdata& other) const = 0; + //@} + + /// \brief Get the wire format length of an Rdata. + /// + /// IMPLEMENTATION NOTE: Currently this base class implementation is + /// non-optimal as it renders the wire data to a buffer and returns + /// the buffer's length. What would perform better is to add + /// implementations of \c getLength() method to every RDATA + /// type. This is why this method is virtual. Once all Rdata types + /// have \c getLength() implementations, this base class + /// implementation must be removed and the method should become a + /// pure interface. + /// + /// \return The length of the wire format representation of the + /// RDATA. + virtual uint16_t getLength() const; +}; + +namespace generic { + +/// \brief The \c GenericImpl class is the actual implementation of the +/// \c generic::Generic class. +/// +/// The implementation is hidden from applications. This approach requires +/// dynamic memory allocation on construction, copy, or assignment, but +/// we believe it should be acceptable as "unknown" RDATA should be pretty +/// rare. +struct GenericImpl; + +/// \brief The \c generic::Generic class represents generic "unknown" RDATA. +/// +/// This class is used as a placeholder for all non well-known type of RDATA. +/// By definition, the stored data is regarded as opaque binary without +/// assuming any structure. +class Generic : public Rdata { +public: + /// + /// \name Constructors, Assignment Operator and Destructor. + /// + //@{ + /// \brief Constructor from a string. + /// + /// This method constructs a \c generic::Generic object from a textual + /// representation as defined in RFC3597. + /// + /// If \c rdata_string isn't a valid textual representation of this type + /// of RDATA, an exception of class \c InvalidRdataText or + /// \c InvalidRdataLength will be thrown. + /// If resource allocation to store the data fails, a corresponding standard + /// exception will be thrown. + /// + /// \param rdata_string A string of textual representation of generic + /// RDATA. + explicit Generic(const std::string& rdata_string); + + /// + /// \brief Constructor from wire-format data. + /// + /// The \c buffer parameter normally stores a complete DNS message + /// containing the generic RDATA to be constructed. + /// The current read position of the buffer points to the head of the + /// data. + /// + /// This method reads \c rdata_len bytes from the \c buffer, and internally + /// stores the data as an opaque byte sequence. + /// + /// \c rdata_len must not exceed \c MAX_RDLENGTH; otherwise, an exception + /// of class \c InvalidRdataLength will be thrown. + /// If resource allocation to hold the data fails, a corresponding standard + /// exception will be thrown; if the \c buffer doesn't contain \c rdata_len + /// bytes of unread data, an exception of class \c InvalidBufferPosition + /// will be thrown. + /// + /// \param buffer A reference to an \c InputBuffer object storing the + /// \c Rdata to parse. + /// \param rdata_len The length in buffer of the \c Rdata. In bytes. + Generic(isc::util::InputBuffer& buffer, size_t rdata_len); + + /// \brief Constructor from master lexer. + /// + Generic(MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + + /// + /// \brief The destructor. + virtual ~Generic(); + /// + /// \brief The copy constructor. + /// + /// If resource allocation to copy the data fails, a corresponding standard + /// exception will be thrown. + /// + /// \param source A reference to a \c generic::Generic object to copy from. + Generic(const Generic& source); + + /// + /// \brief The assignment operator. + /// + /// If resource allocation to copy the data fails, a corresponding standard + /// exception will be thrown. + /// + /// \param source A reference to a \c generic::Generic object to copy from. + Generic& operator=(const Generic& source); + //@} + + /// + /// \name Converter methods + /// + //@{ + /// \brief Convert an \c generic::Generic object to a string. + /// + /// This method converts a generic "unknown" RDATA object into a textual + /// representation of such unknown data as defined in RFC3597. + /// + /// If resource allocation to copy the data fails, a corresponding standard + /// exception will be thrown. + /// + /// \return A string representation of \c generic::Generic. + virtual std::string toText() const; + + /// + /// \brief Render the \c generic::Generic in the wire format into a buffer. + /// + /// This will require \c rdata_len bytes of remaining capacity in the + /// \c buffer. If this is not the case and resource allocation for the + /// necessary memory space fails, a corresponding standard exception will + /// be thrown. + /// + /// \param buffer An output buffer to store the wire data. + virtual void toWire(isc::util::OutputBuffer& buffer) const; + + /// \brief Render the \c generic::Generic in the wire format into a + /// \c MessageRenderer object. + /// + /// This will require \c rdata_len bytes of remaining capacity in the + /// \c buffer. If this is not the case and resource allocation for the + /// necessary memory space fails, a corresponding standard exception will + /// be thrown. + /// + /// \param renderer DNS message rendering context that encapsulates the + /// output buffer in which the \c Generic object is to be stored. + virtual void toWire(AbstractMessageRenderer& renderer) const; + //@} + + /// + /// \name Comparison method + /// + //@{ + /// \brief Compare two instances of \c generic::Generic objects. + /// + /// As defined in RFC4034, this method simply compares the wire-format + /// representations of the two objects as left-justified unsigned octet + /// sequences. + /// + /// The object referenced by \c other must have been instantiated as + /// a c generic::Generic class object; otherwise, an exception of class + /// \c std::bad_cast will be thrown. + /// Note that the comparison is RR type/class agnostic: this method doesn't + /// check whether the two \c Rdata objects to compare are of the comparable + /// RR type/class. For example, \c this object may come from an \c RRset + /// of \c RRType x, and the \c other may come from a different \c RRset + /// of \c RRType y (where x != y). This situation would be considered a + /// bug, but this method cannot detect this type of error. + /// The caller must ensure this condition. + /// + /// \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. + virtual int compare(const Rdata& other) const; + //@} + +private: + GenericImpl* constructFromLexer(MasterLexer& lexer); + + GenericImpl* impl_; +}; + +/// +/// \brief Insert the name as a string into stream. +/// +/// This method convert the \c rdata into a string and inserts it into the +/// output stream \c os. +/// +/// This function overloads the global \c operator<< to behave as described in +/// \c ostream::operator<< but applied to \c generic::Generic Rdata objects. +/// +/// \param os A \c std::ostream object on which the insertion operation is +/// performed. +/// \param rdata The \c Generic object output by the operation. +/// \return A reference to the same \c std::ostream object referenced by +/// parameter \c os after the insertion operation. +std::ostream& operator<<(std::ostream& os, const Generic& rdata); +} // end of namespace "generic" + +// +// Non class-member functions related to Rdata +// + +/// +/// \name Parameterized Polymorphic RDATA Factories +/// +/// This set of global functions provide a unified interface to create an +/// \c Rdata object in a parameterized polymorphic way, +/// that is, these functions take a pair of \c RRType and \c RRClass +/// objects and data specific to that pair, and create an object of +/// the corresponding concrete derived class of \c Rdata. +/// +/// These will be useful when parsing/constructing a DNS message or +/// parsing a master file, where information for a specific type of RDATA +/// is given but the resulting object, once created, should better be used +/// in a polymorphic way. +/// +/// For example, if a master file parser encounters an NS RR +/// \verbatim example.com. 3600 IN NS ns.example.com.\endverbatim +/// it stores the text fragments "IN", "NS", and "ns.example.com." in +/// \c std::string objects \c class_txt, \c type_txt, and \c nsname_txt, +/// respectively, then it would create a new \c RdataPtr object as follows: +/// \code RdataPtr rdata = createRdata(RRType(type_txt), RRClass(class_txt), +/// nsname_txt); \endcode +/// On success, \c rdata will point to an object of the \c generic::NS class +/// that internally holds a domain name of "ns.example.com." +/// +/// Internally, these functions uses the corresponding +/// \c RRParamRegistry::createRdata methods of the \c RRParamRegistry. +/// See also the description on these methods for related notes. +//@{ +/// \brief Create RDATA of a given pair of RR type and class from a string. +/// +/// This method creates from a string an \c Rdata object of the given pair +/// of RR type and class. +/// +/// \param rrtype An \c RRType object specifying the type/class pair. +/// \param rrclass An \c RRClass object specifying the type/class pair. +/// \param rdata_string A string of textual representation of the \c Rdata. +/// \return An \c RdataPtr object pointing to the created \c Rdata +/// object. +RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, + const std::string& rdata_string); + +/// \brief Create RDATA of a given pair of RR type and class from +/// wire-format data. +/// +/// This method creates from wire-format binary data an \c Rdata object +/// of the given pair of RR type and class. +/// +/// \c len must not exceed the protocol defined maximum value, \c MAX_RDLENGTH; +/// otherwise, an exception of class \c InvalidRdataLength will be thrown. +/// +/// In some cases, the length of the RDATA is determined without the +/// information of \c len. For example, the RDATA length of an IN/A RR +/// must always be 4. If \c len is not equal to the actual length in such +/// cases, an exception of class InvalidRdataLength will be thrown. +/// +/// \param rrtype An \c RRType object specifying the type/class pair. +/// \param rrclass An \c RRClass object specifying the type/class pair. +/// \param buffer A reference to an \c InputBuffer object storing the +/// \c Rdata to parse. +/// \param len The length in buffer of the \c Rdata. In bytes. +/// \return An \c RdataPtr object pointing to the created \c Rdata +/// object. +RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, + isc::util::InputBuffer& buffer, size_t len); + +/// \brief Create RDATA of a given pair of RR type and class, copying +/// of another RDATA of same kind. +/// +/// This method creates an \c Rdata object of the given pair of +/// RR type and class, copying the content of the given \c Rdata, +/// \c source. +/// +/// \param rrtype An \c RRType object specifying the type/class pair. +/// \param rrclass An \c RRClass object specifying the type/class pair. +/// \param source A reference to an \c Rdata object whose content +/// is to be copied to the created \c Rdata object. +/// \return An \c RdataPtr object pointing to the created +/// \c Rdata object. +RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, + const Rdata& source); + +/// \brief Create RDATA of a given pair of RR type and class using the +/// master lexer. +/// +/// This is a more generic form of factory from textual RDATA, and is mainly +/// intended to be used internally by the master file parser (\c MasterLoader) +/// of this library. +/// +/// The \c lexer is expected to be at the beginning of textual RDATA of the +/// specified type and class. This function (and its underlying Rdata +/// implementations) extracts necessary tokens from the lexer and constructs +/// the RDATA from them. +/// +/// Due to the intended usage of this version, this function handles error +/// cases quite differently from other versions. It internally catches +/// most of syntax and semantics errors of the input (reported as exceptions), +/// calls the corresponding callback specified by the \c callbacks parameters, +/// and returns a NULL smart pointer. If the caller rather wants to get +/// an exception in these cases, it can pass a callback that internally +/// throws on error. Some critical exceptions such as \c std::bad_alloc are +/// still propagated to the upper layer as it doesn't make sense to try +/// recovery from such a situation within this function. +/// +/// Whether or not the creation succeeds, this function updates the lexer +/// until it reaches either the end of line or file, starting from the end of +/// the RDATA text (or the point of failure if the parsing fails in the +/// middle of it). The caller can therefore assume it's ready for reading +/// the next data (which is normally a subsequent RR in the zone file) on +/// return, whether or not this function succeeds. +/// +/// \param rrtype An \c RRType object specifying the type/class pair. +/// \param rrclass An \c RRClass object specifying the type/class pair. +/// \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 any domain name fields +/// of the RDATA that are non absolute. +/// \param options Master loader options controlling how to deal with errors +/// or non critical issues in the parsed RDATA. +/// \param callbacks Callback to be called when an error or non critical issue +/// is found. +/// \return An \c RdataPtr object pointing to the created +/// \c Rdata object. Will be NULL if parsing fails. +RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, + MasterLexer& lexer, const Name* origin, + MasterLoader::Options options, + MasterLoaderCallbacks& callbacks); + +//@} + +/// +/// \brief Gives relative ordering of two names in terms of DNSSEC RDATA +/// ordering. +/// +/// This method compares two names as defined in Sections 6.2 and 6.3 of +/// RFC4034: Comparing two names in their canonical form +/// (i.e., converting upper case ASCII characters to lower ones) and +/// as a left-justified unsigned octet sequence. Note that the ordering is +/// different from that for owner names. For example, "a.example" should be +/// sorted before "example" as RDATA, but the ordering is the opposite when +/// compared as owner names. +/// +/// Normally, applications would not need this function directly. +/// This is mostly an internal helper function for \c Rdata related classes +/// to implement their \c compare() method. +/// This function is publicly open, however, for the convenience of +/// external developers who want to implement new or experimental RR types. +/// +/// This function never throws an exception as long as the given names are +/// valid \c Name objects. +/// +/// Additional note about applicability: In fact, BIND9's similar function, +/// \c dns_name_rdatacompare(), is only used in rdata implementations and +/// for testing purposes. +/// +/// \param n1,n2 \c Name class objects to compare. +/// \return -1 if \c n1 would be sorted before \c n2. +/// \return 0 if \c n1 is identical to \c n2 in terms of sorting order. +/// \return 1 if \c n1 would be sorted after \c n2. +/// +int compareNames(const Name& n1, const Name& n2); + +} // end of namespace "rdata" +} +} +#endif // RDATA_H + +// Local Variables: +// mode: c++ +// End: 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: diff --git a/src/lib/dns/rdata_pimpl_holder.h b/src/lib/dns/rdata_pimpl_holder.h new file mode 100644 index 0000000..baa343a --- /dev/null +++ b/src/lib/dns/rdata_pimpl_holder.h @@ -0,0 +1,52 @@ +// 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/. + +#ifndef DNS_RDATA_PIMPL_HOLDER_H +#define DNS_RDATA_PIMPL_HOLDER_H 1 + +#include <boost/noncopyable.hpp> + +#include <cstddef> // for NULL + +namespace isc { +namespace dns { +namespace rdata { + +template <typename T> +class RdataPimplHolder : boost::noncopyable { +public: + RdataPimplHolder(T* obj = NULL) : + obj_(obj) + {} + + ~RdataPimplHolder() { + delete obj_; + } + + void reset(T* obj = NULL) { + delete obj_; + obj_ = obj; + } + + T* get() { + return (obj_); + } + + T* release() { + T* obj = obj_; + obj_ = NULL; + return (obj); + } + +private: + T* obj_; +}; + +} // namespace rdata +} // namespace dns +} // namespace isc + +#endif // DNS_RDATA_PIMPL_HOLDER_H diff --git a/src/lib/dns/rdataclass.cc b/src/lib/dns/rdataclass.cc new file mode 100644 index 0000000..dcd5e13 --- /dev/null +++ b/src/lib/dns/rdataclass.cc @@ -0,0 +1,7078 @@ +/////////////// +/////////////// +/////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py. +/////////////// DO NOT EDIT! +/////////////// +/////////////// + +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace any { + +// 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 of namespace "any" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace ch { + +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 of namespace "ch" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2014-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +/// \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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2012-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// 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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2014-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace generic { + +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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace hs { + +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 of namespace "hs" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace in { + +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 of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2010-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace in { + +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 of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace in { + +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 of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +// Copyright (C) 2011-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 <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; + +namespace isc { +namespace dns { +namespace rdata { +namespace in { + +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 of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" diff --git a/src/lib/dns/rdataclass.h b/src/lib/dns/rdataclass.h new file mode 100644 index 0000000..85e6551 --- /dev/null +++ b/src/lib/dns/rdataclass.h @@ -0,0 +1,2746 @@ +/////////////// +/////////////// +/////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py. +/////////////// DO NOT EDIT! +/////////////// +/////////////// + + +#ifndef DNS_RDATACLASS_H +#define DNS_RDATACLASS_H 1 + +#include <dns/master_loader.h> + +namespace isc { +namespace dns { +class Name; +class MasterLexer; +class MasterLoaderCallbacks; +} +} +// Copyright (C) 2010-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 ANY_TSIG_250_H +#define ANY_TSIG_250_H 1 + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace any { + +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 + + explicit TSIG(const std::string& type_str); + TSIG(isc::util::InputBuffer& buffer, size_t rdata_len); + TSIG(const TSIG& other); + TSIG( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "any" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // ANY_TSIG_250_H + +// Copyright (C) 2010-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 CH_A_1_H +#define CH_A_1_H 1 + +#include <string> + +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace ch { + +class A : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit A(const std::string& type_str); + A(isc::util::InputBuffer& buffer, size_t rdata_len); + A(const A& other); + A( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // END_COMMON_MEMBERS +}; + +} // end of namespace "ch" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // CH_A_1_H + +// Copyright (C) 2011-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 GENERIC_AFSDB_18_H +#define GENERIC_AFSDB_18_H 1 + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +/// \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 + + explicit AFSDB(const std::string& type_str); + AFSDB(isc::util::InputBuffer& buffer, size_t rdata_len); + AFSDB(const AFSDB& other); + AFSDB( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_AFSDB_18_H + +// Copyright (C) 2014-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 GENERIC_CAA_257_H +#define GENERIC_CAA_257_H 1 + +#include <stdint.h> + +#include <dns/name.h> +#include <dns/rdata.h> + +#include <string> +#include <vector> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct CAAImpl; + +class CAA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit CAA(const std::string& type_str); + CAA(isc::util::InputBuffer& buffer, size_t rdata_len); + CAA(const CAA& other); + CAA( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_CAA_257_H + +// Copyright (C) 2010-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 GENERIC_CNAME_5_H +#define GENERIC_CNAME_5_H 1 + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +class CNAME : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit CNAME(const std::string& type_str); + CNAME(isc::util::InputBuffer& buffer, size_t rdata_len); + CNAME(const CNAME& other); + CNAME( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // END_COMMON_MEMBERS + + // CNAME specific methods + CNAME(const Name& cname); + const Name& getCname() const; +private: + Name cname_; +}; + +} // end of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_CNAME_5_H + +// Copyright (C) 2011-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 GENERIC_DLV_32769_H +#define GENERIC_DLV_32769_H 1 + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +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 + + explicit DLV(const std::string& type_str); + DLV(isc::util::InputBuffer& buffer, size_t rdata_len); + DLV(const DLV& other); + DLV( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_DLV_32769_H + +// Copyright (C) 2010-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 GENERIC_DNAME_39_H +#define GENERIC_DNAME_39_H 1 + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +class DNAME : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit DNAME(const std::string& type_str); + DNAME(isc::util::InputBuffer& buffer, size_t rdata_len); + DNAME(const DNAME& other); + DNAME( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // END_COMMON_MEMBERS + + // DNAME specific methods + DNAME(const Name& dname); + const Name& getDname() const; +private: + Name dname_; +}; + +} // end of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_DNAME_39_H + +// Copyright (C) 2010-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 <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> + +#ifndef GENERIC_DNSKEY_48_H +#define GENERIC_DNSKEY_48_H 1 + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct DNSKEYImpl; + +class DNSKEY : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit DNSKEY(const std::string& type_str); + DNSKEY(isc::util::InputBuffer& buffer, size_t rdata_len); + DNSKEY(const DNSKEY& other); + DNSKEY( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_DNSKEY_48_H + +// Copyright (C) 2011-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 GENERIC_DS_43_H +#define GENERIC_DS_43_H 1 + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +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 + + explicit DS(const std::string& type_str); + DS(isc::util::InputBuffer& buffer, size_t rdata_len); + DS(const DS& other); + DS( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_DS_43_H + +// Copyright (C) 2011-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 GENERIC_HINFO_13_H +#define GENERIC_HINFO_13_H 1 +#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> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +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 + + explicit HINFO(const std::string& type_str); + HINFO(isc::util::InputBuffer& buffer, size_t rdata_len); + HINFO(const HINFO& other); + HINFO( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_HINFO_13_H + +// Copyright (C) 2011-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 GENERIC_MINFO_14_H +#define GENERIC_MINFO_14_H 1 + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +/// \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 + + explicit MINFO(const std::string& type_str); + MINFO(isc::util::InputBuffer& buffer, size_t rdata_len); + MINFO(const MINFO& other); + MINFO( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_MINFO_14_H + +// Copyright (C) 2010-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 GENERIC_MX_15_H +#define GENERIC_MX_15_H 1 + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +class MX : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit MX(const std::string& type_str); + MX(isc::util::InputBuffer& buffer, size_t rdata_len); + MX(const MX& other); + MX( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_MX_15_H + +// Copyright (C) 2011-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 GENERIC_NAPTR_35_H +#define GENERIC_NAPTR_35_H 1 + +#include <string> + +#include <boost/scoped_ptr.hpp> + +#include <dns/name.h> +#include <dns/rdata.h> +#include <util/buffer.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +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 + + explicit NAPTR(const std::string& type_str); + NAPTR(isc::util::InputBuffer& buffer, size_t rdata_len); + NAPTR(const NAPTR& other); + NAPTR( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_NAPTR_35_H + +// Copyright (C) 2010-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 GENERIC_NS_2_H +#define GENERIC_NS_2_H 1 + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +class NS : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit NS(const std::string& type_str); + NS(isc::util::InputBuffer& buffer, size_t rdata_len); + NS(const NS& other); + NS( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // END_COMMON_MEMBERS + /// + /// Specialized constructor + /// + explicit NS(const Name& nsname) : nsname_(nsname) {} + /// + /// Specialized methods + /// + const Name& getNSName() const; +private: + Name nsname_; +}; + +} // end of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_NS_2_H + +// Copyright (C) 2010-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 <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> + +#ifndef GENERIC_NSEC3_50_H +#define GENERIC_NSEC3_50_H 1 + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct NSEC3Impl; + +class NSEC3 : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit NSEC3(const std::string& type_str); + NSEC3(isc::util::InputBuffer& buffer, size_t rdata_len); + NSEC3(const NSEC3& other); + NSEC3( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_NSEC3_50_H + +// Copyright (C) 2010-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 <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> + +#ifndef GENERIC_NSEC3PARAM_51_H +#define GENERIC_NSEC3PARAM_51_H 1 + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct NSEC3PARAMImpl; + +class NSEC3PARAM : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit NSEC3PARAM(const std::string& type_str); + NSEC3PARAM(isc::util::InputBuffer& buffer, size_t rdata_len); + NSEC3PARAM(const NSEC3PARAM& other); + NSEC3PARAM( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_NSEC3PARAM_51_H + +// Copyright (C) 2010-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 <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> + +#ifndef GENERIC_NSEC_47_H +#define GENERIC_NSEC_47_H 1 + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct NSECImpl; + +class NSEC : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit NSEC(const std::string& type_str); + NSEC(isc::util::InputBuffer& buffer, size_t rdata_len); + NSEC(const NSEC& other); + NSEC( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_NSEC_47_H + +// Copyright (C) 2010-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 GENERIC_OPT_41_H +#define GENERIC_OPT_41_H 1 + +#include <string> + +#include <dns/rdata.h> + +#include <boost/shared_ptr.hpp> + +#include <vector> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct OPTImpl; + +class OPT : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit OPT(const std::string& type_str); + OPT(isc::util::InputBuffer& buffer, size_t rdata_len); + OPT(const OPT& other); + OPT( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_OPT_41_H + +// Copyright (C) 2010-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 GENERIC_PTR_12_H +#define GENERIC_PTR_12_H 1 + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +class PTR : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit PTR(const std::string& type_str); + PTR(isc::util::InputBuffer& buffer, size_t rdata_len); + PTR(const PTR& other); + PTR( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_PTR_12_H + +// Copyright (C) 2011-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 GENERIC_RP_17_H +#define GENERIC_RP_17_H 1 + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +/// \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 + + explicit RP(const std::string& type_str); + RP(isc::util::InputBuffer& buffer, size_t rdata_len); + RP(const RP& other); + RP( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_RP_17_H + +// Copyright (C) 2010-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 <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rdata.h> + +#ifndef GENERIC_RRSIG_46_H +#define GENERIC_RRSIG_46_H 1 + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +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 + + explicit RRSIG(const std::string& type_str); + RRSIG(isc::util::InputBuffer& buffer, size_t rdata_len); + RRSIG(const RRSIG& other); + RRSIG( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_RRSIG_46_H + +// Copyright (C) 2010-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 GENERIC_SOA_6_H +#define GENERIC_SOA_6_H 1 + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/serial.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +class SOA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit SOA(const std::string& type_str); + SOA(isc::util::InputBuffer& buffer, size_t rdata_len); + SOA(const SOA& other); + SOA( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_SOA_6_H + +// Copyright (C) 2010-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 GENERIC_SPF_99_H +#define GENERIC_SPF_99_H 1 + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +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 + + explicit SPF(const std::string& type_str); + SPF(isc::util::InputBuffer& buffer, size_t rdata_len); + SPF(const SPF& other); + SPF( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_SPF_99_H + +// Copyright (C) 2012-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 GENERIC_SSHFP_44_H +#define GENERIC_SSHFP_44_H 1 + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct SSHFPImpl; + +class SSHFP : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit SSHFP(const std::string& type_str); + SSHFP(isc::util::InputBuffer& buffer, size_t rdata_len); + SSHFP(const SSHFP& other); + SSHFP( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_SSHFP_44_H + +// 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/. + +#ifndef GENERIC_TKEY_249_H +#define GENERIC_TKEY_249_H 1 + +#include <stdint.h> + +#include <string> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +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 + + explicit TKEY(const std::string& type_str); + TKEY(isc::util::InputBuffer& buffer, size_t rdata_len); + TKEY(const TKEY& other); + TKEY( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_TKEY_249_H + +// Copyright (C) 2014-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 GENERIC_TLSA_52_H +#define GENERIC_TLSA_52_H 1 + +#include <stdint.h> + +#include <dns/name.h> +#include <dns/rdata.h> + +#include <string> +#include <vector> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +struct TLSAImpl; + +class TLSA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit TLSA(const std::string& type_str); + TLSA(isc::util::InputBuffer& buffer, size_t rdata_len); + TLSA(const TLSA& other); + TLSA( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_TLSA_52_H + +// Copyright (C) 2010-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 GENERIC_TXT_16_H +#define GENERIC_TXT_16_H 1 + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace generic { + +namespace detail { +template<class Type, uint16_t typeCode> class TXTLikeImpl; +} + +class TXT : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit TXT(const std::string& type_str); + TXT(isc::util::InputBuffer& buffer, size_t rdata_len); + TXT(const TXT& other); + TXT( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // END_COMMON_MEMBERS + + TXT& operator=(const TXT& source); + ~TXT(); + +private: + typedef isc::dns::rdata::generic::detail::TXTLikeImpl<TXT, 16> TXTImpl; + TXTImpl* impl_; +}; + +} // end of namespace "generic" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // GENERIC_TXT_16_H + +// Copyright (C) 2010-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 HS_A_1_H +#define HS_A_1_H 1 + +#include <string> + +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace hs { + +class A : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit A(const std::string& type_str); + A(isc::util::InputBuffer& buffer, size_t rdata_len); + A(const A& other); + A( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // END_COMMON_MEMBERS +}; + +} // end of namespace "hs" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // HS_A_1_H + +// Copyright (C) 2010-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 IN_A_1_H +#define IN_A_1_H 1 + +#include <string> + +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace in { + +class A : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit A(const std::string& type_str); + A(isc::util::InputBuffer& buffer, size_t rdata_len); + A(const A& other); + A( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // IN_A_1_H + +// Copyright (C) 2010-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 IN_AAAA_28_H +#define IN_AAAA_28_H 1 + +#include <stdint.h> + +#include <string> + +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace in { + +class AAAA : public Rdata { +public: + // BEGIN_COMMON_MEMBERS + + explicit AAAA(const std::string& type_str); + AAAA(isc::util::InputBuffer& buffer, size_t rdata_len); + AAAA(const AAAA& other); + AAAA( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // END_COMMON_MEMBERS + // notyet: + //const struct in6_addr& getAddress() const { return (addr_); } +private: + uint8_t addr_[16]; // raw IPv6 address (network byte order) +}; + +} // end of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // IN_AAAA_28_H + +// Copyright (C) 2011-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 IN_DHCID_49_H +#define IN_DHCID_49_H 1 + +#include <string> +#include <vector> + +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace in { + +/// \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 + + explicit DHCID(const std::string& type_str); + DHCID(isc::util::InputBuffer& buffer, size_t rdata_len); + DHCID(const DHCID& other); + DHCID( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // IN_DHCID_49_H + +// Copyright (C) 2011-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 IN_SRV_33_H +#define IN_SRV_33_H 1 + +#include <stdint.h> + +#include <dns/name.h> +#include <dns/rdata.h> + +namespace isc { +namespace util { + +class InputBuffer; +class OutputBuffer; +} + +namespace dns { + +// BEGIN_COMMON_DECLARATIONS + +class AbstractMessageRenderer; + +// END_COMMON_DECLARATIONS + +namespace rdata { +namespace in { + +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 + + explicit SRV(const std::string& type_str); + SRV(isc::util::InputBuffer& buffer, size_t rdata_len); + SRV(const SRV& other); + SRV( + MasterLexer& lexer, const Name* name, + MasterLoader::Options options, MasterLoaderCallbacks& callbacks); + virtual std::string toText() const; + virtual void toWire(isc::util::OutputBuffer& buffer) const; + virtual void toWire(AbstractMessageRenderer& renderer) const; + virtual int compare(const Rdata& other) const; + + // 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 of namespace "in" +} // end of namespace "rdata" +} // end of namespace "dns" +} // end of namespace "isc" +#endif // IN_SRV_33_H + + +#endif // DNS_RDATACLASS_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/rdatafields.cc b/src/lib/dns/rdatafields.cc new file mode 100644 index 0000000..e02ec8f --- /dev/null +++ b/src/lib/dns/rdatafields.cc @@ -0,0 +1,216 @@ +// Copyright (C) 2010-2015,2017 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 <cassert> +#include <vector> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdatafields.h> + +using namespace std; +using namespace isc::dns; +using namespace isc::dns::rdata; +using isc::util::OutputBuffer; +using isc::util::InputBuffer; + +namespace isc { +namespace dns { +namespace rdata { + +/// This is a helper class for \c RdataFields. +/// +/// It manages a local storage for the data when \c RdataFields is constructed +/// from an \c Rdata. +/// To minimize construction overhead in the other case, an instance of +/// this class is instantiated only when necessary - we don't need the vectors +/// when only rendering. +struct RdataFields::RdataFieldsDetail { + RdataFieldsDetail(const vector<FieldSpec>& fields, + const uint8_t* data, size_t data_length) : + allocated_fields_(fields), + allocated_data_(data, data + data_length) + {} + const vector<FieldSpec> allocated_fields_; + const vector<uint8_t> allocated_data_; +}; + +namespace { +// This class is used to divide the content of RDATA into \c RdataField +// fields via message rendering logic. +// The idea is to identify domain name fields in the writeName() method, +// and determine whether they are compressible using the "compress" +// parameter. +// Other types of data are simply copied into the internal buffer, and +// consecutive such fields are combined into a single \c RdataField field. +// +// Technically, this use of inheritance may be considered a violation of +// Liskov Substitution Principle in that it doesn't actually compress domain +// names, and some of the methods are not expected to be used. +// In fact, skip() or trim() may not be make much sense in this context. +// Nevertheless we keep this idea at the moment. Since the usage is limited +// (it's only used within this file, and only used with \c Rdata variants), +// it's hopefully an acceptable practice. +class RdataFieldComposer : public AbstractMessageRenderer { +public: + RdataFieldComposer() : + truncated_(false), length_limit_(65535), + mode_(CASE_INSENSITIVE), last_data_pos_(0) + {} + virtual ~RdataFieldComposer() {} + virtual bool isTruncated() const { return (truncated_); } + virtual size_t getLengthLimit() const { return (length_limit_); } + virtual CompressMode getCompressMode() const { return (mode_); } + virtual void setTruncated() { truncated_ = true; } + virtual void setLengthLimit(size_t len) { length_limit_ = len; } + virtual void setCompressMode(CompressMode mode) { mode_ = mode; } + virtual void writeName(const LabelSequence&, bool) {} + virtual void writeName(const Name& name, bool compress) { + extendData(); + const RdataFields::Type field_type = + compress ? RdataFields::COMPRESSIBLE_NAME : + RdataFields::INCOMPRESSIBLE_NAME; + // TODO: When we get rid of need for getBuffer, we can output the name + // to a buffer and then write the buffer inside + name.toWire(getBuffer()); + fields_.push_back(RdataFields::FieldSpec(field_type, + name.getLength())); + last_data_pos_ = getLength(); + } + + virtual void clear() { + isc_throw(Unexpected, "unexpected clear() for RdataFieldComposer"); + } + bool truncated_; + size_t length_limit_; + CompressMode mode_; + vector<RdataFields::FieldSpec> fields_; + vector<RdataFields::FieldSpec>& getFields() { + extendData(); + return (fields_); + } + // We use generic write* methods, with the exception of writeName. + // So new data can arrive without us knowing it, this considers all new + // data to be just data and extends the fields to take it into account. + size_t last_data_pos_; + void extendData() { + // No news, return to work + if (getLength() == last_data_pos_) { + return; + } + // The new bytes are just ordinary uninteresting data + if (fields_.empty() || fields_.back().type != RdataFields::DATA) { + fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0)); + } + // We added this much data from last time + fields_.back().len += getLength() - last_data_pos_; + last_data_pos_ = getLength(); + } +}; + +} + +RdataFields::RdataFields(const Rdata& rdata) { + RdataFieldComposer field_composer; + rdata.toWire(field_composer); + nfields_ = field_composer.getFields().size(); + data_length_ = field_composer.getLength(); + if (nfields_ > 0) { + assert(data_length_ > 0); + detail_ = new RdataFieldsDetail(field_composer.getFields(), + static_cast<const uint8_t*> + (field_composer.getData()), + field_composer.getLength()); + data_ = &detail_->allocated_data_[0]; + fields_ = &detail_->allocated_fields_[0]; + } else { + assert(data_length_ == 0); + detail_ = NULL; + data_ = NULL; + fields_ = NULL; + } +} + +RdataFields::RdataFields(const void* fields, const unsigned int fields_length, + const void* data, const size_t data_length) : + fields_(static_cast<const FieldSpec*>(fields)), + nfields_(fields_length / sizeof(*fields_)), + data_(static_cast<const uint8_t*>(data)), + data_length_(data_length), + detail_(NULL) +{ + if ((fields_ == NULL && nfields_ > 0) || + (fields_ != NULL && nfields_ == 0)) { + isc_throw(InvalidParameter, + "Inconsistent parameters for RdataFields: fields_length (" + << fields_length << ") and fields conflict each other"); + } + if ((data_ == NULL && data_length_ > 0) || + (data_ != NULL && data_length_ == 0)) { + isc_throw(InvalidParameter, + "Inconsistent parameters for RdataFields: data length (" + << data_length_ << ") and data conflict each other"); + } + + size_t total_length = 0; + for (unsigned int i = 0; i < nfields_; ++i) { + total_length += fields_[i].len; + } + if (total_length != data_length_) { + isc_throw(InvalidParameter, + "Inconsistent parameters for RdataFields: " + "fields len: " << total_length << + " data len: " << data_length_); + } +} + +RdataFields::~RdataFields() { + delete detail_; +} + +RdataFields::FieldSpec +RdataFields::getFieldSpec(const unsigned int field_id) const { + if (field_id >= nfields_) { + isc_throw(OutOfRange, "Rdata field ID is out of range: " << field_id); + } + return (fields_[field_id]); +} + +void +RdataFields::toWire(AbstractMessageRenderer& renderer) const { + size_t offset = 0; + + for (unsigned int i = 0; i < nfields_; ++i) { + if (fields_[i].type == DATA) { + renderer.writeData(data_ + offset, fields_[i].len); + } else { + // XXX: this is inefficient. Even if it's quite likely the + // data is a valid wire representation of a name we parse + // it to construct the Name object in the generic mode. + // This should be improved in a future version. + InputBuffer buffer(data_ + offset, fields_[i].len); + renderer.writeName(Name(buffer), + fields_[i].type == COMPRESSIBLE_NAME); + } + offset += fields_[i].len; + } +} + +void +RdataFields::toWire(OutputBuffer& buffer) const { + buffer.writeData(data_, data_length_); +} +} // end of namespace rdata +} // end of namespace dns +} // end of namespace isc diff --git a/src/lib/dns/rdatafields.h b/src/lib/dns/rdatafields.h new file mode 100644 index 0000000..c4a64ad --- /dev/null +++ b/src/lib/dns/rdatafields.h @@ -0,0 +1,419 @@ +// 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/. + +#ifndef RDATAFIELDS_H +#define RDATAFIELDS_H 1 + +#include <stdint.h> + +#include <cstddef> + +namespace isc { +namespace util { +class OutputBuffer; +} +namespace dns { +class AbstractMessageRenderer; + +namespace rdata { +class Rdata; + +/// A low-level, RR type-independent representation of DNS RDATA. +/// +/// <b>Purpose of the Class</b> +/// +/// This class intends to help "serialization" of the content of RDATA +/// in a space-efficient manner. Specific derived classes of \c Rdata +/// focus on the convenience of accessing RDATA fields for RR type-specific +/// protocol operations, and can be inefficient in terms of space. +/// For example, a DNS character string may be internally represented as a +/// \c std::string object with all of the overhead of the richer class. +/// If an application needs to maintain a very large number of RRs and it +/// does not have to perform RR specific operation so often, it may make more +/// sense to store the data in memory in a lower-level but space efficient +/// form. +/// +/// Another purpose of this class is to improve rendering performance for +/// RDATA. If the only requirement were space efficiency, it would be just +/// sufficient to convert the \c RDATA into a binary sequence in the wire +/// format. However, to render the data in a DNS message, we'd have to +/// re-construct a corresponding \c Rdata object in the case where name +/// compression is necessary. This is not desirable, and this class is +/// provided to avoid such unnecessary overhead. +/// +/// <b>Data Format</b> +/// +/// To meet these goals, this class helps convert an \c Rdata object into +/// two pieces of information: Wire-format representation of the \c Rdata +/// and associated meta information for efficient rendering. +/// +/// Specifically, it maintains the wire-format data as a sequence of typed +/// fields. The types are: +/// - Compressible name: a domain name as an RDATA field that can be compressed +/// - Incompressible name: a domain name as an RDATA field that cannot be +/// compressed +/// - Other data: any other fields of RDATA, which should be treated as opaque +/// +/// (See also the description of \c RdataFields::Type) +/// Whether a name can or cannot be compressed is determined according to +/// RFC3597. +/// +/// A "other data" field may not always correspond to a single RDATA field. +/// A \c RdataFields field (of other data) is just a contiguous region of the +/// wire-format data that does not involve name compression. +/// For example, the SOA RDATA begins with two "compressible" names followed +/// by 5 32-bit fields. +/// In \c RdataFields the last 5 fields would be considered a single 20-byte +/// field. +/// +/// Each \c RdataFields field is identified by the \c FieldSpec structure, +/// which provides the type and length of the field. +/// An \c RdataFields object internally maintains a sequence of \c FieldSpec +/// objects in a form of plain C-style array, which can be referenced via +/// a pointer returned by the \c getFieldSpecData() method. +/// The \c \c FieldSpec for a specific field can also be retrieved by the +/// \c getFieldSpec() method. +/// +/// The following diagram shows the internal memory representation of +/// an SOA RDATA in the form of \c RdataFields object and how an application +/// can get access to the memory region. +/** \verbatim +accessible via |0 getDataLength() bytes +getData()----------> <MNAME><RNAME><Rest of the data> + <---------- 3 * sizeof(FieldSpec) bytes -------------> +getFieldSpecData()-> { compressible name { compressible name { other data + len: MNAME-len } len: RNAME-len } len: 20 } +\endverbatim + */ +/// where MNAME and RNAME are wire format representations of the MNAME and +/// RNAME fields of the SOA RDATA, respectively, and "Rest of the data" +/// encodes the remaining 20 bytes of the RDATA in network byte order. +/// +/// <b>Usage of the Class</b> +/// +/// One major and common use case of the \c RdataFields class is to convert +/// a \c Rdata object (possibly given from a DNS message or some configuration +/// source such as a zone file) in the serialized format and store a copy of +/// the data somewhere in memory. The following code sample implements this +/// scenario: +/// \code // assume "rdata" is a reference type to Rdata +/// const RdataFields fields(rdata); +/// const unsigned int fields_size = fields.getFieldDataSize(); +/// memcpy(some_place, fields.getFieldSpecData(), fields_size); +/// const size_t data_length = fields.getDataLength(); +/// memcpy(other_place, fields.getData(), data_length); +/// // (fields_size and data_length should be stored somewhere, too) +/// \endcode +/// +/// Another typical usage is to render the stored data in the wire format +/// as efficiently as possible. The following code is an example of such +/// usage: +/// \code // assume "renderer" is of type MessageRenderer +/// // retrieve data_length and fields_size from the storage +/// RdataFields(some_place, fields_size, other_place, +/// data_length).toWire(renderer); +/// \endcode +/// +/// <b>Notes to Users</b> +/// +/// The main purposes of this class is to help efficient operation +/// for some (limited classes of) performance sensitive application. +/// For this reason the interface and implementation rely on relatively +/// lower-level, riskier primitives such as passing around bare pointers. +/// +/// It is therefore discouraged to use this class for general purpose +/// applications that do not need to maximize performance in terms of either +/// memory footprint or rendering speed. +/// All functionality provided by this class can be achieved via higher level +/// interfaces such as the \c Rdata class variants. +/// Normal applications should use those interfaces. +/// +/// The data format is public information so that an application can examine +/// and use selected parts of data. For example, an application may want to +/// encode domain names in RDATA in a different way while storing the other +/// data in a separate place. +/// However, at this moment the format is still in flux, and it may not +/// be compatible with future versions (see below). +/// +/// <b>Development Notes</b> +/// +/// We should conduct benchmark tests to measure rendering performance. +/// +/// The current implementation needs to re-construct name objects from +/// compressible and incompressible name fields as wire-format data. +/// This is not efficient, and we'll probably want to improve this in a +/// future version. One possibility is to store offset information as well +/// as the name data (at the cost of increasing memory footprint), and +/// to use the pair of data for faster rendering. +class RdataFields { +public: + /// Types of \c RdataFields fields. + /// + /// \c COMPRESSIBLE_NAME and \c INCOMPRESSIBLE_NAME represent a domain + /// name used as a field of an RDATA that can and cannot be compressed + /// per RFC3597. + /// \c DATA means all other types of fields. + enum Type { + DATA, ///< Plain data. + COMPRESSIBLE_NAME, ///< A domain name subject to name compression. + INCOMPRESSIBLE_NAME ///< A domain name that shouldn't be compressed. + }; + + /// Structure that specifies a single \c RdataFields field. + /// + /// This is a straightforward pair of the type and length of a single + /// \c RdataFields field. + /// + /// In some cases an application may want to do deeper inspection of + /// some \c RdataFields field(s). For example, an application may want + /// to construct a \c Name object for each domain name field of an RDATA + /// and use it for some special purpose. + /// The \c FieldSpec structure provides necessary parameters to get access + /// to a specific \c RdataFields field. + /// + /// The following code snippet implements the above example scenario: + /// \code // assume "fields" is of type RdataFields + /// size_t offset = 0; + /// for (int i = 0; i < fields.getFieldCount(); ++i) { + /// const FieldSpec spec = fields.getFieldSpec(i); + /// if (spec.type == RdataFields::COMPRESSIBLE_NAME || + /// spec.type == RdataFields::INCOMPRESSIBLE_NAME) { + /// InputBuffer ibuffer(fields.getData() + offset, spec.len); + /// Name name(ibuffer); + /// // do something with name + /// } + /// offset += spec.len; + /// } \endcode + /// + /// Note that the offset is not included in \c FieldSpec. + /// This is because such deeper inspection would be a relatively rare + /// operation while it is desirable to keep this structure as small as + /// possible for the purpose of space efficiency. + /// Also, if and when an application wants to look into a specific field, + /// it would be quite likely that the application iterates over all fields + /// and does something special for selected fields like the above example. + /// In that case the application can easily and efficiently identify the + /// necessary offset, again, as shown in the above code example. + /// + /// \todo We might find that 16bits per field is generally too much and + /// squeeze the two bit type into it as well, having 14bit length + /// (in the rare case of having too long field, it could be split into + /// multiple ones). That would save 2 bytes per item (one for the type, + /// one for padding). + struct FieldSpec { + FieldSpec(Type type_param, uint16_t len_param) : + type(type_param), len(len_param) + {} + Type type; ///< The type of the field. + uint16_t len; ///< The length of the field in bytes. + }; + + /// + /// \name Constructors and Destructor. + /// + /// \b Note: + /// The copy constructor and the assignment operator are intentionally + /// defined as private, making this class non copyable. + //@{ +private: + RdataFields(const RdataFields& source); + RdataFields& operator=(const RdataFields& source); + +public: + /// Constructor from Rdata. + /// + /// This constructor converts the data of a given \c Rdata object into + /// an \c RdataFields object so that the resulting data can be stored + /// in memory in a space-efficient way. + /// + /// It makes a local copy of the original data and dynamically allocates + /// necessary memory, so is not very efficient. + /// The basic idea is to perform the expensive conversion once and keep + /// using the result as long as possible to improve overall performance + /// in a longer term. + /// + /// If the internal resource allocation fails, a corresponding standard + /// exception will be thrown. + /// The current implementation of this constructor internally calls + /// the <code>Rdata::toWire(AbstractMessageRenderer&) const</code> method + /// for the conversion. + /// If that method throws an exception it will be propagated to the caller + /// of this constructor. + /// + /// \param rdata The RDATA for which the \c RdataFields to be constructed. + RdataFields(const Rdata& rdata); + + /// Constructor from field parameters. + /// + /// The intended usage of this version of constructor is to form a + /// structured representation of \c RDATA encoded by the other + /// constructor so that the resulting object can be used for subsequent + /// operations such as rendering in the wire format. + /// This version is intended to be efficient by not making any copy + /// of variable length data or expensive data inspection. + /// + /// This constructor is basically exception free, except against bogus + /// input parameters. + /// Specifically, the parameters must meet the following conditions; + /// otherwise an exception of class \c InvalidParameter will be thrown. + /// - \c fields can be \c NULL if and only if \c nfields is 0 + /// - \c data can be \c NULL if and only if \c data_length is 0 + /// - the sum of the lengths of \c fields entries must be equal to + /// \c data_length + /// + /// This constructor assumes that the memory region pointed by \c data (if + /// non \c NULL) is encoded as a sequence of valid \c RdataFields fields, + /// and does not perform deep inspection on each field. + /// In particular, for fields of type \c COMPRESSIBLE_NAME or + /// \c INCOMPRESSIBLE_NAME, this constructor assumes the corresponding + /// memory region is a valid representation of domain name. + /// Otherwise, a subsequent method call such as + /// <code>toWire(AbstractMessageRenderer&) const</code> + /// may trigger an unexpected exception. It also expects the fields reside + /// on address that is valid for them (eg. it has valid alignment), see + /// getFieldSpecData() for details. + /// + /// It is the caller's responsibility to ensure this assumption. + /// In general, this constructor is expected to be used for serialized data + /// generated by the other constructor from a valid \c Rdata. + /// The result is not guaranteed if the data is generated in any other + /// ways. + /// + /// The resulting \c RdataFields object does not maintain a copy of + /// \c fields or \c data. It is the caller's responsibility to ensure + /// the memory regions pointed to by these parameters are valid and intact + /// as long as the \c RdataFields object is used. + /// + /// \param fields An array of \c FieldSpec entries. This can be \c NULL. + /// \param fields_length The total length of the \c fields. + /// \param data A pointer to memory region for the entire RDATA. This can + /// be NULL. + /// \param data_length The length of \c data in bytes. + RdataFields(const void* fields, const unsigned int fields_length, + const void* data, const size_t data_length); + + /// The destructor. + ~RdataFields(); + //@} + + /// + /// \name Getter Methods + /// + //@{ + /// \brief Return the length of the entire RDATA encoded in the + /// \c RdataFields in bytes. + /// + /// This method never throws an exception. + unsigned int getDataLength() const { return (data_length_); } + + /// \brief Return a pointer to the RDATA encoded in the \c RdataFields. + /// + /// The RdataFields holds ownership of the data. + /// + /// This method never throws an exception. + const void* getData() const { return (data_); } + + /// \brief Return the number of bytes the buffer returned by + /// getFieldSpecData() will occupy. + /// + /// This method never throws an exception. + unsigned int getFieldSpecDataSize() const { return (nfields_ * + sizeof (*fields_)); } + + /// \brief Return the number of specs fields. + /// + /// It specifies the range of parameter for getFieldSpec(). + /// + /// This method never throws. + unsigned int getFieldCount() const { return (nfields_); } + + /// \brief Return a pointer to a sequence of \c FieldSpec for the + /// \c RdataFields. + /// + /// This should be treated as an opaque internal representation you can + /// just store off somewhere and use it to construct a new RdataFields. + /// from it. If you are really interested, you can typecast it to + /// FieldSpec * (which is what it really is internally). + /// + /// The RdataFields holds ownership of the data. + /// + /// \note You should, however, be aware of alignment issues. The pointer + /// you pass to the constructor must be an address where the FieldSpec + /// can live. If you store it at a wrong address (eg. even one with + /// current implementation on most architectures), it might lead bad + /// things from slow access to SIGBUS. The easiest way is not to + /// interleave the fields with data from getData(). It is OK to place + /// all the fields first (even from multiple RdataFields) and then + /// place all the data after them. + /// + /// This method never throws an exception. + const void* getFieldSpecData() const { + return (fields_); + } + + /// \brief Return the specification of the field identified by the given + /// index. + /// + /// \c field_id is the field index, which must be in the range of + /// <code>[0, getFieldCount())</code>. 0 means the first field, and + /// <code>getFieldCount()-1</code> means the last. + /// + /// If the given index is not in the valid range, an exception of class + /// \c OutOfRange will be thrown. + /// This method never throws an exception otherwise. + /// + /// \param field_id The index of an \c RdataFields field to be returned. + /// \return A \c FieldSpec structure that contains the information of + /// the \c field_id-th field. + FieldSpec getFieldSpec(const unsigned int field_id) const; + //@} + + /// + /// \name Converter Methods + /// + //@{ + /// \brief Render the RdataFields in the wire format with name compression. + /// + /// This method may require resource allocation in \c renderer. + /// If it fails, a corresponding standard exception will be thrown. + /// It should not throw any other exception as long as the \c RdataFields + /// object was constructed from valid parameters (see the description of + /// constructors). The result is not guaranteed if it's constructed in + /// any other ways. + /// + /// \param renderer DNS message rendering context that encapsulates the + /// output buffer and name compression information. + void toWire(AbstractMessageRenderer& renderer) const; + + /// \brief Render the RdataFields in the wire format without name + /// compression. + /// + /// This method may require resource allocation in \c buffer. + /// If it fails, a corresponding standard exception will be thrown. + /// + /// \param buffer An output buffer to store the wire data. + void toWire(isc::util::OutputBuffer& buffer) const; + //@} + +private: + const FieldSpec* fields_; + unsigned int nfields_; + const uint8_t* data_; + size_t data_length_; + + // hide further details within the implementation and don't create vectors + // every time we don't need them. + struct RdataFieldsDetail; + RdataFieldsDetail* detail_; +}; +} +} +} +#endif // RDATAFIELDS_H + +// Local Variables: +// mode: c++ +// End: |