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:
90 MessageImpl(Message::Mode mode);
91 // Open issues: should we rather have a header in wire-format
92 // for efficiency?
93 Message::Mode mode_;
94 qid_t qid_;
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_;
101 Rcode rcode_placeholder_;
102 const Opcode* opcode_;
103 Opcode opcode_placeholder_;
104
105 uint16_t flags_; // wire-format representation of header flags.
106
107 bool header_parsed_;
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];
112 ConstEDNSPtr edns_;
113 ConstTSIGRecordPtr tsig_rr_;
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
MessageImpl(Message::Mode mode)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
init()151 MessageImpl::init() {
152 flags_ = 0;
153 qid_ = 0;
154 rcode_ = NULL;
155 opcode_ = NULL;
156 edns_ = EDNSPtr();
157 tsig_rr_ = ConstTSIGRecordPtr();
158
159 for (int i = 0; i < NUM_SECTIONS; ++i) {
160 counts_[i] = 0;
161 }
162
163 header_parsed_ = false;
164 questions_.clear();
165 rrsets_[Message::SECTION_ANSWER].clear();
166 rrsets_[Message::SECTION_AUTHORITY].clear();
167 rrsets_[Message::SECTION_ADDITIONAL].clear();
168 }
169
170 void
setOpcode(const Opcode & opcode)171 MessageImpl::setOpcode(const Opcode& opcode) {
172 opcode_placeholder_ = opcode;
173 opcode_ = &opcode_placeholder_;
174 }
175
176 void
setRcode(const Rcode & rcode)177 MessageImpl::setRcode(const Rcode& rcode) {
178 rcode_placeholder_ = rcode;
179 rcode_ = &rcode_placeholder_;
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 {
RenderSectionisc::dns::__anon51655ca60211::RenderSection201 RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
202 counter_(0), renderer_(renderer), partial_ok_(partial_ok),
203 truncated_(false)
204 {}
operator ()isc::dns::__anon51655ca60211::RenderSection205 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 }
getTotalCountisc::dns::__anon51655ca60211::RenderSection220 unsigned int getTotalCount() { return (counter_); }
221 unsigned int counter_;
222 AbstractMessageRenderer& renderer_;
223 const bool partial_ok_;
224 bool truncated_;
225 };
226 }
227
228 void
toWire(AbstractMessageRenderer & renderer,TSIGContext * tsig_ctx)229 MessageImpl::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) {
230 if (mode_ != Message::RENDER) {
231 isc_throw(InvalidMessageOperation,
232 "Message rendering attempted in non render mode");
233 }
234 if (rcode_ == NULL) {
235 isc_throw(InvalidMessageOperation,
236 "Message rendering attempted without Rcode set");
237 }
238 if (opcode_ == NULL) {
239 isc_throw(InvalidMessageOperation,
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(),
285 rrsets_[Message::SECTION_ANSWER].end(),
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(),
292 rrsets_[Message::SECTION_AUTHORITY].end(),
293 RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
294 }
295 uint16_t arcount = 0;
296 if (renderer.isTruncated()) {
297 flags_ |= Message::HEADERFLAG_TC;
298 } else {
299 arcount =
300 for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
301 rrsets_[Message::SECTION_ADDITIONAL].end(),
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.
339 counts_[Message::SECTION_QUESTION] = qdcount;
340 counts_[Message::SECTION_ANSWER] = ancount;
341 counts_[Message::SECTION_AUTHORITY] = nscount;
342 counts_[Message::SECTION_ADDITIONAL] = arcount;
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
Message(Mode mode)382 Message::Message(Mode mode) :
383 impl_(new MessageImpl(mode))
384 {}
385
~Message()386 Message::~Message() {
387 delete impl_;
388 }
389
390 bool
getHeaderFlag(const HeaderFlag flag) const391 Message::getHeaderFlag(const HeaderFlag flag) const {
392 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
393 isc_throw(InvalidParameter,
394 "Message::getHeaderFlag:: Invalid flag is specified: " <<
395 "0x" << std::hex << flag);
396 }
397 return ((impl_->flags_ & flag) != 0);
398 }
399
400 void
setHeaderFlag(const HeaderFlag flag,const bool on)401 Message::setHeaderFlag(const HeaderFlag flag, const bool on) {
402 if (impl_->mode_ != Message::RENDER) {
403 isc_throw(InvalidMessageOperation,
404 "setHeaderFlag performed in non-render mode");
405 }
406 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
407 isc_throw(InvalidParameter,
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
getQid() const419 Message::getQid() const {
420 return (impl_->qid_);
421 }
422
423 void
setQid(qid_t qid)424 Message::setQid(qid_t qid) {
425 if (impl_->mode_ != Message::RENDER) {
426 isc_throw(InvalidMessageOperation,
427 "setQid performed in non-render mode");
428 }
429 impl_->qid_ = qid;
430 }
431
432 const Rcode&
getRcode() const433 Message::getRcode() const {
434 if (impl_->rcode_ == NULL) {
435 isc_throw(InvalidMessageOperation, "getRcode attempted before set");
436 }
437 return (*impl_->rcode_);
438 }
439
440 void
setRcode(const Rcode & rcode)441 Message::setRcode(const Rcode& rcode) {
442 if (impl_->mode_ != Message::RENDER) {
443 isc_throw(InvalidMessageOperation,
444 "setRcode performed in non-render mode");
445 }
446 impl_->setRcode(rcode);
447 }
448
449 const Opcode&
getOpcode() const450 Message::getOpcode() const {
451 if (impl_->opcode_ == NULL) {
452 isc_throw(InvalidMessageOperation, "getOpcode attempted before set");
453 }
454 return (*impl_->opcode_);
455 }
456
457 void
setOpcode(const Opcode & opcode)458 Message::setOpcode(const Opcode& opcode) {
459 if (impl_->mode_ != Message::RENDER) {
460 isc_throw(InvalidMessageOperation,
461 "setOpcode performed in non-render mode");
462 }
463 impl_->setOpcode(opcode);
464 }
465
466 ConstEDNSPtr
getEDNS() const467 Message::getEDNS() const {
468 return (impl_->edns_);
469 }
470
471 void
setEDNS(ConstEDNSPtr edns)472 Message::setEDNS(ConstEDNSPtr edns) {
473 if (impl_->mode_ != Message::RENDER) {
474 isc_throw(InvalidMessageOperation,
475 "setEDNS performed in non-render mode");
476 }
477 impl_->edns_ = edns;
478 }
479
480 const TSIGRecord*
getTSIGRecord() const481 Message::getTSIGRecord() const {
482 if (impl_->mode_ != Message::PARSE) {
483 isc_throw(InvalidMessageOperation,
484 "getTSIGRecord performed in non-parse mode");
485 }
486
487 return (impl_->tsig_rr_.get());
488 }
489
490 unsigned int
getRRCount(const Section section) const491 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
addRRset(const Section section,RRsetPtr rrset)499 Message::addRRset(const Section section, RRsetPtr rrset) {
500 if (!rrset) {
501 isc_throw(InvalidParameter,
502 "NULL RRset is given to Message::addRRset");
503 }
504 if (impl_->mode_ != Message::RENDER) {
505 isc_throw(InvalidMessageOperation,
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
hasRRset(const Section section,const Name & name,const RRClass & rrclass,const RRType & rrtype) const518 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
hasRRset(const Section section,const RRsetPtr & rrset) const537 Message::hasRRset(const Section section, const RRsetPtr& rrset) const {
538 return (hasRRset(section, rrset->getName(),
539 rrset->getClass(), rrset->getType()));
540 }
541
542 bool
removeRRset(const Section section,RRsetIterator & iterator)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
clearSection(const Section section)568 Message::clearSection(const Section section) {
569 if (impl_->mode_ != Message::RENDER) {
570 isc_throw(InvalidMessageOperation,
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
addQuestion(const QuestionPtr question)585 Message::addQuestion(const QuestionPtr question) {
586 if (impl_->mode_ != Message::RENDER) {
587 isc_throw(InvalidMessageOperation,
588 "addQuestion performed in non-render mode");
589 }
590
591 impl_->questions_.push_back(question);
592 ++impl_->counts_[SECTION_QUESTION];
593 }
594
595 void
addQuestion(const Question & question)596 Message::addQuestion(const Question& question) {
597 addQuestion(QuestionPtr(new Question(question)));
598 }
599
600 void
toWire(AbstractMessageRenderer & renderer,TSIGContext * tsig_ctx)601 Message::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) {
602 impl_->toWire(renderer, tsig_ctx);
603 }
604
605 void
parseHeader(InputBuffer & buffer)606 Message::parseHeader(InputBuffer& buffer) {
607 if (impl_->mode_ != Message::PARSE) {
608 isc_throw(InvalidMessageOperation,
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
fromWire(InputBuffer & buffer,ParseOptions options)635 Message::fromWire(InputBuffer& buffer, ParseOptions options) {
636 if (impl_->mode_ != Message::PARSE) {
637 isc_throw(InvalidMessageOperation,
638 "Message parse attempted in non parse mode");
639 }
640
641 // Clear any old parsed data
642 clear(Message::PARSE);
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
parseQuestion(InputBuffer & buffer)657 MessageImpl::parseQuestion(InputBuffer& buffer) {
658 unsigned int added = 0;
659
660 for (unsigned int count = 0;
661 count < counts_[Message::SECTION_QUESTION];
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> {
MatchRRisc::dns::__anon51655ca60311::MatchRR686 MatchRR(const Name& name, const RRType& rrtype, const RRClass& rrclass) :
687 name_(name), rrtype_(rrtype), rrclass_(rrclass) {}
operator ()isc::dns::__anon51655ca60311::MatchRR688 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
parseSection(const Message::Section section,InputBuffer & buffer,Message::ParseOptions options)728 MessageImpl::parseSection(const Message::Section section,
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
addRR(Message::Section section,const Name & name,const RRClass & rrclass,const RRType & rrtype,const RRTTL & ttl,ConstRdataPtr rdata,Message::ParseOptions options)781 MessageImpl::addRR(Message::Section section, const Name& name,
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
addRR(Message::Section section,const Name & name,const RRClass & rrclass,const RRType & rrtype,const RRTTL & ttl,Message::ParseOptions options)802 MessageImpl::addRR(Message::Section section, const Name& name,
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
addEDNS(Message::Section section,const Name & name,const RRClass & rrclass,const RRType & rrtype,const RRTTL & ttl,const Rdata & rdata)820 MessageImpl::addEDNS(Message::Section section, const Name& name,
821 const RRClass& rrclass, const RRType& rrtype,
822 const RRTTL& ttl, const Rdata& rdata)
823 {
824 if (section != Message::SECTION_ADDITIONAL) {
825 isc_throw(DNSMessageFORMERR,
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
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)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) {
845 isc_throw(DNSMessageFORMERR,
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 {
SectionFormatterisc::dns::__anon51655ca60411::SectionFormatter865 SectionFormatter(const Message::Section section, string& output) :
866 section_(section), output_(output) {}
operator ()isc::dns::__anon51655ca60411::SectionFormatter867 void operator()(const T& entry) {
868 if (section_ == Message::SECTION_QUESTION) {
869 output_ += ";";
870 output_ += entry->toText();
871 output_ += "\n";
872 } else {
873 output_ += entry->toText();
874 }
875 }
876 const Message::Section section_;
877 string& output_;
878 };
879 }
880
881 string
toText() const882 Message::toText() const {
883 if (impl_->rcode_ == NULL) {
884 isc_throw(InvalidMessageOperation,
885 "Message::toText() attempted without Rcode set");
886 }
887 if (impl_->opcode_ == NULL) {
888 isc_throw(InvalidMessageOperation,
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:";
899 if (getHeaderFlag(HEADERFLAG_QR)) {
900 s += " qr";
901 }
902 if (getHeaderFlag(HEADERFLAG_AA)) {
903 s += " aa";
904 }
905 if (getHeaderFlag(HEADERFLAG_TC)) {
906 s += " tc";
907 }
908 if (getHeaderFlag(HEADERFLAG_RD)) {
909 s += " rd";
910 }
911 if (getHeaderFlag(HEADERFLAG_RA)) {
912 s += " ra";
913 }
914 if (getHeaderFlag(HEADERFLAG_AD)) {
915 s += " ad";
916 }
917 if (getHeaderFlag(HEADERFLAG_CD)) {
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
clear(Mode mode)981 Message::clear(Mode mode) {
982 impl_->init();
983 impl_->mode_ = mode;
984 }
985
986 void
appendSection(const Section section,const Message & source)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
makeResponse()1008 Message::makeResponse() {
1009 if (impl_->mode_ != Message::PARSE) {
1010 isc_throw(InvalidMessageOperation,
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;
1018 setHeaderFlag(HEADERFLAG_QR, true);
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
1028 ///
1029 /// Template version of Section Iterator
1030 ///
1031 template <typename T>
1032 struct SectionIteratorImpl {
SectionIteratorImplisc::dns::SectionIteratorImpl1033 SectionIteratorImpl(const typename vector<T>::const_iterator& it) :
1034 it_(it) {}
1035 typename vector<T>::const_iterator it_;
1036 };
1037
1038 template <typename T>
SectionIterator(const SectionIteratorImpl<T> & impl)1039 SectionIterator<T>::SectionIterator(const SectionIteratorImpl<T>& impl) {
1040 impl_ = new SectionIteratorImpl<T>(impl.it_);
1041 }
1042
1043 template <typename T>
~SectionIterator()1044 SectionIterator<T>::~SectionIterator() {
1045 delete impl_;
1046 }
1047
1048 template <typename T>
SectionIterator(const SectionIterator<T> & source)1049 SectionIterator<T>::SectionIterator(const SectionIterator<T>& source) :
1050 impl_(new SectionIteratorImpl<T>(source.impl_->it_))
1051 {}
1052
1053 template <typename T>
1054 void
operator =(const SectionIterator<T> & source)1055 SectionIterator<T>::operator=(const SectionIterator<T>& source) {
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>
1066 SectionIterator<T>&
operator ++()1067 SectionIterator<T>::operator++() {
1068 ++(impl_->it_);
1069 return (*this);
1070 }
1071
1072 template <typename T>
1073 SectionIterator<T>
operator ++(int)1074 SectionIterator<T>::operator++(int) {
1075 SectionIterator<T> tmp(*this);
1076 ++(*this);
1077 return (tmp);
1078 }
1079
1080 template <typename T>
1081 const T&
operator *() const1082 SectionIterator<T>::operator*() const {
1083 return (*(impl_->it_));
1084 }
1085
1086 template <typename T>
1087 const T*
operator ->() const1088 SectionIterator<T>::operator->() const {
1089 return (&(operator*()));
1090 }
1091
1092 template <typename T>
1093 bool
operator ==(const SectionIterator<T> & other) const1094 SectionIterator<T>::operator==(const SectionIterator<T>& other) const {
1095 return (impl_->it_ == other.impl_->it_);
1096 }
1097
1098 template <typename T>
1099 bool
operator !=(const SectionIterator<T> & other) const1100 SectionIterator<T>::operator!=(const SectionIterator<T>& other) const {
1101 return (impl_->it_ != other.impl_->it_);
1102 }
1103
1104 ///
1105 /// We need to explicitly instantiate these template classes because these
1106 /// are public classes but defined in this implementation file.
1107 ///
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
1116 ///
1117 /// Question iterator
1118 ///
1119 const QuestionIterator
beginQuestion() const1120 Message::beginQuestion() const {
1121 return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
1122 }
1123
1124 const QuestionIterator
endQuestion() const1125 Message::endQuestion() const {
1126 return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.end())));
1127 }
1128
1129 ///
1130 /// RRsets iterators
1131 ///
1132 const SectionIterator<RRsetPtr>
beginSection(const Section section) const1133 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) {
1138 isc_throw(InvalidMessageSection,
1139 "RRset iterator is requested for question");
1140 }
1141
1142 return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].begin())));
1143 }
1144
1145 const SectionIterator<RRsetPtr>
endSection(const Section section) const1146 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) {
1151 isc_throw(InvalidMessageSection,
1152 "RRset iterator is requested for question");
1153 }
1154
1155 return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].end())));
1156 }
1157
1158 ostream&
operator <<(ostream & os,const Message & message)1159 operator<<(ostream& os, const Message& message) {
1160 return (os << message.toText());
1161 }
1162 } // end of namespace dns
1163 } // end of namespace isc
1164