recursor.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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 <config.h>
  16. #include <netinet/in.h>
  17. #include <algorithm>
  18. #include <cassert>
  19. #include <iostream>
  20. #include <vector>
  21. #include <asiolink/asiolink.h>
  22. #include <boost/foreach.hpp>
  23. #include <config/ccsession.h>
  24. #include <cc/data.h>
  25. #include <exceptions/exceptions.h>
  26. #include <dns/buffer.h>
  27. #include <dns/exceptions.h>
  28. #include <dns/name.h>
  29. #include <dns/question.h>
  30. #include <dns/rrset.h>
  31. #include <dns/rrttl.h>
  32. #include <dns/message.h>
  33. #include <dns/messagerenderer.h>
  34. #include <xfr/xfrout_client.h>
  35. #include <recurse/recursor.h>
  36. using namespace std;
  37. using namespace isc;
  38. using namespace isc::cc;
  39. using namespace isc::dns;
  40. using namespace isc::dns::rdata;
  41. using namespace isc::data;
  42. using namespace isc::config;
  43. using namespace isc::xfr;
  44. using namespace asiolink;
  45. class RecursorImpl {
  46. private:
  47. // prohibit copy
  48. RecursorImpl(const RecursorImpl& source);
  49. RecursorImpl& operator=(const RecursorImpl& source);
  50. public:
  51. RecursorImpl(const char& forward) :
  52. config_session_(NULL), verbose_mode_(false),
  53. forward_(forward), rec_query_()
  54. {}
  55. ~RecursorImpl() {
  56. queryShutdown();
  57. }
  58. void querySetup(DNSService& dnss) {
  59. rec_query_ = new RecursiveQuery(dnss, forward_);
  60. }
  61. void queryShutdown() {
  62. if (rec_query_) {
  63. delete rec_query_;
  64. }
  65. }
  66. void processNormalQuery(const Question& question, MessagePtr message,
  67. OutputBufferPtr buffer,
  68. DNSServer* server);
  69. /// Currently non-configurable, but will be.
  70. static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
  71. /// These members are public because Recursor accesses them directly.
  72. ModuleCCSession* config_session_;
  73. bool verbose_mode_;
  74. private:
  75. /// Address of the forward nameserver
  76. const char& forward_;
  77. /// Object to handle upstream queries
  78. RecursiveQuery* rec_query_;
  79. };
  80. class QuestionInserter {
  81. public:
  82. QuestionInserter(MessagePtr message) : message_(message) {}
  83. void operator()(const QuestionPtr question) {
  84. message_->addQuestion(question);
  85. }
  86. MessagePtr message_;
  87. };
  88. class SectionInserter {
  89. public:
  90. SectionInserter(MessagePtr message, const Section& sect, bool sign) :
  91. message_(message), section_(sect), sign_(sign)
  92. {}
  93. void operator()(const RRsetPtr rrset) {
  94. message_->addRRset(section_, rrset, true);
  95. }
  96. MessagePtr message_;
  97. const Section& section_;
  98. bool sign_;
  99. };
  100. void
  101. makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
  102. const Rcode& rcode, const bool verbose_mode)
  103. {
  104. // extract the parameters that should be kept.
  105. // XXX: with the current implementation, it's not easy to set EDNS0
  106. // depending on whether the query had it. So we'll simply omit it.
  107. const qid_t qid = message->getQid();
  108. const bool rd = message->getHeaderFlag(MessageFlag::RD());
  109. const bool cd = message->getHeaderFlag(MessageFlag::CD());
  110. const Opcode& opcode = message->getOpcode();
  111. vector<QuestionPtr> questions;
  112. // If this is an error to a query or notify, we should also copy the
  113. // question section.
  114. if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
  115. questions.assign(message->beginQuestion(), message->endQuestion());
  116. }
  117. message->clear(Message::RENDER);
  118. message->setQid(qid);
  119. message->setOpcode(opcode);
  120. message->setHeaderFlag(MessageFlag::QR());
  121. message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
  122. if (rd) {
  123. message->setHeaderFlag(MessageFlag::RD());
  124. }
  125. if (cd) {
  126. message->setHeaderFlag(MessageFlag::CD());
  127. }
  128. for_each(questions.begin(), questions.end(), QuestionInserter(message));
  129. message->setRcode(rcode);
  130. MessageRenderer renderer(*buffer);
  131. message->toWire(renderer);
  132. if (verbose_mode) {
  133. cerr << "[b10-recurse] sending an error response (" <<
  134. renderer.getLength() << " bytes):\n" << message->toText() << endl;
  135. }
  136. }
  137. // This is a derived class of \c DNSLookup, to serve as a
  138. // callback in the asiolink module. It calls
  139. // Recursor::processMessage() on a single DNS message.
  140. class MessageLookup : public DNSLookup {
  141. public:
  142. MessageLookup(Recursor* srv) : server_(srv) {}
  143. // \brief Handle the DNS Lookup
  144. virtual void operator()(const IOMessage& io_message, MessagePtr message,
  145. OutputBufferPtr buffer, DNSServer* server) const
  146. {
  147. server_->processMessage(io_message, message, buffer, server);
  148. }
  149. private:
  150. Recursor* server_;
  151. };
  152. // This is a derived class of \c DNSAnswer, to serve as a
  153. // callback in the asiolink module. It takes a completed
  154. // set of answer data from the DNS lookup and assembles it
  155. // into a wire-format response.
  156. class MessageAnswer : public DNSAnswer {
  157. public:
  158. MessageAnswer(Recursor* srv) : server_(srv) {}
  159. virtual void operator()(const IOMessage& io_message,
  160. MessagePtr message,
  161. OutputBufferPtr buffer) const
  162. {
  163. const qid_t qid = message->getQid();
  164. const bool rd = message->getHeaderFlag(MessageFlag::RD());
  165. const bool cd = message->getHeaderFlag(MessageFlag::CD());
  166. const Opcode& opcode = message->getOpcode();
  167. const Rcode& rcode = message->getRcode();
  168. vector<QuestionPtr> questions;
  169. questions.assign(message->beginQuestion(), message->endQuestion());
  170. message->clear(Message::RENDER);
  171. message->setQid(qid);
  172. message->setOpcode(opcode);
  173. message->setRcode(rcode);
  174. message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
  175. message->setHeaderFlag(MessageFlag::QR());
  176. message->setHeaderFlag(MessageFlag::RA());
  177. if (rd) {
  178. message->setHeaderFlag(MessageFlag::RD());
  179. }
  180. if (cd) {
  181. message->setHeaderFlag(MessageFlag::CD());
  182. }
  183. // Copy the question section.
  184. for_each(questions.begin(), questions.end(), QuestionInserter(message));
  185. // If the buffer already has an answer in it, copy RRsets from
  186. // that into the new message, then clear the buffer and render
  187. // the new message into it.
  188. if (buffer->getLength() != 0) {
  189. try {
  190. Message incoming(Message::PARSE);
  191. InputBuffer ibuf(buffer->getData(), buffer->getLength());
  192. incoming.fromWire(ibuf);
  193. for_each(incoming.beginSection(Section::ANSWER()),
  194. incoming.endSection(Section::ANSWER()),
  195. SectionInserter(message, Section::ANSWER(), true));
  196. for_each(incoming.beginSection(Section::ADDITIONAL()),
  197. incoming.endSection(Section::ADDITIONAL()),
  198. SectionInserter(message, Section::ADDITIONAL(), true));
  199. for_each(incoming.beginSection(Section::AUTHORITY()),
  200. incoming.endSection(Section::AUTHORITY()),
  201. SectionInserter(message, Section::AUTHORITY(), true));
  202. } catch (const Exception& ex) {
  203. // Incoming message couldn't be read, we just SERVFAIL
  204. message->setRcode(Rcode::SERVFAIL());
  205. }
  206. }
  207. // Now we can clear the buffer and render the new message into it
  208. buffer->clear();
  209. MessageRenderer renderer(*buffer);
  210. if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
  211. renderer.setLengthLimit(message->getUDPSize());
  212. } else {
  213. renderer.setLengthLimit(65535);
  214. }
  215. message->toWire(renderer);
  216. if (server_->getVerbose()) {
  217. cerr << "[b10-recurse] sending a response ("
  218. << renderer.getLength() << " bytes):\n"
  219. << message->toText() << endl;
  220. }
  221. }
  222. private:
  223. Recursor* server_;
  224. };
  225. // This is a derived class of \c SimpleCallback, to serve
  226. // as a callback in the asiolink module. It checks for queued
  227. // configuration messages, and executes them if found.
  228. class ConfigCheck : public SimpleCallback {
  229. public:
  230. ConfigCheck(Recursor* srv) : server_(srv) {}
  231. virtual void operator()(const IOMessage& io_message UNUSED_PARAM) const {
  232. if (server_->getConfigSession()->hasQueuedMsgs()) {
  233. server_->getConfigSession()->checkCommand();
  234. }
  235. }
  236. private:
  237. Recursor* server_;
  238. };
  239. Recursor::Recursor(const char& forward) :
  240. impl_(new RecursorImpl(forward)),
  241. checkin_(new ConfigCheck(this)),
  242. dns_lookup_(new MessageLookup(this)),
  243. dns_answer_(new MessageAnswer(this))
  244. {}
  245. Recursor::~Recursor() {
  246. delete impl_;
  247. delete checkin_;
  248. delete dns_lookup_;
  249. delete dns_answer_;
  250. }
  251. void
  252. Recursor::setDNSService(asiolink::DNSService& dnss) {
  253. impl_->queryShutdown();
  254. impl_->querySetup(dnss);
  255. dnss_ = &dnss;
  256. }
  257. void
  258. Recursor::setVerbose(const bool on) {
  259. impl_->verbose_mode_ = on;
  260. }
  261. bool
  262. Recursor::getVerbose() const {
  263. return (impl_->verbose_mode_);
  264. }
  265. void
  266. Recursor::setConfigSession(ModuleCCSession* config_session) {
  267. impl_->config_session_ = config_session;
  268. }
  269. ModuleCCSession*
  270. Recursor::getConfigSession() const {
  271. return (impl_->config_session_);
  272. }
  273. void
  274. Recursor::processMessage(const IOMessage& io_message, MessagePtr message,
  275. OutputBufferPtr buffer, DNSServer* server)
  276. {
  277. InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
  278. // First, check the header part. If we fail even for the base header,
  279. // just drop the message.
  280. try {
  281. message->parseHeader(request_buffer);
  282. // Ignore all responses.
  283. if (message->getHeaderFlag(MessageFlag::QR())) {
  284. if (impl_->verbose_mode_) {
  285. cerr << "[b10-recurse] received unexpected response, ignoring"
  286. << endl;
  287. }
  288. server->resume(false);
  289. return;
  290. }
  291. } catch (const Exception& ex) {
  292. if (impl_->verbose_mode_) {
  293. cerr << "[b10-recurse] DNS packet exception: " << ex.what() << endl;
  294. }
  295. server->resume(false);
  296. return;
  297. }
  298. // Parse the message. On failure, return an appropriate error.
  299. try {
  300. message->fromWire(request_buffer);
  301. } catch (const DNSProtocolError& error) {
  302. if (impl_->verbose_mode_) {
  303. cerr << "[b10-recurse] returning " << error.getRcode().toText()
  304. << ": " << error.what() << endl;
  305. }
  306. makeErrorMessage(message, buffer, error.getRcode(),
  307. impl_->verbose_mode_);
  308. server->resume(true);
  309. return;
  310. } catch (const Exception& ex) {
  311. if (impl_->verbose_mode_) {
  312. cerr << "[b10-recurse] returning SERVFAIL: " << ex.what() << endl;
  313. }
  314. makeErrorMessage(message, buffer, Rcode::SERVFAIL(),
  315. impl_->verbose_mode_);
  316. server->resume(true);
  317. return;
  318. } // other exceptions will be handled at a higher layer.
  319. if (impl_->verbose_mode_) {
  320. cerr << "[b10-recurse] received a message:\n"
  321. << message->toText() << endl;
  322. }
  323. // Perform further protocol-level validation.
  324. bool sendAnswer = true;
  325. if (message->getOpcode() == Opcode::NOTIFY()) {
  326. makeErrorMessage(message, buffer, Rcode::NOTAUTH(),
  327. impl_->verbose_mode_);
  328. } else if (message->getOpcode() != Opcode::QUERY()) {
  329. if (impl_->verbose_mode_) {
  330. cerr << "[b10-recurse] unsupported opcode" << endl;
  331. }
  332. makeErrorMessage(message, buffer, Rcode::NOTIMP(),
  333. impl_->verbose_mode_);
  334. } else if (message->getRRCount(Section::QUESTION()) != 1) {
  335. makeErrorMessage(message, buffer, Rcode::FORMERR(),
  336. impl_->verbose_mode_);
  337. } else {
  338. ConstQuestionPtr question = *message->beginQuestion();
  339. const RRType &qtype = question->getType();
  340. if (qtype == RRType::AXFR()) {
  341. if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
  342. makeErrorMessage(message, buffer, Rcode::FORMERR(),
  343. impl_->verbose_mode_);
  344. } else {
  345. makeErrorMessage(message, buffer, Rcode::NOTIMP(),
  346. impl_->verbose_mode_);
  347. }
  348. } else if (qtype == RRType::IXFR()) {
  349. makeErrorMessage(message, buffer, Rcode::NOTIMP(),
  350. impl_->verbose_mode_);
  351. } else {
  352. // The RecursiveQuery object will post the "resume" event to the
  353. // DNSServer when an answer arrives, so we don't have to do it now.
  354. sendAnswer = false;
  355. impl_->processNormalQuery(*question, message, buffer, server);
  356. }
  357. }
  358. if (sendAnswer) {
  359. server->resume(true);
  360. }
  361. }
  362. void
  363. RecursorImpl::processNormalQuery(const Question& question, MessagePtr message,
  364. OutputBufferPtr buffer, DNSServer* server)
  365. {
  366. const bool dnssec_ok = message->isDNSSECSupported();
  367. message->makeResponse();
  368. message->setHeaderFlag(MessageFlag::RA());
  369. message->setRcode(Rcode::NOERROR());
  370. message->setDNSSECSupported(dnssec_ok);
  371. message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
  372. rec_query_->sendQuery(question, buffer, server);
  373. }
  374. ConstElementPtr
  375. Recursor::updateConfig(ConstElementPtr new_config UNUSED_PARAM) {
  376. try {
  377. // We will do configuration updates here. None are presently
  378. // defined, so we just return an empty answer.
  379. return (isc::config::createAnswer());
  380. } catch (const isc::Exception& error) {
  381. if (impl_->verbose_mode_) {
  382. cerr << "[b10-recurse] error: " << error.what() << endl;
  383. }
  384. return (isc::config::createAnswer(1, error.what()));
  385. }
  386. }