From: Mukund Sivaraman Date: Fri, 10 Jan 2014 10:27:16 +0000 (+0530) Subject: [2426] Support generic version of rdata::createRdata(text) in generic RDATA X-Git-Tag: bind10-1.2.0beta1-release~43^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4976235a26688d12d2c2a51f13ef66dc38ff9ee9;p=thirdparty%2Fkea.git [2426] Support generic version of rdata::createRdata(text) in generic RDATA Also adjust tests correcting the expected behaviour. --- diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc index f42c349f2d..cdd03c155c 100644 --- a/src/lib/dns/rdata.cc +++ b/src/lib/dns/rdata.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -212,93 +213,87 @@ Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) { } void -Generic::constructHelper(const std::string& rdata_string) { - istringstream iss(rdata_string); - string unknown_mark; - iss >> unknown_mark; - if (unknown_mark != "\\#") { +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"); + uint32_t rdlen; + + 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 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)) { + 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) { + lexer.ungetToken(); + + 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"); + "Unknown RDATA hex data doesn't match RDLENGTH: " + << data.size() << " vs. " << rdlen); } impl_ = new GenericImpl(data); } Generic::Generic(const std::string& rdata_string) { - constructHelper(rdata_string); + try { + std::istringstream ss(rdata_string); + MasterLexer lexer; + lexer.pushSource(ss); + + constructFromLexer(lexer); + + 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()); + } } Generic::Generic(MasterLexer& lexer, const Name*, MasterLoader::Options, MasterLoaderCallbacks&) { - std::string s; - - 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; - } - - if (!s.empty()) { - s += " "; - } - - s += token.getString(); - } - - constructHelper(s); + constructFromLexer(lexer); } Generic::~Generic() { diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h index 3fe0c74dd2..01ce7b3026 100644 --- a/src/lib/dns/rdata.h +++ b/src/lib/dns/rdata.h @@ -378,7 +378,7 @@ public: //@} private: - void constructHelper(const std::string& rdata_string); + void constructFromLexer(MasterLexer& lexer); GenericImpl* impl_; }; diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc index 3839fbd24f..dcac2667e9 100644 --- a/src/lib/dns/tests/rdata_unittest.cc +++ b/src/lib/dns/tests/rdata_unittest.cc @@ -290,14 +290,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) {