Kea 2.5.5
rdata.cc
Go to the documentation of this file.
1// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10
11#include <util/buffer.h>
12#include <util/encode/hex.h>
13
14#include <dns/name.h>
15#include <dns/messagerenderer.h>
16#include <dns/master_lexer.h>
17#include <dns/rdata.h>
18#include <dns/rrparamregistry.h>
19#include <dns/rrtype.h>
20
21#include <boost/lexical_cast.hpp>
22#include <boost/shared_ptr.hpp>
23
24#include <algorithm>
25#include <cctype>
26#include <string>
27#include <sstream>
28#include <iomanip>
29#include <ios>
30#include <ostream>
31#include <vector>
32
33#include <stdint.h>
34#include <string.h>
35
36using namespace std;
37using boost::lexical_cast;
38using namespace isc::util;
39
40namespace isc {
41namespace dns {
42namespace rdata {
43
44uint16_t
46 OutputBuffer obuffer(0);
47
48 toWire(obuffer);
49
50 return (obuffer.getLength());
51}
52
53// XXX: we need to specify std:: for string to help doxygen match the
54// function signature with that given in the header file.
56createRdata(const RRType& rrtype, const RRClass& rrclass,
57 const std::string& rdata_string)
58{
59 return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass,
60 rdata_string));
61}
62
64createRdata(const RRType& rrtype, const RRClass& rrclass,
65 isc::util::InputBuffer& buffer, size_t len)
66{
67 if (len > MAX_RDLENGTH) {
68 isc_throw(InvalidRdataLength, "RDLENGTH too large");
69 }
70
71 size_t old_pos = buffer.getPosition();
72
73 RdataPtr rdata =
74 RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, buffer,
75 len);
76
77 if (buffer.getPosition() - old_pos != len) {
78 isc_throw(InvalidRdataLength, "RDLENGTH mismatch: " <<
79 buffer.getPosition() - old_pos << " != " << len);
80 }
81
82 return (rdata);
83}
84
86createRdata(const RRType& rrtype, const RRClass& rrclass, const Rdata& source)
87{
88 return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass,
89 source));
90}
91
92namespace {
93void
94fromtextError(bool& error_issued, const MasterLexer& lexer,
95 MasterLoaderCallbacks& callbacks,
96 const MasterToken* token, const char* reason)
97{
98 // Don't be too noisy if there are many issues for single RDATA
99 if (error_issued) {
100 return;
101 }
102 error_issued = true;
103
104 if (token == NULL) {
105 callbacks.error(lexer.getSourceName(), lexer.getSourceLine(),
106 "createRdata from text failed: " + string(reason));
107 return;
108 }
109
110 switch (token->getType()) {
113 callbacks.error(lexer.getSourceName(), lexer.getSourceLine(),
114 "createRdata from text failed near '" +
115 token->getString() + "': " + string(reason));
116 break;
118 callbacks.error(lexer.getSourceName(), lexer.getSourceLine(),
119 "createRdata from text failed: " +
120 token->getErrorText());
121 break;
122 default:
123 // This case shouldn't happen based on how we use MasterLexer in
124 // createRdata(), so we could assert() that here. But since it
125 // depends on detailed behavior of other classes, we treat the case
126 // in a bit less harsh way.
127 isc_throw(Unexpected, "bug: createRdata() saw unexpected token type");
128 }
129}
130}
131
133createRdata(const RRType& rrtype, const RRClass& rrclass,
134 MasterLexer& lexer, const Name* origin,
135 MasterLoader::Options options,
136 MasterLoaderCallbacks& callbacks)
137{
138 RdataPtr rdata;
139
140 bool error_issued = false;
141 try {
143 rrtype, rrclass, lexer, origin, options, callbacks);
144 } catch (const MasterLexer::LexerError& error) {
145 fromtextError(error_issued, lexer, callbacks, &error.token_, "");
146 } catch (const Exception& ex) {
147 // Catching all isc::Exception is too broad, but right now we don't
148 // have better granularity. When we complete #2518 we can make this
149 // finer.
150 fromtextError(error_issued, lexer, callbacks, NULL, ex.what());
151 }
152 // Other exceptions mean a serious implementation bug or fatal system
153 // error; it doesn't make sense to catch and try to recover from them
154 // here. Just propagate.
155
156 // Consume to end of line / file.
157 // Call callback via fromtextError once if there was an error.
158 do {
159 const MasterToken& token = lexer.getNextToken();
160 switch (token.getType()) {
162 return (rdata);
164 callbacks.warning(lexer.getSourceName(), lexer.getSourceLine(),
165 "file does not end with newline");
166 return (rdata);
167 default:
168 rdata.reset(); // we'll return NULL
169 fromtextError(error_issued, lexer, callbacks, &token,
170 "extra input text");
171 // Continue until we see EOL or EOF
172 }
173 } while (true);
174
175 // We shouldn't reach here
176 assert(false);
177 return (RdataPtr()); // add explicit return to silence some compilers
178}
179
180int
181compareNames(const Name& n1, const Name& n2) {
182 size_t len1 = n1.getLength();
183 size_t len2 = n2.getLength();
184 size_t cmplen = min(len1, len2);
185
186 for (size_t i = 0; i < cmplen; ++i) {
187 uint8_t c1 = tolower(n1.at(i));
188 uint8_t c2 = tolower(n2.at(i));
189 if (c1 < c2) {
190 return (-1);
191 } else if (c1 > c2) {
192 return (1);
193 }
194 }
195
196 return ((len1 == len2) ? 0 : (len1 < len2) ? -1 : 1);
197}
198
199namespace generic {
201 GenericImpl(const vector<uint8_t>& data) : data_(data) {}
202 vector<uint8_t> data_;
203};
204
205Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) {
206 if (rdata_len > MAX_RDLENGTH) {
207 isc_throw(InvalidRdataLength, "RDLENGTH too large");
208 }
209
210 vector<uint8_t> data(rdata_len);
211 if (rdata_len > 0) {
212 buffer.readData(&data[0], rdata_len);
213 }
214
215 impl_ = new GenericImpl(data);
216}
217
219Generic::constructFromLexer(MasterLexer& lexer) {
220 const MasterToken& token = lexer.getNextToken(MasterToken::STRING);
221 if (token.getString() != "\\#") {
223 "Missing the special token (\\#) for "
224 "unknown RDATA encoding");
225 }
226
227 // Initialize with an absurd value.
228 uint32_t rdlen = 65536;
229
230 try {
232 } catch (const MasterLexer::LexerError&) {
233 isc_throw(InvalidRdataLength,
234 "Unknown RDATA length is invalid");
235 }
236
237 if (rdlen > 65535) {
238 isc_throw(InvalidRdataLength,
239 "Unknown RDATA length is out of range: " << rdlen);
240 }
241
242 vector<uint8_t> data;
243
244 if (rdlen > 0) {
245 string hex_txt;
246 string hex_part;
247 // Whitespace is allowed within hex data, so read to the end of input.
248 while (true) {
249 const MasterToken& token =
251 if ((token.getType() == MasterToken::END_OF_FILE) ||
252 (token.getType() == MasterToken::END_OF_LINE)) {
253 // Unget the last read token as createRdata() expects us
254 // to leave it at the end-of-line or end-of-file when we
255 // return.
256 lexer.ungetToken();
257 break;
258 }
259 token.getString(hex_part);
260 hex_txt.append(hex_part);
261 }
262
263 try {
264 isc::util::encode::decodeHex(hex_txt, data);
265 } catch (const isc::BadValue& ex) {
266 isc_throw(InvalidRdataText,
267 "Invalid hex encoding of generic RDATA: " << ex.what());
268 }
269 }
270
271 if (data.size() != rdlen) {
272 isc_throw(InvalidRdataLength,
273 "Size of unknown RDATA hex data doesn't match RDLENGTH: "
274 << data.size() << " vs. " << rdlen);
275 }
276
277 return (new GenericImpl(data));
278}
279
280Generic::Generic(const std::string& rdata_string) :
281 impl_(NULL)
282{
283 // We use unique_ptr here because if there is an exception in this
284 // constructor, the destructor is not called and there could be a
285 // leak of the GenericImpl that constructFromLexer() returns.
286 std::unique_ptr<GenericImpl> impl_ptr;
287
288 try {
289 std::istringstream ss(rdata_string);
290 MasterLexer lexer;
291 lexer.pushSource(ss);
292
293 impl_ptr.reset(constructFromLexer(lexer));
294
296 isc_throw(InvalidRdataText, "extra input text for unknown RDATA: "
297 << rdata_string);
298 }
299 } catch (const MasterLexer::LexerError& ex) {
300 isc_throw(InvalidRdataText, "Failed to construct unknown RDATA "
301 "from '" << rdata_string << "': " << ex.what());
302 }
303
304 impl_ = impl_ptr.release();
305}
306
310 impl_(constructFromLexer(lexer))
311{
312}
313
315 delete impl_;
316}
317
318Generic::Generic(const Generic& source) :
319 Rdata(), impl_(new GenericImpl(*source.impl_))
320{}
321
322Generic&
323// Our check is better than the usual if (this == &source),
324// but cppcheck doesn't recognize it.
325// cppcheck-suppress operatorEqToSelf
327 if (impl_ == source.impl_) {
328 return (*this);
329 }
330
331 GenericImpl* newimpl = new GenericImpl(*source.impl_);
332 delete impl_;
333 impl_ = newimpl;
334
335 return (*this);
336}
337
338namespace {
339class UnknownRdataDumper {
340public:
341 UnknownRdataDumper(ostringstream& oss) : oss_(&oss) {}
342 void operator()(const unsigned char d)
343 {
344 *oss_ << setw(2) << static_cast<unsigned int>(d);
345 }
346private:
347 ostringstream* oss_;
348};
349}
350
351string
353 ostringstream oss;
354
355 oss << "\\# " << impl_->data_.size() << " ";
356 oss.fill('0');
357 oss << right << hex;
358 for_each(impl_->data_.begin(), impl_->data_.end(), UnknownRdataDumper(oss));
359
360 return (oss.str());
361}
362
363void
365 buffer.writeData(&impl_->data_[0], impl_->data_.size());
366}
367
368void
370 renderer.writeData(&impl_->data_[0], impl_->data_.size());
371}
372
373namespace {
374inline int
375compare_internal(const GenericImpl& lhs, const GenericImpl& rhs) {
376 size_t this_len = lhs.data_.size();
377 size_t other_len = rhs.data_.size();
378 size_t len = (this_len < other_len) ? this_len : other_len;
379 int cmp;
380
381 // TODO: is there a need to check len - should we just assert?
382 // (Depends if it is possible for rdata to have zero length)
383 if ((len != 0) &&
384 ((cmp = memcmp(&lhs.data_[0], &rhs.data_[0], len)) != 0)) {
385 return (cmp);
386 } else {
387 return ((this_len == other_len) ? 0 :
388 (this_len < other_len) ? -1 : 1);
389 }
390}
391}
392
393int
394Generic::compare(const Rdata& other) const {
395 const Generic& other_rdata = dynamic_cast<const Generic&>(other);
396
397 return (compare_internal(*impl_, *other_rdata.impl_));
398}
399
400std::ostream&
401operator<<(std::ostream& os, const Generic& rdata) {
402 return (os << rdata.toText());
403}
404} // end of namespace generic
405
406} // end of namespace rdata
407}
408}
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the internal buffer of the renderer object.
Exception thrown from a wrapper version of MasterLexer::getNextToken() for non fatal errors.
Definition: master_lexer.h:320
Tokenizer for parsing DNS master files.
Definition: master_lexer.h:301
void ungetToken()
Return the last token back to the lexer.
bool pushSource(const char *filename, std::string *error=NULL)
Open a file and make it the current input source of MasterLexer.
std::string getSourceName() const
Return the name of the current input source name.
const MasterToken & getNextToken(Options options=NONE)
Parse and return another token from the input.
size_t getSourceLine() const
Return the input source line number.
Set of issue callbacks for a loader.
void error(const std::string &source_name, size_t source_line, const std::string &reason) const
Call callback for serious errors.
void warning(const std::string &source_name, size_t source_line, const std::string &reason) const
Call callback for potential problems.
Options
Options how the parsing should work.
Definition: master_loader.h:39
Tokens for MasterLexer.
Definition: master_lexer.h:39
uint32_t getNumber() const
Return the value of a string-variant token as a string object.
Definition: master_lexer.h:218
std::string getString() const
Return the value of a string-variant token as a string object.
Definition: master_lexer.h:183
@ ERROR
Error detected in getting a token.
Definition: master_lexer.h:59
@ NUMBER
A decimal number (unsigned 32-bit)
Definition: master_lexer.h:58
@ END_OF_LINE
End of line detected.
Definition: master_lexer.h:48
@ STRING
A single string.
Definition: master_lexer.h:56
@ QSTRING
A single string quoted by double-quotes (").
Definition: master_lexer.h:57
@ END_OF_FILE
End of file detected.
Definition: master_lexer.h:49
Type getType() const
Return the token type.
Definition: master_lexer.h:157
std::string getErrorText() const
Return a textual description of the error of a error type token.
The Name class encapsulates DNS names.
Definition: name.h:223
uint8_t at(size_t pos) const
Provides one-byte name data in wire format at the specified position.
Definition: name.h:346
size_t getLength() const
Gets the length of the Name in its wire format.
Definition: name.h:360
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:98
rdata::RdataPtr createRdata(const RRType &rrtype, const RRClass &rrclass, const std::string &rdata_string)
Create RDATA of a given pair of RR type and class from a string.
static RRParamRegistry & getRegistry()
Return the singleton instance of RRParamRegistry.
The RRType class encapsulates DNS resource record types.
Definition: rrtype.h:106
A standard DNS module exception that is thrown if RDATA parser encounters an invalid or inconsistent ...
Definition: rdata.h:37
A standard DNS module exception that is thrown if RDATA parser fails to recognize a given textual rep...
Definition: rdata.h:47
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
Definition: rdata.h:123
virtual void toWire(isc::util::OutputBuffer &buffer) const =0
Render the Rdata in the wire format into a buffer.
virtual uint16_t getLength() const
Get the wire format length of an Rdata.
Definition: rdata.cc:45
The generic::Generic class represents generic "unknown" RDATA.
Definition: rdata.h:249
virtual ~Generic()
The destructor.
Definition: rdata.cc:314
Generic & operator=(const Generic &source)
The assignment operator.
Definition: rdata.cc:326
Generic(const std::string &rdata_string)
Constructor from a string.
Definition: rdata.cc:280
virtual std::string toText() const
Convert an generic::Generic object to a string.
Definition: rdata.cc:352
virtual void toWire(isc::util::OutputBuffer &buffer) const
Render the generic::Generic in the wire format into a buffer.
Definition: rdata.cc:364
virtual int compare(const Rdata &other) const
Compare two instances of generic::Generic objects.
Definition: rdata.cc:394
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
size_t getPosition() const
Return the current read position.
Definition: buffer.h:102
void readData(void *data, size_t len)
Read data of the specified length from the buffer and copy it to the caller supplied buffer.
Definition: buffer.h:186
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
@ error
Definition: db_log.h:116
std::ostream & operator<<(std::ostream &os, const Generic &rdata)
Insert the name as a string into stream.
Definition: rdata.cc:401
int compareNames(const Name &n1, const Name &n2)
Gives relative ordering of two names in terms of DNSSEC RDATA ordering.
Definition: rdata.cc:181
RdataPtr createRdata(const RRType &rrtype, const RRClass &rrclass, const std::string &rdata_string)
Create RDATA of a given pair of RR type and class from a string.
Definition: rdata.cc:56
const size_t MAX_RDLENGTH
Possible maximum length of RDATA, which is the maximum unsigned 16 bit value.
Definition: rdata.h:76
boost::shared_ptr< Rdata > RdataPtr
The RdataPtr type is a pointer-like type, pointing to an object of some concrete derived class of Rda...
void decodeHex(const string &input, vector< uint8_t > &result)
Decode a text encoded in the base16 ('hex') format into the original data.
Definition: base_n.cc:488
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
GenericImpl(const vector< uint8_t > &data)
Definition: rdata.cc:201