Kea  1.9.9-git
dns/message.cc
Go to the documentation of this file.
1 // Copyright (C) 2009-2015 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 
21 #include <exceptions/exceptions.h>
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 
40 using namespace std;
41 using boost::lexical_cast;
42 using namespace isc::dns::rdata;
43 using namespace isc::util;
44 
45 namespace isc {
46 namespace dns {
47 
48 namespace {
49 // protocol constants
50 const size_t HEADERLEN = 12;
51 
52 const unsigned int OPCODE_MASK = 0x7800;
53 const unsigned int OPCODE_SHIFT = 11;
54 const 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.
70 const 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).
77 const uint16_t MESSAGE_REPLYPRESERVE = (Message::HEADERFLAG_RD |
78  Message::HEADERFLAG_CD);
79 
80 const char* const sectiontext[] = {
81  "QUESTION",
82  "ANSWER",
83  "AUTHORITY",
84  "ADDITIONAL"
85 };
86 }
87 
88 class MessageImpl {
89 public:
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_;
102  const Opcode* opcode_;
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 
142 MessageImpl::MessageImpl(Message::Mode mode) :
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 
150 void
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 
170 void
172  opcode_placeholder_ = opcode;
174 }
175 
176 void
178  rcode_placeholder_ = rcode;
180 }
181 
182 namespace {
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.
199 template <typename T>
200 struct 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 
228 void
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.
340  counts_[Message::SECTION_ANSWER] = ancount;
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 
390 bool
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 
400 void
401 Message::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 
418 qid_t
420  return (impl_->qid_);
421 }
422 
423 void
425  if (impl_->mode_ != Message::RENDER) {
427  "setQid performed in non-render mode");
428  }
429  impl_->qid_ = qid;
430 }
431 
432 const Rcode&
434  if (impl_->rcode_ == NULL) {
435  isc_throw(InvalidMessageOperation, "getRcode attempted before set");
436  }
437  return (*impl_->rcode_);
438 }
439 
440 void
441 Message::setRcode(const Rcode& rcode) {
442  if (impl_->mode_ != Message::RENDER) {
444  "setRcode performed in non-render mode");
445  }
446  impl_->setRcode(rcode);
447 }
448 
449 const Opcode&
451  if (impl_->opcode_ == NULL) {
452  isc_throw(InvalidMessageOperation, "getOpcode attempted before set");
453  }
454  return (*impl_->opcode_);
455 }
456 
457 void
458 Message::setOpcode(const Opcode& opcode) {
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 
471 void
473  if (impl_->mode_ != Message::RENDER) {
475  "setEDNS performed in non-render mode");
476  }
477  impl_->edns_ = edns;
478 }
479 
480 const TSIGRecord*
482  if (impl_->mode_ != Message::PARSE) {
484  "getTSIGRecord performed in non-parse mode");
485  }
486 
487  return (impl_->tsig_rr_.get());
488 }
489 
490 unsigned int
491 Message::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 
498 void
499 Message::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 
517 bool
518 Message::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 
536 bool
537 Message::hasRRset(const Section section, const RRsetPtr& rrset) const {
538  return (hasRRset(section, rrset->getName(),
539  rrset->getClass(), rrset->getType()));
540 }
541 
542 bool
543 Message::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 
567 void
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 
584 void
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 
595 void
596 Message::addQuestion(const Question& question) {
597  addQuestion(QuestionPtr(new Question(question)));
598 }
599 
600 void
602  impl_->toWire(renderer, tsig_ctx);
603 }
604 
605 void
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 
634 void
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);
652  impl_->counts_[SECTION_ADDITIONAL] =
653  impl_->parseSection(SECTION_ADDITIONAL, buffer, options);
654 }
655 
656 int
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 
684 namespace {
685 struct MatchRR : public unary_function<RRsetPtr, bool> {
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.
727 int
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 
780 void
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 
801 void
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 
819 void
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 
838 void
839 MessageImpl::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 
862 namespace {
863 template <typename T>
864 struct 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 
881 string
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 
980 void
982  impl_->init();
983  impl_->mode_ = mode;
984 }
985 
986 void
987 Message::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 
1007 void
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 
1031 template <typename T>
1033  SectionIteratorImpl(const typename vector<T>::const_iterator& it) :
1034  it_(it) {}
1035  typename vector<T>::const_iterator it_;
1036 };
1037 
1038 template <typename T>
1040  impl_ = new SectionIteratorImpl<T>(impl.it_);
1041 }
1042 
1043 template <typename T>
1045  delete impl_;
1046 }
1047 
1048 template <typename T>
1050  impl_(new SectionIteratorImpl<T>(source.impl_->it_))
1051 {}
1052 
1053 template <typename T>
1054 void
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 
1065 template <typename T>
1068  ++(impl_->it_);
1069  return (*this);
1070 }
1071 
1072 template <typename T>
1075  SectionIterator<T> tmp(*this);
1076  ++(*this);
1077  return (tmp);
1078 }
1079 
1080 template <typename T>
1081 const T&
1083  return (*(impl_->it_));
1084 }
1085 
1086 template <typename T>
1087 const T*
1089  return (&(operator*()));
1090 }
1091 
1092 template <typename T>
1093 bool
1095  return (impl_->it_ == other.impl_->it_);
1096 }
1097 
1098 template <typename T>
1099 bool
1101  return (impl_->it_ != other.impl_->it_);
1102 }
1103 
1108 template class SectionIterator<QuestionPtr>;
1109 template class SectionIterator<RRsetPtr>;
1110 
1111 namespace {
1112 typedef SectionIteratorImpl<QuestionPtr> QuestionIteratorImpl;
1113 typedef SectionIteratorImpl<RRsetPtr> RRsetIteratorImpl;
1114 }
1115 
1119 const QuestionIterator
1121  return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
1122 }
1123 
1124 const QuestionIterator
1126  return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.end())));
1127 }
1128 
1133 Message::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 
1146 Message::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 
1158 ostream&
1159 operator<<(ostream& os, const Message& message) {
1160  return (os << message.toText());
1161 }
1162 } // end of namespace dns
1163 } // end of namespace isc
The Name class encapsulates DNS names.
Definition: name.h:223
uint16_t qid_t
Definition: message.h:75
size_t getLength() const
Return the length of the data stored in the buffer.
Definition: buffer.h:100
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 Rcode & getRcode() const
Return the Response Code of the message.
Definition: dns/message.cc:433
const RRClass & rrclass_
Definition: dns/message.cc:695
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
Render mode (building an outgoing message)
Definition: message.h:148
void clear(Mode mode)
Clear the message content (if any) and reinitialize it in the specified mode.
Definition: dns/message.cc:981
void setEDNS(ConstEDNSPtr edns)
Set EDNS for the message.
Definition: dns/message.cc:472
Mode
Constants to specify the operation mode of the Message.
Definition: message.h:146
ostream & operator<<(std::ostream &os, const EDNS &edns)
Insert the EDNS as a string into stream.
Definition: edns.cc:172
TSIG session context.
Definition: tsig.h:171
A standard DNS module exception that is thrown if a Message class method is called that is prohibited...
Definition: message.h:58
static const RRType & TSIG()
Definition: rrtype.h:335
bool operator==(const SectionIterator< T > &other) const
ParseOptions
Parse options.
Definition: message.h:587
std::string toText() const
Convert the Rcode to a string.
Definition: rcode.cc:80
const QuestionIterator beginQuestion() const
Return an iterator corresponding to the beginning of the Question section of the message.
The Question class encapsulates the common search key of DNS lookup, consisting of owner name...
Definition: question.h:95
ConstTSIGRecordPtr tsig_rr_
Definition: dns/message.cc:113
void setPosition(size_t position)
Set the read position of the buffer to the given value.
Definition: buffer.h:115
CompressMode mode_
Definition: rdatafields.cc:97
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
AbstractMessageRenderer & renderer_
Definition: dns/message.cc:222
int parseQuestion(InputBuffer &buffer)
Definition: dns/message.cc:657
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
void skip(size_t len)
Insert a specified length of gap at the end of the buffer.
std::string toText() const
Convert the Opcode to a string.
Definition: opcode.cc:53
boost::shared_ptr< const EDNS > ConstEDNSPtr
A pointer-like type pointing to an immutable EDNS object.
Definition: edns.h:37
ConstTSIGRecordPtr sign(const uint16_t qid, const void *const data, const size_t data_len)
Sign a DNS message.
Definition: tsig.cc:344
~Message()
The destructor.
Definition: dns/message.cc:386
qid_t getQid() const
Return the query ID given in the header section of the message.
Definition: dns/message.cc:419
boost::shared_ptr< const Rdata > ConstRdataPtr
Definition: rdata.h:72
Recursion available.
Definition: message.h:198
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
Definition: rdata.h:123
TSIG resource record.
Definition: tsigrecord.h:54
vector< RRsetPtr > rrsets_[NUM_SECTIONS]
Definition: dns/message.cc:111
void clearSection(const Section section)
Remove all RRSets from the given Section.
Definition: dns/message.cc:568
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
STL namespace.
const Opcode * opcode_
Definition: dns/message.cc:102
void setRcode(const Rcode &rcode)
Set the Response Code of the message.
Definition: dns/message.cc:441
DNS Response Codes (RCODEs) class.
Definition: rcode.h:40
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
SectionIterator< T > & operator++()
const RRType & rrtype_
Definition: dns/message.cc:694
static const RRType & OPT()
Definition: rrtype.h:437
Authentic data (RFC4035)
Definition: message.h:199
const T & operator*() const
const Opcode & getOpcode() const
Return the OPCODE given in the header section of the message.
Definition: dns/message.cc:450
const T * operator->() const
The Message class encapsulates a standard DNS message.
Definition: message.h:143
SectionIterator< QuestionPtr > QuestionIterator
Definition: message.h:108
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:98
Template version of Section Iterator.
virtual void clear()
Clear the internal buffer and other internal resources.
void operator=(const SectionIterator< T > &source)
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
ConstEDNSPtr getEDNS() const
Return, if any, the EDNS associated with the message.
Definition: dns/message.cc:467
Definition: edns.h:19
A standard DNS module exception that is thrown if a section iterator is being constructed for an inco...
Definition: message.h:47
boost::shared_ptr< EDNS > EDNSPtr
A pointer-like type pointing to an EDNS object.
Definition: edns.h:31
void fromWire(isc::util::InputBuffer &buffer, ParseOptions options=PARSE_DEFAULT)
(Re)build a Message object from wire-format data.
Definition: dns/message.cc:635
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
SectionIteratorImpl(const typename vector< T >::const_iterator &it)
void addQuestion(QuestionPtr question)
Add a (pointer like object of) Question to the message.
Definition: dns/message.cc:585
const QuestionIterator endQuestion() const
Return an iterator corresponding to the end of the Question section of the message.
uint8_t getExtendedCode() const
Returns the upper 8-bit of the Rcode code value.
Definition: rcode.cc:75
CompressMode
Compression mode constants.
bool operator!=(const SectionIterator< T > &other) const
A generic exception that is thrown when an unexpected error condition occurs.
bool getHeaderFlag(const HeaderFlag flag) const
Return whether the specified header flag bit is set in the header section.
Definition: dns/message.cc:391
Parse mode (handling an incoming message)
Definition: message.h:147
virtual void setCompressMode(CompressMode mode)=0
Set the compression mode of the renderer class object.
The RRTTL class encapsulates TTLs used in DNS resource records.
Definition: rrttl.h:55
Authoritative answer.
Definition: message.h:195
The EDNS class represents the EDNS OPT RR defined in RFC2671.
Definition: edns.h:123
Query (if cleared) or response (if set)
Definition: message.h:194
DNSSEC checking disabled (RFC4035)
Definition: message.h:200
CodeValue getCode() const
Returns the Opcode code value.
Definition: opcode.h:78
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
vector< T >::const_iterator it_
A standard DNS module exception that is thrown if a wire format message parser encounters a short len...
Definition: message.h:36
vector< QuestionPtr > questions_
Definition: dns/message.cc:110
const Rcode * rcode_
Definition: dns/message.cc:100
const Message::Section section_
Definition: dns/message.cc:876
static const RRClass & ANY()
Definition: rrclass.h:301
std::string toText() const
Convert the Message to a string.
Definition: dns/message.cc:882
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
void setOpcode(const Opcode &opcode)
Definition: dns/message.cc:171
boost::shared_ptr< const TSIGRecord > ConstTSIGRecordPtr
A pointer-like type pointing to an immutable TSIGRecord object.
Definition: tsigrecord.h:280
Defines the logger used by the top-level component of kea-dhcp-ddns.
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 toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx)
Definition: dns/message.cc:229
SectionIterator is a templated class to provide standard-compatible iterators for Questions and RRset...
Definition: message.h:91
size_t getPosition() const
Return the current read position.
Definition: buffer.h:102
void setRcode(const Rcode &rcode)
Definition: dns/message.cc:177
SectionIterator< RRsetPtr > RRsetIterator
Definition: message.h:109
unsigned int getRRCount(const Section section) const
Returns the number of RRs contained in the given section.
Definition: dns/message.cc:491
string & output_
Definition: dns/message.cc:877
size_t getTSIGLength() const
Return the expected length of TSIG RR after sign()
Definition: tsig.cc:295
void setOpcode(const Opcode &opcode)
Set the OPCODE of the header section of the message.
Definition: dns/message.cc:458
Section
Constants to specify sections of a DNS message.
Definition: message.h:233
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
std::vector< rdata::ConstRdataPtr >::const_iterator it_
Iterator used to retrieve data.
Definition: rrset.cc:455
The RRset class is a concrete derived class of BasicRRset which contains a pointer to an additional R...
Definition: rrset.h:847
bool removeRRset(const Section section, RRsetIterator &iterator)
Remove RRSet from Message.
Definition: dns/message.cc:543
int counts_[NUM_SECTIONS]
Definition: dns/message.cc:109
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
const Name & name_
Definition: dns/message.cc:693
FlexOptionImplPtr impl
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
The RRType class encapsulates DNS resource record types.
Definition: rrtype.h:106
virtual void setLengthLimit(size_t len)=0
Set the maximum length of rendered data that can fit in the corresponding DNS message without truncat...
Recursion desired.
Definition: message.h:197
const TSIGRecord * getTSIGRecord() const
Return, if any, the TSIG record contained in the received message.
Definition: dns/message.cc:481
void parseHeader(isc::util::InputBuffer &buffer)
Parse the header section of the Message.
Definition: dns/message.cc:606
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
static const RRClass & NONE()
Definition: rrclass.h:325
void setQid(qid_t qid)
Set the query ID of the header section of the message.
Definition: dns/message.cc:424
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
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
const bool partial_ok_
Definition: dns/message.cc:223
boost::shared_ptr< const AbstractRRset > ConstRRsetPtr
A pointer-like type pointing to an (immutable) RRset object.
Definition: rrset.h:60
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
Definition: rrset.h:47
static const unsigned int NUM_SECTIONS
Definition: dns/message.cc:108
HeaderFlag
Constants for flag bit fields of a DNS message header.
Definition: message.h:193
void makeResponse()
Prepare for making a response from a request.
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
bool truncated_
Definition: dns/message.cc:224
The Opcode class objects represent standard OPCODEs of the header section of DNS messages as defined ...
Definition: opcode.h:32
virtual size_t getLengthLimit() const =0
Return the maximum length of rendered data that can fit in the corresponding DNS message without trun...
unsigned int counter_
Definition: dns/message.cc:221
boost::shared_ptr< Question > QuestionPtr
A pointer-like type pointing to an Question object.
Definition: question.h:28
uint16_t getCode() const
Returns the Rcode code value.
Definition: rcode.h:106
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
int parseSection(const Message::Section section, InputBuffer &buffer, Message::ParseOptions options)
Definition: dns/message.cc:728
Preserve RR order and don't combine them.
Definition: message.h:589
virtual CompressMode getCompressMode() const =0
Return the compression mode of the renderer class object.
Message::Mode mode_
Definition: dns/message.cc:93
Message(Mode mode)
The constructor.
Definition: dns/message.cc:382