query.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. // $Id$
  15. #ifndef __QUERY_H
  16. #define __QUERY_H
  17. #include <queue>
  18. #include <exceptions/exceptions.h>
  19. #include <dns/name.h>
  20. #include <dns/message.h>
  21. #include <dns/rrset.h>
  22. #include <dns/rrclass.h>
  23. #include <dns/rrtype.h>
  24. using namespace isc::dns;
  25. namespace isc {
  26. namespace auth {
  27. // An individual task to be carried out by the query logic
  28. class QueryTask {
  29. public:
  30. // XXX: Members are currently public, but should probably be
  31. // moved to private and wrapped in get() functions later.
  32. // The standard query tuple: qname/qclass/qtype.
  33. // Note that qtype is ignored in the GLUE_QUERY/NOGLUE_QUERY case.
  34. const Name& qname;
  35. const RRClass& qclass;
  36. const RRType& qtype;
  37. // Optional: name for the containing zone, if known.
  38. // This is particularly needed when looking up data in a
  39. // zone other than the closest enclosure (such as getting
  40. // DS queries from a parent zone on a server which serves
  41. // both parent and child).
  42. Name* zone;
  43. // The section of the reply into which the data should be
  44. // written after it has been fetched from the data source.
  45. const Section& section;
  46. // The op field indicates the operation to be carried out by
  47. // this query task:
  48. //
  49. // - SIMPLE_QUERY: look for a match for qname/qclass/qtype
  50. // in local data (regardless of whether it is above or below
  51. // a zone cut).
  52. //
  53. // - AUTH_QUERY: look for a match for qname/qclass/qtype, or
  54. // for qname/qclass/CNAME, or for a referral.
  55. //
  56. // - GLUE_QUERY: look for matches with qname/qclass/A
  57. // OR qname/class/AAAA in local data, regardless of
  58. // authority, for use in glue. (This can be implemented
  59. // as two successive SIMPLE_QUERY tasks, but might be
  60. // optimized by the concrete data source implementation
  61. // by turning it into a single database lookup.)
  62. //
  63. // - NOGLUE_QUERY: same as GLUE_QUERY except that answers
  64. // are rejected if they are below a zone cut.
  65. //
  66. // - REF_QUERY: look for matches for qname/qclass/NS,
  67. // qname/qclass/DS, and qname/qclass/DNAME. Used
  68. // to search for a zone cut.
  69. const enum Op {
  70. SIMPLE_QUERY,
  71. AUTH_QUERY,
  72. GLUE_QUERY,
  73. NOGLUE_QUERY,
  74. REF_QUERY,
  75. } op;
  76. // The state field indicates the state of the query; it controls
  77. // the next step after processing each query task.
  78. //
  79. // - GETANSWER: We are looking for the answer to a primary query.
  80. // (The qname of the task should exactly match the qname of the
  81. // query.) If we have no match, the query has failed.
  82. //
  83. // - GETADDITIONAL: We are filling in additional data, either
  84. // as a result of finding NS or MX records via a GETANSWER
  85. // query task, or as a result of finding NS records when
  86. // getting authority-section data.
  87. //
  88. // - FOLLOWCNAME: We are looking for the target of a CNAME RR that
  89. // was found via a previous GETANSWER query task. If we have no
  90. // match, the query is still successful.
  91. //
  92. // (NOTE: It is only necessary to set a task state when pushing
  93. // tasks onto the query task queue, which in turn is only necessary
  94. // when it's uncertain which data source will be authoritative for the
  95. // data. That's why there is no GETAUTHORITY task state; when
  96. // processing an answer, either positive or negative, the authoritative
  97. // data source will already have been discovered, and can be queried
  98. // directly.)
  99. enum State {
  100. GETANSWER,
  101. GETADDITIONAL,
  102. FOLLOWCNAME
  103. } state;
  104. // Response flags to indicate conditions encountered while
  105. // processing this task.
  106. uint32_t flags;
  107. // Constructors
  108. QueryTask(const Name& n, const RRClass& c,
  109. const RRType& t, const Section& sect) :
  110. qname(n), qclass(c), qtype(t), zone(NULL),
  111. section(sect), op(AUTH_QUERY), state(GETANSWER), flags(0) {}
  112. QueryTask(const Name& n, const RRClass& c,
  113. const RRType& t, const Section& sect, const Op o) :
  114. qname(n), qclass(c), qtype(t), zone(NULL),
  115. section(sect), op(o), state(GETANSWER), flags(0) {}
  116. QueryTask(const Name& n, const RRClass& c,
  117. const RRType& t, const Section& sect, const State st) :
  118. qname(n), qclass(c), qtype(t), zone(NULL),
  119. section(sect), op(AUTH_QUERY), state(st), flags(0) {}
  120. QueryTask(const Name& n, const RRClass& c,
  121. const RRType& t, const Section& sect,
  122. const Op o, const State st) :
  123. qname(n), qclass(c), qtype(t), zone(NULL),
  124. section(sect), op(o), state(st), flags(0) {}
  125. // These are special constructors for particular query task types,
  126. // to simplify the code.
  127. //
  128. // A simple query doesn't need to specify section or state.
  129. QueryTask(const Name& n, const RRClass& c, const RRType& t, const Op o) :
  130. qname(n), qclass(c), qtype(t), zone(NULL),
  131. section(Section::ANSWER()), op(o), state(GETANSWER), flags(0) {
  132. if (op != SIMPLE_QUERY) {
  133. throw "invalid constructor for this task operation";
  134. }
  135. }
  136. // A referral query doesn't need to specify section, state, or type.
  137. QueryTask(const Name& n, const RRClass& c, const Op o) :
  138. qname(n), qclass(c), qtype(RRType::ANY()), zone(NULL),
  139. section(Section::ANSWER()), op(o), state(GETANSWER), flags(0) {
  140. if (op != REF_QUERY) {
  141. throw "invalid constructor for this task operation";
  142. }
  143. }
  144. // A glue (or noglue) query doesn't need to specify type.
  145. QueryTask(const Name& n, const RRClass& c,
  146. const Section& sect, const Op o, const State st) :
  147. qname(n), qclass(c), qtype(RRType::ANY()), zone(NULL),
  148. section(sect), op(o), state(st), flags(0) {
  149. if (op != GLUE_QUERY && op != NOGLUE_QUERY) {
  150. throw "invalid constructor for this task operation";
  151. }
  152. }
  153. virtual ~QueryTask();
  154. };
  155. typedef boost::shared_ptr<QueryTask> QueryTaskPtr;
  156. typedef std::queue<QueryTaskPtr> QueryTaskQueue;
  157. class Query;
  158. typedef boost::shared_ptr<Query> QueryPtr;
  159. // Data Source query
  160. class Query {
  161. public:
  162. // The state of a query: pending or answered.
  163. enum Status {
  164. PENDING,
  165. ANSWERED
  166. };
  167. // Query constructor
  168. Query(Message& m, bool dnssec) {
  169. message_ = &m;
  170. want_additional_ = true;
  171. want_dnssec_ = dnssec;
  172. status_ = PENDING;
  173. // Check message formatting
  174. if (message_->getRRCount(Section::QUESTION()) != 1) {
  175. dns_throw(Unexpected, "malformed message: too many questions");
  176. }
  177. // Populate the query task queue with the initial question
  178. QuestionPtr query = *message_->beginQuestion();
  179. qname_ = &query->getName();
  180. qclass_ = &query->getClass();
  181. qtype_ = &query->getType();
  182. QueryTaskPtr initial_task(new QueryTask(*qname_, *qclass_, *qtype_,
  183. Section::ANSWER()));
  184. querytasks_.push(initial_task);
  185. };
  186. virtual ~Query();
  187. // wantAdditional() == true indicates that additional-section data
  188. // should be looked up while processing this query. false indicates
  189. // that we're only interested in answer-section data
  190. bool wantAdditional() { return want_additional_; }
  191. void setWantAdditional(bool d) { want_additional_ = d; }
  192. // wantDnssec() == true indicates that DNSSEC data should be retrieved
  193. // from the data source when this query is being processed
  194. bool wantDnssec() const { return want_dnssec_; }
  195. void setWantDnssec(bool d) { want_dnssec_ = d; }
  196. const Name& qname() const { return *qname_; }
  197. const RRClass& qclass() const { return *qclass_; }
  198. const RRType& qtype() const { return *qtype_; }
  199. Message& message() const { return *message_; }
  200. QueryTaskQueue& tasks() { return querytasks_; }
  201. Status status() const { return status_; }
  202. void setStatus(Status s) { status_ = s; }
  203. private:
  204. Status status_;
  205. const Name* qname_;
  206. const RRClass* qclass_;
  207. const RRType* qtype_;
  208. Message* message_;
  209. QueryTaskQueue querytasks_;
  210. bool want_additional_;
  211. bool want_dnssec_;
  212. };
  213. }
  214. }
  215. #endif
  216. // Local Variables:
  217. // mode: c++
  218. // End: