summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/rdata.h
blob: af294f0670e085825d5da850ae545962d0559181 (plain)
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
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
// Copyright (C) 2010-2024 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/.

#ifndef RDATA_H
#define RDATA_H

#include <dns/master_lexer.h>
#include <dns/master_loader.h>
#include <dns/master_loader_callbacks.h>
#include <dns/exceptions.h>
#include <util/buffer.h>

#include <boost/shared_ptr.hpp>

#include <memory>
#include <stdint.h>

namespace isc {
namespace dns {
class AbstractMessageRenderer;
class RRType;
class RRClass;
class Name;

namespace rdata {

///
/// \brief A standard DNS module exception that is thrown if RDATA parser
/// encounters an invalid or inconsistent data length.
///
class InvalidRdataLength : public DNSTextError {
public:
    InvalidRdataLength(const char* file, size_t line, const char* what) :
        DNSTextError(file, line, what) {}
};

///
/// \brief A standard DNS module exception that is thrown if RDATA parser
/// fails to recognize a given textual representation.
///
class InvalidRdataText : public DNSTextError {
public:
    InvalidRdataText(const char* file, size_t line, const char* what) :
        DNSTextError(file, line, what) {}
};

///
/// \brief A standard DNS module exception that is thrown if RDATA parser
/// encounters a character-string (as defined in RFC1035) exceeding
/// the maximum allowable length (\c MAX_CHARSTRING_LEN).
///
class CharStringTooLong : public DNSTextError {
public:
    CharStringTooLong(const char* file, size_t line, const char* what) :
        DNSTextError(file, line, what) {}
};

// Forward declaration to define RdataPtr.
class Rdata;

///
/// The \c RdataPtr type is a pointer-like type, pointing to an
/// object of some concrete derived class of \c Rdata.
///
typedef boost::shared_ptr<Rdata> RdataPtr;
typedef boost::shared_ptr<const Rdata> ConstRdataPtr;

/// \brief Possible maximum length of RDATA, which is the maximum unsigned
/// 16 bit value.
const size_t MAX_RDLENGTH = 65535;

/// \brief The maximum allowable length of character-string containing in
/// RDATA as defined in RFC1035, not including the 1-byte length field.
const unsigned int MAX_CHARSTRING_LEN = 255;

/// \brief The \c Rdata class is an abstract base class that provides
/// a set of common interfaces to manipulate concrete RDATA objects.
///
/// Generally, a separate derived class directly inherited from the base
/// \c Rdata class is defined for each well known RDATA.
/// Each of such classes will define the common logic based on the
/// corresponding protocol standard.
///
/// Since some types of RRs are class specific and the corresponding RDATA
/// may have different semantics (e.g. type A for class IN and type A for
/// class CH have different representations and semantics), we separate
/// \c Rdata derived classes for such RR types in different namespaces.
/// The namespace of types specific to a class is named the lower-cased class
/// name; for example, RDATA of class IN-specific types are defined in the
/// \c in namespace, and RDATA of class CH-specific types are defined in
/// the \c ch namespace, and so on.
/// The derived classes are named using the RR type name (upper cased) such as
/// \c A or \c AAAA.
/// Thus RDATA of type A RR for class IN and CH are defined as \c in::A and
/// \c ch::A, respectively.
/// Many other RR types are class independent; the derived \c Rdata classes
/// for such RR types are defined in the \c generic namespace.  Examples are
/// \c generic::NS and \c generic::SOA.
///
/// If applications need to refer to these derived classes, it is generally
/// recommended to prepend at least some part of the namespace because the
/// same class name can be used in different namespaces.
/// So, instead of doing
/// \code using namespace isc::dns::rdata::in;
/// A& rdata_type_a; \endcode
/// it is advisable to prepend at least \c in from the namespace:
/// \code using namespace isc::dns::rdata;
/// in::A& rdata_type_a; \endcode
///
/// In many cases, however, an application doesn't have to care about such
/// derived classes.
/// For instance, to parse an incoming DNS message an application wouldn't
/// have to perform type specific operation unless the application is
/// specifically concerned about a particular type.
/// So, this API generally handles \c Rdata in a polymorphic way through
/// a pointer or reference to this base abstract class.
class Rdata {
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are intentionally
    /// defined as private.  Concrete classes should generally specialize their
    /// own versions of these methods.
    //@{
protected:
    /// The default constructor.
    ///
    /// This is intentionally defined as \c protected as this base class should
    /// never be instantiated (except as part of a derived class).  In many
    /// cases, the derived class wouldn't define a public default constructor
    /// either, because an \c Rdata object without concrete data isn't
    /// meaningful.
    Rdata() {}
private:
    Rdata(const Rdata& source);
    void operator=(const Rdata& source);
public:
    /// The destructor.
    virtual ~Rdata() {};
    //@}

    ///
    /// \name Converter methods
    ///
    //@{
    /// \brief Convert an \c Rdata to a string.
    ///
    /// This method returns a \c std::string object representing the \c Rdata.
    ///
    /// This is a pure virtual method without the definition; the actual
    /// representation is specific to each derived concrete class and
    /// should be explicitly defined in the derived class.
    ///
    /// \return A string representation of \c Rdata.
    virtual std::string toText() const = 0;

    /// \brief Render the \c Rdata in the wire format into a buffer.
    ///
    /// This is a pure virtual method without the definition; the actual
    /// conversion is specific to each derived concrete class and
    /// should be explicitly defined in the derived class.
    ///
    /// \param buffer An output buffer to store the wire data.
    virtual void toWire(isc::util::OutputBuffer& buffer) const = 0;

    /// \brief Render the \c Rdata in the wire format into a
    /// \c MessageRenderer object.
    ///
    /// This is a pure virtual method without the definition; the actual
    /// conversion is specific to each derived concrete class and
    /// should be explicitly defined in the derived class.
    ///
    /// \param renderer DNS message rendering context that encapsulates the
    /// output buffer in which the \c Rdata is to be stored.
    virtual void toWire(AbstractMessageRenderer& renderer) const = 0;
    //@}

    ///
    /// \name Comparison method
    ///
    //@{
    /// \brief Compare two instances of \c Rdata.
    ///
    /// This method compares \c this and the \c other Rdata objects
    /// in terms of the DNSSEC sorting order as defined in RFC4034, and returns
    /// the result as an integer.
    ///
    /// This is a pure virtual method without the definition; the actual
    /// comparison logic is specific to each derived concrete class and
    /// should be explicitly defined in the derived class.
    ///
    /// Specific implementations of this method must confirm that \c this
    /// and the \c other are objects of the same concrete derived class of
    /// \c Rdata.  This is normally done by \c dynamic_cast in the
    /// implementation.  It also means if the assumption isn't met
    /// an exception of class \c std::bad_cast will be thrown.
    ///
    /// Here is an implementation choice: instead of relying on
    /// \c dynamic_cast, we could first convert the data into wire-format
    /// and compare the pair as opaque data.  This would be more polymorphic,
    /// but might involve significant overhead, especially for a large size
    /// of RDATA.
    ///
    /// \param other the right-hand operand to compare against.
    /// \return < 0 if \c this would be sorted before \c other.
    /// \return 0 if \c this is identical to \c other in terms of sorting order.
    /// \return > 0 if \c this would be sorted after \c other.
    virtual int compare(const Rdata& other) const = 0;
    //@}

    /// \brief Get the wire format length of an Rdata.
    ///
    /// IMPLEMENTATION NOTE: Currently this base class implementation is
    /// non-optimal as it renders the wire data to a buffer and returns
    /// the buffer's length. What would perform better is to add
    /// implementations of \c getLength() method to every RDATA
    /// type. This is why this method is virtual. Once all Rdata types
    /// have \c getLength() implementations, this base class
    /// implementation must be removed and the method should become a
    /// pure interface.
    ///
    /// \return The length of the wire format representation of the
    /// RDATA.
    virtual uint16_t getLength() const;
};

namespace generic {

/// \brief The \c GenericImpl class is the actual implementation of the
/// \c generic::Generic class.
///
/// The implementation is hidden from applications.  This approach requires
/// dynamic memory allocation on construction, copy, or assignment, but
/// we believe it should be acceptable as "unknown" RDATA should be pretty
/// rare.
struct GenericImpl;

/// \brief The \c generic::Generic class represents generic "unknown" RDATA.
///
/// This class is used as a placeholder for all non well-known type of RDATA.
/// By definition, the stored data is regarded as opaque binary without
/// assuming any structure.
class Generic : public Rdata {
public:
    ///
    /// \name Constructors, Assignment Operator and Destructor.
    ///
    //@{
    /// \brief Constructor from a string.
    ///
    /// This method constructs a \c generic::Generic object from a textual
    /// representation as defined in RFC3597.
    ///
    /// If \c rdata_string isn't a valid textual representation of this type
    /// of RDATA, an exception of class \c InvalidRdataText or
    /// \c InvalidRdataLength will be thrown.
    /// If resource allocation to store the data fails, a corresponding standard
    /// exception will be thrown.
    ///
    /// \param rdata_string A string of textual representation of generic
    /// RDATA.
    explicit Generic(const std::string& rdata_string);

    ///
    /// \brief Constructor from wire-format data.
    ///
    /// The \c buffer parameter normally stores a complete DNS message
    /// containing the generic RDATA to be constructed.
    /// The current read position of the buffer points to the head of the
    /// data.
    ///
    /// This method reads \c rdata_len bytes from the \c buffer, and internally
    /// stores the data as an opaque byte sequence.
    ///
    /// \c rdata_len must not exceed \c MAX_RDLENGTH; otherwise, an exception
    /// of class \c InvalidRdataLength will be thrown.
    /// If resource allocation to hold the data fails, a corresponding
    /// standard exception will be thrown; if the \c buffer doesn't
    /// contain \c rdata_len bytes of unread data, an exception of
    /// class \c isc::OutOfRange will be thrown.
    ///
    /// \param buffer A reference to an \c InputBuffer object storing the
    /// \c Rdata to parse.
    /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
    Generic(isc::util::InputBuffer& buffer, size_t rdata_len);

    /// \brief Constructor from master lexer.
    ///
    Generic(MasterLexer& lexer, const Name* name,
            MasterLoader::Options options, MasterLoaderCallbacks& callbacks);

    ///
    /// \brief The destructor.
    virtual ~Generic();
    ///
    /// \brief The copy constructor.
    ///
    /// If resource allocation to copy the data fails, a corresponding standard
    /// exception will be thrown.
    ///
    /// \param source A reference to a \c generic::Generic object to copy from.
    Generic(const Generic& source);

    ///
    /// \brief The assignment operator.
    ///
    /// If resource allocation to copy the data fails, a corresponding standard
    /// exception will be thrown.
    ///
    /// \param source A reference to a \c generic::Generic object to copy from.
    Generic& operator=(const Generic& source);
    //@}

    ///
    /// \name Converter methods
    ///
    //@{
    /// \brief Convert an \c generic::Generic object to a string.
    ///
    /// This method converts a generic "unknown" RDATA object into a textual
    /// representation of such unknown data as defined in RFC3597.
    ///
    /// If resource allocation to copy the data fails, a corresponding standard
    /// exception will be thrown.
    ///
    /// \return A string representation of \c generic::Generic.
    virtual std::string toText() const;

    ///
    /// \brief Render the \c generic::Generic in the wire format into a buffer.
    ///
    /// This will require \c rdata_len bytes of remaining capacity in the
    /// \c buffer.  If this is not the case and resource allocation for the
    /// necessary memory space fails, a corresponding standard exception will
    /// be thrown.
    ///
    /// \param buffer An output buffer to store the wire data.
    virtual void toWire(isc::util::OutputBuffer& buffer) const;

    /// \brief Render the \c generic::Generic in the wire format into a
    /// \c MessageRenderer object.
    ///
    /// This will require \c rdata_len bytes of remaining capacity in the
    /// \c buffer.  If this is not the case and resource allocation for the
    /// necessary memory space fails, a corresponding standard exception will
    /// be thrown.
    ///
    /// \param renderer DNS message rendering context that encapsulates the
    /// output buffer in which the \c Generic object is to be stored.
    virtual void toWire(AbstractMessageRenderer& renderer) const;
    //@}

    ///
    /// \name Comparison method
    ///
    //@{
    /// \brief Compare two instances of \c generic::Generic objects.
    ///
    /// As defined in RFC4034, this method simply compares the wire-format
    /// representations of the two objects as left-justified unsigned octet
    /// sequences.
    ///
    /// The object referenced by \c other must have been instantiated as
    /// a c generic::Generic class object; otherwise, an exception of class
    /// \c std::bad_cast will be thrown.
    /// Note that the comparison is RR type/class agnostic: this method doesn't
    /// check whether the two \c Rdata objects to compare are of the comparable
    /// RR type/class.  For example, \c this object may come from an \c RRset
    /// of \c RRType x, and the \c other may come from a different \c RRset
    /// of \c RRType y (where x != y).  This situation would be considered a
    /// bug, but this method cannot detect this type of error.
    /// The caller must ensure this condition.
    ///
    /// \param other the right-hand operand to compare against.
    /// \return < 0 if \c this would be sorted before \c other.
    /// \return 0 if \c this is identical to \c other in terms of sorting order.
    /// \return > 0 if \c this would be sorted after \c other.
    virtual int compare(const Rdata& other) const;
    //@}

private:
    std::unique_ptr<GenericImpl> constructFromLexer(MasterLexer& lexer);

    std::unique_ptr<GenericImpl> impl_;
};

///
/// \brief Insert the name as a string into stream.
///
/// This method convert the \c rdata into a string and inserts it into the
/// output stream \c os.
///
/// This function overloads the global \c operator<< to behave as described in
/// \c ostream::operator<< but applied to \c generic::Generic Rdata objects.
///
/// \param os A \c std::ostream object on which the insertion operation is
/// performed.
/// \param rdata The \c Generic object output by the operation.
/// \return A reference to the same \c std::ostream object referenced by
/// parameter \c os after the insertion operation.
std::ostream& operator<<(std::ostream& os, const Generic& rdata);
} // end of namespace "generic"

//
// Non class-member functions related to Rdata
//

///
/// \name Parameterized Polymorphic RDATA Factories
///
/// This set of global functions provide a unified interface to create an
/// \c Rdata object in a parameterized polymorphic way,
/// that is, these functions take a pair of \c RRType and \c RRClass
/// objects and data specific to that pair, and create an object of
/// the corresponding concrete derived class of \c Rdata.
///
/// These will be useful when parsing/constructing a DNS message or
/// parsing a master file, where information for a specific type of RDATA
/// is given but the resulting object, once created, should better be used
/// in a polymorphic way.
///
/// For example, if a master file parser encounters an NS RR
/// \verbatim example.com. 3600 IN NS ns.example.com.\endverbatim
/// it stores the text fragments "IN", "NS", and "ns.example.com." in
/// \c std::string objects \c class_txt, \c type_txt, and \c nsname_txt,
/// respectively, then it would create a new \c RdataPtr object as follows:
/// \code RdataPtr rdata = createRdata(RRType(type_txt), RRClass(class_txt),
///                              nsname_txt); \endcode
/// On success, \c rdata will point to an object of the \c generic::NS class
/// that internally holds a domain name of "ns.example.com."
///
/// Internally, these functions uses the corresponding
/// \c RRParamRegistry::createRdata methods of the \c RRParamRegistry.
/// See also the description on these methods for related notes.
//@{
/// \brief Create RDATA of a given pair of RR type and class from a string.
///
/// This method creates from a string an \c Rdata object of the given pair
/// of RR type and class.
///
/// \param rrtype An \c RRType object specifying the type/class pair.
/// \param rrclass An \c RRClass object specifying the type/class pair.
/// \param rdata_string A string of textual representation of the \c Rdata.
/// \return An \c RdataPtr object pointing to the created \c Rdata
/// object.
RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                     const std::string& rdata_string);

/// \brief Create RDATA of a given pair of RR type and class from
/// wire-format data.
///
/// This method creates from wire-format binary data an \c Rdata object
/// of the given pair of RR type and class.
///
/// \c len must not exceed the protocol defined maximum value, \c MAX_RDLENGTH;
/// otherwise, an exception of class \c InvalidRdataLength will be thrown.
///
/// In some cases, the length of the RDATA is determined without the
/// information of \c len.  For example, the RDATA length of an IN/A RR
/// must always be 4.  If \c len is not equal to the actual length in such
/// cases, an exception of class InvalidRdataLength will be thrown.
///
/// \param rrtype An \c RRType object specifying the type/class pair.
/// \param rrclass An \c RRClass object specifying the type/class pair.
/// \param buffer A reference to an \c InputBuffer object storing the
/// \c Rdata to parse.
/// \param len The length in buffer of the \c Rdata.  In bytes.
/// \return An \c RdataPtr object pointing to the created \c Rdata
/// object.
RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                     isc::util::InputBuffer& buffer, size_t len);

/// \brief Create RDATA of a given pair of RR type and class, copying
/// of another RDATA of same kind.
///
/// This method creates an \c Rdata object of the given pair of
/// RR type and class, copying the  content of the given \c Rdata,
/// \c source.
///
/// \param rrtype An \c RRType object specifying the type/class pair.
/// \param rrclass An \c RRClass object specifying the type/class pair.
/// \param source A reference to an \c Rdata object whose content
/// is to be copied to the created \c Rdata object.
/// \return An \c RdataPtr object pointing to the created
/// \c Rdata object.
RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                     const Rdata& source);

