]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-ueberbackend_cc.cc
Merge pull request #11307 from omoerbeek/rec-send-sni
[thirdparty/pdns.git] / pdns / test-ueberbackend_cc.cc
1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
3
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
7
8 #include <unordered_map>
9
10 #include <boost/test/unit_test.hpp>
11
12 #include <boost/multi_index_container.hpp>
13 #include <boost/multi_index/ordered_index.hpp>
14 #include <boost/multi_index/hashed_index.hpp>
15 #include <boost/multi_index/key_extractors.hpp>
16
17 #include "arguments.hh"
18 #include "auth-querycache.hh"
19 #include "auth-zonecache.hh"
20 #include "ueberbackend.hh"
21
22 class SimpleBackend : public DNSBackend
23 {
24 public:
25 struct SimpleDNSRecord
26 {
27 SimpleDNSRecord(const DNSName& name, uint16_t type, const std::string& content, uint32_t ttl): d_content(content), d_name(name), d_ttl(ttl), d_type(type)
28 {
29 }
30
31 std::string d_content;
32 DNSName d_name;
33 uint32_t d_ttl;
34 uint16_t d_type;
35 };
36
37 struct OrderedNameTypeTag;
38
39 typedef multi_index_container<
40 SimpleDNSRecord,
41 indexed_by <
42 ordered_non_unique<tag<OrderedNameTypeTag>,
43 composite_key<
44 SimpleDNSRecord,
45 member<SimpleDNSRecord, DNSName, &SimpleDNSRecord::d_name>,
46 member<SimpleDNSRecord, uint16_t, &SimpleDNSRecord::d_type>
47 >,
48 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t> >
49 >
50 >
51 > RecordStorage;
52
53 struct SimpleDNSZone
54 {
55 SimpleDNSZone(const DNSName& name, uint64_t id): d_records(std::make_shared<RecordStorage>()), d_name(name), d_id(id)
56 {
57 }
58 std::shared_ptr<RecordStorage> d_records;
59 DNSName d_name;
60 uint64_t d_id;
61 };
62
63 struct HashedNameTag {};
64 struct IDTag {};
65
66 typedef multi_index_container<
67 SimpleDNSZone,
68 indexed_by <
69 ordered_unique<tag<IDTag>, member<SimpleDNSZone, uint64_t, &SimpleDNSZone::d_id> >,
70 hashed_unique<tag<HashedNameTag>, member<SimpleDNSZone, DNSName, &SimpleDNSZone::d_name> >
71 >
72 > ZoneStorage;
73
74 struct SimpleMetaData
75 {
76 SimpleMetaData(const DNSName& name, const std::string& kind, const std::vector<std::string>& values): d_name(name), d_kind(kind), d_values(values)
77 {
78 }
79
80 DNSName d_name;
81 std::string d_kind;
82 std::vector<std::string> d_values;
83 };
84
85 struct OrderedNameKindTag {};
86
87 typedef multi_index_container<
88 SimpleMetaData,
89 indexed_by <
90 ordered_unique<tag<OrderedNameKindTag>,
91 composite_key<
92 SimpleMetaData,
93 member<SimpleMetaData, DNSName, &SimpleMetaData::d_name>,
94 member<SimpleMetaData, std::string, &SimpleMetaData::d_kind>
95 >,
96 composite_key_compare<CanonDNSNameCompare, std::less<std::string> >
97 >
98 >
99 > MetaDataStorage;
100
101 // Initialize our backend ID from the suffix, skipping the '-' that DNSBackend adds there
102 SimpleBackend(const std::string& suffix): d_suffix(suffix), d_backendId(pdns_stou(suffix.substr(1)))
103 {
104 }
105
106 bool findZone(const DNSName& qdomain, int zoneId, std::shared_ptr<RecordStorage>& records, uint64_t& currentZoneId) const
107 {
108 currentZoneId = -1;
109 records.reset();
110
111 if (zoneId != -1) {
112 const auto& idx = boost::multi_index::get<IDTag>(s_zones.at(d_backendId));
113 auto it = idx.find(zoneId);
114 if (it == idx.end()) {
115 return false;
116 }
117 records = it->d_records;
118 currentZoneId = it->d_id;
119 }
120 else {
121 const auto& idx = boost::multi_index::get<HashedNameTag>(s_zones.at(d_backendId));
122 auto it = idx.find(qdomain);
123 if (it == idx.end()) {
124 return false;
125 }
126 records = it->d_records;
127 currentZoneId = it->d_id;
128 }
129
130 return true;
131 }
132
133 void lookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket *pkt_p = nullptr) override
134 {
135 d_currentScopeMask = 0;
136 findZone(qdomain, zoneId, d_records, d_currentZone);
137
138 if (d_records) {
139 if (qdomain == DNSName("geo.powerdns.com.") && pkt_p != nullptr) {
140 if (pkt_p->getRealRemote() == Netmask("192.0.2.1")) {
141 d_currentScopeMask = 32;
142 }
143 else if (pkt_p->getRealRemote() == Netmask("198.51.100.1")) {
144 d_currentScopeMask = 24;
145 }
146 }
147
148 auto& idx = d_records->get<OrderedNameTypeTag>();
149 if (qtype == QType::ANY) {
150 auto range = idx.equal_range(qdomain);
151 d_iter = range.first;
152 d_end = range.second;
153 }
154 else {
155 auto range = idx.equal_range(std::make_tuple(qdomain, qtype.getCode()));
156 d_iter = range.first;
157 d_end = range.second;
158 }
159 }
160 }
161
162 bool get(DNSResourceRecord& drr) override
163 {
164 if (!d_records) {
165 return false;
166 }
167
168 if (d_iter == d_end) {
169 return false;
170 }
171
172 drr.qname = d_iter->d_name;
173 drr.domain_id = d_currentZone;
174 drr.content = d_iter->d_content;
175 drr.qtype = d_iter->d_type;
176 drr.ttl = d_iter->d_ttl;
177
178 // drr.auth = d_iter->auth; might bring pain at some point, let's not cross that bridge until then
179 drr.auth = true;
180 drr.scopeMask = d_currentScopeMask;
181
182 ++d_iter;
183 return true;
184 }
185
186 bool list(const DNSName& target, int zoneId, bool include_disabled = false) override
187 {
188 findZone(target, zoneId, d_records, d_currentZone);
189
190 if (d_records) {
191 d_iter = d_records->begin();
192 d_end = d_records->end();
193 return true;
194 }
195
196 return false;
197 }
198
199 bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override
200 {
201 const auto& idx = boost::multi_index::get<OrderedNameKindTag>(s_metadata.at(d_backendId));
202 auto it = idx.find(std::make_tuple(name, kind));
203 if (it == idx.end()) {
204 /* funnily enough, we are expected to return true even though we might not know that zone */
205 return true;
206 }
207
208 meta = it->d_values;
209 return true;
210 }
211
212 bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) override
213 {
214 auto& idx = boost::multi_index::get<OrderedNameKindTag>(s_metadata.at(d_backendId));
215 auto it = idx.find(std::make_tuple(name, kind));
216 if (it == idx.end()) {
217 s_metadata.at(d_backendId).insert(SimpleMetaData(name, kind, meta));
218 return true;
219 }
220 idx.replace(it, SimpleMetaData(name, kind, meta));
221 return true;
222 }
223
224 /* this is not thread-safe */
225 static std::unordered_map<uint64_t, ZoneStorage> s_zones;
226 static std::unordered_map<uint64_t, MetaDataStorage> s_metadata;
227
228 protected:
229 std::string d_suffix;
230 std::shared_ptr<RecordStorage> d_records{nullptr};
231 RecordStorage::index<OrderedNameTypeTag>::type::const_iterator d_iter;
232 RecordStorage::index<OrderedNameTypeTag>::type::const_iterator d_end;
233 const uint64_t d_backendId;
234 uint64_t d_currentZone{0};
235 uint8_t d_currentScopeMask{0};
236 };
237
238 class SimpleBackendBestAuth : public SimpleBackend
239 {
240 public:
241 SimpleBackendBestAuth(const std::string& suffix): SimpleBackend(suffix)
242 {
243 }
244
245 bool getAuth(const DNSName& target, SOAData* sd) override
246 {
247 static const DNSName best("d.0.1.0.0.2.ip6.arpa.");
248
249 ++d_authLookupCount;
250
251 if (target.isPartOf(best)) {
252 /* return the best SOA right away */
253 std::shared_ptr<RecordStorage> records;
254 uint64_t zoneId;
255 if (!findZone(best, -1, records, zoneId)) {
256 return false;
257 }
258
259 auto& idx = records->get<OrderedNameTypeTag>();
260 auto range = idx.equal_range(std::make_tuple(best, QType::SOA));
261 if (range.first == range.second) {
262 return false;
263 }
264
265 fillSOAData(range.first->d_content, *sd);
266 sd->ttl = range.first->d_ttl;
267 sd->qname = best;
268 sd->domain_id = zoneId;
269 return true;
270 }
271
272 return getSOA(target, *sd);
273 }
274
275 size_t d_authLookupCount{0};
276 };
277
278 class SimpleBackendNoMeta : public SimpleBackend
279 {
280 public:
281 SimpleBackendNoMeta(const std::string& suffix): SimpleBackend(suffix)
282 {
283 }
284
285 bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override
286 {
287 return false;
288 }
289
290 bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) override
291 {
292 return false;
293 }
294 };
295
296 std::unordered_map<uint64_t, SimpleBackend::ZoneStorage> SimpleBackend::s_zones;
297 std::unordered_map<uint64_t, SimpleBackend::MetaDataStorage> SimpleBackend::s_metadata;
298
299 class SimpleBackendFactory : public BackendFactory
300 {
301 public:
302 SimpleBackendFactory(): BackendFactory("SimpleBackend")
303 {
304 }
305
306 DNSBackend *make(const string& suffix="") override
307 {
308 return new SimpleBackend(suffix);
309 }
310 };
311
312 class SimpleBackendBestAuthFactory : public BackendFactory
313 {
314 public:
315 SimpleBackendBestAuthFactory(): BackendFactory("SimpleBackendBestAuth")
316 {
317 }
318
319 DNSBackend *make(const string& suffix="") override
320 {
321 return new SimpleBackendBestAuth(suffix);
322 }
323 };
324
325 class SimpleBackendNoMetaFactory : public BackendFactory
326 {
327 public:
328 SimpleBackendNoMetaFactory(): BackendFactory("SimpleBackendNoMeta")
329 {
330 }
331
332 DNSBackend *make(const string& suffix="") override
333 {
334 return new SimpleBackendNoMeta(suffix);
335 }
336 };
337
338 struct UeberBackendSetupArgFixture {
339 UeberBackendSetupArgFixture() {
340 extern AuthQueryCache QC;
341 ::arg().set("query-cache-ttl")="0";
342 ::arg().set("negquery-cache-ttl")="0";
343 ::arg().set("consistent-backends")="no";
344 QC.purge();
345 g_zoneCache.setRefreshInterval(0);
346 g_zoneCache.clear();
347 BackendMakers().clear();
348 SimpleBackend::s_zones.clear();
349 SimpleBackend::s_metadata.clear();
350 };
351 };
352
353 static void testWithoutThenWithAuthCache(std::function<void(UeberBackend& ub)> func)
354 {
355 extern AuthQueryCache QC;
356
357 {
358 /* disable the cache */
359 ::arg().set("query-cache-ttl")="0";
360 ::arg().set("negquery-cache-ttl")="0";
361 QC.purge();
362 QC.setMaxEntries(0);
363 /* keep zone cache disabled */
364 g_zoneCache.setRefreshInterval(0);
365 g_zoneCache.clear();
366
367 UeberBackend ub;
368 func(ub);
369 }
370
371 {
372 /* enable the cache */
373 ::arg().set("query-cache-ttl")="20";
374 ::arg().set("negquery-cache-ttl")="60";
375 QC.purge();
376 QC.setMaxEntries(100000);
377 /* keep zone cache disabled */
378 g_zoneCache.setRefreshInterval(0);
379 g_zoneCache.clear();
380
381 UeberBackend ub;
382 /* a first time to fill the cache */
383 func(ub);
384 /* a second time to make sure every call has been tried with the cache filled */
385 func(ub);
386 }
387 }
388
389 static void testWithoutThenWithZoneCache(std::function<void(UeberBackend& ub)> func)
390 {
391 extern AuthQueryCache QC;
392
393 {
394 /* disable zone cache */
395 g_zoneCache.setRefreshInterval(0);
396 g_zoneCache.clear();
397 /* keep auth caches disabled */
398 ::arg().set("query-cache-ttl")="0";
399 ::arg().set("negquery-cache-ttl")="0";
400 QC.purge();
401 QC.setMaxEntries(0);
402
403 UeberBackend ub;
404 func(ub);
405 }
406
407 // This test is broken without getAllDomains() in SimpleBackend
408 // {
409 // /* enable zone cache */
410 // //g_zoneCache.setRefreshInterval(60);
411 // g_zoneCache.clear();
412 // /* keep auth caches disabled */
413 // ::arg().set("query-cache-ttl")="0";
414 // ::arg().set("negquery-cache-ttl")="0";
415 // QC.purge();
416 // QC.setMaxEntries(0);
417 //
418 // UeberBackend ub;
419 // ub.updateZoneCache();
420 // func(ub);
421 // }
422 }
423
424 BOOST_FIXTURE_TEST_SUITE(test_ueberbackend_cc, UeberBackendSetupArgFixture)
425
426 static std::vector<DNSZoneRecord> getRecords(UeberBackend& ub, const DNSName& name, uint16_t qtype, int zoneId, const DNSPacket* pkt)
427 {
428 std::vector<DNSZoneRecord> result;
429
430 ub.lookup(QType(qtype), name, zoneId, const_cast<DNSPacket*>(pkt));
431
432 DNSZoneRecord dzr;
433 while (ub.get(dzr))
434 {
435 result.push_back(std::move(dzr));
436 }
437
438 return result;
439 }
440
441 static void checkRecordExists(const std::vector<DNSZoneRecord>& records, const DNSName& name, uint16_t type, int zoneId, uint8_t scopeMask, bool auth)
442 {
443 BOOST_REQUIRE_GE(records.size(), 1U);
444 for (const auto& record : records) {
445 if (record.domain_id == zoneId &&
446 record.dr.d_type == type &&
447 record.dr.d_name == name &&
448 record.auth == auth &&
449 record.scopeMask == scopeMask) {
450 return;
451 }
452 }
453 BOOST_CHECK_MESSAGE(false, "Record " + name.toString() + "/" + QType(type).toString() + " - " + std::to_string(zoneId) + " not found");
454 }
455
456 BOOST_AUTO_TEST_CASE(test_simple) {
457
458 try {
459 SimpleBackend::SimpleDNSZone zoneA(DNSName("powerdns.com."), 1);
460 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::SOA, "ns1.powerdns.com. powerdns.com. 3 600 600 3600000 604800", 3600));
461 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::AAAA, "2001:db8::1", 60));
462 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.com."), QType::A, "192.168.0.1", 60));
463 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("geo.powerdns.com."), QType::A, "192.168.0.42", 60));
464 SimpleBackend::s_zones[1].insert(zoneA);
465
466 BackendMakers().report(new SimpleBackendFactory());
467 BackendMakers().launch("SimpleBackend:1");
468 UeberBackend::go();
469
470 auto testFunction = [](UeberBackend& ub) -> void {
471 {
472 // test SOA with unknown zone id == -1
473 auto records = getRecords(ub, DNSName("powerdns.com."), QType::SOA, -1, nullptr);
474 BOOST_REQUIRE_EQUAL(records.size(), 1U);
475 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
476 }
477
478 {
479 // test ANY with zone id == -1
480 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, -1, nullptr);
481 BOOST_REQUIRE_EQUAL(records.size(), 2U);
482 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
483 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
484 }
485
486 {
487 // test AAAA with zone id == -1
488 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, -1, nullptr);
489 BOOST_REQUIRE_EQUAL(records.size(), 1U);
490 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
491 }
492
493 {
494 // test NODATA with zone id == -1
495 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, -1, nullptr);
496 BOOST_REQUIRE_EQUAL(records.size(), 0U);
497 }
498
499 {
500 // test ANY with zone id set
501 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 1, nullptr);
502 BOOST_REQUIRE_EQUAL(records.size(), 2U);
503 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
504 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
505 }
506
507 {
508 // test AAAA with zone id set
509 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, 1, nullptr);
510 BOOST_REQUIRE_EQUAL(records.size(), 1U);
511 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
512 }
513
514 {
515 // test NODATA with zone id set
516 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, 1, nullptr);
517 BOOST_REQUIRE_EQUAL(records.size(), 0U);
518 }
519
520 {
521 // test ANY with wrong zone id
522 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 65535, nullptr);
523 BOOST_REQUIRE_EQUAL(records.size(), 0U);
524 }
525
526 {
527 // test a DNS packet is correctly passed and that the corresponding scope is passed back
528 DNSPacket pkt(true);
529 ComboAddress remote("192.0.2.1");
530 pkt.setRemote(&remote);
531 auto records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
532 BOOST_REQUIRE_EQUAL(records.size(), 1U);
533 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 32, true);
534 // and that we don't get the same result for a different client
535 remote = ComboAddress("198.51.100.1");
536 pkt.setRemote(&remote);
537 records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
538 BOOST_REQUIRE_EQUAL(records.size(), 1U);
539 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 24, true);
540 }
541
542 };
543 testWithoutThenWithAuthCache(testFunction);
544 testWithoutThenWithZoneCache(testFunction);
545 }
546 catch(const PDNSException& e) {
547 cerr<<e.reason<<endl;
548 throw;
549 }
550 catch(const std::exception& e) {
551 cerr<<e.what()<<endl;
552 throw;
553 }
554 catch(...) {
555 cerr<<"An unexpected error occurred.."<<endl;
556 throw;
557 }
558 }
559
560 BOOST_AUTO_TEST_CASE(test_multi_backends_separate_zones) {
561 // one zone in backend 1, a second zone in backend 2
562 // no overlap
563
564 try {
565 SimpleBackend::SimpleDNSZone zoneA(DNSName("powerdns.com."), 1);
566 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::SOA, "ns1.powerdns.com. powerdns.com. 3 600 600 3600000 604800", 3600));
567 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::AAAA, "2001:db8::1", 60));
568 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.com."), QType::A, "192.168.0.1", 60));
569 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("geo.powerdns.com."), QType::A, "192.168.0.42", 60));
570 SimpleBackend::s_zones[1].insert(zoneA);
571
572 SimpleBackend::SimpleDNSZone zoneB(DNSName("powerdns.org."), 2);
573 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.org."), QType::SOA, "ns1.powerdns.org. powerdns.org. 3 600 600 3600000 604800", 3600));
574 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.org."), QType::AAAA, "2001:db8::2", 60));
575 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.org."), QType::AAAA, "2001:db8::2", 60));
576 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("geo.powerdns.org."), QType::AAAA, "2001:db8::42", 60));
577 SimpleBackend::s_zones[2].insert(zoneB);
578
579 BackendMakers().report(new SimpleBackendFactory());
580 BackendMakers().launch("SimpleBackend:1, SimpleBackend:2");
581 UeberBackend::go();
582
583 auto testFunction = [](UeberBackend& ub) -> void {
584 {
585 // test SOA with unknown zone id == -1
586 auto records = getRecords(ub, DNSName("powerdns.com."), QType::SOA, -1, nullptr);
587 BOOST_REQUIRE_EQUAL(records.size(), 1U);
588 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
589
590 records = getRecords(ub, DNSName("powerdns.org."), QType::SOA, -1, nullptr);
591 BOOST_REQUIRE_EQUAL(records.size(), 1U);
592 checkRecordExists(records, DNSName("powerdns.org."), QType::SOA, 2, 0, true);
593 }
594
595 {
596 // test ANY with zone id == -1
597 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, -1, nullptr);
598 BOOST_REQUIRE_EQUAL(records.size(), 2U);
599 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
600 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
601
602 records = getRecords(ub, DNSName("powerdns.org."), QType::ANY, -1, nullptr);
603 BOOST_REQUIRE_EQUAL(records.size(), 2U);
604 checkRecordExists(records, DNSName("powerdns.org."), QType::SOA, 2, 0, true);
605 checkRecordExists(records, DNSName("powerdns.org."), QType::AAAA, 2, 0, true);
606 }
607
608 {
609 // test AAAA with zone id == -1
610 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, -1, nullptr);
611 BOOST_REQUIRE_EQUAL(records.size(), 1U);
612 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
613
614 records = getRecords(ub, DNSName("powerdns.org."), QType::AAAA, -1, nullptr);
615 BOOST_REQUIRE_EQUAL(records.size(), 1U);
616 checkRecordExists(records, DNSName("powerdns.org."), QType::AAAA, 2, 0, true);
617 }
618
619 {
620 // test NODATA with zone id == -1
621 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, -1, nullptr);
622 BOOST_REQUIRE_EQUAL(records.size(), 0U);
623
624 records = getRecords(ub, DNSName("powerdns.org."), QType::PTR, -1, nullptr);
625 BOOST_REQUIRE_EQUAL(records.size(), 0U);
626 }
627
628 {
629 // test ANY with zone id set
630 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 1, nullptr);
631 BOOST_REQUIRE_EQUAL(records.size(), 2U);
632 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
633 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
634
635 records = getRecords(ub, DNSName("powerdns.org."), QType::ANY, 2, nullptr);
636 BOOST_REQUIRE_EQUAL(records.size(), 2U);
637 checkRecordExists(records, DNSName("powerdns.org."), QType::SOA, 2, 0, true);
638 checkRecordExists(records, DNSName("powerdns.org."), QType::AAAA, 2, 0, true);
639 }
640
641 {
642 // test AAAA with zone id set
643 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, 1, nullptr);
644 BOOST_REQUIRE_EQUAL(records.size(), 1U);
645 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
646
647 records = getRecords(ub, DNSName("www.powerdns.org."), QType::AAAA, 2, nullptr);
648 BOOST_REQUIRE_EQUAL(records.size(), 1U);
649 checkRecordExists(records, DNSName("www.powerdns.org."), QType::AAAA, 2, 0, true);
650 }
651
652 {
653 // test NODATA with zone id set
654 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, 1, nullptr);
655 BOOST_REQUIRE_EQUAL(records.size(), 0U);
656
657 records = getRecords(ub, DNSName("powerdns.org."), QType::PTR, 2, nullptr);
658 BOOST_REQUIRE_EQUAL(records.size(), 0U);
659 }
660
661 {
662 // test ANY with wrong zone id
663 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 2, nullptr);
664 BOOST_REQUIRE_EQUAL(records.size(), 0U);
665
666 records = getRecords(ub, DNSName("powerdns.org."), QType::ANY, 1, nullptr);
667 BOOST_REQUIRE_EQUAL(records.size(), 0U);
668
669 records = getRecords(ub, DNSName("not-powerdns.com."), QType::ANY, 65535, nullptr);
670 BOOST_REQUIRE_EQUAL(records.size(), 0U);
671 }
672
673 {
674 // test a DNS packet is correctly passed and that the corresponding scope is passed back
675 DNSPacket pkt(true);
676 ComboAddress remote("192.0.2.1");
677 pkt.setRemote(&remote);
678 auto records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
679 BOOST_REQUIRE_EQUAL(records.size(), 1U);
680 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 32, true);
681 // and that we don't get the same result for a different client
682 remote = ComboAddress("198.51.100.1");
683 pkt.setRemote(&remote);
684 records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
685 BOOST_REQUIRE_EQUAL(records.size(), 1U);
686 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 24, true);
687 }
688
689 };
690 testWithoutThenWithAuthCache(testFunction);
691 testWithoutThenWithZoneCache(testFunction);
692 }
693 catch(const PDNSException& e) {
694 cerr<<e.reason<<endl;
695 throw;
696 }
697 catch(const std::exception& e) {
698 cerr<<e.what()<<endl;
699 throw;
700 }
701 catch(...) {
702 cerr<<"An unexpected error occurred.."<<endl;
703 throw;
704 }
705 }
706
707 BOOST_AUTO_TEST_CASE(test_multi_backends_overlay) {
708 // one backend holds the SOA, NS and one A
709 // a second backend holds another A and AAAA
710 try {
711 SimpleBackend::SimpleDNSZone zoneA(DNSName("powerdns.com."), 1);
712 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::SOA, "ns1.powerdns.com. powerdns.com. 3 600 600 3600000 604800", 3600));
713 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", 3600));
714 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::A, "192.168.0.1", 60));
715 SimpleBackend::s_zones[1].insert(zoneA);
716
717 SimpleBackend::SimpleDNSZone zoneB(DNSName("powerdns.com."), 1);
718 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::A, "192.168.0.2", 60));
719 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::AAAA, "2001:db8::1", 60));
720 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.com."), QType::A, "192.168.0.1", 60));
721 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("geo.powerdns.com."), QType::A, "192.168.0.42", 60));
722 SimpleBackend::s_zones[2].insert(zoneB);
723
724 BackendMakers().report(new SimpleBackendFactory());
725 BackendMakers().launch("SimpleBackend:1, SimpleBackend:2");
726 UeberBackend::go();
727
728 auto testFunction = [](UeberBackend& ub) -> void {
729 {
730 // test SOA with unknown zone id == -1
731 auto records = getRecords(ub, DNSName("powerdns.com."), QType::SOA, -1, nullptr);
732 BOOST_REQUIRE_EQUAL(records.size(), 1U);
733 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
734 }
735
736 {
737 // test ANY with zone id == -1
738 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, -1, nullptr);
739 // /!\ only 3 records are returned since we don't allow spreading the same name over several backends
740 BOOST_REQUIRE_EQUAL(records.size(), 3U);
741 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
742 checkRecordExists(records, DNSName("powerdns.com."), QType::NS, 1, 0, true);
743 checkRecordExists(records, DNSName("powerdns.com."), QType::A, 1, 0, true);
744 //checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
745 }
746
747 {
748 // test AAAA with zone id == -1
749 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, -1, nullptr);
750 // /!\ the AAAA will be found on an exact search, but not on an ANY one
751 BOOST_REQUIRE_EQUAL(records.size(), 1U);
752 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
753 }
754
755 {
756 // test NODATA with zone id == -1
757 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, -1, nullptr);
758 BOOST_REQUIRE_EQUAL(records.size(), 0U);
759 }
760
761 {
762 // test ANY with zone id set
763 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 1, nullptr);
764 // /!\ only 3 records are returned since we don't allow spreading the same name over several backends
765 BOOST_REQUIRE_EQUAL(records.size(), 3U);
766 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
767 checkRecordExists(records, DNSName("powerdns.com."), QType::NS, 1, 0, true);
768 checkRecordExists(records, DNSName("powerdns.com."), QType::A, 1, 0, true);
769 //checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
770 }
771
772 {
773 // test AAAA with zone id set
774 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, 1, nullptr);
775 // /!\ the AAAA will be found on an exact search, but not on an ANY one
776 BOOST_REQUIRE_EQUAL(records.size(), 1U);
777 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
778 }
779
780 {
781 // test www - A with zone id set (only in the second backend)
782 auto records = getRecords(ub, DNSName("www.powerdns.com."), QType::A, 1, nullptr);
783 BOOST_REQUIRE_EQUAL(records.size(), 1U);
784 checkRecordExists(records, DNSName("www.powerdns.com."), QType::A, 1, 0, true);
785 }
786
787 {
788 // test NODATA with zone id set
789 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, 1, nullptr);
790 BOOST_REQUIRE_EQUAL(records.size(), 0U);
791 }
792
793 {
794 // test ANY with wrong zone id
795 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 2, nullptr);
796 BOOST_REQUIRE_EQUAL(records.size(), 0U);
797 }
798
799 {
800 // test a DNS packet is correctly passed and that the corresponding scope is passed back
801 DNSPacket pkt(true);
802 ComboAddress remote("192.0.2.1");
803 pkt.setRemote(&remote);
804 auto records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
805 BOOST_REQUIRE_EQUAL(records.size(), 1U);
806 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 32, true);
807 // and that we don't get the same result for a different client
808 remote = ComboAddress("198.51.100.1");
809 pkt.setRemote(&remote);
810 records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
811 BOOST_REQUIRE_EQUAL(records.size(), 1U);
812 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 24, true);
813 }
814
815 };
816 testWithoutThenWithAuthCache(testFunction);
817 testWithoutThenWithZoneCache(testFunction);
818 }
819 catch(const PDNSException& e) {
820 cerr<<e.reason<<endl;
821 throw;
822 }
823 catch(const std::exception& e) {
824 cerr<<e.what()<<endl;
825 throw;
826 }
827 catch(...) {
828 cerr<<"An unexpected error occurred.."<<endl;
829 throw;
830 }
831 }
832
833 BOOST_AUTO_TEST_CASE(test_multi_backends_overlay_name) {
834 // one backend holds the apex with SOA, NS and one A
835 // a second backend holds others names
836 try {
837 SimpleBackend::SimpleDNSZone zoneA(DNSName("powerdns.com."), 1);
838 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::SOA, "ns1.powerdns.com. powerdns.com. 3 600 600 3600000 604800", 3600));
839 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", 3600));
840 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::A, "192.168.0.1", 60));
841 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::A, "192.168.0.2", 60));
842 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::AAAA, "2001:db8::1", 60));
843 SimpleBackend::s_zones[1].insert(zoneA);
844
845 SimpleBackend::SimpleDNSZone zoneB(DNSName("powerdns.com."), 1);
846 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.com."), QType::A, "192.168.0.1", 60));
847 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.com."), QType::AAAA, "192.168.0.1", 60));
848 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("geo.powerdns.com."), QType::A, "192.168.0.42", 60));
849 SimpleBackend::s_zones[2].insert(zoneB);
850
851 BackendMakers().report(new SimpleBackendFactory());
852 BackendMakers().launch("SimpleBackend:1, SimpleBackend:2");
853 UeberBackend::go();
854
855 auto testFunction = [](UeberBackend& ub) -> void {
856 {
857 // test SOA with unknown zone id == -1
858 auto records = getRecords(ub, DNSName("powerdns.com."), QType::SOA, -1, nullptr);
859 BOOST_REQUIRE_EQUAL(records.size(), 1U);
860 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
861 }
862
863 {
864 // test ANY with zone id == -1
865 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, -1, nullptr);
866 BOOST_REQUIRE_EQUAL(records.size(), 5U);
867 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
868 checkRecordExists(records, DNSName("powerdns.com."), QType::NS, 1, 0, true);
869 checkRecordExists(records, DNSName("powerdns.com."), QType::A, 1, 0, true);
870 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
871 }
872
873 {
874 // test AAAA with zone id == -1
875 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, -1, nullptr);
876 BOOST_REQUIRE_EQUAL(records.size(), 1U);
877 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
878 }
879
880 {
881 // test NODATA with zone id == -1
882 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, -1, nullptr);
883 BOOST_REQUIRE_EQUAL(records.size(), 0U);
884 }
885
886 {
887 // test ANY with zone id set
888 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 1, nullptr);
889 BOOST_REQUIRE_EQUAL(records.size(), 5U);
890 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 1, 0, true);
891 checkRecordExists(records, DNSName("powerdns.com."), QType::NS, 1, 0, true);
892 checkRecordExists(records, DNSName("powerdns.com."), QType::A, 1, 0, true);
893 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
894 }
895
896 {
897 // test AAAA with zone id set
898 auto records = getRecords(ub, DNSName("powerdns.com."), QType::AAAA, 1, nullptr);
899 BOOST_REQUIRE_EQUAL(records.size(), 1U);
900 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 1, 0, true);
901 }
902
903 {
904 // test www - A with zone id set (only in the second backend)
905 auto records = getRecords(ub, DNSName("www.powerdns.com."), QType::A, 1, nullptr);
906 BOOST_REQUIRE_EQUAL(records.size(), 1U);
907 checkRecordExists(records, DNSName("www.powerdns.com."), QType::A, 1, 0, true);
908 }
909
910 {
911 // test NODATA with zone id set
912 auto records = getRecords(ub, DNSName("powerdns.com."), QType::PTR, 1, nullptr);
913 BOOST_REQUIRE_EQUAL(records.size(), 0U);
914 }
915
916 {
917 // test ANY with wrong zone id
918 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, 2, nullptr);
919 BOOST_REQUIRE_EQUAL(records.size(), 0U);
920 }
921
922 {
923 // test a DNS packet is correctly passed and that the corresponding scope is passed back
924 DNSPacket pkt(true);
925 ComboAddress remote("192.0.2.1");
926 pkt.setRemote(&remote);
927 auto records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
928 BOOST_REQUIRE_EQUAL(records.size(), 1U);
929 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 32, true);
930 // and that we don't get the same result for a different client
931 remote = ComboAddress("198.51.100.1");
932 pkt.setRemote(&remote);
933 records = getRecords(ub, DNSName("geo.powerdns.com."), QType::ANY, 1, &pkt);
934 BOOST_REQUIRE_EQUAL(records.size(), 1U);
935 checkRecordExists(records, DNSName("geo.powerdns.com."), QType::A, 1, 24, true);
936 }
937
938 };
939 testWithoutThenWithAuthCache(testFunction);
940 testWithoutThenWithZoneCache(testFunction);
941 }
942 catch(const PDNSException& e) {
943 cerr<<e.reason<<endl;
944 throw;
945 }
946 catch(const std::exception& e) {
947 cerr<<e.what()<<endl;
948 throw;
949 }
950 catch(...) {
951 cerr<<"An unexpected error occurred.."<<endl;
952 throw;
953 }
954 }
955
956 BOOST_AUTO_TEST_CASE(test_child_zone) {
957 // Backend 1 holds zone A "com" while backend 2 holds zone B "powerdns.com"
958 // Check that DS queries are correctly handled
959
960 try {
961 SimpleBackend::SimpleDNSZone zoneA(DNSName("com."), 1);
962 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("com."), QType::SOA, "a.gtld-servers.net. nstld.verisign-grs.com. 3 600 600 3600000 604800", 3600));
963 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", 3600));
964 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::DS, "44030 8 3 7DD75AE1565051F9563CF8DF976AC99CDCA51E3463019C81BD2BB083 82F3854E", 3600));
965 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("ns1.powerdns.com."), QType::A, "192.0.2.1", 3600));
966 SimpleBackend::s_zones[1].insert(zoneA);
967
968 SimpleBackend::SimpleDNSZone zoneB(DNSName("powerdns.com."), 2);
969 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::SOA, "ns1.powerdns.com. powerdns.com. 3 600 600 3600000 604800", 3600));
970 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::AAAA, "2001:db8::2", 60));
971 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", 3600));
972 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("ns1.powerdns.com."), QType::A, "192.0.2.1", 3600));
973 SimpleBackend::s_zones[2].insert(zoneB);
974
975 BackendMakers().report(new SimpleBackendFactory());
976 BackendMakers().launch("SimpleBackend:1, SimpleBackend:2");
977 UeberBackend::go();
978
979 auto testFunction = [](UeberBackend& ub) -> void {
980 {
981 // test SOA with unknown zone id == -1
982 auto records = getRecords(ub, DNSName("com."), QType::SOA, -1, nullptr);
983 BOOST_REQUIRE_EQUAL(records.size(), 1U);
984 checkRecordExists(records, DNSName("com."), QType::SOA, 1, 0, true);
985
986 records = getRecords(ub, DNSName("powerdns.com."), QType::SOA, -1, nullptr);
987 BOOST_REQUIRE_EQUAL(records.size(), 1U);
988 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 2, 0, true);
989 }
990
991 {
992 // test ANY with zone id == -1
993 auto records = getRecords(ub, DNSName("powerdns.com."), QType::ANY, -1, nullptr);
994 BOOST_REQUIRE_EQUAL(records.size(), 3U);
995 checkRecordExists(records, DNSName("powerdns.com."), QType::SOA, 2, 0, true);
996 checkRecordExists(records, DNSName("powerdns.com."), QType::NS, 2, 0, true);
997 checkRecordExists(records, DNSName("powerdns.com."), QType::AAAA, 2, 0, true);
998 }
999
1000 {
1001 // test getAuth() for DS
1002 SOAData sd;
1003 BOOST_REQUIRE(ub.getAuth(DNSName("powerdns.com."), QType::DS, &sd));
1004 BOOST_CHECK_EQUAL(sd.qname.toString(), "com.");
1005 BOOST_CHECK_EQUAL(sd.domain_id, 1);
1006 }
1007
1008 {
1009 // test getAuth() for A
1010 SOAData sd;
1011 BOOST_REQUIRE(ub.getAuth(DNSName("powerdns.com."), QType::A, &sd));
1012 BOOST_CHECK_EQUAL(sd.qname.toString(), "powerdns.com.");
1013 BOOST_CHECK_EQUAL(sd.domain_id, 2);
1014 }
1015
1016 };
1017 testWithoutThenWithAuthCache(testFunction);
1018 testWithoutThenWithZoneCache(testFunction);
1019 }
1020 catch(const PDNSException& e) {
1021 cerr<<e.reason<<endl;
1022 throw;
1023 }
1024 catch(const std::exception& e) {
1025 cerr<<e.what()<<endl;
1026 throw;
1027 }
1028 catch(...) {
1029 cerr<<"An unexpected error occurred.."<<endl;
1030 throw;
1031 }
1032 }
1033
1034 BOOST_AUTO_TEST_CASE(test_multi_backends_best_soa) {
1035 // several backends, one returns the best SOA it has right away
1036 // while the others do simple lookups
1037
1038 try {
1039 SimpleBackend::SimpleDNSZone zoneA(DNSName("d.0.1.0.0.2.ip6.arpa."), 1);
1040 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("d.0.1.0.0.2.ip6.arpa."), QType::SOA, "ns.apnic.net. read-txt-record-of-zone-first-dns-admin.apnic.net. 3005126844 7200 1800 604800 3600", 3600));
1041 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("2.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa."), QType::PTR, "a.reverse.", 3600));
1042 SimpleBackend::s_zones[1].insert(zoneA);
1043
1044 SimpleBackend::SimpleDNSZone zoneB(DNSName("0.1.0.0.2.ip6.arpa."), 2);
1045 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("0.1.0.0.2.ip6.arpa."), QType::SOA, "ns.apnic.net. read-txt-record-of-zone-first-dns-admin.apnic.net. 3005126844 7200 1800 604800 3600", 3600));
1046 SimpleBackend::s_zones[2].insert(zoneB);
1047
1048 BackendMakers().report(new SimpleBackendFactory());
1049 BackendMakers().report(new SimpleBackendBestAuthFactory());
1050 BackendMakers().launch("SimpleBackendBestAuth:1, SimpleBackend:2");
1051 UeberBackend::go();
1052
1053 auto testFunction = [](UeberBackend& ub) -> void {
1054 {
1055 auto sbba = dynamic_cast<SimpleBackendBestAuth*>(ub.backends.at(0));
1056 BOOST_REQUIRE(sbba != nullptr);
1057 sbba->d_authLookupCount = 0;
1058
1059 // test getAuth()
1060 SOAData sd;
1061 BOOST_REQUIRE(ub.getAuth(DNSName("2.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa."), QType::PTR, &sd));
1062 BOOST_CHECK_EQUAL(sd.qname.toString(), "d.0.1.0.0.2.ip6.arpa.");
1063 BOOST_CHECK_EQUAL(sd.domain_id, 1);
1064
1065 // check that at most one auth lookup occurred to this backend (O with caching enabled)
1066 BOOST_CHECK_LE(sbba->d_authLookupCount, 1U);
1067 }
1068
1069 };
1070 testWithoutThenWithAuthCache(testFunction);
1071 testWithoutThenWithZoneCache(testFunction);
1072 }
1073 catch(const PDNSException& e) {
1074 cerr<<e.reason<<endl;
1075 throw;
1076 }
1077 catch(const std::exception& e) {
1078 cerr<<e.what()<<endl;
1079 throw;
1080 }
1081 catch(...) {
1082 cerr<<"An unexpected error occurred.."<<endl;
1083 throw;
1084 }
1085 }
1086
1087 BOOST_AUTO_TEST_CASE(test_multi_backends_metadata) {
1088 // we have metadata stored in the first and second backend.
1089 // We can read from the first backend but not from the second, since the first will return "true" even though it has nothing
1090 // Updating will insert into the first backend, leaving the first one untouched
1091
1092 try {
1093 SimpleBackend::SimpleDNSZone zoneA(DNSName("powerdns.com."), 1);
1094 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::SOA, "ns1.powerdns.com. powerdns.com. 3 600 600 3600000 604800", 3600));
1095 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.com."), QType::AAAA, "2001:db8::1", 60));
1096 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.com."), QType::A, "192.168.0.1", 60));
1097 zoneA.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("geo.powerdns.com."), QType::A, "192.168.0.42", 60));
1098 SimpleBackend::s_zones[1].insert(zoneA);
1099 SimpleBackend::s_metadata[1].insert(SimpleBackend::SimpleMetaData(DNSName("powerdns.com."), "test-data-a", { "value1", "value2"}));
1100
1101 SimpleBackend::SimpleDNSZone zoneB(DNSName("powerdns.org."), 2);
1102 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.org."), QType::SOA, "ns1.powerdns.org. powerdns.org. 3 600 600 3600000 604800", 3600));
1103 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("powerdns.org."), QType::AAAA, "2001:db8::2", 60));
1104 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("www.powerdns.org."), QType::AAAA, "2001:db8::2", 60));
1105 zoneB.d_records->insert(SimpleBackend::SimpleDNSRecord(DNSName("geo.powerdns.org."), QType::AAAA, "2001:db8::42", 60));
1106 SimpleBackend::s_zones[2].insert(zoneB);
1107 SimpleBackend::s_metadata[2].insert(SimpleBackend::SimpleMetaData(DNSName("powerdns.org."), "test-data-b", { "value1", "value2"}));
1108
1109 BackendMakers().report(new SimpleBackendFactory());
1110 BackendMakers().launch("SimpleBackend:1, SimpleBackend:2");
1111 UeberBackend::go();
1112
1113 auto testFunction = [](UeberBackend& ub) -> void {
1114 {
1115 // check the initial values
1116 std::vector<std::string> values;
1117 BOOST_CHECK(ub.getDomainMetadata(DNSName("powerdns.com."), "test-data-a", values));
1118 BOOST_REQUIRE_EQUAL(values.size(), 2U);
1119 BOOST_CHECK_EQUAL(values.at(0), "value1");
1120 BOOST_CHECK_EQUAL(values.at(1), "value2");
1121 values.clear();
1122 BOOST_CHECK(ub.getDomainMetadata(DNSName("powerdns.com."), "test-data-b", values));
1123 BOOST_CHECK_EQUAL(values.size(), 0U);
1124 values.clear();
1125 BOOST_CHECK(ub.getDomainMetadata(DNSName("powerdns.org."), "test-data-a", values));
1126 BOOST_CHECK_EQUAL(values.size(), 0U);
1127 values.clear();
1128 BOOST_CHECK(ub.getDomainMetadata(DNSName("powerdns.org."), "test-data-b", values));
1129 BOOST_CHECK_EQUAL(values.size(), 0U);
1130 }
1131
1132 {
1133 // update the values
1134 BOOST_CHECK(ub.setDomainMetadata(DNSName("powerdns.com."), "test-data-a", { "value3" }));
1135 BOOST_CHECK(ub.setDomainMetadata(DNSName("powerdns.org."), "test-data-a", { "value4" }));
1136 BOOST_CHECK(ub.setDomainMetadata(DNSName("powerdns.org."), "test-data-b", { "value5" }));
1137 }
1138
1139 // check the updated values
1140 {
1141 std::vector<std::string> values;
1142 BOOST_CHECK(ub.getDomainMetadata(DNSName("powerdns.com."), "test-data-a", values));
1143 BOOST_REQUIRE_EQUAL(values.size(), 1U);
1144 BOOST_CHECK_EQUAL(values.at(0), "value3");
1145 values.clear();
1146 BOOST_CHECK(ub.getDomainMetadata(DNSName("powerdns.org."), "test-data-a", values));
1147 BOOST_REQUIRE_EQUAL(values.size(), 1U);
1148 BOOST_CHECK_EQUAL(values.at(0), "value4");
1149 values.clear();
1150 BOOST_CHECK(ub.getDomainMetadata(DNSName("powerdns.org."), "test-data-b", values));
1151 BOOST_REQUIRE_EQUAL(values.size(), 1U);
1152 BOOST_CHECK_EQUAL(values.at(0), "value5");
1153 }
1154
1155 {
1156 // check that it has not been updated in the second backend
1157 const auto& it = SimpleBackend::s_metadata[2].find(std::make_tuple(DNSName("powerdns.org."), "test-data-b"));
1158 BOOST_REQUIRE(it != SimpleBackend::s_metadata[2].end());
1159 BOOST_REQUIRE_EQUAL(it->d_values.size(), 2U);
1160 BOOST_CHECK_EQUAL(it->d_values.at(0), "value1");
1161 BOOST_CHECK_EQUAL(it->d_values.at(1), "value2");
1162 }
1163 };
1164
1165 UeberBackend ub;
1166 testFunction(ub);
1167 }
1168 catch(const PDNSException& e) {
1169 cerr<<e.reason<<endl;
1170 throw;
1171 }
1172 catch(const std::exception& e) {
1173 cerr<<e.what()<<endl;
1174 throw;
1175 }
1176 catch(...) {
1177 cerr<<"An unexpected error occurred.."<<endl;
1178 throw;
1179 }
1180 }
1181
1182
1183 BOOST_AUTO_TEST_SUITE_END();