Commit a1681704 authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

Merge branch 'trac2185'

parents 670577e8 080f7d6b
......@@ -70,6 +70,8 @@ EXTRA_DIST += rdata/generic/spf_99.cc
EXTRA_DIST += rdata/generic/spf_99.h
EXTRA_DIST += rdata/generic/sshfp_44.cc
EXTRA_DIST += rdata/generic/sshfp_44.h
EXTRA_DIST += rdata/generic/tlsa_52.cc
EXTRA_DIST += rdata/generic/tlsa_52.h
EXTRA_DIST += rdata/generic/txt_16.cc
EXTRA_DIST += rdata/generic/txt_16.h
EXTRA_DIST += rdata/generic/minfo_14.cc
......@@ -135,6 +137,7 @@ libb10_dns___la_SOURCES += master_loader.h
libb10_dns___la_SOURCES += rrset_collection_base.h
libb10_dns___la_SOURCES += rrset_collection.h rrset_collection.cc
libb10_dns___la_SOURCES += zone_checker.h zone_checker.cc
libb10_dns___la_SOURCES += rdata_pimpl_holder.h
libb10_dns___la_SOURCES += rdata/generic/detail/char_string.h
libb10_dns___la_SOURCES += rdata/generic/detail/char_string.cc
libb10_dns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
......
......@@ -41,7 +41,7 @@ meta_types = {
'10': 'null', '11': 'wks', '19': 'x25', '21': 'rt', '22': 'nsap',
'23': 'nsap-ptr', '24': 'sig', '20': 'isdn', '25': 'key', '26': 'px',
'27': 'gpos', '29': 'loc', '36': 'kx', '37': 'cert', '42': 'apl',
'45': 'ipseckey', '52': 'tlsa', '55': 'hip', '103': 'unspec',
'45': 'ipseckey', '55': 'hip', '103': 'unspec',
'104': 'nid', '105': 'l32', '106': 'l64', '107': 'lp', '249': 'tkey',
'253': 'mailb', '256': 'uri', '257': 'caa'
}
......
// 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
// 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:
// 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.
#ifndef DNS_RDATA_PIMPL_HOLDER_H
#define DNS_RDATA_PIMPL_HOLDER_H 1
#include <boost/noncopyable.hpp>
#include <cstddef> // for NULL
namespace isc {
namespace dns {
namespace rdata {
template <typename T>
class RdataPimplHolder : boost::noncopyable {
public:
RdataPimplHolder(T* obj = NULL) :
obj_(obj)
{}
~RdataPimplHolder() {
delete obj_;
}
void reset(T* obj = NULL) {
delete obj_;
obj_ = obj;
}
T* get() {
return (obj_);
}
T* release() {
T* obj = obj_;
obj_ = NULL;
return (obj);
}
private:
T* obj_;
};
} // namespace rdata
} // namespace dns
} // namespace isc
#endif // DNS_RDATA_PIMPL_HOLDER_H
......@@ -39,6 +39,7 @@ run_unittests_SOURCES += opcode_unittest.cc
run_unittests_SOURCES += rcode_unittest.cc
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_in_a_unittest.cc rdata_in_aaaa_unittest.cc
run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
......@@ -60,6 +61,7 @@ run_unittests_SOURCES += rdata_nsec3param_like_unittest.cc
run_unittests_SOURCES += rdata_rrsig_unittest.cc
run_unittests_SOURCES += rdata_rp_unittest.cc
run_unittests_SOURCES += rdata_srv_unittest.cc
run_unittests_SOURCES += rdata_tlsa_unittest.cc
run_unittests_SOURCES += rdata_minfo_unittest.cc
run_unittests_SOURCES += rdata_tsig_unittest.cc
run_unittests_SOURCES += rdata_naptr_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 <dns/rdata_pimpl_holder.h>
#include <gtest/gtest.h>
using namespace isc::dns::rdata;
namespace {
TEST(RdataPimplHolderTest, all) {
// Let's check with an integer
int* i1 = new int(42);
RdataPimplHolder<int> holder1(i1);
// The same pointer must be returned.
EXPECT_EQ(i1, holder1.get());
// Obviously the value should match too.
EXPECT_EQ(42, *holder1.get());
// We don't explictly delete i or holder1, so it should not leak
// anything when the test is done (checked by Valgrind).
// The following cases are similar:
// Test no-argument reset()
int* i2 = new int(43);
RdataPimplHolder<int> holder2(i2);
holder2.reset();
EXPECT_EQ(NULL, holder2.get());
// Test reset() with argument
int* i3 = new int(44);
int* i4 = new int(45);
RdataPimplHolder<int> holder3(i3);
EXPECT_EQ(i3, holder3.get());
holder3.reset(i4);
EXPECT_EQ(i4, holder3.get());
EXPECT_EQ(45, *holder3.get());
// Test release()
RdataPimplHolder<int> holder4(new int(46));
EXPECT_NE(static_cast<void*>(NULL), holder4.get());
EXPECT_EQ(46, *holder4.get());
int* i5 = holder4.release();
EXPECT_EQ(NULL, holder4.get());
EXPECT_NE(static_cast<void*>(NULL), i5);
EXPECT_EQ(46, *i5);
delete i5;
}
}
// 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>