Branch data Line data Source code
1 : : // Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #include <stdint.h>
16 : :
17 : : #include <algorithm>
18 : : #include <cassert>
19 : : #include <string>
20 : : #include <sstream>
21 : : #include <vector>
22 : :
23 : : #include <boost/foreach.hpp>
24 : : #include <boost/lexical_cast.hpp>
25 : : #include <boost/shared_ptr.hpp>
26 : :
27 : : #include <exceptions/exceptions.h>
28 : :
29 : : #include <util/buffer.h>
30 : :
31 : : #include <dns/edns.h>
32 : : #include <dns/exceptions.h>
33 : : #include <dns/message.h>
34 : : #include <dns/messagerenderer.h>
35 : : #include <dns/name.h>
36 : : #include <dns/opcode.h>
37 : : #include <dns/rcode.h>
38 : : #include <dns/question.h>
39 : : #include <dns/rdataclass.h>
40 : : #include <dns/rrclass.h>
41 : : #include <dns/rrtype.h>
42 : : #include <dns/rrttl.h>
43 : : #include <dns/rrset.h>
44 : : #include <dns/tsig.h>
45 : :
46 : : using namespace std;
47 : : using namespace boost;
48 : : using namespace isc::dns::rdata;
49 : : using namespace isc::util;
50 : :
51 : : namespace isc {
52 : : namespace dns {
53 : :
54 : : namespace {
55 : : // protocol constants
56 : : const size_t HEADERLEN = 12;
57 : :
58 : : const unsigned int OPCODE_MASK = 0x7800;
59 : : const unsigned int OPCODE_SHIFT = 11;
60 : : const unsigned int RCODE_MASK = 0x000f;
61 : :
62 : : // This diagram shows the wire-format representation of the 2nd 16 bits of
63 : : // the DNS header section, which contain all defined flag bits.
64 : : //
65 : : // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
66 : : // |QR| Opcode |AA|TC|RD|RA| |AD|CD| RCODE |
67 : : // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
68 : : // 1 0 0 0| 0 1 1 1| 1 0 1 1| 0 0 0 0|
69 : : // 0x8 0x7 0xb 0x0
70 : : //
71 : : // This mask covers all the flag bits, and those bits only.
72 : : // Note: we reject a "flag" the is not covered by this mask in some of the
73 : : // public methods. This means our current definition is not fully extendable;
74 : : // applications cannot introduce a new flag bit temporarily without modifying
75 : : // the source code.
76 : : const unsigned int HEADERFLAG_MASK = 0x87b0;
77 : :
78 : : // This is a set of flag bits that should be preserved when building a reply
79 : : // from a request.
80 : : // Note: we assume the specific definition of HEADERFLAG_xx. We may change
81 : : // the definition in future, in which case we need to adjust this definition,
82 : : // too (see also the description about the Message::HeaderFlag type).
83 : : const uint16_t MESSAGE_REPLYPRESERVE = (Message::HEADERFLAG_RD |
84 : : Message::HEADERFLAG_CD);
85 : :
86 : : const char* const sectiontext[] = {
87 : : "QUESTION",
88 : : "ANSWER",
89 : : "AUTHORITY",
90 : : "ADDITIONAL"
91 : : };
92 : : }
93 : :
94 [ + - ][ + + ]: 7965 : class MessageImpl {
[ + - ][ # # ]
[ # # ]
95 : : public:
96 : : MessageImpl(Message::Mode mode);
97 : : // Open issues: should we rather have a header in wire-format
98 : : // for efficiency?
99 : : Message::Mode mode_;
100 : : qid_t qid_;
101 : :
102 : : // We want to use NULL for [op,r]code_ to mean the code being not
103 : : // correctly parsed or set. We store the real code object in
104 : : // xxcode_placeholder_ and have xxcode_ refer to it when the object
105 : : // is valid.
106 : : const Rcode* rcode_;
107 : : Rcode rcode_placeholder_;
108 : : const Opcode* opcode_;
109 : : Opcode opcode_placeholder_;
110 : :
111 : : uint16_t flags_; // wire-format representation of header flags.
112 : :
113 : : bool header_parsed_;
114 : : static const unsigned int NUM_SECTIONS = 4; // TODO: revisit this design
115 : : int counts_[NUM_SECTIONS]; // TODO: revisit this definition
116 : : vector<QuestionPtr> questions_;
117 : : vector<RRsetPtr> rrsets_[NUM_SECTIONS];
118 : : ConstEDNSPtr edns_;
119 : : ConstTSIGRecordPtr tsig_rr_;
120 : :
121 : : // RRsetsSorter* sorter_; : TODO
122 : :
123 : : void init();
124 : : void setOpcode(const Opcode& opcode);
125 : : void setRcode(const Rcode& rcode);
126 : : int parseQuestion(InputBuffer& buffer);
127 : : int parseSection(const Message::Section section, InputBuffer& buffer,
128 : : Message::ParseOptions options);
129 : : void addRR(Message::Section section, const Name& name,
130 : : const RRClass& rrclass, const RRType& rrtype,
131 : : const RRTTL& ttl, ConstRdataPtr rdata,
132 : : Message::ParseOptions options);
133 : : void addEDNS(Message::Section section, const Name& name,
134 : : const RRClass& rrclass, const RRType& rrtype,
135 : : const RRTTL& ttl, const Rdata& rdata);
136 : : void addTSIG(Message::Section section, unsigned int count,
137 : : const InputBuffer& buffer, size_t start_position,
138 : : const Name& name, const RRClass& rrclass,
139 : : const RRTTL& ttl, const Rdata& rdata);
140 : : void toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx);
141 : : };
142 : :
143 : 1613 : MessageImpl::MessageImpl(Message::Mode mode) :
144 : : mode_(mode),
145 : : rcode_placeholder_(Rcode(0)), // as a placeholder the value doesn't matter
146 [ + + ]: 8065 : opcode_placeholder_(Opcode(0)) // ditto
147 : : {
148 [ + - ]: 1613 : init();
149 [ # # ][ # # ]: 1613 : }
150 : :
151 : : void
152 : 2343 : MessageImpl::init() {
153 : 2343 : flags_ = 0;
154 : 2343 : qid_ = 0;
155 : 2343 : rcode_ = NULL;
156 : 2343 : opcode_ = NULL;
157 [ + - ]: 2343 : edns_ = EDNSPtr();
158 [ + - ]: 2343 : tsig_rr_ = ConstTSIGRecordPtr();
159 : :
160 [ + + ]: 11715 : for (int i = 0; i < NUM_SECTIONS; ++i) {
161 : 9372 : counts_[i] = 0;
162 : : }
163 : :
164 : 2343 : header_parsed_ = false;
165 : 2343 : questions_.clear();
166 : 2343 : rrsets_[Message::SECTION_ANSWER].clear();
167 : 2343 : rrsets_[Message::SECTION_AUTHORITY].clear();
168 : 2343 : rrsets_[Message::SECTION_ADDITIONAL].clear();
169 : 2343 : }
170 : :
171 : : void
172 : 1893 : MessageImpl::setOpcode(const Opcode& opcode) {
173 : 1893 : opcode_placeholder_ = opcode;
174 : 1893 : opcode_ = &opcode_placeholder_;
175 : 1893 : }
176 : :
177 : : void
178 : 2118 : MessageImpl::setRcode(const Rcode& rcode) {
179 : 2118 : rcode_placeholder_ = rcode;
180 : 2118 : rcode_ = &rcode_placeholder_;
181 : 2118 : }
182 : :
183 : : namespace {
184 : : // This helper class is used by MessageImpl::toWire() to render a set of
185 : : // RRsets of a specific section of message to a given MessageRenderer.
186 : : //
187 : : // A RenderSection object is expected to be used with a QuestionIterator or
188 : : // SectionIterator. Its operator() is called for each RRset as the iterator
189 : : // iterates over the corresponding section, and it renders the RRset to
190 : : // the given MessageRenderer, while counting the number of RRs (note: not
191 : : // RRsets) successfully rendered. If the MessageRenderer reports the need
192 : : // for truncation (via its isTruncated() method), the RenderSection object
193 : : // stops rendering further RRsets. In addition, unless partial_ok (given on
194 : : // construction) is true, it removes any RRs that are partially rendered
195 : : // from the MessageRenderer.
196 : : //
197 : : // On the completion of rendering the entire section, the owner of the
198 : : // RenderSection object can get the number of rendered RRs via the
199 : : // getTotalCount() method.
200 : : template <typename T>
201 : : struct RenderSection {
202 : : RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
203 : : counter_(0), renderer_(renderer), partial_ok_(partial_ok),
204 : 3632 : truncated_(false)
205 : : {}
206 : : void operator()(const T& entry) {
207 : : // If it's already truncated, ignore the rest of the section.
208 [ + - ][ + - ]: 1366 : if (truncated_) {
209 : : return;
210 : : }
211 : 1366 : const size_t pos0 = renderer_.getLength();
212 : 1366 : counter_ += entry->toWire(renderer_);
213 [ + + + + ]: 1364 : if (renderer_.isTruncated()) {
214 : 16 : truncated_ = true;
215 [ - + ][ + - ]: 16 : if (!partial_ok_) {
216 : : // roll back to the end of the previous RRset.
217 : 4 : renderer_.trim(renderer_.getLength() - pos0);
218 : : }
219 : : }
220 : : }
221 : 0 : unsigned int getTotalCount() { return (counter_); }
222 : : unsigned int counter_;
223 : : AbstractMessageRenderer& renderer_;
224 : : const bool partial_ok_;
225 : : bool truncated_;
226 : : };
227 : : }
228 : :
229 : : void
230 : 923 : MessageImpl::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) {
231 [ + + ]: 923 : if (mode_ != Message::RENDER) {
232 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
233 : : "Message rendering attempted in non render mode");
234 : : }
235 [ + + ]: 921 : if (rcode_ == NULL) {
236 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
237 : : "Message rendering attempted without Rcode set");
238 : : }
239 [ + + ]: 919 : if (opcode_ == NULL) {
240 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
241 : : "Message rendering attempted without Opcode set");
242 : : }
243 : :
244 : : // Reserve the space for TSIG (if needed) so that we can handle truncation
245 : : // case correctly later when that happens. orig_xxx variables remember
246 : : // some configured parameters of renderer in case they are needed in
247 : : // truncation processing below.
248 [ + + ]: 917 : const size_t tsig_len = (tsig_ctx != NULL) ? tsig_ctx->getTSIGLength() : 0;
249 : 917 : const size_t orig_msg_len_limit = renderer.getLengthLimit();
250 : : const AbstractMessageRenderer::CompressMode orig_compress_mode =
251 : 917 : renderer.getCompressMode();
252 [ + + ]: 917 : if (tsig_len > 0) {
253 [ + + ]: 160 : if (tsig_len > orig_msg_len_limit) {
254 [ + - ][ + - ]: 6 : isc_throw(InvalidParameter, "Failed to render DNS message: "
255 : : "too small limit for a TSIG (" <<
256 : : orig_msg_len_limit << ")");
257 : : }
258 : 158 : renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
259 : : }
260 : :
261 : : // reserve room for the header
262 [ + + ]: 915 : if (renderer.getLengthLimit() < HEADERLEN) {
263 [ + - ]: 4 : isc_throw(InvalidParameter, "Failed to render DNS message: "
264 : : "too small limit for a Header");
265 : : }
266 : 913 : renderer.skip(HEADERLEN);
267 : :
268 : : uint16_t qdcount =
269 : 1826 : for_each(questions_.begin(), questions_.end(),
270 : 913 : RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
271 : :
272 : : // TODO: sort RRsets in each section based on configuration policy.
273 : 913 : uint16_t ancount = 0;
274 [ + + ]: 913 : if (!renderer.isTruncated()) {
275 : : ancount =
276 : 911 : for_each(rrsets_[Message::SECTION_ANSWER].begin(),
277 : 911 : rrsets_[Message::SECTION_ANSWER].end(),
278 : 911 : RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
279 : : }
280 : 911 : uint16_t nscount = 0;
281 [ + + ]: 911 : if (!renderer.isTruncated()) {
282 : : nscount =
283 : 905 : for_each(rrsets_[Message::SECTION_AUTHORITY].begin(),
284 : 905 : rrsets_[Message::SECTION_AUTHORITY].end(),
285 : 905 : RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
286 : : }
287 : 911 : uint16_t arcount = 0;
288 [ + + ]: 911 : if (renderer.isTruncated()) {
289 : 14 : flags_ |= Message::HEADERFLAG_TC;
290 : : } else {
291 : : arcount =
292 : 897 : for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
293 : 897 : rrsets_[Message::SECTION_ADDITIONAL].end(),
294 : 897 : RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
295 : : }
296 : :
297 : : // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
298 : : // has been explicitly set. However, if the RCODE would require it and
299 : : // no EDNS has been set we generate a temporary local EDNS and use it.
300 [ + + ]: 911 : if (!renderer.isTruncated()) {
301 : 897 : ConstEDNSPtr local_edns = edns_;
302 [ + + ][ + - ]: 897 : if (!local_edns && rcode_->getExtendedCode() != 0) {
[ + + ][ + + ]
303 [ + - ][ + - ]: 2 : local_edns = ConstEDNSPtr(new EDNS());
[ + - ][ + - ]
304 : : }
305 [ + + ]: 897 : if (local_edns) {
306 [ + - ][ + - ]: 262 : arcount += local_edns->toWire(renderer, rcode_->getExtendedCode());
307 : : }
308 : : }
309 : :
310 : : // If we're adding a TSIG to a truncated message, clear all RRsets
311 : : // from the message except for the question before adding the TSIG.
312 : : // If even (some of) the question doesn't fit, don't include it.
313 [ + + ][ + + ]: 911 : if (tsig_ctx != NULL && renderer.isTruncated()) {
[ + + ]
314 : 6 : renderer.clear();
315 : 6 : renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
316 : 6 : renderer.setCompressMode(orig_compress_mode);
317 : 6 : renderer.skip(HEADERLEN);
318 : 12 : qdcount = for_each(questions_.begin(), questions_.end(),
319 : : RenderSection<QuestionPtr>(renderer,
320 : 6 : false)).getTotalCount();
321 : 6 : ancount = 0;
322 : 6 : nscount = 0;
323 : 6 : arcount = 0;
324 : : }
325 : :
326 : : // Adjust the counter buffer.
327 : : // XXX: these may not be equal to the number of corresponding entries
328 : : // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
329 : : // was inserted. This is not good, and we should revisit the entire
330 : : // design.
331 : 911 : counts_[Message::SECTION_QUESTION] = qdcount;
332 : 911 : counts_[Message::SECTION_ANSWER] = ancount;
333 : 911 : counts_[Message::SECTION_AUTHORITY] = nscount;
334 : 911 : counts_[Message::SECTION_ADDITIONAL] = arcount;
335 : :
336 : : // fill in the header
337 : 911 : size_t header_pos = 0;
338 : 911 : renderer.writeUint16At(qid_, header_pos);
339 : 911 : header_pos += sizeof(uint16_t);
340 : :
341 : : uint16_t codes_and_flags =
342 : 1822 : (opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
343 : 1822 : codes_and_flags |= (rcode_->getCode() & RCODE_MASK);
344 : 911 : codes_and_flags |= (flags_ & HEADERFLAG_MASK);
345 : 911 : renderer.writeUint16At(codes_and_flags, header_pos);
346 : 911 : header_pos += sizeof(uint16_t);
347 : : // TODO: should avoid repeated pattern
348 : 911 : renderer.writeUint16At(qdcount, header_pos);
349 : 911 : header_pos += sizeof(uint16_t);
350 : 911 : renderer.writeUint16At(ancount, header_pos);
351 : 911 : header_pos += sizeof(uint16_t);
352 : 911 : renderer.writeUint16At(nscount, header_pos);
353 : 911 : header_pos += sizeof(uint16_t);
354 : 911 : renderer.writeUint16At(arcount, header_pos);
355 : :
356 : : // Add TSIG, if necessary, at the end of the message.
357 [ + + ]: 911 : if (tsig_ctx != NULL) {
358 : : // Release the reserved space in the renderer.
359 : 156 : renderer.setLengthLimit(orig_msg_len_limit);
360 : :
361 : : const int tsig_count =
362 : : tsig_ctx->sign(qid_, renderer.getData(),
363 [ + - ]: 312 : renderer.getLength())->toWire(renderer);
364 [ + + ]: 156 : if (tsig_count != 1) {
365 [ + - ]: 2 : isc_throw(Unexpected, "Failed to render a TSIG RR");
366 : : }
367 : :
368 : : // update the ARCOUNT for the TSIG RR. Note that for a sane DNS
369 : : // message arcount should never overflow to 0.
370 : 155 : renderer.writeUint16At(++arcount, header_pos);
371 : : }
372 : 910 : }
373 : :
374 : 1613 : Message::Message(Mode mode) :
375 [ + - ]: 1613 : impl_(new MessageImpl(mode))
376 : 1613 : {}
377 : :
378 : 1593 : Message::~Message() {
379 [ + - ]: 3186 : delete impl_;
380 : 1593 : }
381 : :
382 : : bool
383 : 5472 : Message::getHeaderFlag(const HeaderFlag flag) const {
384 [ + - ][ - + ]: 5472 : if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
385 [ # # ][ # # ]: 0 : isc_throw(InvalidParameter,
386 : : "Message::getHeaderFlag:: Invalid flag is specified: " <<
387 : : flag);
388 : : }
389 : 5472 : return ((impl_->flags_ & flag) != 0);
390 : : }
391 : :
392 : : void
393 : 1458 : Message::setHeaderFlag(const HeaderFlag flag, const bool on) {
394 [ + + ]: 1458 : if (impl_->mode_ != Message::RENDER) {
395 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
396 : : "setHeaderFlag performed in non-render mode");
397 : : }
398 [ + + ][ + + ]: 1456 : if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
399 [ + - ][ + - ]: 18 : isc_throw(InvalidParameter,
400 : : "Message::getHeaderFlag:: Invalid flag is specified: " <<
401 : : flag);
402 : : }
403 [ + + ]: 1447 : if (on) {
404 : 1315 : impl_->flags_ |= flag;
405 : : } else {
406 : 132 : impl_->flags_ &= ~flag;
407 : : }
408 : 1447 : }
409 : :
410 : : qid_t
411 : 826 : Message::getQid() const {
412 : 826 : return (impl_->qid_);
413 : : }
414 : :
415 : : void
416 : 862 : Message::setQid(qid_t qid) {
417 [ + + ]: 862 : if (impl_->mode_ != Message::RENDER) {
418 [ + - ][ + - ]: 2 : isc_throw(InvalidMessageOperation,
419 : : "setQid performed in non-render mode");
420 : : }
421 : 861 : impl_->qid_ = qid;
422 : 861 : }
423 : :
424 : : const Rcode&
425 : 899 : Message::getRcode() const {
426 [ + + ]: 899 : if (impl_->rcode_ == NULL) {
427 [ + - ][ + - ]: 2 : isc_throw(InvalidMessageOperation, "getRcode attempted before set");
428 : : }
429 : 898 : return (*impl_->rcode_);
430 : : }
431 : :
432 : : void
433 : 1367 : Message::setRcode(const Rcode& rcode) {
434 [ + + ]: 1367 : if (impl_->mode_ != Message::RENDER) {
435 [ + - ][ + - ]: 2 : isc_throw(InvalidMessageOperation,
436 : : "setRcode performed in non-render mode");
437 : : }
438 : 1366 : impl_->setRcode(rcode);
439 : 1366 : }
440 : :
441 : : const Opcode&
442 : 1404 : Message::getOpcode() const {
443 [ + + ]: 1404 : if (impl_->opcode_ == NULL) {
444 [ + - ][ + - ]: 2 : isc_throw(InvalidMessageOperation, "getOpcode attempted before set");
445 : : }
446 : 1403 : return (*impl_->opcode_);
447 : : }
448 : :
449 : : void
450 : 1176 : Message::setOpcode(const Opcode& opcode) {
451 [ + + ]: 1176 : if (impl_->mode_ != Message::RENDER) {
452 [ + - ][ + - ]: 6 : isc_throw(InvalidMessageOperation,
453 : : "setOpcode performed in non-render mode");
454 : : }
455 : 1173 : impl_->setOpcode(opcode);
456 : 1173 : }
457 : :
458 : : ConstEDNSPtr
459 : 60 : Message::getEDNS() const {
460 : 60 : return (impl_->edns_);
461 : : }
462 : :
463 : : void
464 : 110 : Message::setEDNS(ConstEDNSPtr edns) {
465 [ + + ]: 110 : if (impl_->mode_ != Message::RENDER) {
466 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
467 : : "setEDNS performed in non-render mode");
468 : : }
469 : 108 : impl_->edns_ = edns;
470 : 108 : }
471 : :
472 : : const TSIGRecord*
473 : 564 : Message::getTSIGRecord() const {
474 [ + + ]: 564 : if (impl_->mode_ != Message::PARSE) {
475 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
476 : : "getTSIGRecord performed in non-parse mode");
477 : : }
478 : :
479 : 562 : return (impl_->tsig_rr_.get());
480 : : }
481 : :
482 : : unsigned int
483 : 1474 : Message::getRRCount(const Section section) const {
484 [ + + ]: 1474 : if (section >= MessageImpl::NUM_SECTIONS) {
485 [ + - ][ + - ]: 4 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ + - ]
486 : : }
487 : 1472 : return (impl_->counts_[section]);
488 : : }
489 : :
490 : : void
491 : 1140 : Message::addRRset(const Section section, RRsetPtr rrset, const bool sign) {
492 [ + + ]: 1140 : if (!rrset) {
493 [ + - ]: 2 : isc_throw(InvalidParameter,
494 : : "NULL RRset is given to Message::addRRset");
495 : : }
496 [ + + ]: 1139 : if (impl_->mode_ != Message::RENDER) {
497 [ + - ][ + - ]: 6 : isc_throw(InvalidMessageOperation,
498 : : "addRRset performed in non-render mode");
499 : : }
500 [ + + ]: 1136 : if (section >= MessageImpl::NUM_SECTIONS) {
501 [ + - ][ + - ]: 6 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ + - ]
502 : : }
503 : :
504 : 1133 : impl_->rrsets_[section].push_back(rrset);
505 : 1133 : impl_->counts_[section] += rrset->getRdataCount();
506 : :
507 : 1133 : RRsetPtr sp = rrset->getRRsig();
508 [ + + ][ + + ]: 1316 : if (sign && sp != NULL) {
[ + + ]
509 [ + - ]: 159 : impl_->rrsets_[section].push_back(sp);
510 [ + - ]: 159 : impl_->counts_[section] += sp->getRdataCount();
511 : : }
512 : 1133 : }
513 : :
514 : : bool
515 : 293 : Message::hasRRset(const Section section, const Name& name,
516 : : const RRClass& rrclass, const RRType& rrtype)
517 : : {
518 [ + + ]: 293 : if (section >= MessageImpl::NUM_SECTIONS) {
519 [ + - ][ + - ]: 4 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ + - ]
520 : : }
521 : :
522 [ + + + - ]: 1335 : BOOST_FOREACH(ConstRRsetPtr r, impl_->rrsets_[section]) {
[ + - ][ + + ]
[ + + ]
523 [ + - ][ + + ]: 759 : if (r->getClass() == rrclass &&
[ + + ][ + + ]
[ + + ]
524 [ + - ]: 291 : r->getType() == rrtype &&
525 [ + - ]: 175 : r->getName() == name) {
526 : 64 : return (true);
527 : : }
528 : : }
529 : :
530 : : return (false);
531 : : }
532 : :
533 : : bool
534 : 72 : Message::hasRRset(const Section section, const RRsetPtr& rrset) {
535 : 72 : return (hasRRset(section, rrset->getName(), rrset->getClass(), rrset->getType()));
536 : : }
537 : :
538 : : bool
539 : 16 : Message::removeRRset(const Section section, RRsetIterator& iterator) {
540 [ - + ]: 16 : if (section >= MessageImpl::NUM_SECTIONS) {
541 [ # # ][ # # ]: 0 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ # # ]
542 : : }
543 : :
544 : 16 : bool removed = false;
545 [ + - ]: 30 : for (vector<RRsetPtr>::iterator i = impl_->rrsets_[section].begin();
546 : 60 : i != impl_->rrsets_[section].end(); ++i) {
547 [ + + + - : 94 : if (((*i)->getName() == (*iterator)->getName()) &&
+ + ][ + + ]
548 : 17 : ((*i)->getClass() == (*iterator)->getClass()) &&
549 : 17 : ((*i)->getType() == (*iterator)->getType())) {
550 : :
551 : : // Found the matching RRset so remove it & ignore rest
552 : 16 : impl_->counts_[section] -= (*iterator)->getRdataCount();
553 : 16 : impl_->rrsets_[section].erase(i);
554 : : removed = true;
555 : : break;
556 : : }
557 : : }
558 : :
559 : 16 : return (removed);
560 : : }
561 : :
562 : : void
563 : 25 : Message::clearSection(const Section section) {
564 [ - + ]: 25 : if (section >= MessageImpl::NUM_SECTIONS) {
565 [ # # ][ # # ]: 0 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ # # ]
566 : : }
567 : 25 : impl_->rrsets_[section].clear();
568 : 25 : impl_->counts_[section] = 0;
569 : 25 : }
570 : :
571 : : void
572 : 826 : Message::addQuestion(const QuestionPtr question) {
573 [ - + ]: 826 : if (impl_->mode_ != Message::RENDER) {
574 [ # # ][ # # ]: 0 : isc_throw(InvalidMessageOperation,
575 : : "addQuestion performed in non-render mode");
576 : : }
577 : :
578 : 826 : impl_->questions_.push_back(question);
579 : 826 : ++impl_->counts_[SECTION_QUESTION];
580 : 826 : }
581 : :
582 : : void
583 : 775 : Message::addQuestion(const Question& question) {
584 [ + - ]: 1550 : addQuestion(QuestionPtr(new Question(question)));
585 : 775 : }
586 : :
587 : : void
588 : 763 : Message::toWire(AbstractMessageRenderer& renderer) {
589 : 763 : impl_->toWire(renderer, NULL);
590 : 755 : }
591 : :
592 : : void
593 : 160 : Message::toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx) {
594 : 160 : impl_->toWire(renderer, &tsig_ctx);
595 : 155 : }
596 : :
597 : : void
598 : 731 : Message::parseHeader(InputBuffer& buffer) {
599 [ + + ]: 731 : if (impl_->mode_ != Message::PARSE) {
600 [ + - ][ + - ]: 2 : isc_throw(InvalidMessageOperation,
601 : : "Message parse attempted in non parse mode");
602 : : }
603 : :
604 [ + + ]: 730 : if ((buffer.getLength() - buffer.getPosition()) < HEADERLEN) {
605 [ + - ]: 30 : isc_throw(MessageTooShort, "Malformed DNS message (short length): "
606 : : << buffer.getLength() - buffer.getPosition());
607 : : }
608 : :
609 : 720 : impl_->qid_ = buffer.readUint16();
610 : 720 : const uint16_t codes_and_flags = buffer.readUint16();
611 : 720 : impl_->setOpcode(Opcode((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT));
612 : 720 : impl_->setRcode(Rcode(codes_and_flags & RCODE_MASK));
613 : 720 : impl_->flags_ = (codes_and_flags & HEADERFLAG_MASK);
614 : 720 : impl_->counts_[SECTION_QUESTION] = buffer.readUint16();
615 : 720 : impl_->counts_[SECTION_ANSWER] = buffer.readUint16();
616 : 720 : impl_->counts_[SECTION_AUTHORITY] = buffer.readUint16();
617 : 720 : impl_->counts_[SECTION_ADDITIONAL] = buffer.readUint16();
618 : :
619 : 720 : impl_->header_parsed_ = true;
620 : 720 : }
621 : :
622 : : void
623 : 723 : Message::fromWire(InputBuffer& buffer, ParseOptions options) {
624 [ + + ]: 723 : if (impl_->mode_ != Message::PARSE) {
625 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
626 : : "Message parse attempted in non parse mode");
627 : : }
628 : :
629 [ + + ]: 721 : if (!impl_->header_parsed_) {
630 : 488 : parseHeader(buffer);
631 : : }
632 : :
633 : 713 : impl_->counts_[SECTION_QUESTION] = impl_->parseQuestion(buffer);
634 : : impl_->counts_[SECTION_ANSWER] =
635 : 711 : impl_->parseSection(SECTION_ANSWER, buffer, options);
636 : : impl_->counts_[SECTION_AUTHORITY] =
637 : 705 : impl_->parseSection(SECTION_AUTHORITY, buffer, options);
638 : : impl_->counts_[SECTION_ADDITIONAL] =
639 : 705 : impl_->parseSection(SECTION_ADDITIONAL, buffer, options);
640 : 690 : }
641 : :
642 : : int
643 : 713 : MessageImpl::parseQuestion(InputBuffer& buffer) {
644 : 713 : unsigned int added = 0;
645 : :
646 [ + + ]: 1443 : for (unsigned int count = 0;
647 : 1443 : count < counts_[Message::SECTION_QUESTION];
648 : : ++count) {
649 : 1464 : const Name name(buffer);
650 : :
651 [ + + ]: 732 : if ((buffer.getLength() - buffer.getPosition()) <
652 : : 2 * sizeof(uint16_t)) {
653 [ + - ][ + - ]: 6 : isc_throw(DNSMessageFORMERR, "Question section too short: " <<
[ + - ]
654 : : (buffer.getLength() - buffer.getPosition()) << " bytes");
655 : : }
656 [ + - ]: 730 : const RRType rrtype(buffer.readUint16());
657 [ + - ]: 730 : const RRClass rrclass(buffer.readUint16());
658 : :
659 : : // XXX: need a duplicate check. We might also want to have an
660 : : // optimized algorithm that requires the question section contain
661 : : // exactly one RR.
662 : :
663 [ + - ][ + - ]: 1460 : questions_.push_back(QuestionPtr(new Question(name, rrclass, rrtype)));
[ + - ]
664 : 730 : ++added;
665 : : }
666 : :
667 : 711 : return (added);
668 : : }
669 : :
670 : : namespace {
671 : : struct MatchRR : public unary_function<RRsetPtr, bool> {
672 : : MatchRR(const Name& name, const RRType& rrtype, const RRClass& rrclass) :
673 : : name_(name), rrtype_(rrtype), rrclass_(rrclass) {}
674 : 366 : bool operator()(const RRsetPtr& rrset) const {
675 : 366 : return (rrset->getType() == rrtype_ &&
676 : 345 : rrset->getClass() == rrclass_ &&
677 [ + + + - ]: 1056 : rrset->getName() == name_);
[ + + ]
678 : : }
679 : : const Name& name_;
680 : : const RRType& rrtype_;
681 : : const RRClass& rrclass_;
682 : : };
683 : : }
684 : :
685 : : // Note about design decision:
686 : : // we need some type specific processing here, including EDNS and TSIG.
687 : : // how much we should generalize/hardcode the special logic is subject
688 : : // to discussion. In terms of modularity it would be ideal to introduce
689 : : // an abstract class (say "MessageAttribute") and let other such
690 : : // concrete notions as EDNS or TSIG inherit from it. Then we would
691 : : // just do:
692 : : // message->addAttribute(rrtype, rrclass, buffer);
693 : : // to create and attach type-specific concrete object to the message.
694 : : //
695 : : // A major downside of this approach is, as usual, complexity due to
696 : : // indirection and performance penalty. Also, it may not be so easy
697 : : // to separate the processing logic because in many cases we'll need
698 : : // parse context for which the message class is responsible (e.g.
699 : : // to check the EDNS OPT RR only appears in the additional section,
700 : : // and appears only once).
701 : : //
702 : : // Another point to consider is that we may not need so many special
703 : : // types other than EDNS and TSIG (and when and if we implement it,
704 : : // SIG(0)); newer optional attributes of the message would more likely
705 : : // be standardized as new flags or options of EDNS. If that's the case,
706 : : // introducing an abstract class with all the overhead and complexity
707 : : // may not make much sense.
708 : : //
709 : : // Conclusion: don't over-generalize type-specific logic for now.
710 : : // introduce separate concrete classes, and move context-independent
711 : : // logic to that class; processing logic dependent on parse context
712 : : // is hardcoded here.
713 : : int
714 : 2121 : MessageImpl::parseSection(const Message::Section section,
715 : : InputBuffer& buffer, Message::ParseOptions options)
716 : : {
717 [ + - ]: 2121 : assert(section < MessageImpl::NUM_SECTIONS);
718 : :
719 : : unsigned int added = 0;
720 : :
721 [ + + ]: 3025 : for (unsigned int count = 0; count < counts_[section]; ++count) {
722 : : // We need to remember the start position for TSIG processing
723 : 925 : const size_t start_position = buffer.getPosition();
724 : :
725 : 1847 : const Name name(buffer);
726 : :
727 : : // buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
728 [ - + ]: 922 : if ((buffer.getLength() - buffer.getPosition()) <
729 : : 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
730 [ # # ][ # # ]: 0 : isc_throw(DNSMessageFORMERR, sectiontext[section] <<
[ # # ][ # # ]
731 : : " section too short: " <<
732 : : (buffer.getLength() - buffer.getPosition()) << " bytes");
733 : : }
734 : :
735 [ + - ]: 922 : const RRType rrtype(buffer.readUint16());
736 [ + - ]: 922 : const RRClass rrclass(buffer.readUint16());
737 : 922 : const RRTTL ttl(buffer.readUint32());
738 [ + - ]: 922 : const size_t rdlen = buffer.readUint16();
739 [ + + ]: 922 : ConstRdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
740 : :
741 [ + + ]: 920 : if (rrtype == RRType::OPT()) {
742 [ + + ]: 40 : addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
743 [ + + ]: 880 : } else if (rrtype == RRType::TSIG()) {
744 : : addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
745 [ + + ]: 192 : *rdata);
746 : : } else {
747 [ + - ]: 688 : addRR(section, name, rrclass, rrtype, ttl, rdata, options);
748 : 688 : ++added;
749 : : }
750 : : }
751 : :
752 : 2100 : return (added);
753 : : }
754 : :
755 : : void
756 : 688 : MessageImpl::addRR(Message::Section section, const Name& name,
757 : : const RRClass& rrclass, const RRType& rrtype,
758 : : const RRTTL& ttl, ConstRdataPtr rdata,
759 : : Message::ParseOptions options)
760 : : {
761 [ + + ]: 688 : if ((options & Message::PRESERVE_ORDER) == 0) {
762 : : vector<RRsetPtr>::iterator it =
763 : 924 : find_if(rrsets_[section].begin(), rrsets_[section].end(),
764 : 462 : MatchRR(name, rrtype, rrclass));
765 [ + + ]: 462 : if (it != rrsets_[section].end()) {
766 : 246 : (*it)->setTTL(min((*it)->getTTL(), ttl));
767 [ + - ]: 246 : (*it)->addRdata(rdata);
768 : 688 : return;
769 : : }
770 : : }
771 [ + - ]: 565 : RRsetPtr rrset(new RRset(name, rrclass, rrtype, ttl));
772 [ + - ]: 1130 : rrset->addRdata(rdata);
773 [ + - ]: 565 : rrsets_[section].push_back(rrset);
774 : : }
775 : :
776 : : void
777 : 40 : MessageImpl::addEDNS(Message::Section section, const Name& name,
778 : : const RRClass& rrclass, const RRType& rrtype,
779 : : const RRTTL& ttl, const Rdata& rdata)
780 : : {
781 [ + + ]: 40 : if (section != Message::SECTION_ADDITIONAL) {
782 [ + - ]: 4 : isc_throw(DNSMessageFORMERR,
783 : : "EDNS OPT RR found in an invalid section");
784 : : }
785 [ + + ]: 38 : if (edns_) {
786 [ + - ]: 4 : isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
787 : : }
788 : :
789 : : uint8_t extended_rcode;
790 : : edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl, rdata,
791 [ + - ]: 36 : extended_rcode));
792 : 32 : setRcode(Rcode(rcode_->getCode(), extended_rcode));
793 : 32 : }
794 : :
795 : : void
796 : 192 : MessageImpl::addTSIG(Message::Section section, unsigned int count,
797 : : const InputBuffer& buffer, size_t start_position,
798 : : const Name& name, const RRClass& rrclass,
799 : : const RRTTL& ttl, const Rdata& rdata)
800 : : {
801 [ + + ]: 192 : if (section != Message::SECTION_ADDITIONAL) {
802 [ + - ]: 4 : isc_throw(DNSMessageFORMERR,
803 : : "TSIG RR found in an invalid section");
804 : : }
805 [ + + ]: 190 : if (count != counts_[section] - 1) {
806 [ + - ]: 8 : isc_throw(DNSMessageFORMERR, "TSIG RR is not the last record");
807 : : }
808 [ - + ]: 186 : if (tsig_rr_) {
809 [ # # ]: 0 : isc_throw(DNSMessageFORMERR, "multiple TSIG RRs found");
810 : : }
811 : : tsig_rr_ = ConstTSIGRecordPtr(new TSIGRecord(name, rrclass,
812 : : ttl, rdata,
813 : : buffer.getPosition() -
814 [ + + ][ + - ]: 370 : start_position));
815 : 184 : }
816 : :
817 : : namespace {
818 : : template <typename T>
819 : : struct SectionFormatter {
820 : : SectionFormatter(const Message::Section section, string& output) :
821 : 307 : section_(section), output_(output) {}
822 : 0 : void operator()(const T& entry) {
823 [ # # ][ # # ]: 315 : if (section_ == Message::SECTION_QUESTION) {
[ - + ][ + - ]
824 : 280 : output_ += ";";
825 : : }
826 : 630 : output_ += entry->toText();
827 : 0 : }
828 : : const Message::Section section_;
829 : : string& output_;
830 : : };
831 : : }
832 : :
833 : : string
834 : 429 : Message::toText() const {
835 [ + + ]: 429 : if (impl_->rcode_ == NULL) {
836 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
837 : : "Message::toText() attempted without Rcode set");
838 : : }
839 [ + + ]: 427 : if (impl_->opcode_ == NULL) {
840 [ + - ][ + - ]: 4 : isc_throw(InvalidMessageOperation,
841 : : "Message::toText() attempted without Opcode set");
842 : : }
843 : :
844 : 0 : string s;
845 : :
846 [ + - ][ + - ]: 850 : s += ";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
847 : : // for simplicity we don't consider extended rcode (unlike BIND9)
848 [ + - ][ + - ]: 850 : s += ", status: " + impl_->rcode_->toText();
849 [ + - ]: 850 : s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
850 : : s += "\n;; flags:";
851 [ + - ][ + + ]: 425 : if (getHeaderFlag(HEADERFLAG_QR)) {
852 : : s += " qr";
853 : : }
854 [ + - ][ + + ]: 425 : if (getHeaderFlag(HEADERFLAG_AA)) {
855 : : s += " aa";
856 : : }
857 [ + - ][ - + ]: 425 : if (getHeaderFlag(HEADERFLAG_TC)) {
858 : : s += " tc";
859 : : }
860 [ + - ][ + + ]: 425 : if (getHeaderFlag(HEADERFLAG_RD)) {
861 : : s += " rd";
862 : : }
863 [ + - ][ - + ]: 425 : if (getHeaderFlag(HEADERFLAG_RA)) {
864 : : s += " ra";
865 : : }
866 [ + - ][ - + ]: 425 : if (getHeaderFlag(HEADERFLAG_AD)) {
867 : : s += " ad";
868 : : }
869 [ + - ][ - + ]: 425 : if (getHeaderFlag(HEADERFLAG_CD)) {
870 : : s += " cd";
871 : : }
872 : :
873 : : // for simplicity, don't consider the update case for now
874 : : s += "; QUERY: " + // note: not "QUESTION" to be compatible with BIND 9 dig
875 [ + - ]: 850 : lexical_cast<string>(impl_->counts_[SECTION_QUESTION]);
876 : : s += ", ANSWER: " +
877 [ + - ]: 850 : lexical_cast<string>(impl_->counts_[SECTION_ANSWER]);
878 : : s += ", AUTHORITY: " +
879 [ + - ]: 850 : lexical_cast<string>(impl_->counts_[SECTION_AUTHORITY]);
880 : :
881 : 425 : unsigned int arcount = impl_->counts_[SECTION_ADDITIONAL];
882 [ + + ]: 425 : if (impl_->edns_ != NULL) {
883 : 13 : ++arcount;
884 : : }
885 [ + + ]: 425 : if (impl_->tsig_rr_ != NULL) {
886 : 6 : ++arcount;
887 : : }
888 [ + - ][ + - ]: 850 : s += ", ADDITIONAL: " + lexical_cast<string>(arcount) + "\n";
889 : :
890 [ + + ]: 425 : if (impl_->edns_ != NULL) {
891 : : s += "\n;; OPT PSEUDOSECTION:\n";
892 [ + - ]: 26 : s += impl_->edns_->toText();
893 : : }
894 : :
895 [ + + ]: 425 : if (!impl_->questions_.empty()) {
896 : : s += "\n;; " +
897 [ + - ][ + - ]: 550 : string(sectiontext[SECTION_QUESTION]) + " SECTION:\n";
[ + - ]
898 : 550 : for_each(impl_->questions_.begin(), impl_->questions_.end(),
899 [ + - ]: 275 : SectionFormatter<QuestionPtr>(SECTION_QUESTION, s));
900 : : }
901 [ + + ]: 425 : if (!impl_->rrsets_[SECTION_ANSWER].empty()) {
902 : : s += "\n;; " +
903 [ + - ][ + - ]: 28 : string(sectiontext[SECTION_ANSWER]) + " SECTION:\n";
[ + - ]
904 : 14 : for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
905 : 14 : impl_->rrsets_[SECTION_ANSWER].end(),
906 [ + - ]: 14 : SectionFormatter<RRsetPtr>(SECTION_ANSWER, s));
907 : : }
908 [ + + ]: 425 : if (!impl_->rrsets_[SECTION_AUTHORITY].empty()) {
909 : : s += "\n;; " +
910 [ + - ][ + - ]: 24 : string(sectiontext[SECTION_AUTHORITY]) + " SECTION:\n";
[ + - ]
911 : 12 : for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
912 : 12 : impl_->rrsets_[SECTION_AUTHORITY].end(),
913 [ + - ]: 12 : SectionFormatter<RRsetPtr>(SECTION_AUTHORITY, s));
914 : : }
915 [ + + ]: 425 : if (!impl_->rrsets_[SECTION_ADDITIONAL].empty()) {
916 : : s += "\n;; " +
917 : 6 : string(sectiontext[SECTION_ADDITIONAL]) +
918 [ + - ][ + - ]: 12 : " SECTION:\n";
[ + - ]
919 : 6 : for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
920 : 6 : impl_->rrsets_[SECTION_ADDITIONAL].end(),
921 [ + - ]: 6 : SectionFormatter<RRsetPtr>(SECTION_ADDITIONAL, s));
922 : : }
923 : :
924 [ + + ]: 425 : if (impl_->tsig_rr_ != NULL) {
925 : : s += "\n;; TSIG PSEUDOSECTION:\n";
926 [ + - ]: 12 : s += impl_->tsig_rr_->toText();
927 : : }
928 : :
929 : 425 : return (s);
930 : : }
931 : :
932 : : void
933 : 730 : Message::clear(Mode mode) {
934 : 730 : impl_->init();
935 : 730 : impl_->mode_ = mode;
936 : 730 : }
937 : :
938 : : void
939 : 20 : Message::appendSection(const Section section, const Message& source) {
940 [ + + ]: 20 : if (section >= MessageImpl::NUM_SECTIONS) {
941 [ + - ][ + - ]: 2 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ + - ]
942 : : }
943 : :
944 [ + + ]: 19 : if (section == SECTION_QUESTION) {
945 [ + - ][ + - ]: 15 : for (QuestionIterator qi = source.beginQuestion();
[ + + ]
946 [ + - ][ + - ]: 10 : qi != source.endQuestion();
947 : : ++qi) {
948 [ + - ][ + - ]: 4 : addQuestion(*qi);
949 : : }
950 : : } else {
951 [ + - ][ + - ]: 87 : for (RRsetIterator rrsi = source.beginSection(section);
[ + + ]
952 [ + - ][ + - ]: 58 : rrsi != source.endSection(section);
953 : : ++rrsi) {
954 [ + - ][ + - ]: 26 : addRRset(section, *rrsi);
955 : : }
956 : : }
957 : 19 : }
958 : :
959 : : void
960 : 123 : Message::makeResponse() {
961 [ - + ]: 123 : if (impl_->mode_ != Message::PARSE) {
962 [ # # ][ # # ]: 0 : isc_throw(InvalidMessageOperation,
963 : : "makeResponse() is performed in non-parse mode");
964 : : }
965 : :
966 : 123 : impl_->mode_ = Message::RENDER;
967 : :
968 [ + - ]: 123 : impl_->edns_ = EDNSPtr();
969 : 123 : impl_->flags_ &= MESSAGE_REPLYPRESERVE;
970 : 123 : setHeaderFlag(HEADERFLAG_QR, true);
971 : :
972 : 123 : impl_->rrsets_[SECTION_ANSWER].clear();
973 : 123 : impl_->counts_[SECTION_ANSWER] = 0;
974 : 123 : impl_->rrsets_[SECTION_AUTHORITY].clear();
975 : 123 : impl_->counts_[SECTION_AUTHORITY] = 0;
976 : 123 : impl_->rrsets_[SECTION_ADDITIONAL].clear();
977 : 123 : impl_->counts_[SECTION_ADDITIONAL] = 0;
978 : 123 : }
979 : :
980 : : ///
981 : : /// Template version of Section Iterator
982 : : ///
983 : : template <typename T>
984 : : struct SectionIteratorImpl {
985 : : SectionIteratorImpl(const typename vector<T>::const_iterator& it) :
986 : 7318 : it_(it) {}
987 : : typename vector<T>::const_iterator it_;
988 : : };
989 : :
990 : : template <typename T>
991 : 2502 : SectionIterator<T>::SectionIterator(const SectionIteratorImpl<T>& impl) {
992 : 2502 : impl_ = new SectionIteratorImpl<T>(impl.it_);
993 : 2502 : }
994 : :
995 : : template <typename T>
996 : 4780 : SectionIterator<T>::~SectionIterator() {
997 : 4780 : delete impl_;
998 : 4780 : }
999 : :
1000 : : template <typename T>
1001 : 2056 : SectionIterator<T>::SectionIterator(const SectionIterator<T>& source) :
1002 : 2056 : impl_(new SectionIteratorImpl<T>(source.impl_->it_))
1003 : 2056 : {}
1004 : :
1005 : : template <typename T>
1006 : : void
1007 : 258 : SectionIterator<T>::operator=(const SectionIterator<T>& source) {
1008 [ + - ][ + - ]: 258 : if (impl_ == source.impl_) {
1009 : 258 : return;
1010 : : }
1011 : : SectionIteratorImpl<T>* newimpl =
1012 : 258 : new SectionIteratorImpl<T>(source.impl_->it_);
1013 : 258 : delete impl_;
1014 : 258 : impl_ = newimpl;
1015 : : }
1016 : :
1017 : : template <typename T>
1018 : : SectionIterator<T>&
1019 : 1706 : SectionIterator<T>::operator++() {
1020 : 1706 : ++(impl_->it_);
1021 : 1706 : return (*this);
1022 : : }
1023 : :
1024 : : template <typename T>
1025 : : SectionIterator<T>
1026 : 0 : SectionIterator<T>::operator++(int) {
1027 : 0 : SectionIterator<T> tmp(*this);
1028 [ # # # # ]: 0 : ++(*this);
1029 : 0 : return (tmp);
1030 : : }
1031 : :
1032 : : template <typename T>
1033 : : const T&
1034 : 3182 : SectionIterator<T>::operator*() const {
1035 : 3182 : return (*(impl_->it_));
1036 : : }
1037 : :
1038 : : template <typename T>
1039 : : const T*
1040 : 0 : SectionIterator<T>::operator->() const {
1041 : 0 : return (&(operator*()));
1042 : : }
1043 : :
1044 : : template <typename T>
1045 : : bool
1046 : 79 : SectionIterator<T>::operator==(const SectionIterator<T>& other) const {
1047 : 79 : return (impl_->it_ == other.impl_->it_);
1048 : : }
1049 : :
1050 : : template <typename T>
1051 : : bool
1052 : 2763 : SectionIterator<T>::operator!=(const SectionIterator<T>& other) const {
1053 : 2763 : return (impl_->it_ != other.impl_->it_);
1054 : : }
1055 : :
1056 : : ///
1057 : : /// We need to explicitly instantiate these template classes because these
1058 : : /// are public classes but defined in this implementation file.
1059 : : ///
1060 : : template class SectionIterator<QuestionPtr>;
1061 : : template class SectionIterator<RRsetPtr>;
1062 : :
1063 : : namespace {
1064 : : typedef SectionIteratorImpl<QuestionPtr> QuestionIteratorImpl;
1065 : : typedef SectionIteratorImpl<RRsetPtr> RRsetIteratorImpl;
1066 : : }
1067 : :
1068 : : ///
1069 : : /// Question iterator
1070 : : ///
1071 : : const QuestionIterator
1072 : 624 : Message::beginQuestion() const {
1073 : 624 : return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
1074 : : }
1075 : :
1076 : : const QuestionIterator
1077 : 310 : Message::endQuestion() const {
1078 : 310 : return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.end())));
1079 : : }
1080 : :
1081 : : ///
1082 : : /// RRsets iterators
1083 : : ///
1084 : : const SectionIterator<RRsetPtr>
1085 : 723 : Message::beginSection(const Section section) const {
1086 [ + + ]: 723 : if (section >= MessageImpl::NUM_SECTIONS) {
1087 [ + - ][ + - ]: 2 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ + - ]
1088 : : }
1089 [ + + ]: 722 : if (section == SECTION_QUESTION) {
1090 [ + - ]: 2 : isc_throw(InvalidMessageSection,
1091 : : "RRset iterator is requested for question");
1092 : : }
1093 : :
1094 : 721 : return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].begin())));
1095 : : }
1096 : :
1097 : : const SectionIterator<RRsetPtr>
1098 : 849 : Message::endSection(const Section section) const {
1099 [ + + ]: 849 : if (section >= MessageImpl::NUM_SECTIONS) {
1100 [ + - ][ + - ]: 2 : isc_throw(OutOfRange, "Invalid message section: " << section);
[ + - ]
1101 : : }
1102 [ + + ]: 848 : if (section == SECTION_QUESTION) {
1103 [ + - ]: 2 : isc_throw(InvalidMessageSection,
1104 : : "RRset iterator is requested for question");
1105 : : }
1106 : :
1107 : 847 : return (RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].end())));
1108 : : }
1109 : :
1110 : : ostream&
1111 : 420 : operator<<(ostream& os, const Message& message) {
1112 [ + - ]: 420 : return (os << message.toText());
1113 : : }
1114 : : } // end of namespace dns
1115 : 137 : } // end of namespace isc
|