recursive_query.cc 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. // Copyright (C) 2011 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 <stdlib.h>
  16. #include <netinet/in.h>
  17. #include <sys/socket.h>
  18. #include <unistd.h> // for some IPC/network system calls
  19. #include <string>
  20. #include <boost/lexical_cast.hpp>
  21. #include <boost/bind.hpp>
  22. #include <dns/question.h>
  23. #include <dns/message.h>
  24. #include <dns/opcode.h>
  25. #include <dns/exceptions.h>
  26. #include <dns/rdataclass.h>
  27. #include <resolve/resolve.h>
  28. #include <resolve/resolve_log.h>
  29. #include <resolve/resolve_messages.h>
  30. #include <cache/resolver_cache.h>
  31. #include <nsas/address_request_callback.h>
  32. #include <nsas/nameserver_address.h>
  33. #include <asio.hpp>
  34. #include <asiodns/dns_service.h>
  35. #include <asiodns/io_fetch.h>
  36. #include <asiolink/io_service.h>
  37. #include <resolve/response_classifier.h>
  38. #include <resolve/recursive_query.h>
  39. using namespace isc::dns;
  40. using namespace isc::nsas;
  41. using namespace isc::util;
  42. using namespace isc::asiolink;
  43. using namespace isc::resolve;
  44. namespace isc {
  45. namespace asiodns {
  46. namespace {
  47. // Function to check if the given name/class has any address in the cache
  48. bool
  49. hasAddress(const Name& name, const RRClass& rrClass,
  50. const isc::cache::ResolverCache& cache)
  51. {
  52. // FIXME: If we are single-stack and we get only the other type of
  53. // address, what should we do? In that case, it will be considered
  54. // unreachable, which is most probably true, because A and AAAA will
  55. // usually have the same RTT, so we should have both or none from the
  56. // glue.
  57. return (cache.lookup(name, RRType::A(), rrClass) != RRsetPtr() ||
  58. cache.lookup(name, RRType::AAAA(), rrClass) != RRsetPtr());
  59. }
  60. // Convenience function for debug messages. Question::toText() includes
  61. // a trailing newline in its output, which makes it awkward to embed in a
  62. // message. This just strips that newline from it.
  63. std::string
  64. questionText(const isc::dns::Question& question) {
  65. std::string text = question.toText();
  66. if (!text.empty()) {
  67. text.erase(text.size() - 1);
  68. }
  69. return (text);
  70. }
  71. } // anonymous namespace
  72. /// \brief Find deepest usable delegation in the cache
  73. ///
  74. /// This finds the deepest delegation we have in cache and is safe to use.
  75. /// It is not public function, therefore it's not in header. But it's not
  76. /// in anonymous namespace, so we can call it from unittests.
  77. /// \param name The name we want to delegate to.
  78. /// \param rrclass The class.
  79. /// \param cache The place too look for known delegations.
  80. std::string
  81. deepestDelegation(Name name, RRClass rrclass,
  82. isc::cache::ResolverCache& cache)
  83. {
  84. RRsetPtr cachedNS;
  85. // Look for delegation point from bottom, until we find one with
  86. // IP address or get to root.
  87. //
  88. // We need delegation with IP address so we can ask it right away.
  89. // If we don't have the IP address, we would need to ask above it
  90. // anyway in the best case, and the NS could be inside the zone,
  91. // and we could get all loopy with the NSAS in the worst case.
  92. while (name.getLabelCount() > 1 &&
  93. (cachedNS = cache.lookupDeepestNS(name, rrclass)) != RRsetPtr()) {
  94. // Look if we have an IP address for the NS
  95. for (RdataIteratorPtr ns(cachedNS->getRdataIterator());
  96. !ns->isLast(); ns->next()) {
  97. // Do we have IP for this specific NS?
  98. if (hasAddress(dynamic_cast<const rdata::generic::NS&>(
  99. ns->getCurrent()).getNSName(), rrclass,
  100. cache)) {
  101. // Found one, stop checking and use this zone
  102. // (there may be more addresses, that's only better)
  103. return (cachedNS->getName().toText());
  104. }
  105. }
  106. // We don't have anything for this one, so try something higher
  107. if (name.getLabelCount() > 1) {
  108. name = name.split(1);
  109. }
  110. }
  111. // Fallback, nothing found, start at root
  112. return (".");
  113. }
  114. // Here we do not use the typedef above, as the SunStudio compiler
  115. // mishandles this in its name mangling, and wouldn't compile.
  116. // We can probably use a typedef, but need to move it to a central
  117. // location and use it consistently.
  118. RecursiveQuery::RecursiveQuery(DNSServiceBase& dns_service,
  119. isc::nsas::NameserverAddressStore& nsas,
  120. isc::cache::ResolverCache& cache,
  121. const std::vector<std::pair<std::string, uint16_t> >& upstream,
  122. const std::vector<std::pair<std::string, uint16_t> >& upstream_root,
  123. int query_timeout, int client_timeout, int lookup_timeout,
  124. unsigned retries)
  125. :
  126. dns_service_(dns_service),
  127. nsas_(nsas), cache_(cache),
  128. upstream_(new AddressVector(upstream)),
  129. upstream_root_(new AddressVector(upstream_root)),
  130. test_server_("", 0),
  131. query_timeout_(query_timeout), client_timeout_(client_timeout),
  132. lookup_timeout_(lookup_timeout), retries_(retries), rtt_recorder_()
  133. {
  134. }
  135. // Set the test server - only used for unit testing.
  136. void
  137. RecursiveQuery::setTestServer(const std::string& address, uint16_t port) {
  138. LOG_WARN(isc::resolve::logger, RESLIB_TEST_SERVER).arg(address).arg(port);
  139. test_server_.first = address;
  140. test_server_.second = port;
  141. }
  142. // Set the RTT recorder - only used for testing
  143. void
  144. RecursiveQuery::setRttRecorder(boost::shared_ptr<RttRecorder>& recorder) {
  145. rtt_recorder_ = recorder;
  146. }
  147. namespace {
  148. typedef std::pair<std::string, uint16_t> addr_t;
  149. /*
  150. * This is a query in progress. When a new query is made, this one holds
  151. * the context information about it, like how many times we are allowed
  152. * to retry on failure, what to do when we succeed, etc.
  153. *
  154. * Used by RecursiveQuery::sendQuery.
  155. */
  156. class RunningQuery : public IOFetch::Callback, public AbstractRunningQuery {
  157. class ResolverNSASCallback : public isc::nsas::AddressRequestCallback {
  158. public:
  159. ResolverNSASCallback(RunningQuery* rq) : rq_(rq) {}
  160. void success(const isc::nsas::NameserverAddress& address) {
  161. // Success callback, send query to found namesever
  162. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CB, RESLIB_RUNQ_SUCCESS)
  163. .arg(address.getAddress().toText());
  164. rq_->nsasCallbackCalled();
  165. rq_->sendTo(address);
  166. }
  167. void unreachable() {
  168. // Nameservers unreachable: drop query or send servfail?
  169. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CB, RESLIB_RUNQ_FAIL);
  170. rq_->nsasCallbackCalled();
  171. rq_->makeSERVFAIL();
  172. rq_->callCallback(true);
  173. rq_->stop();
  174. }
  175. private:
  176. RunningQuery* rq_;
  177. };
  178. private:
  179. // The io service to handle async calls
  180. IOService& io_;
  181. // Info for (re)sending the query (the question and destination)
  182. Question question_;
  183. // This is the query message got from client
  184. ConstMessagePtr query_message_;
  185. // This is where we build and store our final answer
  186. MessagePtr answer_message_;
  187. // Test server - only used for testing. This takes precedence over all
  188. // other servers if the port is non-zero.
  189. std::pair<std::string, uint16_t> test_server_;
  190. // Buffer to store the intermediate results.
  191. OutputBufferPtr buffer_;
  192. // The callback will be called when we have either decided we
  193. // are done, or when we give up
  194. isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
  195. // Protocol used for the last query. This is set to IOFetch::UDP when a
  196. // new upstream query is initiated, and changed to IOFetch::TCP if a
  197. // packet is returned with the TC bit set. It is stored here to detect the
  198. // case of a TCP packet being returned with the TC bit set.
  199. IOFetch::Protocol protocol_;
  200. // EDNS flag
  201. bool edns_;
  202. // To prevent both unreasonably long cname chains and cname loops,
  203. // we simply keep a counter of the number of CNAMEs we have
  204. // followed so far (and error if it exceeds RESOLVER_MAX_CNAME_CHAIN
  205. // from lib/resolve/response_classifier.h)
  206. unsigned cname_count_;
  207. /*
  208. * TODO Do something more clever with timeouts. In the long term, some
  209. * computation of average RTT, increase with each retry, etc.
  210. */
  211. // Timeout information for outgoing queries
  212. int query_timeout_;
  213. unsigned retries_;
  214. // normal query state
  215. // TODO: replace by our wrapper
  216. asio::deadline_timer client_timer;
  217. asio::deadline_timer lookup_timer;
  218. // If we timed out ourselves (lookup timeout), stop issuing queries
  219. bool done_;
  220. // If we have a client timeout, we call back with a failure message,
  221. // but we do not stop yet. We use this variable to make sure we
  222. // don't call back a second time later
  223. bool callback_called_;
  224. // Reference to our NSAS
  225. isc::nsas::NameserverAddressStore& nsas_;
  226. // Reference to our cache
  227. isc::cache::ResolverCache& cache_;
  228. // the 'current' zone we are in (i.e.) we start out at the root,
  229. // and for each delegation this gets updated with the zone the
  230. // delegation points to.
  231. // TODO: make this a Name (it is a string right now because most
  232. // of the call we use it in take a string, we need update those
  233. // too).
  234. std::string cur_zone_;
  235. // This is the handler we pass on to the NSAS; it is called when
  236. // the NSAS has an address for us to query
  237. boost::shared_ptr<ResolverNSASCallback> nsas_callback_;
  238. // this is set to true if we have asked the nsas to give us
  239. // an address and we are waiting for it to call us back.
  240. // We use is to cancel the outstanding callback in case we
  241. // have a lookup timeout and decide to give up
  242. bool nsas_callback_out_;
  243. // This is the nameserver we have an outstanding query to.
  244. // It is used to update the RTT once the query returns
  245. isc::nsas::NameserverAddress current_ns_address;
  246. // The moment in time we sent a query to the nameserver above.
  247. struct timeval current_ns_qsent_time;
  248. // RunningQuery deletes itself when it is done. In order for us
  249. // to do this safely, we must make sure that there are no events
  250. // that might call back to it. There are two types of events in
  251. // this sense; the timers we set ourselves (lookup and client),
  252. // and outstanding queries to nameservers. When each of these is
  253. // started, we increase this value. When they fire, it is decreased
  254. // again. We cannot delete ourselves until this value is back to 0.
  255. //
  256. // Note that the NSAS callback is *not* seen as an outstanding
  257. // event; we can cancel the NSAS callback safely.
  258. size_t outstanding_events_;
  259. // RTT Recorder. Used for testing, the RTTs of queries are
  260. // sent to this object as well as being used to update the NSAS.
  261. boost::shared_ptr<RttRecorder> rtt_recorder_;
  262. // perform a single lookup; first we check the cache to see
  263. // if we have a response for our query stored already. if
  264. // so, call handlerecursiveresponse(), if not, we call send()
  265. void doLookup() {
  266. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RUNQ_CACHE_LOOKUP)
  267. .arg(questionText(question_));
  268. Message cached_message(Message::RENDER);
  269. isc::resolve::initResponseMessage(question_, cached_message);
  270. if (cache_.lookup(question_.getName(), question_.getType(),
  271. question_.getClass(), cached_message)) {
  272. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RUNQ_CACHE_FIND)
  273. .arg(questionText(question_));
  274. // Should these be set by the cache too?
  275. cached_message.setOpcode(Opcode::QUERY());
  276. cached_message.setRcode(Rcode::NOERROR());
  277. cached_message.setHeaderFlag(Message::HEADERFLAG_QR);
  278. if (handleRecursiveAnswer(cached_message)) {
  279. callCallback(true);
  280. stop();
  281. }
  282. } else {
  283. cur_zone_ = deepestDelegation(question_.getName(),
  284. question_.getClass(), cache_);
  285. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_DEEPEST)
  286. .arg(questionText(question_)).arg(cur_zone_);
  287. send();
  288. }
  289. }
  290. // Send the current question to the given nameserver address
  291. void sendTo(const isc::nsas::NameserverAddress& address) {
  292. // We need to keep track of the Address, so that we can update
  293. // the RTT
  294. current_ns_address = address;
  295. gettimeofday(&current_ns_qsent_time, NULL);
  296. ++outstanding_events_;
  297. if (test_server_.second != 0) {
  298. IOFetch query(protocol_, io_, question_,
  299. test_server_.first,
  300. test_server_.second, buffer_, this,
  301. query_timeout_, edns_);
  302. io_.get_io_service().post(query);
  303. } else {
  304. IOFetch query(protocol_, io_, question_,
  305. current_ns_address.getAddress(),
  306. 53, buffer_, this,
  307. query_timeout_, edns_);
  308. io_.get_io_service().post(query);
  309. }
  310. }
  311. // 'general' send, ask the NSAS to give us an address.
  312. void send(IOFetch::Protocol protocol = IOFetch::UDP, bool edns = true) {
  313. protocol_ = protocol; // Store protocol being used for this
  314. edns_ = edns;
  315. if (test_server_.second != 0) {
  316. // Send query to test server
  317. LOG_DEBUG(isc::resolve::logger,
  318. RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM)
  319. .arg(questionText(question_)).arg(test_server_.first);
  320. gettimeofday(&current_ns_qsent_time, NULL);
  321. ++outstanding_events_;
  322. IOFetch query(protocol, io_, question_,
  323. test_server_.first,
  324. test_server_.second, buffer_, this,
  325. query_timeout_, edns_);
  326. io_.get_io_service().post(query);
  327. } else {
  328. // Ask the NSAS for an address for the current zone,
  329. // the callback will call the actual sendTo()
  330. LOG_DEBUG(isc::resolve::logger,
  331. RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP)
  332. .arg(cur_zone_);
  333. // Can we have multiple calls to nsas_out? Let's assume not
  334. // for now
  335. assert(!nsas_callback_out_);
  336. nsas_callback_out_ = true;
  337. nsas_.lookup(cur_zone_, question_.getClass(), nsas_callback_);
  338. }
  339. }
  340. // Called by our NSAS callback handler so we know we do not have
  341. // an outstanding NSAS call anymore.
  342. void nsasCallbackCalled() {
  343. nsas_callback_out_ = false;
  344. }
  345. // This function is called by operator() and lookup();
  346. // We have an answer either from a nameserver or the cache, and
  347. // we do not know yet if this is a final answer we can send back or
  348. // that more recursive processing needs to be done.
  349. // Depending on the content, we go on recursing or return
  350. //
  351. // This method also updates the cache, depending on the content
  352. // of the message
  353. //
  354. // returns true if we are done (either we have an answer or an
  355. // error message)
  356. // returns false if we are not done
  357. bool handleRecursiveAnswer(const Message& incoming) {
  358. // In case we get a CNAME, we store the target
  359. // here (classify() will set it when it walks through
  360. // the cname chain to verify it).
  361. Name cname_target(question_.getName());
  362. isc::resolve::ResponseClassifier::Category category =
  363. isc::resolve::ResponseClassifier::classify(
  364. question_, incoming, cname_target, cname_count_);
  365. bool found_ns = false;
  366. switch (category) {
  367. case isc::resolve::ResponseClassifier::ANSWER:
  368. case isc::resolve::ResponseClassifier::ANSWERCNAME:
  369. // Answer received - copy and return.
  370. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_ANSWER)
  371. .arg(questionText(question_));
  372. isc::resolve::copyResponseMessage(incoming, answer_message_);
  373. cache_.update(*answer_message_);
  374. return (true);
  375. break;
  376. case isc::resolve::ResponseClassifier::CNAME:
  377. // CNAME received.
  378. // (unfinished) CNAME. We set our question_ to the CNAME
  379. // target, then start over at the beginning (for now, that
  380. // is, we reset our 'current servers' to the root servers).
  381. if (cname_count_ >= RESOLVER_MAX_CNAME_CHAIN) {
  382. // CNAME chain too long - just give up
  383. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_LONG_CHAIN)
  384. .arg(questionText(question_));
  385. makeSERVFAIL();
  386. return (true);
  387. }
  388. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_CNAME)
  389. .arg(questionText(question_));
  390. answer_message_->appendSection(Message::SECTION_ANSWER,
  391. incoming);
  392. question_ = Question(cname_target, question_.getClass(),
  393. question_.getType());
  394. // Follow CNAME chain.
  395. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_FOLLOW_CNAME)
  396. .arg(questionText(question_));
  397. doLookup();
  398. return (false);
  399. break;
  400. case isc::resolve::ResponseClassifier::NXDOMAIN:
  401. case isc::resolve::ResponseClassifier::NXRRSET:
  402. // Received NXDOMAIN or NXRRSET, just copy and return
  403. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_NXDOM_NXRR)
  404. .arg(questionText(question_));
  405. isc::resolve::copyResponseMessage(incoming, answer_message_);
  406. // no negcache yet
  407. //cache_.update(*answer_message_);
  408. return (true);
  409. break;
  410. case isc::resolve::ResponseClassifier::REFERRAL:
  411. // Response is a referral
  412. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_REFERRAL)
  413. .arg(questionText(question_));
  414. cache_.update(incoming);
  415. // Referral. For now we just take the first glue address
  416. // we find and continue with that
  417. // auth section should have at least one RRset
  418. // and one of them should be an NS (otherwise
  419. // classifier should have error'd) to a subdomain
  420. for (RRsetIterator rrsi = incoming.beginSection(Message::SECTION_AUTHORITY);
  421. rrsi != incoming.endSection(Message::SECTION_AUTHORITY) && !found_ns;
  422. ++rrsi) {
  423. ConstRRsetPtr rrs = *rrsi;
  424. if (rrs->getType() == RRType::NS()) {
  425. NameComparisonResult compare(Name(cur_zone_).compare(rrs->getName()));
  426. if (compare.getRelation() == NameComparisonResult::SUPERDOMAIN) {
  427. // TODO: make cur_zone_ a Name instead of a string
  428. // (this requires a few API changes in related
  429. // libraries, so as not to need many conversions)
  430. cur_zone_ = rrs->getName().toText();
  431. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_REFER_ZONE)
  432. .arg(cur_zone_);
  433. found_ns = true;
  434. break;
  435. }
  436. }
  437. }
  438. if (found_ns) {
  439. // next resolver round
  440. // we do NOT use doLookup() here, but send() (i.e. we
  441. // skip the cache), since if we had the final answer
  442. // instead of a delegation cached, we would have been
  443. // there by now.
  444. GlueHints glue_hints(cur_zone_, incoming);
  445. // Ask the NSAS for an address, or glue.
  446. // This will eventually result in either sendTo()
  447. // or stop() being called by nsas_callback_
  448. assert(!nsas_callback_out_);
  449. nsas_callback_out_ = true;
  450. nsas_.lookup(cur_zone_, question_.getClass(),
  451. nsas_callback_, ANY_OK, glue_hints);
  452. return (false);
  453. } else {
  454. // Referral was received but did not contain an NS RRset.
  455. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_NO_NS_RRSET)
  456. .arg(questionText(question_));
  457. // TODO this will result in answering with the delegation. oh well
  458. isc::resolve::copyResponseMessage(incoming, answer_message_);
  459. return (true);
  460. }
  461. break;
  462. case isc::resolve::ResponseClassifier::TRUNCATED:
  463. // Truncated packet. If the protocol we used for the last one is
  464. // UDP, re-query using TCP. Otherwise regard it as an error.
  465. if (protocol_ == IOFetch::UDP) {
  466. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS,
  467. RESLIB_TRUNCATED).arg(questionText(question_));
  468. send(IOFetch::TCP);
  469. return (false);
  470. }
  471. // Was a TCP query so we have received a packet over TCP with the
  472. // TC bit set: report an error by going to the common
  473. // error code.
  474. goto SERVFAIL;
  475. case isc::resolve::ResponseClassifier::RCODE:
  476. // see if it's a FORMERR and a potential EDNS problem
  477. if (incoming.getRcode() == Rcode::FORMERR()) {
  478. if (protocol_ == IOFetch::UDP && edns_) {
  479. // TODO: in case we absolutely need EDNS (i.e. for DNSSEC
  480. // aware queries), we might want to try TCP before we give
  481. // up. For now, just try UDP, no EDNS
  482. send(IOFetch::UDP, false);
  483. return (false);
  484. }
  485. // TC should take care of non-EDNS over UDP, fall through to
  486. // SERVFAIL if we get FORMERR instead
  487. }
  488. goto SERVFAIL;
  489. default:
  490. SERVFAIL:
  491. // Some error in received packet it. Report it and return SERVFAIL
  492. // to the caller.
  493. if (logger.isDebugEnabled()) {
  494. reportResponseClassifierError(category, incoming.getRcode());
  495. }
  496. makeSERVFAIL();
  497. return (true);
  498. }
  499. // If we get here, there is some serious logic error (or a missing
  500. // "return").
  501. assert(false);
  502. return (true); // To keep the compiler happy
  503. }
  504. /// \brief Report classification-detected error
  505. ///
  506. /// When the response classifier has detected an error in the response from
  507. /// an upstream query, this method is called to log a debug message giving
  508. /// information about the problem.
  509. ///
  510. /// \param category Classification code for the packet
  511. /// \param rcode RCODE value in the packet
  512. void reportResponseClassifierError(ResponseClassifier::Category category,
  513. const Rcode& rcode)
  514. {
  515. // We could set up a table of response classifications to message
  516. // IDs here and index into that table. But given that (a) C++ does
  517. // not have C's named initializers, (b) the codes for the
  518. // response classifier are in another module and (c) not all messages
  519. // have the same number of arguments, the setup of the table would be
  520. // almost as long as the code here: it would need to include a number
  521. // of assertions to ensure that any change to the the response
  522. // classifier codes was detected, and the checking logic would need to
  523. // check that the numeric value of the code lay within the defined
  524. // limits of the table.
  525. if (category == ResponseClassifier::RCODE) {
  526. // Special case as this message takes two arguments.
  527. LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_RETURNED).
  528. arg(questionText(question_)).arg(rcode);
  529. } else {
  530. isc::log::MessageID message_id;
  531. switch (category) {
  532. case ResponseClassifier::TRUNCATED:
  533. message_id = RESLIB_TCP_TRUNCATED;
  534. break;
  535. case ResponseClassifier::EMPTY:
  536. message_id = RESLIB_EMPTY_RESPONSE;
  537. break;
  538. case ResponseClassifier::EXTRADATA:
  539. message_id = RESLIB_EXTRADATA_RESPONSE;
  540. break;
  541. case ResponseClassifier::INVNAMCLASS:
  542. message_id = RESLIB_INVALID_NAMECLASS_RESPONSE;
  543. break;
  544. case ResponseClassifier::INVTYPE:
  545. message_id = RESLIB_INVALID_TYPE_RESPONSE;
  546. break;
  547. case ResponseClassifier::MISMATQUEST:
  548. message_id = RESLIB_INVALID_QNAME_RESPONSE;
  549. break;
  550. case ResponseClassifier::MULTICLASS:
  551. message_id = RESLIB_MULTIPLE_CLASS_RESPONSE;
  552. break;
  553. case ResponseClassifier::NOTONEQUEST:
  554. message_id = RESLIB_NOT_ONE_QNAME_RESPONSE;
  555. break;
  556. case ResponseClassifier::NOTRESPONSE:
  557. message_id = RESLIB_NOT_RESPONSE;
  558. break;
  559. case ResponseClassifier::NOTSINGLE:
  560. message_id = RESLIB_NOTSINGLE_RESPONSE;
  561. break;
  562. case ResponseClassifier::OPCODE:
  563. message_id = RESLIB_OPCODE_RESPONSE;
  564. break;
  565. default:
  566. message_id = RESLIB_ERROR_RESPONSE;
  567. break;
  568. }
  569. LOG_DEBUG(logger, RESLIB_DBG_RESULTS, message_id).
  570. arg(questionText(question_));
  571. }
  572. }
  573. public:
  574. RunningQuery(IOService& io,
  575. const Question& question,
  576. MessagePtr answer_message,
  577. std::pair<std::string, uint16_t>& test_server,
  578. OutputBufferPtr buffer,
  579. isc::resolve::ResolverInterface::CallbackPtr cb,
  580. int query_timeout, int client_timeout, int lookup_timeout,
  581. unsigned retries,
  582. isc::nsas::NameserverAddressStore& nsas,
  583. isc::cache::ResolverCache& cache,
  584. boost::shared_ptr<RttRecorder>& recorder)
  585. :
  586. io_(io),
  587. question_(question),
  588. query_message_(),
  589. answer_message_(answer_message),
  590. test_server_(test_server),
  591. buffer_(buffer),
  592. resolvercallback_(cb),
  593. protocol_(IOFetch::UDP),
  594. cname_count_(0),
  595. query_timeout_(query_timeout),
  596. retries_(retries),
  597. client_timer(io.get_io_service()),
  598. lookup_timer(io.get_io_service()),
  599. done_(false),
  600. callback_called_(false),
  601. nsas_(nsas),
  602. cache_(cache),
  603. cur_zone_("."),
  604. nsas_callback_(),
  605. nsas_callback_out_(false),
  606. outstanding_events_(0),
  607. rtt_recorder_(recorder)
  608. {
  609. // Set here to avoid using "this" in initializer list.
  610. nsas_callback_.reset(new ResolverNSASCallback(this));
  611. // Setup the timer to stop trying (lookup_timeout)
  612. if (lookup_timeout >= 0) {
  613. lookup_timer.expires_from_now(
  614. boost::posix_time::milliseconds(lookup_timeout));
  615. ++outstanding_events_;
  616. lookup_timer.async_wait(boost::bind(&RunningQuery::lookupTimeout, this));
  617. }
  618. // Setup the timer to send an answer (client_timeout)
  619. if (client_timeout >= 0) {
  620. client_timer.expires_from_now(
  621. boost::posix_time::milliseconds(client_timeout));
  622. ++outstanding_events_;
  623. client_timer.async_wait(boost::bind(&RunningQuery::clientTimeout, this));
  624. }
  625. doLookup();
  626. }
  627. virtual ~RunningQuery() {};
  628. // called if we have a lookup timeout; if our callback has
  629. // not been called, call it now. Then stop.
  630. void lookupTimeout() {
  631. if (!callback_called_) {
  632. makeSERVFAIL();
  633. callCallback(true);
  634. }
  635. assert(outstanding_events_ > 0);
  636. --outstanding_events_;
  637. stop();
  638. }
  639. // called if we have a client timeout; if our callback has
  640. // not been called, call it now. But do not stop.
  641. void clientTimeout() {
  642. if (!callback_called_) {
  643. makeSERVFAIL();
  644. callCallback(true);
  645. }
  646. assert(outstanding_events_ > 0);
  647. --outstanding_events_;
  648. if (outstanding_events_ == 0) {
  649. stop();
  650. }
  651. }
  652. // If the callback has not been called yet, call it now
  653. // If success is true, we call 'success' with our answer_message
  654. // If it is false, we call failure()
  655. void callCallback(bool success) {
  656. if (!callback_called_) {
  657. callback_called_ = true;
  658. // There are two types of messages we could store in the
  659. // cache;
  660. // 1. answers to our fetches from authoritative servers,
  661. // exactly as we receive them, and
  662. // 2. answers to queries we received from clients, which
  663. // have received additional processing (following CNAME
  664. // chains, for instance)
  665. //
  666. // Doing only the first would mean we would have to re-do
  667. // processing when we get data from our cache, and doing
  668. // only the second would miss out on the side-effect of
  669. // having nameserver data in our cache.
  670. //
  671. // So right now we do both. Since the cache (currently)
  672. // stores Messages on their question section only, this
  673. // does mean that we overwrite the messages we stored in
  674. // the previous iteration if we are following a delegation.
  675. if (success) {
  676. resolvercallback_->success(answer_message_);
  677. } else {
  678. resolvercallback_->failure();
  679. }
  680. }
  681. }
  682. // We are done. If there are no more outstanding events, we delete
  683. // ourselves. If there are any, we do not.
  684. void stop() {
  685. done_ = true;
  686. if (nsas_callback_out_) {
  687. nsas_.cancel(cur_zone_, question_.getClass(), nsas_callback_);
  688. nsas_callback_out_ = false;
  689. }
  690. client_timer.cancel();
  691. lookup_timer.cancel();
  692. if (outstanding_events_ > 0) {
  693. return;
  694. } else {
  695. delete this;
  696. }
  697. }
  698. // This function is used as callback from DNSQuery.
  699. virtual void operator()(IOFetch::Result result) {
  700. // XXX is this the place for TCP retry?
  701. assert(outstanding_events_ > 0);
  702. --outstanding_events_;
  703. if (!done_ && result != IOFetch::TIME_OUT) {
  704. // we got an answer
  705. // Update the NSAS with the time it took
  706. struct timeval cur_time;
  707. gettimeofday(&cur_time, NULL);
  708. uint32_t rtt = 0;
  709. // Only calculate RTT if it is positive
  710. if (cur_time.tv_sec > current_ns_qsent_time.tv_sec ||
  711. (cur_time.tv_sec == current_ns_qsent_time.tv_sec &&
  712. cur_time.tv_usec > current_ns_qsent_time.tv_usec)) {
  713. rtt = 1000 * (cur_time.tv_sec - current_ns_qsent_time.tv_sec);
  714. rtt += (cur_time.tv_usec - current_ns_qsent_time.tv_usec) / 1000;
  715. }
  716. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_RTT).arg(rtt);
  717. current_ns_address.updateRTT(rtt);
  718. if (rtt_recorder_) {
  719. rtt_recorder_->addRtt(rtt);
  720. }
  721. try {
  722. Message incoming(Message::PARSE);
  723. InputBuffer ibuf(buffer_->getData(), buffer_->getLength());
  724. incoming.fromWire(ibuf);
  725. buffer_->clear();
  726. done_ = handleRecursiveAnswer(incoming);
  727. if (done_) {
  728. callCallback(true);
  729. stop();
  730. }
  731. } catch (const isc::dns::DNSProtocolError& dpe) {
  732. // Right now, we treat this similar to timeouts
  733. // (except we don't store RTT)
  734. // We probably want to make this an integral part
  735. // of the fetch data process. (TODO)
  736. if (retries_--) {
  737. // Retry
  738. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS,
  739. RESLIB_PROTOCOL_RETRY)
  740. .arg(questionText(question_)).arg(dpe.what())
  741. .arg(retries_);
  742. send();
  743. } else {
  744. // Give up
  745. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS,
  746. RESLIB_PROTOCOL)
  747. .arg(questionText(question_)).arg(dpe.what());
  748. if (!callback_called_) {
  749. makeSERVFAIL();
  750. callCallback(true);
  751. }
  752. stop();
  753. }
  754. }
  755. } else if (!done_ && retries_--) {
  756. // Query timed out, but we have some retries, so send again
  757. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_TIMEOUT_RETRY)
  758. .arg(questionText(question_))
  759. .arg(current_ns_address.getAddress().toText()).arg(retries_);
  760. current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
  761. send();
  762. } else {
  763. // We are either already done, or out of retries
  764. if (result == IOFetch::TIME_OUT) {
  765. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_TIMEOUT)
  766. .arg(questionText(question_))
  767. .arg(current_ns_address.getAddress().toText());
  768. current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
  769. }
  770. if (!callback_called_) {
  771. makeSERVFAIL();
  772. callCallback(true);
  773. }
  774. stop();
  775. }
  776. }
  777. // Clear the answer parts of answer_message, and set the rcode
  778. // to servfail
  779. void makeSERVFAIL() {
  780. if (answer_message_) {
  781. isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
  782. }
  783. }
  784. };
  785. class ForwardQuery : public IOFetch::Callback, public AbstractRunningQuery {
  786. private:
  787. // The io service to handle async calls
  788. IOService& io_;
  789. // This is the query message got from client
  790. ConstMessagePtr query_message_;
  791. // This is where we build and store our final answer
  792. MessagePtr answer_message_;
  793. // List of nameservers to forward to
  794. boost::shared_ptr<AddressVector> upstream_;
  795. // Buffer to store the result.
  796. OutputBufferPtr buffer_;
  797. // This will be notified when we succeed or fail
  798. isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
  799. /*
  800. * TODO Do something more clever with timeouts. In the long term, some
  801. * computation of average RTT, increase with each retry, etc.
  802. */
  803. // Timeout information
  804. int query_timeout_;
  805. // TODO: replace by our wrapper
  806. asio::deadline_timer client_timer;
  807. asio::deadline_timer lookup_timer;
  808. // Make ForwardQuery deletes itself safely. for more information see
  809. // the comments of outstanding_events in RunningQuery.
  810. size_t outstanding_events_;
  811. // If we have a client timeout, we call back with a failure message,
  812. // but we do not stop yet. We use this variable to make sure we
  813. // don't call back a second time later
  814. bool callback_called_;
  815. // send the query to the server.
  816. void send(IOFetch::Protocol protocol = IOFetch::UDP) {
  817. const int uc = upstream_->size();
  818. buffer_->clear();
  819. int serverIndex = rand() % uc;
  820. ConstQuestionPtr question = *(query_message_->beginQuestion());
  821. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_UPSTREAM)
  822. .arg(questionText(*question))
  823. .arg(upstream_->at(serverIndex).first);
  824. ++outstanding_events_;
  825. // Forward the query, create the IOFetch with
  826. // query message, so that query flags can be forwarded
  827. // together.
  828. IOFetch query(protocol, io_, query_message_,
  829. upstream_->at(serverIndex).first,
  830. upstream_->at(serverIndex).second,
  831. buffer_, this, query_timeout_);
  832. io_.get_io_service().post(query);
  833. }
  834. public:
  835. ForwardQuery(IOService& io,
  836. ConstMessagePtr query_message,
  837. MessagePtr answer_message,
  838. boost::shared_ptr<AddressVector> upstream,
  839. OutputBufferPtr buffer,
  840. isc::resolve::ResolverInterface::CallbackPtr cb,
  841. int query_timeout, int client_timeout, int lookup_timeout) :
  842. io_(io),
  843. query_message_(query_message),
  844. answer_message_(answer_message),
  845. upstream_(upstream),
  846. buffer_(buffer),
  847. resolvercallback_(cb),
  848. query_timeout_(query_timeout),
  849. client_timer(io.get_io_service()),
  850. lookup_timer(io.get_io_service()),
  851. outstanding_events_(0),
  852. callback_called_(false)
  853. {
  854. // Setup the timer to stop trying (lookup_timeout)
  855. if (lookup_timeout >= 0) {
  856. lookup_timer.expires_from_now(
  857. boost::posix_time::milliseconds(lookup_timeout));
  858. ++outstanding_events_;
  859. lookup_timer.async_wait(boost::bind(&ForwardQuery::lookupTimeout, this));
  860. }
  861. // Setup the timer to send an answer (client_timeout)
  862. if (client_timeout >= 0) {
  863. client_timer.expires_from_now(
  864. boost::posix_time::milliseconds(client_timeout));
  865. ++outstanding_events_;
  866. client_timer.async_wait(boost::bind(&ForwardQuery::clientTimeout, this));
  867. }
  868. send();
  869. }
  870. virtual ~ForwardQuery() {};
  871. virtual void lookupTimeout() {
  872. if (!callback_called_) {
  873. makeSERVFAIL();
  874. callCallback(false);
  875. }
  876. assert(outstanding_events_ > 0);
  877. --outstanding_events_;
  878. stop();
  879. }
  880. virtual void clientTimeout() {
  881. if (!callback_called_) {
  882. makeSERVFAIL();
  883. callCallback(false);
  884. }
  885. assert(outstanding_events_ > 0);
  886. --outstanding_events_;
  887. stop();
  888. }
  889. // If the callback has not been called yet, call it now
  890. // If success is true, we call 'success' with our answer_message
  891. // If it is false, we call failure()
  892. void callCallback(bool success) {
  893. if (!callback_called_) {
  894. callback_called_ = true;
  895. if (success) {
  896. resolvercallback_->success(answer_message_);
  897. } else {
  898. resolvercallback_->failure();
  899. }
  900. }
  901. }
  902. virtual void stop() {
  903. // if we cancel our timers, we will still get an event for
  904. // that, so we cannot delete ourselves just yet (those events
  905. // would be bound to a deleted object)
  906. // cancel them one by one, both cancels should get us back
  907. // here again.
  908. // same goes if we have an outstanding query (can't delete
  909. // until that one comes back to us)
  910. lookup_timer.cancel();
  911. client_timer.cancel();
  912. if (outstanding_events_ > 0) {
  913. return;
  914. } else {
  915. delete this;
  916. }
  917. }
  918. // This function is used as callback from DNSQuery.
  919. virtual void operator()(IOFetch::Result result) {
  920. // XXX is this the place for TCP retry?
  921. assert(outstanding_events_ > 0);
  922. --outstanding_events_;
  923. if (result != IOFetch::TIME_OUT) {
  924. // we got an answer
  925. Message incoming(Message::PARSE);
  926. InputBuffer ibuf(buffer_->getData(), buffer_->getLength());
  927. incoming.fromWire(ibuf);
  928. isc::resolve::copyResponseMessage(incoming, answer_message_);
  929. callCallback(true);
  930. }
  931. stop();
  932. }
  933. // Clear the answer parts of answer_message, and set the rcode
  934. // to servfail
  935. void makeSERVFAIL() {
  936. isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
  937. }
  938. };
  939. }
  940. AbstractRunningQuery*
  941. RecursiveQuery::resolve(const QuestionPtr& question,
  942. const isc::resolve::ResolverInterface::CallbackPtr callback)
  943. {
  944. IOService& io = dns_service_.getIOService();
  945. MessagePtr answer_message(new Message(Message::RENDER));
  946. isc::resolve::initResponseMessage(*question, *answer_message);
  947. OutputBufferPtr buffer(new OutputBuffer(0));
  948. // First try to see if we have something cached in the messagecache
  949. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RESOLVE)
  950. .arg(questionText(*question)).arg(1);
  951. if (cache_.lookup(question->getName(), question->getType(),
  952. question->getClass(), *answer_message) &&
  953. answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
  954. // Message found, return that
  955. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RECQ_CACHE_FIND)
  956. .arg(questionText(*question)).arg(1);
  957. // TODO: err, should cache set rcode as well?
  958. answer_message->setRcode(Rcode::NOERROR());
  959. callback->success(answer_message);
  960. } else {
  961. // Perhaps we only have the one RRset?
  962. // TODO: can we do this? should we check for specific types only?
  963. RRsetPtr cached_rrset = cache_.lookup(question->getName(),
  964. question->getType(),
  965. question->getClass());
  966. if (cached_rrset) {
  967. // Found single RRset in cache
  968. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RRSET_FOUND)
  969. .arg(questionText(*question)).arg(1);
  970. answer_message->addRRset(Message::SECTION_ANSWER,
  971. cached_rrset);
  972. answer_message->setRcode(Rcode::NOERROR());
  973. callback->success(answer_message);
  974. } else {
  975. // Message not found in cache, start recursive query. It will
  976. // delete itself when it is done
  977. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
  978. .arg(questionText(*question)).arg(1);
  979. return (new RunningQuery(io, *question, answer_message,
  980. test_server_, buffer, callback,
  981. query_timeout_, client_timeout_,
  982. lookup_timeout_, retries_, nsas_,
  983. cache_, rtt_recorder_));
  984. }
  985. }
  986. return (NULL);
  987. }
  988. AbstractRunningQuery*
  989. RecursiveQuery::resolve(const Question& question,
  990. MessagePtr answer_message,
  991. OutputBufferPtr buffer,
  992. DNSServer* server)
  993. {
  994. // XXX: eventually we will need to be able to determine whether
  995. // the message should be sent via TCP or UDP, or sent initially via
  996. // UDP and then fall back to TCP on failure, but for the moment
  997. // we're only going to handle UDP.
  998. IOService& io = dns_service_.getIOService();
  999. isc::resolve::ResolverInterface::CallbackPtr crs(
  1000. new isc::resolve::ResolverCallbackServer(server));
  1001. // TODO: general 'prepareinitialanswer'
  1002. answer_message->setOpcode(isc::dns::Opcode::QUERY());
  1003. answer_message->addQuestion(question);
  1004. // First try to see if we have something cached in the messagecache
  1005. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RESOLVE)
  1006. .arg(questionText(question)).arg(2);
  1007. if (cache_.lookup(question.getName(), question.getType(),
  1008. question.getClass(), *answer_message) &&
  1009. answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
  1010. // Message found, return that
  1011. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RECQ_CACHE_FIND)
  1012. .arg(questionText(question)).arg(2);
  1013. // TODO: err, should cache set rcode as well?
  1014. answer_message->setRcode(Rcode::NOERROR());
  1015. crs->success(answer_message);
  1016. } else {
  1017. // Perhaps we only have the one RRset?
  1018. // TODO: can we do this? should we check for specific types only?
  1019. RRsetPtr cached_rrset = cache_.lookup(question.getName(),
  1020. question.getType(),
  1021. question.getClass());
  1022. if (cached_rrset) {
  1023. // Found single RRset in cache
  1024. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RRSET_FOUND)
  1025. .arg(questionText(question)).arg(2);
  1026. answer_message->addRRset(Message::SECTION_ANSWER,
  1027. cached_rrset);
  1028. answer_message->setRcode(Rcode::NOERROR());
  1029. crs->success(answer_message);
  1030. } else {
  1031. // Message not found in cache, start recursive query. It will
  1032. // delete itself when it is done
  1033. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
  1034. .arg(questionText(question)).arg(2);
  1035. return (new RunningQuery(io, question, answer_message,
  1036. test_server_, buffer, crs, query_timeout_,
  1037. client_timeout_, lookup_timeout_, retries_,
  1038. nsas_, cache_, rtt_recorder_));
  1039. }
  1040. }
  1041. return (NULL);
  1042. }
  1043. AbstractRunningQuery*
  1044. RecursiveQuery::forward(ConstMessagePtr query_message,
  1045. MessagePtr answer_message,
  1046. OutputBufferPtr buffer,
  1047. DNSServer* server,
  1048. isc::resolve::ResolverInterface::CallbackPtr callback)
  1049. {
  1050. // XXX: eventually we will need to be able to determine whether
  1051. // the message should be sent via TCP or UDP, or sent initially via
  1052. // UDP and then fall back to TCP on failure, but for the moment
  1053. // we're only going to handle UDP.
  1054. IOService& io = dns_service_.getIOService();
  1055. if (!callback) {
  1056. callback.reset(new isc::resolve::ResolverCallbackServer(server));
  1057. }
  1058. // TODO: general 'prepareinitialanswer'
  1059. answer_message->setOpcode(isc::dns::Opcode::QUERY());
  1060. ConstQuestionPtr question = *query_message->beginQuestion();
  1061. answer_message->addQuestion(*question);
  1062. // implement the simplest forwarder, which will pass
  1063. // everything throught without interpretation, except
  1064. // QID, port number. The response will not be cached.
  1065. // It will delete itself when it is done
  1066. return (new ForwardQuery(io, query_message, answer_message,
  1067. upstream_, buffer, callback, query_timeout_,
  1068. client_timeout_, lookup_timeout_));
  1069. }
  1070. } // namespace asiodns
  1071. } // namespace isc