query_unittest.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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 <dns/message.h>
  15. #include <dns/name.h>
  16. #include <dns/rcode.h>
  17. #include <dns/rrttl.h>
  18. #include <dns/rrtype.h>
  19. #include <dns/rdataclass.h>
  20. #include <datasrc/memory_datasrc.h>
  21. #include <auth/query.h>
  22. #include <gtest/gtest.h>
  23. using namespace isc::dns;
  24. using namespace isc::datasrc;
  25. using namespace isc::auth;
  26. namespace {
  27. RRsetPtr a_rrset = RRsetPtr(new RRset(Name("www.example.com"),
  28. RRClass::IN(), RRType::A(),
  29. RRTTL(3600)));
  30. RRsetPtr soa_rrset = RRsetPtr(new RRset(Name("example.com"),
  31. RRClass::IN(), RRType::SOA(),
  32. RRTTL(3600)));
  33. RRsetPtr ns_rrset(RRsetPtr(new RRset(Name("ns.example.com"),
  34. RRClass::IN(), RRType::NS(),
  35. RRTTL(3600))));
  36. RRsetPtr glue_a_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
  37. RRClass::IN(), RRType::A(),
  38. RRTTL(3600))));
  39. RRsetPtr glue_aaaa_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
  40. RRClass::IN(), RRType::AAAA(),
  41. RRTTL(3600))));
  42. RRsetPtr noglue_a_rrset(RRsetPtr(new RRset(Name("noglue.example.com"),
  43. RRClass::IN(), RRType::A(),
  44. RRTTL(3600))));
  45. // This is a mock Zone class for testing.
  46. // It is a derived class of Zone, and simply hardcode the results of find()
  47. // return SUCCESS for "www.example.com",
  48. // return NXDOMAIN for "nxdomain.example.com",
  49. // return NXRRSET for "nxrrset.example.com",
  50. // return CNAME for "cname.example.com",
  51. // otherwise return DNAME
  52. class MockZone : public Zone {
  53. public:
  54. MockZone(bool has_SOA = true) :
  55. origin_(Name("example.com")),
  56. has_SOA_(has_SOA),
  57. delegation_rrset(RRsetPtr(new RRset(Name("delegation.example.com"),
  58. RRClass::IN(), RRType::NS(),
  59. RRTTL(3600)))),
  60. cname_rrset(RRsetPtr(new RRset(Name("cname.example.com"),
  61. RRClass::IN(), RRType::CNAME(),
  62. RRTTL(3600))))
  63. {
  64. delegation_rrset->addRdata(rdata::generic::NS(
  65. Name("glue.ns.example.com")));
  66. delegation_rrset->addRdata(rdata::generic::NS(
  67. Name("noglue.example.com")));
  68. delegation_rrset->addRdata(rdata::generic::NS(
  69. Name("cname.example.com")));
  70. delegation_rrset->addRdata(rdata::generic::NS(
  71. Name("example.org")));
  72. cname_rrset->addRdata(rdata::generic::CNAME(
  73. Name("www.example.com")));
  74. }
  75. virtual const isc::dns::Name& getOrigin() const;
  76. virtual const isc::dns::RRClass& getClass() const;
  77. FindResult find(const isc::dns::Name& name,
  78. const isc::dns::RRType& type,
  79. const FindOptions options = FIND_DEFAULT) const;
  80. private:
  81. Name origin_;
  82. bool has_SOA_;
  83. RRsetPtr delegation_rrset;
  84. RRsetPtr cname_rrset;
  85. };
  86. const Name&
  87. MockZone::getOrigin() const {
  88. return (origin_);
  89. }
  90. const RRClass&
  91. MockZone::getClass() const {
  92. return (RRClass::IN());
  93. }
  94. Zone::FindResult
  95. MockZone::find(const Name& name, const RRType& type,
  96. const FindOptions options) const
  97. {
  98. // hardcode the find results
  99. if (name == Name("www.example.com")) {
  100. return (FindResult(SUCCESS, a_rrset));
  101. } else if (name == Name("glue.ns.example.com") && type == RRType::A() &&
  102. options == FIND_GLUE_OK) {
  103. return (FindResult(SUCCESS, glue_a_rrset));
  104. } else if (name == Name("noglue.example.com") && type == RRType::A()) {
  105. return (FindResult(SUCCESS, noglue_a_rrset));
  106. } else if (name == Name("glue.ns.example.com") && type == RRType::AAAA() &&
  107. options == FIND_GLUE_OK) {
  108. return (FindResult(SUCCESS, glue_aaaa_rrset));
  109. } else if (name == Name("example.com") && type == RRType::SOA() &&
  110. has_SOA_)
  111. {
  112. return (FindResult(SUCCESS, soa_rrset));
  113. } else if (name == Name("delegation.example.com")) {
  114. return (FindResult(DELEGATION, delegation_rrset));
  115. } else if (name == Name("ns.example.com")) {
  116. return (FindResult(DELEGATION, ns_rrset));
  117. } else if (name == Name("nxdomain.example.com")) {
  118. return (FindResult(NXDOMAIN, RRsetPtr()));
  119. } else if (name == Name("nxrrset.example.com")) {
  120. return (FindResult(NXRRSET, RRsetPtr()));
  121. } else if ((name == Name("cname.example.com"))) {
  122. return (FindResult(CNAME, cname_rrset));
  123. } else {
  124. return (FindResult(DNAME, RRsetPtr()));
  125. }
  126. }
  127. class QueryTest : public ::testing::Test {
  128. protected:
  129. QueryTest() :
  130. qname(Name("www.example.com")), qclass(RRClass::IN()),
  131. qtype(RRType::A()), response(Message::RENDER),
  132. query(memory_datasrc, qname, qtype, response)
  133. {
  134. response.setRcode(Rcode::NOERROR());
  135. }
  136. MemoryDataSrc memory_datasrc;
  137. const Name qname;
  138. const RRClass qclass;
  139. const RRType qtype;
  140. Message response;
  141. Query query;
  142. };
  143. TEST_F(QueryTest, noZone) {
  144. // There's no zone in the memory datasource. So the response should have
  145. // REFUSED.
  146. query.process();
  147. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  148. }
  149. TEST_F(QueryTest, matchZone) {
  150. // add a matching zone.
  151. memory_datasrc.addZone(ZonePtr(new MockZone()));
  152. query.process();
  153. EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
  154. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  155. EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
  156. Name("www.example.com"), RRClass::IN(),
  157. RRType::A()));
  158. // Delegation
  159. const Name delegation_name(Name("delegation.example.com"));
  160. Query delegation_query(memory_datasrc, delegation_name, qtype, response);
  161. delegation_query.process();
  162. EXPECT_FALSE(response.getHeaderFlag(Message::HEADERFLAG_AA));
  163. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  164. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  165. Name("delegation.example.com"),
  166. RRClass::IN(), RRType::NS()));
  167. // glue address records
  168. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  169. Name("glue.ns.example.com"),
  170. RRClass::IN(), RRType::A()));
  171. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  172. Name("glue.ns.example.com"),
  173. RRClass::IN(), RRType::AAAA()));
  174. // noglue address records
  175. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  176. Name("noglue.example.com"),
  177. RRClass::IN(), RRType::A()));
  178. // NS name has a CNAME
  179. EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
  180. Name("www.example.com"),
  181. RRClass::IN(), RRType::A()));
  182. // NS name is out of zone
  183. EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
  184. Name("example.org"),
  185. RRClass::IN(), RRType::A()));
  186. // NXDOMAIN
  187. const Name nxdomain_name(Name("nxdomain.example.com"));
  188. Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
  189. nxdomain_query.process();
  190. EXPECT_EQ(Rcode::NXDOMAIN(), response.getRcode());
  191. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ANSWER));
  192. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ADDITIONAL));
  193. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  194. Name("example.com"), RRClass::IN(), RRType::SOA()));
  195. // NXRRSET
  196. const Name nxrrset_name(Name("nxrrset.example.com"));
  197. Query nxrrset_query(memory_datasrc, nxrrset_name, qtype, response);
  198. nxrrset_query.process();
  199. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  200. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ANSWER));
  201. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ADDITIONAL));
  202. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  203. Name("example.com"), RRClass::IN(), RRType::SOA()));
  204. }
  205. /*
  206. * This tests that when there's no SOA and we need a negative answer. It should
  207. * throw in that case.
  208. */
  209. TEST_F(QueryTest, noSOA) {
  210. memory_datasrc.addZone(ZonePtr(new MockZone(false)));
  211. // The NX Domain
  212. const Name nxdomain_name(Name("nxdomain.example.com"));
  213. Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
  214. EXPECT_THROW(nxdomain_query.process(), Query::NoSOA);
  215. // Of course, we don't look into the response, as it throwed
  216. // NXRRSET
  217. const Name nxrrset_name(Name("nxrrset.example.com"));
  218. Query nxrrset_query(memory_datasrc, nxrrset_name, qtype, response);
  219. EXPECT_THROW(nxrrset_query.process(), Query::NoSOA);
  220. }
  221. TEST_F(QueryTest, noMatchZone) {
  222. // there's a zone in the memory datasource but it doesn't match the qname.
  223. // should result in REFUSED.
  224. memory_datasrc.addZone(ZonePtr(new MockZone()));
  225. const Name nomatch_name(Name("example.org"));
  226. Query nomatch_query(memory_datasrc, nomatch_name, qtype, response);
  227. nomatch_query.process();
  228. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  229. }
  230. }