Commit 0770d2df authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

Merge branch 'trac2426'

parents 91867e08 acb20abe
......@@ -15,6 +15,7 @@
#include <exceptions/exceptions.h>
#include <util/buffer.h>
#include <util/encode/hex.h>
#include <dns/name.h>
#include <dns/messagerenderer.h>
......@@ -220,94 +221,100 @@ Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) {
impl_ = new GenericImpl(data);
}
void
Generic::constructHelper(const std::string& rdata_string) {
istringstream iss(rdata_string);
string unknown_mark;
iss >> unknown_mark;
if (unknown_mark != "\\#") {
GenericImpl*
Generic::constructFromLexer(MasterLexer& lexer) {
const MasterToken& token = lexer.getNextToken(MasterToken::STRING);
if (token.getString() != "\\#") {
isc_throw(InvalidRdataText,
"Missing the special token (\\#) for generic RDATA encoding");
"Missing the special token (\\#) for "
"unknown RDATA encoding");
}
// RDLENGTH: read into a string so that we can easily reject invalid tokens
string rdlen_txt;
iss >> rdlen_txt;
istringstream iss_rdlen(rdlen_txt);
int32_t rdlen;
iss_rdlen >> rdlen;
if (iss_rdlen.rdstate() != ios::eofbit) {
isc_throw(InvalidRdataText,
"Invalid representation for a generic RDLENGTH");
// Initialize with an absurd value.
uint32_t rdlen = 65536;
try {
rdlen = lexer.getNextToken(MasterToken::NUMBER).getNumber();
} catch (const MasterLexer::LexerError& ex) {
isc_throw(InvalidRdataLength,
"Unknown RDATA length is invalid");
}
if (rdlen < 0 || rdlen > 0xffff) {
isc_throw(InvalidRdataLength, "RDATA length is out of range");
if (rdlen > 65535) {
isc_throw(InvalidRdataLength,
"Unknown RDATA length is out of range: " << rdlen);
}
iss >> ws; // skip any white spaces
// Hexadecimal encoding of RDATA: each segment must consist of an even
// number of hex digits.
vector<uint8_t> data;
while (!iss.eof() && data.size() < rdlen) {
// extract two characters, which should compose a single byte of data.
char buf[2];
iss.read(buf, sizeof(buf));
if ((iss.rdstate() & (ios::badbit | ios::failbit)) != 0) {
isc_throw(InvalidRdataText,
"Invalid hex encoding of generic RDATA");
if (rdlen > 0) {
string hex_txt;
string hex_part;
// Whitespace is allowed within hex data, 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)) {
// Unget the last read token as createRdata() expects us
// to leave it at the end-of-line or end-of-file when we
// return.
lexer.ungetToken();
break;
}
token.getString(hex_part);
hex_txt.append(hex_part);
}
// convert it to a single byte integer as a hex digit.
istringstream iss_byte(string(buf, sizeof(buf)));
unsigned int ch;
iss_byte >> hex >> ch;
if (iss_byte.rdstate() != ios::eofbit) {
try {
isc::util::encode::decodeHex(hex_txt, data);
} catch (const isc::BadValue& ex) {
isc_throw(InvalidRdataText,
"Invalid hex encoding of generic RDATA");
"Invalid hex encoding of generic RDATA: " << ex.what());
}
data.push_back(ch);
iss >> ws; // skip spaces
}
if (!iss.eof()) {
isc_throw(InvalidRdataLength,
"RDLENGTH is too small for generic RDATA");
}
if (data.size() != rdlen) {
isc_throw(InvalidRdataLength,
"Generic RDATA code doesn't match RDLENGTH");
"Size of unknown RDATA hex data doesn't match RDLENGTH: "
<< data.size() << " vs. " << rdlen);
}
impl_ = new GenericImpl(data);
return (new GenericImpl(data));
}
Generic::Generic(const std::string& rdata_string) {
constructHelper(rdata_string);
}
Generic::Generic(MasterLexer& lexer, const Name*,
MasterLoader::Options,
MasterLoaderCallbacks&)
Generic::Generic(const std::string& rdata_string) :
impl_(NULL)
{
std::string s;
// 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 GenericImpl that constructFromLexer() returns.
std::auto_ptr<GenericImpl> impl_ptr(NULL);
while (true) {
const MasterToken& token = lexer.getNextToken();
if ((token.getType() == MasterToken::END_OF_FILE) ||
(token.getType() == MasterToken::END_OF_LINE)) {
lexer.ungetToken(); // let the upper layer handle the end-of token
break;
}
try {
std::istringstream ss(rdata_string);
MasterLexer lexer;
lexer.pushSource(ss);
if (!s.empty()) {
s += " ";
}
impl_ptr.reset(constructFromLexer(lexer));
s += token.getString();
if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
isc_throw(InvalidRdataText, "extra input text for unknown RDATA: "
<< rdata_string);
}
} catch (const MasterLexer::LexerError& ex) {
isc_throw(InvalidRdataText, "Failed to construct unknown RDATA "
"from '" << rdata_string << "': " << ex.what());
}
constructHelper(s);
impl_ = impl_ptr.release();
}
Generic::Generic(MasterLexer& lexer, const Name*,
MasterLoader::Options,
MasterLoaderCallbacks&) :
impl_(constructFromLexer(lexer))
{
}
Generic::~Generic() {
......
......@@ -393,7 +393,7 @@ public:
//@}
private:
void constructHelper(const std::string& rdata_string);
GenericImpl* constructFromLexer(MasterLexer& lexer);
GenericImpl* impl_;
};
......
......@@ -301,14 +301,14 @@ TEST_F(Rdata_Unknown_Test, createFromText) {
// the length should be 16-bit unsigned integer
EXPECT_THROW(generic::Generic("\\# 65536 a1b2c30d"), InvalidRdataLength);
EXPECT_THROW(generic::Generic("\\# -1 a1b2c30d"), InvalidRdataLength);
EXPECT_THROW(generic::Generic("\\# 1.1 a1"), InvalidRdataText);
EXPECT_THROW(generic::Generic("\\# 1.1 a1"), InvalidRdataLength);
EXPECT_THROW(generic::Generic("\\# 0a 00010203040506070809"),
InvalidRdataText);
InvalidRdataLength);
// should reject if the special token is missing.
EXPECT_THROW(generic::Generic("4 a1b2c30d"), InvalidRdataText);
// the special token, the RDLENGTH and the data must be space separated.
EXPECT_THROW(generic::Generic("\\#0"), InvalidRdataText);
EXPECT_THROW(generic::Generic("\\# 1ff"), InvalidRdataText);
EXPECT_THROW(generic::Generic("\\# 1ff"), InvalidRdataLength);
}
TEST_F(Rdata_Unknown_Test, createFromWire) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment