query.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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 <boost/noncopyable.hpp>
  20. #include <functional>
  21. #include <vector>
  22. namespace isc {
  23. namespace dns {
  24. class Message;
  25. class Name;
  26. class RRType;
  27. class RRset;
  28. }
  29. namespace datasrc {
  30. class DataSourceClient;
  31. }
  32. namespace auth {
  33. /// The \c Query class represents a standard DNS query that encapsulates
  34. /// processing logic to answer the query.
  35. ///
  36. /// Many of the design details for this class are still in flux.
  37. /// We'll revisit and update them as we add more functionality, for example:
  38. /// - as a related point, we may have to pass the RR class of the query.
  39. /// in the initial implementation the RR class is an attribute of
  40. /// datasource and omitted. It's not clear if this assumption holds with
  41. /// generic data sources. On the other hand, it will help keep
  42. /// implementation simpler, and we might rather want to modify the design
  43. /// of the data source on this point.
  44. /// - return value of process(). rather than or in addition to setting the
  45. /// Rcode, we might use it as a return value of \c process().
  46. /// - we'll have to be able to specify whether DNSSEC is requested.
  47. /// It's an open question whether it should be in the constructor or via a
  48. /// separate attribute setter.
  49. /// - likewise, we'll eventually need to do per zone access control, for which
  50. /// we need querier's information such as its IP address.
  51. /// - datasrc_client and response may better be parameters to process() instead
  52. /// of the constructor.
  53. ///
  54. /// <b>Note:</b> The class name is intentionally the same as the one used in
  55. /// the datasrc library. This is because the plan is to eventually merge
  56. /// the two classes. We could give it a different name such as "AuthQuery"
  57. /// to avoid possible ambiguity, but it may sound redundant in that it's
  58. /// obvious that this class is for authoritative queries.
  59. /// Since the interfaces are very different for now and it's less
  60. /// likely to misuse one of the classes instead of the other
  61. /// accidentally, and since it's considered a temporary development state,
  62. /// we keep this name at the moment.
  63. class Query : boost::noncopyable {
  64. private:
  65. /// \brief Initial reserved size for the vectors in Query
  66. ///
  67. /// The value is larger than we expect the vectors to even become, and
  68. /// has been chosen arbitrarily. The reason to set them quite high is
  69. /// to prevent reallocation on addition.
  70. static const size_t RESERVE_RRSETS = 64;
  71. /// \brief Adds a SOA.
  72. ///
  73. /// Adds a SOA of the zone into the authority zone of response_.
  74. /// Can throw NoSOA.
  75. ///
  76. void addSOA(isc::datasrc::ZoneFinder& finder);
  77. /// \brief Adds the DS rrset for the given name, if available
  78. ///
  79. /// This is intended to be called when returning a delegation, and
  80. /// if DNSSEC data is requested. If the DS record is not found
  81. /// (signaled by find() returning NXRRSET), and the zone is signed
  82. /// with NSEC, an NSEC denial of existence proof is added.
  83. ///
  84. /// \exception BadDS raised if find() returns anything other than
  85. /// SUCCESS or NXRRSET when searching for the DS
  86. /// record.
  87. /// \param finder The ZoneFinder where the delegation was found
  88. /// \param ds_name The name of the delegation RRset
  89. void addDS(isc::datasrc::ZoneFinder& finder,
  90. const isc::dns::Name& ds_name);
  91. /// \brief Adds NSEC(3) denial proof for the given NXRRset result
  92. ///
  93. /// If available, NSEC or NSEC3 records are added to the authority
  94. /// section (depending on whether isNSECSigned() or isNSEC3Signed()
  95. /// returns true).
  96. ///
  97. /// \param finder The ZoneFinder that was used to search for the missing
  98. /// data
  99. /// \param db_result The ZoneFinder::FindResult returned by find()
  100. void addNXRRsetProof(isc::datasrc::ZoneFinder& finder,
  101. const isc::datasrc::ZoneFinder::Context& db_context);
  102. /// Add NSEC RRs that prove an NXDOMAIN result.
  103. ///
  104. /// This corresponds to Section 3.1.3.2 of RFC 4035.
  105. void addNXDOMAINProofByNSEC(isc::datasrc::ZoneFinder& finder,
  106. isc::dns::ConstRRsetPtr nsec);
  107. /// Add NSEC3 RRs that prove an NXDOMAIN result.
  108. ///
  109. /// This corresponds to Section 7.2.2 of RFC 5155.
  110. void addNXDOMAINProofByNSEC3(isc::datasrc::ZoneFinder& finder);
  111. /// Add NSEC or NSEC3 RRs that prove a wildcard answer is the best one.
  112. ///
  113. /// This corresponds to Section 3.1.3.3 of RFC 4035 and Section 7.2.6
  114. /// of RFC5155.
  115. void addWildcardProof(
  116. isc::datasrc::ZoneFinder& finder,
  117. const isc::datasrc::ZoneFinder::Context& db_context);
  118. /// \brief Adds one NSEC RR proved no matched QNAME,one NSEC RR proved no
  119. /// matched <QNAME,QTYPE> through wildcard extension.
  120. ///
  121. /// Add NSEC RRs that prove an WILDCARD_NXRRSET result.
  122. /// This corresponds to Section 3.1.3.4 of RFC 4035.
  123. /// \param finder The ZoneFinder through which the authority data for the
  124. /// query is to be found.
  125. /// \param nsec The RRset (NSEC RR) which proved that there is no matched
  126. /// <QNAME,QTTYPE>.
  127. void addWildcardNXRRSETProof(isc::datasrc::ZoneFinder& finder,
  128. isc::dns::ConstRRsetPtr nsec);
  129. /// \brief Look up a zone's NS RRset and their address records for an
  130. /// authoritative answer, and add them to the additional section.
  131. ///
  132. /// On returning an authoritative answer, insert a zone's NS into the
  133. /// authority section and AAAA/A RRs of each of the NS RDATA into the
  134. /// additional section.
  135. ///
  136. /// <b>Notes to developer:</b>
  137. ///
  138. /// We should omit address records which has already been provided in the
  139. /// answer section from the additional.
  140. ///
  141. /// For now, in order to optimize the additional section processing, we
  142. /// include AAAA/A RRs under a zone cut in additional section. (BIND 9
  143. /// excludes under-cut RRs; NSD include them.)
  144. ///
  145. /// \param finder The \c ZoneFinder through which the NS and additional
  146. /// data for the query are to be found.
  147. void addAuthAdditional(isc::datasrc::ZoneFinder& finder,
  148. std::vector<isc::dns::ConstRRsetPtr>& additionals);
  149. /// \brief Process a DS query possible at the child side of zone cut.
  150. ///
  151. /// This private method is a subroutine of process(), and is called if
  152. /// there's a possibility that this server has authority for the child
  153. /// side of the DS's owner name (and it's detected that the server at
  154. /// least doesn't have authority at the parent side). This method
  155. /// first checks if it has authority for the child, and if does,
  156. /// just build a "no data" response with SOA for the zone origin
  157. /// (possibly with a proof for the no data) as specified in Section
  158. /// 2.2.1.1 of RFC3658.
  159. ///
  160. /// It returns true if this server has authority of the child; otherwise
  161. /// it returns false. In the former case, the caller is expected to
  162. /// terminate the query processing, because it should have been completed
  163. /// within this method.
  164. bool processDSAtChild();
  165. /// \brief Add NSEC3 to the response for a closest encloser proof for a
  166. /// given name.
  167. ///
  168. /// This method calls \c findNSEC3() of the given zone finder for the
  169. /// given name in the recursive mode, and adds the returned NSEC3(s) to
  170. /// the authority section of the response message associated with the
  171. /// \c Query object.
  172. ///
  173. /// It returns the number of labels of the closest encloser (returned via
  174. /// the \c findNSEC3() call) in case the caller needs to use that value
  175. /// for subsequent processing, i.e, constructing the best possible wildcard
  176. /// name that (would) match the query name.
  177. ///
  178. /// Unless \c exact_ok is true, \c name is expected to be non existent,
  179. /// in which case findNSEC3() in the recursive mode must return both
  180. /// closest and next proofs. If the latter is NULL, it means a run time
  181. /// collision (or the zone is broken in other way), and this method throws
  182. /// a BadNSEC3 exception.
  183. ///
  184. /// If \c exact_ok is true, this method takes into account the case
  185. /// where the name exists and may or may not be at a zone cut to an
  186. /// optout zone. In this case, depending on whether the zone is optout
  187. /// or not, findNSEC3() may return non-NULL or NULL next_proof
  188. /// (respectively). This method adds the next proof if and only if
  189. /// findNSEC3() returns non NULL value for it. The Opt-Out flag
  190. /// must be set or cleared accordingly, but this method doesn't check that
  191. /// in this level (as long as the zone is signed validly and findNSEC3()
  192. /// for the data source is implemented as documented, the condition
  193. /// should be met; otherwise we'd let the validator detect the error).
  194. ///
  195. /// By default this method always adds the closest proof.
  196. /// If \c add_closest is false, it only adds the next proof to the message.
  197. /// This correspond to the case of "wildcard answer responses" as described
  198. /// in Section 7.2.6 of RFC5155.
  199. uint8_t addClosestEncloserProof(isc::datasrc::ZoneFinder& finder,
  200. const isc::dns::Name& name, bool exact_ok,
  201. bool add_closest = true);
  202. /// \brief Add matching or covering NSEC3 to the response for a give name.
  203. ///
  204. /// This method calls \c findNSEC3() of the given zone finder for the
  205. /// given name in the non recursive mode, and adds the returned NSEC3 to
  206. /// the authority section of the response message associated with the
  207. /// \c Query object.
  208. ///
  209. /// Depending on the caller's context, the returned NSEC3 is one and
  210. /// only one of matching or covering NSEC3. If \c match is true the
  211. /// returned NSEC3 must be a matching one; otherwise it must be a covering
  212. /// one. If this assumption isn't met this method throws a BadNSEC3
  213. /// exception (if it must be a matching NSEC3 but is not, it means a broken
  214. /// zone, maybe with incorrect optout NSEC3s; if it must be a covering
  215. /// NSEC3 but is not, it means a run time collision; or the \c findNSEC3()
  216. /// implementation is broken for both cases.)
  217. void addNSEC3ForName(isc::datasrc::ZoneFinder& finder,
  218. const isc::dns::Name& name, bool match);
  219. /// Set up the Query object for a new query lookup
  220. ///
  221. /// This is the first step of the process() method, and initializes
  222. /// the member data
  223. ///
  224. /// \param datasrc_client The datasource wherein the answer to the query is
  225. /// to be found.
  226. /// \param qname The query name
  227. /// \param qtype The RR type of the query
  228. /// \param response The response message to store the answer to the query.
  229. /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
  230. /// possible.
  231. void initialize(datasrc::DataSourceClient& datasrc_client,
  232. const isc::dns::Name& qname, const isc::dns::RRType& qtype,
  233. isc::dns::Message& response, bool dnssec = false);
  234. /// \brief Resets any partly built response data, and internal pointers
  235. ///
  236. /// Called by the QueryCleaner object upon its destruction
  237. void reset();
  238. /// \brief Internal class used for cleanup of Query members
  239. ///
  240. /// The process() call creates an object of this class, which
  241. /// upon its destruction, calls Query::reset(), so that outside
  242. /// of single calls to process(), the query state is always clean.
  243. class QueryCleaner {
  244. public:
  245. QueryCleaner(isc::auth::Query& query) : query_(query) {}
  246. ~QueryCleaner() { query_.reset(); }
  247. private:
  248. isc::auth::Query& query_;
  249. };
  250. protected:
  251. // Following methods declared protected so they can be accessed
  252. // by unit tests.
  253. void createResponse();
  254. public:
  255. /// Default constructor.
  256. ///
  257. /// Query parameters will be set by the call to process()
  258. ///
  259. Query() :
  260. datasrc_client_(NULL), qname_(NULL), qtype_(NULL),
  261. dnssec_(false), dnssec_opt_(isc::datasrc::ZoneFinder::FIND_DEFAULT),
  262. response_(NULL)
  263. {
  264. answers_.reserve(RESERVE_RRSETS);
  265. authorities_.reserve(RESERVE_RRSETS);
  266. additionals_.reserve(RESERVE_RRSETS);
  267. }
  268. /// Process the query.
  269. ///
  270. /// This method first identifies the zone that best matches the query
  271. /// name (and in some cases RR type when the search is dependent on the
  272. /// type) and then searches the zone for an entry that best matches the
  273. /// query name.
  274. /// It then updates the response message accordingly; for example, a
  275. /// successful search would result in adding a corresponding RRset to
  276. /// the answer section of the response.
  277. ///
  278. /// If no matching zone is found in the datasource, the RCODE of
  279. /// SERVFAIL will be set in the response.
  280. /// <b>Note:</b> this is different from the error code that BIND 9 returns
  281. /// by default when it's configured as an authoritative-only server (and
  282. /// from the behavior of the BIND 10 datasrc library, which was implemented
  283. /// to be compatible with BIND 9).
  284. /// The difference comes from the fact that BIND 9 returns REFUSED as a
  285. /// result of access control check on the use of its cache.
  286. /// Since BIND 10's authoritative server doesn't have the notion of cache
  287. /// by design, it doesn't make sense to return REFUSED. On the other hand,
  288. /// providing compatible behavior may have its own benefit, so this point
  289. /// should be revisited later.
  290. ///
  291. /// This might throw BadZone or any of its specific subclasses, but that
  292. /// shouldn't happen in real-life (as BadZone means wrong data, it should
  293. /// have been rejected upon loading).
  294. ///
  295. /// \param datasrc_client The datasource wherein the answer to the query is
  296. /// to be found.
  297. /// \param qname The query name
  298. /// \param qtype The RR type of the query
  299. /// \param response The response message to store the answer to the query.
  300. /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
  301. /// possible.
  302. void process(datasrc::DataSourceClient& datasrc_client,
  303. const isc::dns::Name& qname, const isc::dns::RRType& qtype,
  304. isc::dns::Message& response, bool dnssec = false);
  305. /// \short Bad zone data encountered.
  306. ///
  307. /// This is thrown when process encounteres misconfigured zone in a way
  308. /// it can't continue. This throws, not sets the Rcode, because such
  309. /// misconfigured zone should not be present in the data source and
  310. /// should have been rejected sooner.
  311. struct BadZone : public isc::Exception {
  312. BadZone(const char* file, size_t line, const char* what) :
  313. Exception(file, line, what)
  314. {}
  315. };
  316. /// \short Zone is missing its SOA record.
  317. ///
  318. /// We tried to add a SOA into the authoritative section, but the zone
  319. /// does not contain one.
  320. struct NoSOA : public BadZone {
  321. NoSOA(const char* file, size_t line, const char* what) :
  322. BadZone(file, line, what)
  323. {}
  324. };
  325. /// \short Zone is missing its apex NS records.
  326. ///
  327. /// We tried to add apex NS records into the authority section, but the
  328. /// zone does not contain any.
  329. struct NoApexNS: public BadZone {
  330. NoApexNS(const char* file, size_t line, const char* what) :
  331. BadZone(file, line, what)
  332. {}
  333. };
  334. /// An invalid result is given when a valid NSEC is expected
  335. ///
  336. /// This can only happen when the underlying data source implementation or
  337. /// the zone is broken. By throwing an exception we treat such cases
  338. /// as SERVFAIL.
  339. struct BadNSEC : public BadZone {
  340. BadNSEC(const char* file, size_t line, const char* what) :
  341. BadZone(file, line, what)
  342. {}
  343. };
  344. /// An invalid result is given when a valid NSEC3 is expected
  345. ///
  346. /// This can only happen when the underlying data source implementation or
  347. /// the zone is broken. By throwing an exception we treat such cases
  348. /// as SERVFAIL.
  349. struct BadNSEC3 : public BadZone {
  350. BadNSEC3(const char* file, size_t line, const char* what) :
  351. BadZone(file, line, what)
  352. {}
  353. };
  354. /// An invalid result is given when a valid DS records (or NXRRSET) is
  355. /// expected
  356. ///
  357. /// This can only happen when the underlying data source implementation
  358. /// or the zone is broken. A DS query for a known delegation point should
  359. /// either result in SUCCESS (if available) or NXRRSET
  360. struct BadDS : public BadZone {
  361. BadDS(const char* file, size_t line, const char* what) :
  362. BadZone(file, line, what)
  363. {}
  364. };
  365. /// \brief Response Creator Class
  366. ///
  367. /// This is a helper class of Query, and is expected to be used during the
  368. /// construction of the response message. This class performs the
  369. /// duplicate RRset detection check. It keeps a list of RRsets added
  370. /// to the message and does not add an RRset if it is the same as one
  371. /// already added.
  372. ///
  373. /// This class is essentially private to Query, but is visible to public
  374. /// for testing purposes. It's not expected to be used from a normal
  375. /// application.
  376. class ResponseCreator {
  377. public:
  378. /// \brief Constructor
  379. ///
  380. /// Reserves space for the list of RRsets. Although the
  381. /// ResponseCreator will be used to create a message from the
  382. /// contents of the Query object's answers_, authorities_ and
  383. /// additionals_ elements, and each of these are sized to
  384. /// RESERVE_RRSETS, it is _extremely_ unlikely that all three will be
  385. /// filled to capacity. So we reserve more elements than in each of
  386. /// these components, but not three times the amount.
  387. ///
  388. /// As with the answers_, authorities_ and additionals_ elements, the
  389. /// reservation is made in the constructor to avoid dynamic allocation
  390. /// of memory. The ResponseCreator is a member variable of the Query
  391. /// object so is constructed once and lasts as long as that object.
  392. /// Internal state is cleared through the clear() method.
  393. ResponseCreator() {
  394. added_.reserve(2 * RESERVE_RRSETS);
  395. }
  396. /// \brief Reset internal state
  397. void clear() {
  398. added_.clear();
  399. }
  400. /// \brief Complete the response message with filling in the
  401. /// response sections.
  402. ///
  403. /// This is the final step of the Query::process() method, and within
  404. /// that method, it should be called before it returns (if any
  405. /// response data is to be added)
  406. ///
  407. /// This will take a message to build and each RRsets for the answer,
  408. /// authority, and additional sections, and add them to their
  409. /// corresponding sections in the given message. The RRsets are
  410. /// filtered such that a particular RRset appears only once in the
  411. /// message.
  412. ///
  413. /// If \c dnssec is true, it tells the message to include any RRSIGs
  414. /// attached to the RRsets.
  415. void create(
  416. isc::dns::Message& message,
  417. const std::vector<isc::dns::ConstRRsetPtr>& answers_,
  418. const std::vector<isc::dns::ConstRRsetPtr>& authorities_,
  419. const std::vector<isc::dns::ConstRRsetPtr>& additionals_,
  420. const bool dnssec);
  421. private:
  422. // \brief RRset comparison functor.
  423. struct IsSameKind : public std::binary_function<
  424. const isc::dns::AbstractRRset*,
  425. const isc::dns::AbstractRRset*,
  426. bool> {
  427. bool operator()(const isc::dns::AbstractRRset* r1,
  428. const isc::dns::AbstractRRset* r2) const {
  429. return (r1->isSameKind(*r2));
  430. }
  431. };
  432. /// Insertion operation
  433. ///
  434. /// \param message Message to which the RRset is to be added
  435. /// \param section Section of the message in which the RRset is put
  436. /// \param rrset Pointer to RRset to be added to the message
  437. /// \param dnssec Whether RRSIG records should be added as well
  438. void addRRset(isc::dns::Message& message,
  439. const isc::dns::Message::Section section,
  440. const isc::dns::ConstRRsetPtr& rrset, const bool dnssec);
  441. private:
  442. /// List of RRsets already added to the message
  443. std::vector<const isc::dns::AbstractRRset*> added_;
  444. };
  445. private:
  446. const isc::datasrc::DataSourceClient* datasrc_client_;
  447. const isc::dns::Name* qname_;
  448. const isc::dns::RRType* qtype_;
  449. bool dnssec_;
  450. isc::datasrc::ZoneFinder::FindOptions dnssec_opt_;
  451. ResponseCreator response_creator_;
  452. isc::dns::Message* response_;
  453. std::vector<isc::dns::ConstRRsetPtr> answers_;
  454. std::vector<isc::dns::ConstRRsetPtr> authorities_;
  455. std::vector<isc::dns::ConstRRsetPtr> additionals_;
  456. };
  457. }
  458. }
  459. // Local Variables:
  460. // mode: c++
  461. // End: