message.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. // $Id$
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <stdexcept>
  18. #include <functional>
  19. #include <algorithm>
  20. #include <boost/lexical_cast.hpp>
  21. #include <dns/buffer.h>
  22. #include <dns/rrset.h>
  23. #include <dns/message.h>
  24. using isc::dns::Name;
  25. using isc::dns::Message;
  26. using isc::dns::RRType;
  27. using isc::dns::RRClass;
  28. using isc::dns::RRsetPtr;
  29. using isc::dns::RR;
  30. using isc::dns::TTL;
  31. Message::Message()
  32. {
  33. initialize();
  34. default_buffer_ = new isc::SingleBuffer;
  35. buffer_ = default_buffer_;
  36. default_compressor_ = new NameCompressor;
  37. compressor_ = default_compressor_;
  38. default_decompressor_ = new NameDecompressor;
  39. decompressor_ = default_decompressor_;
  40. }
  41. Message::~Message()
  42. {
  43. delete default_buffer_;
  44. delete default_compressor_;
  45. delete default_decompressor_;
  46. }
  47. void
  48. Message::initialize()
  49. {
  50. qid_ = 0;
  51. rcode_ = RCODE_NOERROR;
  52. opcode_ = OPCODE_QUERY; // default
  53. flags_ = 0;
  54. for (int section = SECTION_QUESTION; section < SECTION_MAX; ++section) {
  55. counts_[section] = 0;
  56. }
  57. edns_ = NULL;
  58. buffer_ = NULL;
  59. compressor_ = NULL;
  60. decompressor_ = NULL;
  61. sorter_ = NULL;
  62. default_compressor_ = NULL;
  63. default_decompressor_ = NULL;
  64. }
  65. void
  66. Message::addRRset(section_t section, RRsetPtr rrsetp)
  67. {
  68. if (section >= SECTION_MAX)
  69. throw DNSInvalidMessageSection();
  70. // Note: should check duplicate (TBD)
  71. sections_[section].push_back(rrsetp);
  72. }
  73. void
  74. Message::addQuestion(const Name& qname, const RRClass& qclass,
  75. const RRType& qtype)
  76. {
  77. addRRset(SECTION_QUESTION, RRsetPtr(new Question(qname, qclass, qtype)));
  78. }
  79. void
  80. Message::toWire()
  81. {
  82. uint16_t codes_and_flags;
  83. if (buffer_ == NULL)
  84. throw DNSNoMessageBuffer();
  85. // reserve room for the header
  86. buffer_->reserve(HEADERLEN);
  87. for (int section = SECTION_QUESTION; section < SECTION_MAX; ++section) {
  88. if (sorter_ != NULL)
  89. sorter_->sort(*this, (section_t)section); //TBD
  90. counts_[section] = 0;
  91. for (std::vector<RRsetPtr>::const_iterator it =
  92. getSection((section_t)section).begin();
  93. it != getSection((section_t)section).end();
  94. ++it)
  95. {
  96. int counter = (*it)->toWire(*buffer_, getCompressor(),
  97. (section_t)section);
  98. // TBD: if truncation is necessary, do something special.
  99. // throw an exception, return an error code (in which case the
  100. // function signature should be changed), etc.
  101. counts_[section] += counter;
  102. }
  103. }
  104. // EDNS, TSIG, etc.
  105. // fill in the header
  106. size_t header_pos = 0;
  107. buffer_->writeUint16At(qid_, header_pos);
  108. header_pos += sizeof(uint16_t);
  109. codes_and_flags = (opcode_ << OPCODE_SHIFT) & OPCODE_MASK;
  110. codes_and_flags |= (rcode_ & RCODE_MASK);
  111. codes_and_flags |= (flags_ & FLAG_MASK);
  112. buffer_->writeUint16At(codes_and_flags, header_pos);
  113. header_pos += sizeof(uint16_t);
  114. for (int section = SECTION_QUESTION; section < SECTION_MAX; ++section) {
  115. buffer_->writeUint16At(counts_[section], header_pos);
  116. header_pos += sizeof(uint16_t);
  117. }
  118. }
  119. void
  120. Message::fromWire()
  121. {
  122. if (buffer_ == NULL)
  123. throw DNSNoMessageBuffer();
  124. if (buffer_->getSpace() < HEADERLEN)
  125. throw DNSMessageTooShort();
  126. qid_ = buffer_->readUint16();
  127. uint16_t codes_and_flags = buffer_->readUint16();
  128. opcode_ = ((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT);
  129. rcode_ = (codes_and_flags & RCODE_MASK);
  130. flags_ = (codes_and_flags & FLAG_MASK);
  131. counts_[SECTION_QUESTION] = buffer_->readUint16();
  132. counts_[SECTION_ANSWER] = buffer_->readUint16();
  133. counts_[SECTION_AUTHORITY] = buffer_->readUint16();
  134. counts_[SECTION_ADDITIONAL] = buffer_->readUint16();
  135. parse_question();
  136. // parse other sections (TBD)
  137. }
  138. void
  139. Message::parse_question()
  140. {
  141. Name name;
  142. if (buffer_ == NULL)
  143. throw DNSNoMessageBuffer();
  144. for (int count = 0; count < this->counts_[SECTION_QUESTION]; count++) {
  145. Name name(*buffer_, getDecompressor());
  146. // Get type and class
  147. if (buffer_->getSpace() < 2 * sizeof(uint16_t))
  148. throw DNSMessageTooShort();
  149. // XXX: need a duplicate check. We might also want to have an optimized
  150. // algorithm that requires the question section contain exactly one
  151. // RR.
  152. RRType rrtype(buffer_->readUint16());
  153. RRClass rrclass(buffer_->readUint16());
  154. addRRset(SECTION_QUESTION,
  155. RRsetPtr(new Question(name, rrclass, rrtype)));
  156. }
  157. }
  158. static const char *opcodetext[] = {
  159. "QUERY",
  160. "IQUERY",
  161. "STATUS",
  162. "RESERVED3",
  163. "NOTIFY",
  164. "UPDATE",
  165. "RESERVED6",
  166. "RESERVED7",
  167. "RESERVED8",
  168. "RESERVED9",
  169. "RESERVED10",
  170. "RESERVED11",
  171. "RESERVED12",
  172. "RESERVED13",
  173. "RESERVED14",
  174. "RESERVED15"
  175. };
  176. static const char *rcodetext[] = {
  177. "NOERROR",
  178. "FORMERR",
  179. "SERVFAIL",
  180. "NXDOMAIN",
  181. "NOTIMP",
  182. "REFUSED",
  183. "YXDOMAIN",
  184. "YXRRSET",
  185. "NXRRSET",
  186. "NOTAUTH",
  187. "NOTZONE",
  188. "RESERVED11",
  189. "RESERVED12",
  190. "RESERVED13",
  191. "RESERVED14",
  192. "RESERVED15"
  193. };
  194. static const char *sectiontext[] = {
  195. "QUESTION",
  196. "ANSWER",
  197. "AUTHORITY",
  198. "ADDITIONAL"
  199. };
  200. std::string
  201. Message::toText() const
  202. {
  203. std::string s;
  204. s += ";; ->>HEADER<<- opcode: " + std::string(opcodetext[opcode_]);
  205. // for simplicity we don't consider extended rcode (unlike BIND9)
  206. s += ", status: " + std::string(rcodetext[rcode_]);
  207. s += ", id: " + boost::lexical_cast<std::string>(qid_);
  208. s += "\n;; flags: ";
  209. if (getQR())
  210. s += "qr ";
  211. if (getAA())
  212. s += "aa ";
  213. if (getTC())
  214. s += "tc ";
  215. if (getRD())
  216. s += "rd ";
  217. if (getRA())
  218. s += "ra ";
  219. if (getAD())
  220. s += "ad ";
  221. if (getCD())
  222. s += "cd ";
  223. // for simply, don't consider the update case
  224. s += "; QUESTION: " +
  225. boost::lexical_cast<std::string>(counts_[SECTION_QUESTION]);
  226. s += ", ANSWER: " +
  227. boost::lexical_cast<std::string>(counts_[SECTION_ANSWER]);
  228. s += ", AUTHORITY: " +
  229. boost::lexical_cast<std::string>(counts_[SECTION_AUTHORITY]);
  230. s += ", ADDITIONAL: " +
  231. boost::lexical_cast<std::string>(counts_[SECTION_ADDITIONAL]) + "\n";
  232. for (int section = SECTION_QUESTION; section < SECTION_MAX; ++section) {
  233. if (sections_[section].empty())
  234. continue;
  235. s += "\n;; " + std::string(sectiontext[section]) + " SECTION:\n";
  236. std::vector<RRsetPtr>::const_iterator it;
  237. for (it = sections_[section].begin();
  238. it != sections_[section].end();
  239. ++it)
  240. {
  241. if (section == SECTION_QUESTION)
  242. s += ";";
  243. s += (**it).toText() + "\n";
  244. }
  245. }
  246. return (s);
  247. }
  248. struct MatchRR : public std::binary_function<RRsetPtr, RR, bool> {
  249. bool operator()(const RRsetPtr& rrset, const RR& rr) const
  250. {
  251. return (rrset->getType() == rr.getType() &&
  252. rrset->getClass() == rr.getClass() &&
  253. rrset->getName() == rr.getName());
  254. }
  255. };
  256. void
  257. Message::addRR(section_t section, const RR& rr)
  258. {
  259. std::vector<RRsetPtr>::iterator it;
  260. it = find_if(sections_[section].begin(), sections_[section].end(),
  261. std::bind2nd(MatchRR(), rr));
  262. if (it != sections_[section].end()) {
  263. (*it)->setTtl(std::min((*it)->getTtl(), rr.getTtl()));
  264. (*it)->addRdata(Rdata::RDATAPTR(rr.getRdata()->copy()));
  265. } else {
  266. RRset *rrset = new RRset(rr.getName(), rr.getClass(), rr.getType(),
  267. rr.getTtl());
  268. rrset->addRdata(Rdata::RDATAPTR(rr.getRdata()->copy()));
  269. sections_[section].push_back(RRsetPtr(rrset));
  270. }
  271. }
  272. void
  273. Message::makeResponse()
  274. {
  275. flags_ &= MESSAGE_REPLYPRESERVE;
  276. setQR(true);
  277. for (int section = SECTION_ANSWER; section < SECTION_MAX; ++section) {
  278. sections_[section].clear();
  279. }
  280. }