You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

975 lines
30 KiB

  1. #define BOOST_TEST_DYN_LINK
  2. #define BOOST_TEST_NO_MAIN
  3. #include <boost/test/unit_test.hpp>
  4. #include <boost/assign/std/map.hpp>
  5. #include <numeric>
  6. #include <math.h>
  7. #include "dnsname.hh"
  8. #include "misc.hh"
  9. #include "dnswriter.hh"
  10. #include "dnsrecords.hh"
  11. #include <unordered_set>
  12. using namespace boost;
  13. using std::string;
  14. BOOST_AUTO_TEST_SUITE(test_dnsname_cc)
  15. BOOST_AUTO_TEST_CASE(test_basic) {
  16. DNSName aroot("a.root-servers.net"), broot("b.root-servers.net");
  17. BOOST_CHECK(aroot < broot);
  18. BOOST_CHECK(!(broot < aroot));
  19. BOOST_CHECK(aroot.canonCompare(broot));
  20. BOOST_CHECK(!broot.canonCompare(aroot));
  21. string before("www.ds9a.nl.");
  22. DNSName b(before);
  23. BOOST_CHECK_EQUAL(b.getRawLabels().size(), 3U);
  24. string after(b.toString());
  25. BOOST_CHECK_EQUAL(before, after);
  26. DNSName jpmens("ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test.");
  27. BOOST_CHECK_EQUAL(jpmens.toString(), "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test.");
  28. DNSName wwwds9anl("www.ds9a.nl.");
  29. DNSName wwwds9anl1("www.ds9a\002nl.");
  30. DNSName nl("nl.");
  31. BOOST_CHECK(wwwds9anl.isPartOf(nl));
  32. BOOST_CHECK(!wwwds9anl1.isPartOf(nl));
  33. BOOST_CHECK(wwwds9anl.isPartOf(wwwds9anl));
  34. BOOST_CHECK(!nl.isPartOf(wwwds9anl));
  35. BOOST_CHECK(wwwds9anl == wwwds9anl);
  36. BOOST_CHECK(DNSName("wWw.ds9A.Nl.") == DNSName("www.ds9a.nl."));
  37. BOOST_CHECK(DNSName("www.ds9a.nl.") == DNSName("www.ds9a.nl."));
  38. BOOST_CHECK(DNSName("www.ds9a.nl.").toString() == "www.ds9a.nl.");
  39. { // Check root vs empty
  40. DNSName name("."); // root
  41. DNSName parent; // empty
  42. BOOST_CHECK(name != parent);
  43. }
  44. { // Check name part of root
  45. DNSName name("a.");
  46. DNSName parent(".");
  47. BOOST_CHECK(name.isPartOf(parent));
  48. }
  49. { // Label boundary
  50. DNSName name("a\002bb.");
  51. DNSName parent("bb.");
  52. BOOST_CHECK(!name.isPartOf(parent));
  53. }
  54. { // Multi label parent
  55. DNSName name("a.bb.ccc.dddd.");
  56. DNSName parent("ccc.dddd.");
  57. BOOST_CHECK(name.isPartOf(parent));
  58. }
  59. { // Last char diff
  60. DNSName name("a.bb.ccc.dddd.");
  61. DNSName parent("ccc.dddx.");
  62. BOOST_CHECK(!name.isPartOf(parent));
  63. }
  64. { // Equal length identical
  65. DNSName name("aaaa.bbb.cc.d.");
  66. DNSName parent("aaaa.bbb.cc.d.");
  67. BOOST_CHECK(name.isPartOf(parent));
  68. }
  69. { // Equal length first char diff
  70. DNSName name("xaaa.bbb.cc.d.");
  71. DNSName parent("aaaa.bbb.cc.d.");
  72. BOOST_CHECK(!name.isPartOf(parent));
  73. }
  74. { // Make relative
  75. DNSName name("aaaa.bbb.cc.d.");
  76. DNSName parent("cc.d.");
  77. BOOST_CHECK_EQUAL( name.makeRelative(parent), DNSName("aaaa.bbb."));
  78. }
  79. { // Labelreverse
  80. DNSName name("aaaa.bbb.cc.d.");
  81. BOOST_CHECK( name.labelReverse() == DNSName("d.cc.bbb.aaaa."));
  82. }
  83. { // empty() empty
  84. DNSName name;
  85. BOOST_CHECK(name.empty());
  86. }
  87. { // empty() root
  88. DNSName name(".");
  89. BOOST_CHECK(!name.empty());
  90. DNSName rootnodot("");
  91. BOOST_CHECK_EQUAL(name, rootnodot);
  92. string empty;
  93. DNSName rootnodot2(empty);
  94. BOOST_CHECK_EQUAL(rootnodot2, name);
  95. }
  96. DNSName left("ds9a.nl.");
  97. left.prependRawLabel("www");
  98. BOOST_CHECK( left == DNSName("WwW.Ds9A.Nl."));
  99. left.appendRawLabel("com");
  100. BOOST_CHECK( left == DNSName("WwW.Ds9A.Nl.com."));
  101. DNSName unset;
  102. unset.appendRawLabel("www");
  103. unset.appendRawLabel("powerdns.com");
  104. unset.appendRawLabel("com");
  105. BOOST_CHECK_EQUAL(unset.toString(), "www.powerdns\\.com.com.");
  106. DNSName rfc4343_2_1("~!.example.");
  107. DNSName rfc4343_2_2(R"(Donald\032E\.\032Eastlake\0323rd.example.)");
  108. DNSName example("example.");
  109. BOOST_CHECK(rfc4343_2_1.isPartOf(example));
  110. BOOST_CHECK(rfc4343_2_2.isPartOf(example));
  111. BOOST_CHECK_EQUAL(rfc4343_2_1.toString(), "~!.example.");
  112. auto labels=rfc4343_2_2.getRawLabels();
  113. BOOST_CHECK_EQUAL(*labels.begin(), "Donald E. Eastlake 3rd");
  114. BOOST_CHECK_EQUAL(*labels.rbegin(), "example");
  115. BOOST_CHECK_EQUAL(labels.size(), 2U);
  116. DNSName build;
  117. build.appendRawLabel("Donald E. Eastlake 3rd");
  118. build.appendRawLabel("example");
  119. BOOST_CHECK_EQUAL(build.toString(), R"(Donald\032E\.\032Eastlake\0323rd.example.)");
  120. BOOST_CHECK_THROW(DNSName broken("bert..hubert."), std::runtime_error);
  121. DNSName n;
  122. n.appendRawLabel("powerdns.dnsmaster");
  123. n.appendRawLabel("powerdns");
  124. n.appendRawLabel("com");
  125. BOOST_CHECK_EQUAL(n.toString(), "powerdns\\.dnsmaster.powerdns.com.");
  126. // BOOST_CHECK(DNSName().toString() != ".");
  127. DNSName p;
  128. string label("power");
  129. label.append(1, (char)0);
  130. label.append("dns");
  131. p.appendRawLabel(label);
  132. p.appendRawLabel("com");
  133. BOOST_CHECK_EQUAL(p.toString(), "power\\000dns.com.");
  134. }
  135. BOOST_AUTO_TEST_CASE(test_trim) {
  136. DNSName w("www.powerdns.com.");
  137. BOOST_CHECK_EQUAL(w.countLabels(), 3U);
  138. w.trimToLabels(2);
  139. BOOST_CHECK_EQUAL(w.toString(), "powerdns.com.");
  140. DNSName w2("powerdns.com.");
  141. BOOST_CHECK(w==w2);
  142. DNSName root(".");
  143. BOOST_CHECK_EQUAL(root.countLabels(), 0U);
  144. }
  145. BOOST_AUTO_TEST_CASE(test_toolong) {
  146. BOOST_CHECK_THROW(DNSName w("1234567890123456789012345678901234567890123456789012345678901234567890.com."), std::range_error);
  147. BOOST_CHECK_THROW(DNSName w("12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.234567890.789012345678901.234567890.234567890.789012345678901.234567890.234567890.com."), std::range_error);
  148. }
  149. BOOST_AUTO_TEST_CASE(test_dnsstrings) {
  150. DNSName w("www.powerdns.com.");
  151. BOOST_CHECK_EQUAL(w.toDNSString(), string("\003www\010powerdns\003com\000", 18));
  152. }
  153. BOOST_AUTO_TEST_CASE(test_empty) {
  154. DNSName empty;
  155. BOOST_CHECK_THROW(empty.toString(), std::out_of_range);
  156. BOOST_CHECK_THROW(empty.toStringNoDot(), std::out_of_range);
  157. BOOST_CHECK_THROW(empty.toDNSString(), std::out_of_range);
  158. BOOST_CHECK(empty.empty());
  159. BOOST_CHECK(!empty.isRoot());
  160. BOOST_CHECK(!empty.isWildcard());
  161. BOOST_CHECK_EQUAL(empty, empty);
  162. BOOST_CHECK(!(empty < empty));
  163. DNSName root(".");
  164. BOOST_CHECK(empty < root);
  165. BOOST_CHECK_THROW(empty.isPartOf(root), std::out_of_range);
  166. BOOST_CHECK_THROW(root.isPartOf(empty), std::out_of_range);
  167. }
  168. BOOST_AUTO_TEST_CASE(test_specials) {
  169. DNSName root(".");
  170. BOOST_CHECK(root.isRoot());
  171. BOOST_CHECK(root != DNSName());
  172. DNSName wcard("*.powerdns.com");
  173. BOOST_CHECK(wcard.isWildcard());
  174. DNSName notwcard("www.powerdns.com");
  175. BOOST_CHECK(!notwcard.isWildcard());
  176. }
  177. BOOST_AUTO_TEST_CASE(test_chopping) {
  178. DNSName w("www.powerdns.com.");
  179. BOOST_CHECK_EQUAL(w.toString(), "www.powerdns.com.");
  180. BOOST_CHECK(w.chopOff());
  181. BOOST_CHECK_EQUAL(w.toString(), "powerdns.com.");
  182. BOOST_CHECK(w.chopOff());
  183. BOOST_CHECK_EQUAL(w.toString(), "com.");
  184. BOOST_CHECK(w.chopOff());
  185. BOOST_CHECK_EQUAL(w.toString(), ".");
  186. BOOST_CHECK(!w.chopOff());
  187. BOOST_CHECK(!w.chopOff());
  188. w.prependRawLabel("net");
  189. w.prependRawLabel("root-servers");
  190. w.prependRawLabel("a");
  191. BOOST_CHECK_EQUAL(w.toString(), "a.root-servers.net.");
  192. }
  193. BOOST_AUTO_TEST_CASE(test_Append) {
  194. DNSName dn("www."), powerdns("powerdns.com.");
  195. DNSName tot=dn+powerdns;
  196. BOOST_CHECK_EQUAL(tot.toString(), "www.powerdns.com.");
  197. BOOST_CHECK(tot == DNSName("www.powerdns.com."));
  198. dn+=powerdns;
  199. BOOST_CHECK(dn == DNSName("www.powerdns.com."));
  200. }
  201. BOOST_AUTO_TEST_CASE(test_packetCompress) {
  202. reportBasicTypes();
  203. vector<unsigned char> packet;
  204. DNSPacketWriter dpw(packet, DNSName("www.ds9a.nl."), QType::AAAA);
  205. dpw.startRecord(DNSName("ds9a.nl"), QType::SOA);
  206. SOARecordContent src("ns1.powerdns.nl admin.powerdns.nl 1 2 3 4 5");
  207. src.toPacket(dpw);
  208. AAAARecordContent aaaa("::1");
  209. dpw.startRecord(DNSName("www.dS9A.nl"), QType::AAAA);
  210. aaaa.toPacket(dpw);
  211. dpw.startRecord(DNSName("www.ds9A.nl"), QType::AAAA);
  212. aaaa.toPacket(dpw);
  213. dpw.startRecord(DNSName("www.dS9a.nl"), QType::AAAA);
  214. aaaa.toPacket(dpw);
  215. dpw.startRecord(DNSName("www2.DS9a.nl"), QType::AAAA);
  216. aaaa.toPacket(dpw);
  217. dpw.startRecord(DNSName("www2.dS9a.nl"), QType::AAAA);
  218. aaaa.toPacket(dpw);
  219. dpw.commit();
  220. string str((const char*)&packet[0], (const char*)&packet[0] + packet.size());
  221. size_t pos = 0;
  222. int count=0;
  223. while((pos = str.find("ds9a", pos)) != string::npos) {
  224. ++pos;
  225. ++count;
  226. }
  227. BOOST_CHECK_EQUAL(count, 1);
  228. pos = 0;
  229. count=0;
  230. while((pos = str.find("powerdns", pos)) != string::npos) {
  231. ++pos;
  232. ++count;
  233. }
  234. BOOST_CHECK_EQUAL(count, 1);
  235. }
  236. BOOST_AUTO_TEST_CASE(test_packetCompressLong) {
  237. reportBasicTypes();
  238. vector<unsigned char> packet;
  239. DNSName loopback("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa");
  240. DNSPacketWriter dpw(packet, loopback, QType::PTR);
  241. dpw.startRecord(loopback, QType::PTR);
  242. PTRRecordContent prc(DNSName("localhost"));
  243. prc.toPacket(dpw);
  244. dpw.commit();
  245. DNSName roundtrip((char*)&packet[0], packet.size(), 12, false);
  246. BOOST_CHECK_EQUAL(loopback,roundtrip);
  247. packet.clear();
  248. DNSName longer("1.2.3.4.5.6.7.8.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa");
  249. DNSPacketWriter dpw2(packet, longer, QType::PTR);
  250. dpw2.startRecord(DNSName("a.b.c.d.e")+longer, QType::PTR);
  251. PTRRecordContent prc2(DNSName("localhost"));
  252. prc2.toPacket(dpw2);
  253. dpw2.commit();
  254. }
  255. BOOST_AUTO_TEST_CASE(test_PacketParse) {
  256. vector<unsigned char> packet;
  257. reportBasicTypes();
  258. DNSName root(".");
  259. DNSPacketWriter dpw1(packet, g_rootdnsname, QType::AAAA);
  260. DNSName p((char*)&packet[0], packet.size(), 12, false);
  261. BOOST_CHECK_EQUAL(p, root);
  262. unsigned char* buffer=&packet[0];
  263. /* set invalid label len:
  264. - packet.size() == 17 (sizeof(dnsheader) + 1 + 2 + 2)
  265. - label len < packet.size() but
  266. - offset is 12, label len of 15 should be rejected
  267. because offset + 15 >= packet.size()
  268. */
  269. buffer[sizeof(dnsheader)] = 15;
  270. BOOST_CHECK_THROW(DNSName((char*)&packet[0], packet.size(), 12, false), std::range_error);
  271. }
  272. BOOST_AUTO_TEST_CASE(test_hash) {
  273. DNSName a("wwW.Ds9A.Nl"), b("www.ds9a.nl");
  274. BOOST_CHECK_EQUAL(a.hash(), b.hash());
  275. vector<uint32_t> counts(1500);
  276. for(unsigned int n=0; n < 100000; ++n) {
  277. DNSName dn(std::to_string(n)+"."+std::to_string(n*2)+"ds9a.nl");
  278. DNSName dn2(std::to_string(n)+"."+std::to_string(n*2)+"Ds9a.nL");
  279. BOOST_CHECK_EQUAL(dn.hash(), dn2.hash());
  280. counts[dn.hash() % counts.size()]++;
  281. }
  282. double sum = std::accumulate(std::begin(counts), std::end(counts), 0.0);
  283. double m = sum / counts.size();
  284. double accum = 0.0;
  285. std::for_each (std::begin(counts), std::end(counts), [&](const double d) {
  286. accum += (d - m) * (d - m);
  287. });
  288. double stdev = sqrt(accum / (counts.size()-1));
  289. BOOST_CHECK(stdev < 10);
  290. }
  291. BOOST_AUTO_TEST_CASE(test_hashContainer) {
  292. std::unordered_set<DNSName> s;
  293. s.insert(DNSName("www.powerdns.com"));
  294. BOOST_CHECK(s.count(DNSName("WwW.PoWerDNS.CoM")));
  295. BOOST_CHECK_EQUAL(s.size(), 1U);
  296. s.insert(DNSName("www.POWERDNS.com"));
  297. BOOST_CHECK_EQUAL(s.size(), 1U);
  298. s.insert(DNSName("www2.POWERDNS.com"));
  299. BOOST_CHECK_EQUAL(s.size(), 2U);
  300. s.clear();
  301. unsigned int n=0;
  302. for(; n < 100000; ++n)
  303. s.insert(DNSName(std::to_string(n)+".test.nl"));
  304. BOOST_CHECK_EQUAL(s.size(), n);
  305. }
  306. BOOST_AUTO_TEST_CASE(test_QuestionHash) {
  307. vector<unsigned char> packet;
  308. reportBasicTypes();
  309. DNSPacketWriter dpw1(packet, DNSName("www.ds9a.nl."), QType::AAAA);
  310. auto hash1=hashQuestion((char*)&packet[0], packet.size(), 0);
  311. DNSPacketWriter dpw2(packet, DNSName("wWw.Ds9A.nL."), QType::AAAA);
  312. auto hash2=hashQuestion((char*)&packet[0], packet.size(), 0);
  313. BOOST_CHECK_EQUAL(hash1, hash2);
  314. vector<uint32_t> counts(1500);
  315. for(unsigned int n=0; n < 100000; ++n) {
  316. packet.clear();
  317. DNSPacketWriter dpw3(packet, DNSName(std::to_string(n)+"."+std::to_string(n*2)+"."), QType::AAAA);
  318. counts[hashQuestion((char*)&packet[0], packet.size(), 0) % counts.size()]++;
  319. }
  320. double sum = std::accumulate(std::begin(counts), std::end(counts), 0.0);
  321. double m = sum / counts.size();
  322. double accum = 0.0;
  323. std::for_each (std::begin(counts), std::end(counts), [&](const double d) {
  324. accum += (d - m) * (d - m);
  325. });
  326. double stdev = sqrt(accum / (counts.size()-1));
  327. BOOST_CHECK(stdev < 10);
  328. }
  329. BOOST_AUTO_TEST_CASE(test_packetParse) {
  330. vector<unsigned char> packet;
  331. reportBasicTypes();
  332. DNSPacketWriter dpw(packet, DNSName("www.ds9a.nl."), QType::AAAA);
  333. uint16_t qtype, qclass;
  334. DNSName dn((char*)&packet[0], packet.size(), 12, false, &qtype, &qclass);
  335. BOOST_CHECK_EQUAL(dn.toString(), "www.ds9a.nl.");
  336. BOOST_CHECK(qtype == QType::AAAA);
  337. BOOST_CHECK_EQUAL(qclass, 1);
  338. dpw.startRecord(DNSName("ds9a.nl."), DNSRecordContent::TypeToNumber("NS"));
  339. NSRecordContent nrc("ns1.powerdns.com");
  340. nrc.toPacket(dpw);
  341. dpw.commit();
  342. /* packet now looks like this:
  343. 012345678901 12 bytes of header
  344. 3www4ds9a2nl0 13 bytes of name
  345. 0001 0001 4 bytes of qtype and qclass
  346. answername 2 bytes
  347. 0001 0001 4 bytes of qtype and class
  348. 0000 0000 4 bytes of TTL
  349. 0000 2 bytes of content length
  350. content name */
  351. DNSName dn2((char*)&packet[0], packet.size(), 12+13+4, true, &qtype, &qclass);
  352. BOOST_CHECK_EQUAL(dn2.toString(), "ds9a.nl.");
  353. BOOST_CHECK(qtype == QType::NS);
  354. BOOST_CHECK_EQUAL(qclass, 1);
  355. DNSName dn3((char*)&packet[0], packet.size(), 12+13+4+2 + 4 + 4 + 2, true);
  356. BOOST_CHECK_EQUAL(dn3.toString(), "ns1.powerdns.com.");
  357. try {
  358. DNSName dn4((char*)&packet[0], packet.size(), 12+13+4, false); // compressed, should fail
  359. BOOST_CHECK(0);
  360. }
  361. catch(...){}
  362. }
  363. BOOST_AUTO_TEST_CASE(test_escaping) {
  364. DNSName n;
  365. string label;
  366. for(int i = 0; i < 250; ++i) {
  367. if(!((i+1)%63)) {
  368. n.appendRawLabel(label);
  369. label.clear();
  370. }
  371. label.append(1,(char)i);
  372. }
  373. if(!label.empty())
  374. n.appendRawLabel(label);
  375. DNSName n2(n.toString());
  376. BOOST_CHECK(n==n2);
  377. }
  378. BOOST_AUTO_TEST_CASE(test_suffixmatch) {
  379. SuffixMatchNode smn;
  380. DNSName ezdns("ezdns.it.");
  381. smn.add(ezdns.getRawLabels());
  382. smn.add(DNSName("org.").getRawLabels());
  383. DNSName wwwpowerdnscom("www.powerdns.com.");
  384. DNSName wwwezdnsit("www.ezdns.it.");
  385. BOOST_CHECK(smn.check(wwwezdnsit));
  386. BOOST_CHECK(!smn.check(wwwpowerdnscom));
  387. BOOST_CHECK(smn.check(DNSName("www.powerdns.org.")));
  388. BOOST_CHECK(smn.check(DNSName("www.powerdns.oRG.")));
  389. smn.add(DNSName("news.bbc.co.uk."));
  390. BOOST_CHECK(smn.check(DNSName("news.bbc.co.uk.")));
  391. BOOST_CHECK(smn.check(DNSName("www.news.bbc.co.uk.")));
  392. BOOST_CHECK(smn.check(DNSName("www.www.www.www.www.news.bbc.co.uk.")));
  393. BOOST_CHECK(!smn.check(DNSName("images.bbc.co.uk.")));
  394. BOOST_CHECK(!smn.check(DNSName("www.news.gov.uk.")));
  395. smn.add(g_rootdnsname); // block the root
  396. BOOST_CHECK(smn.check(DNSName("a.root-servers.net.")));
  397. DNSName examplenet("example.net.");
  398. DNSName net("net.");
  399. smn.add(examplenet);
  400. smn.add(net);
  401. BOOST_CHECK(smn.check(examplenet));
  402. BOOST_CHECK(smn.check(net));
  403. // Remove .net and the root, and check that example.net still exists
  404. smn.remove(g_rootdnsname);
  405. smn.remove(net);
  406. BOOST_CHECK_EQUAL(smn.check(net), false);
  407. BOOST_CHECK(smn.check(examplenet));
  408. smn.add(DNSName("fr."));
  409. smn.add(DNSName("www.sub.domain.fr."));
  410. // should not match www.sub.domain.fr. but should still match fr.
  411. BOOST_CHECK(smn.check(DNSName("sub.domain.fr.")));
  412. }
  413. BOOST_AUTO_TEST_CASE(test_suffixmatch_tree) {
  414. SuffixMatchTree<DNSName> smt;
  415. DNSName ezdns("ezdns.it.");
  416. smt.add(ezdns, ezdns);
  417. smt.add(DNSName("org.").getRawLabels(), DNSName("org."));
  418. DNSName wwwpowerdnscom("www.powerdns.com.");
  419. DNSName wwwezdnsit("www.ezdns.it.");
  420. BOOST_REQUIRE(smt.lookup(wwwezdnsit));
  421. BOOST_CHECK_EQUAL(*smt.lookup(wwwezdnsit), ezdns);
  422. BOOST_CHECK(smt.lookup(wwwpowerdnscom) == nullptr);
  423. BOOST_REQUIRE(smt.lookup(DNSName("www.powerdns.org.")));
  424. BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.powerdns.org.")), DNSName("org."));
  425. BOOST_REQUIRE(smt.lookup(DNSName("www.powerdns.oRG.")));
  426. BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.powerdns.oRG.")), DNSName("org."));
  427. smt.add(DNSName("news.bbc.co.uk."), DNSName("news.bbc.co.uk."));
  428. BOOST_REQUIRE(smt.lookup(DNSName("news.bbc.co.uk.")));
  429. BOOST_CHECK_EQUAL(*smt.lookup(DNSName("news.bbc.co.uk.")), DNSName("news.bbc.co.uk."));
  430. BOOST_REQUIRE(smt.lookup(DNSName("www.news.bbc.co.uk.")));
  431. BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.news.bbc.co.uk.")), DNSName("news.bbc.co.uk."));
  432. BOOST_REQUIRE(smt.lookup(DNSName("www.www.www.www.www.news.bbc.co.uk.")));
  433. BOOST_CHECK_EQUAL(*smt.lookup(DNSName("www.www.www.www.www.news.bbc.co.uk.")), DNSName("news.bbc.co.uk."));
  434. BOOST_CHECK(smt.lookup(DNSName("images.bbc.co.uk.")) == nullptr);
  435. BOOST_CHECK(smt.lookup(DNSName("www.news.gov.uk.")) == nullptr);
  436. smt.add(g_rootdnsname, g_rootdnsname); // block the root
  437. BOOST_REQUIRE(smt.lookup(DNSName("a.root-servers.net.")));
  438. BOOST_CHECK_EQUAL(*smt.lookup(DNSName("a.root-servers.net.")), g_rootdnsname);
  439. DNSName apowerdnscom("a.powerdns.com.");
  440. DNSName bpowerdnscom("b.powerdns.com.");
  441. smt.add(apowerdnscom, apowerdnscom);
  442. smt.add(bpowerdnscom, bpowerdnscom);
  443. BOOST_REQUIRE(smt.lookup(apowerdnscom));
  444. BOOST_CHECK_EQUAL(*smt.lookup(apowerdnscom), apowerdnscom);
  445. BOOST_REQUIRE(smt.lookup(bpowerdnscom));
  446. BOOST_CHECK_EQUAL(*smt.lookup(bpowerdnscom), bpowerdnscom);
  447. DNSName examplenet("example.net.");
  448. DNSName net("net.");
  449. smt.add(examplenet, examplenet);
  450. smt.add(net, net);
  451. BOOST_REQUIRE(smt.lookup(examplenet));
  452. BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
  453. BOOST_REQUIRE(smt.lookup(net));
  454. BOOST_CHECK_EQUAL(*smt.lookup(net), net);
  455. // Remove .net and the root, and check that example.net remains
  456. smt.remove(g_rootdnsname);
  457. smt.remove(net);
  458. BOOST_CHECK(smt.lookup(net) == nullptr);
  459. BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
  460. smt = SuffixMatchTree<DNSName>();
  461. smt.add(examplenet, examplenet);
  462. smt.add(net, net);
  463. smt.add(DNSName("news.bbc.co.uk."), DNSName("news.bbc.co.uk."));
  464. smt.add(apowerdnscom, apowerdnscom);
  465. smt.remove(DNSName("not-such-entry.news.bbc.co.uk."));
  466. BOOST_REQUIRE(smt.lookup(DNSName("news.bbc.co.uk.")));
  467. smt.remove(DNSName("news.bbc.co.uk."));
  468. BOOST_CHECK(smt.lookup(DNSName("news.bbc.co.uk.")) == nullptr);
  469. smt.remove(net);
  470. BOOST_REQUIRE(smt.lookup(examplenet));
  471. BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
  472. BOOST_CHECK(smt.lookup(net) == nullptr);
  473. smt.remove(examplenet);
  474. BOOST_CHECK(smt.lookup(net) == nullptr);
  475. BOOST_CHECK(smt.lookup(examplenet) == nullptr);
  476. smt.add(examplenet, examplenet);
  477. smt.add(net, net);
  478. BOOST_REQUIRE(smt.lookup(examplenet));
  479. BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
  480. BOOST_REQUIRE(smt.lookup(net));
  481. BOOST_CHECK_EQUAL(*smt.lookup(net), net);
  482. smt.remove(examplenet);
  483. BOOST_CHECK_EQUAL(*smt.lookup(examplenet), net);
  484. BOOST_CHECK_EQUAL(*smt.lookup(net), net);
  485. smt.remove(examplenet);
  486. BOOST_CHECK_EQUAL(*smt.lookup(examplenet), net);
  487. BOOST_CHECK_EQUAL(*smt.lookup(net), net);
  488. smt.remove(net);
  489. BOOST_CHECK(smt.lookup(net) == nullptr);
  490. BOOST_CHECK(smt.lookup(examplenet) == nullptr);
  491. smt.remove(net);
  492. size_t count = 0;
  493. smt.visit([apowerdnscom, &count](const SuffixMatchTree<DNSName>& smtarg) {
  494. count++;
  495. BOOST_CHECK_EQUAL(smtarg.d_value, apowerdnscom);
  496. });
  497. BOOST_CHECK_EQUAL(count, 1U);
  498. BOOST_CHECK_EQUAL(*smt.lookup(apowerdnscom), apowerdnscom);
  499. smt.remove(apowerdnscom);
  500. BOOST_CHECK(smt.lookup(apowerdnscom) == nullptr);
  501. count = 0;
  502. smt.visit([&count](const SuffixMatchTree<DNSName>&) {
  503. count++;
  504. });
  505. BOOST_CHECK_EQUAL(count, 0U);
  506. }
  507. BOOST_AUTO_TEST_CASE(test_concat) {
  508. DNSName first("www."), second("powerdns.com.");
  509. BOOST_CHECK_EQUAL((first+second).toString(), "www.powerdns.com.");
  510. }
  511. BOOST_AUTO_TEST_CASE(test_compare_naive) {
  512. BOOST_CHECK(DNSName("abc.com.") < DNSName("zdf.com."));
  513. BOOST_CHECK(DNSName("Abc.com.") < DNSName("zdf.com."));
  514. BOOST_CHECK(DNSName("Abc.com.") < DNSName("Zdf.com."));
  515. BOOST_CHECK(DNSName("abc.com.") < DNSName("Zdf.com."));
  516. }
  517. BOOST_AUTO_TEST_CASE(test_compare_empty) {
  518. DNSName a, b;
  519. BOOST_CHECK(!(a<b));
  520. BOOST_CHECK(!a.canonCompare(b));
  521. }
  522. BOOST_AUTO_TEST_CASE(test_casing) {
  523. DNSName a("WwW.PoWeRdNS.Com"), b("www.powerdns.com.");
  524. BOOST_CHECK_EQUAL(a,b);
  525. BOOST_CHECK_EQUAL(a.toString(), "WwW.PoWeRdNS.Com.");
  526. DNSName c=a.makeLowerCase();
  527. BOOST_CHECK_EQUAL(a,c);
  528. BOOST_CHECK_EQUAL(b,c);
  529. BOOST_CHECK_EQUAL(c.toString(), b.toString());
  530. BOOST_CHECK_EQUAL(c.toString(), "www.powerdns.com.");
  531. }
  532. BOOST_AUTO_TEST_CASE(test_compare_canonical) {
  533. DNSName lower("bert.com."), higher("alpha.nl.");
  534. BOOST_CHECK(lower.canonCompare(higher));
  535. BOOST_CHECK(DNSName("bert.com").canonCompare(DNSName("www.bert.com")));
  536. BOOST_CHECK(DNSName("BeRt.com").canonCompare(DNSName("WWW.berT.com")));
  537. BOOST_CHECK(!DNSName("www.BeRt.com").canonCompare(DNSName("WWW.berT.com")));
  538. CanonDNSNameCompare a;
  539. BOOST_CHECK(a(g_rootdnsname, DNSName("www.powerdns.com")));
  540. BOOST_CHECK(a(g_rootdnsname, DNSName("www.powerdns.net")));
  541. BOOST_CHECK(!a(DNSName("www.powerdns.net"), g_rootdnsname));
  542. vector<DNSName> vec;
  543. for(const std::string& b : {"bert.com.", "alpha.nl.", "articles.xxx.",
  544. "Aleph1.powerdns.com.", "ZOMG.powerdns.com.", "aaa.XXX.", "yyy.XXX.",
  545. "test.powerdns.com.", "\\128.com"}) {
  546. vec.push_back(DNSName(b));
  547. }
  548. sort(vec.begin(), vec.end(), CanonDNSNameCompare());
  549. // for(const auto& v : vec)
  550. // cerr<<'"'<<v<<'"'<<endl;
  551. vector<DNSName> right;
  552. for(const auto& b: {"bert.com.", "Aleph1.powerdns.com.",
  553. "test.powerdns.com.",
  554. "ZOMG.powerdns.com.",
  555. "\\128.com.",
  556. "alpha.nl.",
  557. "aaa.XXX.",
  558. "articles.xxx.",
  559. "yyy.XXX."})
  560. right.push_back(DNSName(b));
  561. BOOST_CHECK(vec==right);
  562. }
  563. BOOST_AUTO_TEST_CASE(test_empty_label) { // empty label
  564. { // append
  565. DNSName dn("www.");
  566. BOOST_CHECK_THROW(dn.appendRawLabel(""), std::range_error);
  567. }
  568. { // prepend
  569. DNSName dn("www.");
  570. BOOST_CHECK_THROW(dn.prependRawLabel(""), std::range_error);
  571. }
  572. }
  573. BOOST_AUTO_TEST_CASE(test_label_length_max) { // 63 char label
  574. string label("123456789012345678901234567890123456789012345678901234567890123");
  575. { // append
  576. DNSName dn("www.");
  577. dn.appendRawLabel(label);
  578. BOOST_CHECK_EQUAL(dn.toString(), "www." + label + ".");
  579. }
  580. { // prepend
  581. DNSName dn("www.");
  582. dn.prependRawLabel(label);
  583. BOOST_CHECK_EQUAL(dn.toString(), label + ".www.");
  584. }
  585. }
  586. BOOST_AUTO_TEST_CASE(test_label_length_too_long) { // 64 char label
  587. string label("1234567890123456789012345678901234567890123456789012345678901234");
  588. { // append
  589. DNSName dn("www.");
  590. BOOST_CHECK_THROW(dn.appendRawLabel(label), std::range_error);
  591. }
  592. { // prepend
  593. DNSName dn("www.");
  594. BOOST_CHECK_THROW(dn.prependRawLabel(label), std::range_error);
  595. }
  596. }
  597. BOOST_AUTO_TEST_CASE(test_name_length_max) { // 255 char name
  598. string name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
  599. "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
  600. "123456789.123456789.123456789.123456789.123456789.");
  601. string label("123");
  602. { // append
  603. DNSName dn(name);
  604. dn.appendRawLabel(label);
  605. BOOST_CHECK_EQUAL(dn.toString().size(), 254U);
  606. }
  607. { // prepend
  608. DNSName dn(name);
  609. dn.prependRawLabel(label);
  610. BOOST_CHECK_EQUAL(dn.toString().size(), 254U);
  611. }
  612. { // concat
  613. DNSName dn(name);
  614. dn += DNSName(label + ".");
  615. BOOST_CHECK_EQUAL(dn.toString().size(), 254U);
  616. }
  617. }
  618. BOOST_AUTO_TEST_CASE(test_name_length_too_long) { // 256 char name
  619. string name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
  620. "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
  621. "123456789.123456789.123456789.123456789.123456789.");
  622. string label("1234");
  623. { // append
  624. DNSName dn(name);
  625. BOOST_CHECK_THROW(dn.appendRawLabel(label), std::range_error);
  626. }
  627. { // prepend
  628. DNSName dn(name);
  629. BOOST_CHECK_THROW(dn.prependRawLabel(label), std::range_error);
  630. }
  631. { // concat
  632. DNSName dn(name);
  633. BOOST_CHECK_THROW(dn += DNSName(label + "."), std::range_error);
  634. }
  635. }
  636. BOOST_AUTO_TEST_CASE(test_invalid_label_length) { // Invalid label length in qname
  637. string name("\x02""ns\x07""example\x04""com\x00", 16);
  638. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error);
  639. }
  640. BOOST_AUTO_TEST_CASE(test_compression) { // Compression test
  641. string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05", 21);
  642. DNSName dn(name.c_str(), name.size(), 15, true);
  643. BOOST_CHECK_EQUAL(dn.toString(), "www.example.com.");
  644. }
  645. BOOST_AUTO_TEST_CASE(test_compression_qtype_qclass) { // Compression test with QClass and QType extraction
  646. uint16_t qtype = 0;
  647. uint16_t qclass = 0;
  648. {
  649. string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""\x01", 25);
  650. DNSName dn(name.c_str(), name.size(), 15, true, &qtype, &qclass);
  651. BOOST_CHECK_EQUAL(dn.toString(), "www.example.com.");
  652. BOOST_CHECK_EQUAL(qtype, 1);
  653. BOOST_CHECK_EQUAL(qclass, 1);
  654. }
  655. {
  656. /* same but this time we are one byte short for the qclass */
  657. string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""", 24);
  658. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true, &qtype, &qclass), std::range_error);
  659. }
  660. {
  661. /* this time with a compression pointer such as (labellen << 8) != 0, see #4718 */
  662. string name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00""\x01", 25);
  663. name.insert(0, 256, '0');
  664. DNSName dn(name.c_str(), name.size(), 271, true, &qtype, &qclass);
  665. BOOST_CHECK_EQUAL(dn.toString(), "www.example.com.");
  666. BOOST_CHECK_EQUAL(qtype, 1);
  667. BOOST_CHECK_EQUAL(qclass, 1);
  668. }
  669. {
  670. /* same but this time we are one byte short for the qclass */
  671. string name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00", 24);
  672. name.insert(0, 256, '0');
  673. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 271, true, &qtype, &qclass), std::range_error);
  674. }
  675. }
  676. BOOST_AUTO_TEST_CASE(test_compression_single_bit_set) { // first 2 bits as 10 or 01, not 11
  677. // first 2 bits: 10
  678. {
  679. string name("\x03""com\x00""\x07""example\x80""\x00""\x03""www\x80""\x05", 21);
  680. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true), std::range_error);
  681. }
  682. // first 2 bits: 01
  683. {
  684. string name("\x03""com\x00""\x07""example\x40""\x00""\x03""www\x40""\x05", 21);
  685. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true), std::range_error);
  686. }
  687. }
  688. BOOST_AUTO_TEST_CASE(test_pointer_pointer_root) { // Pointer to pointer to root
  689. string name("\x00""\xc0""\x00""\x03""com\xc0""\x01",9);
  690. DNSName dn(name.c_str(), name.size(), 3, true);
  691. BOOST_CHECK_EQUAL(dn.toString(), "com.");
  692. }
  693. BOOST_AUTO_TEST_CASE(test_bad_compression_pointer) { // Pointing beyond packet boundary
  694. std::string name("\x03""com\x00""\x07""example\xc0""\x11""xc0""\x00", 17);
  695. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.length(), 5, true), std::range_error);
  696. }
  697. BOOST_AUTO_TEST_CASE(test_compression_loop) { // Compression loop (add one label)
  698. std::string name("\x03""www\xc0""\x00", 6);
  699. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.length(), 0, true), std::range_error);
  700. }
  701. BOOST_AUTO_TEST_CASE(test_compression_loop1) { // Compression loop (pointer loop)
  702. string name("\xc0""\x00", 2);
  703. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error);
  704. }
  705. BOOST_AUTO_TEST_CASE(test_compression_loop2) { // Compression loop (deep recursion)
  706. int i;
  707. string name("\x00\xc0\x00", 3);
  708. for (i=0; i<98; ++i) {
  709. name.append( 1, ((i >> 7) & 0xff) | 0xc0);
  710. name.append( 1, ((i << 1) & 0xff) | 0x01);
  711. }
  712. BOOST_CHECK_NO_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true));
  713. ++i;
  714. name.append( 1, ((i >> 7) & 0xff) | 0xc0);
  715. name.append( 1, ((i << 1) & 0xff) | 0x01);
  716. BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true), std::range_error);
  717. }
  718. BOOST_AUTO_TEST_CASE(test_wirelength) { // Testing if we get the correct value from the wirelength function
  719. DNSName name("www.powerdns.com");
  720. BOOST_CHECK_EQUAL(name.wirelength(), 18U);
  721. DNSName sname("powerdns.com");
  722. sname.prependRawLabel(string("ww\x00""w", 4));
  723. BOOST_CHECK_EQUAL(sname.wirelength(), 19U);
  724. sname = DNSName("powerdns.com");
  725. sname.prependRawLabel(string("www\x00", 4));
  726. BOOST_CHECK_EQUAL(sname.wirelength(), 19U);
  727. }
  728. BOOST_AUTO_TEST_CASE(test_getrawlabel) {
  729. DNSName name("a.bb.ccc.dddd.");
  730. BOOST_CHECK_EQUAL(name.getRawLabel(0), "a");
  731. BOOST_CHECK_EQUAL(name.getRawLabel(1), "bb");
  732. BOOST_CHECK_EQUAL(name.getRawLabel(2), "ccc");
  733. BOOST_CHECK_EQUAL(name.getRawLabel(3), "dddd");
  734. BOOST_CHECK_THROW(name.getRawLabel(name.countLabels()), std::out_of_range);
  735. }
  736. BOOST_AUTO_TEST_CASE(test_getlastlabel) {
  737. DNSName name("www.powerdns.com");
  738. DNSName ans = name.getLastLabel();
  739. // Check the const-ness
  740. BOOST_CHECK_EQUAL(name, DNSName("www.powerdns.com"));
  741. // Check if the last label is indeed returned
  742. BOOST_CHECK_EQUAL(ans, DNSName("com"));
  743. }
  744. BOOST_AUTO_TEST_CASE(test_getcommonlabels) {
  745. const DNSName name1("www.powerdns.com");
  746. const DNSName name2("a.long.list.of.labels.powerdns.com");
  747. BOOST_CHECK_EQUAL(name1.getCommonLabels(name1), name1);
  748. BOOST_CHECK_EQUAL(name2.getCommonLabels(name2), name2);
  749. BOOST_CHECK_EQUAL(name1.getCommonLabels(name2), DNSName("powerdns.com"));
  750. BOOST_CHECK_EQUAL(name2.getCommonLabels(name1), DNSName("powerdns.com"));
  751. const DNSName name3("www.powerdns.org");
  752. BOOST_CHECK_EQUAL(name1.getCommonLabels(name3), DNSName());
  753. BOOST_CHECK_EQUAL(name2.getCommonLabels(name3), DNSName());
  754. BOOST_CHECK_EQUAL(name3.getCommonLabels(name1), DNSName());
  755. BOOST_CHECK_EQUAL(name3.getCommonLabels(name2), DNSName());
  756. const DNSName name4("WWw.PowErDnS.org");
  757. BOOST_CHECK_EQUAL(name3.getCommonLabels(name4), name3);
  758. BOOST_CHECK_EQUAL(name4.getCommonLabels(name3), name4);
  759. }
  760. BOOST_AUTO_TEST_SUITE_END()