Kea 2.2.0
dns/message.cc
Go to the documentation of this file.
1// Copyright (C) 2009-2022 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
143 mode_(mode),
144 rcode_placeholder_(Rcode(0)), // as a placeholder the value doesn't matter
145 opcode_placeholder_(Opcode(0)) // ditto
146{
147 init();
148}
149
150void
152 flags_ = 0;
153 qid_ = 0;
154 rcode_ = NULL;
155 opcode_ = NULL;
156 edns_ = EDNSPtr();
158
159 for (int i = 0; i < NUM_SECTIONS; ++i) {
160 counts_[i] = 0;
161 }
162
163 header_parsed_ = false;
164 questions_.clear();
168}
169
170void
172 opcode_placeholder_ = opcode;
174}
175
176void
178 rcode_placeholder_ = rcode;
180}
181
182namespace {
183// This helper class is used by MessageImpl::toWire() to render a set of
184// RRsets of a specific section of message to a given MessageRenderer.
185//
186// A RenderSection object is expected to be used with a QuestionIterator or
187// SectionIterator. Its operator() is called for each RRset as the iterator
188// iterates over the corresponding section, and it renders the RRset to
189// the given MessageRenderer, while counting the number of RRs (note: not
190// RRsets) successfully rendered. If the MessageRenderer reports the need
191// for truncation (via its isTruncated() method), the RenderSection object
192// stops rendering further RRsets. In addition, unless partial_ok (given on
193// construction) is true, it removes any RRs that are partially rendered
194// from the MessageRenderer.
195//
196// On the completion of rendering the entire section, the owner of the
197// RenderSection object can get the number of rendered RRs via the
198// getTotalCount() method.
199template <typename T>
200struct RenderSection {
201 RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
202 counter_(0), renderer_(renderer), partial_ok_(partial_ok),
203 truncated_(false)
204 {}
205 void operator()(const T& entry) {
206 // If it's already truncated, ignore the rest of the section.
207 if (truncated_) {
208 return;
209 }
210 const size_t pos0 = renderer_.getLength();
211 counter_ += entry->toWire(renderer_);
212 if (renderer_.isTruncated()) {
213 truncated_ = true;
214 if (!partial_ok_) {
215 // roll back to the end of the previous RRset.
216 renderer_.trim(renderer_.getLength() - pos0);
217 }
218 }
219 }
220 unsigned int getTotalCount() { return (counter_); }
221 unsigned int counter_;
222 AbstractMessageRenderer& renderer_;
223 const bool partial_ok_;
225};
226}
227
228void
230 if (mode_ != Message::RENDER) {
232 "Message rendering attempted in non render mode");
233 }
234 if (rcode_ == NULL) {
236 "Message rendering attempted without Rcode set");
237 }
238 if (opcode_ == NULL) {
240 "Message rendering attempted without Opcode set");
241 }
242
243 // Reserve the space for TSIG (if needed) so that we can handle truncation
244 // case correctly later when that happens. orig_xxx variables remember
245 // some configured parameters of renderer in case they are needed in
246 // truncation processing below.
247 const size_t tsig_len = (tsig_ctx != NULL) ? tsig_ctx->getTSIGLength() : 0;
248 const size_t orig_msg_len_limit = renderer.getLengthLimit();
249 const AbstractMessageRenderer::CompressMode orig_compress_mode =
250 renderer.getCompressMode();
251
252 // We are going to skip soon, so we need to clear the renderer
253 // But we'll leave the length limit and the compress mode intact
254 // (or shortened in case of TSIG)
255 renderer.clear();
256 renderer.setCompressMode(orig_compress_mode);
257
258 if (tsig_len > 0) {
259 if (tsig_len > orig_msg_len_limit) {
260 isc_throw(InvalidParameter, "Failed to render DNS message: "
261 "too small limit for a TSIG (" <<
262 orig_msg_len_limit << ")");
263 }
264 renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
265 } else {
266 renderer.setLengthLimit(orig_msg_len_limit);
267 }
268
269 // reserve room for the header
270 if (renderer.getLengthLimit() < HEADERLEN) {
271 isc_throw(InvalidParameter, "Failed to render DNS message: "
272 "too small limit for a Header");
273 }
274 renderer.skip(HEADERLEN);
275
276 uint16_t qdcount =
277 for_each(questions_.begin(), questions_.end(),
278 RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
279
280 // TODO: sort RRsets in each section based on configuration policy.
281 uint16_t ancount = 0;
282 if (!renderer.isTruncated()) {
283 ancount =
284 for_each(rrsets_[Message::SECTION_ANSWER].begin(),
286 RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
287 }
288 uint16_t nscount = 0;
289 if (!renderer.isTruncated()) {
290 nscount =
291 for_each(rrsets_[Message::SECTION_AUTHORITY].begin(),
293 RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
294 }
295 uint16_t arcount = 0;
296 if (renderer.isTruncated()) {
298 } else {
299 arcount =
300 for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
302 RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
303 }
304
305 // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
306 // has been explicitly set. However, if the RCODE would require it and
307 // no EDNS has been set we generate a temporary local EDNS and use it.
308 if (!renderer.isTruncated()) {
309 ConstEDNSPtr local_edns = edns_;
310 if (!local_edns && rcode_->getExtendedCode() != 0) {
311 local_edns = ConstEDNSPtr(new EDNS());
312 }
313 if (local_edns) {
314 arcount += local_edns->toWire(renderer, rcode_->getExtendedCode());
315 }
316 }
317
318 // If we're adding a TSIG to a truncated message, clear all RRsets
319 // from the message except for the question before adding the TSIG.
320 // If even (some of) the question doesn't fit, don't include it.
321 if (tsig_ctx != NULL && renderer.isTruncated()) {
322 renderer.clear();
323 renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
324 renderer.setCompressMode(orig_compress_mode);
325 renderer.skip(HEADERLEN);
326 qdcount = for_each(questions_.begin(), questions_.end(),
327 RenderSection<QuestionPtr>(renderer,
328 false)).getTotalCount();
329 ancount = 0;
330 nscount = 0;
331 arcount = 0;
332 }
333
334 // Adjust the counter buffer.
335 // XXX: these may not be equal to the number of corresponding entries
336 // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
337 // was inserted. This is not good, and we should revisit the entire
338 // design.
343
344 // fill in the header
345 size_t header_pos = 0;
346 renderer.writeUint16At(qid_, header_pos);
347 header_pos += sizeof(uint16_t);
348
349 uint16_t codes_and_flags =
350 (opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
351 codes_and_flags |= (rcode_->getCode() & RCODE_MASK);
352 codes_and_flags |= (flags_ & HEADERFLAG_MASK);
353 renderer.writeUint16At(codes_and_flags, header_pos);
354 header_pos += sizeof(uint16_t);
355 // TODO: should avoid repeated pattern
356 renderer.writeUint16At(qdcount, header_pos);
357 header_pos += sizeof(uint16_t);
358 renderer.writeUint16At(ancount, header_pos);
359 header_pos += sizeof(uint16_t);
360 renderer.writeUint16At(nscount, header_pos);
361 header_pos += sizeof(uint16_t);
362 renderer.writeUint16At(arcount, header_pos);
363
364 // Add TSIG, if necessary, at the end of the message.
365 if (tsig_ctx != NULL) {
366 // Release the reserved space in the renderer.
367 renderer.setLengthLimit(orig_msg_len_limit);
368
369 const int tsig_count =
370 tsig_ctx->sign(qid_, renderer.getData(),
371 renderer.getLength())->toWire(renderer);
372 if (tsig_count != 1) {
373 isc_throw(Unexpected, "Failed to render a TSIG RR");
374 }
375
376 // update the ARCOUNT for the TSIG RR. Note that for a sane DNS
377 // message arcount should never overflow to 0.
378 renderer.writeUint16At(++arcount, header_pos);
379 }
380}
381
383 impl_(new MessageImpl(mode))
384{}
385
387 delete impl_;
388}
389
390bool
392 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
394 "Message::getHeaderFlag:: Invalid flag is specified: " <<
395 "0x" << std::hex << flag);
396 }
397 return ((impl_->flags_ & flag) != 0);
398}
399
400void
401Message::setHeaderFlag(const HeaderFlag flag, const bool on) {
402 if (impl_->mode_ != Message::RENDER) {
404 "setHeaderFlag performed in non-render mode");
405 }
406 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
408 "Message::getHeaderFlag:: Invalid flag is specified: " <<
409 "0x" << std::hex << flag);
410 }
411 if (on) {
412 impl_->flags_ |= flag;
413 } else {
414 impl_->flags_ &= ~flag;
415 }
416}
417
418qid_t
420 return (impl_->qid_);
421}
422
423void
425 if (impl_->mode_ != Message::RENDER) {
427 "setQid performed in non-render mode");
428 }
429 impl_->qid_ = qid;
430}
431
432const Rcode&
434 if (impl_->rcode_ == NULL) {
435 isc_throw(InvalidMessageOperation, "getRcode attempted before set");
436 }
437 return (*impl_->rcode_);
438}
439
440void
442 if (impl_->mode_ != Message::RENDER) {
444 "setRcode performed in non-render mode");
445 }
446 impl_->setRcode(rcode);
447}
448
449const Opcode&
451 if (impl_->opcode_ == NULL) {
452 isc_throw(InvalidMessageOperation, "getOpcode attempted before set");
453 }
454 return (*impl_->opcode_);
455}
456
457void
459 if (impl_->mode_ != Message::RENDER) {
461 "setOpcode performed in non-render mode");
462 }
463 impl_->setOpcode(opcode);
464}
465
468 return (impl_->edns_);
469}
470
471void
473 if (impl_->mode_ != Message::RENDER) {
475 "setEDNS performed in non-render mode");
476 }
477 impl_->edns_ = edns;
478}
479
480const TSIGRecord*
482 if (impl_->mode_ != Message::PARSE) {
484 "getTSIGRecord performed in non-parse mode");
485 }
486
487 return (impl_->tsig_rr_.get());
488}
489
490unsigned int
491Message::getRRCount(const Section section) const {
492 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
493 isc_throw(OutOfRange, "Invalid message section: " << section);
494 }
495 return (impl_->counts_[section]);
496}
497
498void
499Message::addRRset(const Section section, RRsetPtr rrset) {
500 if (!rrset) {
502 "NULL RRset is given to Message::addRRset");
503 }
504 if (impl_->mode_ != Message::RENDER) {
506 "addRRset performed in non-render mode");
507 }
508 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
509 isc_throw(OutOfRange, "Invalid message section: " << section);
510 }
511
512 impl_->rrsets_[section].push_back(rrset);
513 impl_->counts_[section] += rrset->getRdataCount();
514 impl_->counts_[section] += rrset->getRRsigDataCount();
515}
516
517bool
518Message::hasRRset(const Section section, const Name& name,
519 const RRClass& rrclass, const RRType& rrtype) const
520{
521 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
522 isc_throw(OutOfRange, "Invalid message section: " << section);
523 }
524
525 BOOST_FOREACH(ConstRRsetPtr r, impl_->rrsets_[section]) {
526 if (r->getClass() == rrclass &&
527 r->getType() == rrtype &&
528 r->getName() == name) {
529 return (true);
530 }
531 }
532
533 return (false);
534}
535
536bool
537Message::hasRRset(const Section section, const RRsetPtr& rrset) const {
538 return (hasRRset(section, rrset->getName(),
539 rrset->getClass(), rrset->getType()));
540}
541
542bool
543Message::removeRRset(const Section section, RRsetIterator& iterator) {
544 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
545 isc_throw(OutOfRange, "Invalid message section: " << section);
546 }
547
548 bool removed = false;
549 for (vector<RRsetPtr>::iterator i = impl_->rrsets_[section].begin();
550 i != impl_->rrsets_[section].end(); ++i) {
551 if (((*i)->getName() == (*iterator)->getName()) &&
552 ((*i)->getClass() == (*iterator)->getClass()) &&
553 ((*i)->getType() == (*iterator)->getType())) {
554
555 // Found the matching RRset so remove it & ignore rest
556 impl_->counts_[section] -= (*iterator)->getRdataCount();
557 impl_->counts_[section] -= (*iterator)->getRRsigDataCount();
558 impl_->rrsets_[section].erase(i);
559 removed = true;
560 break;
561 }
562 }
563
564 return (removed);
565}
566
567void
569 if (impl_->mode_ != Message::RENDER) {
571 "clearSection performed in non-render mode");
572 }
573 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
574 isc_throw(OutOfRange, "Invalid message section: " << section);
575 }
576 if (section == Message::SECTION_QUESTION) {
577 impl_->questions_.clear();
578 } else {
579 impl_->rrsets_[section].clear();
580 }
581 impl_->counts_[section] = 0;
582}
583
584void
586 if (impl_->mode_ != Message::RENDER) {
588 "addQuestion performed in non-render mode");
589 }
590
591 impl_->questions_.push_back(question);
592 ++impl_->counts_[SECTION_QUESTION];
593}
594
595void
597 addQuestion(QuestionPtr(new Question(question)));
598}
599
600void
602 impl_->toWire(renderer, tsig_ctx);
603}
604
605void
607 if (impl_->mode_ != Message::PARSE) {
609 "Message parse attempted in non parse mode");
610 }
611
612 if (impl_->header_parsed_) {
613 return;
614 }
615
616 if ((buffer.getLength() - buffer.getPosition()) < HEADERLEN) {
617 isc_throw(MessageTooShort, "Malformed DNS message (short length): "
618 << buffer.getLength() - buffer.getPosition());
619 }
620
621 impl_->qid_ = buffer.readUint16();
622 const uint16_t codes_and_flags = buffer.readUint16();
623 impl_->setOpcode(Opcode((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT));
624 impl_->setRcode(Rcode(codes_and_flags & RCODE_MASK));
625 impl_->flags_ = (codes_and_flags & HEADERFLAG_MASK);
626 impl_->counts_[SECTION_QUESTION] = buffer.readUint16();
627 impl_->counts_[SECTION_ANSWER] = buffer.readUint16();
628 impl_->counts_[SECTION_AUTHORITY] = buffer.readUint16();
629 impl_->counts_[SECTION_ADDITIONAL] = buffer.readUint16();
630
631 impl_->header_parsed_ = true;
632}
633
634void
636 if (impl_->mode_ != Message::PARSE) {
638 "Message parse attempted in non parse mode");
639 }
640
641 // Clear any old parsed data
643
644 buffer.setPosition(0);
645 parseHeader(buffer);
646
647 impl_->counts_[SECTION_QUESTION] = impl_->parseQuestion(buffer);
648 impl_->counts_[SECTION_ANSWER] =
649 impl_->parseSection(SECTION_ANSWER, buffer, options);
650 impl_->counts_[SECTION_AUTHORITY] =
651 impl_->parseSection(SECTION_AUTHORITY, buffer, options);
653 impl_->parseSection(SECTION_ADDITIONAL, buffer, options);
654}
655
656int
658 unsigned int added = 0;
659
660 for (unsigned int count = 0;
662 ++count) {
663 const Name name(buffer);
664
665 if ((buffer.getLength() - buffer.getPosition()) <
666 2 * sizeof(uint16_t)) {
667 isc_throw(DNSMessageFORMERR, "Question section too short: " <<
668 (buffer.getLength() - buffer.getPosition()) << " bytes");
669 }
670 const RRType rrtype(buffer.readUint16());
671 const RRClass rrclass(buffer.readUint16());
672
673 // XXX: need a duplicate check. We might also want to have an
674 // optimized algorithm that requires the question section contain
675 // exactly one RR.
676
677 questions_.push_back(QuestionPtr(new Question(name, rrclass, rrtype)));
678 ++added;
679 }
680
681 return (added);
682}
683
684namespace {
685struct MatchRR {
686 MatchRR(const Name& name, const RRType& rrtype, const RRClass& rrclass) :
687 name_(name), rrtype_(rrtype), rrclass_(rrclass) {}
688 bool operator()(const RRsetPtr& rrset) const {
689 return (rrset->getType() == rrtype_ &&
690 rrset->getClass() == rrclass_ &&
691 rrset->getName() == name_);
692 }
693 const Name& name_;
694 const RRType& rrtype_;
695 const RRClass& rrclass_;
696};
697}
698
699// Note about design decision:
700// we need some type specific processing here, including EDNS and TSIG.
701// how much we should generalize/hardcode the special logic is subject
702// to discussion. In terms of modularity it would be ideal to introduce
703// an abstract class (say "MessageAttribute") and let other such
704// concrete notions as EDNS or TSIG inherit from it. Then we would
705// just do:
706// message->addAttribute(rrtype, rrclass, buffer);
707// to create and attach type-specific concrete object to the message.
708//
709// A major downside of this approach is, as usual, complexity due to
710// indirection and performance penalty. Also, it may not be so easy
711// to separate the processing logic because in many cases we'll need
712// parse context for which the message class is responsible (e.g.
713// to check the EDNS OPT RR only appears in the additional section,
714// and appears only once).
715//
716// Another point to consider is that we may not need so many special
717// types other than EDNS and TSIG (and when and if we implement it,
718// SIG(0)); newer optional attributes of the message would more likely
719// be standardized as new flags or options of EDNS. If that's the case,
720// introducing an abstract class with all the overhead and complexity
721// may not make much sense.
722//
723// Conclusion: don't over-generalize type-specific logic for now.
724// introduce separate concrete classes, and move context-independent
725// logic to that class; processing logic dependent on parse context
726// is hardcoded here.
727int
729 InputBuffer& buffer, Message::ParseOptions options)
730{
731 assert(static_cast<int>(section) < MessageImpl::NUM_SECTIONS);
732
733 unsigned int added = 0;
734
735 for (unsigned int count = 0; count < counts_[section]; ++count) {
736 // We need to remember the start position for TSIG processing
737 const size_t start_position = buffer.getPosition();
738
739 const Name name(buffer);
740
741 // buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
742 if ((buffer.getLength() - buffer.getPosition()) <
743 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
744 isc_throw(DNSMessageFORMERR, sectiontext[section] <<
745 " section too short: " <<
746 (buffer.getLength() - buffer.getPosition()) << " bytes");
747 }
748
749 const RRType rrtype(buffer.readUint16());
750 const RRClass rrclass(buffer.readUint16());
751 const RRTTL ttl(buffer.readUint32());
752 const size_t rdlen = buffer.readUint16();
753
754 // If class is ANY or NONE, rdlength may be zero, to signal
755 // an empty RRset.
756 // (the class check must be done to differentiate from RRTypes
757 // that can have zero length rdata
758 if ((rrclass == RRClass::ANY() || rrclass == RRClass::NONE()) &&
759 rdlen == 0) {
760 addRR(section, name, rrclass, rrtype, ttl, options);
761 ++added;
762 continue;
763 }
764 ConstRdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
765
766 if (rrtype == RRType::OPT()) {
767 addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
768 } else if (rrtype == RRType::TSIG()) {
769 addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
770 *rdata);
771 } else {
772 addRR(section, name, rrclass, rrtype, ttl, rdata, options);
773 ++added;
774 }
775 }
776
777 return (added);
778}
779
780void
782 const RRClass& rrclass, const RRType& rrtype,
783 const RRTTL& ttl, ConstRdataPtr rdata,
784 Message::ParseOptions options)
785{
786 if ((options & Message::PRESERVE_ORDER) == 0) {
787 vector<RRsetPtr>::iterator it =
788 find_if(rrsets_[section].begin(), rrsets_[section].end(),
789 MatchRR(name, rrtype, rrclass));
790 if (it != rrsets_[section].end()) {
791 (*it)->setTTL(min((*it)->getTTL(), ttl));
792 (*it)->addRdata(rdata);
793 return;
794 }
795 }
796 RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
797 rrset->addRdata(rdata);
798 rrsets_[section].push_back(rrset);
799}
800
801void
803 const RRClass& rrclass, const RRType& rrtype,
804 const RRTTL& ttl, Message::ParseOptions options)
805{
806 if ((options & Message::PRESERVE_ORDER) == 0) {
807 vector<RRsetPtr>::iterator it =
808 find_if(rrsets_[section].begin(), rrsets_[section].end(),
809 MatchRR(name, rrtype, rrclass));
810 if (it != rrsets_[section].end()) {
811 (*it)->setTTL(min((*it)->getTTL(), ttl));
812 return;
813 }
814 }
815 RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
816 rrsets_[section].push_back(rrset);
817}
818
819void
821 const RRClass& rrclass, const RRType& rrtype,
822 const RRTTL& ttl, const Rdata& rdata)
823{
824 if (section != Message::SECTION_ADDITIONAL) {
826 "EDNS OPT RR found in an invalid section");
827 }
828 if (edns_) {
829 isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
830 }
831
832 uint8_t extended_rcode;
833 edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl, rdata,
834 extended_rcode));
835 setRcode(Rcode(rcode_->getCode(), extended_rcode));
836}
837
838void
839MessageImpl::addTSIG(Message::Section section, unsigned int count,
840 const InputBuffer& buffer, size_t start_position,
841 const Name& name, const RRClass& rrclass,
842 const RRTTL& ttl, const Rdata& rdata)
843{
844 if (section != Message::SECTION_ADDITIONAL) {
846 "TSIG RR found in an invalid section");
847 }
848 if (count != counts_[section] - 1) {
849 isc_throw(DNSMessageFORMERR, "TSIG RR is not the last record");
850 }
851 // This check will never fail as the multiple TSIG RR case is
852 // caught before by the not the last record check...
853 if (tsig_rr_) {
854 isc_throw(DNSMessageFORMERR, "multiple TSIG RRs found");
855 }
856 tsig_rr_ = ConstTSIGRecordPtr(new TSIGRecord(name, rrclass,
857 ttl, rdata,
858 buffer.getPosition() -
859 start_position));
860}
861
862namespace {
863template <typename T>
864struct SectionFormatter {
865 SectionFormatter(const Message::Section section, string& output) :
866 section_(section), output_(output) {}
867 void operator()(const T& entry) {
869 output_ += ";";
870 output_ += entry->toText();
871 output_ += "\n";
872 } else {
873 output_ += entry->toText();
874 }
875 }
877 string& output_;
878};
879}
880
881string
883 if (impl_->rcode_ == NULL) {
885 "Message::toText() attempted without Rcode set");
886 }
887 if (impl_->opcode_ == NULL) {
889 "Message::toText() attempted without Opcode set");
890 }
891
892 string s;
893
894 s += ";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
895 // for simplicity we don't consider extended rcode (unlike BIND9)
896 s += ", status: " + impl_->rcode_->toText();
897 s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
898 s += "\n;; flags:";
900 s += " qr";
901 }
903 s += " aa";
904 }
906 s += " tc";
907 }
909 s += " rd";
910 }
912 s += " ra";
913 }
915 s += " ad";
916 }
918 s += " cd";
919 }
920
921 // for simplicity, don't consider the update case for now
922 s += "; QUERY: " + // note: not "QUESTION" to be compatible with BIND 9 dig
923 lexical_cast<string>(impl_->counts_[SECTION_QUESTION]);
924 s += ", ANSWER: " +
925 lexical_cast<string>(impl_->counts_[SECTION_ANSWER]);
926 s += ", AUTHORITY: " +
927 lexical_cast<string>(impl_->counts_[SECTION_AUTHORITY]);
928
929 unsigned int arcount = impl_->counts_[SECTION_ADDITIONAL];
930 if (impl_->edns_ != NULL) {
931 ++arcount;
932 }
933 if (impl_->tsig_rr_ != NULL) {
934 ++arcount;
935 }
936 s += ", ADDITIONAL: " + lexical_cast<string>(arcount) + "\n";
937
938 if (impl_->edns_ != NULL) {
939 s += "\n;; OPT PSEUDOSECTION:\n";
940 s += impl_->edns_->toText();
941 }
942
943 if (!impl_->questions_.empty()) {
944 s += "\n;; " +
945 string(sectiontext[SECTION_QUESTION]) + " SECTION:\n";
946 for_each(impl_->questions_.begin(), impl_->questions_.end(),
947 SectionFormatter<QuestionPtr>(SECTION_QUESTION, s));
948 }
949 if (!impl_->rrsets_[SECTION_ANSWER].empty()) {
950 s += "\n;; " +
951 string(sectiontext[SECTION_ANSWER]) + " SECTION:\n";
952 for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
953 impl_->rrsets_[SECTION_ANSWER].end(),
954 SectionFormatter<RRsetPtr>(SECTION_ANSWER, s));
955 }
956 if (!impl_->rrsets_[SECTION_AUTHORITY].empty()) {
957 s += "\n;; " +
958 string(sectiontext[SECTION_AUTHORITY]) + " SECTION:\n";
959 for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
960 impl_->rrsets_[SECTION_AUTHORITY].end(),
961 SectionFormatter<RRsetPtr>(SECTION_AUTHORITY, s));
962 }
963 if (!impl_->rrsets_[SECTION_ADDITIONAL].empty()) {
964 s += "\n;; " +
965 string(sectiontext[SECTION_ADDITIONAL]) +
966 " SECTION:\n";
967 for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
968 impl_->rrsets_[SECTION_ADDITIONAL].end(),
969 SectionFormatter<RRsetPtr>(SECTION_ADDITIONAL, s));
970 }
971
972 if (impl_->tsig_rr_ != NULL) {
973 s += "\n;; TSIG PSEUDOSECTION:\n";
974 s += impl_->tsig_rr_->toText();
975 }
976
977 return (s);
978}
979
980void
982 impl_->init();
983 impl_->mode_ = mode;
984}
985
986void
987Message::appendSection(const Section section, const Message& source) {
988 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
989 isc_throw(OutOfRange, "Invalid message section: " << section);
990 }
991
992 if (section == SECTION_QUESTION) {
993 for (QuestionIterator qi = source.beginQuestion();
994 qi != source.endQuestion();
995 ++qi) {
996 addQuestion(*qi);
997 }
998 } else {
999 for (RRsetIterator rrsi = source.beginSection(section);
1000 rrsi != source.endSection(section);
1001 ++rrsi) {
1002 addRRset(section, *rrsi);
1003 }
1004 }
1005}
1006
1007void
1009 if (impl_->mode_ != Message::PARSE) {
1011 "makeResponse() is performed in non-parse mode");
1012 }
1013
1014 impl_->mode_ = Message::RENDER;
1015
1016 impl_->edns_ = EDNSPtr();
1017 impl_->flags_ &= MESSAGE_REPLYPRESERVE;
1019
1020 impl_->rrsets_[SECTION_ANSWER].clear();
1021 impl_->counts_[SECTION_ANSWER] = 0;
1022 impl_->rrsets_[SECTION_AUTHORITY].clear();
1023 impl_->counts_[SECTION_AUTHORITY] = 0;
1024 impl_->rrsets_[SECTION_ADDITIONAL].clear();
1025 impl_->counts_[SECTION_ADDITIONAL] = 0;
1026}
1027
1031template <typename T>
1033 SectionIteratorImpl(const typename vector<T>::const_iterator& it) :
1034 it_(it) {}
1035 typename vector<T>::const_iterator it_;
1036};
1037
1038template <typename T>
1040 impl_ = new SectionIteratorImpl<T>(impl.it_);
1041}
1042
1043template <typename T>
1045 delete impl_;
1046}
1047
1048template <typename T>
1050 impl_(new SectionIteratorImpl<T>(source.impl_->it_))
1051{}
1052
1053template <typename T>
1054void
1056 if (impl_ == source.impl_) {
1057 return;
1058 }
1059 SectionIteratorImpl<T>* newimpl =
1060 new SectionIteratorImpl<T>(source.impl_->it_);
1061 delete impl_;
1062 impl_ = newimpl;
1063}
1064
1065template <typename T>
1068 ++(impl_->it_);
1069 return (*this);
1070}
1071
1072template <typename T>
1075 SectionIterator<T> tmp(*this);
1076 ++(*this);
1077 return (tmp);
1078}
1079
1080template <typename T>
1081const T&
1083 return (*(impl_->it_));
1084}
1085
1086template <typename T>
1087const T*
1089 return (&(operator*()));
1090}
1091
1092template <typename T>
1093bool
1095 return (impl_->it_ == other.impl_->it_);
1096}
1097
1098template <typename T>
1099bool
1101 return (impl_->it_ != other.impl_->it_);
1102}
1103
1108template class SectionIterator<QuestionPtr>;
1109template class SectionIterator<RRsetPtr>;
1110
1111namespace {
1112typedef SectionIteratorImpl<QuestionPtr> QuestionIteratorImpl;
1113typedef SectionIteratorImpl<RRsetPtr> RRsetIteratorImpl;
1114}
1115
1119const QuestionIterator
1121 return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
1122}
1123
1124const QuestionIterator
1126 return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.end())));
1127}
1128
1133Message::beginSection(const Section section) const {
1134 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
1135 isc_throw(OutOfRange, "Invalid message section: " << section);
1136 }
1137 if (section == SECTION_QUESTION) {
1139 "RRset iterator is requested for question");
1140 }
1141
1142 return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].begin())));
1143}
1144
1146Message::endSection(const Section section) const {
1147 if (static_cast<int>(section) >= MessageImpl::NUM_SECTIONS) {
1148 isc_throw(OutOfRange, "Invalid message section: " << section);
1149 }
1150 if (section == SECTION_QUESTION) {
1152 "RRset iterator is requested for question");
1153 }
1154
1155 return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].end())));
1156}
1157
1158ostream&
1159operator<<(ostream& os, const Message& message) {
1160 return (os << message.toText());
1161}
1162} // end of namespace dns
1163} // 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:229
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:781
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:728
MessageImpl(Message::Mode mode)
Definition: dns/message.cc:142
void setOpcode(const Opcode &opcode)
Definition: dns/message.cc:171
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:839
void addEDNS(Message::Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, const Rdata &rdata)
Definition: dns/message.cc:820
ConstTSIGRecordPtr tsig_rr_
Definition: dns/message.cc:113
int parseQuestion(InputBuffer &buffer)
Definition: dns/message.cc:657
void setRcode(const Rcode &rcode)
Definition: dns/message.cc:177
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:143
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:193
@ HEADERFLAG_RD
Recursion desired.
Definition: message.h:197
@ HEADERFLAG_TC
Truncation.
Definition: message.h:196
@ HEADERFLAG_AA
Authoritative answer.
Definition: message.h:195
@ HEADERFLAG_RA
Recursion available.
Definition: message.h:198
@ HEADERFLAG_CD
DNSSEC checking disabled (RFC4035)
Definition: message.h:200
@ HEADERFLAG_QR
Query (if cleared) or response (if set)
Definition: message.h:194
@ HEADERFLAG_AD
Authentic data (RFC4035)
Definition: message.h:199
const Rcode & getRcode() const
Return the Response Code of the message.
Definition: dns/message.cc:433
bool getHeaderFlag(const HeaderFlag flag) const
Return whether the specified header flag bit is set in the header section.
Definition: dns/message.cc:391
void clear(Mode mode)
Clear the message content (if any) and reinitialize it in the specified mode.
Definition: dns/message.cc:981
Section
Constants to specify sections of a DNS message.
Definition: message.h:233
@ SECTION_ADDITIONAL
Additional section.
Definition: message.h:237
@ SECTION_AUTHORITY
Authority section.
Definition: message.h:236
@ SECTION_ANSWER
Answer section.
Definition: message.h:235
@ SECTION_QUESTION
Question section
Definition: message.h:234
void clearSection(const Section section)
Remove all RRSets from the given Section.
Definition: dns/message.cc:568
ParseOptions
Parse options.
Definition: message.h:587
@ PRESERVE_ORDER
Preserve RR order and don't combine them.
Definition: message.h:589
Mode
Constants to specify the operation mode of the Message.
Definition: message.h:146
@ RENDER
Render mode (building an outgoing message)
Definition: message.h:148
@ PARSE
Parse mode (handling an incoming message)
Definition: message.h:147
unsigned int getRRCount(const Section section) const
Returns the number of RRs contained in the given section.
Definition: dns/message.cc:491
void setOpcode(const Opcode &opcode)
Set the OPCODE of the header section of the message.
Definition: dns/message.cc:458
bool removeRRset(const Section section, RRsetIterator &iterator)
Remove RRSet from Message.
Definition: dns/message.cc:543
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:499
void fromWire(isc::util::InputBuffer &buffer, ParseOptions options=PARSE_DEFAULT)
(Re)build a Message object from wire-format data.
Definition: dns/message.cc:635
~Message()
The destructor.
Definition: dns/message.cc:386
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:481
std::string toText() const
Convert the Message to a string.
Definition: dns/message.cc:882
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:401
ConstEDNSPtr getEDNS() const
Return, if any, the EDNS associated with the message.
Definition: dns/message.cc:467
const Opcode & getOpcode() const
Return the OPCODE given in the header section of the message.
Definition: dns/message.cc:450
void parseHeader(isc::util::InputBuffer &buffer)
Parse the header section of the Message.
Definition: dns/message.cc:606
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:518
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:987
void addQuestion(QuestionPtr question)
Add a (pointer like object of) Question to the message.
Definition: dns/message.cc:585
void setQid(qid_t qid)
Set the query ID of the header section of the message.
Definition: dns/message.cc:424
qid_t getQid() const
Return the query ID given in the header section of the message.
Definition: dns/message.cc:419
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:441
Message(Mode mode)
The constructor.
Definition: dns/message.cc:382
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:601
void setEDNS(ConstEDNSPtr edns)
Set EDNS for the message.
Definition: dns/message.cc:472
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
std::string toText() const
Convert the Opcode to a string.
Definition: opcode.cc:53
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
std::string toText() const
Convert the Rcode to a string.
Definition: rcode.cc:80
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:221
const RRClass & rrclass_
Definition: dns/message.cc:695
AbstractMessageRenderer & renderer_
Definition: dns/message.cc:222
string & output_
Definition: dns/message.cc:877
const Name & name_
Definition: dns/message.cc:693
bool truncated_
Definition: dns/message.cc:224
const Message::Section section_
Definition: dns/message.cc:876
const RRType & rrtype_
Definition: dns/message.cc:694
const bool partial_ok_
Definition: dns/message.cc:223
#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< 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:28
SectionIterator< QuestionPtr > QuestionIterator
Definition: message.h:108
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
Definition: rrset.h:47
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:31
SectionIterator< RRsetPtr > RRsetIterator
Definition: message.h:109
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)