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