diff options
Diffstat (limited to 'src/lib/dns/rdata.h')
-rw-r--r-- | src/lib/dns/rdata.h | 582 |
1 files changed, 582 insertions, 0 deletions
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: |