query_unittest.cc 82 KB

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