123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872 |
- // Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- // $Id$
- #include <stdint.h>
- #include <algorithm>
- #include <string>
- #include <sstream>
- #include <vector>
- #include <boost/foreach.hpp>
- #include <boost/lexical_cast.hpp>
- #include <boost/shared_ptr.hpp>
- #include <exceptions/exceptions.h>
- #include <dns/buffer.h>
- #include <dns/edns.h>
- #include <dns/exceptions.h>
- #include <dns/message.h>
- #include <dns/messagerenderer.h>
- #include <dns/name.h>
- #include <dns/opcode.h>
- #include <dns/rcode.h>
- #include <dns/question.h>
- #include <dns/rdataclass.h>
- #include <dns/rrclass.h>
- #include <dns/rrtype.h>
- #include <dns/rrttl.h>
- #include <dns/rrset.h>
- using namespace std;
- using namespace boost;
- using namespace isc::dns;
- using namespace isc::dns::rdata;
- namespace isc {
- namespace dns {
- namespace {
- typedef uint16_t flags_t;
- // protocol constants
- const size_t HEADERLEN = 12;
- const flags_t FLAG_QR = 0x8000;
- const flags_t FLAG_AA = 0x0400;
- const flags_t FLAG_TC = 0x0200;
- const flags_t FLAG_RD = 0x0100;
- const flags_t FLAG_RA = 0x0080;
- const flags_t FLAG_AD = 0x0020;
- const flags_t FLAG_CD = 0x0010;
- const unsigned int OPCODE_MASK = 0x7800;
- const unsigned int OPCODE_SHIFT = 11;
- const unsigned int RCODE_MASK = 0x000f;
- const unsigned int FLAG_MASK = 0x8ff0;
- const unsigned int MESSAGE_REPLYPRESERVE = (FLAG_RD | FLAG_CD);
- const char *sectiontext[] = {
- "QUESTION",
- "ANSWER",
- "AUTHORITY",
- "ADDITIONAL"
- };
- }
- namespace {
- inline unsigned int
- sectionCodeToId(const Section& section) {
- unsigned int code = section.getCode();
- assert(code > 0);
- return (section.getCode() - 1);
- }
- }
- class MessageImpl {
- public:
- MessageImpl(Message::Mode mode);
- // Open issues: should we rather have a header in wire-format
- // for efficiency?
- Message::Mode mode_;
- qid_t qid_;
- // We want to use NULL for [op,r]code_ to mean the code being not
- // correctly parsed or set. We store the real code object in
- // xxcode_placeholder_ and have xxcode_ refer to it when the object
- // is valid.
- const Rcode* rcode_;
- Rcode rcode_placeholder_;
- const Opcode* opcode_;
- Opcode opcode_placeholder_;
- flags_t flags_;
- bool header_parsed_;
- static const unsigned int SECTION_MAX = 4; // TODO: revisit this design
- int counts_[SECTION_MAX]; // TODO: revisit this definition
- vector<QuestionPtr> questions_;
- vector<RRsetPtr> rrsets_[SECTION_MAX];
- ConstEDNSPtr edns_;
- #ifdef notyet
- // tsig/sig0: TODO
- RRsetsSorter* sorter_;
- #endif
- void init();
- void setOpcode(const Opcode& opcode);
- void setRcode(const Rcode& rcode);
- int parseQuestion(InputBuffer& buffer);
- int parseSection(const Section& section, InputBuffer& buffer);
- };
- MessageImpl::MessageImpl(Message::Mode mode) :
- mode_(mode),
- rcode_placeholder_(Rcode(0)), // as a placeholder the value doesn't matter
- opcode_placeholder_(Opcode(0)) // ditto
- {
- init();
- }
- void
- MessageImpl::init() {
- flags_ = 0;
- qid_ = 0;
- rcode_ = NULL;
- opcode_ = NULL;
- edns_ = EDNSPtr();
- for (int i = 0; i < SECTION_MAX; ++i) {
- counts_[i] = 0;
- }
- header_parsed_ = false;
- questions_.clear();
- rrsets_[sectionCodeToId(Section::ANSWER())].clear();
- rrsets_[sectionCodeToId(Section::AUTHORITY())].clear();
- rrsets_[sectionCodeToId(Section::ADDITIONAL())].clear();
- }
- void
- MessageImpl::setOpcode(const Opcode& opcode) {
- opcode_placeholder_ = opcode;
- opcode_ = &opcode_placeholder_;
- }
- void
- MessageImpl::setRcode(const Rcode& rcode) {
- rcode_placeholder_ = rcode;
- rcode_ = &rcode_placeholder_;
- }
- Message::Message(Mode mode) :
- impl_(new MessageImpl(mode))
- {}
- Message::~Message() {
- delete impl_;
- }
- bool
- Message::getHeaderFlag(const MessageFlag& flag) const {
- return ((impl_->flags_ & flag.getBit()) != 0);
- }
- void
- Message::setHeaderFlag(const MessageFlag& flag) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "setHeaderFlag performed in non-render mode");
- }
- impl_->flags_ |= flag.getBit();
- }
- void
- Message::clearHeaderFlag(const MessageFlag& flag) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "clearHeaderFlag performed in non-render mode");
- }
- impl_->flags_ &= ~flag.getBit();
- }
- qid_t
- Message::getQid() const {
- return (impl_->qid_);
- }
- void
- Message::setQid(qid_t qid) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "setQid performed in non-render mode");
- }
- impl_->qid_ = qid;
- }
- const Rcode&
- Message::getRcode() const {
- if (impl_->rcode_ == NULL) {
- isc_throw(InvalidMessageOperation, "getRcode attempted before set");
- }
- return (*impl_->rcode_);
- }
- void
- Message::setRcode(const Rcode& rcode) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "setRcode performed in non-render mode");
- }
- impl_->setRcode(rcode);
- }
- const Opcode&
- Message::getOpcode() const {
- if (impl_->opcode_ == NULL) {
- isc_throw(InvalidMessageOperation, "getOpcode attempted before set");
- }
- return (*impl_->opcode_);
- }
- void
- Message::setOpcode(const Opcode& opcode) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "setOpcode performed in non-render mode");
- }
- impl_->setOpcode(opcode);
- }
- ConstEDNSPtr
- Message::getEDNS() const {
- return (impl_->edns_);
- }
- void
- Message::setEDNS(ConstEDNSPtr edns) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "setEDNS performed in non-render mode");
- }
- impl_->edns_ = edns;
- }
- unsigned int
- Message::getRRCount(const Section& section) const {
- return (impl_->counts_[section.getCode()]);
- }
- void
- Message::addRRset(const Section& section, RRsetPtr rrset, const bool sign) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "addRRset performed in non-render mode");
- }
- impl_->rrsets_[sectionCodeToId(section)].push_back(rrset);
- impl_->counts_[section.getCode()] += rrset->getRdataCount();
- RRsetPtr sp = rrset->getRRsig();
- if (sign && sp != NULL) {
- impl_->rrsets_[sectionCodeToId(section)].push_back(sp);
- impl_->counts_[section.getCode()] += sp->getRdataCount();
- }
- }
- bool
- Message::hasRRset(const Section& section, RRsetPtr rrset) {
- BOOST_FOREACH(RRsetPtr r, impl_->rrsets_[sectionCodeToId(section)]) {
- if (r->getType() == rrset->getType() &&
- r->getName() == rrset->getName())
- {
- return (true);
- }
- }
- return (false);
- }
- void
- Message::addQuestion(const QuestionPtr question) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "addQuestion performed in non-render mode");
- }
- impl_->questions_.push_back(question);
- ++impl_->counts_[Section::QUESTION().getCode()];
- }
- void
- Message::addQuestion(const Question& question) {
- addQuestion(QuestionPtr(new Question(question)));
- }
- namespace {
- template <typename T>
- struct RenderSection {
- RenderSection(MessageRenderer& renderer, const bool partial_ok) :
- counter_(0), renderer_(renderer), partial_ok_(partial_ok),
- truncated_(false)
- {}
- void operator()(const T& entry) {
- // If it's already truncated, ignore the rest of the section.
- if (truncated_) {
- return;
- }
- const size_t pos0 = renderer_.getLength();
- counter_ += entry->toWire(renderer_);
- if (renderer_.isTruncated()) {
- truncated_ = true;
- if (!partial_ok_) {
- // roll back to the end of the previous RRset.
- renderer_.trim(renderer_.getLength() - pos0);
- }
- }
- }
- unsigned int getTotalCount() { return (counter_); }
- unsigned int counter_;
- MessageRenderer& renderer_;
- const bool partial_ok_;
- bool truncated_;
- };
- }
- void
- Message::toWire(MessageRenderer& renderer) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted in non render mode");
- }
- if (impl_->rcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted without Rcode set");
- }
- if (impl_->opcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted without Opcode set");
- }
- // reserve room for the header
- renderer.skip(HEADERLEN);
- uint16_t qdcount =
- for_each(impl_->questions_.begin(), impl_->questions_.end(),
- RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
- // TBD: sort RRsets in each section based on configuration policy.
- uint16_t ancount = 0;
- if (!renderer.isTruncated()) {
- ancount =
- for_each(impl_->rrsets_[sectionCodeToId(Section::ANSWER())].begin(),
- impl_->rrsets_[sectionCodeToId(Section::ANSWER())].end(),
- RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
- }
- uint16_t nscount = 0;
- if (!renderer.isTruncated()) {
- nscount =
- for_each(impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].begin(),
- impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].end(),
- RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
- }
- uint16_t arcount = 0;
- if (renderer.isTruncated()) {
- setHeaderFlag(MessageFlag::TC());
- } else {
- arcount =
- for_each(impl_->rrsets_[sectionCodeToId(Section::ADDITIONAL())].begin(),
- impl_->rrsets_[sectionCodeToId(Section::ADDITIONAL())].end(),
- RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
- }
- // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
- // has been explicitly set. However, if the RCODE would require it and
- // no EDNS has been set we generate a temporary local EDNS and use it.
- if (!renderer.isTruncated()) {
- ConstEDNSPtr local_edns = impl_->edns_;
- if (!local_edns && impl_->rcode_->getExtendedCode() != 0) {
- local_edns = ConstEDNSPtr(new EDNS());
- }
- if (local_edns) {
- arcount += local_edns->toWire(renderer,
- impl_->rcode_->getExtendedCode());
- }
- }
-
- // Adjust the counter buffer.
- // XXX: these may not be equal to the number of corresponding entries
- // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
- // was inserted. This is not good, and we should revisit the entire
- // design.
- impl_->counts_[Section::QUESTION().getCode()] = qdcount;
- impl_->counts_[Section::ANSWER().getCode()] = ancount;
- impl_->counts_[Section::AUTHORITY().getCode()] = nscount;
- impl_->counts_[Section::ADDITIONAL().getCode()] = arcount;
- // TBD: TSIG, SIG(0) etc.
- // fill in the header
- size_t header_pos = 0;
- renderer.writeUint16At(impl_->qid_, header_pos);
- header_pos += sizeof(uint16_t);
- uint16_t codes_and_flags =
- (impl_->opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
- codes_and_flags |= (impl_->rcode_->getCode() & RCODE_MASK);
- codes_and_flags |= (impl_->flags_ & FLAG_MASK);
- renderer.writeUint16At(codes_and_flags, header_pos);
- header_pos += sizeof(uint16_t);
- // XXX: should avoid repeated pattern (TODO)
- renderer.writeUint16At(qdcount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(ancount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(nscount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(arcount, header_pos);
- header_pos += sizeof(uint16_t);
- }
- void
- Message::parseHeader(InputBuffer& buffer) {
- if (impl_->mode_ != Message::PARSE) {
- isc_throw(InvalidMessageOperation,
- "Message parse attempted in non parse mode");
- }
- if ((buffer.getLength() - buffer.getPosition()) < HEADERLEN) {
- isc_throw(MessageTooShort, "Malformed DNS message (short length): "
- << buffer.getLength() - buffer.getPosition());
- }
- impl_->qid_ = buffer.readUint16();
- const uint16_t codes_and_flags = buffer.readUint16();
- impl_->setOpcode(Opcode((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT));
- impl_->setRcode(Rcode(codes_and_flags & RCODE_MASK));
- impl_->flags_ = (codes_and_flags & FLAG_MASK);
- impl_->counts_[Section::QUESTION().getCode()] = buffer.readUint16();
- impl_->counts_[Section::ANSWER().getCode()] = buffer.readUint16();
- impl_->counts_[Section::AUTHORITY().getCode()] = buffer.readUint16();
- impl_->counts_[Section::ADDITIONAL().getCode()] = buffer.readUint16();
- impl_->header_parsed_ = true;
- }
- void
- Message::fromWire(InputBuffer& buffer) {
- if (impl_->mode_ != Message::PARSE) {
- isc_throw(InvalidMessageOperation,
- "Message parse attempted in non parse mode");
- }
- if (!impl_->header_parsed_) {
- parseHeader(buffer);
- }
- impl_->counts_[Section::QUESTION().getCode()] =
- impl_->parseQuestion(buffer);
- impl_->counts_[Section::ANSWER().getCode()] =
- impl_->parseSection(Section::ANSWER(), buffer);
- impl_->counts_[Section::AUTHORITY().getCode()] =
- impl_->parseSection(Section::AUTHORITY(), buffer);
- impl_->counts_[Section::ADDITIONAL().getCode()] =
- impl_->parseSection(Section::ADDITIONAL(), buffer);
- }
- int
- MessageImpl::parseQuestion(InputBuffer& buffer) {
- unsigned int added = 0;
- for (unsigned int count = 0;
- count < counts_[Section::QUESTION().getCode()];
- ++count) {
- const Name name(buffer);
- if ((buffer.getLength() - buffer.getPosition()) <
- 2 * sizeof(uint16_t)) {
- isc_throw(DNSMessageFORMERR, "Question section too short: " <<
- (buffer.getLength() - buffer.getPosition()) << " bytes");
- }
- const RRType rrtype(buffer.readUint16());
- const RRClass rrclass(buffer.readUint16());
- // XXX: need a duplicate check. We might also want to have an optimized
- // algorithm that requires the question section contain exactly one
- // RR.
- questions_.push_back(QuestionPtr(new Question(name, rrclass, rrtype)));
- ++added;
- }
- return (added);
- }
- namespace {
- struct MatchRR : public unary_function<RRsetPtr, bool> {
- MatchRR(const Name& name, const RRType& rrtype, const RRClass& rrclass) :
- name_(name), rrtype_(rrtype), rrclass_(rrclass) {}
- bool operator()(const RRsetPtr& rrset) const {
- return (rrset->getType() == rrtype_ &&
- rrset->getClass() == rrclass_ &&
- rrset->getName() == name_);
- }
- const Name& name_;
- const RRType& rrtype_;
- const RRClass& rrclass_;
- };
- }
- // Note about design decision:
- // we need some type specific processing here, including EDNS and TSIG.
- // how much we should generalize/hardcode the special logic is subject
- // to discussion. In terms of modularity it would be ideal to introduce
- // an abstract class (say "MessageAttribute") and let other such
- // concrete notions as EDNS or TSIG inherit from it. Then we would
- // just do:
- // message->addAttribute(rrtype, rrclass, buffer);
- // to create and attach type-specific concrete object to the message.
- //
- // A major downside of this approach is, as usual, complexity due to
- // indirection and performance penalty. Also, it may not be so easy
- // to separate the processing logic because in many cases we'll need
- // parse context for which the message class is responsible (e.g.
- // to check the EDNS OPT RR only appears in the additional section,
- // and appears only once).
- //
- // Another point to consider is that we may not need so many special
- // types other than EDNS and TSIG (and when and if we implement it,
- // SIG(0)); newer optional attributes of the message would more likely
- // be standardized as new flags or options of EDNS. If that's the case,
- // introducing an abstract class with all the overhead and complexity
- // may not make much sense.
- //
- // Conclusion: don't over-generalize type-specific logic for now.
- // introduce separate concrete classes, and move context-independent
- // logic to that class; processing logic dependent on parse context
- // is hardcoded here.
- int
- MessageImpl::parseSection(const Section& section, InputBuffer& buffer) {
- unsigned int added = 0;
- for (unsigned int count = 0; count < counts_[section.getCode()]; ++count) {
- const Name name(buffer);
- // buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
- if ((buffer.getLength() - buffer.getPosition()) <
- 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
- isc_throw(DNSMessageFORMERR, sectiontext[section.getCode()] <<
- " section too short: " <<
- (buffer.getLength() - buffer.getPosition()) << " bytes");
- }
- const RRType rrtype(buffer.readUint16());
- const RRClass rrclass(buffer.readUint16());
- const RRTTL ttl(buffer.readUint32());
- const size_t rdlen = buffer.readUint16();
- ConstRdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
- if (rrtype == RRType::OPT()) {
- if (section != Section::ADDITIONAL()) {
- isc_throw(DNSMessageFORMERR,
- "EDNS OPT RR found in an invalid section");
- }
- if (edns_) {
- isc_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
- }
- uint8_t extended_rcode;
- edns_ = ConstEDNSPtr(createEDNSFromRR(name, rrclass, rrtype, ttl,
- *rdata, extended_rcode));
- setRcode(Rcode(rcode_->getCode(), extended_rcode));
- continue;
- } else {
- vector<RRsetPtr>::iterator it =
- find_if(rrsets_[sectionCodeToId(section)].begin(),
- rrsets_[sectionCodeToId(section)].end(),
- MatchRR(name, rrtype, rrclass));
- if (it != rrsets_[sectionCodeToId(section)].end()) {
- (*it)->setTTL(min((*it)->getTTL(), ttl));
- (*it)->addRdata(rdata);
- } else {
- RRsetPtr rrset =
- RRsetPtr(new RRset(name, rrclass, rrtype, ttl));
- rrset->addRdata(rdata);
- rrsets_[sectionCodeToId(section)].push_back(rrset);
- }
- ++added;
- }
- }
- return (added);
- }
- namespace {
- template <typename T>
- struct SectionFormatter {
- SectionFormatter(const Section& section, string& output) :
- section_(section), output_(output) {}
- void operator()(const T& entry) {
- if (section_ == Section::QUESTION()) {
- output_ += ";";
- }
- output_ += entry->toText();
- }
- const Section& section_;
- string& output_;
- };
- }
- string
- Message::toText() const {
- if (impl_->rcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message::toText() attempted without Rcode set");
- }
- if (impl_->opcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message::toText() attempted without Opcode set");
- }
- string s;
- s += ";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
- // for simplicity we don't consider extended rcode (unlike BIND9)
- s += ", status: " + impl_->rcode_->toText();
- s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
- s += "\n;; flags: ";
- if (getHeaderFlag(MessageFlag::QR()))
- s += "qr ";
- if (getHeaderFlag(MessageFlag::AA()))
- s += "aa ";
- if (getHeaderFlag(MessageFlag::TC()))
- s += "tc ";
- if (getHeaderFlag(MessageFlag::RD()))
- s += "rd ";
- if (getHeaderFlag(MessageFlag::RA()))
- s += "ra ";
- if (getHeaderFlag(MessageFlag::AD()))
- s += "ad ";
- if (getHeaderFlag(MessageFlag::CD()))
- s += "cd ";
- // for simplicity, don't consider the update case for now
- s += "; QUESTION: " +
- lexical_cast<string>(impl_->counts_[Section::QUESTION().getCode()]);
- s += ", ANSWER: " +
- lexical_cast<string>(impl_->counts_[Section::ANSWER().getCode()]);
- s += ", AUTHORITY: " +
- lexical_cast<string>(impl_->counts_[Section::AUTHORITY().getCode()]);
- unsigned int arcount = impl_->counts_[Section::ADDITIONAL().getCode()];
- if (impl_->edns_ != NULL) {
- ++arcount;
- }
- s += ", ADDITIONAL: " + lexical_cast<string>(arcount) + "\n";
- if (impl_->edns_ != NULL) {
- s += "\n;; OPT PSEUDOSECTION:\n";
- s += impl_->edns_->toText();
- }
- if (!impl_->questions_.empty()) {
- s += "\n;; " +
- string(sectiontext[Section::QUESTION().getCode()]) + " SECTION:\n";
- for_each(impl_->questions_.begin(), impl_->questions_.end(),
- SectionFormatter<QuestionPtr>(Section::QUESTION(), s));
- }
- if (!impl_->rrsets_[sectionCodeToId(Section::ANSWER())].empty()) {
- s += "\n;; " +
- string(sectiontext[Section::ANSWER().getCode()]) + " SECTION:\n";
- for_each(impl_->rrsets_[sectionCodeToId(Section::ANSWER())].begin(),
- impl_->rrsets_[sectionCodeToId(Section::ANSWER())].end(),
- SectionFormatter<RRsetPtr>(Section::ANSWER(), s));
- }
- if (!impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].empty()) {
- s += "\n;; " +
- string(sectiontext[Section::AUTHORITY().getCode()]) + " SECTION:\n";
- for_each(impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].begin(),
- impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].end(),
- SectionFormatter<RRsetPtr>(Section::AUTHORITY(), s));
- }
- if (!impl_->rrsets_[sectionCodeToId(Section::ADDITIONAL())].empty()) {
- s += "\n;; " +
- string(sectiontext[Section::ADDITIONAL().getCode()]) +
- " SECTION:\n";
- for_each(impl_->rrsets_[sectionCodeToId(Section::ADDITIONAL())].begin(),
- impl_->rrsets_[sectionCodeToId(Section::ADDITIONAL())].end(),
- SectionFormatter<RRsetPtr>(Section::ADDITIONAL(), s));
- }
- return (s);
- }
- void
- Message::clear(Mode mode) {
- impl_->init();
- impl_->mode_ = mode;
- }
- void
- Message::makeResponse() {
- if (impl_->mode_ != Message::PARSE) {
- isc_throw(InvalidMessageOperation,
- "makeResponse() is performed in non-parse mode");
- }
- impl_->mode_ = Message::RENDER;
- impl_->edns_ = EDNSPtr();
- impl_->flags_ &= MESSAGE_REPLYPRESERVE;
- setHeaderFlag(MessageFlag::QR());
- impl_->rrsets_[sectionCodeToId(Section::ANSWER())].clear();
- impl_->counts_[Section::ANSWER().getCode()] = 0;
- impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].clear();
- impl_->counts_[Section::AUTHORITY().getCode()] = 0;
- impl_->rrsets_[sectionCodeToId(Section::ADDITIONAL())].clear();
- impl_->counts_[Section::ADDITIONAL().getCode()] = 0;
- }
- ///
- /// Template version of Section Iterator
- ///
- template <typename T>
- struct SectionIteratorImpl {
- SectionIteratorImpl(const typename vector<T>::const_iterator& it) :
- it_(it) {}
- typename vector<T>::const_iterator it_;
- };
- template <typename T>
- SectionIterator<T>::SectionIterator(const SectionIteratorImpl<T>& impl) {
- impl_ = new SectionIteratorImpl<T>(impl.it_);
- }
- template <typename T>
- SectionIterator<T>::~SectionIterator() {
- delete impl_;
- }
- template <typename T>
- SectionIterator<T>::SectionIterator(const SectionIterator<T>& source) :
- impl_(new SectionIteratorImpl<T>(source.impl_->it_))
- {}
- template <typename T>
- void
- SectionIterator<T>::operator=(const SectionIterator<T>& source) {
- if (impl_ == source.impl_) {
- return;
- }
- SectionIteratorImpl<T>* newimpl =
- new SectionIteratorImpl<T>(source.impl_->it_);
- delete impl_;
- impl_ = newimpl;
- }
- template <typename T>
- SectionIterator<T>&
- SectionIterator<T>::operator++() {
- ++(impl_->it_);
- return (*this);
- }
- template <typename T>
- SectionIterator<T>
- SectionIterator<T>::operator++(int) {
- SectionIterator<T> tmp(*this);
- ++(*this);
- return (tmp);
- }
- template <typename T>
- const T&
- SectionIterator<T>::operator*() const {
- return (*(impl_->it_));
- }
- template <typename T>
- const T*
- SectionIterator<T>::operator->() const {
- return (&(operator*()));
- }
- template <typename T>
- bool
- SectionIterator<T>::operator==(const SectionIterator<T>& other) const {
- return (impl_->it_ == other.impl_->it_);
- }
- template <typename T>
- bool
- SectionIterator<T>::operator!=(const SectionIterator<T>& other) const {
- return (impl_->it_ != other.impl_->it_);
- }
- ///
- /// We need to explicitly instantiate these template classes because these
- /// are public classes but defined in this implementation file.
- ///
- template class SectionIterator<QuestionPtr>;
- template class SectionIterator<RRsetPtr>;
- namespace {
- typedef SectionIteratorImpl<QuestionPtr> QuestionIteratorImpl;
- typedef SectionIteratorImpl<RRsetPtr> RRsetIteratorImpl;
- }
- ///
- /// Question iterator
- ///
- const QuestionIterator
- Message::beginQuestion() const {
- return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
- }
- const QuestionIterator
- Message::endQuestion() const {
- return (QuestionIterator(QuestionIteratorImpl(impl_->questions_.end())));
- }
- ///
- /// RRsets iterators
- ///
- const SectionIterator<RRsetPtr>
- Message::beginSection(const Section& section) const {
- if (section == Section::QUESTION()) {
- isc_throw(InvalidMessageSection,
- "RRset iterator is requested for question");
- }
- return (RRsetIterator(
- RRsetIteratorImpl(
- impl_->rrsets_[sectionCodeToId(section)].begin())));
- }
- const SectionIterator<RRsetPtr>
- Message::endSection(const Section& section) const {
- if (section == Section::QUESTION()) {
- isc_throw(InvalidMessageSection,
- "RRset iterator is requested for question");
- }
- return (RRsetIterator(
- RRsetIteratorImpl(
- impl_->rrsets_[sectionCodeToId(section)].end())));
- }
- ostream&
- operator<<(ostream& os, const Message& message) {
- return (os << message.toText());
- }
- } // end of namespace dns
- } // end of namespace isc
|