recursive_query.cc 47 KB

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