query.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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 <dns/rrset.h>
  18. #include <datasrc/zone.h>
  19. #include <vector>
  20. namespace isc {
  21. namespace dns {
  22. class Message;
  23. class Name;
  24. class RRType;
  25. class RRset;
  26. }
  27. namespace datasrc {
  28. class DataSourceClient;
  29. }
  30. namespace auth {
  31. /// The \c Query class represents a standard DNS query that encapsulates
  32. /// processing logic to answer the query.
  33. ///
  34. /// Many of the design details for this class are still in flux.
  35. /// We'll revisit and update them as we add more functionality, for example:
  36. /// - as a related point, we may have to pass the RR class of the query.
  37. /// in the initial implementation the RR class is an attribute of
  38. /// datasource and omitted. It's not clear if this assumption holds with
  39. /// generic data sources. On the other hand, it will help keep
  40. /// implementation simpler, and we might rather want to modify the design
  41. /// of the data source on this point.
  42. /// - return value of process(). rather than or in addition to setting the
  43. /// Rcode, we might use it as a return value of \c process().
  44. /// - we'll have to be able to specify whether DNSSEC is requested.
  45. /// It's an open question whether it should be in the constructor or via a
  46. /// separate attribute setter.
  47. /// - likewise, we'll eventually need to do per zone access control, for which
  48. /// we need querier's information such as its IP address.
  49. /// - datasrc_client and response may better be parameters to process() instead
  50. /// of the constructor.
  51. ///
  52. /// <b>Note:</b> The class name is intentionally the same as the one used in
  53. /// the datasrc library. This is because the plan is to eventually merge
  54. /// the two classes. We could give it a different name such as "AuthQuery"
  55. /// to avoid possible ambiguity, but it may sound redundant in that it's
  56. /// obvious that this class is for authoritative queries.
  57. /// Since the interfaces are very different for now and it's less
  58. /// likely to misuse one of the classes instead of the other
  59. /// accidentally, and since it's considered a temporary development state,
  60. /// we keep this name at the moment.
  61. class Query {
  62. private:
  63. /// \brief Adds a SOA.
  64. ///
  65. /// Adds a SOA of the zone into the authority zone of response_.
  66. /// Can throw NoSOA.
  67. ///
  68. void addSOA(isc::datasrc::ZoneFinder& finder);
  69. /// \brief Adds the DS rrset for the given name, if available
  70. ///
  71. /// This is intended to be called when returning a delegation, and
  72. /// if DNSSEC data is requested. If the DS record is not found
  73. /// (signaled by find() returning NXRRSET), and the zone is signed
  74. /// with NSEC, an NSEC denial of existence proof is added.
  75. ///
  76. /// \exception BadDS raised if find() returns anything other than
  77. /// SUCCESS or NXRRSET when searching for the DS
  78. /// record.
  79. /// \param finder The ZoneFinder where the delegation was found
  80. /// \param ds_name The name of the delegation RRset
  81. void addDS(isc::datasrc::ZoneFinder& finder,
  82. const isc::dns::Name& ds_name);
  83. /// \brief Adds NSEC(3) denial proof for the given NXRRset result
  84. ///
  85. /// If available, NSEC or NSEC3 records are added to the authority
  86. /// section (depending on whether isNSECSigned() or isNSEC3Signed()
  87. /// returns true).
  88. ///
  89. /// \param finder The ZoneFinder that was used to search for the missing
  90. /// data
  91. /// \param db_result The ZoneFinder::FindResult returned by find()
  92. void addNXRRsetProof(isc::datasrc::ZoneFinder& finder,
  93. const isc::datasrc::ZoneFinder::Context& db_context);
  94. /// Add NSEC RRs that prove an NXDOMAIN result.
  95. ///
  96. /// This corresponds to Section 3.1.3.2 of RFC 4035.
  97. void addNXDOMAINProofByNSEC(isc::datasrc::ZoneFinder& finder,
  98. isc::dns::ConstRRsetPtr nsec);
  99. /// Add NSEC3 RRs that prove an NXDOMAIN result.
  100. ///
  101. /// This corresponds to Section 7.2.2 of RFC 5155.
  102. void addNXDOMAINProofByNSEC3(isc::datasrc::ZoneFinder& finder);
  103. /// Add NSEC or NSEC3 RRs that prove a wildcard answer is the best one.
  104. ///
  105. /// This corresponds to Section 3.1.3.3 of RFC 4035 and Section 7.2.6
  106. /// of RFC5155.
  107. void addWildcardProof(
  108. isc::datasrc::ZoneFinder& finder,
  109. const isc::datasrc::ZoneFinder::Context& db_context);
  110. /// \brief Adds one NSEC RR proved no matched QNAME,one NSEC RR proved no
  111. /// matched <QNAME,QTYPE> through wildcard extension.
  112. ///
  113. /// Add NSEC RRs that prove an WILDCARD_NXRRSET result.
  114. /// This corresponds to Section 3.1.3.4 of RFC 4035.
  115. /// \param finder The ZoneFinder through which the authority data for the
  116. /// query is to be found.
  117. /// \param nsec The RRset (NSEC RR) which proved that there is no matched
  118. /// <QNAME,QTTYPE>.
  119. void addWildcardNXRRSETProof(isc::datasrc::ZoneFinder& finder,
  120. isc::dns::ConstRRsetPtr nsec);
  121. /// \brief Look up a zone's NS RRset and their address records for an
  122. /// authoritative answer, and add them to the additional section.
  123. ///
  124. /// On returning an authoritative answer, insert a zone's NS into the
  125. /// authority section and AAAA/A RRs of each of the NS RDATA into the
  126. /// additional section.
  127. ///
  128. /// <b>Notes to developer:</b>
  129. ///
  130. /// We should omit address records which has already been provided in the
  131. /// answer section from the additional.
  132. ///
  133. /// For now, in order to optimize the additional section processing, we
  134. /// include AAAA/A RRs under a zone cut in additional section. (BIND 9
  135. /// excludes under-cut RRs; NSD include them.)
  136. ///
  137. /// \param finder The \c ZoneFinder through which the NS and additional
  138. /// data for the query are to be found.
  139. void addAuthAdditional(isc::datasrc::ZoneFinder& finder,
  140. std::vector<isc::dns::ConstRRsetPtr>& additionals);
  141. /// \brief Process a DS query possible at the child side of zone cut.
  142. ///
  143. /// This private method is a subroutine of process(), and is called if
  144. /// there's a possibility that this server has authority for the child
  145. /// side of the DS's owner name (and it's detected that the server at
  146. /// least doesn't have authority at the parent side). This method
  147. /// first checks if it has authority for the child, and if does,
  148. /// just build a "no data" response with SOA for the zone origin
  149. /// (possibly with a proof for the no data) as specified in Section
  150. /// 2.2.1.1 of RFC3658.
  151. ///
  152. /// It returns true if this server has authority of the child; otherwise
  153. /// it returns false. In the former case, the caller is expected to
  154. /// terminate the query processing, because it should have been completed
  155. /// within this method.
  156. bool processDSAtChild();
  157. /// \brief Add NSEC3 to the response for a closest encloser proof for a
  158. /// given name.
  159. ///
  160. /// This method calls \c findNSEC3() of the given zone finder for the
  161. /// given name in the recursive mode, and adds the returned NSEC3(s) to
  162. /// the authority section of the response message associated with the
  163. /// \c Query object.
  164. ///
  165. /// It returns the number of labels of the closest encloser (returned via
  166. /// the \c findNSEC3() call) in case the caller needs to use that value
  167. /// for subsequent processing, i.e, constructing the best possible wildcard
  168. /// name that (would) match the query name.
  169. ///
  170. /// Unless \c exact_ok is true, \c name is expected to be non existent,
  171. /// in which case findNSEC3() in the recursive mode must return both
  172. /// closest and next proofs. If the latter is NULL, it means a run time
  173. /// collision (or the zone is broken in other way), and this method throws
  174. /// a BadNSEC3 exception.
  175. ///
  176. /// If \c exact_ok is true, this method takes into account the case
  177. /// where the name exists and may or may not be at a zone cut to an
  178. /// optout zone. In this case, depending on whether the zone is optout
  179. /// or not, findNSEC3() may return non-NULL or NULL next_proof
  180. /// (respectively). This method adds the next proof if and only if
  181. /// findNSEC3() returns non NULL value for it. The Opt-Out flag
  182. /// must be set or cleared accordingly, but this method doesn't check that
  183. /// in this level (as long as the zone is signed validly and findNSEC3()
  184. /// for the data source is implemented as documented, the condition
  185. /// should be met; otherwise we'd let the validator detect the error).
  186. ///
  187. /// By default this method always adds the closest proof.
  188. /// If \c add_closest is false, it only adds the next proof to the message.
  189. /// This correspond to the case of "wildcard answer responses" as described
  190. /// in Section 7.2.6 of RFC5155.
  191. uint8_t addClosestEncloserProof(isc::datasrc::ZoneFinder& finder,
  192. const isc::dns::Name& name, bool exact_ok,
  193. bool add_closest = true);
  194. /// \brief Add matching or covering NSEC3 to the response for a give name.
  195. ///
  196. /// This method calls \c findNSEC3() of the given zone finder for the
  197. /// given name in the non recursive mode, and adds the returned NSEC3 to
  198. /// the authority section of the response message associated with the
  199. /// \c Query object.
  200. ///
  201. /// Depending on the caller's context, the returned NSEC3 is one and
  202. /// only one of matching or covering NSEC3. If \c match is true the
  203. /// returned NSEC3 must be a matching one; otherwise it must be a covering
  204. /// one. If this assumption isn't met this method throws a BadNSEC3
  205. /// exception (if it must be a matching NSEC3 but is not, it means a broken
  206. /// zone, maybe with incorrect optout NSEC3s; if it must be a covering
  207. /// NSEC3 but is not, it means a run time collision; or the \c findNSEC3()
  208. /// implementation is broken for both cases.)
  209. void addNSEC3ForName(isc::datasrc::ZoneFinder& finder,
  210. const isc::dns::Name& name, bool match);
  211. public:
  212. /// Constructor from query parameters.
  213. ///
  214. /// This constructor never throws an exception.
  215. ///
  216. /// \param datasrc_client The datasource wherein the answer to the query is
  217. /// to be found.
  218. /// \param qname The query name
  219. /// \param qtype The RR type of the query
  220. /// \param response The response message to store the answer to the query.
  221. /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
  222. /// possible.
  223. Query(const isc::datasrc::DataSourceClient& datasrc_client,
  224. const isc::dns::Name& qname, const isc::dns::RRType& qtype,
  225. isc::dns::Message& response, bool dnssec = false) :
  226. datasrc_client_(datasrc_client), qname_(qname), qtype_(qtype),
  227. response_(response), dnssec_(dnssec),
  228. dnssec_opt_(dnssec ? isc::datasrc::ZoneFinder::FIND_DNSSEC :
  229. isc::datasrc::ZoneFinder::FIND_DEFAULT)
  230. {}
  231. /// Process the query.
  232. ///
  233. /// This method first identifies the zone that best matches the query
  234. /// name (and in some cases RR type when the search is dependent on the
  235. /// type) and then searches the zone for an entry that best matches the
  236. /// query name.
  237. /// It then updates the response message accordingly; for example, a
  238. /// successful search would result in adding a corresponding RRset to
  239. /// the answer section of the response.
  240. ///
  241. /// If no matching zone is found in the datasource, the RCODE of
  242. /// SERVFAIL will be set in the response.
  243. /// <b>Note:</b> this is different from the error code that BIND 9 returns
  244. /// by default when it's configured as an authoritative-only server (and
  245. /// from the behavior of the BIND 10 datasrc library, which was implemented
  246. /// to be compatible with BIND 9).
  247. /// The difference comes from the fact that BIND 9 returns REFUSED as a
  248. /// result of access control check on the use of its cache.
  249. /// Since BIND 10's authoritative server doesn't have the notion of cache
  250. /// by design, it doesn't make sense to return REFUSED. On the other hand,
  251. /// providing compatible behavior may have its own benefit, so this point
  252. /// should be revisited later.
  253. ///
  254. /// This might throw BadZone or any of its specific subclasses, but that
  255. /// shouldn't happen in real-life (as BadZone means wrong data, it should
  256. /// have been rejected upon loading).
  257. void process();
  258. /// \short Bad zone data encountered.
  259. ///
  260. /// This is thrown when process encounteres misconfigured zone in a way
  261. /// it can't continue. This throws, not sets the Rcode, because such
  262. /// misconfigured zone should not be present in the data source and
  263. /// should have been rejected sooner.
  264. struct BadZone : public isc::Exception {
  265. BadZone(const char* file, size_t line, const char* what) :
  266. Exception(file, line, what)
  267. {}
  268. };
  269. /// \short Zone is missing its SOA record.
  270. ///
  271. /// We tried to add a SOA into the authoritative section, but the zone
  272. /// does not contain one.
  273. struct NoSOA : public BadZone {
  274. NoSOA(const char* file, size_t line, const char* what) :
  275. BadZone(file, line, what)
  276. {}
  277. };
  278. /// \short Zone is missing its apex NS records.
  279. ///
  280. /// We tried to add apex NS records into the authority section, but the
  281. /// zone does not contain any.
  282. struct NoApexNS: public BadZone {
  283. NoApexNS(const char* file, size_t line, const char* what) :
  284. BadZone(file, line, what)
  285. {}
  286. };
  287. /// An invalid result is given when a valid NSEC is expected
  288. ///
  289. /// This can only happen when the underlying data source implementation or
  290. /// the zone is broken. By throwing an exception we treat such cases
  291. /// as SERVFAIL.
  292. struct BadNSEC : public BadZone {
  293. BadNSEC(const char* file, size_t line, const char* what) :
  294. BadZone(file, line, what)
  295. {}
  296. };
  297. /// An invalid result is given when a valid NSEC3 is expected
  298. ///
  299. /// This can only happen when the underlying data source implementation or
  300. /// the zone is broken. By throwing an exception we treat such cases
  301. /// as SERVFAIL.
  302. struct BadNSEC3 : public BadZone {
  303. BadNSEC3(const char* file, size_t line, const char* what) :
  304. BadZone(file, line, what)
  305. {}
  306. };
  307. /// An invalid result is given when a valid DS records (or NXRRSET) is
  308. /// expected
  309. ///
  310. /// This can only happen when the underlying data source implementation
  311. /// or the zone is broken. A DS query for a known delegation point should
  312. /// either result in SUCCESS (if available) or NXRRSET
  313. struct BadDS : public BadZone {
  314. BadDS(const char* file, size_t line, const char* what) :
  315. BadZone(file, line, what)
  316. {}
  317. };
  318. private:
  319. const isc::datasrc::DataSourceClient& datasrc_client_;
  320. const isc::dns::Name& qname_;
  321. const isc::dns::RRType& qtype_;
  322. isc::dns::Message& response_;
  323. const bool dnssec_;
  324. const isc::datasrc::ZoneFinder::FindOptions dnssec_opt_;
  325. };
  326. }
  327. }
  328. // Local Variables:
  329. // mode: c++
  330. // End: