1 #ifndef BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_DYN_LINK
5 #define BOOST_TEST_NO_MAIN
7 #include <boost/test/unit_test.hpp>
11 #include <unordered_set>
15 #include "dnswriter.hh"
16 #include "dnsrecords.hh"
18 using namespace boost
;
21 BOOST_AUTO_TEST_SUITE(test_dnsname_cc
)
23 BOOST_AUTO_TEST_CASE(test_basic
) {
24 DNSName
aroot("a.root-servers.net"), broot("b.root-servers.net");
25 BOOST_CHECK(aroot
< broot
);
26 BOOST_CHECK(!(broot
< aroot
));
27 BOOST_CHECK(aroot
.canonCompare(broot
));
28 BOOST_CHECK(!broot
.canonCompare(aroot
));
31 string
before("www.ds9a.nl.");
33 BOOST_CHECK_EQUAL(b
.getRawLabels().size(), 3U);
34 string
after(b
.toString());
35 BOOST_CHECK_EQUAL(before
, after
);
37 DNSName
jpmens("ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test.");
39 BOOST_CHECK_EQUAL(jpmens
.toString(), "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test.");
41 DNSName
wwwds9anl("www.ds9a.nl.");
42 DNSName
wwwds9anl1("www.ds9a\002nl.");
44 BOOST_CHECK(wwwds9anl
.isPartOf(nl
));
45 BOOST_CHECK(!wwwds9anl1
.isPartOf(nl
));
46 BOOST_CHECK(wwwds9anl
.isPartOf(wwwds9anl
));
48 BOOST_CHECK(!nl
.isPartOf(wwwds9anl
));
50 BOOST_CHECK(wwwds9anl
== wwwds9anl
);
52 BOOST_CHECK(DNSName("wWw.ds9A.Nl.") == DNSName("www.ds9a.nl."));
53 BOOST_CHECK(DNSName("www.ds9a.nl.") == DNSName("www.ds9a.nl."));
55 BOOST_CHECK(DNSName("www.ds9a.nl.").toString() == "www.ds9a.nl.");
58 { // Check root vs empty
59 DNSName
name("."); // root
60 DNSName parent
; // empty
61 BOOST_CHECK(name
!= parent
);
64 { // Check name part of root
67 BOOST_CHECK(name
.isPartOf(parent
));
71 DNSName
name("a\002bb.");
72 DNSName
parent("bb.");
73 BOOST_CHECK(!name
.isPartOf(parent
));
76 { // Multi label parent
77 DNSName
name("a.bb.ccc.dddd.");
78 DNSName
parent("ccc.dddd.");
79 BOOST_CHECK(name
.isPartOf(parent
));
83 DNSName
name("a.bb.ccc.dddd.");
84 DNSName
parent("ccc.dddx.");
85 BOOST_CHECK(!name
.isPartOf(parent
));
88 { // Equal length identical
89 DNSName
name("aaaa.bbb.cc.d.");
90 DNSName
parent("aaaa.bbb.cc.d.");
91 BOOST_CHECK(name
.isPartOf(parent
));
94 { // Equal length first char diff
95 DNSName
name("xaaa.bbb.cc.d.");
96 DNSName
parent("aaaa.bbb.cc.d.");
97 BOOST_CHECK(!name
.isPartOf(parent
));
101 DNSName
name("aaaa.bbb.cc.d.");
102 DNSName
parent("cc.d.");
103 BOOST_CHECK_EQUAL( name
.makeRelative(parent
), DNSName("aaaa.bbb."));
107 DNSName
name("aaaa.bbb.cc.d.");
108 BOOST_CHECK( name
.labelReverse() == DNSName("d.cc.bbb.aaaa."));
113 BOOST_CHECK(name
.empty());
118 BOOST_CHECK(!name
.empty());
120 DNSName
rootnodot("");
121 BOOST_CHECK_EQUAL(name
, rootnodot
);
124 DNSName
rootnodot2(empty
);
125 BOOST_CHECK_EQUAL(rootnodot2
, name
);
128 DNSName
left("ds9a.nl.");
129 left
.prependRawLabel("www");
130 BOOST_CHECK( left
== DNSName("WwW.Ds9A.Nl."));
132 left
.appendRawLabel("com");
134 BOOST_CHECK( left
== DNSName("WwW.Ds9A.Nl.com."));
138 unset
.appendRawLabel("www");
139 unset
.appendRawLabel("powerdns.com");
140 unset
.appendRawLabel("com");
142 BOOST_CHECK_EQUAL(unset
.toString(), "www.powerdns\\.com.com.");
144 DNSName
rfc4343_2_1("~!.example.");
145 DNSName
rfc4343_2_2(R
"(Donald\032E\.\032Eastlake\0323rd.example.)");
146 DNSName
example("example.");
147 BOOST_CHECK(rfc4343_2_1
.isPartOf(example
));
148 BOOST_CHECK(rfc4343_2_2
.isPartOf(example
));
149 BOOST_CHECK_EQUAL(rfc4343_2_1
.toString(), "~!.example.");
151 auto labels
=rfc4343_2_2
.getRawLabels();
152 BOOST_CHECK_EQUAL(*labels
.begin(), "Donald E. Eastlake 3rd");
153 BOOST_CHECK_EQUAL(*labels
.rbegin(), "example");
154 BOOST_CHECK_EQUAL(labels
.size(), 2U);
157 build
.appendRawLabel("Donald E. Eastlake 3rd");
158 build
.appendRawLabel("example");
159 BOOST_CHECK_EQUAL(build
.toString(), R
"(Donald\032E\.\032Eastlake\0323rd.example.)");
160 BOOST_CHECK_THROW(DNSName
broken("bert..hubert."), std::runtime_error
);
163 n
.appendRawLabel("powerdns.dnsmaster");
164 n
.appendRawLabel("powerdns");
165 n
.appendRawLabel("com");
167 BOOST_CHECK_EQUAL(n
.toString(), "powerdns\\.dnsmaster.powerdns.com.");
169 // BOOST_CHECK(DNSName().toString() != ".");
172 string
label("power");
173 label
.append(1, (char)0);
175 p
.appendRawLabel(label
);
176 p
.appendRawLabel("com");
178 BOOST_CHECK_EQUAL(p
.toString(), "power\\000dns.com.");
181 BOOST_AUTO_TEST_CASE(test_trim
) {
182 DNSName
w("www.powerdns.com.");
183 BOOST_CHECK_EQUAL(w
.countLabels(), 3U);
185 BOOST_CHECK_EQUAL(w
.toString(), "powerdns.com.");
186 DNSName
w2("powerdns.com.");
190 BOOST_CHECK_EQUAL(root
.countLabels(), 0U);
193 BOOST_AUTO_TEST_CASE(test_toolong
) {
195 BOOST_CHECK_THROW(DNSName
w("1234567890123456789012345678901234567890123456789012345678901234567890.com."), std::range_error
);
197 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
);
200 BOOST_AUTO_TEST_CASE(test_dnsstrings
) {
201 DNSName
w("www.powerdns.com.");
202 BOOST_CHECK_EQUAL(w
.toDNSString(), string("\003www\010powerdns\003com\000", 18));
205 BOOST_AUTO_TEST_CASE(test_empty
) {
207 BOOST_CHECK_THROW(empty
.toString(), std::out_of_range
);
208 BOOST_CHECK_THROW(empty
.toStringNoDot(), std::out_of_range
);
209 BOOST_CHECK_THROW(empty
.toDNSString(), std::out_of_range
);
210 BOOST_CHECK(empty
.empty());
211 BOOST_CHECK(!empty
.isRoot());
212 BOOST_CHECK(!empty
.isWildcard());
213 BOOST_CHECK_EQUAL(empty
, empty
);
214 BOOST_CHECK(!(empty
< empty
));
217 BOOST_CHECK(empty
< root
);
219 BOOST_CHECK_THROW(empty
.isPartOf(root
), std::out_of_range
);
220 BOOST_CHECK_THROW(root
.isPartOf(empty
), std::out_of_range
);
223 BOOST_AUTO_TEST_CASE(test_specials
) {
226 BOOST_CHECK(root
.isRoot());
227 BOOST_CHECK(root
!= DNSName());
229 DNSName
wcard("*.powerdns.com");
230 BOOST_CHECK(wcard
.isWildcard());
232 DNSName
notwcard("www.powerdns.com");
233 BOOST_CHECK(!notwcard
.isWildcard());
237 BOOST_AUTO_TEST_CASE(test_chopping
) {
238 DNSName
w("www.powerdns.com.");
239 BOOST_CHECK_EQUAL(w
.toString(), "www.powerdns.com.");
240 BOOST_CHECK(w
.chopOff());
241 BOOST_CHECK_EQUAL(w
.toString(), "powerdns.com.");
242 BOOST_CHECK(w
.chopOff());
243 BOOST_CHECK_EQUAL(w
.toString(), "com.");
244 BOOST_CHECK(w
.chopOff());
245 BOOST_CHECK_EQUAL(w
.toString(), ".");
246 BOOST_CHECK(!w
.chopOff());
247 BOOST_CHECK(!w
.chopOff());
249 w
.prependRawLabel("net");
250 w
.prependRawLabel("root-servers");
251 w
.prependRawLabel("a");
252 BOOST_CHECK_EQUAL(w
.toString(), "a.root-servers.net.");
255 BOOST_AUTO_TEST_CASE(test_Append
) {
256 DNSName
dn("www."), powerdns("powerdns.com.");
257 DNSName tot
=dn
+powerdns
;
259 BOOST_CHECK_EQUAL(tot
.toString(), "www.powerdns.com.");
260 BOOST_CHECK(tot
== DNSName("www.powerdns.com."));
264 BOOST_CHECK(dn
== DNSName("www.powerdns.com."));
267 BOOST_AUTO_TEST_CASE(test_packetCompress
) {
269 vector
<unsigned char> packet
;
270 DNSPacketWriter
dpw(packet
, DNSName("www.ds9a.nl."), QType::AAAA
);
271 dpw
.startRecord(DNSName("ds9a.nl"), QType::SOA
);
272 SOARecordContent
src("ns1.powerdns.nl admin.powerdns.nl 1 2 3 4 5");
274 AAAARecordContent
aaaa("::1");
275 dpw
.startRecord(DNSName("www.dS9A.nl"), QType::AAAA
);
277 dpw
.startRecord(DNSName("www.ds9A.nl"), QType::AAAA
);
279 dpw
.startRecord(DNSName("www.dS9a.nl"), QType::AAAA
);
281 dpw
.startRecord(DNSName("www2.DS9a.nl"), QType::AAAA
);
283 dpw
.startRecord(DNSName("www2.dS9a.nl"), QType::AAAA
);
286 string
str((const char*)&packet
[0], (const char*)&packet
[0] + packet
.size());
289 while((pos
= str
.find("ds9a", pos
)) != string::npos
) {
293 BOOST_CHECK_EQUAL(count
, 1);
296 while((pos
= str
.find("powerdns", pos
)) != string::npos
) {
300 BOOST_CHECK_EQUAL(count
, 1);
304 BOOST_AUTO_TEST_CASE(test_packetCompressLong
) {
306 vector
<unsigned char> packet
;
307 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");
308 DNSPacketWriter
dpw(packet
, loopback
, QType::PTR
);
310 dpw
.startRecord(loopback
, QType::PTR
);
311 PTRRecordContent
prc(DNSName("localhost"));
314 DNSName
roundtrip((char*)&packet
[0], packet
.size(), 12, false);
315 BOOST_CHECK_EQUAL(loopback
,roundtrip
);
318 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");
319 DNSPacketWriter
dpw2(packet
, longer
, QType::PTR
);
321 dpw2
.startRecord(DNSName("a.b.c.d.e")+longer
, QType::PTR
);
322 PTRRecordContent
prc2(DNSName("localhost"));
331 BOOST_AUTO_TEST_CASE(test_PacketParse
) {
332 vector
<unsigned char> packet
;
335 DNSPacketWriter
dpw1(packet
, g_rootdnsname
, QType::AAAA
);
336 DNSName
p((char*)&packet
[0], packet
.size(), 12, false);
337 BOOST_CHECK_EQUAL(p
, root
);
338 unsigned char* buffer
=&packet
[0];
339 /* set invalid label len:
340 - packet.size() == 17 (sizeof(dnsheader) + 1 + 2 + 2)
341 - label len < packet.size() but
342 - offset is 12, label len of 15 should be rejected
343 because offset + 15 >= packet.size()
345 buffer
[sizeof(dnsheader
)] = 15;
346 BOOST_CHECK_THROW(DNSName((char*)&packet
[0], packet
.size(), 12, false), std::range_error
);
350 BOOST_AUTO_TEST_CASE(test_hash
) {
351 DNSName
a("wwW.Ds9A.Nl"), b("www.ds9a.nl");
352 BOOST_CHECK_EQUAL(a
.hash(), b
.hash());
354 vector
<uint32_t> counts(1500);
356 for(unsigned int n
=0; n
< 100000; ++n
) {
357 DNSName
dn(std::to_string(n
)+"."+std::to_string(n
*2)+"ds9a.nl");
358 DNSName
dn2(std::to_string(n
)+"."+std::to_string(n
*2)+"Ds9a.nL");
359 BOOST_CHECK_EQUAL(dn
.hash(), dn2
.hash());
360 counts
[dn
.hash() % counts
.size()]++;
363 double sum
= std::accumulate(std::begin(counts
), std::end(counts
), 0.0);
364 double m
= sum
/ counts
.size();
367 std::for_each (std::begin(counts
), std::end(counts
), [&](const double d
) {
368 accum
+= (d
- m
) * (d
- m
);
371 double stdev
= sqrt(accum
/ (counts
.size()-1));
372 BOOST_CHECK(stdev
< 10);
375 BOOST_AUTO_TEST_CASE(test_hashContainer
) {
376 std::unordered_set
<DNSName
> s
;
377 s
.insert(DNSName("www.powerdns.com"));
378 BOOST_CHECK(s
.count(DNSName("WwW.PoWerDNS.CoM")));
379 BOOST_CHECK_EQUAL(s
.size(), 1U);
380 s
.insert(DNSName("www.POWERDNS.com"));
381 BOOST_CHECK_EQUAL(s
.size(), 1U);
382 s
.insert(DNSName("www2.POWERDNS.com"));
383 BOOST_CHECK_EQUAL(s
.size(), 2U);
387 for(; n
< 100000; ++n
)
388 s
.insert(DNSName(std::to_string(n
)+".test.nl"));
389 BOOST_CHECK_EQUAL(s
.size(), n
);
394 BOOST_AUTO_TEST_CASE(test_QuestionHash
) {
395 vector
<unsigned char> packet(sizeof(dnsheader
));
399 // A return init case
400 BOOST_CHECK_EQUAL(hashQuestion(packet
.data(), sizeof(dnsheader
), 0xffU
, ok
), 0xffU
);
403 // We subtract 4 from the packet sizes since DNSPacketWriter adds a type and a class
404 // We expect the hash of the root to be unequal to the burtle init value
405 DNSPacketWriter
dpw0(packet
, DNSName("."), QType::AAAA
);
406 BOOST_CHECK(hashQuestion(packet
.data(), packet
.size() - 4, 0xffU
, ok
) != 0xffU
);
409 // A truncated buffer should return the init value
410 DNSPacketWriter
dpw1(packet
, DNSName("."), QType::AAAA
);
411 BOOST_CHECK_EQUAL(hashQuestion(packet
.data(), packet
.size() - 5, 0xffU
, ok
), 0xffU
);
414 DNSPacketWriter
dpw2(packet
, DNSName("www.ds9a.nl."), QType::AAAA
);
415 // Let's make an invalid name by overwriting the length of the second label just outside the buffer
416 packet
[sizeof(dnsheader
) + 4] = 8;
417 BOOST_CHECK_EQUAL(hashQuestion(packet
.data(), packet
.size() - 4, 0xffU
, ok
), 0xffU
);
420 DNSPacketWriter
dpw3(packet
, DNSName("www.ds9a.nl."), QType::AAAA
);
421 // Let's make an invalid name by overwriting the length of the second label way outside the buffer
422 packet
[sizeof(dnsheader
) + 4] = 0xff;
423 BOOST_CHECK_EQUAL(hashQuestion(packet
.data(), packet
.size() - 4, 0xffU
, ok
), 0xffU
);
426 DNSPacketWriter
dpw4(packet
, DNSName("www.ds9a.nl."), QType::AAAA
);
427 auto hash1
= hashQuestion(&packet
[0], packet
.size() - 4, 0, ok
);
429 DNSPacketWriter
dpw5(packet
, DNSName("wWw.Ds9A.nL."), QType::AAAA
);
430 auto hash2
= hashQuestion(&packet
[0], packet
.size() - 4, 0, ok
);
431 BOOST_CHECK_EQUAL(hash1
, hash2
);
434 vector
<uint32_t> counts(1500);
435 for(unsigned int n
= 0; n
< 100000; ++n
) {
437 DNSPacketWriter
dpw(packet
, DNSName(std::to_string(n
) + "." + std::to_string(n
*2) + "."), QType::AAAA
);
439 counts
[hashQuestion(&packet
[0], packet
.size() - 4, 0, ok
) % counts
.size()]++;
442 double sum
= std::accumulate(std::begin(counts
), std::end(counts
), 0.0);
443 double m
= sum
/ counts
.size();
446 std::for_each (std::begin(counts
), std::end(counts
), [&](const double d
) {
447 accum
+= (d
- m
) * (d
- m
);
450 double stdev
= sqrt(accum
/ (counts
.size()-1));
451 BOOST_CHECK(stdev
< 10);
454 BOOST_AUTO_TEST_CASE(test_packetParse
) {
455 vector
<unsigned char> packet
;
457 DNSPacketWriter
dpw(packet
, DNSName("www.ds9a.nl."), QType::AAAA
);
459 uint16_t qtype
, qclass
;
460 DNSName
dn((char*)&packet
[0], packet
.size(), 12, false, &qtype
, &qclass
);
461 BOOST_CHECK_EQUAL(dn
.toString(), "www.ds9a.nl.");
462 BOOST_CHECK(qtype
== QType::AAAA
);
463 BOOST_CHECK_EQUAL(qclass
, 1);
465 dpw
.startRecord(DNSName("ds9a.nl."), DNSRecordContent::TypeToNumber("NS"));
466 NSRecordContent
nrc("ns1.powerdns.com");
471 /* packet now looks like this:
472 012345678901 12 bytes of header
473 3www4ds9a2nl0 13 bytes of name
474 0001 0001 4 bytes of qtype and qclass
476 0001 0001 4 bytes of qtype and class
477 0000 0000 4 bytes of TTL
478 0000 2 bytes of content length
481 DNSName
dn2((char*)&packet
[0], packet
.size(), 12+13+4, true, &qtype
, &qclass
);
482 BOOST_CHECK_EQUAL(dn2
.toString(), "ds9a.nl.");
483 BOOST_CHECK(qtype
== QType::NS
);
484 BOOST_CHECK_EQUAL(qclass
, 1);
486 DNSName
dn3((char*)&packet
[0], packet
.size(), 12+13+4+2 + 4 + 4 + 2, true);
487 BOOST_CHECK_EQUAL(dn3
.toString(), "ns1.powerdns.com.");
489 DNSName
dn4((char*)&packet
[0], packet
.size(), 12+13+4, false); // compressed, should fail
495 BOOST_AUTO_TEST_CASE(test_escaping
) {
499 for(int i
= 0; i
< 250; ++i
) {
501 n
.appendRawLabel(label
);
504 label
.append(1,(char)i
);
507 n
.appendRawLabel(label
);
509 DNSName
n2(n
.toString());
513 BOOST_AUTO_TEST_CASE(test_suffixmatch
) {
515 DNSName
ezdns("ezdns.it.");
516 smn
.add(ezdns
.getRawLabels());
518 smn
.add(DNSName("org.").getRawLabels());
520 DNSName
wwwpowerdnscom("www.powerdns.com.");
521 DNSName
wwwezdnsit("www.ezdns.it.");
522 BOOST_CHECK(smn
.check(wwwezdnsit
));
523 BOOST_CHECK(!smn
.check(wwwpowerdnscom
));
525 BOOST_CHECK(smn
.check(DNSName("www.powerdns.org.")));
526 BOOST_CHECK(smn
.check(DNSName("www.powerdns.oRG.")));
528 smn
.add(DNSName("news.bbc.co.uk."));
529 BOOST_CHECK(smn
.check(DNSName("news.bbc.co.uk.")));
530 BOOST_CHECK(smn
.getBestMatch(DNSName("news.bbc.co.uk")) == DNSName("news.bbc.co.uk."));
531 BOOST_CHECK(smn
.check(DNSName("www.news.bbc.co.uk.")));
532 BOOST_CHECK(smn
.getBestMatch(DNSName("www.news.bbc.co.uk")) == DNSName("news.bbc.co.uk."));
533 BOOST_CHECK(smn
.check(DNSName("www.www.www.www.www.news.bbc.co.uk.")));
534 BOOST_CHECK(!smn
.check(DNSName("images.bbc.co.uk.")));
535 BOOST_CHECK(smn
.getBestMatch(DNSName("images.bbc.co.uk")) == std::nullopt
);
537 BOOST_CHECK(!smn
.check(DNSName("www.news.gov.uk.")));
538 BOOST_CHECK(smn
.getBestMatch(DNSName("www.news.gov.uk")) == std::nullopt
);
540 smn
.add(g_rootdnsname
); // block the root
541 BOOST_CHECK(smn
.check(DNSName("a.root-servers.net.")));
542 BOOST_CHECK(smn
.getBestMatch(DNSName("a.root-servers.net.")) == g_rootdnsname
);
544 DNSName
examplenet("example.net.");
548 BOOST_CHECK(smn
.check(examplenet
));
549 BOOST_CHECK(smn
.check(net
));
551 // Remove .net and the root, and check that example.net still exists
552 smn
.remove(g_rootdnsname
);
554 BOOST_CHECK_EQUAL(smn
.check(net
), false);
555 BOOST_CHECK(smn
.check(examplenet
));
557 smn
.add(DNSName("fr."));
558 smn
.add(DNSName("www.sub.domain.fr."));
559 // should not match www.sub.domain.fr. but should still match fr.
560 BOOST_CHECK(smn
.check(DNSName("sub.domain.fr.")));
563 BOOST_AUTO_TEST_CASE(test_suffixmatch_tree
) {
564 SuffixMatchTree
<DNSName
> smt
;
565 DNSName
ezdns("ezdns.it.");
566 smt
.add(ezdns
, DNSName(ezdns
));
568 auto labels
= DNSName("org.").getRawLabels();
569 smt
.add(labels
, DNSName("org."));
571 DNSName
wwwpowerdnscom("www.powerdns.com.");
572 DNSName
wwwezdnsit("www.ezdns.it.");
573 BOOST_REQUIRE(smt
.lookup(wwwezdnsit
));
574 BOOST_CHECK_EQUAL(*smt
.lookup(wwwezdnsit
), ezdns
);
575 BOOST_CHECK(smt
.lookup(wwwpowerdnscom
) == nullptr);
577 BOOST_REQUIRE(smt
.lookup(DNSName("www.powerdns.org.")));
578 BOOST_CHECK_EQUAL(*smt
.lookup(DNSName("www.powerdns.org.")), DNSName("org."));
579 BOOST_REQUIRE(smt
.lookup(DNSName("www.powerdns.oRG.")));
580 BOOST_CHECK_EQUAL(*smt
.lookup(DNSName("www.powerdns.oRG.")), DNSName("org."));
582 smt
.add(DNSName("news.bbc.co.uk."), DNSName("news.bbc.co.uk."));
583 BOOST_REQUIRE(smt
.lookup(DNSName("news.bbc.co.uk.")));
584 BOOST_CHECK_EQUAL(*smt
.lookup(DNSName("news.bbc.co.uk.")), DNSName("news.bbc.co.uk."));
585 BOOST_REQUIRE(smt
.lookup(DNSName("www.news.bbc.co.uk.")));
586 BOOST_CHECK_EQUAL(*smt
.lookup(DNSName("www.news.bbc.co.uk.")), DNSName("news.bbc.co.uk."));
587 BOOST_REQUIRE(smt
.lookup(DNSName("www.www.www.www.www.news.bbc.co.uk.")));
588 BOOST_CHECK_EQUAL(*smt
.lookup(DNSName("www.www.www.www.www.news.bbc.co.uk.")), DNSName("news.bbc.co.uk."));
589 BOOST_CHECK(smt
.lookup(DNSName("images.bbc.co.uk.")) == nullptr);
590 BOOST_CHECK(smt
.lookup(DNSName("www.news.gov.uk.")) == nullptr);
592 smt
.add(g_rootdnsname
, DNSName(g_rootdnsname
)); // block the root
593 BOOST_REQUIRE(smt
.lookup(DNSName("a.root-servers.net.")));
594 BOOST_CHECK_EQUAL(*smt
.lookup(DNSName("a.root-servers.net.")), g_rootdnsname
);
596 DNSName
apowerdnscom("a.powerdns.com.");
597 DNSName
bpowerdnscom("b.powerdns.com.");
598 smt
.add(apowerdnscom
, DNSName(apowerdnscom
));
599 smt
.add(bpowerdnscom
, DNSName(bpowerdnscom
));
600 BOOST_REQUIRE(smt
.lookup(apowerdnscom
));
601 BOOST_CHECK_EQUAL(*smt
.lookup(apowerdnscom
), apowerdnscom
);
602 BOOST_REQUIRE(smt
.lookup(bpowerdnscom
));
603 BOOST_CHECK_EQUAL(*smt
.lookup(bpowerdnscom
), bpowerdnscom
);
605 DNSName
examplenet("example.net.");
607 smt
.add(examplenet
, DNSName(examplenet
));
608 smt
.add(net
, DNSName(net
));
609 BOOST_REQUIRE(smt
.lookup(examplenet
));
610 BOOST_CHECK_EQUAL(*smt
.lookup(examplenet
), examplenet
);
611 BOOST_REQUIRE(smt
.lookup(net
));
612 BOOST_CHECK_EQUAL(*smt
.lookup(net
), net
);
614 // Remove .net and the root, and check that example.net remains
615 smt
.remove(g_rootdnsname
);
617 BOOST_CHECK(smt
.lookup(net
) == nullptr);
618 BOOST_CHECK_EQUAL(*smt
.lookup(examplenet
), examplenet
);
620 smt
= SuffixMatchTree
<DNSName
>();
621 smt
.add(examplenet
, DNSName(examplenet
));
622 smt
.add(net
, DNSName(net
));
623 smt
.add(DNSName("news.bbc.co.uk."), DNSName("news.bbc.co.uk."));
624 smt
.add(apowerdnscom
, DNSName(apowerdnscom
));
626 smt
.remove(DNSName("not-such-entry.news.bbc.co.uk."));
627 BOOST_REQUIRE(smt
.lookup(DNSName("news.bbc.co.uk.")));
628 smt
.remove(DNSName("news.bbc.co.uk."));
629 BOOST_CHECK(smt
.lookup(DNSName("news.bbc.co.uk.")) == nullptr);
632 BOOST_REQUIRE(smt
.lookup(examplenet
));
633 BOOST_CHECK_EQUAL(*smt
.lookup(examplenet
), examplenet
);
634 BOOST_CHECK(smt
.lookup(net
) == nullptr);
636 smt
.remove(examplenet
);
637 BOOST_CHECK(smt
.lookup(net
) == nullptr);
638 BOOST_CHECK(smt
.lookup(examplenet
) == nullptr);
640 smt
.add(examplenet
, DNSName(examplenet
));
641 smt
.add(net
, DNSName(net
));
642 BOOST_REQUIRE(smt
.lookup(examplenet
));
643 BOOST_CHECK_EQUAL(*smt
.lookup(examplenet
), examplenet
);
644 BOOST_REQUIRE(smt
.lookup(net
));
645 BOOST_CHECK_EQUAL(*smt
.lookup(net
), net
);
647 smt
.remove(examplenet
);
648 BOOST_CHECK_EQUAL(*smt
.lookup(examplenet
), net
);
649 BOOST_CHECK_EQUAL(*smt
.lookup(net
), net
);
650 smt
.remove(examplenet
);
651 BOOST_CHECK_EQUAL(*smt
.lookup(examplenet
), net
);
652 BOOST_CHECK_EQUAL(*smt
.lookup(net
), net
);
654 BOOST_CHECK(smt
.lookup(net
) == nullptr);
655 BOOST_CHECK(smt
.lookup(examplenet
) == nullptr);
659 smt
.visit([apowerdnscom
, &count
](const SuffixMatchTree
<DNSName
>& smtarg
) {
661 BOOST_CHECK_EQUAL(smtarg
.d_value
, apowerdnscom
);
663 BOOST_CHECK_EQUAL(count
, 1U);
665 BOOST_CHECK_EQUAL(*smt
.lookup(apowerdnscom
), apowerdnscom
);
666 smt
.remove(apowerdnscom
);
667 BOOST_CHECK(smt
.lookup(apowerdnscom
) == nullptr);
670 smt
.visit([&count
](const SuffixMatchTree
<DNSName
>&) {
673 BOOST_CHECK_EQUAL(count
, 0U);
677 BOOST_AUTO_TEST_CASE(test_concat
) {
678 DNSName
first("www."), second("powerdns.com.");
679 BOOST_CHECK_EQUAL((first
+second
).toString(), "www.powerdns.com.");
682 BOOST_AUTO_TEST_CASE(test_compare_naive
) {
683 BOOST_CHECK(DNSName("abc.com.") < DNSName("zdf.com."));
684 BOOST_CHECK(DNSName("Abc.com.") < DNSName("zdf.com."));
685 BOOST_CHECK(DNSName("Abc.com.") < DNSName("Zdf.com."));
686 BOOST_CHECK(DNSName("abc.com.") < DNSName("Zdf.com."));
689 BOOST_AUTO_TEST_CASE(test_compare_empty
) {
692 BOOST_CHECK(!a
.canonCompare(b
));
695 BOOST_AUTO_TEST_CASE(test_casing
) {
696 DNSName
a("WwW.PoWeRdNS.Com"), b("www.powerdns.com.");
697 BOOST_CHECK_EQUAL(a
,b
);
698 BOOST_CHECK_EQUAL(a
.toString(), "WwW.PoWeRdNS.Com.");
699 DNSName c
=a
.makeLowerCase();
700 BOOST_CHECK_EQUAL(a
,c
);
701 BOOST_CHECK_EQUAL(b
,c
);
702 BOOST_CHECK_EQUAL(c
.toString(), b
.toString());
703 BOOST_CHECK_EQUAL(c
.toString(), "www.powerdns.com.");
708 BOOST_AUTO_TEST_CASE(test_compare_canonical
) {
709 DNSName
lower("bert.com."), higher("alpha.nl.");
710 BOOST_CHECK(lower
.canonCompare(higher
));
712 BOOST_CHECK(DNSName("bert.com").canonCompare(DNSName("www.bert.com")));
713 BOOST_CHECK(DNSName("BeRt.com").canonCompare(DNSName("WWW.berT.com")));
714 BOOST_CHECK(!DNSName("www.BeRt.com").canonCompare(DNSName("WWW.berT.com")));
716 CanonDNSNameCompare a
;
717 BOOST_CHECK(a(g_rootdnsname
, DNSName("www.powerdns.com")));
718 BOOST_CHECK(a(g_rootdnsname
, DNSName("www.powerdns.net")));
719 BOOST_CHECK(!a(DNSName("www.powerdns.net"), g_rootdnsname
));
722 for(const char* b
: {"bert.com.", "alpha.nl.", "articles.xxx.",
723 "Aleph1.powerdns.com.", "ZOMG.powerdns.com.", "aaa.XXX.", "yyy.XXX.",
724 "test.powerdns.com.", "\\128.com"}) {
725 vec
.push_back(DNSName(b
));
727 sort(vec
.begin(), vec
.end(), CanonDNSNameCompare());
728 // for(const auto& v : vec)
729 // cerr<<'"'<<v<<'"'<<endl;
731 vector
<DNSName
> right
;
732 for(const auto& b
: {"bert.com.", "Aleph1.powerdns.com.",
733 "test.powerdns.com.",
734 "ZOMG.powerdns.com.",
740 right
.push_back(DNSName(b
));
743 BOOST_CHECK(vec
==right
);
747 BOOST_AUTO_TEST_CASE(test_empty_label
) { // empty label
751 BOOST_CHECK_THROW(dn
.appendRawLabel(""), std::range_error
);
756 BOOST_CHECK_THROW(dn
.prependRawLabel(""), std::range_error
);
760 BOOST_AUTO_TEST_CASE(test_label_length_max
) { // 63 char label
762 string
label("123456789012345678901234567890123456789012345678901234567890123");
766 dn
.appendRawLabel(label
);
767 BOOST_CHECK_EQUAL(dn
.toString(), "www." + label
+ ".");
772 dn
.prependRawLabel(label
);
773 BOOST_CHECK_EQUAL(dn
.toString(), label
+ ".www.");
777 BOOST_AUTO_TEST_CASE(test_label_length_too_long
) { // 64 char label
779 string
label("1234567890123456789012345678901234567890123456789012345678901234");
783 BOOST_CHECK_THROW(dn
.appendRawLabel(label
), std::range_error
);
788 BOOST_CHECK_THROW(dn
.prependRawLabel(label
), std::range_error
);
792 BOOST_AUTO_TEST_CASE(test_name_length_max
) { // 255 char name
794 string
name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
795 "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
796 "123456789.123456789.123456789.123456789.123456789.");
801 dn
.appendRawLabel(label
);
802 BOOST_CHECK_EQUAL(dn
.toString().size(), 254U);
807 dn
.prependRawLabel(label
);
808 BOOST_CHECK_EQUAL(dn
.toString().size(), 254U);
814 dn
+= DNSName(label
+ ".");
815 BOOST_CHECK_EQUAL(dn
.toString().size(), 254U);
819 BOOST_AUTO_TEST_CASE(test_name_length_too_long
) { // 256 char name
821 string
name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
822 "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
823 "123456789.123456789.123456789.123456789.123456789.");
824 string
label("1234");
828 BOOST_CHECK_THROW(dn
.appendRawLabel(label
), std::range_error
);
833 BOOST_CHECK_THROW(dn
.prependRawLabel(label
), std::range_error
);
838 BOOST_CHECK_THROW(dn
+= DNSName(label
+ "."), std::range_error
);
843 BOOST_AUTO_TEST_CASE(test_invalid_label_length
) { // Invalid label length in qname
845 string
name("\x02""ns\x07""example\x04""com\x00", 16);
847 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.size(), 0, true), std::range_error
);
850 BOOST_AUTO_TEST_CASE(test_compression
) { // Compression test
852 string
name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05", 21);
854 DNSName
dn(name
.c_str(), name
.size(), 15, true);
855 BOOST_CHECK_EQUAL(dn
.toString(), "www.example.com.");
858 BOOST_AUTO_TEST_CASE(test_compression_qtype_qclass
) { // Compression test with QClass and QType extraction
864 string
name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""\x01", 25);
865 DNSName
dn(name
.c_str(), name
.size(), 15, true, &qtype
, &qclass
);
866 BOOST_CHECK_EQUAL(dn
.toString(), "www.example.com.");
867 BOOST_CHECK_EQUAL(qtype
, 1);
868 BOOST_CHECK_EQUAL(qclass
, 1);
872 /* same but this time we are one byte short for the qclass */
873 string
name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""", 24);
874 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.size(), 15, true, &qtype
, &qclass
), std::range_error
);
878 /* this time with a compression pointer such as (labellen << 8) != 0, see #4718 */
879 string
name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00""\x01", 25);
880 name
.insert(0, 256, '0');
882 DNSName
dn(name
.c_str(), name
.size(), 271, true, &qtype
, &qclass
);
883 BOOST_CHECK_EQUAL(dn
.toString(), "www.example.com.");
884 BOOST_CHECK_EQUAL(qtype
, 1);
885 BOOST_CHECK_EQUAL(qclass
, 1);
889 /* same but this time we are one byte short for the qclass */
890 string
name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00", 24);
891 name
.insert(0, 256, '0');
893 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.size(), 271, true, &qtype
, &qclass
), std::range_error
);
897 BOOST_AUTO_TEST_CASE(test_compression_single_bit_set
) { // first 2 bits as 10 or 01, not 11
901 string
name("\x03""com\x00""\x07""example\x80""\x00""\x03""www\x80""\x05", 21);
903 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.size(), 15, true), std::range_error
);
908 string
name("\x03""com\x00""\x07""example\x40""\x00""\x03""www\x40""\x05", 21);
910 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.size(), 15, true), std::range_error
);
915 BOOST_AUTO_TEST_CASE(test_pointer_pointer_root
) { // Pointer to pointer to root
917 string
name("\x00""\xc0""\x00""\x03""com\xc0""\x01",9);
919 DNSName
dn(name
.c_str(), name
.size(), 3, true);
920 BOOST_CHECK_EQUAL(dn
.toString(), "com.");
923 BOOST_AUTO_TEST_CASE(test_bad_compression_pointer
) { // Pointing beyond packet boundary
925 std::string
name("\x03""com\x00""\x07""example\xc0""\x11""xc0""\x00", 17);
927 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.length(), 5, true), std::range_error
);
930 BOOST_AUTO_TEST_CASE(test_compression_loop
) { // Compression loop (add one label)
932 std::string
name("\x03""www\xc0""\x00", 6);
934 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.length(), 0, true), std::range_error
);
937 BOOST_AUTO_TEST_CASE(test_compression_loop1
) { // Compression loop (pointer loop)
939 string
name("\xc0""\x00", 2);
941 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.size(), 0, true), std::range_error
);
944 BOOST_AUTO_TEST_CASE(test_compression_loop2
) { // Compression loop (deep recursion)
947 string
name("\x00\xc0\x00", 3);
948 for (i
=0; i
<98; ++i
) {
949 name
.append( 1, ((i
>> 7) & 0xff) | 0xc0);
950 name
.append( 1, ((i
<< 1) & 0xff) | 0x01);
952 BOOST_CHECK_NO_THROW(DNSName
dn(name
.c_str(), name
.size(), name
.size()-2, true));
955 name
.append( 1, ((i
>> 7) & 0xff) | 0xc0);
956 name
.append( 1, ((i
<< 1) & 0xff) | 0x01);
958 BOOST_CHECK_THROW(DNSName
dn(name
.c_str(), name
.size(), name
.size()-2, true), std::range_error
);
961 BOOST_AUTO_TEST_CASE(test_wirelength
) { // Testing if we get the correct value from the wirelength function
962 DNSName
name("www.powerdns.com");
963 BOOST_CHECK_EQUAL(name
.wirelength(), 18U);
965 DNSName
sname("powerdns.com");
966 sname
.prependRawLabel(string("ww\x00""w", 4));
967 BOOST_CHECK_EQUAL(sname
.wirelength(), 19U);
969 sname
= DNSName("powerdns.com");
970 sname
.prependRawLabel(string("www\x00", 4));
971 BOOST_CHECK_EQUAL(sname
.wirelength(), 19U);
974 BOOST_AUTO_TEST_CASE(test_getrawlabel
) {
975 DNSName
name("a.bb.ccc.dddd.");
976 BOOST_CHECK_EQUAL(name
.getRawLabel(0), "a");
977 BOOST_CHECK_EQUAL(name
.getRawLabel(1), "bb");
978 BOOST_CHECK_EQUAL(name
.getRawLabel(2), "ccc");
979 BOOST_CHECK_EQUAL(name
.getRawLabel(3), "dddd");
980 BOOST_CHECK_THROW(name
.getRawLabel(name
.countLabels()), std::out_of_range
);
983 BOOST_AUTO_TEST_CASE(test_getrawlabels_visitor
) {
984 DNSName
name("a.bb.ccc.dddd.");
985 auto visitor
= name
.getRawLabelsVisitor();
986 BOOST_CHECK(!visitor
.empty());
987 BOOST_CHECK_EQUAL(visitor
.front(), *name
.getRawLabels().begin());
988 BOOST_CHECK_EQUAL(visitor
.back(), *name
.getRawLabels().rbegin());
990 BOOST_CHECK_EQUAL(visitor
.back(), "dddd");
991 BOOST_CHECK(visitor
.pop_back());
992 BOOST_CHECK_EQUAL(visitor
.back(), "ccc");
993 BOOST_CHECK(visitor
.pop_back());
994 BOOST_CHECK_EQUAL(visitor
.back(), "bb");
995 BOOST_CHECK(visitor
.pop_back());
996 BOOST_CHECK_EQUAL(visitor
.back(), "a");
997 BOOST_CHECK(visitor
.pop_back());
998 BOOST_CHECK(visitor
.empty());
999 BOOST_CHECK(!visitor
.pop_back());
1000 BOOST_CHECK_THROW(visitor
.front(), std::out_of_range
);
1001 BOOST_CHECK_THROW(visitor
.back(), std::out_of_range
);
1004 BOOST_AUTO_TEST_CASE(test_getlastlabel
) {
1005 DNSName
name("www.powerdns.com");
1006 DNSName ans
= name
.getLastLabel();
1008 // Check the const-ness
1009 BOOST_CHECK_EQUAL(name
, DNSName("www.powerdns.com"));
1011 // Check if the last label is indeed returned
1012 BOOST_CHECK_EQUAL(ans
, DNSName("com"));
1015 BOOST_AUTO_TEST_CASE(test_getcommonlabels
) {
1016 const DNSName
name1("www.powerdns.com");
1017 const DNSName
name2("a.long.list.of.labels.powerdns.com");
1019 BOOST_CHECK_EQUAL(name1
.getCommonLabels(name1
), name1
);
1020 BOOST_CHECK_EQUAL(name2
.getCommonLabels(name2
), name2
);
1022 BOOST_CHECK_EQUAL(name1
.getCommonLabels(name2
), DNSName("powerdns.com"));
1023 BOOST_CHECK_EQUAL(name2
.getCommonLabels(name1
), DNSName("powerdns.com"));
1025 const DNSName
name3("www.powerdns.org");
1026 BOOST_CHECK_EQUAL(name1
.getCommonLabels(name3
), g_rootdnsname
);
1027 BOOST_CHECK_EQUAL(name2
.getCommonLabels(name3
), g_rootdnsname
);
1028 BOOST_CHECK_EQUAL(name3
.getCommonLabels(name1
), g_rootdnsname
);
1029 BOOST_CHECK_EQUAL(name3
.getCommonLabels(name2
), g_rootdnsname
);
1031 const DNSName
name4("WWw.PowErDnS.org");
1032 BOOST_CHECK_EQUAL(name3
.getCommonLabels(name4
), name3
);
1033 BOOST_CHECK_EQUAL(name4
.getCommonLabels(name3
), name4
);
1035 const DNSName name5
;
1036 BOOST_CHECK_EQUAL(name1
.getCommonLabels(name5
), DNSName());
1037 BOOST_CHECK_EQUAL(name5
.getCommonLabels(name1
), DNSName());
1040 BOOST_AUTO_TEST_SUITE_END()