///////////////
///////////////
///////////////   THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
///////////////   DO NOT EDIT!
///////////////
///////////////

// 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;

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-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 <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-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 <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-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;

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-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;

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-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 <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-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;

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-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;

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-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 <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-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;

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-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 <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-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;

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-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;

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-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;

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-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;

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-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;

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-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 <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-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;

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-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;

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-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 <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-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;

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-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;

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-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.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-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;

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) 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;

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-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.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-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 <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-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.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-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 <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-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.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-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 <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"
