query_unittest.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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::dns::rdata;
  25. using namespace isc::datasrc;
  26. using namespace isc::auth;
  27. namespace {
  28. RRsetPtr a_rrset = RRsetPtr(new RRset(Name("www.example.com"),
  29. RRClass::IN(), RRType::A(),
  30. RRTTL(3600)));
  31. RRsetPtr soa_rrset = RRsetPtr(new RRset(Name("example.com"),
  32. RRClass::IN(), RRType::SOA(),
  33. RRTTL(3600)));
  34. RRsetPtr ns_rrset(RRsetPtr(new RRset(Name("ns.example.com"),
  35. RRClass::IN(), RRType::NS(),
  36. RRTTL(3600))));
  37. RRsetPtr glue_a_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
  38. RRClass::IN(), RRType::A(),
  39. RRTTL(3600))));
  40. RRsetPtr glue_aaaa_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
  41. RRClass::IN(), RRType::AAAA(),
  42. RRTTL(3600))));
  43. RRsetPtr noglue_a_rrset(RRsetPtr(new RRset(Name("noglue.example.com"),
  44. RRClass::IN(), RRType::A(),
  45. RRTTL(3600))));
  46. RRsetPtr delegated_mx_a_rrset(RRsetPtr(new RRset(
  47. Name("mx.delegation.example.com"), RRClass::IN(), RRType::A(),
  48. RRTTL(3600))));
  49. // This is a mock Zone class for testing.
  50. // It is a derived class of Zone, and simply hardcodes the results of find()
  51. // See the find() implementation if you want to know its content.
  52. class MockZone : public Zone {
  53. public:
  54. MockZone(bool has_SOA = true, bool has_apex_NS = true) :
  55. origin_(Name("example.com")),
  56. has_SOA_(has_SOA),
  57. has_apex_NS_(has_apex_NS),
  58. rrclass_(RRClass::IN()),
  59. rrttl_(RRTTL(3600)),
  60. // delegation.example.com. NS glue.ns.example.com.
  61. // NS noglue.ns.example.com.
  62. // NS cname.example.com.
  63. // NS example.org.
  64. delegation_rrset(RRsetPtr(new RRset(Name("delegation.example.com"),
  65. rrclass_, RRType::NS(), rrttl_))),
  66. // cname.example.com. CNAME www.example.com.
  67. cname_rrset(RRsetPtr(new RRset(Name("cname.example.com"), rrclass_,
  68. RRType::CNAME(), rrttl_))),
  69. // example.com. NS glue.ns.example.com.
  70. // NS noglue.ns.example.com.
  71. // NS example.net.
  72. auth_ns_rrset(RRsetPtr(new RRset(Name("example.com"), rrclass_,
  73. RRType::NS(), rrttl_))),
  74. // cnamemailer.example.com. CNAME host.example.com.
  75. mx_cname_rrset_(new RRset(Name("cnamemailer.example.com"), rrclass_,
  76. RRType::CNAME(), rrttl_)),
  77. // mx.example.com. MX 10 www.example.com.
  78. // MX 20 mailer.example.com.
  79. // MX 30 mx.delegation.example.com.
  80. mx_rrset_(new RRset(Name("mx.example.com"), rrclass_, RRType::MX(),
  81. rrttl_)),
  82. // host.example.com. A 192.0.2.1
  83. a_rrset_(new RRset(Name("host.example.com"), rrclass_, RRType::A(),
  84. rrttl_))
  85. {
  86. delegation_rrset->addRdata(generic::NS(Name("glue.ns.example.com")));
  87. delegation_rrset->addRdata(generic::NS(Name("noglue.example.com")));
  88. delegation_rrset->addRdata(generic::NS(Name("cname.example.com")));
  89. delegation_rrset->addRdata(generic::NS(Name("example.org")));
  90. cname_rrset->addRdata(generic::CNAME(Name("www.example.com")));
  91. auth_ns_rrset->addRdata(generic::NS(Name("glue.ns.example.com")));
  92. auth_ns_rrset->addRdata(generic::NS(Name("noglue.example.com")));
  93. auth_ns_rrset->addRdata(generic::NS(Name("example.net")));
  94. mx_rrset_->addRdata(generic::MX(10, Name("www.example.com")));
  95. mx_rrset_->addRdata(generic::MX(20, Name("mailer.example.org")));
  96. mx_rrset_->addRdata(generic::MX(30,
  97. Name("mx.delegation.example.com")));
  98. mx_cname_rrset_->addRdata(generic::CNAME(Name("host.example.com")));
  99. a_rrset_->addRdata(in::A("192.0.2.1"));
  100. }
  101. virtual const isc::dns::Name& getOrigin() const;
  102. virtual const isc::dns::RRClass& getClass() const;
  103. FindResult find(const isc::dns::Name& name,
  104. const isc::dns::RRType& type,
  105. const FindOptions options = FIND_DEFAULT) const;
  106. private:
  107. Name origin_;
  108. bool has_SOA_;
  109. bool has_apex_NS_;
  110. const RRClass rrclass_;
  111. const RRTTL rrttl_;
  112. RRsetPtr delegation_rrset;
  113. RRsetPtr cname_rrset;
  114. RRsetPtr auth_ns_rrset;
  115. RRsetPtr mx_cname_rrset_;
  116. RRsetPtr mx_rrset_;
  117. RRsetPtr a_rrset_;
  118. };
  119. const Name&
  120. MockZone::getOrigin() const {
  121. return (origin_);
  122. }
  123. const RRClass&
  124. MockZone::getClass() const {
  125. return (RRClass::IN());
  126. }
  127. Zone::FindResult
  128. MockZone::find(const Name& name, const RRType& type,
  129. const FindOptions options) const
  130. {
  131. // hardcode the find results
  132. if (name == Name("www.example.com") && type == RRType::A()) {
  133. return (FindResult(SUCCESS, a_rrset));
  134. } else if (name == Name("www.example.com")) {
  135. return (FindResult(NXRRSET, RRsetPtr()));
  136. } else if (name == Name("glue.ns.example.com") && type == RRType::A() &&
  137. (options & FIND_GLUE_OK) != 0) {
  138. return (FindResult(SUCCESS, glue_a_rrset));
  139. } else if (name == Name("noglue.example.com") && (type == RRType::A() ||
  140. type == RRType::ANY())) {
  141. return (FindResult(SUCCESS, noglue_a_rrset));
  142. } else if (name == Name("glue.ns.example.com") && type == RRType::AAAA() &&
  143. (options & FIND_GLUE_OK) != 0) {
  144. return (FindResult(SUCCESS, glue_aaaa_rrset));
  145. } else if (name == Name("example.com") && type == RRType::SOA() &&
  146. has_SOA_)
  147. {
  148. return (FindResult(SUCCESS, soa_rrset));
  149. } else if (name == Name("example.com") && type == RRType::NS() &&
  150. has_apex_NS_)
  151. {
  152. return (FindResult(SUCCESS, auth_ns_rrset));
  153. } else if (name == Name("mx.delegation.example.com") &&
  154. type == RRType::A() && (options & FIND_GLUE_OK) != 0)
  155. {
  156. return (FindResult(SUCCESS, delegated_mx_a_rrset));
  157. } else if (name == Name("delegation.example.com") ||
  158. name.compare(Name("delegation.example.com")).getRelation() ==
  159. NameComparisonResult::SUBDOMAIN)
  160. {
  161. return (FindResult(DELEGATION, delegation_rrset));
  162. } else if (name == Name("ns.example.com")) {
  163. return (FindResult(DELEGATION, ns_rrset));
  164. } else if (name == Name("nxdomain.example.com")) {
  165. return (FindResult(NXDOMAIN, RRsetPtr()));
  166. } else if (name == Name("nxrrset.example.com")) {
  167. return (FindResult(NXRRSET, RRsetPtr()));
  168. } else if ((name == Name("cname.example.com"))) {
  169. return (FindResult(CNAME, cname_rrset));
  170. } else if (name == Name("cnamemailer.example.com")) {
  171. return (FindResult(CNAME, mx_cname_rrset_));
  172. } else if (name == Name("mx.example.com")) {
  173. return (FindResult(SUCCESS, mx_rrset_));
  174. } else {
  175. return (FindResult(DNAME, RRsetPtr()));
  176. }
  177. }
  178. class QueryTest : public ::testing::Test {
  179. protected:
  180. QueryTest() :
  181. qname(Name("www.example.com")), qclass(RRClass::IN()),
  182. qtype(RRType::A()), response(Message::RENDER),
  183. query(memory_datasrc, qname, qtype, response)
  184. {
  185. response.setRcode(Rcode::NOERROR());
  186. }
  187. MemoryDataSrc memory_datasrc;
  188. const Name qname;
  189. const RRClass qclass;
  190. const RRType qtype;
  191. Message response;
  192. Query query;
  193. };
  194. TEST_F(QueryTest, noZone) {
  195. // There's no zone in the memory datasource. So the response should have
  196. // REFUSED.
  197. EXPECT_NO_THROW(query.process());
  198. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  199. }
  200. TEST_F(QueryTest, exactMatch) {
  201. // add a matching zone.
  202. memory_datasrc.addZone(ZonePtr(new MockZone()));
  203. EXPECT_NO_THROW(query.process());
  204. // find match rrset
  205. EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
  206. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  207. EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
  208. Name("www.example.com"), RRClass::IN(),
  209. RRType::A()));
  210. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  211. Name("example.com"), RRClass::IN(),
  212. RRType::NS()));
  213. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  214. Name("glue.ns.example.com"),
  215. RRClass::IN(), RRType::A()));
  216. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  217. Name("glue.ns.example.com"),
  218. RRClass::IN(), RRType::AAAA()));
  219. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  220. Name("noglue.example.com"),
  221. RRClass::IN(), RRType::A()));
  222. }
  223. TEST_F(QueryTest, exactAddrMatch) {
  224. // find match rrset, omit additional data which has already been provided
  225. // in the answer section from the additional.
  226. memory_datasrc.addZone(ZonePtr(new MockZone()));
  227. const Name noglue_name(Name("noglue.example.com"));
  228. Query noglue_query(memory_datasrc, noglue_name, qtype, response);
  229. EXPECT_NO_THROW(noglue_query.process());
  230. EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
  231. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  232. EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
  233. Name("noglue.example.com"), RRClass::IN(),
  234. RRType::A()));
  235. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  236. Name("example.com"), RRClass::IN(),
  237. RRType::NS()));
  238. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  239. Name("glue.ns.example.com"),
  240. RRClass::IN(), RRType::A()));
  241. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  242. Name("glue.ns.example.com"),
  243. RRClass::IN(), RRType::AAAA()));
  244. EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
  245. Name("noglue.example.com"),
  246. RRClass::IN(), RRType::A()));
  247. }
  248. TEST_F(QueryTest, apexNSMatch) {
  249. // find match rrset, omit authority data which has already been provided
  250. // in the answer section from the authority section.
  251. memory_datasrc.addZone(ZonePtr(new MockZone()));
  252. const Name apex_name(Name("example.com"));
  253. Query apex_ns_query(memory_datasrc, apex_name, RRType::NS(), response);
  254. EXPECT_NO_THROW(apex_ns_query.process());
  255. EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
  256. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  257. EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
  258. Name("example.com"), RRClass::IN(),
  259. RRType::NS()));
  260. EXPECT_FALSE(response.hasRRset(Message::SECTION_AUTHORITY,
  261. Name("example.com"), RRClass::IN(),
  262. RRType::NS()));
  263. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  264. Name("glue.ns.example.com"),
  265. RRClass::IN(), RRType::A()));
  266. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  267. Name("glue.ns.example.com"),
  268. RRClass::IN(), RRType::AAAA()));
  269. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  270. Name("noglue.example.com"),
  271. RRClass::IN(), RRType::A()));
  272. }
  273. TEST_F(QueryTest, exactAnyMatch) {
  274. // find match rrset, omit additional data which has already been provided
  275. // in the answer section from the additional.
  276. memory_datasrc.addZone(ZonePtr(new MockZone()));
  277. const Name noglue_name(Name("noglue.example.com"));
  278. Query noglue_query(memory_datasrc, noglue_name, RRType::ANY(), response);
  279. EXPECT_NO_THROW(noglue_query.process());
  280. EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
  281. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  282. EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
  283. Name("noglue.example.com"), RRClass::IN(),
  284. RRType::A()));
  285. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  286. Name("example.com"), RRClass::IN(),
  287. RRType::NS()));
  288. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  289. Name("glue.ns.example.com"),
  290. RRClass::IN(), RRType::A()));
  291. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  292. Name("glue.ns.example.com"),
  293. RRClass::IN(), RRType::AAAA()));
  294. EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
  295. Name("noglue.example.com"),
  296. RRClass::IN(), RRType::A()));
  297. }
  298. // This tests that when we need to look up Zone's apex NS records for
  299. // authoritative answer, and there is no apex NS records. It should
  300. // throw in that case.
  301. TEST_F(QueryTest, noApexNS) {
  302. // Add a zone without apex NS records
  303. memory_datasrc.addZone(ZonePtr(new MockZone(true, false)));
  304. const Name noglue_name(Name("noglue.example.com"));
  305. Query noglue_query(memory_datasrc, noglue_name, qtype, response);
  306. EXPECT_THROW(noglue_query.process(), Query::NoApexNS);
  307. // We don't look into the response, as it throwed
  308. }
  309. TEST_F(QueryTest, delegation) {
  310. // add a matching zone.
  311. memory_datasrc.addZone(ZonePtr(new MockZone()));
  312. const Name delegation_name(Name("delegation.example.com"));
  313. Query delegation_query(memory_datasrc, delegation_name, qtype, response);
  314. EXPECT_NO_THROW(delegation_query.process());
  315. EXPECT_FALSE(response.getHeaderFlag(Message::HEADERFLAG_AA));
  316. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  317. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  318. Name("delegation.example.com"),
  319. RRClass::IN(), RRType::NS()));
  320. // glue address records
  321. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  322. Name("glue.ns.example.com"),
  323. RRClass::IN(), RRType::A()));
  324. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  325. Name("glue.ns.example.com"),
  326. RRClass::IN(), RRType::AAAA()));
  327. // noglue address records
  328. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  329. Name("noglue.example.com"),
  330. RRClass::IN(), RRType::A()));
  331. // NS name has a CNAME
  332. EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
  333. Name("www.example.com"),
  334. RRClass::IN(), RRType::A()));
  335. // NS name is out of zone
  336. EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
  337. Name("example.org"),
  338. RRClass::IN(), RRType::A()));
  339. }
  340. TEST_F(QueryTest, nxdomain) {
  341. // add a matching zone.
  342. memory_datasrc.addZone(ZonePtr(new MockZone()));
  343. const Name nxdomain_name(Name("nxdomain.example.com"));
  344. Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
  345. EXPECT_NO_THROW(nxdomain_query.process());
  346. EXPECT_EQ(Rcode::NXDOMAIN(), response.getRcode());
  347. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ANSWER));
  348. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ADDITIONAL));
  349. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  350. Name("example.com"), RRClass::IN(), RRType::SOA()));
  351. }
  352. TEST_F(QueryTest, nxrrset) {
  353. // add a matching zone.
  354. memory_datasrc.addZone(ZonePtr(new MockZone()));
  355. const Name nxrrset_name(Name("nxrrset.example.com"));
  356. Query nxrrset_query(memory_datasrc, nxrrset_name, qtype, response);
  357. EXPECT_NO_THROW(nxrrset_query.process());
  358. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  359. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ANSWER));
  360. EXPECT_EQ(0, response.getRRCount(Message::SECTION_ADDITIONAL));
  361. EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
  362. Name("example.com"), RRClass::IN(), RRType::SOA()));
  363. }
  364. /*
  365. * This tests that when there's no SOA and we need a negative answer. It should
  366. * throw in that case.
  367. */
  368. TEST_F(QueryTest, noSOA) {
  369. memory_datasrc.addZone(ZonePtr(new MockZone(false)));
  370. // The NX Domain
  371. const Name nxdomain_name(Name("nxdomain.example.com"));
  372. Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
  373. EXPECT_THROW(nxdomain_query.process(), Query::NoSOA);
  374. // Of course, we don't look into the response, as it throwed
  375. // NXRRSET
  376. const Name nxrrset_name(Name("nxrrset.example.com"));
  377. Query nxrrset_query(memory_datasrc, nxrrset_name, qtype, response);
  378. EXPECT_THROW(nxrrset_query.process(), Query::NoSOA);
  379. }
  380. TEST_F(QueryTest, noMatchZone) {
  381. // there's a zone in the memory datasource but it doesn't match the qname.
  382. // should result in REFUSED.
  383. memory_datasrc.addZone(ZonePtr(new MockZone()));
  384. const Name nomatch_name(Name("example.org"));
  385. Query nomatch_query(memory_datasrc, nomatch_name, qtype, response);
  386. nomatch_query.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. memory_datasrc.addZone(ZonePtr(new MockZone()));
  397. Name qname("mx.example.com");
  398. Query mx_query(memory_datasrc, qname, RRType::MX(), response);
  399. EXPECT_NO_THROW(mx_query.process());
  400. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  401. EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
  402. Name("mx.example.com"), RRClass::IN(), RRType::MX()));
  403. EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
  404. Name("www.example.com"), RRClass::IN(), RRType::A()));
  405. // We want to skip the additional ones related to authoritative
  406. RRsetPtr ns;
  407. for (SectionIterator<RRsetPtr> ai(response.beginSection(
  408. Message::SECTION_AUTHORITY)); ai != response.endSection(
  409. Message::SECTION_AUTHORITY); ++ai)
  410. {
  411. if ((*ai)->getName() == Name("example.com") && (*ai)->getType() ==
  412. RRType::NS())
  413. {
  414. ns = *ai;
  415. break;
  416. }
  417. }
  418. /*
  419. * In fact, the MX RRset mentions three names, but we don't know anything
  420. * about one of them and one is under a zone cut, so we should have just
  421. * one RRset (A for www.example.com)
  422. */
  423. // We can't use getRRCount, as it counts RRs, not RRsets
  424. unsigned additional_count(0);
  425. for (SectionIterator<RRsetPtr> ai(response.beginSection(
  426. Message::SECTION_ADDITIONAL)); ai != response.endSection(
  427. Message::SECTION_ADDITIONAL); ++ai)
  428. {
  429. // Skip the ones for the NS record
  430. if (ns) {
  431. for (RdataIteratorPtr nsi(ns->getRdataIterator()); !nsi->isLast();
  432. nsi->next())
  433. {
  434. if ((*ai)->getName() ==
  435. dynamic_cast<const isc::dns::rdata::generic::NS&>(
  436. nsi->getCurrent()).getNSName())
  437. {
  438. goto NS_ADDITIONAL_DATA;
  439. }
  440. }
  441. }
  442. // It is not related to the NS, then it must be related to the MX
  443. ++additional_count;
  444. EXPECT_EQ(Name("www.example.com"), (*ai)->getName());
  445. EXPECT_EQ(RRType::A(), (*ai)->getType());
  446. NS_ADDITIONAL_DATA:;
  447. }
  448. EXPECT_EQ(1, additional_count);
  449. }
  450. /*
  451. * Test when we ask for MX and encounter an alias (CNAME in this case).
  452. *
  453. * This should not trigger the additional processing.
  454. */
  455. TEST_F(QueryTest, MXAlias) {
  456. memory_datasrc.addZone(ZonePtr(new MockZone()));
  457. Name qname("cnamemailer.example.com");
  458. Query mx_query(memory_datasrc, qname, RRType::MX(), response);
  459. EXPECT_NO_THROW(mx_query.process());
  460. EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
  461. // We should not have the IP address in additional section
  462. // Currently, the section should be completely empty
  463. EXPECT_TRUE(response.beginSection(Message::SECTION_ADDITIONAL) ==
  464. response.endSection(Message::SECTION_ADDITIONAL));
  465. }
  466. }