Commit c6603dec authored by Paul Selkirk's avatar Paul Selkirk
Browse files

Merge branch 'trac2521'

Conflicts:
	src/lib/dns/gen-rdatacode.py.in
parents 315d2846 65b7adb8
#!@PYTHON@
# Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
# Copyright (C) 2010-2013 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
......@@ -32,9 +32,11 @@ import sys
#
# Example:
# new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
new_rdata_factory_users = [('a', 'in'), ('aaaa', 'in'),
new_rdata_factory_users = [('a', 'in'),
('aaaa', 'in'),
('afsdb', 'generic'),
('cname', 'generic'),
('dhcid', 'in'),
('dlv', 'generic'),
('dname', 'generic'),
('dnskey', 'generic'),
......@@ -46,7 +48,9 @@ new_rdata_factory_users = [('a', 'in'), ('aaaa', 'in'),
('nsec', 'generic'),
('nsec3', 'generic'),
('nsec3param', 'generic'),
('opt', 'generic'),
('ptr', 'generic'),
('rrsig', 'generic'),
('soa', 'generic'),
('spf', 'generic'),
('srv', 'in'),
......
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010-2013 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
......@@ -27,10 +27,26 @@ using namespace isc::util;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
/// \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&) {
isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text");
}
/// \brief Constructor with a context of MasterLexer.
///
/// This constructor cannot be used, and always throws an exception.
///
/// \throw InvalidRdataText OPT RR cannot be constructed from text.
OPT::OPT(MasterLexer&, const Name*,
MasterLoader::Options, MasterLoaderCallbacks&)
{
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.
......@@ -48,6 +64,7 @@ OPT::OPT(const OPT&) : Rdata() {
std::string
OPT::toText() const {
// OPT records do not have a text format.
return ("");
}
......
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010-2013 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
......@@ -26,9 +26,9 @@
#include <dns/messagerenderer.h>
#include <dns/name.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdata/generic/detail/lexer_util.h>
#include <stdio.h>
#include <time.h>
......@@ -36,6 +36,7 @@
using namespace std;
using namespace isc::util;
using namespace isc::util::encode;
using isc::dns::rdata::generic::detail::createNameFromLexer;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
......@@ -52,8 +53,8 @@ const size_t RRSIG_MINIMUM_LEN = 2 * sizeof(uint8_t) + 2 * sizeof(uint16_t) +
struct RRSIGImpl {
// straightforward representation of RRSIG RDATA fields
RRSIGImpl(const RRType& covered, uint8_t algorithm, uint8_t labels,
uint32_t originalttl, uint32_t timeexpire, uint32_t timeinception,
uint16_t tag, const Name& signer,
uint32_t originalttl, uint32_t timeexpire,
uint32_t timeinception, uint16_t tag, const Name& signer,
const vector<uint8_t>& signature) :
covered_(covered), algorithm_(algorithm), labels_(labels),
originalttl_(originalttl), timeexpire_(timeexpire),
......@@ -72,38 +73,125 @@ struct RRSIGImpl {
const vector<uint8_t> signature_;
};
RRSIG::RRSIG(const std::string& rrsig_str) :
impl_(NULL)
{
istringstream iss(rrsig_str);
string covered_txt, signer_txt, expire_txt, inception_txt;
unsigned int algorithm, labels;
uint32_t originalttl;
uint16_t tag;
stringbuf signaturebuf;
iss >> covered_txt >> algorithm >> labels >> originalttl
>> expire_txt >> inception_txt >> tag >> signer_txt
>> &signaturebuf;
if (iss.bad() || iss.fail()) {
isc_throw(InvalidRdataText, "Invalid RRSIG text");
}
// helper function for string and lexer constructors
RRSIGImpl*
RRSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) {
const RRType covered(lexer.getNextToken(MasterToken::STRING).getString());
const uint32_t algorithm =
lexer.getNextToken(MasterToken::NUMBER).getNumber();
if (algorithm > 0xff) {
isc_throw(InvalidRdataText, "RRSIG algorithm out of range");
}
const uint32_t labels =
lexer.getNextToken(MasterToken::NUMBER).getNumber();
if (labels > 0xff) {
isc_throw(InvalidRdataText, "RRSIG labels out of range");
}
const uint32_t timeexpire = timeFromText32(expire_txt);
const uint32_t timeinception = timeFromText32(inception_txt);
const uint32_t originalttl =
lexer.getNextToken(MasterToken::NUMBER).getNumber();
const uint32_t timeexpire =
timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
const uint32_t timeinception =
timeFromText32(lexer.getNextToken(MasterToken::STRING).getString());
const uint32_t tag =
lexer.getNextToken(MasterToken::NUMBER).getNumber();
if (tag > 0xffff) {
isc_throw(InvalidRdataText, "RRSIG key tag out of range");
}
const Name& signer = createNameFromLexer(lexer, origin);
string signature_txt;
string signature_part;
// Whitespace is allowed within base64 text, so read to the end of input.
while (true) {
const MasterToken& token =
lexer.getNextToken(MasterToken::STRING, true);
if ((token.getType() == MasterToken::END_OF_FILE) ||
(token.getType() == MasterToken::END_OF_LINE)) {
break;
}
token.getString(signature_part);
signature_txt.append(signature_part);
}
lexer.ungetToken();
vector<uint8_t> signature;
decodeBase64(signaturebuf.str(), signature);
// missing signature is okay
if (signature_txt.size() > 0) {
decodeBase64(signature_txt, signature);
}
impl_ = new RRSIGImpl(RRType(covered_txt), algorithm, labels,
originalttl, timeexpire, timeinception, tag,
Name(signer_txt), signature);
return (new RRSIGImpl(covered, algorithm, labels,
originalttl, timeexpire, timeinception,
static_cast<uint16_t>(tag), signer, signature));
}
/// \brief Constructor from string.
///
/// The given string must represent a valid RRSIG RDATA. There can be extra
/// space characters at the beginning or end of the text (which are simply
/// ignored), but other extra text, including a new line, will make the
/// construction fail with an exception.
///
/// The Signer's Name must be absolute since there's no parameter that
/// specifies the origin name; if this is not absolute, \c MissingNameOrigin
/// exception will be thrown. This must not be represented as a quoted
/// string.
///
/// See the construction that takes \c MasterLexer for other fields.
///
/// \throw Others Exception from the Name constructor.
/// \throw InvalidRdataText Other general syntax errors.
RRSIG::RRSIG(const std::string& rrsig_str) :
impl_(NULL)
{
// We use 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 RRSIGImpl that constructFromLexer() returns.
std::auto_ptr<RRSIGImpl> impl_ptr(NULL);
try {
std::istringstream iss(rrsig_str);
MasterLexer lexer;
lexer.pushSource(iss);
impl_ptr.reset(constructFromLexer(lexer, NULL));
if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
isc_throw(InvalidRdataText, "extra input text for RRSIG: "
<< rrsig_str);
}
} catch (const MasterLexer::LexerError& ex) {
isc_throw(InvalidRdataText, "Failed to construct RRSIG from '" <<
rrsig_str << "': " << ex.what());
}
impl_ = impl_ptr.release();
}
/// \brief Constructor with a context of MasterLexer.
///
/// The \c lexer should point to the beginning of valid textual representation
/// of an RRSIG RDATA. The Signer's Name fields can be non absolute if \c
/// origin is non NULL, in which case \c origin is used to make it absolute.
/// This must not be represented as a quoted string.
///
/// The Original TTL field is a valid decimal representation of an unsigned
/// 32-bit integer. Note that alternate textual representations of \c RRTTL,
/// such as "1H" for 3600 seconds, are not allowed here.
///
/// \throw MasterLexer::LexerError General parsing error such as missing field.
/// \throw Other Exceptions from the Name constructor if
/// construction of textual fields as these objects fail.
///
/// \param lexer A \c MasterLexer object parsing a master file for the
/// RDATA to be created
/// \param origin If non NULL, specifies the origin of Signer's Name when
/// it is non absolute.
RRSIG::RRSIG(MasterLexer& lexer, const Name* origin,
MasterLoader::Options, MasterLoaderCallbacks&) :
impl_(constructFromLexer(lexer, origin))
{
}
RRSIG::RRSIG(InputBuffer& buffer, size_t rdata_len) {
......
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010-2013 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
......@@ -18,7 +18,6 @@
#include <dns/name.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rdata.h>
// BEGIN_HEADER_GUARD
......@@ -32,6 +31,12 @@
struct RRSIGImpl;
/// \brief \c rdata::RRSIG class represents the RRSIG RDATA as defined %in
/// RFC4034.
///
/// This class implements the basic interfaces inherited from the abstract
/// \c rdata::Rdata class, and provides trivial accessors specific to the
/// RRSIG RDATA.
class RRSIG : public Rdata {
public:
// BEGIN_COMMON_MEMBERS
......@@ -42,6 +47,9 @@ public:
// specialized methods
const RRType& typeCovered() const;
private:
// helper function for string and lexer constructors
RRSIGImpl* constructFromLexer(MasterLexer& lexer, const Name* origin);
RRSIGImpl* impl_;
};
......
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2013 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
......@@ -15,8 +15,6 @@
#include <stdint.h>
#include <string.h>
#include <string>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
......@@ -28,53 +26,77 @@
using namespace std;
using namespace isc::util;
using namespace isc::util::encode;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
void
DHCID::constructFromLexer(MasterLexer& lexer) {
string digest_txt = lexer.getNextToken(MasterToken::STRING).getString();
// Whitespace is allowed within base64 text, so read to the end of input.
string digest_part;
while (true) {
const MasterToken& token =
lexer.getNextToken(MasterToken::STRING, true);
if ((token.getType() == MasterToken::END_OF_FILE) ||
(token.getType() == MasterToken::END_OF_LINE)) {
break;
}
token.getString(digest_part);
digest_txt.append(digest_part);
}
lexer.ungetToken();
decodeBase64(digest_txt, digest_);
}
/// \brief Constructor from string.
///
/// \param dhcid_str A base-64 representation of the DHCID binary data.
/// The data is considered to be opaque, but a sanity check is performed.
///
/// <b>Exceptions</b>
///
/// \c dhcid_str must be a valid BASE-64 string, otherwise an exception
/// of class \c isc::BadValue will be thrown;
/// the binary data should consist of at leat of 3 octets as per RFC4701:
/// < 2 octets > Identifier type code
/// < 1 octet > Digest type code
/// < n octets > Digest (length depends on digest type)
/// If the data is less than 3 octets (i.e. it cannot contain id type code and
/// digest type code), an exception of class \c InvalidRdataLength is thrown.
/// \throw InvalidRdataText if the string could not be parsed correctly.
DHCID::DHCID(const std::string& dhcid_str) {
istringstream iss(dhcid_str);
stringbuf digestbuf;
iss >> &digestbuf;
isc::util::encode::decodeBase64(digestbuf.str(), digest_);
// RFC4701 states DNS software should consider the RDATA section to
// be opaque, but there must be at least three bytes in the data:
// < 2 octets > Identifier type code
// < 1 octet > Digest type code
if (digest_.size() < 3) {
isc_throw(InvalidRdataLength, "DHCID length " << digest_.size() <<
" too short, need at least 3 bytes");
try {
std::istringstream iss(dhcid_str);
MasterLexer lexer;
lexer.pushSource(iss);
constructFromLexer(lexer);
if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
isc_throw(InvalidRdataText, "extra input text for DHCID: "
<< dhcid_str);
}
} catch (const MasterLexer::LexerError& ex) {
isc_throw(InvalidRdataText, "Failed to construct DHCID from '" <<
dhcid_str << "': " << ex.what());
}
}
/// \brief Constructor with a context of MasterLexer.
///
/// The \c lexer should point to the beginning of valid textual representation
/// of a DHCID RDATA.
///
/// \throw BadValue if the text is not valid base-64.
/// \throw MasterLexer::LexerError General parsing error such as missing field.
///
/// \param lexer A \c MasterLexer object parsing a master file for the
/// RDATA to be created
DHCID::DHCID(MasterLexer& lexer, const Name*,
MasterLoader::Options, MasterLoaderCallbacks&) {
constructFromLexer(lexer);
}
/// \brief Constructor from wire-format data.
///
/// \param buffer A buffer storing the wire format data.
/// \param rdata_len The length of the RDATA in bytes
///
/// <b>Exceptions</b>
/// \c InvalidRdataLength is thrown if \c rdata_len is than minimum of 3 octets
DHCID::DHCID(InputBuffer& buffer, size_t rdata_len) {
if (rdata_len < 3) {
isc_throw(InvalidRdataLength, "DHCID length " << rdata_len <<
" too short, need at least 3 bytes");
if (rdata_len == 0) {
isc_throw(InvalidRdataLength, "Missing DHCID rdata");
}
digest_.resize(rdata_len);
......@@ -112,7 +134,7 @@ DHCID::toWire(AbstractMessageRenderer& renderer) const {
/// \return A string representation of \c DHCID.
string
DHCID::toText() const {
return (isc::util::encode::encodeBase64(digest_));
return (encodeBase64(digest_));
}
/// \brief Compare two instances of \c DHCID RDATA.
......
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2013 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
......@@ -43,6 +43,9 @@ public:
const std::vector<uint8_t>& getDigest() const;
private:
// helper for string and lexer constructors
void constructFromLexer(MasterLexer& lexer);
/// \brief Private data representation
///
/// Opaque data at least 3 octets long as per RFC4701.
......
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010-2013 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
......@@ -98,7 +98,7 @@ protected:
rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
RRType::RRSIG(), RRTTL(3600)));
rrset_rrsig->addRdata(generic::RRSIG("AAAA 5 3 7200 20100322084538 "
"20100220084538 1 example.com "
"20100220084538 1 example.com. "
"FAKEFAKEFAKEFAKE"));
rrset_aaaa->addRRsig(rrset_rrsig);
}
......
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2013 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
......@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <exceptions/exceptions.h>
#include <util/buffer.h>
#include <dns/rdataclass.h>
#include <util/encode/base64.h>
......@@ -23,6 +25,7 @@
using isc::UnitTestUtil;
using namespace std;
using namespace isc;
using namespace isc::dns;
using namespace isc::util;
using namespace isc::util::encode;
......@@ -30,25 +33,69 @@ using namespace isc::dns::rdata;
namespace {
const string string_dhcid(
"0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA=");
const in::DHCID rdata_dhcid(string_dhcid);
class Rdata_DHCID_Test : public RdataTest {
protected:
Rdata_DHCID_Test() :
dhcid_txt("0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA="),
rdata_dhcid(dhcid_txt)
{}
void checkFromText_None(const string& rdata_str) {
checkFromText<in::DHCID, isc::Exception, isc::Exception>(
rdata_str, rdata_dhcid, false, false);
}
void checkFromText_BadValue(const string& rdata_str) {
checkFromText<in::DHCID, BadValue, BadValue>(
rdata_str, rdata_dhcid, true, true);
}
void checkFromText_LexerError(const string& rdata_str) {
checkFromText
<in::DHCID, InvalidRdataText, MasterLexer::LexerError>(
rdata_str, rdata_dhcid, true, true);
}
void checkFromText_BadString(const string& rdata_str) {
checkFromText
<in::DHCID, InvalidRdataText, isc::Exception>(
rdata_str, rdata_dhcid, true, false);
}
const string dhcid_txt;
const in::DHCID rdata_dhcid;
};
TEST_F(Rdata_DHCID_Test, createFromString) {
const in::DHCID rdata_dhcid2(string_dhcid);
EXPECT_EQ(0, rdata_dhcid2.compare(rdata_dhcid));
}
TEST_F(Rdata_DHCID_Test, fromText) {
EXPECT_EQ(dhcid_txt, rdata_dhcid.toText());
// Space in digest data is OK
checkFromText_None(
"0LIg0LvQtdGB0YMg 0YDQvtC00LjQu9Cw 0YHRjCDRkdC70L7R h9C60LA=");
// Multi-line digest data is OK, if enclosed in parentheses
checkFromText_None(
"( 0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw\n0YHRjCDRkdC70L7R h9C60LA= )");
TEST_F(Rdata_DHCID_Test, badBase64) {
EXPECT_THROW(const in::DHCID rdata_dhcid_bad("00"), isc::BadValue);
// Trailing garbage. This should cause only the string constructor
// to fail, but the lexer constructor must be able to continue
// parsing from it.
checkFromText_BadString(
"0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw0YHRjCDRkdC70L7Rh9C60LA="
" ; comment\n"
"AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=");
}
TEST_F(Rdata_DHCID_Test, badLength) {
EXPECT_THROW(const in::DHCID rdata_dhcid_bad("MDA="), InvalidRdataLength);
TEST_F(Rdata_DHCID_Test, badText) {
// missing digest data
checkFromText_LexerError("");
// invalid base64
checkFromText_BadValue("EEeeeeeeEEEeeeeeeGaaahAAAAAAAAHHHHHHHHHHH!=");
// unterminated multi-line base64
checkFromText_LexerError(
"( 0LIg0LvQtdGB0YMg0YDQvtC00LjQu9Cw\n0YHRjCDRkdC70L7R h9C60LA=");
}
TEST_F(Rdata_DHCID_Test, copy) {
......@@ -60,17 +107,17 @@ TEST_F(Rdata_DHCID_Test, createFromWire) {
EXPECT_EQ(0, rdata_dhcid.compare(
*rdataFactoryFromFile(RRType("DHCID"), RRClass("IN"),
"rdata_dhcid_fromWire")));
InputBuffer buffer(NULL, 0);
EXPECT_THROW(in::DHCID(buffer, 0), InvalidRdataLength);
// TBD: more tests
}
TEST_F(Rdata_DHCID_Test, createFromLexer) {
EXPECT_EQ(0, rdata_dhcid.compare(
*test::createRdataUsingLexer(RRType::DHCID(), RRClass::IN(),
string_dhcid)));
// Exceptions cause NULL to be returned.
EXPECT_FALSE(test::createRdataUsingLexer(RRType::DHCID(), RRClass::IN(),
"00"));
dhcid_txt)));
}
TEST_F(Rdata_DHCID_Test, toWireRenderer) {
......@@ -92,13 +139,13 @@ TEST_F(Rdata_DHCID_Test, toWireBuffer) {
}
TEST_F(Rdata_DHCID_Test, toText) {
EXPECT_EQ(string_dhcid, rdata_dhcid.toText());
EXPECT_EQ(dhcid_txt, rdata_dhcid.toText());
}
TEST_F(Rdata_DHCID_Test, getDHCIDDigest) {
const string string_dhcid1(encodeBase64(rdata_dhcid.getDigest()));
const string dhcid_txt1(encodeBase64(rdata_dhcid.getDigest()));
EXPECT_EQ(string_dhcid, string_dhcid1);
EXPECT_EQ(dhcid_txt, dhcid_txt1);
}
TEST_F(Rdata_DHCID_Test, compare) {
......@@ -117,6 +164,6 @@ TEST_F(Rdata_DHCID_Test, compare) {
EXPECT_GT(rdata_dhcid3.compare(rdata_dhcid2), 0);
// comparison attempt between incompatible RR types should be rejected
EXPECT_THROW(rdata_dhcid.compare(*rdata_nomatch), bad_cast);
EXPECT_THROW(rdata_dhcid.compare(*rdata_nomatch), bad_cast);
}
}
......@@ -84,6 +84,6 @@ TEST_F(Rdata_OPT_Test, compare) {
"rdata_opt_fromWire", 2)));
// comparison attempt between incompatible RR types should be rejected
EXPECT_THROW(rdata_opt.compare(*RdataTest::rdata_nomatch), bad_cast);
EXPECT_THROW(rdata_opt.compare(*RdataTest::rdata_nomatch), bad_cast);
}
}
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010-2013 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
......@@ -36,7 +36,7 @@ using namespace isc::dns::rdata;
namespace {
class Rdata_RRSIG_Test : public<