Kea 2.5.5
dns/message.cc
Go to the documentation of this file.
1// Copyright (C) 2009-2023 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
9#include <stdint.h>
10
11#include <algorithm>
12#include <cassert>
13#include <string>
14#include <sstream>
15#include <vector>
16
17#include <boost/foreach.hpp>
18#include <boost/lexical_cast.hpp>
19#include <boost/shared_ptr.hpp>
20
22
23#include <util/buffer.h>
24
25#include <dns/edns.h>
26#include <dns/exceptions.h>
27#include <dns/message.h>
28#include <dns/messagerenderer.h>
29#include <dns/name.h>
30#include <dns/opcode.h>
31#include <dns/rcode.h>
32#include <dns/question.h>
33#include <dns/rdataclass.h>
34#include <dns/rrclass.h>
35#include <dns/rrtype.h>
36#include <dns/rrttl.h>
37#include <dns/rrset.h>
38#include <dns/tsig.h>
39
40using namespace std;
41using boost::lexical_cast;
42using namespace isc::dns::rdata;
43using namespace isc::util;
44
45namespace isc {
46namespace dns {
47
48namespace {
49// protocol constants
50const size_t HEADERLEN = 12;
51
52const unsigned int OPCODE_MASK = 0x7800;
53const unsigned int OPCODE_SHIFT = 11;
54const unsigned int RCODE_MASK = 0x000f;
55
56// This diagram shows the wire-format representation of the 2nd 16 bits of
57// the DNS header section, which contain all defined flag bits.
58//
59// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
60// |QR| Opcode |AA|TC|RD|RA| |AD|CD| RCODE |
61// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
62// 1 0 0 0| 0 1 1 1| 1 0 1 1| 0 0 0 0|
63// 0x8 0x7 0xb 0x0
64//
65// This mask covers all the flag bits, and those bits only.
66// Note: we reject a "flag" the is not covered by this mask in some of the
67// public methods. This means our current definition is not fully extendable;
68// applications cannot introduce a new flag bit temporarily without modifying
69// the source code.
70const unsigned int HEADERFLAG_MASK = 0x87b0;
71
72// This is a set of flag bits that should be preserved when building a reply
73// from a request.
74// Note: we assume the specific definition of HEADERFLAG_xx. We may change
75// the definition in future, in which case we need to adjust this definition,
76// too (see also the description about the Message::HeaderFlag type).
77const uint16_t MESSAGE_REPLYPRESERVE = (Message::HEADERFLAG_RD |
79
80const char* const sectiontext[] = {
81 "QUESTION",
82 "ANSWER",
83 "AUTHORITY",
84 "ADDITIONAL"
85};
86}
87
89public:
91 // Open issues: should we rather have a header in wire-format
92 // for efficiency?
95
96 // We want to use NULL for [op,r]code_ to mean the code being not
97 // correctly parsed or set. We store the real code object in
98 // xxcode_placeholder_ and have xxcode_ refer to it when the object
99 // is valid.
100 const Rcode* rcode_;
104
105 uint16_t flags_; // wire-format representation of header flags.
106
108 static const unsigned int NUM_SECTIONS = 4; // TODO: revisit this design
109 int counts_[NUM_SECTIONS]; // TODO: revisit this definition
110 vector<QuestionPtr> questions_;
111 vector<RRsetPtr> rrsets_[NUM_SECTIONS];
114
115 // RRsetsSorter* sorter_; : TODO
116
117 void init();
118 void setOpcode(const Opcode& opcode);
119 void setRcode(const Rcode& rcode);
120 int parseQuestion(InputBuffer& buffer);
121 int parseSection(const Message::Section section, InputBuffer& buffer,
122 Message::ParseOptions options);
123 void addRR(Message::Section section, const Name& name,
124 const RRClass& rrclass, const RRType& rrtype,
125 const RRTTL& ttl, ConstRdataPtr rdata,
126 Message::ParseOptions options);
127 // There are also times where an RR needs to be added that
128 // represents an empty RRset. There is no Rdata in that case
129 void addRR(Message::Section section, const Name& name,
130 const RRClass& rrclass, const RRType& rrtype,
131 const RRTTL& ttl, Message::ParseOptions options);
132 void addEDNS(Message::Section section, const Name& name,
133 const RRClass& rrclass, const RRType& rrtype,
134 const RRTTL& ttl, const Rdata& rdata);
135 void addTSIG(Message::Section section, unsigned int count,
136 const InputBuffer& buffer, size_t start_position,
137 const Name& name, const RRClass& rrclass,
138 const RRTTL& ttl, const Rdata& rdata);
139 void toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx);
140};
141
143typedef boost::shared_ptr<MessageImpl> MessageImplPtr;
144
146 mode_(mode),
147 rcode_placeholder_(Rcode(0)), // for placeholders the value doesn't matter
148 opcode_placeholder_(Opcode(0)) {
149 init();
150}
151
152void
154 flags_ = 0;
155 qid_ = 0;
156 rcode_ = NULL;
157 opcode_ = NULL;
158 edns_ = EDNSPtr();
160
161 for (int i = 0; i < NUM_SECTIONS; ++i) {
162 counts_[i] = 0;
163 }
164
165 header_parsed_ = false;
166 questions_.clear();
170}
171
172void
174 opcode_placeholder_ = opcode;
176}
177
178void
180 rcode_placeholder_ = rcode;
182}
183
184namespace {
185// This helper class is used by MessageImpl::toWire() to render a set of
186// RRsets of a specific section of message to a given MessageRenderer.
187//
188// A RenderSection object is expected to be used with a QuestionIterator or
189// SectionIterator. Its operator() is called for each RRset as the iterator
190// iterates over the corresponding section, and it renders the RRset to
191// the given MessageRenderer, while counting the number of RRs (note: not
192// RRsets) successfully rendered. If the MessageRenderer reports the need
193// for truncation (via its isTruncated() method), the RenderSection object
194// stops rendering further RRsets. In addition, unless partial_ok (given on
195// construction) is true, it removes any RRs that are partially rendered
196// from the MessageRenderer.
197//
198// On the completion of rendering the entire section, the owner of the
199// RenderSection object can get the number of rendered RRs via the
200// getTotalCount() method.
201template <typename T>
202struct RenderSection {
203 RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
204 counter_(0), renderer_(renderer), partial_ok_(partial_ok),
205 truncated_(false) {
206 }
207
208 void operator()(const T& entry) {
209 // If it's already truncated, ignore the rest of the section.
210 if (truncated_) {
211 return;
212 }
213 const size_t pos0 = renderer_.getLength();
214 counter_ += entry->toWire(renderer_);
215 if (renderer_.isTruncated()) {
216 truncated_ = true;
217 if (!partial_ok_) {
218 // roll back to the end of the previous RRset.
219 renderer_.trim(renderer_.getLength() - pos0);
220 }
221 }
222 }
223
224 unsigned int getTotalCount() {
225 return (counter_);
226 }
227
228 unsigned int counter_;
229
231
232 const bool partial_ok_;
233
235};
236}
237
238void
240 if (mode_ != Message::RENDER) {
242 "Message rendering attempted in non render mode");
243 }
244 if (rcode_ == NULL) {
246 "Message rendering attempted without Rcode set");
247 }
248 if (opcode_ == NULL) {
250 "Message rendering attempted without Opcode set");
251 }
252
253 // Reserve the space for TSIG (if needed) so that we can handle truncation
254 // case correctly later when that happens. orig_xxx variables remember
255 // some configured parameters of renderer in case they are needed in
256 // truncation processing below.
257 const size_t tsig_len = (tsig_ctx != NULL) ? tsig_ctx->getTSIGLength() : 0;
258 const size_t orig_msg_len_limit = renderer.getLengthLimit();
259 const AbstractMessageRenderer::CompressMode orig_compress_mode =
260 renderer.getCompressMode();
261
262 // We are going to skip soon, so we need to clear the renderer
263 // But we'll leave the length limit and the compress mode intact
264 // (or shortened in case of TSIG)
265 renderer.clear();
266 renderer.setCompressMode(orig_compress_mode);
267
268 if (tsig_len > 0) {
269 if (tsig_len > orig_msg_len_limit) {
270 isc_throw(InvalidParameter, "Failed to render DNS message: "
271 "too small limit for a TSIG (" <<
272 orig_msg_len_limit << ")");
273 }
274 renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
275 } else {
276 renderer.setLengthLimit(orig_msg_len_limit);
277 }
278
279 // reserve room for the header
280 if (renderer.getLengthLimit() < HEADERLEN) {
281 isc_throw(InvalidParameter, "Failed to render DNS message: "
282 "too small limit for a Header");
283 }
284 renderer.skip(HEADERLEN);
285
286 uint16_t qdcount =
287 for_each(questions_.begin(), questions_.end(),
288 RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
289
290 // TODO: sort RRsets in each section based on configuration policy.
291 uint16_t ancount = 0;
292 if (!renderer.isTruncated()) {
293 ancount =
294 for_each(rrsets_[Message::SECTION_ANSWER].begin(),
296 RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
297 }
298 uint16_t nscount = 0;
299 if (!renderer.isTruncated()) {
300 nscount =
301 for_each(rrsets_[Message::SECTION_AUTHORITY].begin(),
303 RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
304 }
305 uint16_t arcount = 0;
306 if (renderer.isTruncated()) {
308 } else {
309 arcount =
310 for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
312 RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
313 }
314
315 // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
316 // has been explicitly set. However, if the RCODE would require it and
317 // no EDNS has been set we generate a temporary local EDNS and use it.
318 if (!renderer.isTruncated()) {
319 ConstEDNSPtr local_edns = edns_;
320 if (!local_edns && rcode_->getExtendedCode() != 0) {
321 local_edns = ConstEDNSPtr(new EDNS());
322 }
323 if (local_edns) {
324 arcount += local_edns->toWire(renderer, rcode_->getExtendedCode());
325 }
326 }
327
328 // If we're adding a TSIG to a truncated message, clear all RRsets
329 // from the message except for the question before adding the TSIG.
330 // If even (some of) the question doesn't fit, don't include it.
331 if (tsig_ctx != NULL && renderer.isTruncated()) {
332 renderer.clear();
333 renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
334 renderer.setCompressMode(orig_compress_mode);
335 renderer.skip(HEADERLEN);
336 qdcount = for_each(questions_.begin(), questions_.end(),
337 RenderSection<QuestionPtr>(renderer,
338 false)).getTotalCount();
339 ancount = 0;
340 nscount = 0;
341 arcount = 0;
342 }
343
344 // Adjust the counter buffer.
345 // XXX: these may not be equal to the number of corresponding entries
346 // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
347 // was inserted. This is not good, and we should revisit the entire
348 // design.
353
354 // fill in the header
355 size_t header_pos = 0;
356 renderer.writeUint16At(qid_, header_pos);
357 header_pos += sizeof(uint16_t);
358
359 uint16_t codes_and_flags =
360 (opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
361 codes_and_flags |= (rcode_->getCode() & RCODE_MASK);
362 codes_and_flags |= (flags_ & HEADERFLAG_MASK);
363 renderer.writeUint16At(codes_and_flags, header_pos);
364 header_pos += sizeof(uint16_t);
365 // TODO: should avoid repeated pattern
366 renderer.writeUint16At(qdcount, header_pos);
367 header_pos += sizeof(uint16_t);
368 renderer.writeUint16At(ancount, header_pos);
369 header_pos += sizeof(uint16_t);
370 renderer.writeUint16At(nscount, header_pos);
371 header_pos += sizeof(uint16_t);
372 renderer.writeUint16At(arcount, header_pos);
373
374 // Add TSIG, if necessary, at the end of the message.
375 if (tsig_ctx != NULL) {
376 // Release the reserved space in the renderer.
377 renderer.setLengthLimit(orig_msg_len_limit);
378
379 const int tsig_count =
380 tsig_ctx->sign(qid_, renderer.getData(),
381 renderer.getLength())->toWire(renderer);
382 if (tsig_count != 1) {
383 isc_throw(Unexpected, "Failed to render a TSIG RR");
384 }
385
386 // update the ARCOUNT for the TSIG RR. Note that for a sane DNS
387 // message arcount should never overflow to 0.
388 renderer.writeUint16At(++arcount, header_pos);
389 }
390}
391
393 impl_(new MessageImpl(mode)) {
394}
395
396bool
398 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
400 "Message::getHeaderFlag:: Invalid flag is specified: " <<
401 "0x" << std::hex << flag);
402 }
403 return ((impl_->flags_ & flag) != 0);
404}
405
406void
407Message::setHeaderFlag(const HeaderFlag flag, const bool on) {
408 if (impl_->mode_ != Message::RENDER) {
410 "setHeaderFlag performed in non-render mode");
411 }
412 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
414 "Message::getHeaderFlag:: Invalid flag is specified: " <<
415 "0x" << std::hex << static_cast<int>(flag));
416 }
417 if (on) {
418 impl_->flags_ |= flag;
419 } else {
420 impl_->flags_ &= ~flag;
421 }
422}
423
424qid_t
426 return (impl_->qid_);
427}
428
429void
431 if (impl_->mode_ != Message::RENDER) {
433 "setQid performed in non-render mode");
434 }
435 impl_->qid_ = qid;
436}
437
438const Rcode&
440 if (impl_->rcode_ == NULL) {
441 isc_throw(InvalidMessageOperation, "getRcode attempted before set");
442 }
443 return (*impl_->rcode_);
444}
445
446void
448 if (impl_->mode_ != Message::RENDER) {
450 "setRcode performed in non-render mode");
451 }
452 impl_->setRcode(rcode);
453}
454
455const Opcode&
457 if (impl_->opcode_ == NULL) {
458 isc_throw(InvalidMessageOperation, "getOpcode attempted before set");
459 }
460 return (*impl_->opcode_);
461}
462
463void
465 if (impl_->mode_ != Message::RENDER) {
467 "setOpcode performed in non-render mode");
468 }
469 impl_->setOpcode(opcode);
470}
471
474 return (impl_->edns_);
475}
476
477void
479 if (impl_->mode_ != Message::RENDER) {
481 "setEDNS performed in non-render mode");
482 }
483 impl_->edns_ = edns;
484}
485
486const TSIGRecord*
488 if (impl_->mode_ != Message::PARSE) {
490 "getTSIGRecord performed in non-parse mode");
491 }
492
493 return (impl_->tsig_rr_.get());
494}
495
496unsigned int
497Message::getRRCount(const Section section) const {
498 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
499 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
500 }
501 return (impl_->counts_[section]);
502}
503
504void
505Message::addRRset(const Section section, RRsetPtr rrset) {
506 if (!rrset) {
508 "NULL RRset is given to Message::addRRset");
509 }
510 if (impl_->mode_ != Message::RENDER) {
512 "addRRset performed in non-render mode");
513 }
514 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
515 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
516 }
517
518 impl_->rrsets_[section].push_back(rrset);
519 impl_->counts_[section] += rrset->getRdataCount();
520 impl_->counts_[section] += rrset->getRRsigDataCount();
521}
522
523bool
524Message::hasRRset(const Section section, const Name& name,
525 const RRClass& rrclass, const RRType& rrtype) const {
526 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
527 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
528 }
529
530 BOOST_FOREACH(ConstRRsetPtr r, impl_->rrsets_[section]) {
531 if (r->getClass() == rrclass &&
532 r->getType() == rrtype &&
533 r->getName() == name) {
534 return (true);
535 }
536 }
537
538 return (false);
539}
540
541bool
542Message::hasRRset(const Section section, const RRsetPtr& rrset) const {
543 return (hasRRset(section, rrset->getName(),
544 rrset->getClass(), rrset->getType()));
545}
546
547bool
548Message::removeRRset(const Section section, RRsetIterator& iterator) {
549 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
550 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
551 }
552
553 bool removed = false;
554 for (vector<RRsetPtr>::iterator i = impl_->rrsets_[section].begin();
555 i != impl_->rrsets_[section].end(); ++i) {
556 if (((*i)->getName() == (*iterator)->getName()) &&
557 ((*i)->getClass() == (*iterator)->getClass()) &&
558 ((*i)->getType() == (*iterator)->getType())) {
559
560 // Found the matching RRset so remove it & ignore rest
561 impl_->counts_[section] -= (*iterator)->getRdataCount();
562 impl_->counts_[section] -= (*iterator)->getRRsigDataCount();
563 impl_->rrsets_[section].erase(i);
564 removed = true;
565 break;
566 }
567 }
568
569 return (removed);
570}
571
572void
574 if (impl_->mode_ != Message::RENDER) {
576 "clearSection performed in non-render mode");
577 }
578 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
579 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
580 }
581 if (section == Message::SECTION_QUESTION) {
582 impl_->questions_.clear();
583 } else {
584 impl_->rrsets_[section].clear();
585 }
586 impl_->counts_[section] = 0;
587}
588
589void
591 if (impl_->mode_ != Message::RENDER) {
593 "addQuestion performed in non-render mode");
594 }
595
596 impl_->questions_.push_back(question);
597 ++impl_->counts_[SECTION_QUESTION];
598}
599
600void
602 addQuestion(QuestionPtr(new Question(question)));
603}
604
605void
607 impl_->toWire(renderer, tsig_ctx);
608}
609
610void
612 if (impl_->mode_ != Message::PARSE) {
614 "Message parse attempted in non parse mode");
615 }
616
617 if (impl_->header_parsed_) {
618 return;
619 }
620
621 if ((buffer.getLength() - buffer.getPosition()) < HEADERLEN) {
622 isc_throw(MessageTooShort, "Malformed DNS message (short length): "
623 << buffer.getLength() - buffer.getPosition());
624 }
625
626 impl_->qid_ = buffer.readUint16();
627 const uint16_t codes_and_flags = buffer.readUint16();
628 impl_->setOpcode(Opcode((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT));
629 impl_->setRcode(Rcode(codes_and_flags & RCODE_MASK));
630 impl_->flags_ = (codes_and_flags & HEADERFLAG_MASK);
631 impl_->counts_[SECTION_QUESTION] = buffer.readUint16();
632 impl_->counts_[SECTION_ANSWER] = buffer.readUint16();
633 impl_->counts_[SECTION_AUTHORITY] = buffer.readUint16();
634 impl_->counts_[SECTION_ADDITIONAL] = buffer.readUint16();
635
636 impl_->header_parsed_ = true;
637}
638
639void
641 if (impl_->mode_ != Message::PARSE) {
643 "Message parse attempted in non parse mode");
644 }
645
646 // Clear any old parsed data
648
649 buffer.setPosition(0);
650 parseHeader(buffer);
651
652 impl_->counts_[SECTION_QUESTION] = impl_->parseQuestion(buffer);
653 impl_->counts_[SECTION_ANSWER] =
654 impl_->parseSection(SECTION_ANSWER, buffer, options);
655 impl_->counts_[SECTION_AUTHORITY] =
656 impl_->parseSection(SECTION_AUTHORITY, buffer, options);
657 impl_->counts_[SECTION_ADDITIONAL] =
658 impl_->parseSection(SECTION_ADDITIONAL, buffer, options);
659}
660
661int
663 unsigned int added = 0;
664
665 for (unsigned int count = 0;
667 ++count) {
668 const Name name(buffer);
669
670 if ((buffer.getLength() - buffer.getPosition()) <
671 2 * sizeof(uint16_t)) {
672 isc_throw(DNSMessageFORMERR, "Question section too short: " <<
673 (buffer.getLength() - buffer.getPosition()) << " bytes");
674 }
675 const RRType rrtype(buffer.readUint16());
676 const RRClass rrclass(buffer.readUint16());
677
678 // XXX: need a duplicate check. We might also want to have an
679 // optimized algorithm that requires the question section contain
680 // exactly one RR.
681
682 questions_.push_back(QuestionPtr(new Question(name, rrclass, rrtype)));
683 ++added;
684 }
685
686 return (added);
687}
688
689namespace {
690struct MatchRR {
691 MatchRR(const Name& name, const RRType& rrtype, const RRClass& rrclass) :
692 name_(name), rrtype_(rrtype), rrclass_(rrclass) {
693 }
694
695 bool operator()(const RRsetPtr& rrset) const {
696 return (rrset->getType() == rrtype_ &&
697 rrset->getClass() == rrclass_ &&
698 rrset->getName() == name_);
699 }
700
701 const Name& name_;
702
704
706};
707}
708
709// Note about design decision:
710// we need some type specific processing here, including EDNS and TSIG.
711// how much we should generalize/hardcode the special logic is subject
712// to discussion. In terms of modularity it would be ideal to introduce
713// an abstract class (say "MessageAttribute") and let other such
714// concrete notions as EDNS or TSIG inherit from it. Then we would
715// just do:
716// message->addAttribute(rrtype, rrclass, buffer);
717// to create and attach type-specific concrete object to the message.
718//
719// A major downside of this approach is, as usual, complexity due to
720// indirection and performance penalty. Also, it may not be so easy
721// to separate the processing logic because in many cases we'll need
722// parse context for which the message class is responsible (e.g.
723// to check the EDNS OPT RR only appears in the additional section,
724// and appears only once).
725//
726// Another point to consider is that we may not need so many special
727// types other than EDNS and TSIG (and when and if we implement it,
728// SIG(0)); newer optional attributes of the message would more likely
729// be standardized as new flags or options of EDNS. If that's the case,
730// introducing an abstract class with all the overhead and complexity
731// may not make much sense.
732//
733// Conclusion: don't over-generalize type-specific logic for now.
734// introduce separate concrete classes, and move context-independent
735// logic to that class; processing logic dependent on parse context
736// is hardcoded here.
737int
739 InputBuffer& buffer, Message::ParseOptions options) {
740 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
741 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
742 }
743
744 unsigned int added = 0;
745
746 for (unsigned int count = 0; count < counts_[section]; ++count) {
747 // We need to remember the start position for TSIG processing
748 const size_t start_position = buffer.getPosition();
749
750 const Name name(buffer);
751
752 // buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
753 if ((buffer.getLength() - buffer.getPosition()) <
754 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
755 isc_throw(DNSMessageFORMERR, sectiontext[section] <<
756 " section too short: " <<
757 (buffer.getLength() - buffer.getPosition()) << " bytes");
758 }
759
760 const RRType rrtype(buffer.readUint16());
761 const RRClass rrclass(buffer.readUint16());
762 const RRTTL ttl(buffer.readUint32());
763 const size_t rdlen = buffer.readUint16();
764
765 // If class is ANY or NONE, rdlength may be zero, to signal
766 // an empty RRset.
767 // (the class check must be done to differentiate from RRTypes
768 // that can have zero length rdata
769 if ((rrclass == RRClass::ANY() || rrclass == RRClass::NONE()) &&
770 rdlen == 0) {
771 addRR(section, name, rrclass, rrtype, ttl, options);
772 ++added;
773 continue;
774 }
775 ConstRdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
776
777 if (rrtype == RRType::OPT()) {
778 addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
779 } else if (rrtype == RRType::TSIG()) {
780 addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
781 *rdata);
782 } else {
783 addRR(section, name, rrclass, rrtype, ttl, rdata, options);
784 ++added;
785 }
786 }
787
788 return (added);
789}
790
791void
793 const RRClass& rrclass, const RRType& rrtype,
794 const RRTTL& ttl, ConstRdataPtr rdata,
795 Message::ParseOptions options) {
796 if ((options & Message::PRESERVE_ORDER) == 0) {
797 vector<RRsetPtr>::iterator it =
798 find_if(rrsets_[section].begin(), rrsets_[section].end(),
799 MatchRR(name, rrtype, rrclass));
800 if (it != rrsets_[section].end()) {
801 (*it)->setTTL(min((*it)->getTTL(), ttl));
802 (*it)->addRdata(rdata);
803 return;
804 }
805 }
806 RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
807 rrset->addRdata(rdata);
808 rrsets_[section].push_back(rrset);
809}
810
811void
813 const RRClass& rrclass, const RRType& rrtype,
814 const RRTTL& ttl, Message::ParseOptions options) {
815 if ((options & Message::PRESERVE_ORDER) == 0) {
816 vector<RRsetPtr>::iterator it =
817 find_if(rrsets_[section].begin(), rrsets_[section].end(),
818 MatchRR(name, rrtype, rrclass));
819 if (it != rrsets_[section].end()) {
820 (*it)->setTTL(min((*it)->getTTL(), ttl));
821 return;
822 }
823 }
824 RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
825 rrsets_[section].push_back(rrset);
826}
827
828void
830 const RRClass& rrclass, const RRType& rrtype,
831 const RRTTL& ttl, const Rdata& rdata) {
832 if (section != Message::SECTION_ADDITIONAL) {
834 "EDNS OPT RR found in an invalid section");
835 }
836 if (edns_) {
837 isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
838 }
839
840 uint8_t extended_rcode;
841 edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl, rdata,
842 extended_rcode));
843 setRcode(Rcode(rcode_->getCode(), extended_rcode));
844}
845
846void
847MessageImpl::addTSIG(Message::Section section, unsigned int count,
848 const InputBuffer& buffer, size_t start_position,
849 const Name& name, const RRClass& rrclass,
850 const RRTTL& ttl, const Rdata& rdata) {
851 if (section != Message::SECTION_ADDITIONAL) {
853 "TSIG RR found in an invalid section");
854 }
855 if (count != counts_[section] - 1) {
856 isc_throw(DNSMessageFORMERR, "TSIG RR is not the last record");
857 }
858 // This check will never fail as the multiple TSIG RR case is
859 // caught before by the not the last record check...
860 if (tsig_rr_) {
861 isc_throw(DNSMessageFORMERR, "multiple TSIG RRs found");
862 }
863 tsig_rr_ = ConstTSIGRecordPtr(new TSIGRecord(name, rrclass,
864 ttl, rdata,
865 buffer.getPosition() -
866 start_position));
867}
868
869namespace {
870template <typename T>
871struct SectionFormatter {
872 SectionFormatter(const Message::Section section, string& output) :
873 section_(section), output_(output) {
874 }
875
876 void operator()(const T& entry) {
878 output_ += ";";
879 output_ += entry->toText();
880 output_ += "\n";
881 } else {
882 output_ += entry->toText();
883 }
884 }
885
887
888 string& output_;
889};
890}
891
892string
894 if (impl_->rcode_ == NULL) {
896 "Message::toText() attempted without Rcode set");
897 }
898 if (impl_->opcode_ == NULL) {
900 "Message::toText() attempted without Opcode set");
901 }
902
903 string s;
904
905 s += ";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
906 // for simplicity we don't consider extended rcode (unlike BIND9)
907 s += ", status: " + impl_->rcode_->toText();
908 s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
909 s += "\n;; flags:";
911 s += " qr";
912 }
914 s += " aa";
915 }
917 s += " tc";
918 }
920 s += " rd";
921 }
923 s += " ra";
924 }
926 s += " ad";
927 }
929 s += " cd";
930 }
931
932 // for simplicity, don't consider the update case for now
933 s += "; QUERY: " + // note: not "QUESTION" to be compatible with BIND 9 dig
934 lexical_cast<string>(impl_->counts_[SECTION_QUESTION]);
935 s += ", ANSWER: " +
936 lexical_cast<string>(impl_->counts_[SECTION_ANSWER]);
937 s += ", AUTHORITY: " +
938 lexical_cast<string>(impl_->counts_[SECTION_AUTHORITY]);
939
940 unsigned int arcount = impl_->counts_[SECTION_ADDITIONAL];
941 if (impl_->edns_ != NULL) {
942 ++arcount;
943 }
944 if (impl_->tsig_rr_ != NULL) {
945 ++arcount;
946 }
947 s += ", ADDITIONAL: " + lexical_cast<string>(arcount) + "\n";
948
949 if (impl_->edns_ != NULL) {
950 s += "\n;; OPT PSEUDOSECTION:\n";
951 s += impl_->edns_->toText();
952 }
953
954 if (!impl_->questions_.empty()) {
955 s += "\n;; " +
956 string(sectiontext[SECTION_QUESTION]) + " SECTION:\n";
957 for_each(impl_->questions_.begin(), impl_->questions_.end(),
958 SectionFormatter<QuestionPtr>(SECTION_QUESTION, s));
959 }
960 if (!impl_->rrsets_[SECTION_ANSWER].empty()) {
961 s += "\n;; " +
962 string(sectiontext[SECTION_ANSWER]) + " SECTION:\n";
963 for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
964 impl_->rrsets_[SECTION_ANSWER].end(),
965 SectionFormatter<RRsetPtr>(SECTION_ANSWER, s));
966 }
967 if (!impl_->rrsets_[SECTION_AUTHORITY].empty()) {
968 s += "\n;; " +
969 string(sectiontext[SECTION_AUTHORITY]) + " SECTION:\n";
970 for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
971 impl_->rrsets_[SECTION_AUTHORITY].end(),
972 SectionFormatter<RRsetPtr>(SECTION_AUTHORITY, s));
973 }
974 if (!impl_->rrsets_[SECTION_ADDITIONAL].empty()) {
975 s += "\n;; " +
976 string(sectiontext[SECTION_ADDITIONAL]) +
977 " SECTION:\n";
978 for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
979 impl_->rrsets_[SECTION_ADDITIONAL].end(),
980 SectionFormatter<RRsetPtr>(SECTION_ADDITIONAL, s));
981 }
982
983 if (impl_->tsig_rr_ != NULL) {
984 s += "\n;; TSIG PSEUDOSECTION:\n";
985 s += impl_->tsig_rr_->toText();
986 }
987
988 return (s);
989}
990
991void
993 impl_->init();
994 impl_->mode_ = mode;
995}
996
997void
998Message::appendSection(const Section section, const Message& source) {
999 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
1000 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
1001 }
1002
1003 if (section == SECTION_QUESTION) {
1004 for (QuestionIterator qi = source.beginQuestion();
1005 qi != source.endQuestion();
1006 ++qi) {
1007 addQuestion(*qi);
1008 }
1009 } else {
1010 for (RRsetIterator rrsi = source.beginSection(section);
1011 rrsi != source.endSection(section);
1012 ++rrsi) {
1013 addRRset(section, *rrsi);
1014 }
1015 }
1016}
1017
1018void
1020 if (impl_->mode_ != Message::PARSE) {
1022 "makeResponse() is performed in non-parse mode");
1023 }
1024
1025 impl_->mode_ = Message::RENDER;
1026
1027 impl_->edns_ = EDNSPtr();
1028 impl_->flags_ &= MESSAGE_REPLYPRESERVE;
1030
1031 impl_->rrsets_[SECTION_ANSWER].clear();
1032 impl_->counts_[SECTION_ANSWER] = 0;
1033 impl_->rrsets_[SECTION_AUTHORITY].clear();
1034 impl_->counts_[SECTION_AUTHORITY] = 0;
1035 impl_->rrsets_[SECTION_ADDITIONAL].clear();
1036 impl_->counts_[SECTION_ADDITIONAL] = 0;
1037}
1038
1042template <typename T>
1044 SectionIteratorImpl(const typename vector<T>::const_iterator& it) :
1045 it_(it) {
1046 }
1047
1048 typename vector<T>::const_iterator it_;
1049};
1050
1051template <typename T>
1053 impl_ = new SectionIteratorImpl<T>(impl.it_);
1054}
1055
1056template <typename T>
1058 delete impl_;
1059}
1060
1061template <typename T>
1063 impl_(new SectionIteratorImpl<T>(source.impl_->it_)) {
1064}
1065
1066template <typename T>
1067void
1069 if (impl_ == source.impl_) {
1070 return;
1071 }
1072 SectionIteratorImpl<T>* newimpl =
1073 new SectionIteratorImpl<T>(source.impl_->it_);
1074 delete impl_;
1075 impl_ = newimpl;
1076}
1077
1078template <typename T>
1081 ++(impl_->it_);
1082 return (*this);
1083}
1084
1085template <typename T>
1088 SectionIterator<T> tmp(*this);
1089 ++(*this);
1090 return (tmp);
1091}
1092
1093template <typename T>
1094const T&
1096 return (*(impl_->it_));
1097}
1098
1099template <typename T>
1100const T*
1102 return (&(operator*()));
1103}
1104
1105template <typename T>
1106bool
1108 return (impl_->it_ == other.impl_->it_);
1109}
1110
1111template <typename T>
1112bool
1114 return (impl_->it_ != other.impl_->it_);
1115}
1116
1121template class SectionIterator<QuestionPtr>;
1122template class SectionIterator<RRsetPtr>;
1123
1124namespace {
1125typedef SectionIteratorImpl<QuestionPtr> QuestionIteratorImpl;
1126typedef SectionIteratorImpl<RRsetPtr> RRsetIteratorImpl;
1127}
1128
1132const QuestionIterator
1134 return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
1135}
1136
1137const QuestionIterator
1139 return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.end())));
1140}
1141
1146Message::beginSection(const Section section) const {
1147 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
1148 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
1149 }
1150 if (section == SECTION_QUESTION) {
1152 "RRset iterator is requested for question");
1153 }
1154
1155 return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].begin())));
1156}
1157
1159Message::endSection(const Section section) const {
1160 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
1161 isc_throw(OutOfRange, "Invalid message section: " << static_cast<int>(section));
1162 }
1163 if (section == SECTION_QUESTION) {
1165 "RRset iterator is requested for question");
1166 }
1167
1168 return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].end())));
1169}
1170
1171ostream&
1172operator<<(ostream& os, const Message& message) {
1173 return (os << message.toText());
1174}
1175} // end of namespace dns
1176} // end of namespace isc
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
virtual void setLengthLimit(size_t len)=0
Set the maximum length of rendered data that can fit in the corresponding DNS message without truncat...
size_t getLength() const
Return the length of data written in the internal buffer.
virtual void clear()
Clear the internal buffer and other internal resources.
virtual size_t getLengthLimit() const =0
Return the maximum length of rendered data that can fit in the corresponding DNS message without trun...
virtual void setCompressMode(CompressMode mode)=0
Set the compression mode of the renderer class object.
const void * getData() const
Return a pointer to the head of the data stored in the internal buffer.
virtual CompressMode getCompressMode() const =0
Return the compression mode of the renderer class object.
virtual bool isTruncated() const =0
Return whether truncation has occurred while rendering.
void skip(size_t len)
Insert a specified length of gap at the end of the buffer.
void writeUint16At(uint16_t data, size_t pos)
Write an unsigned 16-bit integer in host byte order at the specified position of the internal buffer ...
CompressMode
Compression mode constants.
The EDNS class represents the EDNS OPT RR defined in RFC2671.
Definition: edns.h:123
A standard DNS module exception that is thrown if a Message class method is called that is prohibited...
Definition: message.h:58
A standard DNS module exception that is thrown if a section iterator is being constructed for an inco...
Definition: message.h:47
const Opcode * opcode_
Definition: dns/message.cc:102
void toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx)
Definition: dns/message.cc:239
void addRR(Message::Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, ConstRdataPtr rdata, Message::ParseOptions options)
Definition: dns/message.cc:792
static const unsigned int NUM_SECTIONS
Definition: dns/message.cc:108
const Rcode * rcode_
Definition: dns/message.cc:100
vector< QuestionPtr > questions_
Definition: dns/message.cc:110
vector< RRsetPtr > rrsets_[NUM_SECTIONS]
Definition: dns/message.cc:111
int parseSection(const Message::Section section, InputBuffer &buffer, Message::ParseOptions options)
Definition: dns/message.cc:738
MessageImpl(Message::Mode mode)
Definition: dns/message.cc:145
void setOpcode(const Opcode &opcode)
Definition: dns/message.cc:173
void addTSIG(Message::Section section, unsigned int count, const InputBuffer &buffer, size_t start_position, const Name &name, const RRClass &rrclass, const RRTTL &ttl, const Rdata &rdata)
Definition: dns/message.cc:847
void addEDNS(Message::Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, const Rdata &rdata)
Definition: dns/message.cc:829
ConstTSIGRecordPtr tsig_rr_
Definition: dns/message.cc:113
int parseQuestion(InputBuffer &buffer)
Definition: dns/message.cc:662
void setRcode(const Rcode &rcode)
Definition: dns/message.cc:179
int counts_[NUM_SECTIONS]
Definition: dns/message.cc:109
Message::Mode mode_
Definition: dns/message.cc:93
A standard DNS module exception that is thrown if a wire format message parser encounters a short len...
Definition: message.h:36
The Message class encapsulates a standard DNS message.
Definition: message.h:154
const QuestionIterator beginQuestion() const
Return an iterator corresponding to the beginning of the Question section of the message.
const QuestionIterator endQuestion() const
Return an iterator corresponding to the end of the Question section of the message.
HeaderFlag
Constants for flag bit fields of a DNS message header.
Definition: message.h:204
@ HEADERFLAG_RD
Recursion desired.
Definition: message.h:208
@ HEADERFLAG_TC
Truncation.
Definition: message.h:207
@ HEADERFLAG_AA
Authoritative answer.
Definition: message.h:206
@ HEADERFLAG_RA
Recursion available.
Definition: message.h:209
@ HEADERFLAG_CD
DNSSEC checking disabled (RFC4035)
Definition: message.h:211
@ HEADERFLAG_QR
Query (if cleared) or response (if set)
Definition: message.h:205
@ HEADERFLAG_AD
Authentic data (RFC4035)
Definition: message.h:210
const Rcode & getRcode() const
Return the Response Code of the message.
Definition: dns/message.cc:439
bool getHeaderFlag(const HeaderFlag flag) const
Return whether the specified header flag bit is set in the header section.
Definition: dns/message.cc:397
void clear(Mode mode)
Clear the message content (if any) and reinitialize it in the specified mode.
Definition: dns/message.cc:992
Section
Constants to specify sections of a DNS message.
Definition: message.h:244
@ SECTION_ADDITIONAL
Additional section.
Definition: message.h:248
@ SECTION_AUTHORITY
Authority section.
Definition: message.h:247
@ SECTION_ANSWER
Answer section.
Definition: message.h:246
@ SECTION_QUESTION
Question section
Definition: message.h:245
void clearSection(const Section section)
Remove all RRSets from the given Section.
Definition: dns/message.cc:573
ParseOptions
Parse options.
Definition: message.h:598
@ PRESERVE_ORDER
Preserve RR order and don't combine them.
Definition: message.h:600
Mode
Constants to specify the operation mode of the Message.
Definition: message.h:157
@ RENDER
Render mode (building an outgoing message)
Definition: message.h:159
@ PARSE
Parse mode (handling an incoming message)
Definition: message.h:158
unsigned int getRRCount(const Section section) const
Returns the number of RRs contained in the given section.
Definition: dns/message.cc:497
void setOpcode(const Opcode &opcode)
Set the OPCODE of the header section of the message.
Definition: dns/message.cc:464
bool removeRRset(const Section section, RRsetIterator &iterator)
Remove RRSet from Message.
Definition: dns/message.cc:548
void addRRset(const Section section, RRsetPtr rrset)
Add a (pointer like object of) RRset to the given section of the message.
Definition: dns/message.cc:505
void fromWire(isc::util::InputBuffer &buffer, ParseOptions options=PARSE_DEFAULT)
(Re)build a Message object from wire-format data.
Definition: dns/message.cc:640
const RRsetIterator endSection(const Section section) const
Return an iterator corresponding to the end of the given section (other than Question) of the message...
const TSIGRecord * getTSIGRecord() const
Return, if any, the TSIG record contained in the received message.
Definition: dns/message.cc:487
std::string toText() const
Convert the Message to a string.
Definition: dns/message.cc:893
void makeResponse()
Prepare for making a response from a request.
void setHeaderFlag(const HeaderFlag flag, const bool on=true)
Set or clear the specified header flag bit in the header section.
Definition: dns/message.cc:407
ConstEDNSPtr getEDNS() const
Return, if any, the EDNS associated with the message.
Definition: dns/message.cc:473
const Opcode & getOpcode() const
Return the OPCODE given in the header section of the message.
Definition: dns/message.cc:456
void parseHeader(isc::util::InputBuffer &buffer)
Parse the header section of the Message.
Definition: dns/message.cc:611
bool hasRRset(const Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype) const
Determine whether the given section already has an RRset matching the given name, RR class and RR typ...
Definition: dns/message.cc:524
void appendSection(const Section section, const Message &source)
Adds all rrsets from the source the given section in the source message to the same section of this m...
Definition: dns/message.cc:998
void addQuestion(QuestionPtr question)
Add a (pointer like object of) Question to the message.
Definition: dns/message.cc:590
void setQid(qid_t qid)
Set the query ID of the header section of the message.
Definition: dns/message.cc:430
qid_t getQid() const
Return the query ID given in the header section of the message.
Definition: dns/message.cc:425
const RRsetIterator beginSection(const Section section) const
Return an iterator corresponding to the beginning of the given section (other than Question) of the m...
void setRcode(const Rcode &rcode)
Set the Response Code of the message.
Definition: dns/message.cc:447
Message(Mode mode)
The constructor.
Definition: dns/message.cc:392
void toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx=NULL)
Render the message in wire formant into a message renderer object with (or without) TSIG.
Definition: dns/message.cc:606
void setEDNS(ConstEDNSPtr edns)
Set EDNS for the message.
Definition: dns/message.cc:478
The Name class encapsulates DNS names.
Definition: name.h:223
The Opcode class objects represent standard OPCODEs of the header section of DNS messages as defined ...
Definition: opcode.h:32
CodeValue getCode() const
Returns the Opcode code value.
Definition: opcode.h:78
The Question class encapsulates the common search key of DNS lookup, consisting of owner name,...
Definition: question.h:95
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:98
static const RRClass & ANY()
Definition: rrclass.h:301
static const RRClass & NONE()
Definition: rrclass.h:325
The RRTTL class encapsulates TTLs used in DNS resource records.
Definition: rrttl.h:55
The RRType class encapsulates DNS resource record types.
Definition: rrtype.h:106
static const RRType & TSIG()
Definition: rrtype.h:335
static const RRType & OPT()
Definition: rrtype.h:437
The RRset class is a concrete derived class of BasicRRset which contains a pointer to an additional R...
Definition: rrset.h:847
DNS Response Codes (RCODEs) class.
Definition: rcode.h:40
uint16_t getCode() const
Returns the Rcode code value.
Definition: rcode.h:106
uint8_t getExtendedCode() const
Returns the upper 8-bit of the Rcode code value.
Definition: rcode.cc:75
SectionIterator is a templated class to provide standard-compatible iterators for Questions and RRset...
Definition: message.h:91
const T & operator*() const
const T * operator->() const
bool operator!=(const SectionIterator< T > &other) const
bool operator==(const SectionIterator< T > &other) const
SectionIterator< T > & operator++()
void operator=(const SectionIterator< T > &source)
TSIG session context.
Definition: tsig.h:171
virtual ConstTSIGRecordPtr sign(const uint16_t qid, const void *const data, const size_t data_len)
Sign a DNS message.
Definition: tsig.cc:340
virtual size_t getTSIGLength() const
Return the expected length of TSIG RR after sign()
Definition: tsig.cc:291
TSIG resource record.
Definition: tsigrecord.h:54
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
Definition: rdata.h:123
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
uint32_t readUint32()
Read an unsigned 32-bit integer in network byte order from the buffer, convert it to host byte order,...
Definition: buffer.h:162
void setPosition(size_t position)
Set the read position of the buffer to the given value.
Definition: buffer.h:115
size_t getPosition() const
Return the current read position.
Definition: buffer.h:102
size_t getLength() const
Return the length of the data stored in the buffer.
Definition: buffer.h:100
uint16_t readUint16()
Read an unsigned 16-bit integer in network byte order from the buffer, convert it to host byte order,...
Definition: buffer.h:142
unsigned int counter_
Definition: dns/message.cc:228
const RRClass & rrclass_
Definition: dns/message.cc:705
AbstractMessageRenderer & renderer_
Definition: dns/message.cc:230
string & output_
Definition: dns/message.cc:888
const Name & name_
Definition: dns/message.cc:701
bool truncated_
Definition: dns/message.cc:234
const Message::Section section_
Definition: dns/message.cc:886
const RRType & rrtype_
Definition: dns/message.cc:703
const bool partial_ok_
Definition: dns/message.cc:232
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Rdata > ConstRdataPtr
Definition: rdata.h:72
RdataPtr createRdata(const RRType &rrtype, const RRClass &rrclass, const std::string &rdata_string)
Create RDATA of a given pair of RR type and class from a string.
Definition: rdata.cc:56
boost::shared_ptr< MessageImpl > MessageImplPtr
Pointer to the MessageImpl object.
Definition: dns/message.cc:143
boost::shared_ptr< const TSIGRecord > ConstTSIGRecordPtr
A pointer-like type pointing to an immutable TSIGRecord object.
Definition: tsigrecord.h:280
uint16_t qid_t
Definition: message.h:75
boost::shared_ptr< Question > QuestionPtr
A pointer-like type pointing to an Question object.
Definition: question.h:31
SectionIterator< QuestionPtr > QuestionIterator
Definition: message.h:115
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
Definition: rrset.h:53
ostream & operator<<(std::ostream &os, const EDNS &edns)
Insert the EDNS as a string into stream.
Definition: edns.cc:172
EDNS * createEDNSFromRR(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, const Rdata &rdata, uint8_t &extended_rcode)
Create a new EDNS object from a set of RR parameters, also providing the extended RCODE value.
Definition: edns.cc:157
boost::shared_ptr< const EDNS > ConstEDNSPtr
A pointer-like type pointing to an immutable EDNS object.
Definition: edns.h:37
boost::shared_ptr< EDNS > EDNSPtr
A pointer-like type pointing to an EDNS object.
Definition: edns.h:34
SectionIterator< RRsetPtr > RRsetIterator
Definition: message.h:116
boost::shared_ptr< const AbstractRRset > ConstRRsetPtr
A pointer-like type pointing to an (immutable) RRset object.
Definition: rrset.h:60
FlexOptionImplPtr impl
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
CompressMode mode_
Definition: rdatafields.cc:97
Template version of Section Iterator.
vector< T >::const_iterator it_
SectionIteratorImpl(const typename vector< T >::const_iterator &it)