Commit 2d33f5b8 authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

Merge branch 'trac2512'

parents affd7207 0c6ca277
......@@ -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.
......
// 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
// 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
......
// 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>