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