recursor.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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 <vector>
  19. #include <cassert>
  20. #include <asiolink/asiolink.h>
  21. #include <asiolink/ioaddress.h>
  22. #include <boost/foreach.hpp>
  23. #include <boost/lexical_cast.hpp>
  24. #include <config/ccsession.h>
  25. #include <exceptions/exceptions.h>
  26. #include <dns/opcode.h>
  27. #include <dns/rcode.h>
  28. #include <dns/buffer.h>
  29. #include <dns/exceptions.h>
  30. #include <dns/name.h>
  31. #include <dns/question.h>
  32. #include <dns/rrset.h>
  33. #include <dns/rrttl.h>
  34. #include <dns/message.h>
  35. #include <dns/messagerenderer.h>
  36. #include <log/dummylog.h>
  37. #include <recurse/recursor.h>
  38. using namespace std;
  39. using namespace isc;
  40. using namespace isc::dns;
  41. using namespace isc::data;
  42. using namespace isc::config;
  43. using isc::log::dlog;
  44. using namespace asiolink;
  45. typedef pair<string, uint16_t> addr_t;
  46. class RecursorImpl {
  47. private:
  48. // prohibit copy
  49. RecursorImpl(const RecursorImpl& source);
  50. RecursorImpl& operator=(const RecursorImpl& source);
  51. public:
  52. RecursorImpl() :
  53. config_session_(NULL),
  54. rec_query_(NULL)
  55. {}
  56. ~RecursorImpl() {
  57. queryShutdown();
  58. }
  59. void querySetup(DNSService& dnss) {
  60. assert(!rec_query_); // queryShutdown must be called first
  61. dlog("Query setup");
  62. rec_query_ = new RecursiveQuery(dnss, upstream_);
  63. }
  64. void queryShutdown() {
  65. dlog("Query shutdown");
  66. delete rec_query_;
  67. rec_query_ = NULL;
  68. }
  69. void setForwardAddresses(const vector<addr_t>& upstream,
  70. DNSService *dnss)
  71. {
  72. queryShutdown();
  73. upstream_ = upstream;
  74. if (dnss) {
  75. if (upstream_.empty()) {
  76. dlog("Asked to do full recursive, but not implemented yet. "
  77. "I'll do nothing.");
  78. } else {
  79. dlog("Setting forward addresses:");
  80. BOOST_FOREACH(const addr_t& address, upstream) {
  81. dlog(" " + address.first + ":" +
  82. boost::lexical_cast<string>(address.second));
  83. }
  84. querySetup(*dnss);
  85. }
  86. }
  87. }
  88. void processNormalQuery(const Question& question, MessagePtr message,
  89. OutputBufferPtr buffer,
  90. DNSServer* server);
  91. /// Currently non-configurable, but will be.
  92. static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
  93. /// These members are public because Recursor accesses them directly.
  94. ModuleCCSession* config_session_;
  95. /// Addresses of the forward nameserver
  96. vector<addr_t> upstream_;
  97. /// Addresses we listen on
  98. vector<addr_t> listen_;
  99. /// Time in milliseconds, to timeout
  100. int timeout_;
  101. /// Number of retries after timeout
  102. unsigned retries_;
  103. private:
  104. /// Object to handle upstream queries
  105. RecursiveQuery* rec_query_;
  106. };
  107. /*
  108. * std::for_each has a broken interface. It makes no sense in a language
  109. * without lambda functions/closures. These two classes emulate the lambda
  110. * functions so for_each can be used.
  111. */
  112. class QuestionInserter {
  113. public:
  114. QuestionInserter(MessagePtr message) : message_(message) {}
  115. void operator()(const QuestionPtr question) {
  116. dlog(string("Adding question ") + question->getName().toText() +
  117. " to message");
  118. message_->addQuestion(question);
  119. }
  120. MessagePtr message_;
  121. };
  122. class SectionInserter {
  123. public:
  124. SectionInserter(MessagePtr message, const Message::Section sect) :
  125. message_(message), section_(sect)
  126. {}
  127. void operator()(const RRsetPtr rrset) {
  128. //dlog("Adding RRSet to message section " +
  129. // boost::lexical_cast<string>(section_));
  130. message_->addRRset(section_, rrset, true);
  131. }
  132. MessagePtr message_;
  133. const Message::Section section_;
  134. };
  135. void
  136. makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
  137. const Rcode& rcode)
  138. {
  139. // extract the parameters that should be kept.
  140. // XXX: with the current implementation, it's not easy to set EDNS0
  141. // depending on whether the query had it. So we'll simply omit it.
  142. const qid_t qid = message->getQid();
  143. const bool rd = message->getHeaderFlag(Message::HEADERFLAG_RD);
  144. const bool cd = message->getHeaderFlag(Message::HEADERFLAG_CD);
  145. const Opcode& opcode = message->getOpcode();
  146. vector<QuestionPtr> questions;
  147. // If this is an error to a query or notify, we should also copy the
  148. // question section.
  149. if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
  150. questions.assign(message->beginQuestion(), message->endQuestion());
  151. }
  152. message->clear(Message::RENDER);
  153. message->setQid(qid);
  154. message->setOpcode(opcode);
  155. message->setHeaderFlag(Message::HEADERFLAG_QR);
  156. if (rd) {
  157. message->setHeaderFlag(Message::HEADERFLAG_RD);
  158. }
  159. if (cd) {
  160. message->setHeaderFlag(Message::HEADERFLAG_CD);
  161. }
  162. for_each(questions.begin(), questions.end(), QuestionInserter(message));
  163. message->setRcode(rcode);
  164. MessageRenderer renderer(*buffer);
  165. message->toWire(renderer);
  166. dlog(string("Sending an error response (") +
  167. boost::lexical_cast<string>(renderer.getLength()) + " bytes):\n" +
  168. message->toText());
  169. }
  170. // This is a derived class of \c DNSLookup, to serve as a
  171. // callback in the asiolink module. It calls
  172. // Recursor::processMessage() on a single DNS message.
  173. class MessageLookup : public DNSLookup {
  174. public:
  175. MessageLookup(Recursor* srv) : server_(srv) {}
  176. // \brief Handle the DNS Lookup
  177. virtual void operator()(const IOMessage& io_message, MessagePtr message,
  178. OutputBufferPtr buffer, DNSServer* server) const
  179. {
  180. server_->processMessage(io_message, message, buffer, server);
  181. }
  182. private:
  183. Recursor* server_;
  184. };
  185. // This is a derived class of \c DNSAnswer, to serve as a
  186. // callback in the asiolink module. It takes a completed
  187. // set of answer data from the DNS lookup and assembles it
  188. // into a wire-format response.
  189. class MessageAnswer : public DNSAnswer {
  190. public:
  191. virtual void operator()(const IOMessage& io_message,
  192. MessagePtr message,
  193. OutputBufferPtr buffer) const
  194. {
  195. const qid_t qid = message->getQid();
  196. const bool rd = message->getHeaderFlag(Message::HEADERFLAG_RD);
  197. const bool cd = message->getHeaderFlag(Message::HEADERFLAG_CD);
  198. const Opcode& opcode = message->getOpcode();
  199. const Rcode& rcode = message->getRcode();
  200. vector<QuestionPtr> questions;
  201. questions.assign(message->beginQuestion(), message->endQuestion());
  202. message->clear(Message::RENDER);
  203. message->setQid(qid);
  204. message->setOpcode(opcode);
  205. message->setRcode(rcode);
  206. message->setHeaderFlag(Message::HEADERFLAG_QR);
  207. message->setHeaderFlag(Message::HEADERFLAG_RA);
  208. if (rd) {
  209. message->setHeaderFlag(Message::HEADERFLAG_RD);
  210. }
  211. if (cd) {
  212. message->setHeaderFlag(Message::HEADERFLAG_CD);
  213. }
  214. // Copy the question section.
  215. for_each(questions.begin(), questions.end(), QuestionInserter(message));
  216. // If the buffer already has an answer in it, copy RRsets from
  217. // that into the new message, then clear the buffer and render
  218. // the new message into it.
  219. if (buffer->getLength() != 0) {
  220. try {
  221. Message incoming(Message::PARSE);
  222. InputBuffer ibuf(buffer->getData(), buffer->getLength());
  223. incoming.fromWire(ibuf);
  224. for_each(incoming.beginSection(Message::SECTION_ANSWER),
  225. incoming.endSection(Message::SECTION_ANSWER),
  226. SectionInserter(message, Message::SECTION_ANSWER));
  227. for_each(incoming.beginSection(Message::SECTION_AUTHORITY),
  228. incoming.endSection(Message::SECTION_AUTHORITY),
  229. SectionInserter(message, Message::SECTION_AUTHORITY));
  230. for_each(incoming.beginSection(Message::SECTION_ADDITIONAL),
  231. incoming.endSection(Message::SECTION_ADDITIONAL),
  232. SectionInserter(message, Message::SECTION_ADDITIONAL));
  233. } catch (const Exception& ex) {
  234. // Incoming message couldn't be read, we just SERVFAIL
  235. message->setRcode(Rcode::SERVFAIL());
  236. }
  237. }
  238. // Now we can clear the buffer and render the new message into it
  239. buffer->clear();
  240. MessageRenderer renderer(*buffer);
  241. if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
  242. ConstEDNSPtr edns(message->getEDNS());
  243. renderer.setLengthLimit(edns ? edns->getUDPSize() :
  244. Message::DEFAULT_MAX_UDPSIZE);
  245. } else {
  246. renderer.setLengthLimit(65535);
  247. }
  248. message->toWire(renderer);
  249. dlog(string("sending a response (") +
  250. boost::lexical_cast<string>(renderer.getLength()) + "bytes): \n" +
  251. message->toText());
  252. }
  253. };
  254. // This is a derived class of \c SimpleCallback, to serve
  255. // as a callback in the asiolink module. It checks for queued
  256. // configuration messages, and executes them if found.
  257. class ConfigCheck : public SimpleCallback {
  258. public:
  259. ConfigCheck(Recursor* srv) : server_(srv) {}
  260. virtual void operator()(const IOMessage&) const {
  261. if (server_->getConfigSession()->hasQueuedMsgs()) {
  262. server_->getConfigSession()->checkCommand();
  263. }
  264. }
  265. private:
  266. Recursor* server_;
  267. };
  268. Recursor::Recursor() :
  269. impl_(new RecursorImpl()),
  270. checkin_(new ConfigCheck(this)),
  271. dns_lookup_(new MessageLookup(this)),
  272. dns_answer_(new MessageAnswer)
  273. {}
  274. Recursor::~Recursor() {
  275. delete impl_;
  276. delete checkin_;
  277. delete dns_lookup_;
  278. delete dns_answer_;
  279. dlog("Deleting the Recursor");
  280. }
  281. void
  282. Recursor::setDNSService(asiolink::DNSService& dnss) {
  283. impl_->queryShutdown();
  284. impl_->querySetup(dnss);
  285. dnss_ = &dnss;
  286. }
  287. void
  288. Recursor::setConfigSession(ModuleCCSession* config_session) {
  289. impl_->config_session_ = config_session;
  290. }
  291. ModuleCCSession*
  292. Recursor::getConfigSession() const {
  293. return (impl_->config_session_);
  294. }
  295. void
  296. Recursor::processMessage(const IOMessage& io_message, MessagePtr message,
  297. OutputBufferPtr buffer, DNSServer* server)
  298. {
  299. dlog("Got a DNS message");
  300. InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
  301. // First, check the header part. If we fail even for the base header,
  302. // just drop the message.
  303. try {
  304. message->parseHeader(request_buffer);
  305. // Ignore all responses.
  306. if (message->getHeaderFlag(Message::HEADERFLAG_QR)) {
  307. dlog("Received unexpected response, ignoring");
  308. server->resume(false);
  309. return;
  310. }
  311. } catch (const Exception& ex) {
  312. dlog(string("DNS packet exception: ") + ex.what());
  313. server->resume(false);
  314. return;
  315. }
  316. // Parse the message. On failure, return an appropriate error.
  317. try {
  318. message->fromWire(request_buffer);
  319. } catch (const DNSProtocolError& error) {
  320. dlog(string("returning ") + error.getRcode().toText() + ": " +
  321. error.what());
  322. makeErrorMessage(message, buffer, error.getRcode());
  323. server->resume(true);
  324. return;
  325. } catch (const Exception& ex) {
  326. dlog(string("returning SERVFAIL: ") + ex.what());
  327. makeErrorMessage(message, buffer, Rcode::SERVFAIL());
  328. server->resume(true);
  329. return;
  330. } // other exceptions will be handled at a higher layer.
  331. dlog("received a message:\n" + message->toText());
  332. // Perform further protocol-level validation.
  333. bool sendAnswer = true;
  334. if (message->getOpcode() == Opcode::NOTIFY()) {
  335. makeErrorMessage(message, buffer, Rcode::NOTAUTH());
  336. dlog("Notify arrived, but we are not authoritative");
  337. } else if (message->getOpcode() != Opcode::QUERY()) {
  338. dlog("Unsupported opcode (got: " + message->getOpcode().toText() +
  339. ", expected: " + Opcode::QUERY().toText());
  340. makeErrorMessage(message, buffer, Rcode::NOTIMP());
  341. } else if (message->getRRCount(Message::SECTION_QUESTION) != 1) {
  342. dlog("The query contained " +
  343. boost::lexical_cast<string>(message->getRRCount(
  344. Message::SECTION_QUESTION) + " questions, exactly one expected"));
  345. makeErrorMessage(message, buffer, Rcode::FORMERR());
  346. } else {
  347. ConstQuestionPtr question = *message->beginQuestion();
  348. const RRType &qtype = question->getType();
  349. if (qtype == RRType::AXFR()) {
  350. if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
  351. makeErrorMessage(message, buffer, Rcode::FORMERR());
  352. } else {
  353. makeErrorMessage(message, buffer, Rcode::NOTIMP());
  354. }
  355. } else if (qtype == RRType::IXFR()) {
  356. makeErrorMessage(message, buffer, Rcode::NOTIMP());
  357. } else {
  358. // The RecursiveQuery object will post the "resume" event to the
  359. // DNSServer when an answer arrives, so we don't have to do it now.
  360. sendAnswer = false;
  361. impl_->processNormalQuery(*question, message, buffer, server);
  362. }
  363. }
  364. if (sendAnswer) {
  365. server->resume(true);
  366. }
  367. }
  368. void
  369. RecursorImpl::processNormalQuery(const Question& question, MessagePtr message,
  370. OutputBufferPtr buffer, DNSServer* server)
  371. {
  372. dlog("Processing normal query");
  373. ConstEDNSPtr edns(message->getEDNS());
  374. const bool dnssec_ok = edns && edns->getDNSSECAwareness();
  375. message->makeResponse();
  376. message->setHeaderFlag(Message::HEADERFLAG_RA);
  377. message->setRcode(Rcode::NOERROR());
  378. if (edns) {
  379. EDNSPtr edns_response(new EDNS());
  380. edns_response->setDNSSECAwareness(dnssec_ok);
  381. edns_response->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
  382. message->setEDNS(edns_response);
  383. }
  384. rec_query_->sendQuery(question, buffer, server);
  385. }
  386. namespace {
  387. vector<addr_t>
  388. parseAddresses(ConstElementPtr addresses) {
  389. vector<addr_t> result;
  390. if (addresses) {
  391. if (addresses->getType() == Element::list) {
  392. for (size_t i(0); i < addresses->size(); ++ i) {
  393. ConstElementPtr addrPair(addresses->get(i));
  394. ConstElementPtr addr(addrPair->get("address"));
  395. ConstElementPtr port(addrPair->get("port"));
  396. if (!addr || ! port) {
  397. isc_throw(BadValue, "Address must contain both the IP"
  398. "address and port");
  399. }
  400. try {
  401. IOAddress(addr->stringValue());
  402. if (port->intValue() < 0 ||
  403. port->intValue() > 0xffff) {
  404. isc_throw(BadValue, "Bad port value (" <<
  405. port->intValue() << ")");
  406. }
  407. result.push_back(addr_t(addr->stringValue(),
  408. port->intValue()));
  409. }
  410. catch (const TypeError &e) { // Better error message
  411. isc_throw(TypeError,
  412. "Address must be a string and port an integer");
  413. }
  414. }
  415. } else if (addresses->getType() != Element::null) {
  416. isc_throw(TypeError,
  417. "forward_addresses config element must be a list");
  418. }
  419. }
  420. return (result);
  421. }
  422. }
  423. ConstElementPtr
  424. Recursor::updateConfig(ConstElementPtr config) {
  425. dlog("New config comes: " + config->toWire());
  426. try {
  427. // Parse forward_addresses
  428. ConstElementPtr forwardAddressesE(config->get("forward_addresses"));
  429. vector<addr_t> forwardAddresses(parseAddresses(forwardAddressesE));
  430. ConstElementPtr listenAddressesE(config->get("listen_on"));
  431. vector<addr_t> listenAddresses(parseAddresses(listenAddressesE));
  432. bool set_timeouts(false);
  433. int timeout = impl_->timeout_;
  434. unsigned retries = impl_->retries_;
  435. ConstElementPtr timeoutE(config->get("timeout")),
  436. retriesE(config->get("retries"));
  437. if (timeoutE) {
  438. // It should be safe to just get it, the config manager should
  439. // check for us
  440. timeout = timeoutE->intValue();
  441. if (timeout < -1) {
  442. isc_throw(BadValue, "Timeout too small");
  443. }
  444. set_timeouts = true;
  445. }
  446. if (retriesE) {
  447. if (retriesE->intValue() < 0) {
  448. isc_throw(BadValue, "Negative number of retries");
  449. }
  450. retries = retriesE->intValue();
  451. set_timeouts = true;
  452. }
  453. // Everything OK, so commit the changes
  454. // listenAddresses can fail to bind, so try them first
  455. if (listenAddressesE) {
  456. setListenAddresses(listenAddresses);
  457. }
  458. if (forwardAddressesE) {
  459. setForwardAddresses(forwardAddresses);
  460. }
  461. if (set_timeouts) {
  462. setTimeouts(timeout, retries);
  463. }
  464. return (isc::config::createAnswer());
  465. } catch (const isc::Exception& error) {
  466. dlog(string("error in config: ") + error.what());
  467. return (isc::config::createAnswer(1, error.what()));
  468. }
  469. }
  470. void
  471. Recursor::setForwardAddresses(const vector<addr_t>& addresses)
  472. {
  473. impl_->setForwardAddresses(addresses, dnss_);
  474. }
  475. bool
  476. Recursor::isForwarding() const {
  477. return (!impl_->upstream_.empty());
  478. }
  479. vector<addr_t>
  480. Recursor::getForwardAddresses() const {
  481. return (impl_->upstream_);
  482. }
  483. namespace {
  484. void
  485. setAddresses(DNSService *service, const vector<addr_t>& addresses) {
  486. service->clearServers();
  487. BOOST_FOREACH(const addr_t &address, addresses) {
  488. service->addServer(address.second, address.first);
  489. }
  490. }
  491. }
  492. void
  493. Recursor::setListenAddresses(const vector<addr_t>& addresses) {
  494. try {
  495. dlog("Setting listen addresses:");
  496. BOOST_FOREACH(const addr_t& addr, addresses) {
  497. dlog(" " + addr.first + boost::lexical_cast<string>(addr.second));
  498. }
  499. setAddresses(dnss_, addresses);
  500. impl_->listen_ = addresses;
  501. }
  502. catch (const exception& e) {
  503. /*
  504. * We couldn't set it. So return it back. If that fails as well,
  505. * we have a problem.
  506. *
  507. * If that fails, bad luck, but we are useless anyway, so just die
  508. * and let boss start us again.
  509. */
  510. try {
  511. setAddresses(dnss_, impl_->listen_);
  512. }
  513. catch (const exception& e2) {
  514. dlog(string("Unable to recover from error: ") + e.what() +
  515. " Rollback failed with: " + e2.what());
  516. abort();
  517. }
  518. throw e; // Let it fly a little bit further
  519. }
  520. }
  521. void
  522. Recursor::setTimeouts(int timeout, unsigned retries) {
  523. dlog("Setting timeout to " + boost::lexical_cast<string>(timeout) +
  524. " and retry count to " + boost::lexical_cast<string>(retries));
  525. impl_->timeout_ = timeout;
  526. impl_->retries_ = retries;
  527. impl_->queryShutdown();
  528. impl_->querySetup(*dnss_);
  529. }
  530. pair<int, unsigned>
  531. Recursor::getTimeouts() const {
  532. return (pair<int, unsigned>(impl_->timeout_, impl_->retries_));
  533. }
  534. vector<addr_t>
  535. Recursor::getListenAddresses() const {
  536. return (impl_->listen_);
  537. }