resolver.cc 22 KB

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