query_unittest.cc 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607
  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 <boost/scoped_ptr.hpp>
  19. #include <exceptions/exceptions.h>
  20. #include <dns/masterload.h>
  21. #include <dns/message.h>
  22. #include <dns/name.h>
  23. #include <dns/opcode.h>
  24. #include <dns/rcode.h>
  25. #include <dns/rrttl.h>
  26. #include <dns/rrtype.h>
  27. #include <dns/rdataclass.h>
  28. #include <datasrc/memory_datasrc.h>
  29. #include <auth/query.h>
  30. #include <testutils/dnsmessage_test.h>
  31. #include <gtest/gtest.h>
  32. using namespace std;
  33. using namespace isc::dns;
  34. using namespace isc::dns::rdata;
  35. using namespace isc::datasrc;
  36. using namespace isc::auth;
  37. using namespace isc::testutils;
  38. namespace {
  39. // This is the content of the mock zone (see below).
  40. // It's a sequence of textual RRs that is supposed to be parsed by
  41. // dns::masterLoad(). Some of the RRs are also used as the expected
  42. // data in specific tests, in which case they are referenced via specific
  43. // local variables (such as soa_txt).
  44. const char* const soa_txt = "example.com. 3600 IN SOA . . 0 0 0 0 0\n";
  45. const char* const zone_ns_txt =
  46. "example.com. 3600 IN NS glue.delegation.example.com.\n"
  47. "example.com. 3600 IN NS noglue.example.com.\n"
  48. "example.com. 3600 IN NS example.net.\n";
  49. const char* const ns_addrs_txt =
  50. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  51. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n"
  52. "noglue.example.com. 3600 IN A 192.0.2.53\n";
  53. const char* const delegation_txt =
  54. "delegation.example.com. 3600 IN NS glue.delegation.example.com.\n"
  55. "delegation.example.com. 3600 IN NS noglue.example.com.\n"
  56. "delegation.example.com. 3600 IN NS cname.example.com.\n"
  57. "delegation.example.com. 3600 IN NS example.org.\n";
  58. const char* const delegation_ds_txt =
  59. "delegation.example.com. 3600 IN DS 12345 8 2 "
  60. "764501411DE58E8618945054A3F620B36202E115D015A7773F4B78E0F952CECA\n";
  61. const char* const mx_txt =
  62. "mx.example.com. 3600 IN MX 10 www.example.com.\n"
  63. "mx.example.com. 3600 IN MX 20 mailer.example.org.\n"
  64. "mx.example.com. 3600 IN MX 30 mx.delegation.example.com.\n";
  65. const char* const www_a_txt = "www.example.com. 3600 IN A 192.0.2.80\n";
  66. const char* const cname_txt =
  67. "cname.example.com. 3600 IN CNAME www.example.com.\n";
  68. const char* const cname_nxdom_txt =
  69. "cnamenxdom.example.com. 3600 IN CNAME nxdomain.example.com.\n";
  70. // CNAME Leading out of zone
  71. const char* const cname_out_txt =
  72. "cnameout.example.com. 3600 IN CNAME www.example.org.\n";
  73. // The DNAME to do tests against
  74. const char* const dname_txt =
  75. "dname.example.com. 3600 IN DNAME "
  76. "somethinglong.dnametarget.example.com.\n";
  77. // Some data at the dname node (allowed by RFC 2672)
  78. const char* const dname_a_txt =
  79. "dname.example.com. 3600 IN A 192.0.2.5\n";
  80. // This is not inside the zone, this is created at runtime
  81. const char* const synthetized_cname_txt =
  82. "www.dname.example.com. 3600 IN CNAME "
  83. "www.somethinglong.dnametarget.example.com.\n";
  84. // The rest of data won't be referenced from the test cases.
  85. const char* const other_zone_rrs =
  86. "cnamemailer.example.com. 3600 IN CNAME www.example.com.\n"
  87. "cnamemx.example.com. 3600 IN MX 10 cnamemailer.example.com.\n"
  88. "mx.delegation.example.com. 3600 IN A 192.0.2.100\n";
  89. // Wildcards
  90. const char* const wild_txt = "*.wild.example.com. 3600 IN A 192.0.2.7\n";
  91. const char* const nsec_wild_txt =
  92. "*.wild.example.com. 3600 IN NSEC www.example.com. A NSEC RRSIG\n";
  93. const char* const cnamewild_txt =
  94. "*.cnamewild.example.com. 3600 IN CNAME www.example.org.\n";
  95. const char* const nsec_cnamewild_txt = "*.cnamewild.example.com. "
  96. "3600 IN NSEC delegation.example.com. CNAME NSEC RRSIG\n";
  97. // Wildcard_nxrrset
  98. const char* const wild_txt_nxrrset =
  99. "*.uwild.example.com. 3600 IN A 192.0.2.9\n";
  100. const char* const nsec_wild_txt_nxrrset =
  101. "*.uwild.example.com. 3600 IN NSEC www.uwild.example.com. A NSEC RRSIG\n";
  102. const char* const wild_txt_next =
  103. "www.uwild.example.com. 3600 IN A 192.0.2.11\n";
  104. const char* const nsec_wild_txt_next =
  105. "www.uwild.example.com. 3600 IN NSEC *.wild.example.com. A NSEC RRSIG\n";
  106. // Wildcard empty
  107. const char* const empty_txt = "b.*.t.example.com. 3600 IN A 192.0.2.13\n";
  108. const char* const nsec_empty_txt =
  109. "b.*.t.example.com. 3600 IN NSEC *.uwild.example.com. A NSEC RRSIG\n";
  110. const char* const empty_prev_txt = "t.example.com. 3600 IN A 192.0.2.15\n";
  111. const char* const nsec_empty_prev_txt =
  112. "t.example.com. 3600 IN NSEC b.*.t.example.com. A NSEC RRSIG\n";
  113. // Used in NXDOMAIN proof test. We are going to test some unusual case where
  114. // the best possible wildcard is below the "next domain" of the NSEC RR that
  115. // proves the NXDOMAIN, i.e.,
  116. // mx.example.com. (exist)
  117. // (.no.example.com. (qname, NXDOMAIN)
  118. // ).no.example.com. (exist)
  119. // *.no.example.com. (best possible wildcard, not exist)
  120. const char* const no_txt =
  121. ").no.example.com. 3600 IN AAAA 2001:db8::53\n";
  122. // NSEC records.
  123. const char* const nsec_apex_txt =
  124. "example.com. 3600 IN NSEC cname.example.com. NS SOA NSEC RRSIG\n";
  125. const char* const nsec_mx_txt =
  126. "mx.example.com. 3600 IN NSEC ).no.example.com. MX NSEC RRSIG\n";
  127. const char* const nsec_no_txt =
  128. ").no.example.com. 3600 IN NSEC nz.no.example.com. AAAA NSEC RRSIG\n";
  129. // We'll also test the case where a single NSEC proves both NXDOMAIN and the
  130. // non existence of wildcard. The following records will be used for that
  131. // test.
  132. // ).no.example.com. (exist, whose NSEC proves everything)
  133. // *.no.example.com. (best possible wildcard, not exist)
  134. // nx.no.example.com. (NXDOMAIN)
  135. // nz.no.example.com. (exist)
  136. const char* const nz_txt =
  137. "nz.no.example.com. 3600 IN AAAA 2001:db8::5300\n";
  138. const char* const nsec_nz_txt =
  139. "nz.no.example.com. 3600 IN NSEC noglue.example.com. AAAA NSEC RRSIG\n";
  140. const char* const nsec_nxdomain_txt =
  141. "noglue.example.com. 3600 IN NSEC nonsec.example.com. A\n";
  142. // NSEC for the normal NXRRSET case
  143. const char* const nsec_www_txt =
  144. "www.example.com. 3600 IN NSEC example.com. A NSEC RRSIG\n";
  145. // Authoritative data without NSEC
  146. const char* const nonsec_a_txt = "nonsec.example.com. 3600 IN A 192.0.2.0\n";
  147. // NSEC3 RRs. You may also need to add mapping to MockZoneFinder::hash_map_.
  148. const char* const nsec3_apex_txt =
  149. "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN NSEC3 1 1 12 "
  150. "aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA NSEC3PARAM RRSIG\n";
  151. const char* const nsec3_www_txt =
  152. "q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN NSEC3 1 1 12 "
  153. "aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG\n";
  154. // A helper function that generates a textual representation of RRSIG RDATA
  155. // for the given covered type. The resulting RRSIG may not necessarily make
  156. // sense in terms of the DNSSEC protocol, but for our testing purposes it's
  157. // okay.
  158. string
  159. getCommonRRSIGText(const string& type) {
  160. return (type +
  161. string(" 5 3 3600 20000101000000 20000201000000 12345 "
  162. "example.com. FAKEFAKEFAKE"));
  163. }
  164. // This is a mock Zone Finder class for testing.
  165. // It is a derived class of ZoneFinder for the convenient of tests.
  166. // Its find() method emulates the common behavior of protocol compliant
  167. // ZoneFinder classes, but simplifies some minor cases and also supports broken
  168. // behavior.
  169. // For simplicity, most names are assumed to be "in zone"; there's only
  170. // one zone cut at the point of name "delegation.example.com".
  171. // Another special name is "dname.example.com". Query names under this name
  172. // will result in DNAME.
  173. // This mock zone doesn't handle empty non terminal nodes (if we need to test
  174. // such cases find() should have specialized code for it).
  175. class MockZoneFinder : public ZoneFinder {
  176. public:
  177. MockZoneFinder() :
  178. origin_(Name("example.com")),
  179. delegation_name_("delegation.example.com"),
  180. dname_name_("dname.example.com"),
  181. has_SOA_(true),
  182. has_apex_NS_(true),
  183. rrclass_(RRClass::IN()),
  184. include_rrsig_anyway_(false),
  185. use_nsec3_(false),
  186. nsec_name_(origin_)
  187. {
  188. stringstream zone_stream;
  189. zone_stream << soa_txt << zone_ns_txt << ns_addrs_txt <<
  190. delegation_txt << delegation_ds_txt << mx_txt << www_a_txt <<
  191. cname_txt << cname_nxdom_txt << cname_out_txt << dname_txt <<
  192. dname_a_txt << other_zone_rrs << no_txt << nz_txt <<
  193. nsec_apex_txt << nsec_mx_txt << nsec_no_txt << nsec_nz_txt <<
  194. nsec_nxdomain_txt << nsec_www_txt << nonsec_a_txt <<
  195. wild_txt << nsec_wild_txt << cnamewild_txt << nsec_cnamewild_txt <<
  196. wild_txt_nxrrset << nsec_wild_txt_nxrrset << wild_txt_next <<
  197. nsec_wild_txt_next << empty_txt << nsec_empty_txt <<
  198. empty_prev_txt << nsec_empty_prev_txt <<
  199. nsec3_apex_txt << nsec3_www_txt;
  200. masterLoad(zone_stream, origin_, rrclass_,
  201. boost::bind(&MockZoneFinder::loadRRset, this, _1));
  202. empty_nsec_rrset_ = ConstRRsetPtr(new RRset(Name::ROOT_NAME(),
  203. RRClass::IN(),
  204. RRType::NSEC(),
  205. RRTTL(3600)));
  206. // (Faked) NSEC3 hash map. For convenience we use hardcoded built-in
  207. // map instead of calculating and using actual hash.
  208. // The used hash values are borrowed from RFC5155 examples.
  209. hash_map_[Name("example.com")] = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
  210. hash_map_[Name("nxdomain.example.com")] =
  211. "v644ebqk9bibcna874givr6joj62mlhv";
  212. hash_map_[Name("nx.domain.example.com")] =
  213. "v644ebqk9bibcna874givr6joj62mlhv";
  214. hash_map_[Name("domain.example.com")] =
  215. "v644ebqk9bibcna874givr6joj62mlhv";
  216. hash_map_[Name("nxdomain2.example.com")] =
  217. "q00jkcevqvmu85r014c7dkba38o0ji5r";
  218. hash_map_[Name("nxdomain3.example.com")] =
  219. "009mhaveqvm6t7vbl5lop2u3t2rp3tom";
  220. }
  221. virtual isc::dns::Name getOrigin() const { return (origin_); }
  222. virtual isc::dns::RRClass getClass() const { return (rrclass_); }
  223. virtual FindResult find(const isc::dns::Name& name,
  224. const isc::dns::RRType& type,
  225. const FindOptions options = FIND_DEFAULT);
  226. virtual FindResult findAll(const isc::dns::Name& name,
  227. std::vector<ConstRRsetPtr>& target,
  228. const FindOptions options = FIND_DEFAULT);
  229. virtual ZoneFinder::FindNSEC3Result
  230. findNSEC3(const Name& name, bool recursive);
  231. // If false is passed, it makes the zone broken as if it didn't have the
  232. // SOA.
  233. void setSOAFlag(bool on) { has_SOA_ = on; }
  234. // If false is passed, it makes the zone broken as if it didn't have
  235. // the apex NS.
  236. void setApexNSFlag(bool on) { has_apex_NS_ = on; }
  237. // Turn this on if you want it to return RRSIGs regardless of FIND_GLUE_OK
  238. void setIncludeRRSIGAnyway(bool on) { include_rrsig_anyway_ = on; }
  239. // Once called, this "faked" result will be returned when NSEC is expected
  240. // for the specified query name.
  241. void setNSECResult(const Name& nsec_name, Result code,
  242. ConstRRsetPtr rrset)
  243. {
  244. nsec_name_ = nsec_name;
  245. nsec_result_.reset(new ZoneFinder::FindResult(code, rrset));
  246. }
  247. // If true is passed return an empty NSEC3 RRset for some negative
  248. // answers when DNSSEC is required.
  249. void setNSEC3Flag(bool on) { use_nsec3_ = on; }
  250. Name findPreviousName(const Name&) const {
  251. isc_throw(isc::NotImplemented, "Mock doesn't support previous name");
  252. }
  253. public:
  254. // We allow the tests to use these for convenience
  255. ConstRRsetPtr delegation_rrset_;
  256. ConstRRsetPtr delegation_ds_rrset_;
  257. ConstRRsetPtr empty_nsec_rrset_;
  258. private:
  259. typedef map<RRType, ConstRRsetPtr> RRsetStore;
  260. typedef map<Name, RRsetStore> Domains;
  261. Domains domains_;
  262. Domains nsec3_domains_;
  263. void loadRRset(RRsetPtr rrset) {
  264. if (rrset->getType() == RRType::NSEC3()) {
  265. // NSEC3 should go to the dedicated table
  266. nsec3_domains_[rrset->getName()][rrset->getType()] = rrset;
  267. // By nature it should have RRSIG. (We may want to selectively
  268. // omit this to test pathological cases).
  269. rrset->addRRsig(RdataPtr(new generic::RRSIG(
  270. getCommonRRSIGText(rrset->getType().
  271. toText()))));
  272. return;
  273. }
  274. domains_[rrset->getName()][rrset->getType()] = rrset;
  275. if (rrset->getName() == delegation_name_ &&
  276. rrset->getType() == RRType::NS()) {
  277. delegation_rrset_ = rrset;
  278. } else if (rrset->getName() == delegation_name_ &&
  279. rrset->getType() == RRType::DS()) {
  280. delegation_ds_rrset_ = rrset;
  281. // Like NSEC(3), by nature it should have an RRSIG.
  282. rrset->addRRsig(RdataPtr(new generic::RRSIG(
  283. getCommonRRSIGText(rrset->getType().
  284. toText()))));
  285. } else if (rrset->getName() == dname_name_ &&
  286. rrset->getType() == RRType::DNAME()) {
  287. dname_rrset_ = rrset;
  288. // Add some signatures
  289. } else if (rrset->getName() == Name("example.com.") &&
  290. rrset->getType() == RRType::NS()) {
  291. // For NS, we only have RRSIG for the origin name.
  292. rrset->addRRsig(RdataPtr(new generic::RRSIG(
  293. getCommonRRSIGText("NS"))));
  294. } else {
  295. // For others generate RRSIG unconditionally. Technically this
  296. // is wrong because we shouldn't have it for names under a zone
  297. // cut. But in our tests that doesn't matter, so we add them
  298. // just for simplicity.
  299. rrset->addRRsig(RdataPtr(new generic::RRSIG(
  300. getCommonRRSIGText(rrset->getType().
  301. toText()))));
  302. }
  303. }
  304. const Name origin_;
  305. // Names where we delegate somewhere else
  306. const Name delegation_name_;
  307. const Name dname_name_;
  308. bool has_SOA_;
  309. bool has_apex_NS_;
  310. ConstRRsetPtr dname_rrset_;
  311. const RRClass rrclass_;
  312. bool include_rrsig_anyway_;
  313. bool use_nsec3_;
  314. // The following two will be used for faked NSEC cases
  315. Name nsec_name_;
  316. boost::scoped_ptr<ZoneFinder::FindResult> nsec_result_;
  317. map<Name, string> hash_map_;
  318. };
  319. // A helper function that generates a new RRset based on "wild_rrset",
  320. // replacing its owner name with 'real_name'.
  321. ConstRRsetPtr
  322. substituteWild(const RRset& wild_rrset, const Name& real_name) {
  323. RRsetPtr rrset(new RRset(real_name, wild_rrset.getClass(),
  324. wild_rrset.getType(), wild_rrset.getTTL()));
  325. // For simplicity we only consider the case with one RDATA (for now)
  326. rrset->addRdata(wild_rrset.getRdataIterator()->getCurrent());
  327. ConstRRsetPtr wild_sig = wild_rrset.getRRsig();
  328. if (wild_sig) {
  329. RRsetPtr sig(new RRset(real_name, wild_sig->getClass(),
  330. wild_sig->getType(), wild_sig->getTTL()));
  331. sig->addRdata(wild_sig->getRdataIterator()->getCurrent());
  332. rrset->addRRsig(sig);
  333. }
  334. return (rrset);
  335. }
  336. ZoneFinder::FindResult
  337. MockZoneFinder::findAll(const Name& name, std::vector<ConstRRsetPtr>& target,
  338. const FindOptions options)
  339. {
  340. ZoneFinder::FindResult result(find(name, RRType::ANY(), options));
  341. if (result.code == NXRRSET) {
  342. const Domains::const_iterator found_domain = domains_.find(name);
  343. if (!found_domain->second.empty()) {
  344. for (RRsetStore::const_iterator found_rrset =
  345. found_domain->second.begin();
  346. found_rrset != found_domain->second.end(); ++found_rrset) {
  347. // Insert RRs under the domain name into target
  348. target.push_back(found_rrset->second);
  349. }
  350. return (FindResult(SUCCESS, RRsetPtr()));
  351. }
  352. }
  353. return (result);
  354. }
  355. ZoneFinder::FindNSEC3Result
  356. MockZoneFinder::findNSEC3(const Name& name, bool recursive) {
  357. ConstRRsetPtr covering_proof;
  358. const int labels = name.getLabelCount();
  359. // For brevity, we assume several things below: maps should have an
  360. // expected entry when operator[] is used; maps are not empty.
  361. for (int i = 0; i < labels; ++i) {
  362. const string hlabel = hash_map_[name.split(i, labels - i)];
  363. const Name hname = Name(hlabel + ".example.com");
  364. // We don't use const_iterator so that we can use operator[] below
  365. Domains::iterator found_domain = nsec3_domains_.lower_bound(hname);
  366. // If the given hash is larger than the largest stored hash or
  367. // the first label doesn't match the target, identify the "previous"
  368. // hash value and remember it as the candidate next closer proof.
  369. if (found_domain == nsec3_domains_.end() ||
  370. found_domain->first.split(0, 1).toText(true) != hlabel) {
  371. // If the given hash is larger or smaller than everything,
  372. // the covering proof is the NSEC3 that has the largest hash.
  373. if (found_domain == nsec3_domains_.end() ||
  374. found_domain == nsec3_domains_.begin()) {
  375. covering_proof =
  376. nsec3_domains_.rbegin()->second[RRType::NSEC3()];
  377. } else {
  378. // Otherwise, H(found_domain-1) < given_hash < H(found_domain)
  379. // The covering proof is the first one.
  380. covering_proof = (--found_domain)->second[RRType::NSEC3()];
  381. }
  382. if (!recursive) { // in non recursive mode, we are done.
  383. return (ZoneFinder::FindNSEC3Result(false,
  384. name.getLabelCount(),
  385. covering_proof,
  386. ConstRRsetPtr()));
  387. }
  388. } else { // exact match
  389. return (ZoneFinder::FindNSEC3Result(
  390. true, name.getLabelCount() - i,
  391. found_domain->second[RRType::NSEC3()],
  392. covering_proof));
  393. }
  394. }
  395. isc_throw(isc::Unexpected, "findNSEC3() isn't expected to fail");
  396. }
  397. ZoneFinder::FindResult
  398. MockZoneFinder::find(const Name& name, const RRType& type,
  399. const FindOptions options)
  400. {
  401. // Emulating a broken zone: mandatory apex RRs are missing if specifically
  402. // configured so (which are rare cases).
  403. if (name == origin_ && type == RRType::SOA() && !has_SOA_) {
  404. return (FindResult(NXDOMAIN, RRsetPtr()));
  405. } else if (name == origin_ && type == RRType::NS() && !has_apex_NS_) {
  406. return (FindResult(NXDOMAIN, RRsetPtr()));
  407. }
  408. // Special case for names on or under a zone cut
  409. if ((options & FIND_GLUE_OK) == 0 &&
  410. (name == delegation_name_ ||
  411. name.compare(delegation_name_).getRelation() ==
  412. NameComparisonResult::SUBDOMAIN)) {
  413. if (type != RRType::DS()) {
  414. return (FindResult(DELEGATION, delegation_rrset_));
  415. } else {
  416. return (FindResult(SUCCESS, delegation_ds_rrset_));
  417. }
  418. // And under DNAME
  419. } else if (name.compare(dname_name_).getRelation() ==
  420. NameComparisonResult::SUBDOMAIN) {
  421. return (FindResult(DNAME, dname_rrset_));
  422. }
  423. // normal cases. names are searched for only per exact-match basis
  424. // for simplicity.
  425. const Domains::const_iterator found_domain = domains_.find(name);
  426. if (found_domain != domains_.end()) {
  427. // First, try exact match.
  428. RRsetStore::const_iterator found_rrset =
  429. found_domain->second.find(type);
  430. if (found_rrset != found_domain->second.end()) {
  431. ConstRRsetPtr rrset;
  432. // Strip whatever signature there is in case DNSSEC is not required
  433. // Just to make sure the Query asks for it when it is needed
  434. if ((options & ZoneFinder::FIND_DNSSEC) != 0 ||
  435. include_rrsig_anyway_ ||
  436. !found_rrset->second->getRRsig()) {
  437. rrset = found_rrset->second;
  438. } else {
  439. RRsetPtr noconst(new RRset(found_rrset->second->getName(),
  440. found_rrset->second->getClass(),
  441. found_rrset->second->getType(),
  442. found_rrset->second->getTTL()));
  443. for (RdataIteratorPtr
  444. i(found_rrset->second->getRdataIterator());
  445. !i->isLast(); i->next()) {
  446. noconst->addRdata(i->getCurrent());
  447. }
  448. rrset = noconst;
  449. }
  450. return (FindResult(SUCCESS, rrset));
  451. }
  452. // Otherwise, if this domain name has CNAME, return it.
  453. found_rrset = found_domain->second.find(RRType::CNAME());
  454. if (found_rrset != found_domain->second.end()) {
  455. return (FindResult(CNAME, found_rrset->second));
  456. }
  457. // Otherwise it's NXRRSET case.
  458. if ((options & FIND_DNSSEC) != 0) {
  459. if (use_nsec3_) {
  460. return (FindResult(NXRRSET, RRsetPtr(), RESULT_NSEC3_SIGNED));
  461. }
  462. found_rrset = found_domain->second.find(RRType::NSEC());
  463. if (found_rrset != found_domain->second.end()) {
  464. return (FindResult(NXRRSET, found_rrset->second,
  465. RESULT_NSEC_SIGNED));
  466. }
  467. }
  468. return (FindResult(NXRRSET, RRsetPtr(), RESULT_NSEC_SIGNED));
  469. }
  470. // query name isn't found in our domains.
  471. // We first check if the query name is an empty non terminal name
  472. // of the zone by naive linear search.
  473. Domains::const_iterator domain;
  474. for (domain = domains_.begin(); domain != domains_.end(); ++domain) {
  475. if (name.compare((*domain).first).getRelation() ==
  476. NameComparisonResult::SUPERDOMAIN) {
  477. break;
  478. }
  479. }
  480. if (domain != domains_.end()) {
  481. // The query name is in an empty non terminal node followed by 'domain'
  482. // (for simplicity we ignore the pathological case of 'domain' is
  483. // the origin of the zone)
  484. --domain; // reset domain to the "previous name"
  485. if ((options & FIND_DNSSEC) != 0) {
  486. if (use_nsec3_) {
  487. return (FindResult(NXRRSET, RRsetPtr(), RESULT_NSEC3_SIGNED));
  488. }
  489. RRsetStore::const_iterator found_rrset =
  490. (*domain).second.find(RRType::NSEC());
  491. if (found_rrset != (*domain).second.end()) {
  492. return (FindResult(NXRRSET, found_rrset->second,
  493. RESULT_NSEC_SIGNED));
  494. }
  495. }
  496. return (FindResult(NXRRSET, RRsetPtr()));
  497. }
  498. // Another possibility is wildcard. For simplicity we only check
  499. // hardcoded specific cases, ignoring other details such as canceling
  500. // due to the existence of closer name.
  501. if ((options & NO_WILDCARD) == 0) {
  502. const Name wild_suffix(name.split(1));
  503. // Unit Tests use those domains for Wildcard test.
  504. if (name.equals(Name("www.wild.example.com"))||
  505. name.equals(Name("www1.uwild.example.com"))||
  506. name.equals(Name("a.t.example.com"))) {
  507. if (name.compare(wild_suffix).getRelation() ==
  508. NameComparisonResult::SUBDOMAIN) {
  509. domain = domains_.find(Name("*").concatenate(wild_suffix));
  510. // Matched the QNAME
  511. if (domain != domains_.end()) {
  512. RRsetStore::const_iterator found_rrset =
  513. domain->second.find(type);
  514. // Matched the QTYPE
  515. if(found_rrset != domain->second.end()) {
  516. return (FindResult(SUCCESS,
  517. substituteWild(
  518. *found_rrset->second, name),
  519. RESULT_WILDCARD |
  520. (use_nsec3_ ?
  521. RESULT_NSEC3_SIGNED :
  522. RESULT_NSEC_SIGNED)));
  523. } else {
  524. // No matched QTYPE, this case is for WILDCARD_NXRRSET
  525. if (use_nsec3_) {
  526. return (FindResult(NXRRSET, RRsetPtr(),
  527. RESULT_WILDCARD |
  528. RESULT_NSEC3_SIGNED));
  529. }
  530. const Name new_name =
  531. Name("*").concatenate(wild_suffix);
  532. found_rrset = domain->second.find(RRType::NSEC());
  533. assert(found_rrset != domain->second.end());
  534. return (FindResult(NXRRSET,
  535. substituteWild(
  536. *found_rrset->second,
  537. new_name),
  538. RESULT_WILDCARD |
  539. RESULT_NSEC_SIGNED));
  540. }
  541. } else {
  542. // This is empty non terminal name case on wildcard.
  543. const Name empty_name = Name("*").concatenate(wild_suffix);
  544. if (use_nsec3_) {
  545. return (FindResult(NXRRSET, RRsetPtr(),
  546. RESULT_WILDCARD |
  547. RESULT_NSEC3_SIGNED));
  548. }
  549. for (Domains::reverse_iterator it = domains_.rbegin();
  550. it != domains_.rend();
  551. ++it) {
  552. RRsetStore::const_iterator nsec_it;
  553. if ((*it).first < empty_name &&
  554. (nsec_it = (*it).second.find(RRType::NSEC()))
  555. != (*it).second.end()) {
  556. return (FindResult(NXRRSET, (*nsec_it).second,
  557. RESULT_WILDCARD |
  558. RESULT_NSEC_SIGNED));
  559. }
  560. }
  561. }
  562. return (FindResult(NXRRSET, RRsetPtr(), RESULT_WILDCARD));
  563. }
  564. }
  565. const Name cnamewild_suffix("cnamewild.example.com");
  566. if (name.compare(cnamewild_suffix).getRelation() ==
  567. NameComparisonResult::SUBDOMAIN) {
  568. domain = domains_.find(Name("*").concatenate(cnamewild_suffix));
  569. assert(domain != domains_.end());
  570. RRsetStore::const_iterator found_rrset =
  571. domain->second.find(RRType::CNAME());
  572. assert(found_rrset != domain->second.end());
  573. return (FindResult(CNAME,
  574. substituteWild(*found_rrset->second, name),
  575. RESULT_WILDCARD |
  576. (use_nsec3_ ? RESULT_NSEC3_SIGNED :
  577. RESULT_NSEC_SIGNED)));
  578. }
  579. }
  580. // This is an NXDOMAIN case.
  581. // If we need DNSSEC proof, find the "previous name" that has an NSEC RR
  582. // and return NXDOMAIN with the found NSEC. Otherwise, just return the
  583. // NXDOMAIN code and NULL. If DNSSEC proof is requested but no NSEC is
  584. // found, we return NULL, too. (For simplicity under the test conditions
  585. // we don't care about pathological cases such as the name is "smaller"
  586. // than the origin)
  587. if ((options & FIND_DNSSEC) != 0) {
  588. if (use_nsec3_) {
  589. return (FindResult(NXDOMAIN, RRsetPtr(), RESULT_NSEC3_SIGNED));
  590. }
  591. // Emulate a broken DataSourceClient for some special names.
  592. if (nsec_result_ && nsec_name_ == name) {
  593. return (*nsec_result_);
  594. }
  595. // Normal case
  596. // XXX: some older g++ complains about operator!= if we use
  597. // const_reverse_iterator
  598. for (Domains::reverse_iterator it = domains_.rbegin();
  599. it != domains_.rend();
  600. ++it) {
  601. RRsetStore::const_iterator nsec_it;
  602. if ((*it).first < name &&
  603. (nsec_it = (*it).second.find(RRType::NSEC()))
  604. != (*it).second.end()) {
  605. return (FindResult(NXDOMAIN, (*nsec_it).second,
  606. RESULT_NSEC_SIGNED));
  607. }
  608. }
  609. }
  610. return (FindResult(NXDOMAIN, RRsetPtr()));
  611. }
  612. class QueryTest : public ::testing::Test {
  613. protected:
  614. QueryTest() :
  615. qname(Name("www.example.com")), qclass(RRClass::IN()),
  616. qtype(RRType::A()), response(Message::RENDER),
  617. qid(response.getQid()), query_code(Opcode::QUERY().getCode())
  618. {
  619. response.setRcode(Rcode::NOERROR());
  620. response.setOpcode(Opcode::QUERY());
  621. // create and add a matching zone.
  622. mock_finder = new MockZoneFinder();
  623. memory_client.addZone(ZoneFinderPtr(mock_finder));
  624. }
  625. MockZoneFinder* mock_finder;
  626. // We use InMemoryClient here. We could have some kind of mock client
  627. // here, but historically, the Query supported only InMemoryClient
  628. // (originally named MemoryDataSrc) and was tested with it, so we keep
  629. // it like this for now.
  630. InMemoryClient memory_client;
  631. const Name qname;
  632. const RRClass qclass;
  633. const RRType qtype;
  634. Message response;
  635. const qid_t qid;
  636. const uint16_t query_code;
  637. };
  638. // A wrapper to check resulting response message commonly used in
  639. // tests below.
  640. // check_origin needs to be specified only when the authority section has
  641. // an SOA RR. The interface is not generic enough but should be okay
  642. // for our test cases in practice.
  643. void
  644. responseCheck(Message& response, const isc::dns::Rcode& rcode,
  645. unsigned int flags, const unsigned int ancount,
  646. const unsigned int nscount, const unsigned int arcount,
  647. const char* const expected_answer,
  648. const char* const expected_authority,
  649. const char* const expected_additional,
  650. const Name& check_origin = Name::ROOT_NAME())
  651. {
  652. // In our test cases QID, Opcode, and QDCOUNT should be constant, so
  653. // we don't bother the test cases specifying these values.
  654. headerCheck(response, response.getQid(), rcode, Opcode::QUERY().getCode(),
  655. flags, 0, ancount, nscount, arcount);
  656. if (expected_answer != NULL) {
  657. rrsetsCheck(expected_answer,
  658. response.beginSection(Message::SECTION_ANSWER),
  659. response.endSection(Message::SECTION_ANSWER),
  660. check_origin);
  661. }
  662. if (expected_authority != NULL) {
  663. rrsetsCheck(expected_authority,
  664. response.beginSection(Message::SECTION_AUTHORITY),
  665. response.endSection(Message::SECTION_AUTHORITY),
  666. check_origin);
  667. }
  668. if (expected_additional != NULL) {
  669. rrsetsCheck(expected_additional,
  670. response.beginSection(Message::SECTION_ADDITIONAL),
  671. response.endSection(Message::SECTION_ADDITIONAL));
  672. }
  673. }
  674. TEST_F(QueryTest, noZone) {
  675. // There's no zone in the memory datasource. So the response should have
  676. // REFUSED.
  677. InMemoryClient empty_memory_client;
  678. Query nozone_query(empty_memory_client, qname, qtype, response);
  679. EXPECT_NO_THROW(nozone_query.process());
  680. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  681. }
  682. TEST_F(QueryTest, exactMatch) {
  683. Query query(memory_client, qname, qtype, response);
  684. EXPECT_NO_THROW(query.process());
  685. // find match rrset
  686. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  687. www_a_txt, zone_ns_txt, ns_addrs_txt);
  688. }
  689. TEST_F(QueryTest, exactMatchIgnoreSIG) {
  690. // Check that we do not include the RRSIG when not requested even when
  691. // we receive it from the data source.
  692. mock_finder->setIncludeRRSIGAnyway(true);
  693. Query query(memory_client, qname, qtype, response);
  694. EXPECT_NO_THROW(query.process());
  695. // find match rrset
  696. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  697. www_a_txt, zone_ns_txt, ns_addrs_txt);
  698. }
  699. TEST_F(QueryTest, dnssecPositive) {
  700. // Just like exactMatch, but the signatures should be included as well
  701. Query query(memory_client, qname, qtype, response, true);
  702. EXPECT_NO_THROW(query.process());
  703. // find match rrset
  704. // We can't let responseCheck to check the additional section as well,
  705. // it gets confused by the two RRs for glue.delegation.../RRSIG due
  706. // to it's design and fixing it would be hard. Therefore we simply
  707. // check manually this one time.
  708. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
  709. (www_a_txt + std::string("www.example.com. 3600 IN RRSIG "
  710. "A 5 3 3600 20000101000000 "
  711. "20000201000000 12345 example.com. "
  712. "FAKEFAKEFAKE\n")).c_str(),
  713. (zone_ns_txt + std::string("example.com. 3600 IN RRSIG NS 5 "
  714. "3 3600 20000101000000 "
  715. "20000201000000 12345 "
  716. "example.com. FAKEFAKEFAKE\n")).
  717. c_str(), NULL);
  718. RRsetIterator iterator(response.beginSection(Message::SECTION_ADDITIONAL));
  719. const char* additional[] = {
  720. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n",
  721. "glue.delegation.example.com. 3600 IN RRSIG A 5 3 3600 20000101000000 "
  722. "20000201000000 12345 example.com. FAKEFAKEFAKE\n",
  723. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n",
  724. "glue.delegation.example.com. 3600 IN RRSIG AAAA 5 3 3600 "
  725. "20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE\n",
  726. "noglue.example.com. 3600 IN A 192.0.2.53\n",
  727. "noglue.example.com. 3600 IN RRSIG A 5 3 3600 20000101000000 "
  728. "20000201000000 12345 example.com. FAKEFAKEFAKE\n",
  729. NULL
  730. };
  731. for (const char** rr(additional); *rr != NULL; ++ rr) {
  732. ASSERT_FALSE(iterator ==
  733. response.endSection(Message::SECTION_ADDITIONAL));
  734. EXPECT_EQ(*rr, (*iterator)->toText());
  735. iterator ++;
  736. }
  737. EXPECT_TRUE(iterator == response.endSection(Message::SECTION_ADDITIONAL));
  738. }
  739. TEST_F(QueryTest, exactAddrMatch) {
  740. // find match rrset, omit additional data which has already been provided
  741. // in the answer section from the additional.
  742. EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
  743. response).process());
  744. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 2,
  745. "noglue.example.com. 3600 IN A 192.0.2.53\n", zone_ns_txt,
  746. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  747. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n");
  748. }
  749. TEST_F(QueryTest, apexNSMatch) {
  750. // find match rrset, omit authority data which has already been provided
  751. // in the answer section from the authority section.
  752. EXPECT_NO_THROW(Query(memory_client, Name("example.com"), RRType::NS(),
  753. response).process());
  754. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
  755. zone_ns_txt, NULL, ns_addrs_txt);
  756. }
  757. // test type any query logic
  758. TEST_F(QueryTest, exactAnyMatch) {
  759. // find match rrset, omit additional data which has already been provided
  760. // in the answer section from the additional.
  761. EXPECT_NO_THROW(Query(memory_client, Name("noglue.example.com"),
  762. RRType::ANY(), response).process());
  763. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 3, 2,
  764. (string("noglue.example.com. 3600 IN A 192.0.2.53\n") +
  765. string(nsec_nxdomain_txt)).c_str(),
  766. zone_ns_txt,
  767. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  768. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n");
  769. }
  770. TEST_F(QueryTest, apexAnyMatch) {
  771. // find match rrset, omit additional data which has already been provided
  772. // in the answer section from the additional.
  773. EXPECT_NO_THROW(Query(memory_client, Name("example.com"),
  774. RRType::ANY(), response).process());
  775. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 5, 0, 3,
  776. (string(soa_txt) + string(zone_ns_txt) +
  777. string(nsec_apex_txt)).c_str(),
  778. NULL, ns_addrs_txt, mock_finder->getOrigin());
  779. }
  780. TEST_F(QueryTest, mxANYMatch) {
  781. EXPECT_NO_THROW(Query(memory_client, Name("mx.example.com"),
  782. RRType::ANY(), response).process());
  783. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 3, 4,
  784. (string(mx_txt) + string(nsec_mx_txt)).c_str(), zone_ns_txt,
  785. (string(ns_addrs_txt) + string(www_a_txt)).c_str());
  786. }
  787. TEST_F(QueryTest, glueANYMatch) {
  788. EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
  789. RRType::ANY(), response).process());
  790. responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
  791. NULL, delegation_txt, ns_addrs_txt);
  792. }
  793. TEST_F(QueryTest, nodomainANY) {
  794. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"),
  795. RRType::ANY(), response).process());
  796. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
  797. NULL, soa_txt, NULL, mock_finder->getOrigin());
  798. }
  799. // This tests that when we need to look up Zone's apex NS records for
  800. // authoritative answer, and there is no apex NS records. It should
  801. // throw in that case.
  802. TEST_F(QueryTest, noApexNS) {
  803. // Disable apex NS record
  804. mock_finder->setApexNSFlag(false);
  805. EXPECT_THROW(Query(memory_client, Name("noglue.example.com"), qtype,
  806. response).process(), Query::NoApexNS);
  807. // We don't look into the response, as it threw
  808. }
  809. TEST_F(QueryTest, delegation) {
  810. EXPECT_NO_THROW(Query(memory_client, Name("delegation.example.com"),
  811. qtype, response).process());
  812. responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
  813. NULL, delegation_txt, ns_addrs_txt);
  814. }
  815. TEST_F(QueryTest, secureDelegation) {
  816. // find match rrset, omit additional data which has already been provided
  817. // in the answer section from the additional.
  818. EXPECT_NO_THROW(Query(memory_client, Name("foo.delegation.example.com"),
  819. qtype, response, true).process());
  820. // Should now contain RRSIG and DS record as well.
  821. responseCheck(response, Rcode::NOERROR(), 0, 0, 6, 6,
  822. NULL,
  823. (string(delegation_txt) +
  824. string(delegation_ds_txt) +
  825. string("delegation.example.com. 3600 IN RRSIG ") +
  826. getCommonRRSIGText("DS")).c_str(),
  827. // No easy way to get these strings, so entered them
  828. // manually
  829. "glue.delegation.example.com. 3600 IN A 192.0.2.153\n"
  830. "glue.delegation.example.com. 3600 IN RRSIG A 5 3 3600 "
  831. "20000101000000 20000201000000 12345 example.com. "
  832. "FAKEFAKEFAKE\n"
  833. "glue.delegation.example.com. 3600 IN AAAA 2001:db8::53\n"
  834. "glue.delegation.example.com. 3600 IN RRSIG AAAA 5 3 3600 "
  835. "20000101000000 20000201000000 12345 example.com. "
  836. "FAKEFAKEFAKE\n"
  837. "noglue.example.com. 3600 IN A 192.0.2.53\n"
  838. "noglue.example.com. 3600 IN RRSIG A 5 3 3600 20000101000000 "
  839. "20000201000000 12345 example.com. FAKEFAKEFAKE\n");
  840. }
  841. TEST_F(QueryTest, nxdomain) {
  842. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  843. response).process());
  844. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
  845. NULL, soa_txt, NULL, mock_finder->getOrigin());
  846. }
  847. TEST_F(QueryTest, nxdomainWithNSEC) {
  848. // NXDOMAIN with DNSSEC proof. We should have SOA, NSEC that proves
  849. // NXDOMAIN and NSEC that proves nonexistence of matching wildcard,
  850. // as well as their RRSIGs.
  851. EXPECT_NO_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  852. response, true).process());
  853. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
  854. NULL, (string(soa_txt) +
  855. string("example.com. 3600 IN RRSIG ") +
  856. getCommonRRSIGText("SOA") + "\n" +
  857. string(nsec_nxdomain_txt) + "\n" +
  858. string("noglue.example.com. 3600 IN RRSIG ") +
  859. getCommonRRSIGText("NSEC") + "\n" +
  860. string(nsec_apex_txt) + "\n" +
  861. string("example.com. 3600 IN RRSIG ") +
  862. getCommonRRSIGText("NSEC")).c_str(),
  863. NULL, mock_finder->getOrigin());
  864. }
  865. TEST_F(QueryTest, nxdomainWithNSEC2) {
  866. // See comments about no_txt. In this case the best possible wildcard
  867. // is derived from the next domain of the NSEC that proves NXDOMAIN, and
  868. // the NSEC to provide the non existence of wildcard is different from
  869. // the first NSEC.
  870. Query(memory_client, Name("(.no.example.com"), qtype,
  871. response, true).process();
  872. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
  873. NULL, (string(soa_txt) +
  874. string("example.com. 3600 IN RRSIG ") +
  875. getCommonRRSIGText("SOA") + "\n" +
  876. string(nsec_mx_txt) + "\n" +
  877. string("mx.example.com. 3600 IN RRSIG ") +
  878. getCommonRRSIGText("NSEC") + "\n" +
  879. string(nsec_no_txt) + "\n" +
  880. string(").no.example.com. 3600 IN RRSIG ") +
  881. getCommonRRSIGText("NSEC")).c_str(),
  882. NULL, mock_finder->getOrigin());
  883. }
  884. TEST_F(QueryTest, nxdomainWithNSECDuplicate) {
  885. // See comments about nz_txt. In this case we only need one NSEC,
  886. // which proves both NXDOMAIN and the non existence of wildcard.
  887. Query(memory_client, Name("nx.no.example.com"), qtype,
  888. response, true).process();
  889. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
  890. NULL, (string(soa_txt) +
  891. string("example.com. 3600 IN RRSIG ") +
  892. getCommonRRSIGText("SOA") + "\n" +
  893. string(nsec_no_txt) + "\n" +
  894. string(").no.example.com. 3600 IN RRSIG ") +
  895. getCommonRRSIGText("NSEC")).c_str(),
  896. NULL, mock_finder->getOrigin());
  897. }
  898. TEST_F(QueryTest, nxdomainBadNSEC1) {
  899. // ZoneFinder::find() returns NXDOMAIN with non NSEC RR.
  900. mock_finder->setNSECResult(Name("badnsec.example.com"),
  901. ZoneFinder::NXDOMAIN,
  902. mock_finder->delegation_rrset_);
  903. EXPECT_THROW(Query(memory_client, Name("badnsec.example.com"), qtype,
  904. response, true).process(),
  905. std::bad_cast);
  906. }
  907. TEST_F(QueryTest, nxdomainBadNSEC2) {
  908. // ZoneFinder::find() returns NXDOMAIN with an empty NSEC RR.
  909. mock_finder->setNSECResult(Name("emptynsec.example.com"),
  910. ZoneFinder::NXDOMAIN,
  911. mock_finder->empty_nsec_rrset_);
  912. EXPECT_THROW(Query(memory_client, Name("emptynsec.example.com"), qtype,
  913. response, true).process(),
  914. Query::BadNSEC);
  915. }
  916. TEST_F(QueryTest, nxdomainBadNSEC3) {
  917. // "no-wildcard proof" returns SUCCESS. it should be NXDOMAIN.
  918. mock_finder->setNSECResult(Name("*.example.com"),
  919. ZoneFinder::SUCCESS,
  920. mock_finder->delegation_rrset_);
  921. EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  922. response, true).process(),
  923. Query::BadNSEC);
  924. }
  925. TEST_F(QueryTest, nxdomainBadNSEC4) {
  926. // "no-wildcard proof" doesn't return RRset.
  927. mock_finder->setNSECResult(Name("*.example.com"),
  928. ZoneFinder::NXDOMAIN, ConstRRsetPtr());
  929. EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  930. response, true).process(),
  931. Query::BadNSEC);
  932. }
  933. TEST_F(QueryTest, nxdomainBadNSEC5) {
  934. // "no-wildcard proof" returns non NSEC.
  935. mock_finder->setNSECResult(Name("*.example.com"),
  936. ZoneFinder::NXDOMAIN,
  937. mock_finder->delegation_rrset_);
  938. // This is a bit odd, but we'll simply include the returned RRset.
  939. Query(memory_client, Name("nxdomain.example.com"), qtype,
  940. response, true).process();
  941. responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0,
  942. NULL, (string(soa_txt) +
  943. string("example.com. 3600 IN RRSIG ") +
  944. getCommonRRSIGText("SOA") + "\n" +
  945. string(nsec_nxdomain_txt) + "\n" +
  946. string("noglue.example.com. 3600 IN RRSIG ") +
  947. getCommonRRSIGText("NSEC") + "\n" +
  948. delegation_txt).c_str(),
  949. NULL, mock_finder->getOrigin());
  950. }
  951. TEST_F(QueryTest, nxdomainBadNSEC6) {
  952. // "no-wildcard proof" returns empty NSEC.
  953. mock_finder->setNSECResult(Name("*.example.com"),
  954. ZoneFinder::NXDOMAIN,
  955. mock_finder->empty_nsec_rrset_);
  956. EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"), qtype,
  957. response, true).process(),
  958. Query::BadNSEC);
  959. }
  960. TEST_F(QueryTest, nxrrset) {
  961. EXPECT_NO_THROW(Query(memory_client, Name("www.example.com"),
  962. RRType::TXT(), response).process());
  963. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
  964. NULL, soa_txt, NULL, mock_finder->getOrigin());
  965. }
  966. TEST_F(QueryTest, nxrrsetWithNSEC) {
  967. // NXRRSET with DNSSEC proof. We should have SOA, NSEC that proves the
  968. // NXRRSET and their RRSIGs.
  969. Query(memory_client, Name("www.example.com"), RRType::TXT(), response,
  970. true).process();
  971. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
  972. (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
  973. getCommonRRSIGText("SOA") + "\n" +
  974. string(nsec_www_txt) + "\n" +
  975. string("www.example.com. 3600 IN RRSIG ") +
  976. getCommonRRSIGText("NSEC")).c_str(),
  977. NULL, mock_finder->getOrigin());
  978. }
  979. TEST_F(QueryTest, emptyNameWithNSEC) {
  980. // Empty non terminal with DNSSEC proof. This is one of the cases of
  981. // Section 3.1.3.2 of RFC4035.
  982. // mx.example.com. NSEC ).no.example.com. proves no.example.com. is a
  983. // non empty terminal node. Note that it also implicitly proves there
  984. // should be no closer wildcard match (because the empty name is an
  985. // exact match), so we only need one NSEC.
  986. // From the point of the Query::process(), this is actually no different
  987. // from the other NXRRSET case, but we check that explicitly just in case.
  988. Query(memory_client, Name("no.example.com"), RRType::A(), response,
  989. true).process();
  990. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
  991. (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
  992. getCommonRRSIGText("SOA") + "\n" +
  993. string(nsec_mx_txt) + "\n" +
  994. string("mx.example.com. 3600 IN RRSIG ") +
  995. getCommonRRSIGText("NSEC")).c_str(),
  996. NULL, mock_finder->getOrigin());
  997. }
  998. TEST_F(QueryTest, nxrrsetWithoutNSEC) {
  999. // NXRRSET with DNSSEC proof requested, but there's no NSEC at that node.
  1000. // This is an unexpected event (if the zone is supposed to be properly
  1001. // signed with NSECs), but we accept and ignore the oddity.
  1002. Query(memory_client, Name("nonsec.example.com"), RRType::TXT(), response,
  1003. true).process();
  1004. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
  1005. (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
  1006. getCommonRRSIGText("SOA") + "\n").c_str(),
  1007. NULL, mock_finder->getOrigin());
  1008. }
  1009. TEST_F(QueryTest, wildcardNSEC) {
  1010. // The qname matches *.wild.example.com. The response should contain
  1011. // an NSEC that proves the non existence of a closer name.
  1012. Query(memory_client, Name("www.wild.example.com"), RRType::A(), response,
  1013. true).process();
  1014. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
  1015. (string(wild_txt).replace(0, 1, "www") +
  1016. string("www.wild.example.com. 3600 IN RRSIG ") +
  1017. getCommonRRSIGText("A") + "\n").c_str(),
  1018. (zone_ns_txt + string("example.com. 3600 IN RRSIG NS 5 "
  1019. "3 3600 20000101000000 "
  1020. "20000201000000 12345 "
  1021. "example.com. FAKEFAKEFAKE\n") +
  1022. string(nsec_wild_txt) +
  1023. string("*.wild.example.com. 3600 IN RRSIG ") +
  1024. getCommonRRSIGText("NSEC") + "\n").c_str(),
  1025. NULL, // we are not interested in additionals in this test
  1026. mock_finder->getOrigin());
  1027. }
  1028. TEST_F(QueryTest, CNAMEwildNSEC) {
  1029. // Similar to the previous case, but the matching wildcard record is
  1030. // CNAME.
  1031. Query(memory_client, Name("www.cnamewild.example.com"), RRType::A(),
  1032. response, true).process();
  1033. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
  1034. (string(cnamewild_txt).replace(0, 1, "www") +
  1035. string("www.cnamewild.example.com. 3600 IN RRSIG ") +
  1036. getCommonRRSIGText("CNAME") + "\n").c_str(),
  1037. (string(nsec_cnamewild_txt) +
  1038. string("*.cnamewild.example.com. 3600 IN RRSIG ") +
  1039. getCommonRRSIGText("NSEC") + "\n").c_str(),
  1040. NULL, // we are not interested in additionals in this test
  1041. mock_finder->getOrigin());
  1042. }
  1043. TEST_F(QueryTest, badWildcardProof1) {
  1044. // Unexpected case in wildcard proof: ZoneFinder::find() returns SUCCESS
  1045. // when NXDOMAIN is expected.
  1046. mock_finder->setNSECResult(Name("www.wild.example.com"),
  1047. ZoneFinder::SUCCESS,
  1048. mock_finder->delegation_rrset_);
  1049. EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
  1050. RRType::A(), response, true).process(),
  1051. Query::BadNSEC);
  1052. }
  1053. TEST_F(QueryTest, badWildcardProof2) {
  1054. // "wildcard proof" doesn't return RRset.
  1055. mock_finder->setNSECResult(Name("www.wild.example.com"),
  1056. ZoneFinder::NXDOMAIN, ConstRRsetPtr());
  1057. EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
  1058. RRType::A(), response, true).process(),
  1059. Query::BadNSEC);
  1060. }
  1061. TEST_F(QueryTest, badWildcardProof3) {
  1062. // "wildcard proof" returns empty NSEC.
  1063. mock_finder->setNSECResult(Name("www.wild.example.com"),
  1064. ZoneFinder::NXDOMAIN,
  1065. mock_finder->empty_nsec_rrset_);
  1066. EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
  1067. RRType::A(), response, true).process(),
  1068. Query::BadNSEC);
  1069. }
  1070. TEST_F(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
  1071. // WILDCARD_NXRRSET with DNSSEC proof. We should have SOA, NSEC that proves the
  1072. // NXRRSET and their RRSIGs. In this case we only need one NSEC,
  1073. // which proves both NXDOMAIN and the non existence RRSETs of wildcard.
  1074. Query(memory_client, Name("www.wild.example.com"), RRType::TXT(), response,
  1075. true).process();
  1076. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
  1077. (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
  1078. getCommonRRSIGText("SOA") + "\n" +
  1079. string(nsec_wild_txt) +
  1080. string("*.wild.example.com. 3600 IN RRSIG ") +
  1081. getCommonRRSIGText("NSEC")+"\n").c_str(),
  1082. NULL, mock_finder->getOrigin());
  1083. }
  1084. TEST_F(QueryTest, wildcardNxrrsetWithNSEC) {
  1085. // WILDCARD_NXRRSET with DNSSEC proof. We should have SOA, NSEC that proves the
  1086. // NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
  1087. // one proves NXDOMAIN and the other proves non existence RRSETs of wildcard.
  1088. Query(memory_client, Name("www1.uwild.example.com"), RRType::TXT(), response,
  1089. true).process();
  1090. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
  1091. (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
  1092. getCommonRRSIGText("SOA") + "\n" +
  1093. string(nsec_wild_txt_nxrrset) +
  1094. string("*.uwild.example.com. 3600 IN RRSIG ") +
  1095. getCommonRRSIGText("NSEC")+"\n" +
  1096. string(nsec_wild_txt_next) +
  1097. string("www.uwild.example.com. 3600 IN RRSIG ") +
  1098. getCommonRRSIGText("NSEC") + "\n").c_str(),
  1099. NULL, mock_finder->getOrigin());
  1100. }
  1101. TEST_F(QueryTest, wildcardEmptyWithNSEC) {
  1102. // WILDCARD_EMPTY with DNSSEC proof. We should have SOA, NSEC that proves the
  1103. // NXDOMAIN and their RRSIGs. In this case we need two NSEC RRs,
  1104. // one proves NXDOMAIN and the other proves non existence wildcard.
  1105. Query(memory_client, Name("a.t.example.com"), RRType::A(), response,
  1106. true).process();
  1107. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
  1108. (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
  1109. getCommonRRSIGText("SOA") + "\n" +
  1110. string(nsec_empty_prev_txt) +
  1111. string("t.example.com. 3600 IN RRSIG ") +
  1112. getCommonRRSIGText("NSEC")+"\n" +
  1113. string(nsec_empty_txt) +
  1114. string("b.*.t.example.com. 3600 IN RRSIG ") +
  1115. getCommonRRSIGText("NSEC")+"\n").c_str(),
  1116. NULL, mock_finder->getOrigin());
  1117. }
  1118. /*
  1119. * This tests that when there's no SOA and we need a negative answer. It should
  1120. * throw in that case.
  1121. */
  1122. TEST_F(QueryTest, noSOA) {
  1123. // disable zone's SOA RR.
  1124. mock_finder->setSOAFlag(false);
  1125. // The NX Domain
  1126. EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"),
  1127. qtype, response).process(), Query::NoSOA);
  1128. // Of course, we don't look into the response, as it throwed
  1129. // NXRRSET
  1130. EXPECT_THROW(Query(memory_client, Name("nxrrset.example.com"),
  1131. qtype, response).process(), Query::NoSOA);
  1132. }
  1133. TEST_F(QueryTest, noMatchZone) {
  1134. // there's a zone in the memory datasource but it doesn't match the qname.
  1135. // should result in REFUSED.
  1136. Query(memory_client, Name("example.org"), qtype, response).process();
  1137. EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
  1138. }
  1139. /*
  1140. * Test MX additional processing.
  1141. *
  1142. * The MX RRset has two RRs, one pointing to a known domain with
  1143. * A record, other to unknown out of zone one.
  1144. */
  1145. TEST_F(QueryTest, MX) {
  1146. Query(memory_client, Name("mx.example.com"), RRType::MX(),
  1147. response).process();
  1148. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
  1149. mx_txt, NULL,
  1150. (string(ns_addrs_txt) + string(www_a_txt)).c_str());
  1151. }
  1152. /*
  1153. * Test when we ask for MX whose exchange is an alias (CNAME in this case).
  1154. *
  1155. * This should not trigger the additional processing for the exchange.
  1156. */
  1157. TEST_F(QueryTest, MXAlias) {
  1158. Query(memory_client, Name("cnamemx.example.com"), RRType::MX(),
  1159. response).process();
  1160. // there shouldn't be no additional RRs for the exchanges (we have 3
  1161. // RRs for the NS). The normal MX case is tested separately so we don't
  1162. // bother to examine the answer (and authority) sections.
  1163. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  1164. NULL, NULL, ns_addrs_txt);
  1165. }
  1166. /*
  1167. * Tests encountering a cname.
  1168. *
  1169. * There are tests leading to successful answers, NXRRSET, NXDOMAIN and
  1170. * out of the zone.
  1171. *
  1172. * TODO: We currently don't do chaining, so only the CNAME itself should be
  1173. * returned.
  1174. */
  1175. TEST_F(QueryTest, CNAME) {
  1176. Query(memory_client, Name("cname.example.com"), RRType::A(),
  1177. response).process();
  1178. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  1179. cname_txt, NULL, NULL);
  1180. }
  1181. TEST_F(QueryTest, explicitCNAME) {
  1182. // same owner name as the CNAME test but explicitly query for CNAME RR.
  1183. // expect the same response as we don't provide a full chain yet.
  1184. Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
  1185. response).process();
  1186. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  1187. cname_txt, zone_ns_txt, ns_addrs_txt);
  1188. }
  1189. TEST_F(QueryTest, CNAME_NX_RRSET) {
  1190. // Leads to www.example.com, it doesn't have TXT
  1191. // note: with chaining, what should be expected is not trivial:
  1192. // BIND 9 returns the CNAME in answer and SOA in authority, no additional.
  1193. // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
  1194. Query(memory_client, Name("cname.example.com"), RRType::TXT(),
  1195. response).process();
  1196. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  1197. cname_txt, NULL, NULL);
  1198. }
  1199. TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
  1200. // same owner name as the NXRRSET test but explicitly query for CNAME RR.
  1201. Query(memory_client, Name("cname.example.com"), RRType::CNAME(),
  1202. response).process();
  1203. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  1204. cname_txt, zone_ns_txt, ns_addrs_txt);
  1205. }
  1206. TEST_F(QueryTest, CNAME_NX_DOMAIN) {
  1207. // Leads to nxdomain.example.com
  1208. // note: with chaining, what should be expected is not trivial:
  1209. // BIND 9 returns the CNAME in answer and SOA in authority, no additional,
  1210. // RCODE being NXDOMAIN.
  1211. // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
  1212. // RCODE being NOERROR.
  1213. Query(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
  1214. response).process();
  1215. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  1216. cname_nxdom_txt, NULL, NULL);
  1217. }
  1218. TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
  1219. // same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
  1220. Query(memory_client, Name("cnamenxdom.example.com"), RRType::CNAME(),
  1221. response).process();
  1222. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  1223. cname_nxdom_txt, zone_ns_txt, ns_addrs_txt);
  1224. }
  1225. TEST_F(QueryTest, CNAME_OUT) {
  1226. /*
  1227. * This leads out of zone. This should have only the CNAME even
  1228. * when we do chaining.
  1229. *
  1230. * TODO: We should be able to have two zones in the mock data source.
  1231. * Then the same test should be done with .org included there and
  1232. * see what it does (depends on what we want to do)
  1233. */
  1234. Query(memory_client, Name("cnameout.example.com"), RRType::A(),
  1235. response).process();
  1236. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
  1237. cname_out_txt, NULL, NULL);
  1238. }
  1239. TEST_F(QueryTest, explicitCNAME_OUT) {
  1240. // same owner name as the OUT test but explicitly query for CNAME RR.
  1241. Query(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
  1242. response).process();
  1243. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  1244. cname_out_txt, zone_ns_txt, ns_addrs_txt);
  1245. }
  1246. /*
  1247. * Test a query under a domain with DNAME. We should get a synthetized CNAME
  1248. * as well as the DNAME.
  1249. *
  1250. * TODO: Once we have CNAME chaining, check it works with synthetized CNAMEs
  1251. * as well. This includes tests pointing inside the zone, outside the zone,
  1252. * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
  1253. */
  1254. TEST_F(QueryTest, DNAME) {
  1255. Query(memory_client, Name("www.dname.example.com"), RRType::A(),
  1256. response).process();
  1257. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  1258. (string(dname_txt) + synthetized_cname_txt).c_str(),
  1259. NULL, NULL);
  1260. }
  1261. /*
  1262. * Ask an ANY query below a DNAME. Should return the DNAME and synthetized
  1263. * CNAME.
  1264. *
  1265. * ANY is handled specially sometimes. We check it is not the case with
  1266. * DNAME.
  1267. */
  1268. TEST_F(QueryTest, DNAME_ANY) {
  1269. Query(memory_client, Name("www.dname.example.com"), RRType::ANY(),
  1270. response).process();
  1271. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  1272. (string(dname_txt) + synthetized_cname_txt).c_str(), NULL, NULL);
  1273. }
  1274. // Test when we ask for DNAME explicitly, it does no synthetizing.
  1275. TEST_F(QueryTest, explicitDNAME) {
  1276. Query(memory_client, Name("dname.example.com"), RRType::DNAME(),
  1277. response).process();
  1278. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  1279. dname_txt, zone_ns_txt, ns_addrs_txt);
  1280. }
  1281. /*
  1282. * Request a RRset at the domain with DNAME. It should not synthetize
  1283. * the CNAME, it should return the RRset.
  1284. */
  1285. TEST_F(QueryTest, DNAME_A) {
  1286. Query(memory_client, Name("dname.example.com"), RRType::A(),
  1287. response).process();
  1288. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
  1289. dname_a_txt, zone_ns_txt, ns_addrs_txt);
  1290. }
  1291. /*
  1292. * Request a RRset at the domain with DNAME that is not there (NXRRSET).
  1293. * It should not synthetize the CNAME.
  1294. */
  1295. TEST_F(QueryTest, DNAME_NX_RRSET) {
  1296. EXPECT_NO_THROW(Query(memory_client, Name("dname.example.com"),
  1297. RRType::TXT(), response).process());
  1298. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
  1299. NULL, soa_txt, NULL, mock_finder->getOrigin());
  1300. }
  1301. /*
  1302. * Constructing the CNAME will result in a name that is too long. This,
  1303. * however, should not throw (and crash the server), but respond with
  1304. * YXDOMAIN.
  1305. */
  1306. TEST_F(QueryTest, LongDNAME) {
  1307. // A name that is as long as it can be
  1308. Name longname(
  1309. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1310. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1311. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1312. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1313. "dname.example.com.");
  1314. EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
  1315. response).process());
  1316. responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
  1317. dname_txt, NULL, NULL);
  1318. }
  1319. /*
  1320. * Constructing the CNAME will result in a name of maximal length.
  1321. * This tests that we don't reject valid one by some kind of off by
  1322. * one mistake.
  1323. */
  1324. TEST_F(QueryTest, MaxLenDNAME) {
  1325. Name longname(
  1326. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1327. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1328. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1329. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
  1330. "dname.example.com.");
  1331. EXPECT_NO_THROW(Query(memory_client, longname, RRType::A(),
  1332. response).process());
  1333. // Check the answer is OK
  1334. responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
  1335. NULL, NULL, NULL);
  1336. // Check that the CNAME has the maximal length.
  1337. bool ok(false);
  1338. for (RRsetIterator i(response.beginSection(Message::SECTION_ANSWER));
  1339. i != response.endSection(Message::SECTION_ANSWER); ++ i) {
  1340. if ((*i)->getType() == RRType::CNAME()) {
  1341. ok = true;
  1342. RdataIteratorPtr ci((*i)->getRdataIterator());
  1343. ASSERT_FALSE(ci->isLast()) << "The CNAME is empty";
  1344. /*
  1345. * Does anybody have a clue why, if the Name::MAX_WIRE is put
  1346. * directly inside ASSERT_EQ, it fails to link and complains
  1347. * it is unresolved external?
  1348. */
  1349. const size_t max_len(Name::MAX_WIRE);
  1350. ASSERT_EQ(max_len, dynamic_cast<const rdata::generic::CNAME&>(
  1351. ci->getCurrent()).getCname().getLength());
  1352. }
  1353. }
  1354. EXPECT_TRUE(ok) << "The synthetized CNAME not found";
  1355. }
  1356. // Test for this test module itself
  1357. void
  1358. nsec3Check(bool expected_matched, uint8_t expected_labels,
  1359. const string& expected_rrsets_txt,
  1360. const ZoneFinder::FindNSEC3Result& result)
  1361. {
  1362. vector<ConstRRsetPtr> actual_rrsets;
  1363. EXPECT_EQ(expected_matched, result.matched);
  1364. // Convert to int so the error messages would be more readable:
  1365. EXPECT_EQ(static_cast<int>(expected_labels),
  1366. static_cast<int>(result.closest_labels));
  1367. if (result.closest_proof) {
  1368. actual_rrsets.push_back(result.closest_proof);
  1369. }
  1370. if (result.next_proof) {
  1371. actual_rrsets.push_back(result.next_proof);
  1372. }
  1373. rrsetsCheck(expected_rrsets_txt, actual_rrsets.begin(),
  1374. actual_rrsets.end());
  1375. }
  1376. TEST_F(QueryTest, findNSEC3) {
  1377. // In all test cases in the recursive mode, the closest encloser is the
  1378. // apex, and result's closest_labels should be the number of apex labels.
  1379. // (In non recursive mode closest_labels should be the # labels of the
  1380. // query name)
  1381. const uint8_t expected_closest_labels =
  1382. Name("example.com").getLabelCount();
  1383. // Apex name. It should have a matching NSEC3
  1384. nsec3Check(true, expected_closest_labels, nsec3_apex_txt,
  1385. mock_finder->findNSEC3(Name("example.com"), false));
  1386. // Recursive mode doesn't change the result in this case.
  1387. nsec3Check(true, expected_closest_labels, nsec3_apex_txt,
  1388. mock_finder->findNSEC3(Name("example.com"), true));
  1389. // Non existent name. Disabling recursion, a covering NSEC3 should be
  1390. // returned.
  1391. nsec3Check(false, 4, nsec3_www_txt,
  1392. mock_finder->findNSEC3(Name("nxdomain.example.com"), false));
  1393. // Non existent name. The closest provable encloser is the apex,
  1394. // and next closer is the query name.
  1395. nsec3Check(true, expected_closest_labels,
  1396. string(nsec3_apex_txt) + string(nsec3_www_txt),
  1397. mock_finder->findNSEC3(Name("nxdomain.example.com"), true));
  1398. // Similar to the previous case, but next closer name is different
  1399. // (is the parent) of the non existent name.
  1400. nsec3Check(true, expected_closest_labels,
  1401. string(nsec3_apex_txt) + string(nsec3_www_txt),
  1402. mock_finder->findNSEC3(Name("nx.domain.example.com"), true));
  1403. // In the rest of test we check hash comparison for wrap around cases.
  1404. nsec3Check(false, 4, nsec3_apex_txt,
  1405. mock_finder->findNSEC3(Name("nxdomain2.example.com"), false));
  1406. nsec3Check(false, 4, nsec3_www_txt,
  1407. mock_finder->findNSEC3(Name("nxdomain3.example.com"), false));
  1408. }
  1409. // The following are tentative tests until we really add tests for the
  1410. // query logic for these cases. At that point it's probably better to
  1411. // clean them up.
  1412. TEST_F(QueryTest, nxdomainWithNSEC3) {
  1413. mock_finder->setNSEC3Flag(true);
  1414. ZoneFinder::FindResult result = mock_finder->find(
  1415. Name("nxdomain.example.com"), RRType::A(), ZoneFinder::FIND_DNSSEC);
  1416. EXPECT_EQ(ZoneFinder::NXDOMAIN, result.code);
  1417. EXPECT_FALSE(result.rrset);
  1418. EXPECT_TRUE(result.isNSEC3Signed());
  1419. EXPECT_FALSE(result.isWildcard());
  1420. }
  1421. TEST_F(QueryTest, nxrrsetWithNSEC3) {
  1422. mock_finder->setNSEC3Flag(true);
  1423. ZoneFinder::FindResult result = mock_finder->find(
  1424. Name("www.example.com"), RRType::TXT(), ZoneFinder::FIND_DNSSEC);
  1425. EXPECT_EQ(ZoneFinder::NXRRSET, result.code);
  1426. EXPECT_FALSE(result.rrset);
  1427. EXPECT_TRUE(result.isNSEC3Signed());
  1428. EXPECT_FALSE(result.isWildcard());
  1429. }
  1430. TEST_F(QueryTest, emptyNameWithNSEC3) {
  1431. mock_finder->setNSEC3Flag(true);
  1432. ZoneFinder::FindResult result = mock_finder->find(
  1433. Name("no.example.com"), RRType::A(), ZoneFinder::FIND_DNSSEC);
  1434. EXPECT_EQ(ZoneFinder::NXRRSET, result.code);
  1435. EXPECT_FALSE(result.rrset);
  1436. EXPECT_TRUE(result.isNSEC3Signed());
  1437. EXPECT_FALSE(result.isWildcard());
  1438. }
  1439. TEST_F(QueryTest, wildcardNxrrsetWithNSEC3) {
  1440. mock_finder->setNSEC3Flag(true);
  1441. ZoneFinder::FindResult result = mock_finder->find(
  1442. Name("www1.uwild.example.com"), RRType::TXT(),
  1443. ZoneFinder::FIND_DNSSEC);
  1444. EXPECT_EQ(ZoneFinder::NXRRSET, result.code);
  1445. EXPECT_FALSE(result.rrset);
  1446. EXPECT_TRUE(result.isNSEC3Signed());
  1447. EXPECT_TRUE(result.isWildcard());
  1448. }
  1449. TEST_F(QueryTest, wildcardEmptyWithNSEC3) {
  1450. mock_finder->setNSEC3Flag(true);
  1451. ZoneFinder::FindResult result = mock_finder->find(
  1452. Name("a.t.example.com"), RRType::A(), ZoneFinder::FIND_DNSSEC);
  1453. EXPECT_EQ(ZoneFinder::NXRRSET, result.code);
  1454. EXPECT_TRUE(result.isNSEC3Signed());
  1455. EXPECT_TRUE(result.isWildcard());
  1456. }
  1457. }