summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/rdata/generic
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dns/rdata/generic')
-rw-r--r--src/lib/dns/rdata/generic/caa_257.cc306
-rw-r--r--src/lib/dns/rdata/generic/caa_257.h72
-rw-r--r--src/lib/dns/rdata/generic/detail/char_string.cc84
-rw-r--r--src/lib/dns/rdata/generic/detail/char_string.h37
-rw-r--r--src/lib/dns/rdata/generic/opt_41.cc182
-rw-r--r--src/lib/dns/rdata/generic/opt_41.h57
-rw-r--r--src/lib/dns/rdata/generic/sshfp_44.cc30
-rw-r--r--src/lib/dns/rdata/generic/sshfp_44.h4
-rw-r--r--src/lib/dns/rdata/generic/tlsa_52.cc350
-rw-r--r--src/lib/dns/rdata/generic/tlsa_52.h65
10 files changed, 1147 insertions, 40 deletions
diff --git a/src/lib/dns/rdata/generic/caa_257.cc b/src/lib/dns/rdata/generic/caa_257.cc
new file mode 100644
index 0000000000..7d46a57662
--- /dev/null
+++ b/src/lib/dns/rdata/generic/caa_257.cc
@@ -0,0 +1,306 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+
+#include <dns/rdata/generic/detail/char_string.h>
+
+using namespace std;
+using boost::lexical_cast;
+using namespace isc::util;
+
+// BEGIN_ISC_NAMESPACE
+// BEGIN_RDATA_NAMESPACE
+
+struct CAAImpl {
+ // straightforward representation of CAA RDATA fields
+ CAAImpl(uint8_t flags, const std::string& tag,
+ const detail::CharStringData& value) :
+ flags_(flags),
+ tag_(tag),
+ value_(value)
+ {
+ if ((sizeof(flags) + 1 + tag_.size() + value_.size()) > 65535) {
+ isc_throw(InvalidRdataLength,
+ "CAA Value field is too large: " << value_.size());
+ }
+ }
+
+ uint8_t flags_;
+ const std::string tag_;
+ const detail::CharStringData value_;
+};
+
+// helper function for string and lexer constructors
+CAAImpl*
+CAA::constructFromLexer(MasterLexer& lexer) {
+ const uint32_t flags =
+ lexer.getNextToken(MasterToken::NUMBER).getNumber();
+ if (flags > 255) {
+ isc_throw(InvalidRdataText,
+ "CAA flags field out of range");
+ }
+
+ // Tag field must not be empty.
+ const std::string tag =
+ lexer.getNextToken(MasterToken::STRING).getString();
+ if (tag.empty()) {
+ isc_throw(InvalidRdataText, "CAA tag field is empty");
+ } else if (tag.size() > 255) {
+ isc_throw(InvalidRdataText,
+ "CAA tag field is too large: " << tag.size());
+ }
+
+ // Value field may be empty.
+ detail::CharStringData value;
+ MasterToken token = lexer.getNextToken(MasterToken::QSTRING, true);
+ if ((token.getType() != MasterToken::END_OF_FILE) &&
+ (token.getType() != MasterToken::END_OF_LINE))
+ {
+ detail::stringToCharStringData(token.getStringRegion(), value);
+ }
+
+ return (new CAAImpl(flags, tag, value));
+}
+
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid CAA RDATA. There can be
+/// extra space characters at the beginning or end of the text (which
+/// are simply ignored), but other extra text, including a new line,
+/// will make the construction fail with an exception.
+///
+/// The Flags, Tag and Value fields must be within their valid ranges,
+/// but are not constrained to the values defined in RFC6844. The Tag
+/// field must not be empty.
+///
+/// \throw InvalidRdataText if any fields are missing, out of their
+/// valid ranges, incorrect, or empty.
+///
+/// \param caa_str A string containing the RDATA to be created
+CAA::CAA(const string& caa_str) :
+ impl_(NULL)
+{
+ // We use auto_ptr here because if there is an exception in this
+ // constructor, the destructor is not called and there could be a
+ // leak of the CAAImpl that constructFromLexer() returns.
+ std::auto_ptr<CAAImpl> impl_ptr(NULL);
+
+ try {
+ std::istringstream ss(caa_str);
+ MasterLexer lexer;
+ lexer.pushSource(ss);
+
+ impl_ptr.reset(constructFromLexer(lexer));
+
+ if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+ isc_throw(InvalidRdataText, "extra input text for CAA: "
+ << caa_str);
+ }
+ } catch (const MasterLexer::LexerError& ex) {
+ isc_throw(InvalidRdataText, "Failed to construct CAA from '" <<
+ caa_str << "': " << ex.what());
+ }
+
+ impl_ = impl_ptr.release();
+}
+
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual
+/// representation of an CAA RDATA.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing
+/// field.
+/// \throw InvalidRdataText Fields are out of their valid ranges,
+/// incorrect, or empty.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+CAA::CAA(MasterLexer& lexer, const Name*,
+ MasterLoader::Options, MasterLoaderCallbacks&) :
+ impl_(constructFromLexer(lexer))
+{
+}
+
+/// \brief Constructor from InputBuffer.
+///
+/// The passed buffer must contain a valid CAA RDATA.
+///
+/// The Flags, Tag and Value fields must be within their valid ranges,
+/// but are not constrained to the values defined in RFC6844. The Tag
+/// field must not be empty.
+CAA::CAA(InputBuffer& buffer, size_t rdata_len) {
+ if (rdata_len < 2) {
+ isc_throw(InvalidRdataLength, "CAA record too short");
+ }
+
+ const uint8_t flags = buffer.readUint8();
+ const uint8_t tag_length = buffer.readUint8();
+ rdata_len -= 2;
+ if (tag_length == 0) {
+ isc_throw(InvalidRdataText, "CAA tag field is empty");
+ }
+
+ if (rdata_len < tag_length) {
+ isc_throw(InvalidRdataLength,
+ "RDATA is too short for CAA tag field");
+ }
+
+ std::vector<uint8_t> tag_vec(tag_length);
+ buffer.readData(&tag_vec[0], tag_length);
+ std::string tag(tag_vec.begin(), tag_vec.end());
+ rdata_len -= tag_length;
+
+ detail::CharStringData value;
+ value.resize(rdata_len);
+ if (rdata_len > 0) {
+ buffer.readData(&value[0], rdata_len);
+ }
+
+ impl_ = new CAAImpl(flags, tag, value);
+}
+
+CAA::CAA(uint8_t flags, const std::string& tag, const std::string& value) :
+ impl_(NULL)
+{
+ if (tag.empty()) {
+ isc_throw(isc::InvalidParameter,
+ "CAA tag field is empty");
+ } else if (tag.size() > 255) {
+ isc_throw(isc::InvalidParameter,
+ "CAA tag field is too large: " << tag.size());
+ }
+
+ MasterToken::StringRegion region;
+ region.beg = &value[0]; // note std ensures this works even if str is empty
+ region.len = value.size();
+
+ detail::CharStringData value_vec;
+ detail::stringToCharStringData(region, value_vec);
+
+ impl_ = new CAAImpl(flags, tag, value_vec);
+}
+
+CAA::CAA(const CAA& other) :
+ Rdata(), impl_(new CAAImpl(*other.impl_))
+{}
+
+CAA&
+CAA::operator=(const CAA& source) {
+ if (this == &source) {
+ return (*this);
+ }
+
+ CAAImpl* newimpl = new CAAImpl(*source.impl_);
+ delete impl_;
+ impl_ = newimpl;
+
+ return (*this);
+}
+
+CAA::~CAA() {
+ delete impl_;
+}
+
+void
+CAA::toWire(OutputBuffer& buffer) const {
+ buffer.writeUint8(impl_->flags_);
+
+ // The constructors must ensure that the tag field is not empty.
+ assert(!impl_->tag_.empty());
+ buffer.writeUint8(impl_->tag_.size());
+ buffer.writeData(&impl_->tag_[0], impl_->tag_.size());
+
+ if (!impl_->value_.empty()) {
+ buffer.writeData(&impl_->value_[0],
+ impl_->value_.size());
+ }
+}
+
+void
+CAA::toWire(AbstractMessageRenderer& renderer) const {
+ renderer.writeUint8(impl_->flags_);
+
+ // The constructors must ensure that the tag field is not empty.
+ assert(!impl_->tag_.empty());
+ renderer.writeUint8(impl_->tag_.size());
+ renderer.writeData(&impl_->tag_[0], impl_->tag_.size());
+
+ if (!impl_->value_.empty()) {
+ renderer.writeData(&impl_->value_[0],
+ impl_->value_.size());
+ }
+}
+
+std::string
+CAA::toText() const {
+ std::string result;
+
+ result = lexical_cast<std::string>(static_cast<int>(impl_->flags_));
+ result += " " + impl_->tag_;
+ result += " \"" + detail::charStringDataToString(impl_->value_) + "\"";
+
+ return (result);
+}
+
+int
+CAA::compare(const Rdata& other) const {
+ const CAA& other_caa = dynamic_cast<const CAA&>(other);
+
+ if (impl_->flags_ < other_caa.impl_->flags_) {
+ return (-1);
+ } else if (impl_->flags_ > other_caa.impl_->flags_) {
+ return (1);
+ }
+
+ // Do a case-insensitive compare of the tag strings.
+ const int result = boost::ilexicographical_compare
+ <std::string, std::string>(impl_->tag_, other_caa.impl_->tag_);
+ if (result != 0) {
+ return (result);
+ }
+
+ return (detail::compareCharStringDatas(impl_->value_,
+ other_caa.impl_->value_));
+}
+
+uint8_t
+CAA::getFlags() const {
+ return (impl_->flags_);
+}
+
+const std::string&
+CAA::getTag() const {
+ return (impl_->tag_);
+}
+
+const std::vector<uint8_t>&
+CAA::getValue() const {
+ return (impl_->value_);
+}
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/caa_257.h b/src/lib/dns/rdata/generic/caa_257.h
new file mode 100644
index 0000000000..47a1369c97
--- /dev/null
+++ b/src/lib/dns/rdata/generic/caa_257.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// BEGIN_HEADER_GUARD
+
+#include <stdint.h>
+
+#include <dns/name.h>
+#include <dns/rdata.h>
+
+#include <string>
+#include <vector>
+
+// BEGIN_ISC_NAMESPACE
+
+// BEGIN_COMMON_DECLARATIONS
+// END_COMMON_DECLARATIONS
+
+// BEGIN_RDATA_NAMESPACE
+
+struct CAAImpl;
+
+class CAA : public Rdata {
+public:
+ // BEGIN_COMMON_MEMBERS
+ // END_COMMON_MEMBERS
+
+ CAA(uint8_t flags, const std::string& tag, const std::string& value);
+ CAA& operator=(const CAA& source);
+ ~CAA();
+
+ ///
+ /// Specialized methods
+ ///
+
+ /// \brief Return the Flags field of the CAA RDATA.
+ uint8_t getFlags() const;
+
+ /// \brief Return the Tag field of the CAA RDATA.
+ const std::string& getTag() const;
+
+ /// \brief Return the Value field of the CAA RDATA.
+ ///
+ /// Note: The const reference which is returned is valid only during
+ /// the lifetime of this \c generic::CAA object. It should not be
+ /// used afterwards.
+ const std::vector<uint8_t>& getValue() const;
+
+private:
+ CAAImpl* constructFromLexer(MasterLexer& lexer);
+
+ CAAImpl* impl_;
+};
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
+// END_HEADER_GUARD
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/rdata/generic/detail/char_string.cc b/src/lib/dns/rdata/generic/detail/char_string.cc
index 4c8965a10b..328fa7b406 100644
--- a/src/lib/dns/rdata/generic/detail/char_string.cc
+++ b/src/lib/dns/rdata/generic/detail/char_string.cc
@@ -93,6 +93,39 @@ stringToCharString(const MasterToken::StringRegion& str_region,
result[0] = result.size() - 1;
}
+void
+stringToCharStringData(const MasterToken::StringRegion& str_region,
+ CharStringData& result)
+{
+ bool escape = false;
+ const char* s = str_region.beg;
+ const char* const s_end = str_region.beg + str_region.len;
+
+ for (size_t n = str_region.len; n != 0; --n, ++s) {
+ int c = (*s & 0xff);
+ if (escape && std::isdigit(c) != 0) {
+ c = decimalToNumber(s, s_end);
+ // decimalToNumber() already throws if (s_end - s) is less
+ // than 3, so the following assertion is unnecessary. But we
+ // assert it anyway. 'n' is an unsigned type (size_t) and
+ // can underflow.
+ assert(n >= 3);
+ // 'n' and 's' are also updated by 1 in the for statement's
+ // expression, so we update them by 2 instead of 3 here.
+ n -= 2;
+ s += 2;
+ } else if (!escape && c == '\\') {
+ escape = true;
+ continue;
+ }
+ escape = false;
+ result.push_back(c);
+ }
+ if (escape) { // terminated by non-escaped '\'
+ isc_throw(InvalidRdataText, "character-string ends with '\\'");
+ }
+}
+
std::string
charStringToString(const CharString& char_string) {
std::string s;
@@ -116,6 +149,29 @@ charStringToString(const CharString& char_string) {
return (s);
}
+std::string
+charStringDataToString(const CharStringData& char_string) {
+ std::string s;
+ for (CharString::const_iterator it = char_string.begin();
+ it != char_string.end(); ++it) {
+ const uint8_t ch = *it;
+ if ((ch < 0x20) || (ch >= 0x7f)) {
+ // convert to escaped \xxx (decimal) format
+ s.push_back('\\');
+ s.push_back('0' + ((ch / 100) % 10));
+ s.push_back('0' + ((ch / 10) % 10));
+ s.push_back('0' + (ch % 10));
+ continue;
+ }
+ if ((ch == '"') || (ch == ';') || (ch == '\\')) {
+ s.push_back('\\');
+ }
+ s.push_back(ch);
+ }
+
+ return (s);
+}
+
int compareCharStrings(const detail::CharString& self,
const detail::CharString& other) {
if (self.size() == 0 && other.size() == 0) {
@@ -144,6 +200,34 @@ int compareCharStrings(const detail::CharString& self,
}
}
+int compareCharStringDatas(const detail::CharStringData& self,
+ const detail::CharStringData& other) {
+ if (self.size() == 0 && other.size() == 0) {
+ return (0);
+ }
+ if (self.size() == 0) {
+ return (-1);
+ }
+ if (other.size() == 0) {
+ return (1);
+ }
+ const size_t self_len = self.size();
+ const size_t other_len = other.size();
+ const size_t cmp_len = std::min(self_len, other_len);
+ const int cmp = std::memcmp(&self[0], &other[0], cmp_len);
+ if (cmp < 0) {
+ return (-1);
+ } else if (cmp > 0) {
+ return (1);
+ } else if (self_len < other_len) {
+ return (-1);
+ } else if (self_len > other_len) {
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
size_t
bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
CharString& target) {
diff --git a/src/lib/dns/rdata/generic/detail/char_string.h b/src/lib/dns/rdata/generic/detail/char_string.h
index 8e3e2944d0..01fccadc59 100644
--- a/src/lib/dns/rdata/generic/detail/char_string.h
+++ b/src/lib/dns/rdata/generic/detail/char_string.h
@@ -34,6 +34,9 @@ namespace detail {
/// be the bare char basis.
typedef std::vector<uint8_t> CharString;
+/// \brief Type for DNS character string without the length prefix.
+typedef std::vector<uint8_t> CharStringData;
+
/// \brief Convert a DNS character-string into corresponding binary data.
///
/// This helper function takes a string object that is expected to be a
@@ -53,6 +56,20 @@ typedef std::vector<uint8_t> CharString;
void stringToCharString(const MasterToken::StringRegion& str_region,
CharString& result);
+/// \brief Convert a DNS character-string into corresponding binary data.
+///
+/// This method functions similar to \c stringToCharString() except it
+/// does not include the 1-octet length prefix in the \c result, and the
+/// result is not limited to MAX_CHARSTRING_LEN octets.
+///
+/// \throw InvalidRdataText Upon syntax errors.
+///
+/// \brief str_region A string that represents a character-string.
+/// \brief result A placeholder vector where the resulting data are to be
+/// stored. Expected to be empty, but it's not checked.
+void stringToCharStringData(const MasterToken::StringRegion& str_region,
+ CharStringData& result);
+
/// \brief Convert a CharString into a textual DNS character-string.
///
/// This method converts a binary 8-bit representation of a DNS
@@ -67,6 +84,15 @@ void stringToCharString(const MasterToken::StringRegion& str_region,
/// \return A string representation of \c char_string.
std::string charStringToString(const CharString& char_string);
+/// \brief Convert a CharStringData into a textual DNS character-string.
+///
+/// Reverse of \c stringToCharStringData(). See \c stringToCharString()
+/// vs. \c stringToCharStringData().
+///
+/// \param char_string The \c CharStringData to convert.
+/// \return A string representation of \c char_string.
+std::string charStringDataToString(const CharStringData& char_string);
+
/// \brief Compare two CharString objects
///
/// \param self The CharString field to compare
@@ -77,6 +103,17 @@ std::string charStringToString(const CharString& char_string);
/// 0 if \c self and \c other are equal
int compareCharStrings(const CharString& self, const CharString& other);
+/// \brief Compare two CharStringData objects
+///
+/// \param self The CharStringData field to compare
+/// \param other The CharStringData field to compare to
+///
+/// \return -1 if \c self would be sorted before \c other
+/// 1 if \c self would be sorted after \c other
+/// 0 if \c self and \c other are equal
+int compareCharStringDatas(const CharStringData& self,
+ const CharStringData& other);
+
/// \brief Convert a buffer containing a character-string to CharString
///
/// This method reads one character-string from the given buffer (in wire
diff --git a/src/lib/dns/rdata/generic/opt_41.cc b/src/lib/dns/rdata/generic/opt_41.cc
index 136bdf931a..6b292e9fa1 100644
--- a/src/lib/dns/rdata/generic/opt_41.cc
+++ b/src/lib/dns/rdata/generic/opt_41.cc
@@ -14,25 +14,68 @@
#include <config.h>
-#include <string>
-
#include <util/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
+#include <boost/foreach.hpp>
+
+#include <string>
+#include <string.h>
+
using namespace std;
using namespace isc::util;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
+/// \brief Constructor.
+OPT::PseudoRR::PseudoRR(uint16_t code,
+ boost::shared_ptr<std::vector<uint8_t> >& data) :
+ code_(code),
+ data_(data)
+{
+}
+
+uint16_t
+OPT::PseudoRR::getCode() const {
+ return (code_);
+}
+
+const uint8_t*
+OPT::PseudoRR::getData() const {
+ return (&(*data_)[0]);
+}
+
+uint16_t
+OPT::PseudoRR::getLength() const {
+ return (data_->size());
+}
+
+struct OPTImpl {
+ OPTImpl() :
+ rdlength_(0)
+ {}
+
+ uint16_t rdlength_;
+ std::vector<OPT::PseudoRR> pseudo_rrs_;
+};
+
+/// \brief Default constructor.
+OPT::OPT() :
+ impl_(new OPTImpl)
+{
+}
+
/// \brief Constructor from string.
///
/// This constructor cannot be used, and always throws an exception.
///
/// \throw InvalidRdataText OPT RR cannot be constructed from text.
-OPT::OPT(const std::string&) {
+OPT::OPT(const std::string&) :
+ impl_(NULL)
+{
isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text");
}
@@ -42,50 +85,141 @@ OPT::OPT(const std::string&) {
///
/// \throw InvalidRdataText OPT RR cannot be constructed from text.
OPT::OPT(MasterLexer&, const Name*,
- MasterLoader::Options, MasterLoaderCallbacks&)
+ MasterLoader::Options, MasterLoaderCallbacks&) :
+ impl_(NULL)
{
isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text");
}
-OPT::OPT(InputBuffer& buffer, size_t rdata_len) {
- // setPosition() will throw against a short buffer anyway, but it's safer
- // to check it explicitly here.
- if (buffer.getLength() - buffer.getPosition() < rdata_len) {
- isc_throw(InvalidRdataLength, "RDLEN of OPT is too large");
+OPT::OPT(InputBuffer& buffer, size_t rdata_len) :
+ impl_(NULL)
+{
+ std::auto_ptr<OPTImpl> impl_ptr(new OPTImpl);
+
+ while (true) {
+ if (rdata_len == 0) {
+ break;
+ }
+
+ if (rdata_len < 4) {
+ isc_throw(InvalidRdataLength,
+ "Pseudo OPT RR record too short: "
+ << rdata_len << " bytes");
+ }
+
+ const uint16_t option_code = buffer.readUint16();
+ const uint16_t option_length = buffer.readUint16();
+ rdata_len -= 4;
+
+ if (static_cast<uint16_t>(impl_ptr->rdlength_ + option_length) <
+ impl_ptr->rdlength_)
+ {
+ isc_throw(InvalidRdataText,
+ "Option length " << option_length
+ << " would overflow OPT RR RDLEN (currently "
+ << impl_ptr->rdlength_ << ").");
+ }
+
+ if (rdata_len < option_length) {
+ isc_throw(InvalidRdataLength, "Corrupt pseudo OPT RR record");
+ }
+
+ boost::shared_ptr<std::vector<uint8_t> >
+ option_data(new std::vector<uint8_t>(option_length));
+ buffer.readData(&(*option_data)[0], option_length);
+ impl_ptr->pseudo_rrs_.push_back(PseudoRR(option_code, option_data));
+ impl_ptr->rdlength_ += option_length;
+ rdata_len -= option_length;
+ }
+
+ impl_ = impl_ptr.release();
+}
+
+OPT::OPT(const OPT& other) :
+ Rdata(), impl_(new OPTImpl(*other.impl_))
+{
+}
+
+OPT&
+OPT::operator=(const OPT& source) {
+ if (this == &source) {
+ return (*this);
}
- // This simple implementation ignores any options
- buffer.setPosition(buffer.getPosition() + rdata_len);
+ OPTImpl* newimpl = new OPTImpl(*source.impl_);
+ delete impl_;
+ impl_ = newimpl;
+
+ return (*this);
}
-OPT::OPT(const OPT&) : Rdata() {
- // there's nothing to copy in this simple implementation.
+OPT::~OPT() {
+ delete impl_;
}
std::string
OPT::toText() const {
- // OPT records do not have a text format.
- return ("");
+ isc_throw(isc::InvalidOperation,
+ "OPT RRs do not have a presentation format");
}
void
-OPT::toWire(OutputBuffer&) const {
- // nothing to do, as this simple version doesn't support any options.
+OPT::toWire(OutputBuffer& buffer) const {
+ BOOST_FOREACH(const PseudoRR& pseudo_rr, impl_->pseudo_rrs_) {
+ buffer.writeUint16(pseudo_rr.getCode());
+ const uint16_t length = pseudo_rr.getLength();
+ buffer.writeUint16(length);
+ if (length > 0) {
+ buffer.writeData(pseudo_rr.getData(), length);
+ }
+ }
}
void
-OPT::toWire(AbstractMessageRenderer&) const {
- // nothing to do, as this simple version doesn't support any options.
+OPT::toWire(AbstractMessageRenderer& renderer) const {
+ BOOST_FOREACH(const PseudoRR& pseudo_rr, impl_->pseudo_rrs_) {
+ renderer.writeUint16(pseudo_rr.getCode());
+ const uint16_t length = pseudo_rr.getLength();
+ renderer.writeUint16(length);
+ if (length > 0) {
+ renderer.writeData(pseudo_rr.getData(), length);
+ }
+ }
}
int
-OPT::compare(const Rdata& other) const {
- //const OPT& other_opt = dynamic_cast<const OPT&>(other);
- // right now we don't need other_opt:
- static_cast<void>(dynamic_cast<const OPT&>(other));
-
+OPT::compare(const Rdata&) const {
+ isc_throw(isc::InvalidOperation,
+ "It is meaningless to compare a set of OPT pseudo RRs; "
+ "they have unspecified order");
return (0);
}
+void
+OPT::appendPseudoRR(uint16_t code, const uint8_t* data, uint16_t length) {
+ // See if it overflows 16-bit length field. We only worry about the
+ // pseudo-RR length here, not the whole message length (which should
+ // be checked and enforced elsewhere).
+ if (static_cast<uint16_t>(impl_->rdlength_ + length) <
+ impl_->rdlength_)
+ {
+ isc_throw(isc::InvalidParameter,
+ "Option length " << length
+ << " would overflow OPT RR RDLEN (currently "
+ << impl_->rdlength_ << ").");
+ }
+
+ boost::shared_ptr<std::vector<uint8_t> >
+ option_data(new std::vector<uint8_t>(length));
+ std::memcpy(&(*option_data)[0], data, length);
+ impl_->pseudo_rrs_.push_back(PseudoRR(code, option_data));
+ impl_->rdlength_ += length;
+}
+
+const std::vector<OPT::PseudoRR>&
+OPT::getPseudoRRs() const {
+ return (impl_->pseudo_rrs_);
+}
+
// END_RDATA_NAMESPACE
// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/opt_41.h b/src/lib/dns/rdata/generic/opt_41.h
index 0cb7043cca..cc51977e3a 100644
--- a/src/lib/dns/rdata/generic/opt_41.h
+++ b/src/lib/dns/rdata/generic/opt_41.h
@@ -18,6 +18,10 @@
#include <dns/rdata.h>
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+
// BEGIN_ISC_NAMESPACE
// BEGIN_COMMON_DECLARATIONS
@@ -25,15 +29,64 @@
// BEGIN_RDATA_NAMESPACE
+struct OPTImpl;
+
class OPT : public Rdata {
public:
// BEGIN_COMMON_MEMBERS
// END_COMMON_MEMBERS
// The default constructor makes sense for OPT as it can be empty.
- OPT() {}
+ OPT();
+ OPT& operator=(const OPT& source);
+ ~OPT();
+
+ /// \brief A class representing a pseudo RR (or option) within an
+ /// OPT RR (see RFC 6891).
+ class PseudoRR {
+ public:
+ /// \brief Constructor.
+ /// \param code The OPTION-CODE field of the pseudo RR.
+ /// \param data The OPTION-DATA field of the pseudo
+ /// RR. OPTION-LENGTH is set to the length of this vector.
+ PseudoRR(uint16_t code,
+ boost::shared_ptr<std::vector<uint8_t> >& data);
+
+ /// \brief Return the option code of this pseudo RR.
+ uint16_t getCode() const;
+
+ /// \brief Return the option data of this pseudo RR.
+ const uint8_t* getData() const;
+
+ /// \brief Return the length of the option data of this
+ /// pseudo RR.
+ uint16_t getLength() const;
+
+ private:
+ uint16_t code_;
+ boost::shared_ptr<std::vector<uint8_t> > data_;
+ };
+
+ /// \brief Append a pseudo RR (option) in this OPT RR.
+ ///
+ /// \param code The OPTION-CODE field of the pseudo RR.
+ /// \param data The OPTION-DATA field of the pseudo RR.
+ /// \param length The size of the \c data argument. OPTION-LENGTH is
+ /// set to this size.
+ /// \throw \c isc::InvalidParameter if this pseudo RR would cause
+ /// the OPT RDATA to overflow its RDLENGTH.
+ void appendPseudoRR(uint16_t code, const uint8_t* data, uint16_t length);
+
+ /// \brief Return a vector of the pseudo RRs (options) in this
+ /// OPT RR.
+ ///
+ /// Note: The returned reference is only valid during the lifetime
+ /// of this \c generic::OPT object. It should not be used
+ /// afterwards.
+ const std::vector<PseudoRR>& getPseudoRRs() const;
+
private:
- // RR-type specific members are here.
+ OPTImpl* impl_;
};
// END_RDATA_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/sshfp_44.cc b/src/lib/dns/rdata/generic/sshfp_44.cc
index 2865ed18c8..4c1e83274a 100644
--- a/src/lib/dns/rdata/generic/sshfp_44.cc
+++ b/src/lib/dns/rdata/generic/sshfp_44.cc
@@ -14,8 +14,6 @@
#include <config.h>
-#include <string>
-
#include <boost/lexical_cast.hpp>
#include <exceptions/exceptions.h>
@@ -38,7 +36,7 @@ using namespace isc::util::encode;
struct SSHFPImpl {
// straightforward representation of SSHFP RDATA fields
SSHFPImpl(uint8_t algorithm, uint8_t fingerprint_type,
- vector<uint8_t>& fingerprint) :
+ const vector<uint8_t>& fingerprint) :
algorithm_(algorithm),
fingerprint_type_(fingerprint_type),
fingerprint_(fingerprint)
@@ -82,7 +80,11 @@ SSHFP::constructFromLexer(MasterLexer& lexer) {
// If fingerprint is missing, it's OK. See the API documentation of the
// constructor.
if (fingerprint_str.size() > 0) {
- decodeHex(fingerprint_str, fingerprint);
+ try {
+ decodeHex(fingerprint_str, fingerprint);
+ } catch (const isc::BadValue& e) {
+ isc_throw(InvalidRdataText, "Bad SSHFP fingerprint: " << e.what());
+ }
}
return (new SSHFPImpl(algorithm, fingerprint_type, fingerprint));
@@ -102,8 +104,9 @@ SSHFP::constructFromLexer(MasterLexer& lexer) {
/// valid hex encoding of the fingerprint. For compatibility with BIND 9,
/// whitespace is allowed in the hex text (RFC4255 is silent on the matter).
///
-/// \throw InvalidRdataText if any fields are missing, out of their valid
-/// ranges, or incorrect.
+/// \throw InvalidRdataText if any fields are missing, are out of their
+/// valid ranges or are incorrect, or if the fingerprint is not a valid
+/// hex string.
///
/// \param sshfp_str A string containing the RDATA to be created
SSHFP::SSHFP(const string& sshfp_str) :
@@ -128,9 +131,6 @@ SSHFP::SSHFP(const string& sshfp_str) :
} catch (const MasterLexer::LexerError& ex) {
isc_throw(InvalidRdataText, "Failed to construct SSHFP from '" <<
sshfp_str << "': " << ex.what());
- } catch (const isc::BadValue& e) {
- isc_throw(InvalidRdataText,
- "Bad SSHFP fingerprint: " << e.what());
}
impl_ = impl_ptr.release();
@@ -142,9 +142,8 @@ SSHFP::SSHFP(const string& sshfp_str) :
/// of an SSHFP RDATA.
///
/// \throw MasterLexer::LexerError General parsing error such as missing field.
-/// \throw InvalidRdataText Fields are out of their valid range, or are
-/// incorrect.
-/// \throw BadValue Fingerprint is not a valid hex string.
+/// \throw InvalidRdataText Fields are out of their valid range or are
+/// incorrect, or if the fingerprint is not a valid hex string.
///
/// \param lexer A \c MasterLexer object parsing a master file for the
/// RDATA to be created
@@ -293,8 +292,13 @@ SSHFP::getFingerprintType() const {
return (impl_->fingerprint_type_);
}
+const std::vector<uint8_t>&
+SSHFP::getFingerprint() const {
+ return (impl_->fingerprint_);
+}
+
size_t
-SSHFP::getFingerprintLen() const {
+SSHFP::getFingerprintLength() const {
return (impl_->fingerprint_.size());
}
diff --git a/src/lib/dns/rdata/generic/sshfp_44.h b/src/lib/dns/rdata/generic/sshfp_44.h
index 28ce0f3d22..85ae8067c5 100644
--- a/src/lib/dns/rdata/generic/sshfp_44.h
+++ b/src/lib/dns/rdata/generic/sshfp_44.h
@@ -17,6 +17,7 @@
#include <stdint.h>
#include <string>
+#include <vector>
#include <dns/name.h>
#include <dns/rdata.h>
@@ -45,7 +46,8 @@ public:
///
uint8_t getAlgorithmNumber() const;
uint8_t getFingerprintType() const;
- size_t getFingerprintLen() const;
+ const std::vector<uint8_t>& getFingerprint() const;
+ size_t getFingerprintLength() const;
private:
SSHFPImpl* constructFromLexer(MasterLexer& lexer);
diff --git a/src/lib/dns/rdata/generic/tlsa_52.cc b/src/lib/dns/rdata/generic/tlsa_52.cc
new file mode 100644
index 0000000000..774bdef6cf
--- /dev/null
+++ b/src/lib/dns/rdata/generic/tlsa_52.cc
@@ -0,0 +1,350 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/encode/hex.h>
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdata_pimpl_holder.h>
+
+using namespace std;
+using boost::lexical_cast;
+using namespace isc::util;
+using namespace isc::util::encode;
+
+// BEGIN_ISC_NAMESPACE
+// BEGIN_RDATA_NAMESPACE
+
+struct TLSAImpl {
+ // straightforward representation of TLSA RDATA fields
+ TLSAImpl(uint8_t certificate_usage, uint8_t selector,
+ uint8_t matching_type, const vector<uint8_t>& data) :
+ certificate_usage_(certificate_usage),
+ selector_(selector),
+ matching_type_(matching_type),
+ data_(data)
+ {}
+
+ uint8_t certificate_usage_;
+ uint8_t selector_;
+ uint8_t matching_type_;
+ const vector<uint8_t> data_;
+};
+
+// helper function for string and lexer constructors
+TLSAImpl*
+TLSA::constructFromLexer(MasterLexer& lexer) {
+ const uint32_t certificate_usage =
+ lexer.getNextToken(MasterToken::NUMBER).getNumber();
+ if (certificate_usage > 255) {
+ isc_throw(InvalidRdataText,
+ "TLSA certificate usage field out of range");
+ }
+
+ const uint32_t selector =
+ lexer.getNextToken(MasterToken::NUMBER).getNumber();
+ if (selector > 255) {
+ isc_throw(InvalidRdataText,
+ "TLSA selector field out of range");
+ }
+
+ const uint32_t matching_type =
+ lexer.getNextToken(MasterToken::NUMBER).getNumber();
+ if (matching_type > 255) {
+ isc_throw(InvalidRdataText,
+ "TLSA matching type field out of range");
+ }
+
+ std::string certificate_assoc_data;
+ std::string data_substr;
+ while (true) {
+ const MasterToken& token =
+ lexer.getNextToken(MasterToken::STRING, true);
+ if ((token.getType() == MasterToken::END_OF_FILE) ||
+ (token.getType() == MasterToken::END_OF_LINE)) {
+ break;
+ }
+
+ token.getString(data_substr);
+ certificate_assoc_data.append(data_substr);
+ }
+ lexer.ungetToken();
+
+ if (certificate_assoc_data.empty()) {
+ isc_throw(InvalidRdataText, "Empty TLSA certificate association data");
+ }
+
+ vector<uint8_t> data;
+ try {
+ decodeHex(certificate_assoc_data, data);
+ } catch (const isc::BadValue& e) {
+ isc_throw(InvalidRdataText,
+ "Bad TLSA certificate association data: " << e.what());
+ }
+
+ return (new TLSAImpl(certificate_usage, selector, matching_type, data));
+}
+
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid TLSA RDATA. There can be
+/// extra space characters at the beginning or end of the text (which
+/// are simply ignored), but other extra text, including a new line,
+/// will make the construction fail with an exception.
+///
+/// The Certificate Usage, Selector and Matching Type fields must be
+/// within their valid ranges, but are not constrained to the values
+/// defined in RFC6698.
+///
+/// The Certificate Association Data Field field may be absent, but if
+/// present it must contain a valid hex encoding of the data. Whitespace
+/// is allowed in the hex text.
+///
+/// \throw InvalidRdataText if any fields are missing, out of their
+/// valid ranges, or are incorrect, or Certificate Association Data is
+/// not a valid hex string.
+///
+/// \param tlsa_str A string containing the RDATA to be created
+TLSA::TLSA(const string& tlsa_str) :
+ impl_(NULL)
+{
+ // We use a smart pointer here because if there is an exception in
+ // this constructor, the destructor is not called and there could be
+ // a leak of the TLSAImpl that constructFromLexer() returns.
+ RdataPimplHolder<TLSAImpl> impl_ptr;
+
+ try {
+ std::istringstream ss(tlsa_str);
+ MasterLexer lexer;
+ lexer.pushSource(ss);
+
+ impl_ptr.reset(constructFromLexer(lexer));
+
+ if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+ isc_throw(InvalidRdataText, "extra input text for TLSA: "
+ << tlsa_str);
+ }
+ } catch (const MasterLexer::LexerError& ex) {
+ isc_throw(InvalidRdataText, "Failed to construct TLSA from '" <<
+ tlsa_str << "': " << ex.what());
+ }
+
+ impl_ = impl_ptr.release();
+}
+
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an TLSA RDATA.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw InvalidRdataText Fields are out of their valid range, or are
+/// incorrect, or Certificate Association Data is not a valid hex string.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+TLSA::TLSA(MasterLexer& lexer, const Name*,
+ MasterLoader::Options, MasterLoaderCallbacks&) :
+ impl_(constructFromLexer(lexer))
+{
+}
+
+/// \brief Constructor from InputBuffer.
+///
+/// The passed buffer must contain a valid TLSA RDATA.
+///
+/// The Certificate Usage, Selector and Matching Type fields must be
+/// within their valid ranges, but are not constrained to the values
+/// defined in RFC6698. It is okay for the certificate association data
+/// to be missing (see the description of the constructor from string).
+TLSA::TLSA(InputBuffer& buffer, size_t rdata_len) {
+ if (rdata_len < 3) {
+ isc_throw(InvalidRdataLength, "TLSA record too short");
+ }
+
+ const uint8_t certificate_usage = buffer.readUint8();
+ const uint8_t selector = buffer.readUint8();
+ const uint8_t matching_type = buffer.readUint8();
+
+ vector<uint8_t> data;
+ rdata_len -= 3;
+
+ if (rdata_len == 0) {
+ isc_throw(InvalidRdataLength,
+ "Empty TLSA certificate association data");
+ }
+
+ data.resize(rdata_len);
+ buffer.readData(&data[0], rdata_len);
+
+ impl_ = new TLSAImpl(certificate_usage, selector, matching_type, data);
+}
+
+TLSA::TLSA(uint8_t certificate_usage, uint8_t selector,
+ uint8_t matching_type, const std::string& certificate_assoc_data) :
+ impl_(NULL)
+{
+ if (certificate_assoc_data.empty()) {
+ isc_throw(InvalidRdataText, "Empty TLSA certificate association data");
+ }
+
+ vector<uint8_t> data;
+ try {
+ decodeHex(certificate_assoc_data, data);
+ } catch (const isc::BadValue& e) {
+ isc_throw(InvalidRdataText,
+ "Bad TLSA certificate association data: " << e.what());
+ }
+
+ impl_ = new TLSAImpl(certificate_usage, selector, matching_type, data);
+}
+
+TLSA::TLSA(const TLSA& other) :
+ Rdata(), impl_(new TLSAImpl(*other.impl_))
+{}
+
+TLSA&
+TLSA::operator=(const TLSA& source) {
+ if (this == &source) {
+ return (*this);
+ }
+
+ TLSAImpl* newimpl = new TLSAImpl(*source.impl_);
+ delete impl_;
+ impl_ = newimpl;
+
+ return (*this);
+}
+
+TLSA::~TLSA() {
+ delete impl_;
+}
+
+void
+TLSA::toWire(OutputBuffer& buffer) const {
+ buffer.writeUint8(impl_->certificate_usage_);
+ buffer.writeUint8(impl_->selector_);
+ buffer.writeUint8(impl_->matching_type_);
+
+ // The constructors must ensure that the certificate association
+ // data field is not empty.
+ assert(!impl_->data_.empty());
+ buffer.writeData(&impl_->data_[0], impl_->data_.size());
+}
+
+void
+TLSA::toWire(AbstractMessageRenderer& renderer) const {
+ renderer.writeUint8(impl_->certificate_usage_);
+ renderer.writeUint8(impl_->selector_);
+ renderer.writeUint8(impl_->matching_type_);
+
+ // The constructors must ensure that the certificate association
+ // data field is not empty.
+ assert(!impl_->data_.empty());
+ renderer.writeData(&impl_->data_[0], impl_->data_.size());
+}
+
+string
+TLSA::toText() const {
+ // The constructors must ensure that the certificate association
+ // data field is not empty.
+ assert(!impl_->data_.empty());
+
+ return (lexical_cast<string>(static_cast<int>(impl_->certificate_usage_)) + " " +
+ lexical_cast<string>(static_cast<int>(impl_->selector_)) + " " +
+ lexical_cast<string>(static_cast<int>(impl_->matching_type_)) + " " +
+ encodeHex(impl_->data_));
+}
+
+int
+TLSA::compare(const Rdata& other) const {
+ const TLSA& other_tlsa = dynamic_cast<const TLSA&>(other);
+
+ if (impl_->certificate_usage_ < other_tlsa.impl_->certificate_usage_) {
+ return (-1);
+ } else if (impl_->certificate_usage_ >
+ other_tlsa.impl_->certificate_usage_) {
+ return (1);
+ }
+
+ if (impl_->selector_ < other_tlsa.impl_->selector_) {
+ return (-1);
+ } else if (impl_->selector_ > other_tlsa.impl_->selector_) {
+ return (1);
+ }
+
+ if (impl_->matching_type_ < other_tlsa.impl_->matching_type_) {
+ return (-1);
+ } else if (impl_->matching_type_ >
+ other_tlsa.impl_->matching_type_) {
+ return (1);
+ }
+
+ const size_t this_len = impl_->data_.size();
+ const size_t other_len = other_tlsa.impl_->data_.size();
+ const size_t cmplen = min(this_len, other_len);
+
+ if (cmplen > 0) {
+ const int cmp = memcmp(&impl_->data_[0],
+ &other_tlsa.impl_->data_[0],
+ cmplen);
+ if (cmp != 0) {
+ return (cmp);
+ }
+ }
+
+ if (this_len == other_len) {
+ return (0);
+ } else if (this_len < other_len) {
+ return (-1);
+ } else {
+ return (1);
+ }
+}
+
+uint8_t
+TLSA::getCertificateUsage() const {
+ return (impl_->certificate_usage_);
+}
+
+uint8_t
+TLSA::getSelector() const {
+ return (impl_->selector_);
+}
+
+uint8_t
+TLSA::getMatchingType() const {
+ return (impl_->matching_type_);
+}
+
+const std::vector<uint8_t>&
+TLSA::getData() const {
+ return (impl_->data_);
+}
+
+size_t
+TLSA::getDataLength() const {
+ return (impl_->data_.size());
+}
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/tlsa_52.h b/src/lib/dns/rdata/generic/tlsa_52.h
new file mode 100644
index 0000000000..7d8c69a3d1
--- /dev/null
+++ b/src/lib/dns/rdata/generic/tlsa_52.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// BEGIN_HEADER_GUARD
+
+#include <stdint.h>
+
+#include <dns/name.h>
+#include <dns/rdata.h>
+
+#include <string>
+#include <vector>
+
+// BEGIN_ISC_NAMESPACE
+
+// BEGIN_COMMON_DECLARATIONS
+// END_COMMON_DECLARATIONS
+
+// BEGIN_RDATA_NAMESPACE
+
+struct TLSAImpl;
+
+class TLSA : public Rdata {
+public:
+ // BEGIN_COMMON_MEMBERS
+ // END_COMMON_MEMBERS
+
+ TLSA(uint8_t certificate_usage, uint8_t selector,
+ uint8_t matching_type, const std::string& certificate_assoc_data);
+ TLSA& operator=(const TLSA& source);
+ ~TLSA();
+
+ ///
+ /// Specialized methods
+ ///
+ uint8_t getCertificateUsage() const;
+ uint8_t getSelector() const;
+ uint8_t getMatchingType() const;
+ const std::vector<uint8_t>& getData() const;
+ size_t getDataLength() const;
+
+private:
+ TLSAImpl* constructFromLexer(MasterLexer& lexer);
+
+ TLSAImpl* impl_;
+};
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
+// END_HEADER_GUARD
+
+// Local Variables:
+// mode: c++
+// End: