summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/message.h
blob: df5ba62674f0801f796b6d78ee6de6f86c367328 (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
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
// Copyright (C) 2009-2023 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 MESSAGE_H
#define MESSAGE_H 1

#include <stdint.h>

#include <iterator>
#include <string>
#include <ostream>

#include <dns/exceptions.h>

#include <dns/edns.h>
#include <dns/question.h>
#include <dns/rrset.h>

namespace isc {
namespace util {
class InputBuffer;
}

namespace dns {
class TSIGContext;
class TSIGRecord;

///
/// \brief A standard DNS module exception that is thrown if a wire format
/// message parser encounters a short length of data that don't even contain
/// the full header section.
///
class MessageTooShort : public isc::dns::Exception {
public:
    MessageTooShort(const char* file, size_t line, const char* what) :
        isc::dns::Exception(file, line, what) {}
};

///
/// \brief A standard DNS module exception that is thrown if a section iterator
/// is being constructed for an incompatible section.  Specifically, this
/// happens RRset iterator is being constructed for a Question section.
///
class InvalidMessageSection : public isc::dns::Exception {
public:
    InvalidMessageSection(const char* file, size_t line, const char* what) :
        isc::dns::Exception(file, line, what) {}
};

///
/// \brief A standard DNS module exception that is thrown if a \c Message
/// class method is called that is prohibited for the current mode of
/// the message.
///
class InvalidMessageOperation : public isc::dns::Exception {
public:
    InvalidMessageOperation(const char* file, size_t line, const char* what) :
        isc::dns::Exception(file, line, what) {}
};

///
/// \brief A standard DNS module exception that is thrown if a UDP buffer size
/// smaller than the standard default maximum (DEFAULT_MAX_UDPSIZE) is
/// being specified for the message.
///
class InvalidMessageUDPSize : public isc::dns::Exception {
public:
    InvalidMessageUDPSize(const char* file, size_t line, const char* what) :
        isc::dns::Exception(file, line, what) {}
};

typedef uint16_t qid_t;

class AbstractMessageRenderer;
class Message;
class MessageImpl;
class Opcode;
class Rcode;

template <typename T>
struct SectionIteratorImpl;

/// \c SectionIterator is a templated class to provide standard-compatible
/// iterators for Questions and RRsets for a given DNS message section.
/// The template parameter is either \c QuestionPtr (for the question section)
/// or \c RRsetPtr (for the answer, authority, or additional section).
template <typename T>
class SectionIterator {
public:
    // Aliases used to enable iterator behavior on this class
    using iterator_category = std::input_iterator_tag;
    using value_type = T;
    using difference_type = std::ptrdiff_t;
    using pointer = T*;
    using reference = T&;

    SectionIterator() : impl_(NULL) {}
    SectionIterator(const SectionIteratorImpl<T>& impl);
    ~SectionIterator();
    SectionIterator(const SectionIterator<T>& source);
    void operator=(const SectionIterator<T>& source);
    SectionIterator<T>& operator++();
    SectionIterator<T> operator++(int);
    const T& operator*() const;
    const T* operator->() const;
    bool operator==(const SectionIterator<T>& other) const;
    bool operator!=(const SectionIterator<T>& other) const;
private:
    SectionIteratorImpl<T>* impl_;
};

typedef SectionIterator<QuestionPtr> QuestionIterator;
typedef SectionIterator<RRsetPtr> RRsetIterator;

class MessageImpl;
/// @brief Pointer to the @ref MessageImpl object.
typedef boost::shared_ptr<MessageImpl> MessageImplPtr;

/// \brief The \c Message class encapsulates a standard DNS message.
///
/// Details of the design and interfaces of this class are still in flux.
/// Here are some notes about the current design.
///
/// Since many realistic DNS applications deal with messages, message objects
/// will be frequently used, and can be performance sensitive.  To minimize
/// the performance overhead of constructing and destructing the objects,
/// this class is designed to be reusable.  The \c clear() method is provided
/// for this purpose.
///
/// A \c Message class object is in either the \c PARSE or the \c RENDER mode.
/// A \c PARSE mode object is intended to be used to convert wire-format
/// message data into a complete \c Message object.
/// A \c RENDER mode object is intended to be used to convert a \c Message
/// object into wire-format data.
/// Some of the method functions of this class are limited to a specific mode.
/// In general, "set" type operations are only allowed for \c RENDER mode
/// objects.
/// The initial mode must be specified on construction, and can be changed
/// through some method functions.
///
/// This class uses the "pimpl" idiom, and hides detailed implementation
/// through the \c impl_ pointer.  Since a \c Message object is expected to
/// be reused, the construction overhead of this approach should be acceptable.
///
/// Open issues (among other things):
/// - We may want to provide an "iterator" for all RRsets/RRs for convenience.
///   This will be for applications that do not care about performance much,
///   so the implementation can only be moderately efficient.
/// - We may want to provide a "find" method for a specified type
///   of RR in the message.
class Message {
public:
    /// Constants to specify the operation mode of the \c Message.
    enum Mode {
        PARSE = 0,              ///< Parse mode (handling an incoming message)
        RENDER = 1              ///< Render mode (building an outgoing message)
    };

    /// \brief Constants for flag bit fields of a DNS message header.
    ///
    /// Only the defined constants are valid where a header flag is required
    /// in this library (e.g., in \c Message::setHeaderFlag()).
    /// Since these are enum constants, however, an invalid value could be
    /// passed via casting without an error at compilation time.
    /// It is generally the callee's responsibility to check and reject invalid
    /// values.
    /// Of course, applications shouldn't pass invalid values even if the
    /// callee does not perform proper validation; the result in such usage
    /// is undefined.
    ///
    /// In the current implementation, the defined values happen to be
    /// a 16-bit integer with one bit being set corresponding to the
    /// specified flag in the second 16 bits of the DNS Header section
    /// in order to make the internal implementation simpler.
    /// For example, \c HEADERFLAG_QR is defined to be 0x8000 as the QR
    /// bit is the most significant bit of the second 16 bits of the header.
    /// However, applications should not assume this coincidence and
    /// must solely use the enum representations.
    /// Any usage based on the assumption of the underlying values is invalid
    /// and the result is undefined.
    ///
    /// Likewise, bit wise operations such as AND or OR on the flag values
    /// are invalid and are not guaranteed to work, even if it could compile
    /// with casting.
    /// For example, the following code will compile:
    /// \code const uint16_t combined_flags =
    ///           static_cast<uint16_t>(Message::HEADERFLAG_AA) |
    ///           static_cast<uint16_t>(Message::HEADERFLAG_CD);
    /// message->setHeaderFlag(static_cast<Message::HeaderFlag>(combined_flags));
    /// \endcode
    /// and (with the current definition) happens to work as if it were
    /// validly written as follows:
    /// \code message->setHeaderFlag(Message::HEADERFLAG_AA);
    /// message->setHeaderFlag(Message::HEADERFLAG_CD);
    /// \endcode
    /// But the former notation is invalid and may not work in future versions.
    /// We did not try to prohibit such usage at compilation time, e.g., by
    /// introducing a separately defined class considering the balance
    /// between the complexity and advantage, but hopefully the cast notation
    /// is sufficiently ugly to prevent proliferation of the usage.
    enum HeaderFlag {
        HEADERFLAG_QR = 0x8000, ///< Query (if cleared) or response (if set)
        HEADERFLAG_AA = 0x0400, ///< Authoritative answer
        HEADERFLAG_TC = 0x0200, ///< Truncation
        HEADERFLAG_RD = 0x0100, ///< Recursion desired
        HEADERFLAG_RA = 0x0080, ///< Recursion available
        HEADERFLAG_AD = 0x0020, ///< Authentic %data (RFC4035)
        HEADERFLAG_CD = 0x0010  ///< DNSSEC checking disabled (RFC4035)
    };

    /// \brief Constants to specify sections of a DNS message.
    ///
    /// The sections are those defined in RFC 1035 excluding the Header
    /// section; the fields of the Header section are accessed via specific
    /// methods of the \c Message class (e.g., \c getQid()).
    ///
    /// <b>Open Design Issue:</b>
    /// In the current implementation the values for the constants are
    /// sorted in the order of appearance in DNS messages, i.e.,
    /// from %Question to Additional.
    /// So, for example,
    /// code <code>section >= Message::SECTION_AUTHORITY</code> can be
    /// used to do something in or after the Authority section.
    /// This would be convenient, but it is not clear if it's really a good
    /// idea to rely on relationship between the underlying values of enum
    /// constants.  At the moment, applications are discouraged to rely on
    /// this implementation detail.  We will see if such usage is sufficiently
    /// common to officially support it.
    ///
    /// Note also that since we don't define \c operator++ for this enum,
    /// the following code intending to iterate over all sections will
    /// \b not compile:
    /// \code for (Section s; s <= SECTION_ADDITIONAL; ++s) { // ++s undefined
    ///     // do something
    /// } \endcode
    /// This is intentional at this moment, and we'll see if we need to allow
    /// that as we have more experiences with this library.
    ///
    /// <b>Future Extension:</b> We'll probably also define constants for
    /// the section names used in dynamic updates in future versions.
    enum Section {
        SECTION_QUESTION = 0,   ///< %Question section
        SECTION_ANSWER = 1,     ///< Answer section
        SECTION_AUTHORITY = 2,  ///< Authority section
        SECTION_ADDITIONAL = 3  ///< Additional section
    };

    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are
    /// intentionally defined as private.
    /// The intended use case wouldn't require copies of a \c Message object;
    /// once created, it would normally be expected to be reused, changing the
    /// mode from \c PARSE to \c RENDER, and vice versa.
    //@{
public:
    /// \brief The constructor.
    /// The mode of the message is specified by the \c mode parameter.
    Message(Mode mode);
    /// \brief The destructor.
    ~Message() = default;
private:
    Message(const Message& source);
    Message& operator=(const Message& source);
    //@}
public:
    /// \brief Return whether the specified header flag bit is set in the
    /// header section.
    ///
    /// This method is basically exception free, but if
    /// \c flag is not a valid constant of the \c HeaderFlag type,
    /// an exception of class \c InvalidParameter will be thrown.
    ///
    /// \param flag The header flag constant to test.
    /// \return \c true if the specified flag is set; otherwise \c false.
    bool getHeaderFlag(const HeaderFlag flag) const;

    /// \brief Set or clear the specified header flag bit in the header
    /// section.
    ///
    /// The optional parameter \c on indicates the operation mode,
    /// set or clear; if it's \c true the corresponding flag will be set;
    /// otherwise the flag will be cleared.
    /// In either case the original state of the flag does not affect the
    /// operation; for example, if a flag is already set and the "set"
    /// operation is attempted, it effectively results in no operation.
    ///
    /// The parameter \c on can be omitted, in which case a value of \c true
    /// (i.e., set operation) will be assumed.
    /// This is based on the observation that the flag would have to be set
    /// in the vast majority of the cases where an application needs to
    /// use this method.
    ///
    /// This method is only allowed in the \c RENDER mode;
    /// if the \c Message is in other mode, an exception of class
    /// InvalidMessageOperation will be thrown.
    ///
    /// If \c flag is not a valid constant of the \c HeaderFlag type,
    /// an exception of class \c InvalidParameter will be thrown.
    ///
    /// \param flag The header flag constant to set or clear.
    /// \param on If \c true the flag will be set; otherwise the flag will be
    /// cleared.
    void setHeaderFlag(const HeaderFlag flag, const bool on = true);

    /// \brief Return the query ID given in the header section of the message.
    qid_t getQid() const;

    /// \brief Set the query ID of the header section of the message.
    ///
    /// This method is only allowed in the \c RENDER mode;
    /// if the \c Message is in other mode, an exception of class
    /// InvalidMessageOperation will be thrown.
    void setQid(qid_t qid);

    /// \brief Return the Response Code of the message.
    ///
    /// This includes extended codes specified by an EDNS OPT RR (when
    /// included).  In the \c PARSE mode, if the received message contains
    /// an EDNS OPT RR, the corresponding extended code is identified and
    /// returned.
    ///
    /// The message must have been properly parsed (in the case of the
    /// \c PARSE mode) or an \c Rcode has been set (in the case of the
    /// \c RENDER mode) beforehand.  Otherwise, an exception of class
    /// \c InvalidMessageOperation will be thrown.
    const Rcode& getRcode() const;

    /// \brief Set the Response Code of the message.
    ///
    /// This method is only allowed in the \c RENDER mode;
    /// if the \c Message is in other mode, an exception of class
    /// InvalidMessageOperation will be thrown.
    ///
    /// If the specified code is an EDNS extended RCODE, an EDNS OPT RR will be
    /// included in the message.
    void setRcode(const Rcode& rcode);

    /// \brief Return the OPCODE given in the header section of the message.
    ///
    /// The message must have been properly parsed (in the case of the
    /// \c PARSE mode) or an \c Opcode has been set (in the case of the
    /// \c RENDER mode) beforehand.  Otherwise, an exception of class
    /// \c InvalidMessageOperation will be thrown.
    const Opcode& getOpcode() const;

    /// \brief Set the OPCODE of the header section of the message.
    ///
    /// This method is only allowed in the \c RENDER mode;
    /// if the \c Message is in other mode, an exception of class
    /// InvalidMessageOperation will be thrown.
    void setOpcode(const Opcode& opcode);

    /// \brief Return, if any, the EDNS associated with the message.
    ///
    /// This method never throws an exception.
    ///
    /// \return A shared pointer to the EDNS.  This will be a null shared
    /// pointer if the message is not associated with EDNS.
    ConstEDNSPtr getEDNS() const;

    /// \brief Set EDNS for the message.
    ///
    /// This method is only allowed in the \c RENDER mode;
    /// if the \c Message is in other mode, an exception of class
    /// InvalidMessageOperation will be thrown.
    ///
    /// \param edns A shared pointer to an \c EDNS object to be set in
    /// \c Message.
    void setEDNS(ConstEDNSPtr edns);

    /// \brief Return, if any, the TSIG record contained in the received
    /// message.
    ///
    /// Currently, this method is only intended to return a TSIG record
    /// for an incoming message built via the \c fromWire() method in the
    /// PARSE mode.  A call to this method in the RENDER mode is invalid and
    /// result in an exception.  Also, calling this method is meaningless
    /// unless \c fromWire() is performed.
    ///
    /// The returned pointer is valid only during the lifetime of the
    /// \c Message object and until \c clear() is called.  The \c Message
    /// object retains the ownership of \c TSIGRecord; the caller must not
    /// try to delete it.
    ///
    /// \exception InvalidMessageOperation Message is not in the PARSE mode.
    ///
    /// \return A pointer to the stored \c TSIGRecord or \c NULL.
    const TSIGRecord* getTSIGRecord() const;

    /// \brief Returns the number of RRs contained in the given section.
    ///
    /// In the \c PARSE mode, the returned value may not be identical to
    /// the actual number of RRs of the incoming message that is parsed.
    /// The \c Message class handles some "meta" RRs such as EDNS OPT RR
    /// separately.  This method doesn't include such RRs.
    /// Also, a future version of the parser will detect and unify duplicate
    /// RRs (which should be rare in practice though), in which case
    /// the stored RRs in the \c Message object will be fewer than the RRs
    /// originally contained in the incoming message.
    ///
    /// Likewise, in the \c RENDER mode, even if \c EDNS is set in the
    /// \c Message, this method doesn't count the corresponding OPT RR
    /// in the Additional section.
    ///
    /// This method is basically exception free, but if
    /// \c section is not a valid constant of the \c Section type,
    /// an exception of class \c OutOfRange will be thrown.
    ///
    /// \param section The section in the message where RRs should be
    /// counted.
    /// \return The number of RRs stored in the specified section of the
    /// message.
    unsigned int getRRCount(const Section section) const;

    /// \brief Return an iterator corresponding to the beginning of the
    /// Question section of the message.
    const QuestionIterator beginQuestion() const;

    /// \brief Return an iterator corresponding to the end of the
    /// Question section of the message.
    const QuestionIterator endQuestion() const;

    /// \brief Return an iterator corresponding to the beginning of the
    /// given section (other than Question) of the message.
    ///
    /// \c section must be a valid constant of the \c Section type;
    /// otherwise, an exception of class \c OutOfRange will be thrown.
    const RRsetIterator beginSection(const Section section) const;

    /// \brief Return an iterator corresponding to the end of the
    /// given section (other than Question) of the message.
    ///
    /// \c section must be a valid constant of the \c Section type;
    /// otherwise, an exception of class \c OutOfRange will be thrown.
    const RRsetIterator endSection(const Section section) const;

    /// \brief Add a (pointer like object of) Question to the message.
    ///
    /// This method is only allowed in the \c RENDER mode;
    /// if the \c Message is in other mode, an exception of class
    /// InvalidMessageOperation will be thrown.
    void addQuestion(QuestionPtr question);

    /// \brief Add a (pointer like object of) Question to the message.
    ///
    /// This version internally creates a \c QuestionPtr object from the
    /// given \c question and calls the other version of this method.
    /// So this is inherently less efficient, but is provided because this
    /// form may be more intuitive and may make more sense for performance
    /// insensitive applications.
    ///
    /// This method is only allowed in the \c RENDER mode;
    /// if the \c Message is in other mode, an exception of class
    /// InvalidMessageOperation will be thrown.
    void addQuestion(const Question& question);

    /// \brief Add a (pointer like object of) RRset to the given section
    /// of the message.
    ///
    /// Note that \c addRRset() does not currently check for duplicate
    /// data before inserting RRsets.  The caller is responsible for
    /// checking for these (see \c hasRRset() below).
    ///
    /// \throw InvalidParameter rrset is NULL
    /// \throw InvalidMessageOperation The message is not in the \c RENDER
    /// mode.
    /// \throw OutOfRange \c section doesn't specify a valid \c Section value.
    ///
    /// \param section The message section to which the rrset is to be added
    /// \param rrset The rrset to be added.  Must not be NULL.
    void addRRset(const Section section, RRsetPtr rrset);

    /// \brief Determine whether the given section already has an RRset
    /// matching the given name, RR class and RR type.
    ///
    /// \c section must be a valid constant of the \c Section type;
    /// otherwise, an exception of class \c OutOfRange will be thrown.
    ///
    /// This should probably be extended to be a "find" method that returns
    /// a matching RRset if found.
    bool hasRRset(const Section section, const Name& name,
                  const RRClass& rrclass, const RRType& rrtype) const;

    /// \brief Determine whether the given section already has an RRset
    /// matching the one pointed to by the argument
    ///
    /// \c section must be a valid constant of the \c Section type;
    /// otherwise, an exception of class \c OutOfRange will be thrown.
    bool hasRRset(const Section section, const RRsetPtr& rrset) const;

    /// \brief Remove RRSet from Message
    ///
    /// Removes the RRset identified by the section iterator from the message.
    /// Note: if,.for some reason, the RRset is duplicated in the section, only
    /// one occurrence is removed.
    ///
    /// If the operation is successful, all iterators into the section are
    /// invalidated.
    ///
    /// \param section Section to which the iterator belongs
    /// \param iterator Iterator pointing to the element to be removed
    ///
    /// \return true if the element was removed, false if the iterator was not
    /// found in the specified section.
    bool removeRRset(const Section section, RRsetIterator& iterator);

    /// \brief Remove all RRSets from the given Section
    ///
    /// This method is only allowed in the \c RENDER mode, and the given
    /// section must be valid.
    ///
    /// \throw InvalidMessageOperation Message is not in the \c RENDER mode
    /// \throw OutOfRange The specified section is not valid
    ///
    /// \param section Section to remove all rrsets from
    void clearSection(const Section section);

    // The following methods are not currently implemented.
    //void removeQuestion(QuestionPtr question);
    // notyet:
    //void addRR(const Section section, const RR& rr);
    //void removeRR(const Section section, const RR& rr);

    /// \brief Clear the message content (if any) and reinitialize it in the
    /// specified mode.
    void clear(Mode mode);

    /// \brief Adds all rrsets from the source the given section in the
    /// source message to the same section of this message
    ///
    /// \param section the section to append
    /// \param source The source Message
    void appendSection(const Section section, const Message& source);

    /// \brief Prepare for making a response from a request.
    ///
    /// This will clear the DNS header except those fields that should be kept
    /// for the response, and clear answer and the following sections.
    /// See also dns_message_reply() of BIND9.
    void makeResponse();

    /// \brief Convert the Message to a string.
    ///
    /// At least \c Opcode and \c Rcode must be validly set in the \c Message
    /// (as a result of parse in the \c PARSE mode or by explicitly setting
    /// in the \c RENDER mode);  otherwise, an exception of
    /// class \c InvalidMessageOperation will be thrown.
    std::string toText() const;

    /// \brief Render the message in wire formant into a message renderer
    /// object with (or without) TSIG.
    ///
    /// This \c Message must be in the \c RENDER mode and both \c Opcode and
    /// \c Rcode must have been set beforehand; otherwise, an exception of
    /// class \c InvalidMessageOperation will be thrown.
    ///
    /// If a non-NULL \c tsig_ctx is passed, it will also add a TSIG RR
    /// with (in many cases) the TSIG MAC for the message along with the
    /// given TSIG context (\c tsig_ctx).  The TSIG RR will be placed at
    /// the end of \c renderer. The \c TSIGContext at \c tsig_ctx will
    /// be updated based on the fact it was used for signing and with
    /// the latest MAC.
    ///
    /// \exception InvalidMessageOperation The message is not in the Render
    /// mode, or either Rcode or Opcode is not set.
    /// \exception InvalidParameter The allowable limit of \c renderer is too
    /// small for a TSIG or the Header section.  Note that this shouldn't
    /// happen with parameters as defined in the standard protocols,
    /// so it's more likely a program bug.
    /// \exception Unexpected Rendering the TSIG RR fails.  The implementation
    /// internally makes sure this doesn't happen, so if that ever occurs
    /// it should mean a bug either in the TSIG context or in the renderer
    /// implementation.
    ///
    /// \note The renderer's internal buffers and data are automatically
    /// cleared, keeping the length limit and the compression mode intact.
    /// In case truncation is triggered, the renderer is cleared completely.
    ///
    /// \param renderer DNS message rendering context that encapsulates the
    /// output buffer and name compression information.
    /// \param tsig_ctx A TSIG context that is to be used for signing the
    /// message
    void toWire(AbstractMessageRenderer& renderer,
                TSIGContext* tsig_ctx = NULL);

    /// Parse options.
    ///
    /// describe PRESERVE_ORDER: note doesn't affect EDNS or TSIG.
    ///
    /// The option values are used as a parameter for \c fromWire().
    /// These are values of a bitmask type.  Bitwise operations can be
    /// performed on these values to express compound options.
    enum ParseOptions {
        PARSE_DEFAULT = 0,       ///< The default options
        PRESERVE_ORDER = 1       ///< Preserve RR order and don't combine them
    };

    /// \brief Parse the header section of the \c Message.
    ///
    /// NOTE: If the header has already been parsed by a previous call
    /// to this method, this method simply returns (i.e., it does not
    /// read from the \c buffer).
    void parseHeader(isc::util::InputBuffer& buffer);

    /// \brief (Re)build a \c Message object from wire-format data.
    ///
    /// This method parses the given wire format data to build a
    /// complete Message object.  On success, the values of the header section
    /// fields can be accessible via corresponding get methods, and the
    /// question and following sections can be accessible via the
    /// corresponding iterators.  If the message contains an EDNS or TSIG,
    /// they can be accessible via \c getEDNS() and \c getTSIGRecord(),
    /// respectively.
    ///
    /// This \c Message must be in the \c PARSE mode.
    ///
    /// This method performs strict validation on the given message based
    /// on the DNS protocol specifications.  If the given message data is
    /// invalid, this method throws an exception (see the exception list).
    ///
    /// By default, this method combines RRs of the same name, RR type and
    /// RR class in a section into a single RRset, even if they are interleaved
    /// with a different type of RR (though it would be a rare case in
    /// practice).  If the \c PRESERVE_ORDER option is specified, it handles
    /// each RR separately, in the appearing order, and converts it to a
    /// separate RRset (so this RRset should contain exactly one Rdata).
    /// This mode will be necessary when the higher level protocol is
    /// ordering conscious.  For example, in AXFR and IXFR, the position of
    /// the SOA RRs are crucial.
    ///
    /// \exception InvalidMessageOperation \c Message is in the RENDER mode
    /// \exception DNSMessageFORMERR The given message data is syntactically
    /// \exception MessageTooShort The given data is shorter than a valid
    /// header section
    /// \exception std::bad_alloc Memory allocation failure
    /// \exception Others \c Name, \c Rdata, and \c EDNS classes can also throw
    ///
    /// \param buffer A input buffer object that stores the wire
    /// data. This method reads from position 0 in the passed buffer.
    /// \param options Parse options
    void fromWire(isc::util::InputBuffer& buffer, ParseOptions options
        = PARSE_DEFAULT);

    ///
    /// \name Protocol constants
    ///
    //@{
    /// \brief The default maximum size of UDP DNS messages that don't cause
    /// truncation.
    ///
    /// With EDNS the maximum size can be increased per message.
    static const uint16_t DEFAULT_MAX_UDPSIZE = 512;

    /// \brief The default maximum size of UDP DNS messages we can handle
    static const uint16_t DEFAULT_MAX_EDNS0_UDPSIZE = 4096;
    //@}

private:
    MessageImplPtr impl_;
};

/// \brief Pointer-like type pointing to a \c Message
///
/// This type is expected to be used as an argument in asynchronous
/// callback functions.  The internal reference-counting will ensure that
/// that ongoing state information will not be lost if the object
/// that originated the asynchronous call falls out of scope.
typedef boost::shared_ptr<Message> MessagePtr;
typedef boost::shared_ptr<const Message> ConstMessagePtr;

/// Insert the \c Message as a string into stream.
///
/// This method convert \c message into a string and inserts it into the
/// output stream \c os.
///
/// \param os A \c std::ostream object on which the insertion operation is
/// performed.
/// \param message A \c Message 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 Message& message);

}  // namespace dns
}  // namespace isc

#endif  // MESSAGE_H