mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-04 16:05:17 +00:00
Merge branch 'trac2512'
This commit is contained in:
@@ -78,6 +78,8 @@ EXTRA_DIST += rdata/generic/minfo_14.cc
|
||||
EXTRA_DIST += rdata/generic/minfo_14.h
|
||||
EXTRA_DIST += rdata/generic/afsdb_18.cc
|
||||
EXTRA_DIST += rdata/generic/afsdb_18.h
|
||||
EXTRA_DIST += rdata/generic/caa_257.cc
|
||||
EXTRA_DIST += rdata/generic/caa_257.h
|
||||
EXTRA_DIST += rdata/hs_4/a_1.cc
|
||||
EXTRA_DIST += rdata/hs_4/a_1.h
|
||||
EXTRA_DIST += rdata/in_1/a_1.cc
|
||||
|
@@ -43,7 +43,7 @@ meta_types = {
|
||||
'27': 'gpos', '29': 'loc', '36': 'kx', '37': 'cert', '42': 'apl',
|
||||
'45': 'ipseckey', '55': 'hip', '103': 'unspec',
|
||||
'104': 'nid', '105': 'l32', '106': 'l64', '107': 'lp', '249': 'tkey',
|
||||
'253': 'mailb', '256': 'uri', '257': 'caa'
|
||||
'253': 'mailb', '256': 'uri'
|
||||
}
|
||||
# Classes that don't have any known types. This is a dict from type code
|
||||
# values (as string) to textual mnemonic.
|
||||
|
306
src/lib/dns/rdata/generic/caa_257.cc
Normal file
306
src/lib/dns/rdata/generic/caa_257.cc
Normal file
@@ -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
|
72
src/lib/dns/rdata/generic/caa_257.h
Normal file
72
src/lib/dns/rdata/generic/caa_257.h
Normal file
@@ -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:
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -41,6 +41,7 @@ run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc
|
||||
run_unittests_SOURCES += rdatafields_unittest.cc
|
||||
run_unittests_SOURCES += rdata_pimpl_holder_unittest.cc
|
||||
run_unittests_SOURCES += rdata_char_string_unittest.cc
|
||||
run_unittests_SOURCES += rdata_char_string_data_unittest.cc
|
||||
run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
|
||||
run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
|
||||
run_unittests_SOURCES += rdata_txt_like_unittest.cc
|
||||
@@ -66,6 +67,7 @@ run_unittests_SOURCES += rdata_minfo_unittest.cc
|
||||
run_unittests_SOURCES += rdata_tsig_unittest.cc
|
||||
run_unittests_SOURCES += rdata_naptr_unittest.cc
|
||||
run_unittests_SOURCES += rdata_hinfo_unittest.cc
|
||||
run_unittests_SOURCES += rdata_caa_unittest.cc
|
||||
run_unittests_SOURCES += rrset_unittest.cc
|
||||
run_unittests_SOURCES += question_unittest.cc
|
||||
run_unittests_SOURCES += rrparamregistry_unittest.cc
|
||||
|
327
src/lib/dns/tests/rdata_caa_unittest.cc
Normal file
327
src/lib/dns/tests/rdata_caa_unittest.cc
Normal file
@@ -0,0 +1,327 @@
|
||||
// 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 <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <util/buffer.h>
|
||||
#include <dns/messagerenderer.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataclass.h>
|
||||
#include <dns/rrclass.h>
|
||||
#include <dns/rrtype.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <dns/tests/unittest_util.h>
|
||||
#include <dns/tests/rdata_unittest.h>
|
||||
#include <util/unittests/wiredata.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc;
|
||||
using namespace isc::dns;
|
||||
using namespace isc::util;
|
||||
using namespace isc::dns::rdata;
|
||||
using isc::UnitTestUtil;
|
||||
using isc::util::unittests::matchWireData;
|
||||
|
||||
namespace {
|
||||
class Rdata_CAA_Test : public RdataTest {
|
||||
protected:
|
||||
Rdata_CAA_Test() :
|
||||
caa_txt("0 issue \"ca.example.net\""),
|
||||
rdata_caa(caa_txt)
|
||||
{}
|
||||
|
||||
void checkFromText_None(const string& rdata_str) {
|
||||
checkFromText<generic::CAA, isc::Exception, isc::Exception>(
|
||||
rdata_str, rdata_caa, false, false);
|
||||
}
|
||||
|
||||
void checkFromText_InvalidText(const string& rdata_str) {
|
||||
checkFromText<generic::CAA, InvalidRdataText, InvalidRdataText>(
|
||||
rdata_str, rdata_caa, true, true);
|
||||
}
|
||||
|
||||
void checkFromText_LexerError(const string& rdata_str) {
|
||||
checkFromText
|
||||
<generic::CAA, InvalidRdataText, MasterLexer::LexerError>(
|
||||
rdata_str, rdata_caa, true, true);
|
||||
}
|
||||
|
||||
void checkFromText_BadString(const string& rdata_str) {
|
||||
checkFromText
|
||||
<generic::CAA, InvalidRdataText, isc::Exception>(
|
||||
rdata_str, rdata_caa, true, false);
|
||||
}
|
||||
|
||||
const string caa_txt;
|
||||
const generic::CAA rdata_caa;
|
||||
};
|
||||
|
||||
const uint8_t rdata_caa_wiredata[] = {
|
||||
// flags
|
||||
0x00,
|
||||
// tag length
|
||||
0x5,
|
||||
// tag
|
||||
'i', 's', 's', 'u', 'e',
|
||||
// value
|
||||
'c', 'a', '.', 'e', 'x', 'a', 'm', 'p', 'l', 'e',
|
||||
'.', 'n', 'e', 't'
|
||||
};
|
||||
|
||||
TEST_F(Rdata_CAA_Test, createFromText) {
|
||||
// Basic test
|
||||
checkFromText_None(caa_txt);
|
||||
|
||||
// With different spacing
|
||||
checkFromText_None("0 issue \"ca.example.net\"");
|
||||
|
||||
// Combination of lowercase and uppercase
|
||||
checkFromText_None("0 IssUE \"ca.example.net\"");
|
||||
|
||||
// string constructor throws if there's extra text,
|
||||
// but lexer constructor doesn't
|
||||
checkFromText_BadString(caa_txt + "\n" + caa_txt);
|
||||
|
||||
// Missing value field
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue"));
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, fields) {
|
||||
// Some of these may not be RFC conformant, but we relax the check
|
||||
// in our code to work with other field values that may show up in
|
||||
// the future.
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("1 issue \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("2 issue \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("3 issue \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("128 issue \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("255 issue \"ca.example.net\""));
|
||||
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 foo \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 bar \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 12345 \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 w0x1y2z3 \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 relaxed-too \"ca.example.net\""));
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 RELAXED.too \"ca.example.net\""));
|
||||
|
||||
// No value (this is redundant to the last test case in the
|
||||
// .createFromText test
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue"));
|
||||
|
||||
// > 255 would be broken
|
||||
EXPECT_THROW(const generic::CAA rdata_caa2("256 issue \"ca.example.net\""),
|
||||
InvalidRdataText);
|
||||
|
||||
// Missing tag actually passes because it parses the value as tag
|
||||
// and assumes that the value is empty instead.
|
||||
EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 \"ca.example.net\""));
|
||||
|
||||
// Tag is too long
|
||||
const std::string tag(256, 'a');
|
||||
const std::string rdata_txt("0 " + tag + " \"ca.example.net\"");
|
||||
EXPECT_THROW(const generic::CAA rdata_caa2(rdata_txt), InvalidRdataText);
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, characterStringValue) {
|
||||
const generic::CAA rdata_caa_unquoted("0 issue ca.example.net");
|
||||
EXPECT_EQ(0, rdata_caa_unquoted.compare(rdata_caa));
|
||||
|
||||
const generic::CAA rdata_caa_escape_X("0 issue ca.e\\xample.net");
|
||||
EXPECT_EQ(0, rdata_caa_escape_X.compare(rdata_caa));
|
||||
|
||||
const generic::CAA rdata_caa_escape_DDD("0 issue ca.e\\120ample.net");
|
||||
EXPECT_EQ(0, rdata_caa_escape_DDD.compare(rdata_caa));
|
||||
|
||||
const generic::CAA rdata_caa_multiline("0 issue (\nca.example.net)");
|
||||
EXPECT_EQ(0, rdata_caa_multiline.compare(rdata_caa));
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, badText) {
|
||||
checkFromText_LexerError("0");
|
||||
checkFromText_LexerError("ZERO issue \"ca.example.net\"");
|
||||
EXPECT_THROW(const generic::CAA rdata_caa2(caa_txt + " extra text"),
|
||||
InvalidRdataText);
|
||||
|
||||
// Yes, this is redundant to the last test cases in the .fields test
|
||||
checkFromText_InvalidText("2345 issue \"ca.example.net\"");
|
||||
|
||||
// negative values are trapped in the lexer rather than the
|
||||
// constructor
|
||||
checkFromText_LexerError("-2 issue \"ca.example.net\"");
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, copyAndAssign) {
|
||||
// Copy construct
|
||||
generic::CAA rdata_caa2(rdata_caa);
|
||||
EXPECT_EQ(0, rdata_caa.compare(rdata_caa2));
|
||||
|
||||
// Assignment, mainly to confirm it doesn't cause disruption.
|
||||
rdata_caa2 = rdata_caa;
|
||||
EXPECT_EQ(0, rdata_caa.compare(rdata_caa2));
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, createFromWire) {
|
||||
// Basic test
|
||||
EXPECT_EQ(0, rdata_caa.compare(
|
||||
*rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire1.wire")));
|
||||
|
||||
// Combination of lowercase and uppercase
|
||||
EXPECT_EQ(0, rdata_caa.compare(
|
||||
*rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire2.wire")));
|
||||
|
||||
// Value field is empty
|
||||
EXPECT_NO_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire3.wire"));
|
||||
|
||||
// Tag field is empty
|
||||
EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire4.wire"),
|
||||
InvalidRdataText);
|
||||
|
||||
// Value field is shorter than rdata len
|
||||
EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire5"),
|
||||
InvalidBufferPosition);
|
||||
|
||||
// all RDATA is missing
|
||||
EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire6"),
|
||||
InvalidBufferPosition);
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, createFromParams) {
|
||||
const generic::CAA rdata_caa2(0, "issue", "ca.example.net");
|
||||
EXPECT_EQ(0, rdata_caa2.compare(rdata_caa));
|
||||
|
||||
const generic::CAA rdata_caa4(0, "issue", "ca.e\\xample.net");
|
||||
EXPECT_EQ(0, rdata_caa4.compare(rdata_caa));
|
||||
|
||||
const generic::CAA rdata_caa5(0, "issue", "ca.e\\120ample.net");
|
||||
EXPECT_EQ(0, rdata_caa5.compare(rdata_caa));
|
||||
|
||||
// Tag is empty
|
||||
EXPECT_THROW(const generic::CAA rdata_caa3(0, "", "ca.example.net"),
|
||||
isc::InvalidParameter);
|
||||
|
||||
// Tag is too long
|
||||
const std::string tag(256, 'a');
|
||||
EXPECT_THROW(const generic::CAA rdata_caa3(0, tag, "ca.example.net"),
|
||||
isc::InvalidParameter);
|
||||
|
||||
// Value is too long
|
||||
const std::string value(65536, 'a');
|
||||
EXPECT_THROW(const generic::CAA rdata_caa3(0, "issue", value),
|
||||
InvalidRdataLength);
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, toText) {
|
||||
EXPECT_TRUE(boost::iequals(caa_txt, rdata_caa.toText()));
|
||||
|
||||
const string caa_txt2("1 issue \"\"");
|
||||
const generic::CAA rdata_caa2(caa_txt2);
|
||||
EXPECT_TRUE(boost::iequals(caa_txt2, rdata_caa2.toText()));
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, toWire) {
|
||||
obuffer.clear();
|
||||
rdata_caa.toWire(obuffer);
|
||||
|
||||
matchWireData(rdata_caa_wiredata, sizeof(rdata_caa_wiredata),
|
||||
obuffer.getData(), obuffer.getLength());
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, compare) {
|
||||
// Equality test is repeated from createFromWire tests above.
|
||||
EXPECT_EQ(0, rdata_caa.compare(
|
||||
*rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire1.wire")));
|
||||
|
||||
const generic::CAA rdata_caa2("1 issue \"ca.example.net\"");
|
||||
|
||||
EXPECT_EQ(1, rdata_caa2.compare(rdata_caa));
|
||||
EXPECT_EQ(-1, rdata_caa.compare(rdata_caa2));
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, getFlags) {
|
||||
EXPECT_EQ(0, rdata_caa.getFlags());
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, getTag) {
|
||||
EXPECT_EQ("issue", rdata_caa.getTag());
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, getValue) {
|
||||
const uint8_t value_data[] = {
|
||||
'c', 'a', '.',
|
||||
'e', 'x', 'a', 'm', 'p', 'l', 'e', '.',
|
||||
'n', 'e', 't'
|
||||
};
|
||||
|
||||
const std::vector<uint8_t>& value = rdata_caa.getValue();
|
||||
matchWireData(value_data, sizeof(value_data),
|
||||
&value[0], value.size());
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, emptyValueFromWire) {
|
||||
const uint8_t rdf_wiredata[] = {
|
||||
// flags
|
||||
0x00,
|
||||
// tag length
|
||||
0x5,
|
||||
// tag
|
||||
'i', 's', 's', 'u', 'e'
|
||||
};
|
||||
|
||||
const generic::CAA rdf =
|
||||
dynamic_cast<const generic::CAA&>
|
||||
(*rdataFactoryFromFile(RRType("CAA"), RRClass("IN"),
|
||||
"rdata_caa_fromWire3.wire"));
|
||||
|
||||
EXPECT_EQ(0, rdf.getFlags());
|
||||
EXPECT_EQ("issue", rdf.getTag());
|
||||
|
||||
obuffer.clear();
|
||||
rdf.toWire(obuffer);
|
||||
|
||||
matchWireData(rdf_wiredata, sizeof(rdf_wiredata),
|
||||
obuffer.getData(), obuffer.getLength());
|
||||
}
|
||||
|
||||
TEST_F(Rdata_CAA_Test, emptyValueFromString) {
|
||||
const generic::CAA rdata_caa2("0 issue");
|
||||
const uint8_t rdata_caa2_wiredata[] = {
|
||||
// flags
|
||||
0x00,
|
||||
// tag length
|
||||
0x5,
|
||||
// tag
|
||||
'i', 's', 's', 'u', 'e'
|
||||
};
|
||||
|
||||
EXPECT_EQ(0, rdata_caa2.getFlags());
|
||||
EXPECT_EQ("issue", rdata_caa2.getTag());
|
||||
|
||||
obuffer.clear();
|
||||
rdata_caa2.toWire(obuffer);
|
||||
|
||||
matchWireData(rdata_caa2_wiredata, sizeof(rdata_caa2_wiredata),
|
||||
obuffer.getData(), obuffer.getLength());
|
||||
}
|
||||
}
|
187
src/lib/dns/tests/rdata_char_string_data_unittest.cc
Normal file
187
src/lib/dns/tests/rdata_char_string_data_unittest.cc
Normal file
@@ -0,0 +1,187 @@
|
||||
// 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 <util/unittests/wiredata.h>
|
||||
|
||||
#include <dns/exceptions.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdata/generic/detail/char_string.h>
|
||||
#include <util/buffer.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace isc::dns;
|
||||
using namespace isc::dns::rdata;
|
||||
using isc::dns::rdata::generic::detail::CharStringData;
|
||||
using isc::dns::rdata::generic::detail::stringToCharStringData;
|
||||
using isc::dns::rdata::generic::detail::charStringDataToString;
|
||||
using isc::dns::rdata::generic::detail::compareCharStringDatas;
|
||||
using isc::util::unittests::matchWireData;
|
||||
|
||||
namespace {
|
||||
const uint8_t test_charstr[] = {
|
||||
'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
|
||||
};
|
||||
|
||||
class CharStringDataTest : public ::testing::Test {
|
||||
protected:
|
||||
CharStringDataTest() :
|
||||
// char-string representation for test data using two types of escape
|
||||
// ('r' = 114)
|
||||
test_str("Test\\ St\\114ing")
|
||||
{
|
||||
str_region.beg = &test_str[0];
|
||||
str_region.len = test_str.size();
|
||||
}
|
||||
CharStringData chstr; // place holder
|
||||
const std::string test_str;
|
||||
MasterToken::StringRegion str_region;
|
||||
};
|
||||
|
||||
MasterToken::StringRegion
|
||||
createStringRegion(const std::string& str) {
|
||||
MasterToken::StringRegion region;
|
||||
region.beg = &str[0]; // note std ensures this works even if str is empty
|
||||
region.len = str.size();
|
||||
return (region);
|
||||
}
|
||||
|
||||
TEST_F(CharStringDataTest, normalConversion) {
|
||||
uint8_t tmp[3]; // placeholder for expected sequence
|
||||
|
||||
stringToCharStringData(str_region, chstr);
|
||||
matchWireData(test_charstr, sizeof(test_charstr), &chstr[0], chstr.size());
|
||||
|
||||
// Empty string
|
||||
chstr.clear();
|
||||
stringToCharStringData(createStringRegion(""), chstr);
|
||||
EXPECT_TRUE(chstr.empty());
|
||||
|
||||
// Possible largest char string
|
||||
chstr.clear();
|
||||
std::string long_str(255, 'x');
|
||||
stringToCharStringData(createStringRegion(long_str), chstr);
|
||||
std::vector<uint8_t> expected;
|
||||
expected.insert(expected.end(), long_str.begin(), long_str.end());
|
||||
matchWireData(&expected[0], expected.size(), &chstr[0], chstr.size());
|
||||
|
||||
// Escaped '\'
|
||||
chstr.clear();
|
||||
tmp[0] = '\\';
|
||||
stringToCharStringData(createStringRegion("\\\\"), chstr);
|
||||
matchWireData(tmp, 1, &chstr[0], chstr.size());
|
||||
|
||||
// Boundary values for \DDD
|
||||
chstr.clear();
|
||||
tmp[0] = 0;
|
||||
stringToCharStringData(createStringRegion("\\000"), chstr);
|
||||
matchWireData(tmp, 1, &chstr[0], chstr.size());
|
||||
|
||||
chstr.clear();
|
||||
stringToCharStringData(createStringRegion("\\255"), chstr);
|
||||
tmp[0] = 255;
|
||||
matchWireData(tmp, 1, &chstr[0], chstr.size());
|
||||
|
||||
// Another digit follows DDD; it shouldn't cause confusion
|
||||
chstr.clear();
|
||||
stringToCharStringData(createStringRegion("\\2550"), chstr);
|
||||
tmp[1] = '0';
|
||||
matchWireData(tmp, 2, &chstr[0], chstr.size());
|
||||
}
|
||||
|
||||
TEST_F(CharStringDataTest, badConversion) {
|
||||
// input string ending with (non escaped) '\'
|
||||
chstr.clear();
|
||||
EXPECT_THROW(stringToCharStringData(createStringRegion("foo\\"), chstr),
|
||||
InvalidRdataText);
|
||||
}
|
||||
|
||||
TEST_F(CharStringDataTest, badDDD) {
|
||||
// Check various type of bad form of \DDD
|
||||
|
||||
// Not a number
|
||||
EXPECT_THROW(stringToCharStringData(createStringRegion("\\1a2"), chstr),
|
||||
InvalidRdataText);
|
||||
EXPECT_THROW(stringToCharStringData(createStringRegion("\\12a"), chstr),
|
||||
InvalidRdataText);
|
||||
|
||||
// Not in the range of uint8_t
|
||||
EXPECT_THROW(stringToCharStringData(createStringRegion("\\256"), chstr),
|
||||
InvalidRdataText);
|
||||
|
||||
// Short buffer
|
||||
EXPECT_THROW(stringToCharStringData(createStringRegion("\\42"), chstr),
|
||||
InvalidRdataText);
|
||||
}
|
||||
|
||||
const struct TestData {
|
||||
const char *data;
|
||||
const char *expected;
|
||||
} conversion_data[] = {
|
||||
{"Test\"Test", "Test\\\"Test"},
|
||||
{"Test;Test", "Test\\;Test"},
|
||||
{"Test\\Test", "Test\\\\Test"},
|
||||
{"Test\x1fTest", "Test\\031Test"},
|
||||
{"Test ~ Test", "Test ~ Test"},
|
||||
{"Test\x7fTest", "Test\\127Test"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
TEST_F(CharStringDataTest, charStringDataToString) {
|
||||
for (const TestData* cur = conversion_data; cur->data != NULL; ++cur) {
|
||||
uint8_t idata[32];
|
||||
size_t length = std::strlen(cur->data);
|
||||
ASSERT_LT(length, sizeof(idata));
|
||||
std::memcpy(idata, cur->data, length);
|
||||
const CharStringData test_data(idata, idata + length);
|
||||
EXPECT_EQ(cur->expected, charStringDataToString(test_data));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CharStringDataTest, compareCharStringData) {
|
||||
CharStringData charstr;
|
||||
CharStringData charstr2;
|
||||
CharStringData charstr_small1;
|
||||
CharStringData charstr_small2;
|
||||
CharStringData charstr_large1;
|
||||
CharStringData charstr_large2;
|
||||
CharStringData charstr_empty;
|
||||
|
||||
stringToCharStringData(createStringRegion("test string"), charstr);
|
||||
stringToCharStringData(createStringRegion("test string"), charstr2);
|
||||
stringToCharStringData(createStringRegion("test strin"), charstr_small1);
|
||||
stringToCharStringData(createStringRegion("test strina"), charstr_small2);
|
||||
stringToCharStringData(createStringRegion("test stringa"), charstr_large1);
|
||||
stringToCharStringData(createStringRegion("test strinz"), charstr_large2);
|
||||
|
||||
EXPECT_EQ(0, compareCharStringDatas(charstr, charstr2));
|
||||
EXPECT_EQ(0, compareCharStringDatas(charstr2, charstr));
|
||||
EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small1));
|
||||
EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small2));
|
||||
EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large1));
|
||||
EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large2));
|
||||
EXPECT_EQ(-1, compareCharStringDatas(charstr_small1, charstr));
|
||||
EXPECT_EQ(-1, compareCharStringDatas(charstr_small2, charstr));
|
||||
EXPECT_EQ(1, compareCharStringDatas(charstr_large1, charstr));
|
||||
EXPECT_EQ(1, compareCharStringDatas(charstr_large2, charstr));
|
||||
|
||||
EXPECT_EQ(-1, compareCharStringDatas(charstr_empty, charstr));
|
||||
EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_empty));
|
||||
EXPECT_EQ(0, compareCharStringDatas(charstr_empty, charstr_empty));
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
4
src/lib/dns/tests/testdata/.gitignore
vendored
4
src/lib/dns/tests/testdata/.gitignore
vendored
@@ -111,6 +111,10 @@
|
||||
/rdata_txt_fromWire3.wire
|
||||
/rdata_txt_fromWire4.wire
|
||||
/rdata_txt_fromWire5.wire
|
||||
/rdata_caa_fromWire1.wire
|
||||
/rdata_caa_fromWire2.wire
|
||||
/rdata_caa_fromWire3.wire
|
||||
/rdata_caa_fromWire4.wire
|
||||
/rdatafields1.wire
|
||||
/rdatafields2.wire
|
||||
/rdatafields3.wire
|
||||
|
5
src/lib/dns/tests/testdata/Makefile.am
vendored
5
src/lib/dns/tests/testdata/Makefile.am
vendored
@@ -67,6 +67,8 @@ BUILT_SOURCES += rdata_tsig_fromWire9.wire
|
||||
BUILT_SOURCES += rdata_tsig_toWire1.wire rdata_tsig_toWire2.wire
|
||||
BUILT_SOURCES += rdata_tsig_toWire3.wire rdata_tsig_toWire4.wire
|
||||
BUILT_SOURCES += rdata_tsig_toWire5.wire
|
||||
BUILT_SOURCES += rdata_caa_fromWire1.wire rdata_caa_fromWire2.wire
|
||||
BUILT_SOURCES += rdata_caa_fromWire3.wire rdata_caa_fromWire4.wire
|
||||
BUILT_SOURCES += tsigrecord_toWire1.wire tsigrecord_toWire2.wire
|
||||
BUILT_SOURCES += tsig_verify1.wire tsig_verify2.wire tsig_verify3.wire
|
||||
BUILT_SOURCES += tsig_verify4.wire tsig_verify5.wire tsig_verify6.wire
|
||||
@@ -176,6 +178,9 @@ EXTRA_DIST += rdata_tsig_fromWire9.spec
|
||||
EXTRA_DIST += rdata_tsig_toWire1.spec rdata_tsig_toWire2.spec
|
||||
EXTRA_DIST += rdata_tsig_toWire3.spec rdata_tsig_toWire4.spec
|
||||
EXTRA_DIST += rdata_tsig_toWire5.spec
|
||||
EXTRA_DIST += rdata_caa_fromWire1.spec rdata_caa_fromWire2.spec
|
||||
EXTRA_DIST += rdata_caa_fromWire3.spec rdata_caa_fromWire4.spec
|
||||
EXTRA_DIST += rdata_caa_fromWire5 rdata_caa_fromWire6
|
||||
EXTRA_DIST += tsigrecord_toWire1.spec tsigrecord_toWire2.spec
|
||||
EXTRA_DIST += tsig_verify1.spec tsig_verify2.spec tsig_verify3.spec
|
||||
EXTRA_DIST += tsig_verify4.spec tsig_verify5.spec tsig_verify6.spec
|
||||
|
6
src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec
vendored
Normal file
6
src/lib/dns/tests/testdata/rdata_caa_fromWire1.spec
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# The simplest form of CAA: all default parameters
|
||||
#
|
||||
[custom]
|
||||
sections: caa
|
||||
[caa]
|
7
src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec
vendored
Normal file
7
src/lib/dns/tests/testdata/rdata_caa_fromWire2.spec
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Mixed case CAA tag field.
|
||||
#
|
||||
[custom]
|
||||
sections: caa
|
||||
[caa]
|
||||
tag: 'ISSue'
|
7
src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec
vendored
Normal file
7
src/lib/dns/tests/testdata/rdata_caa_fromWire3.spec
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Missing CAA value field.
|
||||
#
|
||||
[custom]
|
||||
sections: caa
|
||||
[caa]
|
||||
value: ''
|
7
src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec
vendored
Normal file
7
src/lib/dns/tests/testdata/rdata_caa_fromWire4.spec
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Missing CAA value field.
|
||||
#
|
||||
[custom]
|
||||
sections: caa
|
||||
[caa]
|
||||
tag: ''
|
6
src/lib/dns/tests/testdata/rdata_caa_fromWire5
vendored
Normal file
6
src/lib/dns/tests/testdata/rdata_caa_fromWire5
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Test where CAA value field is shorter than the RDATA length
|
||||
|
||||
# CAA RDATA, RDLEN=32
|
||||
0020
|
||||
# FLAGS=0 TAG=c VALUE=ca.example.net
|
||||
00 01 63 63612e6578616d706c652e6e6574
|
4
src/lib/dns/tests/testdata/rdata_caa_fromWire6
vendored
Normal file
4
src/lib/dns/tests/testdata/rdata_caa_fromWire6
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Test where RDATA is completely missing
|
||||
|
||||
# CAA RDATA, RDLEN=32
|
||||
0020
|
@@ -355,7 +355,7 @@ dict_rrtype = { 'none' : 0, 'a' : 1, 'ns' : 2, 'md' : 3, 'mf' : 4, 'cname' : 5,
|
||||
'dhcid' : 49, 'nsec3' : 50, 'nsec3param' : 51, 'tlsa' : 52, 'hip' : 55,
|
||||
'spf' : 99, 'unspec' : 103, 'tkey' : 249, 'tsig' : 250,
|
||||
'dlv' : 32769, 'ixfr' : 251, 'axfr' : 252, 'mailb' : 253,
|
||||
'maila' : 254, 'any' : 255 }
|
||||
'maila' : 254, 'any' : 255, 'caa' : 257 }
|
||||
rdict_rrtype = dict([(dict_rrtype[k], k.upper()) for k in dict_rrtype.keys()])
|
||||
dict_rrclass = { 'in' : 1, 'ch' : 3, 'hs' : 4, 'any' : 255 }
|
||||
rdict_rrclass = dict([(dict_rrclass[k], k.upper()) for k in \
|
||||
@@ -893,6 +893,32 @@ class AFSDB(RR):
|
||||
f.write('# SUBTYPE=%d SERVER=%s\n' % (self.subtype, self.server))
|
||||
f.write('%04x %s\n' % (self.subtype, server_wire))
|
||||
|
||||
class CAA(RR):
|
||||
'''Implements rendering CAA RDATA in the test data format.
|
||||
|
||||
Configurable parameters are as follows (see the description of the
|
||||
same name of attribute for the default value):
|
||||
- flags (int): The flags field.
|
||||
- tag (string): The tag field.
|
||||
- value (string): The value field.
|
||||
'''
|
||||
flags = 0
|
||||
tag = 'issue'
|
||||
value = 'ca.example.net'
|
||||
def dump(self, f):
|
||||
if self.rdlen is None:
|
||||
self.rdlen = 1 + 1 + len(self.tag) + len(self.value)
|
||||
else:
|
||||
self.rdlen = int(self.rdlen)
|
||||
self.dump_header(f, self.rdlen)
|
||||
f.write('# FLAGS=%d TAG=%s VALUE=%s\n' % \
|
||||
(self.flags, self.tag, self.value))
|
||||
f.write('%02x %02x ' % \
|
||||
(self.flags, len(self.tag)))
|
||||
f.write(encode_string(self.tag))
|
||||
f.write(encode_string(self.value))
|
||||
f.write('\n')
|
||||
|
||||
class DNSKEY(RR):
|
||||
'''Implements rendering DNSKEY RDATA in the test data format.
|
||||
|
||||
|
Reference in New Issue
Block a user