query.cc 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright (C) 2010 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 <vector>
  15. #include <boost/foreach.hpp>
  16. #include <dns/message.h>
  17. #include <dns/rcode.h>
  18. #include <dns/rdataclass.h>
  19. #include <datasrc/memory_datasrc.h>
  20. #include <auth/query.h>
  21. using namespace isc::dns;
  22. using namespace isc::datasrc;
  23. using namespace isc::dns::rdata;
  24. using namespace std;
  25. namespace isc {
  26. namespace auth {
  27. void
  28. Query::getAdditional(const isc::datasrc::Zone& zone,
  29. const isc::dns::RRset& rrset) const
  30. {
  31. if (rrset.getType() == RRType::NS()) {
  32. // Need to perform the search in the "GLUE OK" mode.
  33. RdataIteratorPtr rdata_iterator = rrset.getRdataIterator();
  34. for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
  35. const Rdata& rdata(rdata_iterator->getCurrent());
  36. const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
  37. findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
  38. }
  39. }
  40. }
  41. void
  42. Query::findAddrs(const isc::datasrc::Zone& zone,
  43. const isc::dns::Name& qname,
  44. const isc::datasrc::Zone::FindOptions options) const
  45. {
  46. // Out of zone name
  47. NameComparisonResult result = zone.getOrigin().compare(qname);
  48. if ((result.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
  49. (result.getRelation() != NameComparisonResult::EQUAL))
  50. return;
  51. // Find A rrset
  52. Zone::FindResult a_result = zone.find(qname, RRType::A(), options);
  53. if (a_result.code == Zone::SUCCESS) {
  54. response_.addRRset(Message::SECTION_ADDITIONAL,
  55. boost::const_pointer_cast<RRset>(a_result.rrset));
  56. }
  57. // Find AAAA rrset
  58. Zone::FindResult aaaa_result = zone.find(qname, RRType::AAAA(), options);
  59. if (aaaa_result.code == Zone::SUCCESS) {
  60. response_.addRRset(Message::SECTION_ADDITIONAL,
  61. boost::const_pointer_cast<RRset>(aaaa_result.rrset));
  62. }
  63. }
  64. void
  65. Query::putSOA(const Zone& zone) const {
  66. Zone::FindResult soa_result(zone.find(zone.getOrigin(),
  67. RRType::SOA()));
  68. if (soa_result.code != Zone::SUCCESS) {
  69. isc_throw(NoSOA, "There's no SOA record in zone " <<
  70. zone.getOrigin().toText());
  71. } else {
  72. /*
  73. * FIXME:
  74. * The const-cast is wrong, but the Message interface seems
  75. * to insist.
  76. */
  77. response_.addRRset(Message::SECTION_AUTHORITY,
  78. boost::const_pointer_cast<RRset>(soa_result.rrset));
  79. }
  80. }
  81. void
  82. Query::process() const {
  83. bool keep_doing = true;
  84. response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
  85. const MemoryDataSrc::FindResult result =
  86. memory_datasrc_.findZone(qname_);
  87. // If we have no matching authoritative zone for the query name, return
  88. // REFUSED. In short, this is to be compatible with BIND 9, but the
  89. // background discussion is not that simple. See the relevant topic
  90. // at the BIND 10 developers's ML:
  91. // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
  92. if (result.code != result::SUCCESS &&
  93. result.code != result::PARTIALMATCH) {
  94. response_.setRcode(Rcode::REFUSED());
  95. return;
  96. }
  97. // Found a zone which is the nearest ancestor to QNAME, set the AA bit
  98. response_.setHeaderFlag(Message::HEADERFLAG_AA);
  99. while (keep_doing) {
  100. keep_doing = false;
  101. Zone::FindResult db_result = result.zone->find(qname_, qtype_);
  102. switch (db_result.code) {
  103. case Zone::SUCCESS:
  104. response_.setRcode(Rcode::NOERROR());
  105. response_.addRRset(Message::SECTION_ANSWER,
  106. boost::const_pointer_cast<RRset>(db_result.rrset));
  107. // Some additional processing
  108. if (qtype_ == RRType::MX()) {
  109. // We look up these RR types
  110. vector<RRType> interesting_types;
  111. interesting_types.push_back(RRType::A());
  112. interesting_types.push_back(RRType::AAAA());
  113. // Go trough all the RRs in the RRset
  114. for (RdataIteratorPtr i(
  115. db_result.rrset->getRdataIterator()); !i->isLast();
  116. i->next())
  117. {
  118. // Who does it talk about?
  119. Name name(
  120. dynamic_cast<const isc::dns::rdata::generic::MX &>(
  121. i->getCurrent()).getMXName());
  122. // Look up both addresses
  123. BOOST_FOREACH(const RRType& type, interesting_types) {
  124. // Recursively call query
  125. Message response(Message::RENDER);
  126. Query sub(memory_datasrc_, name, type, response);
  127. sub.process();
  128. // And run trough all the answers and look if some
  129. // of them match
  130. for (SectionIterator<RRsetPtr> ai(
  131. response.beginSection(
  132. Message::SECTION_ANSWER)); ai !=
  133. response.endSection(Message::SECTION_ANSWER);
  134. ++ ai)
  135. {
  136. if ((*ai)->getType() == type &&
  137. (*ai)->getName() == name)
  138. {
  139. response_.addRRset(
  140. Message::SECTION_ADDITIONAL, *ai);
  141. }
  142. }
  143. }
  144. }
  145. }
  146. // TODO : fill in authority and addtional sections.
  147. break;
  148. case Zone::DELEGATION:
  149. response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
  150. response_.setRcode(Rcode::NOERROR());
  151. response_.addRRset(Message::SECTION_AUTHORITY,
  152. boost::const_pointer_cast<RRset>(db_result.rrset));
  153. getAdditional(*result.zone, *db_result.rrset);
  154. break;
  155. case Zone::NXDOMAIN:
  156. // Just empty answer with SOA in authority section
  157. response_.setRcode(Rcode::NXDOMAIN());
  158. putSOA(*result.zone);
  159. break;
  160. case Zone::NXRRSET:
  161. // Just empty answer with SOA in authority section
  162. response_.setRcode(Rcode::NOERROR());
  163. putSOA(*result.zone);
  164. break;
  165. case Zone::CNAME:
  166. case Zone::DNAME:
  167. // TODO : replace qname, continue lookup
  168. break;
  169. }
  170. }
  171. }
  172. }
  173. }