summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/rdata.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dns/rdata.cc')
-rw-r--r--src/lib/dns/rdata.cc142
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() {