/// \brief Create RDATA of a given pair of RR type and class using the
/// master lexer.
///
/// This is a more generic form of factory from textual RDATA, and is mainly
/// intended to be used internally by the master file parser (\c MasterLoader)
/// of this library.
///
/// The \c lexer is expected to be at the beginning of textual RDATA of the
/// specified type and class.  This function (and its underlying Rdata
/// implementations) extracts necessary tokens from the lexer and constructs
/// the RDATA from them.
///
/// Due to the intended usage of this version, this function handles error
/// cases quite differently from other versions.  It internally catches
/// most of syntax and semantics errors of the input (reported as exceptions),
/// calls the corresponding callback specified by the \c callbacks parameters,
/// and returns a null smart pointer.  If the caller rather wants to get
/// an exception in these cases, it can pass a callback that internally
/// throws on error.  Some critical exceptions such as \c std::bad_alloc are
/// still propagated to the upper layer as it doesn't make sense to try
/// recovery from such a situation within this function.
///
/// Whether or not the creation succeeds, this function updates the lexer
/// until it reaches either the end of line or file, starting from the end of
/// the RDATA text (or the point of failure if the parsing fails in the
/// middle of it).  The caller can therefore assume it's ready for reading
/// the next data (which is normally a subsequent RR in the zone file) on
/// return, whether or not this function succeeds.
///
/// \param rrtype An \c RRType object specifying the type/class pair.
/// \param rrclass An \c RRClass object specifying the type/class pair.
/// \param lexer A \c MasterLexer object parsing a master file for the
/// RDATA to be created
/// \param origin If non null, specifies the origin of any domain name fields
/// of the RDATA that are non absolute.
/// \param options Master loader options controlling how to deal with errors
/// or non critical issues in the parsed RDATA.
/// \param callbacks Callback to be called when an error or non critical issue
/// is found.
/// \return An \c RdataPtr object pointing to the created
/// \c Rdata object.  Will be null if parsing fails.
RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                     MasterLexer& lexer, const Name* origin,
                     MasterLoader::Options options,
                     MasterLoaderCallbacks& callbacks);

//@}

///
/// \brief Gives relative ordering of two names in terms of DNSSEC RDATA
/// ordering.
///
/// This method compares two names as defined in Sections 6.2 and 6.3 of
/// RFC4034: Comparing two names in their canonical form
/// (i.e., converting upper case ASCII characters to lower ones) and
/// as a left-justified unsigned octet sequence.  Note that the ordering is
/// different from that for owner names.  For example, "a.example" should be
/// sorted before "example" as RDATA, but the ordering is the opposite when
/// compared as owner names.
///
/// Normally, applications would not need this function directly.
/// This is mostly an internal helper function for \c Rdata related classes
/// to implement their \c compare() method.
/// This function is publicly open, however, for the convenience of
/// external developers who want to implement new or experimental RR types.
///
/// This function never throws an exception as long as the given names are
/// valid \c Name objects.
///
/// Additional note about applicability: In fact, BIND9's similar function,
/// \c dns_name_rdatacompare(), is only used in rdata implementations and
/// for testing purposes.
///
/// \param n1,n2 \c Name class objects to compare.
/// \return -1 if \c n1 would be sorted before \c n2.
/// \return 0 if \c n1 is identical to \c n2 in terms of sorting order.
/// \return 1 if \c n1 would be sorted after \c n2.
///
int compareNames(const Name& n1, const Name& n2);

} // end of namespace "rdata"
}
}
#endif  // RDATA_H