1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
|
// Copyright (C) 2010-2022 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <cassert>
#include <algorithm>
#include <cctype>
#include <functional>
#include <map>
#include <string>
#include <sstream>
#include <utility>
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include <exceptions/exceptions.h>
#include <dns/rrparamregistry.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
using namespace std;
using namespace isc::util;
using namespace isc::dns::rdata;
namespace isc {
namespace dns {
namespace {
///
/// The following function and class are a helper to define case-insensitive
/// equivalence relationship on strings. They are used in the mapping
/// containers below.
///
bool
CICharLess(char c1, char c2) {
return (tolower(static_cast<unsigned char>(c1)) <
tolower(static_cast<unsigned char>(c2)));
}
struct CIStringLess {
bool operator()(const string& s1, const string& s2) const
{
return (lexicographical_compare(s1.begin(), s1.end(),
s2.begin(), s2.end(), CICharLess));
}
};
struct RRTypeParam {
RRTypeParam(const string& code_string, uint16_t code) :
code_string_(code_string), code_(code) {}
string code_string_;
uint16_t code_;
/// magic constants
static const unsigned int MAX_CODE = 0xffff;
static const string& UNKNOWN_PREFIX();
static size_t UNKNOWN_PREFIXLEN();
static const string& UNKNOWN_MAX();
static size_t UNKNOWN_MAXLEN();
};
typedef boost::shared_ptr<RRTypeParam> RRTypeParamPtr;
typedef map<string, RRTypeParamPtr, CIStringLess> StrRRTypeMap;
typedef map<uint16_t, RRTypeParamPtr> CodeRRTypeMap;
inline const string&
RRTypeParam::UNKNOWN_PREFIX() {
static const string p("TYPE");
return (p);
}
inline size_t
RRTypeParam::UNKNOWN_PREFIXLEN() {
static size_t plen = UNKNOWN_PREFIX().size();
return (plen);
}
inline const string&
RRTypeParam::UNKNOWN_MAX() {
static const string p("TYPE65535");
return (p);
}
inline size_t
RRTypeParam::UNKNOWN_MAXLEN() {
static size_t plen = UNKNOWN_MAX().size();
return (plen);
}
struct RRClassParam {
RRClassParam(const string& code_string, uint16_t code) :
code_string_(code_string), code_(code) {}
string code_string_;
uint16_t code_;
/// magic constants
static const unsigned int MAX_CODE = 0xffff;
static const string& UNKNOWN_PREFIX();
static size_t UNKNOWN_PREFIXLEN();
static const string& UNKNOWN_MAX();
static size_t UNKNOWN_MAXLEN();
};
typedef boost::shared_ptr<RRClassParam> RRClassParamPtr;
typedef map<string, RRClassParamPtr, CIStringLess> StrRRClassMap;
typedef map<uint16_t, RRClassParamPtr> CodeRRClassMap;
inline const string&
RRClassParam::UNKNOWN_PREFIX() {
static const string p("CLASS");
return (p);
}
inline size_t
RRClassParam::UNKNOWN_PREFIXLEN() {
static size_t plen = UNKNOWN_PREFIX().size();
return (plen);
}
inline const string&
RRClassParam::UNKNOWN_MAX() {
static const string p("CLASS65535");
return (p);
}
inline size_t
RRClassParam::UNKNOWN_MAXLEN() {
static size_t plen = UNKNOWN_MAX().size();
return (plen);
}
} // end of anonymous namespace
/// Note: the element ordering in the type/class pair is intentional.
/// The standard library will perform inequality comparison (i.e, '<')
/// in the way that the second elements (RRClass) are compared only when
/// the first elements are equivalent.
/// In practice, when we compare two pairs of RRType and RRClass, RRClass
/// would be the same (and, in particular, be class IN) in the majority of
/// cases. So this comparison ordering should be more efficient in common
/// cases.
typedef pair<RRType, RRClass> RRTypeClass;
typedef map<RRTypeClass, RdataFactoryPtr> RdataFactoryMap;
typedef map<RRType, RdataFactoryPtr> GenericRdataFactoryMap;
template <typename T>
class RdataFactory : public AbstractRdataFactory {
public:
virtual RdataPtr create(const string& rdata_str) const
{
return (RdataPtr(new T(rdata_str)));
}
virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const
{
return (RdataPtr(new T(buffer, rdata_len)));
}
virtual RdataPtr create(const Rdata& source) const
{
return (RdataPtr(new T(dynamic_cast<const T&>(source))));
}
virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
MasterLoader::Options options,
MasterLoaderCallbacks& callbacks) const
{
return (RdataPtr(new T(lexer, origin, options, callbacks)));
}
};
///
/// \brief The \c RRParamRegistryImpl class is the actual implementation of
/// \c RRParamRegistry.
///
/// The implementation is hidden from applications. We can refer to specific
/// members of this class only within the implementation source file.
///
struct RRParamRegistryImpl {
/// Mappings from RR type codes to textual representations.
StrRRTypeMap str2typemap;
/// Mappings from textual representations of RR types to integer codes.
CodeRRTypeMap code2typemap;
/// Mappings from RR class codes to textual representations.
StrRRClassMap str2classmap;
/// Mappings from textual representations of RR classes to integer codes.
CodeRRClassMap code2classmap;
RdataFactoryMap rdata_factories;
GenericRdataFactoryMap genericrdata_factories;
};
RRParamRegistry::RRParamRegistry() {
impl_ = new RRParamRegistryImpl;
// set up parameters for well-known RRs
try {
// BEGIN_WELL_KNOWN_PARAMS
// END_WELL_KNOWN_PARAMS
} catch (...) {
delete impl_;
throw;
}
}
RRParamRegistry::~RRParamRegistry() {
delete impl_;
}
RRParamRegistry&
RRParamRegistry::getRegistry() {
static RRParamRegistry registry;
return (registry);
}
void
RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
RdataFactoryPtr rdata_factory)
{
bool type_added = false;
try {
type_added = addType(typecode_string, typecode);
impl_->genericrdata_factories.insert(pair<RRType, RdataFactoryPtr>(
RRType(typecode),
rdata_factory));
} catch (...) {
if (type_added) {
removeType(typecode);
}
throw;
}
}
void
RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
const std::string& classcode_string, uint16_t classcode,
RdataFactoryPtr rdata_factory)
{
// Rollback logic on failure is complicated. If adding the new type or
// class fails, we should revert to the original state, cleaning up
// intermediate state. But we need to make sure that we don't remove
// existing data. addType()/addClass() will simply ignore an attempt to
// add the same data, so the cleanup should be performed only when we add
// something new but we fail in other part of the process.
bool type_added = false;
bool class_added = false;
try {
type_added = addType(typecode_string, typecode);
class_added = addClass(classcode_string, classcode);
impl_->rdata_factories.insert(pair<RRTypeClass, RdataFactoryPtr>(
RRTypeClass(RRType(typecode),
RRClass(classcode)),
rdata_factory));
} catch (...) {
if (type_added) {
removeType(typecode);
}
if (class_added) {
removeClass(classcode);
}
throw;
}
}
bool
RRParamRegistry::removeRdataFactory(const RRType& rrtype,
const RRClass& rrclass)
{
RdataFactoryMap::iterator found =
impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
if (found != impl_->rdata_factories.end()) {
impl_->rdata_factories.erase(found);
return (true);
}
return (false);
}
bool
RRParamRegistry::removeRdataFactory(const RRType& rrtype) {
GenericRdataFactoryMap::iterator found =
impl_->genericrdata_factories.find(rrtype);
if (found != impl_->genericrdata_factories.end()) {
impl_->genericrdata_factories.erase(found);
return (true);
}
return (false);
}
namespace {
///
/// These are helper functions to implement case-insensitive string comparison.
/// This could be simplified using strncasecmp(), but unfortunately it's not
/// included in <cstring>. To be as much as portable within the C++ standard
/// we take the "in house" approach here.
///
bool CICharEqual(char c1, char c2) {
return (tolower(static_cast<unsigned char>(c1)) ==
tolower(static_cast<unsigned char>(c2)));
}
bool
caseStringEqual(const string& s1, const string& s2, size_t n) {
assert(s1.size() >= n && s2.size() >= n);
return (mismatch(s1.begin(), s1.begin() + n, s2.begin(), CICharEqual).first
== s1.begin() + n);
}
/// Code logic for RRTypes and RRClasses is mostly common except (C++) type and
/// member names. So we define type-independent templates to describe the
/// common logic and let concrete classes use it to avoid code duplicates.
/// The following summarize template parameters used in the set of template
/// functions:
/// PT: parameter type, either RRTypeParam or RRClassParam
/// MC: type of mapping class from code: either CodeRRTypeMap or CodeRRClassMap
/// MS: type of mapping class from string: either StrRRTypeMap or StrRRClassMap
/// ET: exception type for error handling: either InvalidRRType or
/// InvalidRRClass
template <typename PT, typename MC, typename MS, typename ET>
inline bool
addParam(const string& code_string, uint16_t code, MC& codemap, MS& stringmap)
{
// Duplicate type check
typename MC::const_iterator found = codemap.find(code);
if (found != codemap.end()) {
if (found->second->code_string_ != code_string) {
isc_throw(ET, "Duplicate RR parameter registration");
}
return (false);
}
typedef boost::shared_ptr<PT> ParamPtr;
typedef pair<string, ParamPtr> StrParamPair;
typedef pair<uint16_t, ParamPtr> CodeParamPair;
ParamPtr param = ParamPtr(new PT(code_string, code));
try {
stringmap.insert(StrParamPair(code_string, param));
codemap.insert(CodeParamPair(code, param));
} catch (...) {
// Rollback to the previous state: not all of the erase operations will
// find the entry, but we don't care.
stringmap.erase(code_string);
codemap.erase(code);
throw;
}
return (true);
}
template <typename MC, typename MS>
inline bool
removeParam(uint16_t code, MC& codemap, MS& stringmap) {
typename MC::iterator found = codemap.find(code);
if (found != codemap.end()) {
size_t erased = stringmap.erase(found->second->code_string_);
// We must have a corresponding entry of the str2 map exists
assert(erased == 1);
codemap.erase(found);
return (true);
}
return (false);
}
template <typename PT, typename MS>
inline bool
textToCode(const string& code_str, MS& stringmap, uint16_t& ret_code) {
typename MS::const_iterator found;
found = stringmap.find(code_str);
if (found != stringmap.end()) {
ret_code = found->second->code_;
return (true);
}
size_t l = code_str.size();
if (l > PT::UNKNOWN_PREFIXLEN() &&
l <= PT::UNKNOWN_MAXLEN() &&
caseStringEqual(code_str, PT::UNKNOWN_PREFIX(),
PT::UNKNOWN_PREFIXLEN())) {
unsigned int code;
istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN(),
l - PT::UNKNOWN_PREFIXLEN()));
iss >> dec >> code;
if (iss.rdstate() == ios::eofbit && code <= PT::MAX_CODE) {
ret_code = code;
return (true);
}
}
return (false);
}
template <typename PT, typename MC>
inline string
codeToText(uint16_t code, MC& codemap) {
typename MC::const_iterator found;
found = codemap.find(code);
if (found != codemap.end()) {
return (found->second->code_string_);
}
ostringstream ss;
ss << code;
return (PT::UNKNOWN_PREFIX() + ss.str());
}
}
bool
RRParamRegistry::addType(const string& type_string, uint16_t code) {
return (addParam<RRTypeParam, CodeRRTypeMap, StrRRTypeMap, RRTypeExists>
(type_string, code, impl_->code2typemap, impl_->str2typemap));
}
bool
RRParamRegistry::removeType(uint16_t code) {
return (removeParam<CodeRRTypeMap, StrRRTypeMap>(code, impl_->code2typemap,
impl_->str2typemap));
}
bool
RRParamRegistry::textToTypeCode(const string& type_string,
uint16_t& type_code) const
{
return (textToCode<RRTypeParam, StrRRTypeMap>
(type_string, impl_->str2typemap, type_code));
}
string
RRParamRegistry::codeToTypeText(uint16_t code) const {
return (codeToText<RRTypeParam, CodeRRTypeMap>(code, impl_->code2typemap));
}
bool
RRParamRegistry::addClass(const string& class_string, uint16_t code) {
return (addParam<RRClassParam, CodeRRClassMap, StrRRClassMap, RRClassExists>
(class_string, code, impl_->code2classmap, impl_->str2classmap));
}
bool
RRParamRegistry::removeClass(uint16_t code) {
return (removeParam<CodeRRClassMap, StrRRClassMap>(code,
impl_->code2classmap,
impl_->str2classmap));
}
bool
RRParamRegistry::textToClassCode(const string& class_string,
uint16_t& class_code) const
{
return (textToCode<RRClassParam, StrRRClassMap>
(class_string, impl_->str2classmap, class_code));
}
string
RRParamRegistry::codeToClassText(uint16_t code) const {
return (codeToText<RRClassParam, CodeRRClassMap>(code,
impl_->code2classmap));
}
namespace {
inline const AbstractRdataFactory*
findRdataFactory(RRParamRegistryImpl* reg_impl,
const RRType& rrtype, const RRClass& rrclass)
{
RdataFactoryMap::const_iterator found;
found = reg_impl->rdata_factories.find(RRTypeClass(rrtype, rrclass));
if (found != reg_impl->rdata_factories.end()) {
return (found->second.get());
}
GenericRdataFactoryMap::const_iterator genfound =
reg_impl->genericrdata_factories.find(rrtype);
if (genfound != reg_impl->genericrdata_factories.end()) {
return (genfound->second.get());
}
return (NULL);
}
}
RdataPtr
RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
const std::string& rdata_string)
{
// If the text indicates that it's rdata of an "unknown" type (beginning
// with '\# n'), parse it that way. (TBD)
const AbstractRdataFactory* factory =
findRdataFactory(impl_, rrtype, rrclass);
if (factory != NULL) {
return (factory->create(rdata_string));
}
return (RdataPtr(new generic::Generic(rdata_string)));
}
RdataPtr
RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
InputBuffer& buffer, size_t rdata_len)
{
const AbstractRdataFactory* factory =
findRdataFactory(impl_, rrtype, rrclass);
if (factory != NULL) {
return (factory->create(buffer, rdata_len));
}
return (RdataPtr(new generic::Generic(buffer, rdata_len)));
}
RdataPtr
RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
const Rdata& source)
{
const AbstractRdataFactory* factory =
findRdataFactory(impl_, rrtype, rrclass);
if (factory != NULL) {
return (factory->create(source));
}
return (RdataPtr(new rdata::generic::Generic(
dynamic_cast<const generic::Generic&>(source))));
}
RdataPtr
RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
MasterLexer& lexer, const Name* name,
MasterLoader::Options options,
MasterLoaderCallbacks& callbacks)
{
const AbstractRdataFactory* factory =
findRdataFactory(impl_, rrtype, rrclass);
if (factory != NULL) {
return (factory->create(lexer, name, options, callbacks));
}
return (RdataPtr(new generic::Generic(lexer, name, options, callbacks)));
}
}
}
|