query_unittest.cc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  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 <sstream>
  15. #include <vector>
  16. #include <map>
  17. #include <boost/bind.hpp>
  18. #include <dns/masterload.h>
  19. #include <dns/message.h>
  20. #include <dns/name.h>
  21. #include <dns/opcode.h>
  22. #include <dns/rcode.h>
  23. #include <dns/rrttl.h>
  24. #include <dns/rrtype.h>
  25. #include <dns/rdataclass.h>
  26. #include <datasrc/memory_datasrc.h>
  27. #include <auth/query.h>
  28. #include <testutils/dnsmessage_test.h>
  29. #include <gtest/gtest.h>
  30. using namespace std;
  31. using namespace isc::dns;
  32. using namespace isc::dns::rdata;
  33. using namespace isc::datasrc;
  34. using namespace isc::auth;
  35. using namespace isc::testutils;
  36. namespace {
  37. // This is the content of the mock zone (see below).
  38. // It's a sequence of textual RRs that is supposed to be parsed by
  39. // dns::masterLoad(). Some of the RRs are also used as the expected
  40. // data in specific tests, in which case they are referenced via specific
  41. // local variables (such as soa_txt).
  42. const char* const soa_txt = "example.com. 3600 IN SOA . . 0 0 0 0 0\n";
  43. const char* const zone_ns_txt =
  44. "example.com. 3600 IN NS glue.delegation.example.com.\n"
  45. "example.com. 3600 IN NS noglue.example.com.\n"
  46. "example.com. 3600 IN NS example.net.\n";
  47. const char* const ns_addrs_txt =
  48. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  49. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n"
  50. "noglue.example.com. 3600 IN A 192.0.2.53\n";
  51. const char* const delegation_txt =
  52. "delegation.example.com. 3600 IN NS glue.delegation.example.com.\n"
  53. "delegation.example.com. 3600 IN NS noglue.example.com.\n"
  54. "delegation.example.com. 3600 IN NS cname.example.com.\n"
  55. "delegation.example.com. 3600 IN NS example.org.\n";
  56. const char* const mx_txt =
  57. "mx.example.com. 3600 IN MX 10 www.example.com.\n"
  58. "mx.example.com. 3600 IN MX 20 mailer.example.org.\n"
  59. "mx.example.com. 3600 IN MX 30 mx.delegation.example.com.\n";
  60. const char* const www_a_txt = "www.example.com. 3600 IN A 192.0.2.80\n";
  61. const char* const cname_txt =
  62. "cname.example.com. 3600 IN CNAME www.example.com.\n";
  63. const char* const cname_nxdom_txt =
  64. "cnamenxdom.example.com. 3600 IN CNAME nxdomain.example.com.\n";
  65. // CNAME Leading out of zone
  66. const char* const cname_out_txt =
  67. "cnameout.example.com. 3600 IN CNAME www.example.org.\n";
  68. // The DNAME to do tests against
  69. const char* const dname_txt =
  70. "dname.example.com. 3600 IN DNAME "
  71. "somethinglong.dnametarget.example.com.\n";
  72. // Some data at the dname node (allowed by RFC 2672)
  73. const char* const dname_a_txt =
  74. "dname.example.com. 3600 IN A 192.0.2.5\n";
  75. // This is not inside the zone, this is created at runtime
  76. const char* const synthetized_cname_txt =
  77. "www.dname.example.com. 3600 IN CNAME "
  78. "www.somethinglong.dnametarget.example.com.\n";
  79. // The rest of data won't be referenced from the test cases.
  80. const char* const other_zone_rrs =
  81. "cnamemailer.example.com. 3600 IN CNAME www.example.com.\n"
  82. "cnamemx.example.com. 3600 IN MX 10 cnamemailer.example.com.\n"
  83. "mx.delegation.example.com. 3600 IN A 192.0.2.100\n";
  84. // NSEC records.
  85. const char* const nsec_apex_txt =
  86. "example.com. 3600 IN NSEC cname.example.com. NS SOA NSEC RRSIG\n";
  87. const char* const nsec_nxdomain_txt =
  88. "noglue.example.com. 3600 IN NSEC www.example.com. A\n";
  89. // A helper function that generates a textual representation of RRSIG RDATA
  90. // for the given covered type. The resulting RRSIG may not necessarily make
  91. // sense in terms of the DNSSEC protocol, but for our testing purposes it's
  92. // okay.
  93. string
  94. getCommonRRSIGText(const string& type) {
  95. return (type +
  96. string(" 5 3 3600 20000101000000 20000201000000 12345 "
  97. "example.com. FAKEFAKEFAKE"));
  98. }
  99. // This is a mock Zone Finder class for testing.
  100. // It is a derived class of ZoneFinder for the convenient of tests.
  101. // Its find() method emulates the common behavior of protocol compliant
  102. // ZoneFinder classes, but simplifies some minor cases and also supports broken
  103. // behavior.
  104. // For simplicity, most names are assumed to be "in zone"; there's only
  105. // one zone cut at the point of name "delegation.example.com".
  106. // Another special name is "dname.example.com". Query names under this name
  107. // will result in DNAME.
  108. // This mock zone doesn't handle empty non terminal nodes (if we need to test
  109. // such cases find() should have specialized code for it).
  110. class MockZoneFinder : public ZoneFinder {
  111. public:
  112. MockZoneFinder() :
  113. origin_(Name("example.com")),
  114. delegation_name_("delegation.example.com"),
  115. dname_name_("dname.example.com"),
  116. has_SOA_(true),
  117. has_apex_NS_(true),
  118. rrclass_(RRClass::IN()),
  119. include_rrsig_anyway_(false)
  120. {
  121. stringstream zone_stream;
  122. zone_stream << soa_txt << zone_ns_txt << ns_addrs_txt <<
  123. delegation_txt << mx_txt << www_a_txt << cname_txt <<
  124. cname_nxdom_txt << cname_out_txt << dname_txt << dname_a_txt <<
  125. other_zone_rrs << nsec_apex_txt << nsec_nxdomain_txt;
  126. masterLoad(zone_stream, origin_, rrclass_,
  127. boost::bind(&MockZoneFinder::loadRRset, this, _1));
  128. }
  129. virtual isc::dns::Name getOrigin() const { return (origin_); }
  130. virtual isc::dns::RRClass getClass() const { return (rrclass_); }
  131. virtual FindResult find(const isc::dns::Name& name,
  132. const isc::dns::RRType& type,
  133. RRsetList* target = NULL,
  134. const FindOptions options = FIND_DEFAULT);
  135. // If false is passed, it makes the zone broken as if it didn't have the
  136. // SOA.
  137. void setSOAFlag(bool on) { has_SOA_ = on; }
  138. // If false is passed, it makes the zone broken as if it didn't have
  139. // the apex NS.
  140. void setApexNSFlag(bool on) { has_apex_NS_ = on; }
  141. // Turn this on if you want it to return RRSIGs regardless of FIND_GLUE_OK
  142. void setIncludeRRSIGAnyway(bool on) { include_rrsig_anyway_ = on; }
  143. Name findPreviousName(const Name&) const {
  144. isc_throw(isc::NotImplemented, "Mock doesn't support previous name");
  145. }
  146. private:
  147. typedef map<RRType, ConstRRsetPtr> RRsetStore;
  148. typedef map<Name, RRsetStore> Domains;
  149. Domains domains_;
  150. void loadRRset(RRsetPtr rrset) {
  151. domains_[rrset->getName()][rrset->getType()] = rrset;
  152. if (rrset->getName() == delegation_name_ &&
  153. rrset->getType() == RRType::NS()) {
  154. delegation_rrset_ = rrset;
  155. } else if (rrset->getName() == dname_name_ &&
  156. rrset->getType() == RRType::DNAME()) {
  157. dname_rrset_ = rrset;
  158. // Add some signatures
  159. } else if (rrset->getName() == Name("example.com.") &&
  160. rrset->getType() == RRType::NS()) {
  161. // For NS, we only have RRSIG for the origin name.
  162. rrset->addRRsig(RdataPtr(new generic::RRSIG(
  163. getCommonRRSIGText("NS"))));
  164. } else {
  165. // For others generate RRSIG unconditionally. Technically this
  166. // is wrong because we shouldn't have it for names under a zone
  167. // cut. But in our tests that doesn't matter, so we add them
  168. // just for simplicity.
  169. rrset->addRRsig(RdataPtr(new generic::RRSIG(
  170. getCommonRRSIGText(rrset->getType().
  171. toText()))));
  172. }
  173. }
  174. const Name origin_;
  175. // Names where we delegate somewhere else
  176. const Name delegation_name_;
  177. const Name dname_name_;
  178. bool has_SOA_;
  179. bool has_apex_NS_;
  180. ConstRRsetPtr delegation_rrset_;
  181. ConstRRsetPtr dname_rrset_;
  182. const RRClass rrclass_;
  183. bool include_rrsig_anyway_;
  184. };
  185. ZoneFinder::FindResult
  186. MockZoneFinder::find(const Name& name, const RRType& type,
  187. RRsetList* target, const FindOptions options)
  188. {
  189. // Emulating a broken zone: mandatory apex RRs are missing if specifically
  190. // configured so (which are rare cases).
  191. if (name == origin_ && type == RRType::SOA() && !has_SOA_) {
  192. return (FindResult(NXDOMAIN, RRsetPtr()));
  193. } else if (name == origin_ && type == RRType::NS() && !has_apex_NS_) {
  194. return (FindResult(NXDOMAIN, RRsetPtr()));
  195. }
  196. // Special case for names on or under a zone cut
  197. if ((options & FIND_GLUE_OK) == 0 &&
  198. (name == delegation_name_ ||
  199. name.compare(delegation_name_).getRelation() ==
  200. NameComparisonResult::SUBDOMAIN)) {
  201. return (FindResult(DELEGATION, delegation_rrset_));
  202. // And under DNAME
  203. } else if (name.compare(dname_name_).getRelation() ==
  204. NameComparisonResult::SUBDOMAIN) {
  205. return (FindResult(DNAME, dname_rrset_));
  206. }
  207. // normal cases. names are searched for only per exact-match basis
  208. // for simplicity.
  209. const Domains::const_iterator found_domain = domains_.find(name);
  210. if (found_domain != domains_.end()) {
  211. // First, try exact match.
  212. RRsetStore::const_iterator found_rrset =
  213. found_domain->second.find(type);
  214. if (found_rrset != found_domain->second.end()) {
  215. ConstRRsetPtr rrset;
  216. // Strip whatever signature there is in case DNSSEC is not required
  217. // Just to make sure the Query asks for it when it is needed
  218. if (options & ZoneFinder::FIND_DNSSEC ||
  219. include_rrsig_anyway_ ||
  220. !found_rrset->second->getRRsig()) {
  221. rrset = found_rrset->second;
  222. } else {
  223. RRsetPtr noconst(new RRset(found_rrset->second->getName(),
  224. found_rrset->second->getClass(),
  225. found_rrset->second->getType(),
  226. found_rrset->second->getTTL()));
  227. for (RdataIteratorPtr
  228. i(found_rrset->second->getRdataIterator());
  229. !i->isLast(); i->next()) {
  230. noconst->addRdata(i->getCurrent());
  231. }
  232. rrset = noconst;
  233. }
  234. return (FindResult(SUCCESS, rrset));
  235. }
  236. // If not found but we have a target, fill it with all RRsets here
  237. if (!found_domain->second.empty() && target != NULL) {
  238. for (found_rrset = found_domain->second.begin();
  239. found_rrset != found_domain->second.end(); ++found_rrset) {
  240. // Insert RRs under the domain name into target
  241. target->addRRset(
  242. boost::const_pointer_cast<RRset>(found_rrset->second));
  243. }
  244. return (FindResult(SUCCESS, found_domain->second.begin()->second));
  245. }
  246. // Otherwise, if this domain name has CNAME, return it.
  247. found_rrset = found_domain->second.find(RRType::CNAME());
  248. if (found_rrset != found_domain->second.end()) {
  249. return (FindResult(CNAME, found_rrset->second));
  250. }
  251. // Otherwise it's NXRRSET case.
  252. return (FindResult(NXRRSET, RRsetPtr()));
  253. }
  254. // query name isn't found in our domains. This is an NXDOMAIN case.
  255. // If we need DNSSEC proof, find the "previous name" that has an NSEC RR
  256. // and return NXDOMAIN with the found NSEC. Otherwise, just return the
  257. // NXDOMAIN code and NULL. If DNSSEC proof is requested but no NSEC is
  258. // found, we return NULL, too. (For simplicity under the test conditions
  259. // we don't care about pathological cases such as the name is "smaller"
  260. // than the origin)
  261. if ((options & FIND_DNSSEC) != 0) {
  262. for (Domains::const_reverse_iterator it = domains_.rbegin();
  263. it != domains_.rend();
  264. ++it) {
  265. RRsetStore::const_iterator nsec_it;
  266. if ((*it).first < name &&
  267. (nsec_it = (*it).second.find(RRType::NSEC()))
  268. != (*it).second.end()) {
  269. return (FindResult(NXDOMAIN, (*nsec_it).second));
  270. }
  271. }
  272. }
  273. return (FindResult(NXDOMAIN, RRsetPtr()));
  274. }
  275. class QueryTest : public ::testing::Test {
  276. protected:
  277. QueryTest() :
  278. qname(Name("www.example.com")), qclass(RRClass::IN()),
  279. qtype(RRType::A()), response(Message::RENDER),
  280. qid(response.getQid()), query_code(Opcode::QUERY().getCode())
  281. {
  282. response.setRcode(Rcode::NOERROR());
  283. response.setOpcode(Opcode::QUERY());
  284. // create and add a matching zone.
  285. mock_finder = new MockZoneFinder();
  286. memory_client.addZone(ZoneFinderPtr(mock_finder));
  287. }
  288. MockZoneFinder* mock_finder;
  289. // We use InMemoryClient here. We could have some kind of mock client
  290. // here, but historically, the Query supported only InMemoryClient
  291. // (originally named MemoryDataSrc) and was tested with it, so we keep
  292. // it like this for now.
  293. InMemoryClient memory_client;
  294. const Name qname;
  295. const RRClass qclass;
  296. const RRType qtype;
  297. Message response;
  298. const qid_t qid;
  299. const uint16_t query_code;
  300. };
  301. // A wrapper to check resulting response message commonly used in
  302. // tests below.
  303. // check_origin needs to be specified only when the authority section has
  304. // an SOA RR. The interface is not generic enough but should be okay
  305. // for our test cases in practice.
  306. void
  307. responseCheck(Message& response, const isc::dns::Rcode& rcode,
  308. unsigned int flags, const unsigned int ancount,
  309. const unsigned int nscount, const unsigned int arcount,
  310. const char* const expected_answer,
  311. const char* const expected_authority,
  312. const char* const expected_additional,
  313. const Name& check_origin = Name::ROOT_NAME())
  314. {
  315. // In our test cases QID, Opcode, and QDCOUNT should be constant, so
  316. // we don't bother the test cases specifying these values.
  317. headerCheck(response, response.getQid(), rcode, Opcode::QUERY().getCode(),
  318. flags, 0, ancount, nscount, arcount);
  319. if (expected_answer != NULL) {
  320. rrsetsCheck(expected_answer,
  321. response.beginSection(Message::SECTION_ANSWER),
  322. response.endSection(Message::SECTION_ANSWER),
  323. check_origin);
  324. }
  325. if (expected_authority != NULL) {
  326. rrsetsCheck(expected_authority,
  327. response.beginSection(Message::SECTION_AUTHORITY),
  328. response.endSection(Message::SECTION_AUTHORITY),
  329. check_origin);
  330. }
  331. if (expected_additional != NULL) {
  332. rrsetsCheck(expected_additional,
  333. response.beginSection(Message::SECTION_ADDITIONAL),
  334. response.endSection(Message::SECTION_ADDITIONAL));
  335. }
  336. }
  337. TEST_F(QueryTest, noZone) {
  338. // There's no zone in the memory datasource. So the response should have
  339. // REFUSED.
  340. InMemoryClient empty_memory_client;
  341. Query nozone_query(empty_memory_client, qname, qtype, response);
  342. EXPECT_NO_THROW(nozone_query.process());
  343. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  344. }
  345. TEST_F(QueryTest, exactMatch) {
  346. Query query(memory_client, qname, qtype, response);
  347. EXPECT_NO_THROW(query.process());
  348. // find match rrset
  349. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  350. www_a_txt, zone_ns_txt, ns_addrs_txt);
  351. }
  352. TEST_F(QueryTest, exactMatchIgnoreSIG) {
  353. // Check that we do not include the RRSIG when not requested even when
  354. // we receive it from the data source.
  355. mock_finder->setIncludeRRSIGAnyway(true);
  356. Query query(memory_client, qname, qtype, response);
  357. EXPECT_NO_THROW(query.process());
  358. // find match rrset
  359. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  360. www_a_txt, zone_ns_txt, ns_addrs_txt);
  361. }
  362. TEST_F(QueryTest, dnssecPositive) {
  363. // Just like exactMatch, but the signatures should be included as well
  364. Query query(memory_client, qname, qtype, response, true);
  365. EXPECT_NO_THROW(query.process());
  366. // find match rrset
  367. // We can't let responseCheck to check the additional section as well,
  368. // it gets confused by the two RRs for glue.delegation.../RRSIG due
  369. // to it's design and fixing it would be hard. Therefore we simply
  370. // check manually this one time.
  371. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
  372. (www_a_txt + std::string("www.example.com. 3600 IN RRSIG "
  373. "A 5 3 3600 20000101000000 "
  374. "20000201000000 12345 example.com. "
  375. "FAKEFAKEFAKE\n")).c_str(),
  376. (zone_ns_txt + std::string("example.com. 3600 IN RRSIG NS 5 "
  377. "3 3600 20000101000000 "
  378. "20000201000000 12345 "
  379. "example.com. FAKEFAKEFAKE\n")).
  380. c_str(), NULL);
  381. RRsetIterator iterator(response.beginSection(Message::SECTION_ADDITIONAL));
  382. const char* additional[] = {
  383. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n",
  384. "glue.delegation.example.com. 3600 IN RRSIG A 5 3 3600 20000101000000 "
  385. "20000201000000 12345 example.com. FAKEFAKEFAKE\n",
  386. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n",
  387. "glue.delegation.example.com. 3600 IN RRSIG AAAA 5 3 3600 "
  388. "20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE\n",
  389. "noglue.example.com. 3600 IN A 192.0.2.53\n",
  390. "noglue.example.com. 3600 IN RRSIG A 5 3 3600 20000101000000 "
  391. "20000201000000 12345 example.com. FAKEFAKEFAKE\n",
  392. NULL
  393. };
  394. for (const char** rr(additional); *rr != NULL; ++ rr) {
  395. ASSERT_FALSE(iterator ==
  396. response.endSection(Message::SECTION_ADDITIONAL));
  397. EXPECT_EQ(*rr, (*iterator)->toText());
  398. iterator ++;
  399. }
  400. EXPECT_TRUE(iterator == response.endSection(Message::SECTION_ADDITIONAL));
  401. }
  402. TEST_F(QueryTest, exactAddrMatch) {
  403. // find match rrset, omit additional data which has already been provided
  404. // in the answer section from the additional.
  405. EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
  406. response).process());
  407. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 2,
  408. "noglue.example.com. 3600 IN A 192.0.2.53\n", zone_ns_txt,
  409. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  410. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n");
  411. }
  412. TEST_F(QueryTest, apexNSMatch) {
  413. // find match rrset, omit authority data which has already been provided
  414. // in the answer section from the authority section.
  415. EXPECT_NO_THROW(Query(memory_client, Name("example.com"), RRType::NS(),
  416. response).process());
  417. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
  418. zone_ns_txt, NULL, ns_addrs_txt);
  419. }
  420. // test type any query logic
  421. TEST_F(QueryTest, exactAnyMatch) {
  422. // find match rrset, omit additional data which has already been provided
  423. // in the answer section from the additional.
  424. EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"),
  425. RRType::ANY(), response).process());
  426. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 3, 2,
  427. (string("noglue.example.com. 3600 IN A 192.0.2.53\n") +
  428. string(nsec_nxdomain_txt)).c_str(),
  429. zone_ns_txt,
  430. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  431. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n");
  432. }
  433. TEST_F(QueryTest, apexAnyMatch) {
  434. // find match rrset, omit additional data which has already been provided
  435. // in the answer section from the additional.
  436. EXPECT_NO_THROW(Query(memory_client, Name("example.com"),
  437. RRType::ANY(), response).process());
  438. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 5, 0, 3,
  439. (string(soa_txt) + string(zone_ns_txt) +
  440. string(nsec_apex_txt)).c_str(),
  441. NULL, ns_addrs_txt, mock_finder->getOrigin());
  442. }
  443. TEST_F(QueryTest, mxANYMatch) {
  444. EXPECT_NO_THROW(Query(memory_client, Name("mx.example.com"),
  445. RRType::ANY(), response).process());
  446. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
  447. mx_txt, zone_ns_txt,
  448. (string(ns_addrs_txt) + string(www_a_txt)).c_str());
  449. }
  450. TEST_F(QueryTest, glueANYMatch) {
  451. EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
  452. RRType::ANY(), response).process());
  453. responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
  454. NULL, delegation_txt, ns_addrs_txt);
  455. }
  456. TEST_F(QueryTest, nodomainANY) {
  457. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"),
  458. RRType::ANY(), response).process());
  459. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
  460. NULL, soa_txt, NULL, mock_finder->getOrigin());
  461. }
  462. // This tests that when we need to look up Zone's apex NS records for
  463. // authoritative answer, and there is no apex NS records. It should
  464. // throw in that case.
  465. TEST_F(QueryTest, noApexNS) {
  466. // Disable apex NS record
  467. mock_finder->setApexNSFlag(false);
  468. EXPECT_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
  469. response).process(), Query::NoApexNS);
  470. // We don't look into the response, as it threw
  471. }
  472. TEST_F(QueryTest, delegation) {
  473. EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
  474. qtype, response).process());
  475. responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
  476. NULL, delegation_txt, ns_addrs_txt);
  477. }
  478. TEST_F(QueryTest, nxdomain) {
  479. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  480. response).process());
  481. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
  482. NULL, soa_txt, NULL, mock_finder->getOrigin());
  483. }
  484. TEST_F(QueryTest, nxdomainWithNSEC) {
  485. // NXDOMAIN with DNSSEC proof. We should have SOA, NSEC that proves
  486. // NXDOMAIN and NSEC that proves nonexistence of matching wildcard,
  487. // as well as their RRSIGs.
  488. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  489. response, true).process());
  490. cout << response.toText() << endl;
  491. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
  492. NULL, (string(soa_txt) +
  493. string("example.com. 3600 IN RRSIG ") +
  494. getCommonRRSIGText("SOA") + "\n" +
  495. string(nsec_nxdomain_txt) + "\n" +
  496. string("noglue.example.com. 3600 IN RRSIG ") +
  497. getCommonRRSIGText("NSEC") + "\n" +
  498. string(nsec_apex_txt) + "\n" +
  499. string("example.com. 3600 IN RRSIG ") +
  500. getCommonRRSIGText("NSEC")).c_str(),
  501. NULL, mock_finder->getOrigin());
  502. }
  503. TEST_F(QueryTest, nxrrset) {
  504. EXPECT_NO_THROW(Query(memory_client, Name("www.example.com"),
  505. RRType::TXT(), response).process());
  506. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
  507. NULL, soa_txt, NULL, mock_finder->getOrigin());
  508. }
  509. /*
  510. * This tests that when there's no SOA and we need a negative answer. It should
  511. * throw in that case.
  512. */
  513. TEST_F(QueryTest, noSOA) {
  514. // disable zone's SOA RR.
  515. mock_finder->setSOAFlag(false);
  516. // The NX Domain
  517. EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"),
  518. qtype, response).process(), Query::NoSOA);
  519. // Of course, we don't look into the response, as it throwed
  520. // NXRRSET
  521. EXPECT_THROW(Query(memory_client, Name("nxrrset.example.com"),
  522. qtype, response).process(), Query::NoSOA);
  523. }
  524. TEST_F(QueryTest, noMatchZone) {
  525. // there's a zone in the memory datasource but it doesn't match the qname.
  526. // should result in REFUSED.
  527. Query(memory_client, Name("example.org"), qtype, response).process();
  528. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  529. }
  530. /*
  531. * Test MX additional processing.
  532. *
  533. * The MX RRset has two RRs, one pointing to a known domain with
  534. * A record, other to unknown out of zone one.
  535. */
  536. TEST_F(QueryTest, MX) {
  537. Query(memory_client, Name("mx.example.com"), RRType::MX(),
  538. response).process();
  539. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
  540. mx_txt, NULL,
  541. (string(ns_addrs_txt) + string(www_a_txt)).c_str());
  542. }
  543. /*
  544. * Test when we ask for MX whose exchange is an alias (CNAME in this case).
  545. *
  546. * This should not trigger the additional processing for the exchange.
  547. */
  548. TEST_F(QueryTest, MXAlias) {
  549. Query(memory_client, Name("cnamemx.example.com"), RRType::MX(),
  550. response).process();
  551. // there shouldn't be no additional RRs for the exchanges (we have 3
  552. // RRs for the NS). The normal MX case is tested separately so we don't
  553. // bother to examine the answer (and authority) sections.
  554. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  555. NULL, NULL, ns_addrs_txt);
  556. }
  557. /*
  558. * Tests encountering a cname.
  559. *
  560. * There are tests leading to successful answers, NXRRSET, NXDOMAIN and
  561. * out of the zone.
  562. *
  563. * TODO: We currently don't do chaining, so only the CNAME itself should be
  564. * returned.
  565. */
  566. TEST_F(QueryTest, CNAME) {
  567. Query(memory_client, Name("cname.example.com"), RRType::A(),
  568. response).process();
  569. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  570. cname_txt, NULL, NULL);
  571. }
  572. TEST_F(QueryTest, explicitCNAME) {
  573. // same owner name as the CNAME test but explicitly query for CNAME RR.
  574. // expect the same response as we don't provide a full chain yet.
  575. Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
  576. response).process();
  577. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  578. cname_txt, zone_ns_txt, ns_addrs_txt);
  579. }
  580. TEST_F(QueryTest, CNAME_NX_RRSET) {
  581. // Leads to www.example.com, it doesn't have TXT
  582. // note: with chaining, what should be expected is not trivial:
  583. // BIND 9 returns the CNAME in answer and SOA in authority, no additional.
  584. // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
  585. Query(memory_client, Name("cname.example.com"), RRType::TXT(),
  586. response).process();
  587. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  588. cname_txt, NULL, NULL);
  589. }
  590. TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
  591. // same owner name as the NXRRSET test but explicitly query for CNAME RR.
  592. Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
  593. response).process();
  594. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  595. cname_txt, zone_ns_txt, ns_addrs_txt);
  596. }
  597. TEST_F(QueryTest, CNAME_NX_DOMAIN) {
  598. // Leads to nxdomain.example.com
  599. // note: with chaining, what should be expected is not trivial:
  600. // BIND 9 returns the CNAME in answer and SOA in authority, no additional,
  601. // RCODE being NXDOMAIN.
  602. // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
  603. // RCODE being NOERROR.
  604. Query(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
  605. response).process();
  606. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  607. cname_nxdom_txt, NULL, NULL);
  608. }
  609. TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
  610. // same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
  611. Query(memory_client, Name("cnamenxdom.example.com"), RRType::CNAME(),
  612. response).process();
  613. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  614. cname_nxdom_txt, zone_ns_txt, ns_addrs_txt);
  615. }
  616. TEST_F(QueryTest, CNAME_OUT) {
  617. /*
  618. * This leads out of zone. This should have only the CNAME even
  619. * when we do chaining.
  620. *
  621. * TODO: We should be able to have two zones in the mock data source.
  622. * Then the same test should be done with .org included there and
  623. * see what it does (depends on what we want to do)
  624. */
  625. Query(memory_client, Name("cnameout.example.com"), RRType::A(),
  626. response).process();
  627. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  628. cname_out_txt, NULL, NULL);
  629. }
  630. TEST_F(QueryTest, explicitCNAME_OUT) {
  631. // same owner name as the OUT test but explicitly query for CNAME RR.
  632. Query(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
  633. response).process();
  634. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  635. cname_out_txt, zone_ns_txt, ns_addrs_txt);
  636. }
  637. /*
  638. * Test a query under a domain with DNAME. We should get a synthetized CNAME
  639. * as well as the DNAME.
  640. *
  641. * TODO: Once we have CNAME chaining, check it works with synthetized CNAMEs
  642. * as well. This includes tests pointing inside the zone, outside the zone,
  643. * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
  644. */
  645. TEST_F(QueryTest, DNAME) {
  646. Query(memory_client, Name("www.dname.example.com"), RRType::A(),
  647. response).process();
  648. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  649. (string(dname_txt) + synthetized_cname_txt).c_str(),
  650. NULL, NULL);
  651. }
  652. /*
  653. * Ask an ANY query below a DNAME. Should return the DNAME and synthetized
  654. * CNAME.
  655. *
  656. * ANY is handled specially sometimes. We check it is not the case with
  657. * DNAME.
  658. */
  659. TEST_F(QueryTest, DNAME_ANY) {
  660. Query(memory_client, Name("www.dname.example.com"), RRType::ANY(),
  661. response).process();
  662. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  663. (string(dname_txt) + synthetized_cname_txt).c_str(), NULL, NULL);
  664. }
  665. // Test when we ask for DNAME explicitly, it does no synthetizing.
  666. TEST_F(QueryTest, explicitDNAME) {
  667. Query(memory_client, Name("dname.example.com"), RRType::DNAME(),
  668. response).process();
  669. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  670. dname_txt, zone_ns_txt, ns_addrs_txt);
  671. }
  672. /*
  673. * Request a RRset at the domain with DNAME. It should not synthetize
  674. * the CNAME, it should return the RRset.
  675. */
  676. TEST_F(QueryTest, DNAME_A) {
  677. Query(memory_client, Name("dname.example.com"), RRType::A(),
  678. response).process();
  679. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  680. dname_a_txt, zone_ns_txt, ns_addrs_txt);
  681. }
  682. /*
  683. * Request a RRset at the domain with DNAME that is not there (NXRRSET).
  684. * It should not synthetize the CNAME.
  685. */
  686. TEST_F(QueryTest, DNAME_NX_RRSET) {
  687. EXPECT_NO_THROW(Query(memory_client, Name("dname.example.com"),
  688. RRType::TXT(), response).process());
  689. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
  690. NULL, soa_txt, NULL, mock_finder->getOrigin());
  691. }
  692. /*
  693. * Constructing the CNAME will result in a name that is too long. This,
  694. * however, should not throw (and crash the server), but respond with
  695. * YXDOMAIN.
  696. */
  697. TEST_F(QueryTest, LongDNAME) {
  698. // A name that is as long as it can be
  699. Name longname(
  700. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  701. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  702. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  703. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  704. "dname.example.com.");
  705. EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
  706. response).process());
  707. responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
  708. dname_txt, NULL, NULL);
  709. }
  710. /*
  711. * Constructing the CNAME will result in a name of maximal length.
  712. * This tests that we don't reject valid one by some kind of off by
  713. * one mistake.
  714. */
  715. TEST_F(QueryTest, MaxLenDNAME) {
  716. Name longname(
  717. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  718. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  719. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  720. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  721. "dname.example.com.");
  722. EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
  723. response).process());
  724. // Check the answer is OK
  725. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  726. NULL, NULL, NULL);
  727. // Check that the CNAME has the maximal length.
  728. bool ok(false);
  729. for (RRsetIterator i(response.beginSection(Message::SECTION_ANSWER));
  730. i != response.endSection(Message::SECTION_ANSWER); ++ i) {
  731. if ((*i)->getType() == RRType::CNAME()) {
  732. ok = true;
  733. RdataIteratorPtr ci((*i)->getRdataIterator());
  734. ASSERT_FALSE(ci->isLast()) << "The CNAME is empty";
  735. /*
  736. * Does anybody have a clue why, if the Name::MAX_WIRE is put
  737. * directly inside ASSERT_EQ, it fails to link and complains
  738. * it is unresolved external?
  739. */
  740. const size_t max_len(Name::MAX_WIRE);
  741. ASSERT_EQ(max_len, dynamic_cast<const rdata::generic::CNAME&>(
  742. ci->getCurrent()).getCname().getLength());
  743. }
  744. }
  745. EXPECT_TRUE(ok) << "The synthetized CNAME not found";
  746. }
  747. }