query_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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. // This is a mock Zone class for testing.
  85. // It is a derived class of ZoneFinder for the convenient of tests.
  86. // Its find() method emulates the common behavior of protocol compliant
  87. // ZoneFinder classes, but simplifies some minor cases and also supports broken
  88. // behavior.
  89. // For simplicity, most names are assumed to be "in zone"; there's only
  90. // one zone cut at the point of name "delegation.example.com".
  91. // Another special name is "dname.example.com". Query names under this name
  92. // will result in DNAME.
  93. // This mock zone doesn't handle empty non terminal nodes (if we need to test
  94. // such cases find() should have specialized code for it).
  95. class MockZoneFinder : public ZoneFinder {
  96. public:
  97. MockZoneFinder() :
  98. origin_(Name("example.com")),
  99. delegation_name_("delegation.example.com"),
  100. dname_name_("dname.example.com"),
  101. has_SOA_(true),
  102. has_apex_NS_(true),
  103. rrclass_(RRClass::IN())
  104. {
  105. stringstream zone_stream;
  106. zone_stream << soa_txt << zone_ns_txt << ns_addrs_txt <<
  107. delegation_txt << mx_txt << www_a_txt << cname_txt <<
  108. cname_nxdom_txt << cname_out_txt << dname_txt << dname_a_txt <<
  109. other_zone_rrs;
  110. masterLoad(zone_stream, origin_, rrclass_,
  111. boost::bind(&MockZoneFinder::loadRRset, this, _1));
  112. }
  113. virtual isc::dns::Name getOrigin() const { return (origin_); }
  114. virtual isc::dns::RRClass getClass() const { return (rrclass_); }
  115. virtual FindResult find(const isc::dns::Name& name,
  116. const isc::dns::RRType& type,
  117. RRsetList* target = NULL,
  118. const FindOptions options = FIND_DEFAULT);
  119. // If false is passed, it makes the zone broken as if it didn't have the
  120. // SOA.
  121. void setSOAFlag(bool on) { has_SOA_ = on; }
  122. // If false is passed, it makes the zone broken as if it didn't have
  123. // the apex NS.
  124. void setApexNSFlag(bool on) { has_apex_NS_ = on; }
  125. private:
  126. typedef map<RRType, ConstRRsetPtr> RRsetStore;
  127. typedef map<Name, RRsetStore> Domains;
  128. Domains domains_;
  129. void loadRRset(ConstRRsetPtr rrset) {
  130. domains_[rrset->getName()][rrset->getType()] = rrset;
  131. if (rrset->getName() == delegation_name_ &&
  132. rrset->getType() == RRType::NS()) {
  133. delegation_rrset_ = rrset;
  134. } else if (rrset->getName() == dname_name_ &&
  135. rrset->getType() == RRType::DNAME()) {
  136. dname_rrset_ = rrset;
  137. }
  138. }
  139. const Name origin_;
  140. // Names where we delegate somewhere else
  141. const Name delegation_name_;
  142. const Name dname_name_;
  143. bool has_SOA_;
  144. bool has_apex_NS_;
  145. ConstRRsetPtr delegation_rrset_;
  146. ConstRRsetPtr dname_rrset_;
  147. const RRClass rrclass_;
  148. };
  149. ZoneFinder::FindResult
  150. MockZoneFinder::find(const Name& name, const RRType& type,
  151. RRsetList* target, const FindOptions options)
  152. {
  153. // Emulating a broken zone: mandatory apex RRs are missing if specifically
  154. // configured so (which are rare cases).
  155. if (name == origin_ && type == RRType::SOA() && !has_SOA_) {
  156. return (FindResult(NXDOMAIN, RRsetPtr()));
  157. } else if (name == origin_ && type == RRType::NS() && !has_apex_NS_) {
  158. return (FindResult(NXDOMAIN, RRsetPtr()));
  159. }
  160. // Special case for names on or under a zone cut
  161. if ((options & FIND_GLUE_OK) == 0 &&
  162. (name == delegation_name_ ||
  163. name.compare(delegation_name_).getRelation() ==
  164. NameComparisonResult::SUBDOMAIN)) {
  165. return (FindResult(DELEGATION, delegation_rrset_));
  166. // And under DNAME
  167. } else if (name.compare(dname_name_).getRelation() ==
  168. NameComparisonResult::SUBDOMAIN) {
  169. return (FindResult(DNAME, dname_rrset_));
  170. }
  171. // normal cases. names are searched for only per exact-match basis
  172. // for simplicity.
  173. const Domains::const_iterator found_domain = domains_.find(name);
  174. if (found_domain != domains_.end()) {
  175. // First, try exact match.
  176. RRsetStore::const_iterator found_rrset =
  177. found_domain->second.find(type);
  178. if (found_rrset != found_domain->second.end()) {
  179. return (FindResult(SUCCESS, found_rrset->second));
  180. }
  181. // If not found but we have a target, fill it with all RRsets here
  182. if (!found_domain->second.empty() && target != NULL) {
  183. for (found_rrset = found_domain->second.begin();
  184. found_rrset != found_domain->second.end(); ++found_rrset) {
  185. // Insert RRs under the domain name into target
  186. target->addRRset(
  187. boost::const_pointer_cast<RRset>(found_rrset->second));
  188. }
  189. return (FindResult(SUCCESS, found_domain->second.begin()->second));
  190. }
  191. // Otherwise, if this domain name has CNAME, return it.
  192. found_rrset = found_domain->second.find(RRType::CNAME());
  193. if (found_rrset != found_domain->second.end()) {
  194. return (FindResult(CNAME, found_rrset->second));
  195. }
  196. // Otherwise it's NXRRSET case.
  197. return (FindResult(NXRRSET, RRsetPtr()));
  198. }
  199. // query name isn't found in our domains. returns NXDOMAIN.
  200. return (FindResult(NXDOMAIN, RRsetPtr()));
  201. }
  202. class QueryTest : public ::testing::Test {
  203. protected:
  204. QueryTest() :
  205. qname(Name("www.example.com")), qclass(RRClass::IN()),
  206. qtype(RRType::A()), response(Message::RENDER),
  207. qid(response.getQid()), query_code(Opcode::QUERY().getCode())
  208. {
  209. response.setRcode(Rcode::NOERROR());
  210. response.setOpcode(Opcode::QUERY());
  211. // create and add a matching zone.
  212. mock_finder = new MockZoneFinder();
  213. memory_client.addZone(ZoneFinderPtr(mock_finder));
  214. }
  215. MockZoneFinder* mock_finder;
  216. // We use InMemoryClient here. We could have some kind of mock client
  217. // here, but historically, the Query supported only InMemoryClient
  218. // (originally named MemoryDataSrc) and was tested with it, so we keep
  219. // it like this for now.
  220. InMemoryClient memory_client;
  221. const Name qname;
  222. const RRClass qclass;
  223. const RRType qtype;
  224. Message response;
  225. const qid_t qid;
  226. const uint16_t query_code;
  227. };
  228. // A wrapper to check resulting response message commonly used in
  229. // tests below.
  230. // check_origin needs to be specified only when the authority section has
  231. // an SOA RR. The interface is not generic enough but should be okay
  232. // for our test cases in practice.
  233. void
  234. responseCheck(Message& response, const isc::dns::Rcode& rcode,
  235. unsigned int flags, const unsigned int ancount,
  236. const unsigned int nscount, const unsigned int arcount,
  237. const char* const expected_answer,
  238. const char* const expected_authority,
  239. const char* const expected_additional,
  240. const Name& check_origin = Name::ROOT_NAME())
  241. {
  242. // In our test cases QID, Opcode, and QDCOUNT should be constant, so
  243. // we don't bother the test cases specifying these values.
  244. headerCheck(response, response.getQid(), rcode, Opcode::QUERY().getCode(),
  245. flags, 0, ancount, nscount, arcount);
  246. if (expected_answer != NULL) {
  247. rrsetsCheck(expected_answer,
  248. response.beginSection(Message::SECTION_ANSWER),
  249. response.endSection(Message::SECTION_ANSWER),
  250. check_origin);
  251. }
  252. if (expected_authority != NULL) {
  253. rrsetsCheck(expected_authority,
  254. response.beginSection(Message::SECTION_AUTHORITY),
  255. response.endSection(Message::SECTION_AUTHORITY),
  256. check_origin);
  257. }
  258. if (expected_additional != NULL) {
  259. rrsetsCheck(expected_additional,
  260. response.beginSection(Message::SECTION_ADDITIONAL),
  261. response.endSection(Message::SECTION_ADDITIONAL));
  262. }
  263. }
  264. TEST_F(QueryTest, noZone) {
  265. // There's no zone in the memory datasource. So the response should have
  266. // REFUSED.
  267. InMemoryClient empty_memory_client;
  268. Query nozone_query(empty_memory_client, qname, qtype, response);
  269. EXPECT_NO_THROW(nozone_query.process());
  270. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  271. }
  272. TEST_F(QueryTest, exactMatch) {
  273. Query query(memory_client, qname, qtype, response);
  274. EXPECT_NO_THROW(query.process());
  275. // find match rrset
  276. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  277. www_a_txt, zone_ns_txt, ns_addrs_txt);
  278. }
  279. TEST_F(QueryTest, exactAddrMatch) {
  280. // find match rrset, omit additional data which has already been provided
  281. // in the answer section from the additional.
  282. EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
  283. response).process());
  284. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 2,
  285. "noglue.example.com. 3600 IN A 192.0.2.53\n", zone_ns_txt,
  286. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  287. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n");
  288. }
  289. TEST_F(QueryTest, apexNSMatch) {
  290. // find match rrset, omit authority data which has already been provided
  291. // in the answer section from the authority section.
  292. EXPECT_NO_THROW(Query(memory_client, Name("example.com"), RRType::NS(),
  293. response).process());
  294. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
  295. zone_ns_txt, NULL, ns_addrs_txt);
  296. }
  297. // test type any query logic
  298. TEST_F(QueryTest, exactAnyMatch) {
  299. // find match rrset, omit additional data which has already been provided
  300. // in the answer section from the additional.
  301. EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"),
  302. RRType::ANY(), response).process());
  303. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 2,
  304. "noglue.example.com. 3600 IN A 192.0.2.53\n",
  305. zone_ns_txt,
  306. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  307. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n");
  308. }
  309. TEST_F(QueryTest, apexAnyMatch) {
  310. // find match rrset, omit additional data which has already been provided
  311. // in the answer section from the additional.
  312. EXPECT_NO_THROW(Query(memory_client, Name("example.com"),
  313. RRType::ANY(), response).process());
  314. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 0, 3,
  315. "example.com. 3600 IN SOA . . 0 0 0 0 0\n"
  316. "example.com. 3600 IN NS glue.delegation.example.com.\n"
  317. "example.com. 3600 IN NS noglue.example.com.\n"
  318. "example.com. 3600 IN NS example.net.\n",
  319. NULL, ns_addrs_txt, mock_finder->getOrigin());
  320. }
  321. TEST_F(QueryTest, mxANYMatch) {
  322. EXPECT_NO_THROW(Query(memory_client, Name("mx.example.com"),
  323. RRType::ANY(), response).process());
  324. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
  325. mx_txt, zone_ns_txt,
  326. (string(ns_addrs_txt) + string(www_a_txt)).c_str());
  327. }
  328. TEST_F(QueryTest, glueANYMatch) {
  329. EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
  330. RRType::ANY(), response).process());
  331. responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
  332. NULL, delegation_txt, ns_addrs_txt);
  333. }
  334. TEST_F(QueryTest, nodomainANY) {
  335. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"),
  336. RRType::ANY(), response).process());
  337. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
  338. NULL, soa_txt, NULL, mock_finder->getOrigin());
  339. }
  340. // This tests that when we need to look up Zone's apex NS records for
  341. // authoritative answer, and there is no apex NS records. It should
  342. // throw in that case.
  343. TEST_F(QueryTest, noApexNS) {
  344. // Disable apex NS record
  345. mock_finder->setApexNSFlag(false);
  346. EXPECT_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
  347. response).process(), Query::NoApexNS);
  348. // We don't look into the response, as it threw
  349. }
  350. TEST_F(QueryTest, delegation) {
  351. EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
  352. qtype, response).process());
  353. responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
  354. NULL, delegation_txt, ns_addrs_txt);
  355. }
  356. TEST_F(QueryTest, nxdomain) {
  357. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  358. response).process());
  359. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
  360. NULL, soa_txt, NULL, mock_finder->getOrigin());
  361. }
  362. TEST_F(QueryTest, nxrrset) {
  363. EXPECT_NO_THROW(Query(memory_client, Name("www.example.com"),
  364. RRType::TXT(), response).process());
  365. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
  366. NULL, soa_txt, NULL, mock_finder->getOrigin());
  367. }
  368. /*
  369. * This tests that when there's no SOA and we need a negative answer. It should
  370. * throw in that case.
  371. */
  372. TEST_F(QueryTest, noSOA) {
  373. // disable zone's SOA RR.
  374. mock_finder->setSOAFlag(false);
  375. // The NX Domain
  376. EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"),
  377. qtype, response).process(), Query::NoSOA);
  378. // Of course, we don't look into the response, as it throwed
  379. // NXRRSET
  380. EXPECT_THROW(Query(memory_client, Name("nxrrset.example.com"),
  381. qtype, response).process(), Query::NoSOA);
  382. }
  383. TEST_F(QueryTest, noMatchZone) {
  384. // there's a zone in the memory datasource but it doesn't match the qname.
  385. // should result in REFUSED.
  386. Query(memory_client, Name("example.org"), qtype, response).process();
  387. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  388. }
  389. /*
  390. * Test MX additional processing.
  391. *
  392. * The MX RRset has two RRs, one pointing to a known domain with
  393. * A record, other to unknown out of zone one.
  394. */
  395. TEST_F(QueryTest, MX) {
  396. Query(memory_client, Name("mx.example.com"), RRType::MX(),
  397. response).process();
  398. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
  399. mx_txt, NULL,
  400. (string(ns_addrs_txt) + string(www_a_txt)).c_str());
  401. }
  402. /*
  403. * Test when we ask for MX whose exchange is an alias (CNAME in this case).
  404. *
  405. * This should not trigger the additional processing for the exchange.
  406. */
  407. TEST_F(QueryTest, MXAlias) {
  408. Query(memory_client, Name("cnamemx.example.com"), RRType::MX(),
  409. response).process();
  410. // there shouldn't be no additional RRs for the exchanges (we have 3
  411. // RRs for the NS). The normal MX case is tested separately so we don't
  412. // bother to examine the answer (and authority) sections.
  413. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  414. NULL, NULL, ns_addrs_txt);
  415. }
  416. /*
  417. * Tests encountering a cname.
  418. *
  419. * There are tests leading to successful answers, NXRRSET, NXDOMAIN and
  420. * out of the zone.
  421. *
  422. * TODO: We currently don't do chaining, so only the CNAME itself should be
  423. * returned.
  424. */
  425. TEST_F(QueryTest, CNAME) {
  426. Query(memory_client, Name("cname.example.com"), RRType::A(),
  427. response).process();
  428. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  429. cname_txt, NULL, NULL);
  430. }
  431. TEST_F(QueryTest, explicitCNAME) {
  432. // same owner name as the CNAME test but explicitly query for CNAME RR.
  433. // expect the same response as we don't provide a full chain yet.
  434. Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
  435. response).process();
  436. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  437. cname_txt, zone_ns_txt, ns_addrs_txt);
  438. }
  439. TEST_F(QueryTest, CNAME_NX_RRSET) {
  440. // Leads to www.example.com, it doesn't have TXT
  441. // note: with chaining, what should be expected is not trivial:
  442. // BIND 9 returns the CNAME in answer and SOA in authority, no additional.
  443. // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
  444. Query(memory_client, Name("cname.example.com"), RRType::TXT(),
  445. response).process();
  446. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  447. cname_txt, NULL, NULL);
  448. }
  449. TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
  450. // same owner name as the NXRRSET test but explicitly query for CNAME RR.
  451. Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
  452. response).process();
  453. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  454. cname_txt, zone_ns_txt, ns_addrs_txt);
  455. }
  456. TEST_F(QueryTest, CNAME_NX_DOMAIN) {
  457. // Leads to nxdomain.example.com
  458. // note: with chaining, what should be expected is not trivial:
  459. // BIND 9 returns the CNAME in answer and SOA in authority, no additional,
  460. // RCODE being NXDOMAIN.
  461. // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
  462. // RCODE being NOERROR.
  463. Query(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
  464. response).process();
  465. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  466. cname_nxdom_txt, NULL, NULL);
  467. }
  468. TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
  469. // same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
  470. Query(memory_client, Name("cnamenxdom.example.com"), RRType::CNAME(),
  471. response).process();
  472. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  473. cname_nxdom_txt, zone_ns_txt, ns_addrs_txt);
  474. }
  475. TEST_F(QueryTest, CNAME_OUT) {
  476. /*
  477. * This leads out of zone. This should have only the CNAME even
  478. * when we do chaining.
  479. *
  480. * TODO: We should be able to have two zones in the mock data source.
  481. * Then the same test should be done with .org included there and
  482. * see what it does (depends on what we want to do)
  483. */
  484. Query(memory_client, Name("cnameout.example.com"), RRType::A(),
  485. response).process();
  486. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  487. cname_out_txt, NULL, NULL);
  488. }
  489. TEST_F(QueryTest, explicitCNAME_OUT) {
  490. // same owner name as the OUT test but explicitly query for CNAME RR.
  491. Query(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
  492. response).process();
  493. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  494. cname_out_txt, zone_ns_txt, ns_addrs_txt);
  495. }
  496. /*
  497. * Test a query under a domain with DNAME. We should get a synthetized CNAME
  498. * as well as the DNAME.
  499. *
  500. * TODO: Once we have CNAME chaining, check it works with synthetized CNAMEs
  501. * as well. This includes tests pointing inside the zone, outside the zone,
  502. * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
  503. */
  504. TEST_F(QueryTest, DNAME) {
  505. Query(memory_client, Name("www.dname.example.com"), RRType::A(),
  506. response).process();
  507. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  508. (string(dname_txt) + synthetized_cname_txt).c_str(),
  509. NULL, NULL);
  510. }
  511. /*
  512. * Ask an ANY query below a DNAME. Should return the DNAME and synthetized
  513. * CNAME.
  514. *
  515. * ANY is handled specially sometimes. We check it is not the case with
  516. * DNAME.
  517. */
  518. TEST_F(QueryTest, DNAME_ANY) {
  519. Query(memory_client, Name("www.dname.example.com"), RRType::ANY(),
  520. response).process();
  521. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  522. (string(dname_txt) + synthetized_cname_txt).c_str(), NULL, NULL);
  523. }
  524. // Test when we ask for DNAME explicitly, it does no synthetizing.
  525. TEST_F(QueryTest, explicitDNAME) {
  526. Query(memory_client, Name("dname.example.com"), RRType::DNAME(),
  527. response).process();
  528. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  529. dname_txt, zone_ns_txt, ns_addrs_txt);
  530. }
  531. /*
  532. * Request a RRset at the domain with DNAME. It should not synthetize
  533. * the CNAME, it should return the RRset.
  534. */
  535. TEST_F(QueryTest, DNAME_A) {
  536. Query(memory_client, Name("dname.example.com"), RRType::A(),
  537. response).process();
  538. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  539. dname_a_txt, zone_ns_txt, ns_addrs_txt);
  540. }
  541. /*
  542. * Request a RRset at the domain with DNAME that is not there (NXRRSET).
  543. * It should not synthetize the CNAME.
  544. */
  545. TEST_F(QueryTest, DNAME_NX_RRSET) {
  546. EXPECT_NO_THROW(Query(memory_client, Name("dname.example.com"),
  547. RRType::TXT(), response).process());
  548. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
  549. NULL, soa_txt, NULL, mock_finder->getOrigin());
  550. }
  551. /*
  552. * Constructing the CNAME will result in a name that is too long. This,
  553. * however, should not throw (and crash the server), but respond with
  554. * YXDOMAIN.
  555. */
  556. TEST_F(QueryTest, LongDNAME) {
  557. // A name that is as long as it can be
  558. Name longname(
  559. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  560. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  561. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  562. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  563. "dname.example.com.");
  564. EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
  565. response).process());
  566. responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
  567. dname_txt, NULL, NULL);
  568. }
  569. /*
  570. * Constructing the CNAME will result in a name of maximal length.
  571. * This tests that we don't reject valid one by some kind of off by
  572. * one mistake.
  573. */
  574. TEST_F(QueryTest, MaxLenDNAME) {
  575. Name longname(
  576. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  577. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  578. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  579. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  580. "dname.example.com.");
  581. EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
  582. response).process());
  583. // Check the answer is OK
  584. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  585. NULL, NULL, NULL);
  586. // Check that the CNAME has the maximal length.
  587. bool ok(false);
  588. for (RRsetIterator i(response.beginSection(Message::SECTION_ANSWER));
  589. i != response.endSection(Message::SECTION_ANSWER); ++ i) {
  590. if ((*i)->getType() == RRType::CNAME()) {
  591. ok = true;
  592. RdataIteratorPtr ci((*i)->getRdataIterator());
  593. ASSERT_FALSE(ci->isLast()) << "The CNAME is empty";
  594. /*
  595. * Does anybody have a clue why, if the Name::MAX_WIRE is put
  596. * directly inside ASSERT_EQ, it fails to link and complains
  597. * it is unresolved external?
  598. */
  599. const size_t max_len(Name::MAX_WIRE);
  600. ASSERT_EQ(max_len, dynamic_cast<const rdata::generic::CNAME&>(
  601. ci->getCurrent()).getCname().getLength());
  602. }
  603. }
  604. EXPECT_TRUE(ok) << "The synthetized CNAME not found";
  605. }
  606. }