recursive_query.cc 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  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. // Here we do not use the typedef above, as the SunStudio compiler
  114. // mishandles this in its name mangling, and wouldn't compile.
  115. // We can probably use a typedef, but need to move it to a central
  116. // location and use it consistently.
  117. RecursiveQuery::RecursiveQuery(DNSServiceBase& dns_service,
  118. isc::nsas::NameserverAddressStore& nsas,
  119. isc::cache::ResolverCache& cache,
  120. const std::vector<std::pair<std::string, uint16_t> >& upstream,
  121. const std::vector<std::pair<std::string, uint16_t> >& upstream_root,
  122. int query_timeout, int client_timeout, int lookup_timeout,
  123. unsigned retries)
  124. :
  125. dns_service_(dns_service),
  126. nsas_(nsas), cache_(cache),
  127. upstream_(new AddressVector(upstream)),
  128. upstream_root_(new AddressVector(upstream_root)),
  129. test_server_("", 0),
  130. query_timeout_(query_timeout), client_timeout_(client_timeout),
  131. lookup_timeout_(lookup_timeout), retries_(retries), rtt_recorder_()
  132. {
  133. }
  134. // Set the test server - only used for unit testing.
  135. void
  136. RecursiveQuery::setTestServer(const std::string& address, uint16_t port) {
  137. LOG_WARN(isc::resolve::logger, RESLIB_TEST_SERVER).arg(address).arg(port);
  138. test_server_.first = address;
  139. test_server_.second = port;
  140. }
  141. // Set the RTT recorder - only used for testing
  142. void
  143. RecursiveQuery::setRttRecorder(boost::shared_ptr<RttRecorder>& recorder) {
  144. rtt_recorder_ = recorder;
  145. }
  146. namespace {
  147. typedef std::pair<std::string, uint16_t> addr_t;
  148. /*
  149. * This is a query in progress. When a new query is made, this one holds
  150. * the context information about it, like how many times we are allowed
  151. * to retry on failure, what to do when we succeed, etc.
  152. *
  153. * Used by RecursiveQuery::sendQuery.
  154. */
  155. class RunningQuery : public IOFetch::Callback, public AbstractRunningQuery {
  156. class ResolverNSASCallback : public isc::nsas::AddressRequestCallback {
  157. public:
  158. ResolverNSASCallback(RunningQuery* rq) : rq_(rq) {}
  159. void success(const isc::nsas::NameserverAddress& address) {
  160. // Success callback, send query to found namesever
  161. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CB, RESLIB_RUNQ_SUCCESS)
  162. .arg(address.getAddress().toText());
  163. rq_->nsasCallbackCalled();
  164. rq_->sendTo(address);
  165. }
  166. void unreachable() {
  167. // Nameservers unreachable: drop query or send servfail?
  168. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CB, RESLIB_RUNQ_FAIL);
  169. rq_->nsasCallbackCalled();
  170. rq_->makeSERVFAIL();
  171. rq_->callCallback(true);
  172. rq_->stop();
  173. }
  174. private:
  175. RunningQuery* rq_;
  176. };
  177. private:
  178. // The io service to handle async calls
  179. IOService& io_;
  180. // Info for (re)sending the query (the question and destination)
  181. Question question_;
  182. // This is the query message got from client
  183. ConstMessagePtr query_message_;
  184. // This is where we build and store our final answer
  185. MessagePtr answer_message_;
  186. // Test server - only used for testing. This takes precedence over all
  187. // other servers if the port is non-zero.
  188. std::pair<std::string, uint16_t> test_server_;
  189. // Buffer to store the intermediate results.
  190. OutputBufferPtr buffer_;
  191. // The callback will be called when we have either decided we
  192. // are done, or when we give up
  193. isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
  194. // Protocol used for the last query. This is set to IOFetch::UDP when a
  195. // new upstream query is initiated, and changed to IOFetch::TCP if a
  196. // packet is returned with the TC bit set. It is stored here to detect the
  197. // case of a TCP packet being returned with the TC bit set.
  198. IOFetch::Protocol protocol_;
  199. // EDNS flag
  200. bool edns_;
  201. // To prevent both unreasonably long cname chains and cname loops,
  202. // we simply keep a counter of the number of CNAMEs we have
  203. // followed so far (and error if it exceeds RESOLVER_MAX_CNAME_CHAIN
  204. // from lib/resolve/response_classifier.h)
  205. unsigned cname_count_;
  206. /*
  207. * TODO Do something more clever with timeouts. In the long term, some
  208. * computation of average RTT, increase with each retry, etc.
  209. */
  210. // Timeout information for outgoing queries
  211. int query_timeout_;
  212. unsigned retries_;
  213. // normal query state
  214. // Update the question that will be sent to the server
  215. void setQuestion(const Question& new_question) {
  216. question_ = new_question;
  217. }
  218. // TODO: replace by our wrapper
  219. asio::deadline_timer client_timer;
  220. asio::deadline_timer lookup_timer;
  221. // If we timed out ourselves (lookup timeout), stop issuing queries
  222. bool done_;
  223. // If we have a client timeout, we call back with a failure message,
  224. // but we do not stop yet. We use this variable to make sure we
  225. // don't call back a second time later
  226. bool callback_called_;
  227. // Reference to our NSAS
  228. isc::nsas::NameserverAddressStore& nsas_;
  229. // Reference to our cache
  230. isc::cache::ResolverCache& cache_;
  231. // the 'current' zone we are in (i.e.) we start out at the root,
  232. // and for each delegation this gets updated with the zone the
  233. // delegation points to.
  234. // TODO: make this a Name (it is a string right now because most
  235. // of the call we use it in take a string, we need update those
  236. // too).
  237. std::string cur_zone_;
  238. // This is the handler we pass on to the NSAS; it is called when
  239. // the NSAS has an address for us to query
  240. boost::shared_ptr<ResolverNSASCallback> nsas_callback_;
  241. // this is set to true if we have asked the nsas to give us
  242. // an address and we are waiting for it to call us back.
  243. // We use is to cancel the outstanding callback in case we
  244. // have a lookup timeout and decide to give up
  245. bool nsas_callback_out_;
  246. // This is the nameserver we have an outstanding query to.
  247. // It is used to update the RTT once the query returns
  248. isc::nsas::NameserverAddress current_ns_address;
  249. // The moment in time we sent a query to the nameserver above.
  250. struct timeval current_ns_qsent_time;
  251. // RunningQuery deletes itself when it is done. In order for us
  252. // to do this safely, we must make sure that there are no events
  253. // that might call back to it. There are two types of events in
  254. // this sense; the timers we set ourselves (lookup and client),
  255. // and outstanding queries to nameservers. When each of these is
  256. // started, we increase this value. When they fire, it is decreased
  257. // again. We cannot delete ourselves until this value is back to 0.
  258. //
  259. // Note that the NSAS callback is *not* seen as an outstanding
  260. // event; we can cancel the NSAS callback safely.
  261. size_t outstanding_events_;
  262. // RTT Recorder. Used for testing, the RTTs of queries are
  263. // sent to this object as well as being used to update the NSAS.
  264. boost::shared_ptr<RttRecorder> rtt_recorder_;
  265. // perform a single lookup; first we check the cache to see
  266. // if we have a response for our query stored already. if
  267. // so, call handlerecursiveresponse(), if not, we call send()
  268. void doLookup() {
  269. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RUNQ_CACHE_LOOKUP)
  270. .arg(questionText(question_));
  271. Message cached_message(Message::RENDER);
  272. isc::resolve::initResponseMessage(question_, cached_message);
  273. if (cache_.lookup(question_.getName(), question_.getType(),
  274. question_.getClass(), cached_message)) {
  275. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RUNQ_CACHE_FIND)
  276. .arg(questionText(question_));
  277. // Should these be set by the cache too?
  278. cached_message.setOpcode(Opcode::QUERY());
  279. cached_message.setRcode(Rcode::NOERROR());
  280. cached_message.setHeaderFlag(Message::HEADERFLAG_QR);
  281. if (handleRecursiveAnswer(cached_message)) {
  282. callCallback(true);
  283. stop();
  284. }
  285. } else {
  286. cur_zone_ = deepestDelegation(question_.getName(),
  287. question_.getClass(), cache_);
  288. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_DEEPEST)
  289. .arg(questionText(question_)).arg(cur_zone_);
  290. send();
  291. }
  292. }
  293. // Send the current question to the given nameserver address
  294. void sendTo(const isc::nsas::NameserverAddress& address) {
  295. // We need to keep track of the Address, so that we can update
  296. // the RTT
  297. current_ns_address = address;
  298. gettimeofday(&current_ns_qsent_time, NULL);
  299. ++outstanding_events_;
  300. if (test_server_.second != 0) {
  301. IOFetch query(protocol_, io_, question_,
  302. test_server_.first,
  303. test_server_.second, buffer_, this,
  304. query_timeout_, edns_);
  305. io_.get_io_service().post(query);
  306. } else {
  307. IOFetch query(protocol_, io_, question_,
  308. current_ns_address.getAddress(),
  309. 53, buffer_, this,
  310. query_timeout_, edns_);
  311. io_.get_io_service().post(query);
  312. }
  313. }
  314. // 'general' send, ask the NSAS to give us an address.
  315. void send(IOFetch::Protocol protocol = IOFetch::UDP, bool edns = true) {
  316. protocol_ = protocol; // Store protocol being used for this
  317. edns_ = edns;
  318. if (test_server_.second != 0) {
  319. // Send query to test server
  320. LOG_DEBUG(isc::resolve::logger,
  321. RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM)
  322. .arg(questionText(question_)).arg(test_server_.first);
  323. gettimeofday(&current_ns_qsent_time, NULL);
  324. ++outstanding_events_;
  325. IOFetch query(protocol, io_, question_,
  326. test_server_.first,
  327. test_server_.second, buffer_, this,
  328. query_timeout_, edns_);
  329. io_.get_io_service().post(query);
  330. } else {
  331. // Ask the NSAS for an address for the current zone,
  332. // the callback will call the actual sendTo()
  333. LOG_DEBUG(isc::resolve::logger,
  334. RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP)
  335. .arg(cur_zone_);
  336. // Can we have multiple calls to nsas_out? Let's assume not
  337. // for now
  338. assert(!nsas_callback_out_);
  339. nsas_callback_out_ = true;
  340. nsas_.lookup(cur_zone_, question_.getClass(), nsas_callback_);
  341. }
  342. }
  343. // Called by our NSAS callback handler so we know we do not have
  344. // an outstanding NSAS call anymore.
  345. void nsasCallbackCalled() {
  346. nsas_callback_out_ = false;
  347. }
  348. // This function is called by operator() and lookup();
  349. // We have an answer either from a nameserver or the cache, and
  350. // we do not know yet if this is a final answer we can send back or
  351. // that more recursive processing needs to be done.
  352. // Depending on the content, we go on recursing or return
  353. //
  354. // This method also updates the cache, depending on the content
  355. // of the message
  356. //
  357. // returns true if we are done (either we have an answer or an
  358. // error message)
  359. // returns false if we are not done
  360. bool handleRecursiveAnswer(const Message& incoming) {
  361. // In case we get a CNAME, we store the target
  362. // here (classify() will set it when it walks through
  363. // the cname chain to verify it).
  364. Name cname_target(question_.getName());
  365. isc::resolve::ResponseClassifier::Category category =
  366. isc::resolve::ResponseClassifier::classify(
  367. question_, incoming, cname_target, cname_count_);
  368. bool found_ns = false;
  369. switch (category) {
  370. case isc::resolve::ResponseClassifier::ANSWER:
  371. case isc::resolve::ResponseClassifier::ANSWERCNAME:
  372. // Answer received - copy and return.
  373. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_ANSWER)
  374. .arg(questionText(question_));
  375. isc::resolve::copyResponseMessage(incoming, answer_message_);
  376. cache_.update(*answer_message_);
  377. return (true);
  378. break;
  379. case isc::resolve::ResponseClassifier::CNAME:
  380. // CNAME received.
  381. // (unfinished) CNAME. We set our question_ to the CNAME
  382. // target, then start over at the beginning (for now, that
  383. // is, we reset our 'current servers' to the root servers).
  384. if (cname_count_ >= RESOLVER_MAX_CNAME_CHAIN) {
  385. // CNAME chain too long - just give up
  386. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_LONG_CHAIN)
  387. .arg(questionText(question_));
  388. makeSERVFAIL();
  389. return (true);
  390. }
  391. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_CNAME)
  392. .arg(questionText(question_));
  393. answer_message_->appendSection(Message::SECTION_ANSWER,
  394. incoming);
  395. question_ = Question(cname_target, question_.getClass(),
  396. question_.getType());
  397. // Follow CNAME chain.
  398. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_FOLLOW_CNAME)
  399. .arg(questionText(question_));
  400. doLookup();
  401. return (false);
  402. break;
  403. case isc::resolve::ResponseClassifier::NXDOMAIN:
  404. case isc::resolve::ResponseClassifier::NXRRSET:
  405. // Received NXDOMAIN or NXRRSET, just copy and return
  406. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_NXDOM_NXRR)
  407. .arg(questionText(question_));
  408. isc::resolve::copyResponseMessage(incoming, answer_message_);
  409. // no negcache yet
  410. //cache_.update(*answer_message_);
  411. return (true);
  412. break;
  413. case isc::resolve::ResponseClassifier::REFERRAL:
  414. // Response is a referral
  415. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_REFERRAL)
  416. .arg(questionText(question_));
  417. cache_.update(incoming);
  418. // Referral. For now we just take the first glue address
  419. // we find and continue with that
  420. // auth section should have at least one RRset
  421. // and one of them should be an NS (otherwise
  422. // classifier should have error'd) to a subdomain
  423. for (RRsetIterator rrsi = incoming.beginSection(Message::SECTION_AUTHORITY);
  424. rrsi != incoming.endSection(Message::SECTION_AUTHORITY) && !found_ns;
  425. ++rrsi) {
  426. ConstRRsetPtr rrs = *rrsi;
  427. if (rrs->getType() == RRType::NS()) {
  428. NameComparisonResult compare(Name(cur_zone_).compare(rrs->getName()));
  429. if (compare.getRelation() == NameComparisonResult::SUPERDOMAIN) {
  430. // TODO: make cur_zone_ a Name instead of a string
  431. // (this requires a few API changes in related
  432. // libraries, so as not to need many conversions)
  433. cur_zone_ = rrs->getName().toText();
  434. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_REFER_ZONE)
  435. .arg(cur_zone_);
  436. found_ns = true;
  437. break;
  438. }
  439. }
  440. }
  441. if (found_ns) {
  442. // next resolver round
  443. // we do NOT use doLookup() here, but send() (i.e. we
  444. // skip the cache), since if we had the final answer
  445. // instead of a delegation cached, we would have been
  446. // there by now.
  447. GlueHints glue_hints(cur_zone_, incoming);
  448. // Ask the NSAS for an address, or glue.
  449. // This will eventually result in either sendTo()
  450. // or stop() being called by nsas_callback_
  451. assert(!nsas_callback_out_);
  452. nsas_callback_out_ = true;
  453. nsas_.lookup(cur_zone_, question_.getClass(),
  454. nsas_callback_, ANY_OK, glue_hints);
  455. return (false);
  456. } else {
  457. // Referral was received but did not contain an NS RRset.
  458. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_NO_NS_RRSET)
  459. .arg(questionText(question_));
  460. // TODO this will result in answering with the delegation. oh well
  461. isc::resolve::copyResponseMessage(incoming, answer_message_);
  462. return (true);
  463. }
  464. break;
  465. case isc::resolve::ResponseClassifier::TRUNCATED:
  466. // Truncated packet. If the protocol we used for the last one is
  467. // UDP, re-query using TCP. Otherwise regard it as an error.
  468. if (protocol_ == IOFetch::UDP) {
  469. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS,
  470. RESLIB_TRUNCATED).arg(questionText(question_));
  471. send(IOFetch::TCP);
  472. return (false);
  473. }
  474. // Was a TCP query so we have received a packet over TCP with the
  475. // TC bit set: report an error by going to the common
  476. // error code.
  477. goto SERVFAIL;
  478. case isc::resolve::ResponseClassifier::RCODE:
  479. // see if it's a FORMERR and a potential EDNS problem
  480. if (incoming.getRcode() == Rcode::FORMERR()) {
  481. if (protocol_ == IOFetch::UDP && edns_) {
  482. // TODO: in case we absolutely need EDNS (i.e. for DNSSEC
  483. // aware queries), we might want to try TCP before we give
  484. // up. For now, just try UDP, no EDNS
  485. send(IOFetch::UDP, false);
  486. return (false);
  487. }
  488. // TC should take care of non-EDNS over UDP, fall through to
  489. // SERVFAIL if we get FORMERR instead
  490. }
  491. goto SERVFAIL;
  492. default:
  493. SERVFAIL:
  494. // Some error in received packet it. Report it and return SERVFAIL
  495. // to the caller.
  496. if (logger.isDebugEnabled()) {
  497. reportResponseClassifierError(category, incoming.getRcode());
  498. }
  499. makeSERVFAIL();
  500. return (true);
  501. }
  502. // If we get here, there is some serious logic error (or a missing
  503. // "return").
  504. assert(false);
  505. return (true); // To keep the compiler happy
  506. }
  507. /// \brief Report classification-detected error
  508. ///
  509. /// When the response classifier has detected an error in the response from
  510. /// an upstream query, this method is called to log a debug message giving
  511. /// information about the problem.
  512. ///
  513. /// \param category Classification code for the packet
  514. /// \param rcode RCODE value in the packet
  515. void reportResponseClassifierError(ResponseClassifier::Category category,
  516. const Rcode& rcode)
  517. {
  518. // We could set up a table of response classifications to message
  519. // IDs here and index into that table. But given that (a) C++ does
  520. // not have C's named initializers, (b) the codes for the
  521. // response classifier are in another module and (c) not all messages
  522. // have the same number of arguments, the setup of the table would be
  523. // almost as long as the code here: it would need to include a number
  524. // of assertions to ensure that any change to the the response
  525. // classifier codes was detected, and the checking logic would need to
  526. // check that the numeric value of the code lay within the defined
  527. // limits of the table.
  528. if (category == ResponseClassifier::RCODE) {
  529. // Special case as this message takes two arguments.
  530. LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_ERROR).
  531. arg(questionText(question_)).arg(rcode);
  532. } else {
  533. isc::log::MessageID message_id;
  534. switch (category) {
  535. case ResponseClassifier::TRUNCATED:
  536. message_id = RESLIB_TCP_TRUNCATED;
  537. break;
  538. case ResponseClassifier::EMPTY:
  539. message_id = RESLIB_EMPTY_RESPONSE;
  540. break;
  541. case ResponseClassifier::EXTRADATA:
  542. message_id = RESLIB_EXTRADATA_RESPONSE;
  543. break;
  544. case ResponseClassifier::INVNAMCLASS:
  545. message_id = RESLIB_INVALID_NAMECLASS_RESPONSE;
  546. break;
  547. case ResponseClassifier::INVTYPE:
  548. message_id = RESLIB_INVALID_TYPE_RESPONSE;
  549. break;
  550. case ResponseClassifier::MISMATQUEST:
  551. message_id = RESLIB_INVALID_QNAME_RESPONSE;
  552. break;
  553. case ResponseClassifier::MULTICLASS:
  554. message_id = RESLIB_MULTIPLE_CLASS_RESPONSE;
  555. break;
  556. case ResponseClassifier::NOTONEQUEST:
  557. message_id = RESLIB_NOT_ONE_QNAME_RESPONSE;
  558. break;
  559. case ResponseClassifier::NOTRESPONSE:
  560. message_id = RESLIB_NOT_RESPONSE;
  561. break;
  562. case ResponseClassifier::NOTSINGLE:
  563. message_id = RESLIB_NOTSINGLE_RESPONSE;
  564. break;
  565. case ResponseClassifier::OPCODE:
  566. message_id = RESLIB_OPCODE_RESPONSE;
  567. break;
  568. default:
  569. message_id = RESLIB_ERROR_RESPONSE;
  570. break;
  571. }
  572. LOG_DEBUG(logger, RESLIB_DBG_RESULTS, message_id).
  573. arg(questionText(question_));
  574. }
  575. }
  576. public:
  577. RunningQuery(IOService& io,
  578. const Question& question,
  579. MessagePtr answer_message,
  580. std::pair<std::string, uint16_t>& test_server,
  581. OutputBufferPtr buffer,
  582. isc::resolve::ResolverInterface::CallbackPtr cb,
  583. int query_timeout, int client_timeout, int lookup_timeout,
  584. unsigned retries,
  585. isc::nsas::NameserverAddressStore& nsas,
  586. isc::cache::ResolverCache& cache,
  587. boost::shared_ptr<RttRecorder>& recorder)
  588. :
  589. io_(io),
  590. question_(question),
  591. query_message_(),
  592. answer_message_(answer_message),
  593. test_server_(test_server),
  594. buffer_(buffer),
  595. resolvercallback_(cb),
  596. protocol_(IOFetch::UDP),
  597. cname_count_(0),
  598. query_timeout_(query_timeout),
  599. retries_(retries),
  600. client_timer(io.get_io_service()),
  601. lookup_timer(io.get_io_service()),
  602. done_(false),
  603. callback_called_(false),
  604. nsas_(nsas),
  605. cache_(cache),
  606. cur_zone_("."),
  607. nsas_callback_(),
  608. nsas_callback_out_(false),
  609. outstanding_events_(0),
  610. rtt_recorder_(recorder)
  611. {
  612. // Set here to avoid using "this" in initializer list.
  613. nsas_callback_.reset(new ResolverNSASCallback(this));
  614. // Setup the timer to stop trying (lookup_timeout)
  615. if (lookup_timeout >= 0) {
  616. lookup_timer.expires_from_now(
  617. boost::posix_time::milliseconds(lookup_timeout));
  618. ++outstanding_events_;
  619. lookup_timer.async_wait(boost::bind(&RunningQuery::lookupTimeout, this));
  620. }
  621. // Setup the timer to send an answer (client_timeout)
  622. if (client_timeout >= 0) {
  623. client_timer.expires_from_now(
  624. boost::posix_time::milliseconds(client_timeout));
  625. ++outstanding_events_;
  626. client_timer.async_wait(boost::bind(&RunningQuery::clientTimeout, this));
  627. }
  628. doLookup();
  629. }
  630. virtual ~RunningQuery() {};
  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. if (answer_message_) {
  784. isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
  785. }
  786. }
  787. };
  788. class ForwardQuery : public IOFetch::Callback, public AbstractRunningQuery {
  789. private:
  790. // The io service to handle async calls
  791. IOService& io_;
  792. // This is the query message got from client
  793. ConstMessagePtr query_message_;
  794. // This is where we build and store our final answer
  795. MessagePtr answer_message_;
  796. // List of nameservers to forward to
  797. boost::shared_ptr<AddressVector> upstream_;
  798. // Buffer to store the result.
  799. OutputBufferPtr buffer_;
  800. // This will be notified when we succeed or fail
  801. isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
  802. /*
  803. * TODO Do something more clever with timeouts. In the long term, some
  804. * computation of average RTT, increase with each retry, etc.
  805. */
  806. // Timeout information
  807. int query_timeout_;
  808. // TODO: replace by our wrapper
  809. asio::deadline_timer client_timer;
  810. asio::deadline_timer lookup_timer;
  811. // Make FowardQuery deletes itself safely. for more information see
  812. // the comments of outstanding_events in RunningQuery.
  813. size_t outstanding_events_;
  814. // If we have a client timeout, we call back with a failure message,
  815. // but we do not stop yet. We use this variable to make sure we
  816. // don't call back a second time later
  817. bool callback_called_;
  818. // send the query to the server.
  819. void send(IOFetch::Protocol protocol = IOFetch::UDP) {
  820. const int uc = upstream_->size();
  821. buffer_->clear();
  822. int serverIndex = rand() % uc;
  823. ConstQuestionPtr question = *(query_message_->beginQuestion());
  824. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_UPSTREAM)
  825. .arg(questionText(*question))
  826. .arg(upstream_->at(serverIndex).first);
  827. ++outstanding_events_;
  828. // Forward the query, create the IOFetch with
  829. // query message, so that query flags can be forwarded
  830. // together.
  831. IOFetch query(protocol, io_, query_message_,
  832. upstream_->at(serverIndex).first,
  833. upstream_->at(serverIndex).second,
  834. buffer_, this, query_timeout_);
  835. io_.get_io_service().post(query);
  836. }
  837. public:
  838. ForwardQuery(IOService& io,
  839. ConstMessagePtr query_message,
  840. MessagePtr answer_message,
  841. boost::shared_ptr<AddressVector> upstream,
  842. OutputBufferPtr buffer,
  843. isc::resolve::ResolverInterface::CallbackPtr cb,
  844. int query_timeout, int client_timeout, int lookup_timeout) :
  845. io_(io),
  846. query_message_(query_message),
  847. answer_message_(answer_message),
  848. upstream_(upstream),
  849. buffer_(buffer),
  850. resolvercallback_(cb),
  851. query_timeout_(query_timeout),
  852. client_timer(io.get_io_service()),
  853. lookup_timer(io.get_io_service()),
  854. outstanding_events_(0),
  855. callback_called_(false)
  856. {
  857. // Setup the timer to stop trying (lookup_timeout)
  858. if (lookup_timeout >= 0) {
  859. lookup_timer.expires_from_now(
  860. boost::posix_time::milliseconds(lookup_timeout));
  861. ++outstanding_events_;
  862. lookup_timer.async_wait(boost::bind(&ForwardQuery::lookupTimeout, this));
  863. }
  864. // Setup the timer to send an answer (client_timeout)
  865. if (client_timeout >= 0) {
  866. client_timer.expires_from_now(
  867. boost::posix_time::milliseconds(client_timeout));
  868. ++outstanding_events_;
  869. client_timer.async_wait(boost::bind(&ForwardQuery::clientTimeout, this));
  870. }
  871. send();
  872. }
  873. virtual ~ForwardQuery() {};
  874. virtual void lookupTimeout() {
  875. if (!callback_called_) {
  876. makeSERVFAIL();
  877. callCallback(false);
  878. }
  879. assert(outstanding_events_ > 0);
  880. --outstanding_events_;
  881. stop();
  882. }
  883. virtual void clientTimeout() {
  884. if (!callback_called_) {
  885. makeSERVFAIL();
  886. callCallback(false);
  887. }
  888. assert(outstanding_events_ > 0);
  889. --outstanding_events_;
  890. stop();
  891. }
  892. // If the callback has not been called yet, call it now
  893. // If success is true, we call 'success' with our answer_message
  894. // If it is false, we call failure()
  895. void callCallback(bool success) {
  896. if (!callback_called_) {
  897. callback_called_ = true;
  898. if (success) {
  899. resolvercallback_->success(answer_message_);
  900. } else {
  901. resolvercallback_->failure();
  902. }
  903. }
  904. }
  905. virtual void stop() {
  906. // if we cancel our timers, we will still get an event for
  907. // that, so we cannot delete ourselves just yet (those events
  908. // would be bound to a deleted object)
  909. // cancel them one by one, both cancels should get us back
  910. // here again.
  911. // same goes if we have an outstanding query (can't delete
  912. // until that one comes back to us)
  913. lookup_timer.cancel();
  914. client_timer.cancel();
  915. if (outstanding_events_ > 0) {
  916. return;
  917. } else {
  918. delete this;
  919. }
  920. }
  921. // This function is used as callback from DNSQuery.
  922. virtual void operator()(IOFetch::Result result) {
  923. // XXX is this the place for TCP retry?
  924. assert(outstanding_events_ > 0);
  925. --outstanding_events_;
  926. if (result != IOFetch::TIME_OUT) {
  927. // we got an answer
  928. Message incoming(Message::PARSE);
  929. InputBuffer ibuf(buffer_->getData(), buffer_->getLength());
  930. incoming.fromWire(ibuf);
  931. isc::resolve::copyResponseMessage(incoming, answer_message_);
  932. callCallback(true);
  933. }
  934. stop();
  935. }
  936. // Clear the answer parts of answer_message, and set the rcode
  937. // to servfail
  938. void makeSERVFAIL() {
  939. isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
  940. }
  941. };
  942. }
  943. AbstractRunningQuery*
  944. RecursiveQuery::resolve(const QuestionPtr& question,
  945. const isc::resolve::ResolverInterface::CallbackPtr callback)
  946. {
  947. IOService& io = dns_service_.getIOService();
  948. MessagePtr answer_message(new Message(Message::RENDER));
  949. isc::resolve::initResponseMessage(*question, *answer_message);
  950. OutputBufferPtr buffer(new OutputBuffer(0));
  951. // First try to see if we have something cached in the messagecache
  952. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RESOLVE)
  953. .arg(questionText(*question)).arg(1);
  954. if (cache_.lookup(question->getName(), question->getType(),
  955. question->getClass(), *answer_message) &&
  956. answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
  957. // Message found, return that
  958. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RECQ_CACHE_FIND)
  959. .arg(questionText(*question)).arg(1);
  960. // TODO: err, should cache set rcode as well?
  961. answer_message->setRcode(Rcode::NOERROR());
  962. callback->success(answer_message);
  963. } else {
  964. // Perhaps we only have the one RRset?
  965. // TODO: can we do this? should we check for specific types only?
  966. RRsetPtr cached_rrset = cache_.lookup(question->getName(),
  967. question->getType(),
  968. question->getClass());
  969. if (cached_rrset) {
  970. // Found single RRset in cache
  971. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RRSET_FOUND)
  972. .arg(questionText(*question)).arg(1);
  973. answer_message->addRRset(Message::SECTION_ANSWER,
  974. cached_rrset);
  975. answer_message->setRcode(Rcode::NOERROR());
  976. callback->success(answer_message);
  977. } else {
  978. // Message not found in cache, start recursive query. It will
  979. // delete itself when it is done
  980. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
  981. .arg(questionText(*question)).arg(1);
  982. return (new RunningQuery(io, *question, answer_message,
  983. test_server_, buffer, callback,
  984. query_timeout_, client_timeout_,
  985. lookup_timeout_, retries_, nsas_,
  986. cache_, rtt_recorder_));
  987. }
  988. }
  989. return (NULL);
  990. }
  991. AbstractRunningQuery*
  992. RecursiveQuery::resolve(const Question& question,
  993. MessagePtr answer_message,
  994. OutputBufferPtr buffer,
  995. DNSServer* server)
  996. {
  997. // XXX: eventually we will need to be able to determine whether
  998. // the message should be sent via TCP or UDP, or sent initially via
  999. // UDP and then fall back to TCP on failure, but for the moment
  1000. // we're only going to handle UDP.
  1001. IOService& io = dns_service_.getIOService();
  1002. isc::resolve::ResolverInterface::CallbackPtr crs(
  1003. new isc::resolve::ResolverCallbackServer(server));
  1004. // TODO: general 'prepareinitialanswer'
  1005. answer_message->setOpcode(isc::dns::Opcode::QUERY());
  1006. answer_message->addQuestion(question);
  1007. // First try to see if we have something cached in the messagecache
  1008. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RESOLVE)
  1009. .arg(questionText(question)).arg(2);
  1010. if (cache_.lookup(question.getName(), question.getType(),
  1011. question.getClass(), *answer_message) &&
  1012. answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
  1013. // Message found, return that
  1014. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RECQ_CACHE_FIND)
  1015. .arg(questionText(question)).arg(2);
  1016. // TODO: err, should cache set rcode as well?
  1017. answer_message->setRcode(Rcode::NOERROR());
  1018. crs->success(answer_message);
  1019. } else {
  1020. // Perhaps we only have the one RRset?
  1021. // TODO: can we do this? should we check for specific types only?
  1022. RRsetPtr cached_rrset = cache_.lookup(question.getName(),
  1023. question.getType(),
  1024. question.getClass());
  1025. if (cached_rrset) {
  1026. // Found single RRset in cache
  1027. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RRSET_FOUND)
  1028. .arg(questionText(question)).arg(2);
  1029. answer_message->addRRset(Message::SECTION_ANSWER,
  1030. cached_rrset);
  1031. answer_message->setRcode(Rcode::NOERROR());
  1032. crs->success(answer_message);
  1033. } else {
  1034. // Message not found in cache, start recursive query. It will
  1035. // delete itself when it is done
  1036. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
  1037. .arg(questionText(question)).arg(2);
  1038. return (new RunningQuery(io, question, answer_message,
  1039. test_server_, buffer, crs, query_timeout_,
  1040. client_timeout_, lookup_timeout_, retries_,
  1041. nsas_, cache_, rtt_recorder_));
  1042. }
  1043. }
  1044. return (NULL);
  1045. }
  1046. AbstractRunningQuery*
  1047. RecursiveQuery::forward(ConstMessagePtr query_message,
  1048. MessagePtr answer_message,
  1049. OutputBufferPtr buffer,
  1050. DNSServer* server,
  1051. isc::resolve::ResolverInterface::CallbackPtr callback)
  1052. {
  1053. // XXX: eventually we will need to be able to determine whether
  1054. // the message should be sent via TCP or UDP, or sent initially via
  1055. // UDP and then fall back to TCP on failure, but for the moment
  1056. // we're only going to handle UDP.
  1057. IOService& io = dns_service_.getIOService();
  1058. if (!callback) {
  1059. callback.reset(new isc::resolve::ResolverCallbackServer(server));
  1060. }
  1061. // TODO: general 'prepareinitialanswer'
  1062. answer_message->setOpcode(isc::dns::Opcode::QUERY());
  1063. ConstQuestionPtr question = *query_message->beginQuestion();
  1064. answer_message->addQuestion(*question);
  1065. // implement the simplest forwarder, which will pass
  1066. // everything throught without interpretation, except
  1067. // QID, port number. The response will not be cached.
  1068. // It will delete itself when it is done
  1069. return (new ForwardQuery(io, query_message, answer_message,
  1070. upstream_, buffer, callback, query_timeout_,
  1071. client_timeout_, lookup_timeout_));
  1072. }
  1073. } // namespace asiodns
  1074. } // namespace isc