diff options
Diffstat (limited to 'src/lib/dns/rdata.cc')
-rw-r--r-- | src/lib/dns/rdata.cc | 142 |
1 files changed, 79 insertions, 63 deletions
diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc index f42c349f2d..a34f8870fe 100644 --- a/src/lib/dns/rdata.cc +++ b/src/lib/dns/rdata.cc @@ -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> @@ -46,6 +47,15 @@ namespace isc { namespace dns { namespace rdata { +uint16_t +Rdata::getLength() const { + OutputBuffer obuffer(0); + + toWire(obuffer); + + return (obuffer.getLength()); +} + // XXX: we need to specify std:: for string to help doxygen match the // function signature with that given in the header file. RdataPtr @@ -211,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); -} - -Generic::Generic(const std::string& rdata_string) { - constructHelper(rdata_string); + return (new GenericImpl(data)); } -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() { |