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