recursive_query.cc 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220
  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 <netinet/in.h>
  15. #include <stdlib.h>
  16. #include <sys/socket.h>
  17. #include <unistd.h> // for some IPC/network system calls
  18. #include <string>
  19. #include <boost/lexical_cast.hpp>
  20. #include <boost/bind.hpp>
  21. #include <config.h>
  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(DNSService& 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_);
  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_);
  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. // try EDNS over TCP
  484. send(IOFetch::TCP, true);
  485. return (false);
  486. } else if (protocol_ == IOFetch::TCP && edns_) {
  487. // try UDP, no EDNS
  488. send(IOFetch::UDP, false);
  489. return (false);
  490. }
  491. // TC should take care of non-EDNS over UDP, fall through to
  492. // SERVFAIL if we get FORMERR instead
  493. }
  494. goto SERVFAIL;
  495. default:
  496. SERVFAIL:
  497. // Some error in received packet it. Report it and return SERVFAIL
  498. // to the caller.
  499. if (logger.isDebugEnabled()) {
  500. reportResponseClassifierError(category, incoming.getRcode());
  501. }
  502. makeSERVFAIL();
  503. return (true);
  504. }
  505. // If we get here, there is some serious logic error (or a missing
  506. // "return").
  507. assert(false);
  508. return (true); // To keep the compiler happy
  509. }
  510. /// \brief Report classification-detected error
  511. ///
  512. /// When the response classifier has detected an error in the response from
  513. /// an upstream query, this method is called to log a debug message giving
  514. /// information about the problem.
  515. ///
  516. /// \param category Classification code for the packet
  517. /// \param rcode RCODE value in the packet
  518. void reportResponseClassifierError(ResponseClassifier::Category category,
  519. const Rcode& rcode)
  520. {
  521. // We could set up a table of response classifications to message
  522. // IDs here and index into that table. But given that (a) C++ does
  523. // not have C's named initializers, (b) the codes for the
  524. // response classifier are in another module and (c) not all messages
  525. // have the same number of arguments, the setup of the table would be
  526. // almost as long as the code here: it would need to include a number
  527. // of assertions to ensure that any change to the the response
  528. // classifier codes was detected, and the checking logic would need to
  529. // check that the numeric value of the code lay within the defined
  530. // limits of the table.
  531. if (category == ResponseClassifier::RCODE) {
  532. // Special case as this message takes two arguments.
  533. LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_ERROR).
  534. arg(questionText(question_)).arg(rcode);
  535. } else {
  536. isc::log::MessageID message_id;
  537. switch (category) {
  538. case ResponseClassifier::TRUNCATED:
  539. message_id = RESLIB_TCP_TRUNCATED;
  540. break;
  541. case ResponseClassifier::EMPTY:
  542. message_id = RESLIB_EMPTY_RESPONSE;
  543. break;
  544. case ResponseClassifier::EXTRADATA:
  545. message_id = RESLIB_EXTRADATA_RESPONSE;
  546. break;
  547. case ResponseClassifier::INVNAMCLASS:
  548. message_id = RESLIB_INVALID_NAMECLASS_RESPONSE;
  549. break;
  550. case ResponseClassifier::INVTYPE:
  551. message_id = RESLIB_INVALID_TYPE_RESPONSE;
  552. break;
  553. case ResponseClassifier::MISMATQUEST:
  554. message_id = RESLIB_INVALID_QNAME_RESPONSE;
  555. break;
  556. case ResponseClassifier::MULTICLASS:
  557. message_id = RESLIB_MULTIPLE_CLASS_RESPONSE;
  558. break;
  559. case ResponseClassifier::NOTONEQUEST:
  560. message_id = RESLIB_NOT_ONE_QNAME_RESPONSE;
  561. break;
  562. case ResponseClassifier::NOTRESPONSE:
  563. message_id = RESLIB_NOT_RESPONSE;
  564. break;
  565. case ResponseClassifier::NOTSINGLE:
  566. message_id = RESLIB_NOTSINGLE_RESPONSE;
  567. case ResponseClassifier::OPCODE:
  568. message_id = RESLIB_OPCODE_RESPONSE;
  569. default:
  570. message_id = RESLIB_ERROR_RESPONSE;
  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_(new ResolverNSASCallback(this)),
  608. nsas_callback_out_(false),
  609. outstanding_events_(0),
  610. rtt_recorder_(recorder)
  611. {
  612. // Setup the timer to stop trying (lookup_timeout)
  613. if (lookup_timeout >= 0) {
  614. lookup_timer.expires_from_now(
  615. boost::posix_time::milliseconds(lookup_timeout));
  616. ++outstanding_events_;
  617. lookup_timer.async_wait(boost::bind(&RunningQuery::lookupTimeout, this));
  618. }
  619. // Setup the timer to send an answer (client_timeout)
  620. if (client_timeout >= 0) {
  621. client_timer.expires_from_now(
  622. boost::posix_time::milliseconds(client_timeout));
  623. ++outstanding_events_;
  624. client_timer.async_wait(boost::bind(&RunningQuery::clientTimeout, this));
  625. }
  626. doLookup();
  627. }
  628. // called if we have a lookup timeout; if our callback has
  629. // not been called, call it now. Then stop.
  630. void lookupTimeout() {
  631. if (!callback_called_) {
  632. makeSERVFAIL();
  633. callCallback(true);
  634. }
  635. assert(outstanding_events_ > 0);
  636. --outstanding_events_;
  637. stop();
  638. }
  639. // called if we have a client timeout; if our callback has
  640. // not been called, call it now. But do not stop.
  641. void clientTimeout() {
  642. if (!callback_called_) {
  643. makeSERVFAIL();
  644. callCallback(true);
  645. }
  646. assert(outstanding_events_ > 0);
  647. --outstanding_events_;
  648. if (outstanding_events_ == 0) {
  649. stop();
  650. }
  651. }
  652. // If the callback has not been called yet, call it now
  653. // If success is true, we call 'success' with our answer_message
  654. // If it is false, we call failure()
  655. void callCallback(bool success) {
  656. if (!callback_called_) {
  657. callback_called_ = true;
  658. // There are two types of messages we could store in the
  659. // cache;
  660. // 1. answers to our fetches from authoritative servers,
  661. // exactly as we receive them, and
  662. // 2. answers to queries we received from clients, which
  663. // have received additional processing (following CNAME
  664. // chains, for instance)
  665. //
  666. // Doing only the first would mean we would have to re-do
  667. // processing when we get data from our cache, and doing
  668. // only the second would miss out on the side-effect of
  669. // having nameserver data in our cache.
  670. //
  671. // So right now we do both. Since the cache (currently)
  672. // stores Messages on their question section only, this
  673. // does mean that we overwrite the messages we stored in
  674. // the previous iteration if we are following a delegation.
  675. if (success) {
  676. resolvercallback_->success(answer_message_);
  677. } else {
  678. resolvercallback_->failure();
  679. }
  680. }
  681. }
  682. // We are done. If there are no more outstanding events, we delete
  683. // ourselves. If there are any, we do not.
  684. void stop() {
  685. done_ = true;
  686. if (nsas_callback_out_) {
  687. nsas_.cancel(cur_zone_, question_.getClass(), nsas_callback_);
  688. nsas_callback_out_ = false;
  689. }
  690. client_timer.cancel();
  691. lookup_timer.cancel();
  692. if (outstanding_events_ > 0) {
  693. return;
  694. } else {
  695. delete this;
  696. }
  697. }
  698. // This function is used as callback from DNSQuery.
  699. virtual void operator()(IOFetch::Result result) {
  700. // XXX is this the place for TCP retry?
  701. assert(outstanding_events_ > 0);
  702. --outstanding_events_;
  703. if (!done_ && result != IOFetch::TIME_OUT) {
  704. // we got an answer
  705. // Update the NSAS with the time it took
  706. struct timeval cur_time;
  707. gettimeofday(&cur_time, NULL);
  708. uint32_t rtt = 0;
  709. // Only calculate RTT if it is positive
  710. if (cur_time.tv_sec > current_ns_qsent_time.tv_sec ||
  711. (cur_time.tv_sec == current_ns_qsent_time.tv_sec &&
  712. cur_time.tv_usec > current_ns_qsent_time.tv_usec)) {
  713. rtt = 1000 * (cur_time.tv_sec - current_ns_qsent_time.tv_sec);
  714. rtt += (cur_time.tv_usec - current_ns_qsent_time.tv_usec) / 1000;
  715. }
  716. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_RTT).arg(rtt);
  717. current_ns_address.updateRTT(rtt);
  718. if (rtt_recorder_) {
  719. rtt_recorder_->addRtt(rtt);
  720. }
  721. try {
  722. Message incoming(Message::PARSE);
  723. InputBuffer ibuf(buffer_->getData(), buffer_->getLength());
  724. incoming.fromWire(ibuf);
  725. buffer_->clear();
  726. done_ = handleRecursiveAnswer(incoming);
  727. if (done_) {
  728. callCallback(true);
  729. stop();
  730. }
  731. } catch (const isc::dns::DNSProtocolError& dpe) {
  732. // Right now, we treat this similar to timeouts
  733. // (except we don't store RTT)
  734. // We probably want to make this an integral part
  735. // of the fetch data process. (TODO)
  736. if (retries_--) {
  737. // Retry
  738. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS,
  739. RESLIB_PROTOCOL_RETRY)
  740. .arg(questionText(question_)).arg(dpe.what())
  741. .arg(retries_);
  742. send();
  743. } else {
  744. // Give up
  745. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS,
  746. RESLIB_PROTOCOL)
  747. .arg(questionText(question_)).arg(dpe.what());
  748. if (!callback_called_) {
  749. makeSERVFAIL();
  750. callCallback(true);
  751. }
  752. stop();
  753. }
  754. }
  755. } else if (!done_ && retries_--) {
  756. // Query timed out, but we have some retries, so send again
  757. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_TIMEOUT_RETRY)
  758. .arg(questionText(question_))
  759. .arg(current_ns_address.getAddress().toText()).arg(retries_);
  760. current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
  761. send();
  762. } else {
  763. // We are either already done, or out of retries
  764. if (result == IOFetch::TIME_OUT) {
  765. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_TIMEOUT)
  766. .arg(questionText(question_))
  767. .arg(current_ns_address.getAddress().toText());
  768. current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
  769. }
  770. if (!callback_called_) {
  771. makeSERVFAIL();
  772. callCallback(true);
  773. }
  774. stop();
  775. }
  776. }
  777. // Clear the answer parts of answer_message, and set the rcode
  778. // to servfail
  779. void makeSERVFAIL() {
  780. isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
  781. }
  782. };
  783. class ForwardQuery : public IOFetch::Callback {
  784. private:
  785. // The io service to handle async calls
  786. IOService& io_;
  787. // This is the query message got from client
  788. ConstMessagePtr query_message_;
  789. // This is where we build and store our final answer
  790. MessagePtr answer_message_;
  791. // List of nameservers to forward to
  792. boost::shared_ptr<AddressVector> upstream_;
  793. // Buffer to store the result.
  794. OutputBufferPtr buffer_;
  795. // This will be notified when we succeed or fail
  796. isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
  797. /*
  798. * TODO Do something more clever with timeouts. In the long term, some
  799. * computation of average RTT, increase with each retry, etc.
  800. */
  801. // Timeout information
  802. int query_timeout_;
  803. // TODO: replace by our wrapper
  804. asio::deadline_timer client_timer;
  805. asio::deadline_timer lookup_timer;
  806. // Make FowardQuery deletes itself safely. for more information see
  807. // the comments of outstanding_events in RunningQuery.
  808. size_t outstanding_events_;
  809. // If we have a client timeout, we call back with a failure message,
  810. // but we do not stop yet. We use this variable to make sure we
  811. // don't call back a second time later
  812. bool callback_called_;
  813. // send the query to the server.
  814. void send(IOFetch::Protocol protocol = IOFetch::UDP) {
  815. const int uc = upstream_->size();
  816. buffer_->clear();
  817. int serverIndex = rand() % uc;
  818. ConstQuestionPtr question = *(query_message_->beginQuestion());
  819. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_UPSTREAM)
  820. .arg(questionText(*question))
  821. .arg(upstream_->at(serverIndex).first);
  822. ++outstanding_events_;
  823. // Forward the query, create the IOFetch with
  824. // query message, so that query flags can be forwarded
  825. // together.
  826. IOFetch query(protocol, io_, query_message_,
  827. upstream_->at(serverIndex).first,
  828. upstream_->at(serverIndex).second,
  829. buffer_, this, query_timeout_);
  830. io_.get_io_service().post(query);
  831. }
  832. public:
  833. ForwardQuery(IOService& io,
  834. ConstMessagePtr query_message,
  835. MessagePtr answer_message,
  836. boost::shared_ptr<AddressVector> upstream,
  837. OutputBufferPtr buffer,
  838. isc::resolve::ResolverInterface::CallbackPtr cb,
  839. int query_timeout, int client_timeout, int lookup_timeout) :
  840. io_(io),
  841. query_message_(query_message),
  842. answer_message_(answer_message),
  843. upstream_(upstream),
  844. buffer_(buffer),
  845. resolvercallback_(cb),
  846. query_timeout_(query_timeout),
  847. client_timer(io.get_io_service()),
  848. lookup_timer(io.get_io_service()),
  849. outstanding_events_(0),
  850. callback_called_(false)
  851. {
  852. // Setup the timer to stop trying (lookup_timeout)
  853. if (lookup_timeout >= 0) {
  854. lookup_timer.expires_from_now(
  855. boost::posix_time::milliseconds(lookup_timeout));
  856. ++outstanding_events_;
  857. lookup_timer.async_wait(boost::bind(&ForwardQuery::lookupTimeout, this));
  858. }
  859. // Setup the timer to send an answer (client_timeout)
  860. if (client_timeout >= 0) {
  861. client_timer.expires_from_now(
  862. boost::posix_time::milliseconds(client_timeout));
  863. ++outstanding_events_;
  864. client_timer.async_wait(boost::bind(&ForwardQuery::clientTimeout, this));
  865. }
  866. send();
  867. }
  868. virtual void lookupTimeout() {
  869. if (!callback_called_) {
  870. makeSERVFAIL();
  871. callCallback(false);
  872. }
  873. assert(outstanding_events_ > 0);
  874. --outstanding_events_;
  875. stop();
  876. }
  877. virtual void clientTimeout() {
  878. if (!callback_called_) {
  879. makeSERVFAIL();
  880. callCallback(false);
  881. }
  882. assert(outstanding_events_ > 0);
  883. --outstanding_events_;
  884. stop();
  885. }
  886. // If the callback has not been called yet, call it now
  887. // If success is true, we call 'success' with our answer_message
  888. // If it is false, we call failure()
  889. void callCallback(bool success) {
  890. if (!callback_called_) {
  891. callback_called_ = true;
  892. if (success) {
  893. resolvercallback_->success(answer_message_);
  894. } else {
  895. resolvercallback_->failure();
  896. }
  897. }
  898. }
  899. virtual void stop() {
  900. // if we cancel our timers, we will still get an event for
  901. // that, so we cannot delete ourselves just yet (those events
  902. // would be bound to a deleted object)
  903. // cancel them one by one, both cancels should get us back
  904. // here again.
  905. // same goes if we have an outstanding query (can't delete
  906. // until that one comes back to us)
  907. lookup_timer.cancel();
  908. client_timer.cancel();
  909. if (outstanding_events_ > 0) {
  910. return;
  911. } else {
  912. delete this;
  913. }
  914. }
  915. // This function is used as callback from DNSQuery.
  916. virtual void operator()(IOFetch::Result result) {
  917. // XXX is this the place for TCP retry?
  918. assert(outstanding_events_ > 0);
  919. --outstanding_events_;
  920. if (result != IOFetch::TIME_OUT) {
  921. // we got an answer
  922. Message incoming(Message::PARSE);
  923. InputBuffer ibuf(buffer_->getData(), buffer_->getLength());
  924. incoming.fromWire(ibuf);
  925. isc::resolve::copyResponseMessage(incoming, answer_message_);
  926. callCallback(true);
  927. }
  928. stop();
  929. }
  930. // Clear the answer parts of answer_message, and set the rcode
  931. // to servfail
  932. void makeSERVFAIL() {
  933. isc::resolve::makeErrorMessage(answer_message_, Rcode::SERVFAIL());
  934. }
  935. };
  936. }
  937. void
  938. RecursiveQuery::resolve(const QuestionPtr& question,
  939. const isc::resolve::ResolverInterface::CallbackPtr callback)
  940. {
  941. IOService& io = dns_service_.getIOService();
  942. MessagePtr answer_message(new Message(Message::RENDER));
  943. isc::resolve::initResponseMessage(*question, *answer_message);
  944. OutputBufferPtr buffer(new OutputBuffer(0));
  945. // First try to see if we have something cached in the messagecache
  946. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RESOLVE)
  947. .arg(questionText(*question)).arg(1);
  948. if (cache_.lookup(question->getName(), question->getType(),
  949. question->getClass(), *answer_message) &&
  950. answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
  951. // Message found, return that
  952. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RECQ_CACHE_FIND)
  953. .arg(questionText(*question)).arg(1);
  954. // TODO: err, should cache set rcode as well?
  955. answer_message->setRcode(Rcode::NOERROR());
  956. callback->success(answer_message);
  957. } else {
  958. // Perhaps we only have the one RRset?
  959. // TODO: can we do this? should we check for specific types only?
  960. RRsetPtr cached_rrset = cache_.lookup(question->getName(),
  961. question->getType(),
  962. question->getClass());
  963. if (cached_rrset) {
  964. // Found single RRset in cache
  965. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RRSET_FOUND)
  966. .arg(questionText(*question)).arg(1);
  967. answer_message->addRRset(Message::SECTION_ANSWER,
  968. cached_rrset);
  969. answer_message->setRcode(Rcode::NOERROR());
  970. callback->success(answer_message);
  971. } else {
  972. // Message not found in cache, start recursive query. It will
  973. // delete itself when it is done
  974. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
  975. .arg(questionText(*question)).arg(1);
  976. new RunningQuery(io, *question, answer_message,
  977. test_server_, buffer, callback,
  978. query_timeout_, client_timeout_,
  979. lookup_timeout_, retries_, nsas_,
  980. cache_, rtt_recorder_);
  981. }
  982. }
  983. }
  984. void
  985. RecursiveQuery::resolve(const Question& question,
  986. MessagePtr answer_message,
  987. OutputBufferPtr buffer,
  988. DNSServer* server)
  989. {
  990. // XXX: eventually we will need to be able to determine whether
  991. // the message should be sent via TCP or UDP, or sent initially via
  992. // UDP and then fall back to TCP on failure, but for the moment
  993. // we're only going to handle UDP.
  994. IOService& io = dns_service_.getIOService();
  995. isc::resolve::ResolverInterface::CallbackPtr crs(
  996. new isc::resolve::ResolverCallbackServer(server));
  997. // TODO: general 'prepareinitialanswer'
  998. answer_message->setOpcode(isc::dns::Opcode::QUERY());
  999. answer_message->addQuestion(question);
  1000. // First try to see if we have something cached in the messagecache
  1001. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RESOLVE)
  1002. .arg(questionText(question)).arg(2);
  1003. if (cache_.lookup(question.getName(), question.getType(),
  1004. question.getClass(), *answer_message) &&
  1005. answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
  1006. // Message found, return that
  1007. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RECQ_CACHE_FIND)
  1008. .arg(questionText(question)).arg(2);
  1009. // TODO: err, should cache set rcode as well?
  1010. answer_message->setRcode(Rcode::NOERROR());
  1011. crs->success(answer_message);
  1012. } else {
  1013. // Perhaps we only have the one RRset?
  1014. // TODO: can we do this? should we check for specific types only?
  1015. RRsetPtr cached_rrset = cache_.lookup(question.getName(),
  1016. question.getType(),
  1017. question.getClass());
  1018. if (cached_rrset) {
  1019. // Found single RRset in cache
  1020. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RRSET_FOUND)
  1021. .arg(questionText(question)).arg(2);
  1022. answer_message->addRRset(Message::SECTION_ANSWER,
  1023. cached_rrset);
  1024. answer_message->setRcode(Rcode::NOERROR());
  1025. crs->success(answer_message);
  1026. } else {
  1027. // Message not found in cache, start recursive query. It will
  1028. // delete itself when it is done
  1029. LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
  1030. .arg(questionText(question)).arg(2);
  1031. new RunningQuery(io, question, answer_message,
  1032. test_server_, buffer, crs, query_timeout_,
  1033. client_timeout_, lookup_timeout_, retries_,
  1034. nsas_, cache_, rtt_recorder_);
  1035. }
  1036. }
  1037. }
  1038. void
  1039. RecursiveQuery::forward(ConstMessagePtr query_message,
  1040. MessagePtr answer_message,
  1041. OutputBufferPtr buffer,
  1042. DNSServer* server,
  1043. isc::resolve::ResolverInterface::CallbackPtr callback)
  1044. {
  1045. // XXX: eventually we will need to be able to determine whether
  1046. // the message should be sent via TCP or UDP, or sent initially via
  1047. // UDP and then fall back to TCP on failure, but for the moment
  1048. // we're only going to handle UDP.
  1049. IOService& io = dns_service_.getIOService();
  1050. if (!callback) {
  1051. callback.reset(new isc::resolve::ResolverCallbackServer(server));
  1052. }
  1053. // TODO: general 'prepareinitialanswer'
  1054. answer_message->setOpcode(isc::dns::Opcode::QUERY());
  1055. ConstQuestionPtr question = *query_message->beginQuestion();
  1056. answer_message->addQuestion(*question);
  1057. // implement the simplest forwarder, which will pass
  1058. // everything throught without interpretation, except
  1059. // QID, port number. The response will not be cached.
  1060. // It will delete itself when it is done
  1061. new ForwardQuery(io, query_message, answer_message,
  1062. upstream_, buffer, callback, query_timeout_,
  1063. client_timeout_, lookup_timeout_);
  1064. }
  1065. } // namespace asiodns
  1066. } // namespace isc