query.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  9. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  13. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14. * PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <exceptions/exceptions.h>
  17. #include <datasrc/zone.h>
  18. namespace isc {
  19. namespace dns {
  20. class Message;
  21. class Name;
  22. class RRType;
  23. class RRset;
  24. }
  25. namespace datasrc {
  26. class DataSourceClient;
  27. }
  28. namespace auth {
  29. /// The \c Query class represents a standard DNS query that encapsulates
  30. /// processing logic to answer the query.
  31. ///
  32. /// Many of the design details for this class are still in flux.
  33. /// We'll revisit and update them as we add more functionality, for example:
  34. /// - as a related point, we may have to pass the RR class of the query.
  35. /// in the initial implementation the RR class is an attribute of
  36. /// datasource and omitted. It's not clear if this assumption holds with
  37. /// generic data sources. On the other hand, it will help keep
  38. /// implementation simpler, and we might rather want to modify the design
  39. /// of the data source on this point.
  40. /// - return value of process(). rather than or in addition to setting the
  41. /// Rcode, we might use it as a return value of \c process().
  42. /// - we'll have to be able to specify whether DNSSEC is requested.
  43. /// It's an open question whether it should be in the constructor or via a
  44. /// separate attribute setter.
  45. /// - likewise, we'll eventually need to do per zone access control, for which
  46. /// we need querier's information such as its IP address.
  47. /// - datasrc_client and response may better be parameters to process() instead
  48. /// of the constructor.
  49. ///
  50. /// <b>Note:</b> The class name is intentionally the same as the one used in
  51. /// the datasrc library. This is because the plan is to eventually merge
  52. /// the two classes. We could give it a different name such as "AuthQuery"
  53. /// to avoid possible ambiguity, but it may sound redundant in that it's
  54. /// obvious that this class is for authoritative queries.
  55. /// Since the interfaces are very different for now and it's less
  56. /// likely to misuse one of the classes instead of the other
  57. /// accidentally, and since it's considered a temporary development state,
  58. /// we keep this name at the moment.
  59. class Query {
  60. private:
  61. /// \brief Adds a SOA.
  62. ///
  63. /// Adds a SOA of the zone into the authority zone of response_.
  64. /// Can throw NoSOA.
  65. ///
  66. void addSOA(isc::datasrc::ZoneFinder& finder);
  67. /// \brief Adds the DS rrset for the given name, if available
  68. ///
  69. /// This is intended to be called when returning a delegation, and
  70. /// if DNSSEC data is requested. If the DS record is not found
  71. /// (signaled by find() returning NXRRSET), and the zone is signed
  72. /// with NSEC, an NSEC denial of existence proof is added.
  73. ///
  74. /// \exception BadDS raised if find() returns anything other than
  75. /// SUCCESS or NXRRSET when searching for the DS
  76. /// record.
  77. /// \param finder The ZoneFinder where the delegation was found
  78. /// \param ds_name The name of the delegation RRset
  79. void addDS(isc::datasrc::ZoneFinder& finder,
  80. const isc::dns::Name& ds_name);
  81. /// \brief Adds NSEC(3) denial proof for the given NXRRset result
  82. ///
  83. /// If available, NSEC or NSEC3 records are added to the authority
  84. /// section (depending on whether isNSECSigned() or isNSEC3Signed()
  85. /// returns true).
  86. ///
  87. /// \param finder The ZoneFinder that was used to search for the missing
  88. /// data
  89. /// \param db_result The ZoneFinder::FindResult returned by find()
  90. void addNXRRsetProof(isc::datasrc::ZoneFinder& finder,
  91. const isc::datasrc::ZoneFinder::FindResult& db_result);
  92. /// Add NSEC RRs that prove an NXDOMAIN result.
  93. ///
  94. /// This corresponds to Section 3.1.3.2 of RFC 4035.
  95. void addNXDOMAINProofByNSEC(isc::datasrc::ZoneFinder& finder,
  96. isc::dns::ConstRRsetPtr nsec);
  97. /// Add NSEC3 RRs that prove an NXDOMAIN result.
  98. ///
  99. /// This corresponds to Section 7.2.2 of RFC 5155.
  100. void addNXDOMAINProofByNSEC3(isc::datasrc::ZoneFinder& finder);
  101. /// Add NSEC RRs that prove a wildcard answer is the best one.
  102. ///
  103. /// This corresponds to Section 3.1.3.3 of RFC 4035.
  104. void addWildcardProof(isc::datasrc::ZoneFinder& finder);
  105. /// \brief Adds one NSEC RR proved no matched QNAME,one NSEC RR proved no
  106. /// matched <QNAME,QTYPE> through wildcard extension.
  107. ///
  108. /// Add NSEC RRs that prove an WILDCARD_NXRRSET result.
  109. /// This corresponds to Section 3.1.3.4 of RFC 4035.
  110. /// \param finder The ZoneFinder through which the authority data for the
  111. /// query is to be found.
  112. /// \param nsec The RRset (NSEC RR) which proved that there is no matched
  113. /// <QNAME,QTTYPE>.
  114. void addWildcardNXRRSETProof(isc::datasrc::ZoneFinder& finder,
  115. isc::dns::ConstRRsetPtr nsec);
  116. /// \brief Look up additional data (i.e., address records for the names
  117. /// included in NS or MX records) and add them to the additional section.
  118. ///
  119. /// Note: Any additional data which has already been provided in the
  120. /// answer section (i.e., if the original query happend to be for the
  121. /// address of the DNS server), it should be omitted from the additional.
  122. ///
  123. /// This method may throw a exception because its underlying methods may
  124. /// throw exceptions.
  125. ///
  126. /// \param zone The ZoneFinder through which the additional data for the
  127. /// query is to be found.
  128. /// \param rrset The RRset (i.e., NS or MX rrset) which require additional
  129. /// processing.
  130. void addAdditional(isc::datasrc::ZoneFinder& zone,
  131. const isc::dns::AbstractRRset& rrset);
  132. /// \brief Find address records for a specified name.
  133. ///
  134. /// Search the specified zone for AAAA/A RRs of each of the NS/MX RDATA
  135. /// (domain name), and insert the found ones into the additional section
  136. /// if address records are available. By default the search will stop
  137. /// once it encounters a zone cut.
  138. ///
  139. /// Note: we need to perform the search in the "GLUE OK" mode for NS RDATA,
  140. /// which means that we should include A/AAAA RRs under a zone cut.
  141. /// The glue records must exactly match the name in the NS RDATA, without
  142. /// CNAME or wildcard processing.
  143. ///
  144. /// \param zone The \c ZoneFinder through which the address records is to
  145. /// be found.
  146. /// \param qname The name in rrset RDATA.
  147. /// \param options The search options.
  148. void addAdditionalAddrs(isc::datasrc::ZoneFinder& zone,
  149. const isc::dns::Name& qname,
  150. const isc::datasrc::ZoneFinder::FindOptions options
  151. = isc::datasrc::ZoneFinder::FIND_DEFAULT);
  152. /// \brief Look up a zone's NS RRset and their address records for an
  153. /// authoritative answer, and add them to the additional section.
  154. ///
  155. /// On returning an authoritative answer, insert a zone's NS into the
  156. /// authority section and AAAA/A RRs of each of the NS RDATA into the
  157. /// additional section.
  158. ///
  159. /// <b>Notes to developer:</b>
  160. ///
  161. /// We should omit address records which has already been provided in the
  162. /// answer section from the additional.
  163. ///
  164. /// For now, in order to optimize the additional section processing, we
  165. /// include AAAA/A RRs under a zone cut in additional section. (BIND 9
  166. /// excludes under-cut RRs; NSD include them.)
  167. ///
  168. /// \param finder The \c ZoneFinder through which the NS and additional
  169. /// data for the query are to be found.
  170. void addAuthAdditional(isc::datasrc::ZoneFinder& finder);
  171. /// \brief Process a DS query possible at the child side of zone cut.
  172. ///
  173. /// This private method is a subroutine of process(), and is called if
  174. /// there's a possibility that this server has authority for the child
  175. /// side of the DS's owner name (and it's detected that the server at
  176. /// least doesn't have authority at the parent side). This method
  177. /// first checks if it has authority for the child, and if does,
  178. /// just build a "no data" response with SOA for the zone origin
  179. /// (possibly with a proof for the no data) as specified in Section
  180. /// 2.2.1.1 of RFC3658.
  181. ///
  182. /// It returns true if this server has authority of the child; otherwise
  183. /// it returns false. In the former case, the caller is expected to
  184. /// terminate the query processing, because it should have been completed
  185. /// within this method.
  186. bool processDSAtChild();
  187. public:
  188. /// Constructor from query parameters.
  189. ///
  190. /// This constructor never throws an exception.
  191. ///
  192. /// \param datasrc_client The datasource wherein the answer to the query is
  193. /// to be found.
  194. /// \param qname The query name
  195. /// \param qtype The RR type of the query
  196. /// \param response The response message to store the answer to the query.
  197. /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
  198. /// possible.
  199. Query(const isc::datasrc::DataSourceClient& datasrc_client,
  200. const isc::dns::Name& qname, const isc::dns::RRType& qtype,
  201. isc::dns::Message& response, bool dnssec = false) :
  202. datasrc_client_(datasrc_client), qname_(qname), qtype_(qtype),
  203. response_(response), dnssec_(dnssec),
  204. dnssec_opt_(dnssec ? isc::datasrc::ZoneFinder::FIND_DNSSEC :
  205. isc::datasrc::ZoneFinder::FIND_DEFAULT)
  206. {}
  207. /// Process the query.
  208. ///
  209. /// This method first identifies the zone that best matches the query
  210. /// name (and in some cases RR type when the search is dependent on the
  211. /// type) and then searches the zone for an entry that best matches the
  212. /// query name.
  213. /// It then updates the response message accordingly; for example, a
  214. /// successful search would result in adding a corresponding RRset to
  215. /// the answer section of the response.
  216. ///
  217. /// If no matching zone is found in the datasource, the RCODE of
  218. /// SERVFAIL will be set in the response.
  219. /// <b>Note:</b> this is different from the error code that BIND 9 returns
  220. /// by default when it's configured as an authoritative-only server (and
  221. /// from the behavior of the BIND 10 datasrc library, which was implemented
  222. /// to be compatible with BIND 9).
  223. /// The difference comes from the fact that BIND 9 returns REFUSED as a
  224. /// result of access control check on the use of its cache.
  225. /// Since BIND 10's authoritative server doesn't have the notion of cache
  226. /// by design, it doesn't make sense to return REFUSED. On the other hand,
  227. /// providing compatible behavior may have its own benefit, so this point
  228. /// should be revisited later.
  229. ///
  230. /// This might throw BadZone or any of its specific subclasses, but that
  231. /// shouldn't happen in real-life (as BadZone means wrong data, it should
  232. /// have been rejected upon loading).
  233. void process();
  234. /// \short Bad zone data encountered.
  235. ///
  236. /// This is thrown when process encounteres misconfigured zone in a way
  237. /// it can't continue. This throws, not sets the Rcode, because such
  238. /// misconfigured zone should not be present in the data source and
  239. /// should have been rejected sooner.
  240. struct BadZone : public isc::Exception {
  241. BadZone(const char* file, size_t line, const char* what) :
  242. Exception(file, line, what)
  243. {}
  244. };
  245. /// \short Zone is missing its SOA record.
  246. ///
  247. /// We tried to add a SOA into the authoritative section, but the zone
  248. /// does not contain one.
  249. struct NoSOA : public BadZone {
  250. NoSOA(const char* file, size_t line, const char* what) :
  251. BadZone(file, line, what)
  252. {}
  253. };
  254. /// \short Zone is missing its apex NS records.
  255. ///
  256. /// We tried to add apex NS records into the authority section, but the
  257. /// zone does not contain any.
  258. struct NoApexNS: public BadZone {
  259. NoApexNS(const char* file, size_t line, const char* what) :
  260. BadZone(file, line, what)
  261. {}
  262. };
  263. /// An invalid result is given when a valid NSEC is expected
  264. ///
  265. /// This can only happen when the underlying data source implementation or
  266. /// the zone is broken. By throwing an exception we treat such cases
  267. /// as SERVFAIL.
  268. struct BadNSEC : public BadZone {
  269. BadNSEC(const char* file, size_t line, const char* what) :
  270. BadZone(file, line, what)
  271. {}
  272. };
  273. /// An invalid result is given when a valid NSEC3 is expected
  274. ///
  275. /// This can only happen when the underlying data source implementation or
  276. /// the zone is broken. By throwing an exception we treat such cases
  277. /// as SERVFAIL.
  278. struct BadNSEC3 : public BadZone {
  279. BadNSEC3(const char* file, size_t line, const char* what) :
  280. BadZone(file, line, what)
  281. {}
  282. };
  283. /// An invalid result is given when a valid DS records (or NXRRSET) is
  284. /// expected
  285. ///
  286. /// This can only happen when the underlying data source implementation
  287. /// or the zone is broken. A DS query for a known delegation point should
  288. /// either result in SUCCESS (if available) or NXRRSET
  289. struct BadDS : public BadZone {
  290. BadDS(const char* file, size_t line, const char* what) :
  291. BadZone(file, line, what)
  292. {}
  293. };
  294. private:
  295. const isc::datasrc::DataSourceClient& datasrc_client_;
  296. const isc::dns::Name& qname_;
  297. const isc::dns::RRType& qtype_;
  298. isc::dns::Message& response_;
  299. const bool dnssec_;
  300. const isc::datasrc::ZoneFinder::FindOptions dnssec_opt_;
  301. };
  302. }
  303. }
  304. // Local Variables:
  305. // mode: c++
  306. // End: