Kea 2.5.9
rrparamregistry.cc
Go to the documentation of this file.
1// Copyright (C) 2010-2024 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
11#include <dns/rrparamregistry.h>
12#include <dns/rrclass.h>
13#include <dns/rrtype.h>
14#include <dns/rdata.h>
15#include <dns/rdataclass.h>
16
17#include <cassert>
18#include <algorithm>
19#include <cctype>
20#include <functional>
21#include <map>
22#include <stdint.h>
23#include <string>
24#include <sstream>
25#include <utility>
26#include <boost/shared_ptr.hpp>
27
28using namespace isc::util;
29using namespace isc::dns::rdata;
30
31using namespace std;
32
33namespace isc {
34namespace dns {
35
36namespace {
42bool
43CICharLess(char c1, char c2) {
44 return (tolower(static_cast<unsigned char>(c1)) <
45 tolower(static_cast<unsigned char>(c2)));
46}
47
48struct CIStringLess {
49 bool operator()(const string& s1, const string& s2) const {
50 return (lexicographical_compare(s1.begin(), s1.end(),
51 s2.begin(), s2.end(), CICharLess));
52 }
53};
54
55struct RRTypeParam {
56 RRTypeParam(const string& code_string, uint16_t code) :
57 code_string_(code_string), code_(code) {}
59 uint16_t code_;
60
62 static const unsigned int MAX_CODE = 0xffff;
63 static const string& UNKNOWN_PREFIX();
64 static size_t UNKNOWN_PREFIXLEN();
65 static const string& UNKNOWN_MAX();
66 static size_t UNKNOWN_MAXLEN();
67};
68
69typedef boost::shared_ptr<RRTypeParam> RRTypeParamPtr;
70typedef map<string, RRTypeParamPtr, CIStringLess> StrRRTypeMap;
71typedef map<uint16_t, RRTypeParamPtr> CodeRRTypeMap;
72
73inline const string&
74RRTypeParam::UNKNOWN_PREFIX() {
75 static const string p("TYPE");
76 return (p);
77}
78
79inline size_t
80RRTypeParam::UNKNOWN_PREFIXLEN() {
81 static size_t plen = UNKNOWN_PREFIX().size();
82 return (plen);
83}
84
85inline const string&
86RRTypeParam::UNKNOWN_MAX() {
87 static const string p("TYPE65535");
88 return (p);
89}
90
91inline size_t
92RRTypeParam::UNKNOWN_MAXLEN() {
93 static size_t plen = UNKNOWN_MAX().size();
94 return (plen);
95}
96
97struct RRClassParam {
98 RRClassParam(const string& code_string, uint16_t code) :
99 code_string_(code_string), code_(code) {}
100 string code_string_;
101 uint16_t code_;
102
104 static const unsigned int MAX_CODE = 0xffff;
105 static const string& UNKNOWN_PREFIX();
106 static size_t UNKNOWN_PREFIXLEN();
107 static const string& UNKNOWN_MAX();
108 static size_t UNKNOWN_MAXLEN();
109};
110
111typedef boost::shared_ptr<RRClassParam> RRClassParamPtr;
112typedef map<string, RRClassParamPtr, CIStringLess> StrRRClassMap;
113typedef map<uint16_t, RRClassParamPtr> CodeRRClassMap;
114
115inline const string&
116RRClassParam::UNKNOWN_PREFIX() {
117 static const string p("CLASS");
118 return (p);
119}
120
121inline size_t
122RRClassParam::UNKNOWN_PREFIXLEN() {
123 static size_t plen = UNKNOWN_PREFIX().size();
124 return (plen);
125}
126
127inline const string&
128RRClassParam::UNKNOWN_MAX() {
129 static const string p("CLASS65535");
130 return (p);
131}
132
133inline size_t
134RRClassParam::UNKNOWN_MAXLEN() {
135 static size_t plen = UNKNOWN_MAX().size();
136 return (plen);
137}
138} // end of anonymous namespace
139
148typedef pair<RRType, RRClass> RRTypeClass;
149typedef map<RRTypeClass, RdataFactoryPtr> RdataFactoryMap;
150typedef map<RRType, RdataFactoryPtr> GenericRdataFactoryMap;
151
152template <typename T>
154public:
155 virtual RdataPtr create(const string& rdata_str) const {
156 return (RdataPtr(new T(rdata_str)));
157 }
158
159 virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const {
160 return (RdataPtr(new T(buffer, rdata_len)));
161 }
162
163 virtual RdataPtr create(const Rdata& source) const {
164 return (RdataPtr(new T(dynamic_cast<const T&>(source))));
165 }
166
167 virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
168 MasterLoader::Options options,
169 MasterLoaderCallbacks& callbacks) const {
170 return (RdataPtr(new T(lexer, origin, options, callbacks)));
171 }
172};
173
183 StrRRTypeMap str2typemap;
185 CodeRRTypeMap code2typemap;
187 StrRRClassMap str2classmap;
189 CodeRRClassMap code2classmap;
192};
193
194RRParamRegistry::RRParamRegistry() : impl_(new RRParamRegistryImpl()) {
195
196 // set up parameters for well-known RRs
197 try {
198 // ANY class well known RR types.
199 add("TSIG", 250, "ANY", 255, RdataFactoryPtr(new RdataFactory<any::TSIG>()));
200 // CH class well known RR types.
201 add("A", 1, "CH", 3, RdataFactoryPtr(new RdataFactory<ch::A>()));
202 // IN class well known RR types.
203 add("A", 1, "IN", 1, RdataFactoryPtr(new RdataFactory<in::A>()));
204;
205 add("NS", 2, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::NS>()));
206 add("SOA", 6, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::SOA>()));
207 add("PTR", 12, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::PTR>()));
208 add("TXT", 16, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::TXT>()));
209 add("AAAA", 28, "IN", 1, RdataFactoryPtr(new RdataFactory<in::AAAA>()));
210 add("OPT", 41, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::OPT>()));
211 add("RRSIG", 46, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::RRSIG>()));
212 add("DHCID", 49, "IN", 1, RdataFactoryPtr(new RdataFactory<in::DHCID>()));
213 add("TKEY", 249, "IN", 1, RdataFactoryPtr(new RdataFactory<generic::TKEY>()));
214 // Generic well known RR types.
215 add("NS", 2, RdataFactoryPtr(new RdataFactory<generic::NS>()));
216 add("SOA", 6, RdataFactoryPtr(new RdataFactory<generic::SOA>()));
217 add("PTR", 12, RdataFactoryPtr(new RdataFactory<generic::PTR>()));
218 add("TXT", 16, RdataFactoryPtr(new RdataFactory<generic::TXT>()));
219 add("OPT", 41, RdataFactoryPtr(new RdataFactory<generic::OPT>()));
220 add("RRSIG", 46, RdataFactoryPtr(new RdataFactory<generic::RRSIG>()));
221 add("TKEY", 249, RdataFactoryPtr(new RdataFactory<generic::TKEY>()));
222 // Meta and Not supported RR classes.
223 addClass("HS", 4);
224 addClass("NONE", 254);
225 // Meta and non-implemented RR types
226 addType("MD", 3);
227 addType("MF", 4);
228 addType("CNAME", 5);
229 addType("MB", 7);
230 addType("MG", 8);
231 addType("MR", 9);
232 addType("NULL", 10);
233 addType("WKS", 11);
234 addType("HINFO", 13);
235 addType("MINFO", 14);
236 addType("MX", 15);
237 addType("RP", 17);
238 addType("AFSDB", 18);
239 addType("X25", 19);
240 addType("ISDN", 20);
241 addType("RT", 21);
242 addType("NSAP", 22);
243 addType("NSAP-PTR", 23);
244 addType("SIG", 24);
245 addType("KEY", 25);
246 addType("PX", 26);
247 addType("GPOS", 27);
248 addType("LOC", 29);
249 addType("NXT", 30);
250 addType("EID", 31);
251 addType("NIMLOC", 32);
252 addType("SRV", 33);
253 addType("ATMA", 34);
254 addType("NAPTR", 35);
255 addType("KX", 36);
256 addType("CERT", 37);
257 addType("A6", 38);
258 addType("DNAME", 39);
259 addType("SINK", 40);
260 addType("APL", 42);
261 addType("DS", 43);
262 addType("SSHFP", 44);
263 addType("IPSECKEY", 45);
264 addType("NSEC", 47);
265 addType("DNSKEY", 48);
266 addType("NSEC3", 50);
267 addType("NSEC3PARAM", 51);
268 addType("TLSA", 52);
269 addType("SMIMEA", 53);
270 // Unassigned 54
271 addType("HIP", 55);
272 addType("NINFO", 56);
273 addType("RKEY", 57);
274 addType("TALINK", 58);
275 addType("CDS", 59);
276 addType("CDNSKEY", 60);
277 addType("OPENPGPKEY", 61);
278 addType("CSYNC", 62);
279 addType("ZONEMD", 63);
280 addType("SVCB", 64);
281 addType("HTTPS", 65);
282 // Unassigned 66-98
283 addType("SPF", 99);
284 addType("UINFO", 100);
285 addType("UID", 101);
286 addType("GID", 102);
287 addType("UNSPEC", 103);
288 addType("NID", 104);
289 addType("L32", 105);
290 addType("L64", 106);
291 addType("LP", 107);
292 addType("EUI48", 108);
293 addType("EUI64", 109);
294 // Unassigned 110-248
295 addType("IXFR", 251);
296 addType("AXFR", 252);
297 addType("MAILB", 253);
298 addType("MAILA", 254);
299 addType("ANY", 255); // also known as "*"
300 addType("URI", 256);
301 addType("CAA", 257);
302 addType("AVC", 258);
303 addType("DOA", 259);
304 addType("AMTRELAY", 260);
305 addType("RESINFO", 261);
306 // Unassigned 262-32767
307 addType("TA", 32768);
308 addType("DLV", 32769);
309 } catch (...) {
310 throw;
311 }
312}
313
314RRParamRegistry::~RRParamRegistry() {
315}
316
319 static RRParamRegistry registry;
320
321 return (registry);
322}
323
324void
325RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
326 RdataFactoryPtr rdata_factory) {
327 bool type_added = false;
328 try {
329 type_added = addType(typecode_string, typecode);
330 impl_->genericrdata_factories.insert(pair<RRType, RdataFactoryPtr>(
331 RRType(typecode),
332 rdata_factory));
333 } catch (...) {
334 if (type_added) {
335 removeType(typecode);
336 }
337 throw;
338 }
339}
340
341void
342RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
343 const std::string& classcode_string, uint16_t classcode,
344 RdataFactoryPtr rdata_factory) {
345 // Rollback logic on failure is complicated. If adding the new type or
346 // class fails, we should revert to the original state, cleaning up
347 // intermediate state. But we need to make sure that we don't remove
348 // existing data. addType()/addClass() will simply ignore an attempt to
349 // add the same data, so the cleanup should be performed only when we add
350 // something new but we fail in other part of the process.
351 bool type_added = false;
352 bool class_added = false;
353
354 try {
355 type_added = addType(typecode_string, typecode);
356 class_added = addClass(classcode_string, classcode);
357 impl_->rdata_factories.insert(pair<RRTypeClass, RdataFactoryPtr>(
358 RRTypeClass(RRType(typecode),
359 RRClass(classcode)),
360 rdata_factory));
361 } catch (...) {
362 if (type_added) {
363 removeType(typecode);
364 }
365 if (class_added) {
366 removeClass(classcode);
367 }
368 throw;
369 }
370}
371
372bool
374 const RRClass& rrclass) {
375 RdataFactoryMap::iterator found =
376 impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
377 if (found != impl_->rdata_factories.end()) {
378 impl_->rdata_factories.erase(found);
379 return (true);
380 }
381
382 return (false);
383}
384
385bool
387 GenericRdataFactoryMap::iterator found =
388 impl_->genericrdata_factories.find(rrtype);
389 if (found != impl_->genericrdata_factories.end()) {
390 impl_->genericrdata_factories.erase(found);
391 return (true);
392 }
393
394 return (false);
395}
396
397namespace {
404bool CICharEqual(char c1, char c2) {
405 return (tolower(static_cast<unsigned char>(c1)) ==
406 tolower(static_cast<unsigned char>(c2)));
407}
408
409bool
410caseStringEqual(const string& s1, const string& s2, size_t n) {
411 isc_throw_assert(s1.size() >= n && s2.size() >= n);
412
413 return (mismatch(s1.begin(), s1.begin() + n, s2.begin(), CICharEqual).first
414 == s1.begin() + n);
415}
416
427template <typename PT, typename MC, typename MS, typename ET>
428inline bool
429addParam(const string& code_string, uint16_t code, MC& codemap, MS& stringmap) {
430 // Duplicate type check
431 typename MC::const_iterator found = codemap.find(code);
432 if (found != codemap.end()) {
433 if (found->second->code_string_ != code_string) {
434 isc_throw(ET, "Duplicate RR parameter registration");
435 }
436 return (false);
437 }
438
439 typedef boost::shared_ptr<PT> ParamPtr;
440 typedef pair<string, ParamPtr> StrParamPair;
441 typedef pair<uint16_t, ParamPtr> CodeParamPair;
442 ParamPtr param = ParamPtr(new PT(code_string, code));
443 try {
444 stringmap.insert(StrParamPair(code_string, param));
445 codemap.insert(CodeParamPair(code, param));
446 } catch (...) {
447 // Rollback to the previous state: not all of the erase operations will
448 // find the entry, but we don't care.
449 stringmap.erase(code_string);
450 codemap.erase(code);
451 throw;
452 }
453
454 return (true);
455}
456
457template <typename MC, typename MS>
458inline bool
459removeParam(uint16_t code, MC& codemap, MS& stringmap) {
460 typename MC::iterator found = codemap.find(code);
461
462 if (found != codemap.end()) {
463 size_t erased = stringmap.erase(found->second->code_string_);
464 // We must have a corresponding entry of the str2 map exists
465 isc_throw_assert(erased == 1);
466
467 codemap.erase(found);
468
469 return (true);
470 }
471
472 return (false);
473}
474
475template <typename PT, typename MS>
476inline bool
477textToCode(const string& code_str, MS& stringmap, uint16_t& ret_code) {
478 typename MS::const_iterator found;
479
480 found = stringmap.find(code_str);
481 if (found != stringmap.end()) {
482 ret_code = found->second->code_;
483 return (true);
484 }
485
486 size_t l = code_str.size();
487 if (l > PT::UNKNOWN_PREFIXLEN() &&
488 l <= PT::UNKNOWN_MAXLEN() &&
489 caseStringEqual(code_str, PT::UNKNOWN_PREFIX(),
490 PT::UNKNOWN_PREFIXLEN())) {
491 unsigned int code;
492 istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN(),
493 l - PT::UNKNOWN_PREFIXLEN()));
494 iss >> dec >> code;
495 if (iss.rdstate() == ios::eofbit && code <= PT::MAX_CODE) {
496 ret_code = code;
497 return (true);
498 }
499 }
500
501 return (false);
502}
503
504template <typename PT, typename MC>
505inline string
506codeToText(uint16_t code, MC& codemap) {
507 typename MC::const_iterator found;
508
509 found = codemap.find(code);
510 if (found != codemap.end()) {
511 return (found->second->code_string_);
512 }
513
514 ostringstream ss;
515 ss << code;
516 return (PT::UNKNOWN_PREFIX() + ss.str());
517}
518}
519
520bool
521RRParamRegistry::addType(const string& type_string, uint16_t code) {
522 return (addParam<RRTypeParam, CodeRRTypeMap, StrRRTypeMap, RRTypeExists>
523 (type_string, code, impl_->code2typemap, impl_->str2typemap));
524}
525
526bool
528 return (removeParam<CodeRRTypeMap, StrRRTypeMap>(code, impl_->code2typemap,
529 impl_->str2typemap));
530}
531
532bool
533RRParamRegistry::textToTypeCode(const string& type_string,
534 uint16_t& type_code) const {
535 return (textToCode<RRTypeParam, StrRRTypeMap>
536 (type_string, impl_->str2typemap, type_code));
537}
538
539string
541 return (codeToText<RRTypeParam, CodeRRTypeMap>(code, impl_->code2typemap));
542}
543
544bool
545RRParamRegistry::addClass(const string& class_string, uint16_t code) {
546 return (addParam<RRClassParam, CodeRRClassMap, StrRRClassMap, RRClassExists>
547 (class_string, code, impl_->code2classmap, impl_->str2classmap));
548}
549
550bool
552 return (removeParam<CodeRRClassMap, StrRRClassMap>(code,
553 impl_->code2classmap,
554 impl_->str2classmap));
555}
556
557bool
558RRParamRegistry::textToClassCode(const string& class_string,
559 uint16_t& class_code) const {
560 return (textToCode<RRClassParam, StrRRClassMap>
561 (class_string, impl_->str2classmap, class_code));
562}
563
564string
566 return (codeToText<RRClassParam, CodeRRClassMap>(code,
567 impl_->code2classmap));
568}
569
570namespace {
571inline const AbstractRdataFactory*
572findRdataFactory(RRParamRegistryImpl* reg_impl,
573 const RRType& rrtype, const RRClass& rrclass) {
574 RdataFactoryMap::const_iterator found;
575 found = reg_impl->rdata_factories.find(RRTypeClass(rrtype, rrclass));
576 if (found != reg_impl->rdata_factories.end()) {
577 return (found->second.get());
578 }
579
580 GenericRdataFactoryMap::const_iterator genfound =
581 reg_impl->genericrdata_factories.find(rrtype);
582 if (genfound != reg_impl->genericrdata_factories.end()) {
583 return (genfound->second.get());
584 }
585
586 return (0);
587}
588}
589
591RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
592 const std::string& rdata_string) {
593 // If the text indicates that it's rdata of an "unknown" type (beginning
594 // with '\# n'), parse it that way. (TBD)
595
596 const AbstractRdataFactory* factory =
597 findRdataFactory(impl_.get(), rrtype, rrclass);
598 if (factory) {
599 return (factory->create(rdata_string));
600 }
601
602 return (RdataPtr(new generic::Generic(rdata_string)));
603}
604
606RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
607 InputBuffer& buffer, size_t rdata_len) {
608 const AbstractRdataFactory* factory =
609 findRdataFactory(impl_.get(), rrtype, rrclass);
610 if (factory) {
611 return (factory->create(buffer, rdata_len));
612 }
613
614 return (RdataPtr(new generic::Generic(buffer, rdata_len)));
615}
616
618RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
619 const Rdata& source) {
620 const AbstractRdataFactory* factory =
621 findRdataFactory(impl_.get(), rrtype, rrclass);
622 if (factory) {
623 return (factory->create(source));
624 }
625
627 dynamic_cast<const generic::Generic&>(source))));
628}
629
631RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
632 MasterLexer& lexer, const Name* name,
633 MasterLoader::Options options,
634 MasterLoaderCallbacks& callbacks) {
635 const AbstractRdataFactory* factory =
636 findRdataFactory(impl_.get(), rrtype, rrclass);
637 if (factory) {
638 return (factory->create(lexer, name, options, callbacks));
639 }
640
641 return (RdataPtr(new generic::Generic(lexer, name, options, callbacks)));
642}
643}
644}
Tokenizer for parsing DNS master files.
Definition: master_lexer.h:303
Set of issue callbacks for a loader.
Options
Options how the parsing should work.
Definition: master_loader.h:42
The Name class encapsulates DNS names.
Definition: name.h:219
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:89
The RRParamRegistry class represents a registry of parameters to manipulate DNS resource records (RRs...
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.
bool removeType(uint16_t type_code)
Remove mappings between RR type code and textual representation for a given type.
bool textToTypeCode(const std::string &type_string, uint16_t &type_code) const
Convert a textual representation of an RR type to the corresponding 16-bit integer code.
bool textToClassCode(const std::string &class_string, uint16_t &class_code) const
Convert a textual representation of an RR class to the corresponding 16-bit integer code.
std::string codeToClassText(uint16_t class_code) const
Convert class code into its textual representation.
std::string codeToTypeText(uint16_t type_code) const
Convert type code into its textual representation.
bool addClass(const std::string &class_string, uint16_t class_code)
Add mappings between RR class code and textual representation.
static RRParamRegistry & getRegistry()
Return the singleton instance of RRParamRegistry.
bool addType(const std::string &type_string, uint16_t type_code)
Add mappings between RR type code and textual representation.
bool removeRdataFactory(const RRType &rrtype, const RRClass &rrclass)
Remove registered RDATA factory for the given pair of RRType and RRClass.
void add(const std::string &type_string, uint16_t type_code, const std::string &class_string, uint16_t class_code, rdata::RdataFactoryPtr rdata_factory)
Add a set of parameters for a pair of RR type and class.
bool removeClass(uint16_t class_code)
Remove mappings between RR class code and textual representation for a given class.
The RRType class encapsulates DNS resource record types.
Definition: rrtype.h:96
virtual RdataPtr create(const string &rdata_str) const
Create RDATA from a string.
virtual RdataPtr create(InputBuffer &buffer, size_t rdata_len) const
Create RDATA from wire-format data.
virtual RdataPtr create(MasterLexer &lexer, const Name *origin, MasterLoader::Options options, MasterLoaderCallbacks &callbacks) const
Create RDATA using MasterLexer.
virtual RdataPtr create(const Rdata &source) const
Create RDATA from another Rdata object of the same type.
The AbstractRdataFactory class is an abstract base class to encapsulate a set of Rdata factory method...
virtual RdataPtr create(const std::string &rdata_str) const =0
Create RDATA from a string.
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
Definition: rdata.h:120
The generic::Generic class represents generic "unknown" RDATA.
Definition: rdata.h:246
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition: isc_assert.h:18
boost::shared_ptr< AbstractRdataFactory > RdataFactoryPtr
The RdataFactoryPtr type is a pointer-like type, pointing to an object of some concrete derived class...
boost::shared_ptr< Rdata > RdataPtr
The RdataPtr type is a pointer-like type, pointing to an object of some concrete derived class of Rda...
pair< RRType, RRClass > RRTypeClass
Note: the element ordering in the type/class pair is intentional.
map< RRTypeClass, RdataFactoryPtr > RdataFactoryMap
map< RRType, RdataFactoryPtr > GenericRdataFactoryMap
Defines the logger used by the top-level component of kea-lfc.
string code_string_
uint16_t code_
The RRParamRegistryImpl class is the actual implementation of RRParamRegistry.
CodeRRTypeMap code2typemap
Mappings from textual representations of RR types to integer codes.
StrRRClassMap str2classmap
Mappings from RR class codes to textual representations.
CodeRRClassMap code2classmap
Mappings from textual representations of RR classes to integer codes.
GenericRdataFactoryMap genericrdata_factories
StrRRTypeMap str2typemap
Mappings from RR type codes to textual representations.