]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
rec: Add CNAME `SyncRes` unit tests
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc.cc
CommitLineData
30ee601a
RG
1#define BOOST_TEST_DYN_LINK
2#define BOOST_TEST_NO_MAIN
3#include <boost/test/unit_test.hpp>
4
5#include "arguments.hh"
6#include "lua-recursor4.hh"
7#include "namespaces.hh"
8#include "rec-lua-conf.hh"
9#include "root-dnssec.hh"
10#include "syncres.hh"
11#include "validate-recursor.hh"
12
13std::unordered_set<DNSName> g_delegationOnly;
14RecursorStats g_stats;
15GlobalStateHolder<LuaConfigItems> g_luaconfs;
16NetmaskGroup* g_dontQuery{nullptr};
17__thread MemRecursorCache* t_RC{nullptr};
18SyncRes::domainmap_t* g_initialDomainMap{nullptr};
19unsigned int g_numThreads = 1;
20
21/* Fake some required functions we didn't want the trouble to
22 link with */
23ArgvMap &arg()
24{
25 static ArgvMap theArg;
26 return theArg;
27}
28
29int getMTaskerTID()
30{
31 return 0;
32}
33
34bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret)
35{
36 return false;
37}
38
39int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res)
40{
41 return 0;
42}
43
44/* primeHints() is only here for now because it
45 was way too much trouble to link with the real one.
46 We should fix this, empty functions are one thing, but this is
47 bad.
48*/
49
50#include "root-addresses.hh"
51
52void primeHints(void)
53{
54 vector<DNSRecord> nsset;
55 if(!t_RC)
56 t_RC = new MemRecursorCache();
57
58 DNSRecord arr, aaaarr, nsrr;
59 nsrr.d_name=g_rootdnsname;
60 arr.d_type=QType::A;
61 aaaarr.d_type=QType::AAAA;
62 nsrr.d_type=QType::NS;
63 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000;
64
65 for(char c='a';c<='m';++c) {
66 static char templ[40];
67 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
68 templ[sizeof(templ)-1] = '\0';
69 *templ=c;
70 aaaarr.d_name=arr.d_name=DNSName(templ);
71 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
72 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
73 vector<DNSRecord> aset;
74 aset.push_back(arr);
75 t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), true); // auth, nuke it all
76 if (rootIps6[c-'a'] != NULL) {
77 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
78
79 vector<DNSRecord> aaaaset;
80 aaaaset.push_back(aaaarr);
81 t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), true);
82 }
83
84 nsset.push_back(nsrr);
85 }
86 t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), false); // and stuff in the cache
87}
88
89LuaConfigItems::LuaConfigItems()
90{
91 for (const auto &dsRecord : rootDSs) {
92 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
93 dsAnchors[g_rootdnsname].insert(*ds);
94 }
95}
96
97/* Some helpers functions */
98
99static void init(bool debug=false)
100{
101 if (debug) {
102 L.setName("test");
103 L.setLoglevel((Logger::Urgency)(6)); // info and up
104 L.disableSyslog(true);
105 L.toConsole(Logger::Info);
106 }
107
108 seedRandom("/dev/urandom");
109
110 if (g_dontQuery)
111 delete g_dontQuery;
112 g_dontQuery = new NetmaskGroup();
113
114 if (t_RC)
115 delete t_RC;
116 t_RC = new MemRecursorCache();
117
118 if (g_initialDomainMap)
119 delete g_initialDomainMap;
120 g_initialDomainMap = new SyncRes::domainmap_t(); // new threads needs this to be setup
121
122 SyncRes::s_maxqperq = 50;
123 SyncRes::s_maxtotusec = 1000*7000;
124 SyncRes::s_maxdepth = 40;
125 SyncRes::s_maxnegttl = 3600;
126 SyncRes::s_maxcachettl = 86400;
127 SyncRes::s_packetcachettl = 3600;
128 SyncRes::s_packetcacheservfailttl = 60;
129 SyncRes::s_serverdownmaxfails = 64;
130 SyncRes::s_serverdownthrottletime = 60;
131 SyncRes::s_doIPv6 = true;
e9f9b8ec
RG
132 SyncRes::s_ecsipv4limit = 24;
133 SyncRes::s_ecsipv6limit = 56;
30ee601a 134
e9f9b8ec
RG
135 g_ednssubnets = NetmaskGroup();
136 g_ednsdomains = SuffixMatchNode();
137 g_useIncomingECS = false;
30ee601a
RG
138}
139
4fff116b 140static void initSR(std::unique_ptr<SyncRes>& sr, bool edns0, bool dnssec, SyncRes::LogMode lm=SyncRes::LogNone)
30ee601a
RG
141{
142 struct timeval now;
143 Utility::gettimeofday(&now, 0);
144 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
145 sr->setDoEDNS0(edns0);
146 sr->setDoDNSSEC(dnssec);
4fff116b 147 sr->setLogMode(lm);
30ee601a
RG
148 t_sstorage->domainmap = g_initialDomainMap;
149 t_sstorage->negcache.clear();
150 t_sstorage->nsSpeeds.clear();
151 t_sstorage->ednsstatus.clear();
152 t_sstorage->throttle.clear();
153 t_sstorage->fails.clear();
154 t_sstorage->dnssecmap.clear();
155}
156
157static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
158{
159 res->d_rcode = rcode;
160 res->d_aabit = aa;
161 res->d_tcbit = tc;
162 res->d_haveEDNS = edns;
163}
164
165static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
166{
167 DNSRecord rec;
168 rec.d_place = place;
169 rec.d_name = name;
170 rec.d_type = type;
171 rec.d_ttl = ttl;
172
173 if (type == QType::NS) {
174 rec.d_content = std::make_shared<NSRecordContent>(DNSName(content));
175 }
176 else if (type == QType::A) {
177 rec.d_content = std::make_shared<ARecordContent>(ComboAddress(content));
178 }
778bcea6 179 else if (type == QType::AAAA) {
30ee601a
RG
180 rec.d_content = std::make_shared<AAAARecordContent>(ComboAddress(content));
181 }
778bcea6
RG
182 else if (type == QType::CNAME) {
183 rec.d_content = std::make_shared<CNAMERecordContent>(DNSName(content));
184 }
30ee601a
RG
185 else {
186 rec.d_content = shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(type, QClass::IN, content));
187 }
188
189 res->d_records.push_back(rec);
190}
191
192static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
193{
194 addRecordToLW(res, DNSName(name), type, content, place, ttl);
195}
196
197static bool isRootServer(const ComboAddress& ip)
198{
199 for (size_t idx = 0; idx < rootIps4Count; idx++) {
200 if (ip.toString() == rootIps4[idx]) {
201 return true;
202 }
203 }
204
205 for (size_t idx = 0; idx < rootIps6Count; idx++) {
206 if (ip.toString() == rootIps6[idx]) {
207 return true;
208 }
209 }
210 return false;
211}
212
213/* Real tests */
214
215BOOST_AUTO_TEST_SUITE(syncres_cc)
216
217BOOST_AUTO_TEST_CASE(test_root_primed) {
218 std::unique_ptr<SyncRes> sr;
219 init();
220 initSR(sr, true, false);
221
222 primeHints();
223
224 /* we are primed, we should be able to resolve NS . without any query */
225 vector<DNSRecord> ret;
226 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
227 BOOST_CHECK_EQUAL(res, 0);
228 BOOST_CHECK_EQUAL(ret.size(), 13);
229}
230
231BOOST_AUTO_TEST_CASE(test_root_not_primed) {
232 std::unique_ptr<SyncRes> sr;
233 init(false);
234 initSR(sr, true, false);
235
236 size_t queriesCount = 0;
237
238 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
239 queriesCount++;
240
241 if (domain == g_rootdnsname && type == QType::NS) {
242 setLWResult(res, 0, true, false, true);
243 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
244 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
245 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
246
247 return 1;
248 }
249
250 return 0;
251 });
252
253 /* we are not primed yet, so SyncRes will have to call primeHints()
254 then call getRootNS(), for which at least one of the root servers needs to answer */
255 vector<DNSRecord> ret;
256 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
257 BOOST_CHECK_EQUAL(res, 0);
258 BOOST_CHECK_EQUAL(ret.size(), 1);
259 BOOST_CHECK_EQUAL(queriesCount, 2);
260}
261
262BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
263 std::unique_ptr<SyncRes> sr;
264 init();
265 initSR(sr, true, false);
266 std::set<ComboAddress> downServers;
267
268 /* we are not primed yet, so SyncRes will have to call primeHints()
269 then call getRootNS(), for which at least one of the root servers needs to answer.
270 None will, so it should ServFail.
271 */
272 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
273
274 downServers.insert(ip);
275 return 0;
276 });
277
278 vector<DNSRecord> ret;
279 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
280 BOOST_CHECK_EQUAL(res, 2);
281 BOOST_CHECK_EQUAL(ret.size(), 0);
282 BOOST_CHECK(downServers.size() > 0);
283 /* we explicitly refuse to mark the root servers down */
284 for (const auto& server : downServers) {
285 BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 0);
286 }
287}
288
289BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
290 std::unique_ptr<SyncRes> sr;
291 init();
292 initSR(sr, true, false);
293
294 ComboAddress noEDNSServer;
295 size_t queriesWithEDNS = 0;
296 size_t queriesWithoutEDNS = 0;
297
298 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &noEDNSServer](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
299 if (EDNS0Level != 0) {
300 queriesWithEDNS++;
301 noEDNSServer = ip;
302
303 setLWResult(res, RCode::FormErr);
304 return 1;
305 }
306
307 queriesWithoutEDNS++;
308
309 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
310 setLWResult(res, 0, true, false, false);
311 addRecordToLW(res, domain, QType::A, "192.0.2.1");
312 return 1;
313 }
314
315 return 0;
316 });
317
318 primeHints();
319
320 /* fake that the root NS doesn't handle EDNS, check that we fallback */
321 vector<DNSRecord> ret;
322 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
323 BOOST_CHECK_EQUAL(res, 0);
324 BOOST_CHECK_EQUAL(ret.size(), 1);
325 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
326 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
327 BOOST_CHECK_EQUAL(t_sstorage->ednsstatus.size(), 1);
328 BOOST_CHECK_EQUAL(t_sstorage->ednsstatus[noEDNSServer].mode, SyncRes::EDNSStatus::NOEDNS);
329}
330
331BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
332 std::unique_ptr<SyncRes> sr;
333 init();
334 initSR(sr, true, false);
335
336 size_t queriesWithEDNS = 0;
337 size_t queriesWithoutEDNS = 0;
338
339 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
340 if (EDNS0Level != 0) {
341 queriesWithEDNS++;
342 setLWResult(res, RCode::NotImp);
343 return 1;
344 }
345
346 queriesWithoutEDNS++;
347
348 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
349 setLWResult(res, 0, true, false, false);
350 addRecordToLW(res, domain, QType::A, "192.0.2.1");
351 return 1;
352 }
353
354 return 0;
355 });
356
357 primeHints();
358
359 /* fake that the NS doesn't handle EDNS, check that we fallback */
360 vector<DNSRecord> ret;
361 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
362 BOOST_CHECK_EQUAL(res, 0);
363 BOOST_CHECK_EQUAL(ret.size(), 1);
364 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
365 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
366}
367
368BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
369 std::unique_ptr<SyncRes> sr;
370 init();
371 initSR(sr, true, false);
372
373 sr->setAsyncCallback([](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
374 if (!doTCP) {
375 setLWResult(res, 0, false, true, false);
376 return 1;
377 }
378 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
379 setLWResult(res, 0, true, false, false);
380 addRecordToLW(res, domain, QType::A, "192.0.2.1");
381 return 1;
382 }
383
384 return 0;
385 });
386
387 primeHints();
388
389 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
390 vector<DNSRecord> ret;
391 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
392 BOOST_CHECK_EQUAL(res, 0);
393}
394
395BOOST_AUTO_TEST_CASE(test_all_nss_down) {
396 std::unique_ptr<SyncRes> sr;
397 init();
398 initSR(sr, true, false);
399 std::set<ComboAddress> downServers;
400
401 primeHints();
402
403 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
404
405 if (isRootServer(ip)) {
406 setLWResult(res, 0, true, false, true);
407 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
408 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
409 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
410 return 1;
411 }
412 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
413 setLWResult(res, 0, true, false, true);
414 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
415 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
416 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
417 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
418 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
419 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
420 return 1;
421 }
422 else {
423 downServers.insert(ip);
424 return 0;
425 }
426 });
427
428 vector<DNSRecord> ret;
429 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
430 BOOST_CHECK_EQUAL(res, 2);
431 BOOST_CHECK_EQUAL(ret.size(), 0);
432 BOOST_CHECK_EQUAL(downServers.size(), 4);
433
434 for (const auto& server : downServers) {
435 BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 1);
436 }
437}
438
439BOOST_AUTO_TEST_CASE(test_glued_referral) {
440 std::unique_ptr<SyncRes> sr;
441 init();
442 initSR(sr, true, false);
443
444 primeHints();
445
446 const DNSName target("powerdns.com.");
447
448 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
449 /* this will cause issue with qname minimization if we ever implement it */
450 if (domain != target) {
451 return 0;
452 }
453
454 if (isRootServer(ip)) {
455 setLWResult(res, 0, true, false, true);
456 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
457 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
458 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
459 return 1;
460 }
461 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
462 setLWResult(res, 0, true, false, true);
463 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
464 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
465 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
466 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
467 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
468 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
469 return 1;
470 }
471 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
472 setLWResult(res, 0, true, false, true);
473 addRecordToLW(res, target, QType::A, "192.0.2.4");
474 return 1;
475 }
476 else {
477 return 0;
478 }
479 });
480
481 vector<DNSRecord> ret;
482 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
483 BOOST_CHECK_EQUAL(res, 0);
484 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 485 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
486 BOOST_CHECK_EQUAL(ret[0].d_name, target);
487}
488
489BOOST_AUTO_TEST_CASE(test_glueless_referral) {
490 std::unique_ptr<SyncRes> sr;
491 init();
492 initSR(sr, true, false);
493
494 primeHints();
495
496 const DNSName target("powerdns.com.");
497
498 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
499
500 if (isRootServer(ip)) {
501 setLWResult(res, 0, true, false, true);
502
503 if (domain.isPartOf(DNSName("com."))) {
504 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
505 } else if (domain.isPartOf(DNSName("org."))) {
506 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
507 }
508 else {
509 setLWResult(res, RCode::NXDomain, false, false, true);
510 return 1;
511 }
512
513 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
514 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
515 return 1;
516 }
517 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
518 if (domain == target) {
519 setLWResult(res, 0, true, false, true);
520 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
521 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
522 return 1;
523 }
524 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
525 setLWResult(res, 0, true, false, true);
526 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
527 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
528 return 1;
529 }
530 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
531 setLWResult(res, 0, true, false, true);
532 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
533 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
534 return 1;
535 }
536
537 setLWResult(res, RCode::NXDomain, false, false, true);
538 return 1;
539 }
540 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
541 setLWResult(res, 0, true, false, true);
542 addRecordToLW(res, target, QType::A, "192.0.2.4");
543 return 1;
544 }
545 else {
546 return 0;
547 }
548 });
549
550 vector<DNSRecord> ret;
551 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
552 BOOST_CHECK_EQUAL(res, 0);
553 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 554 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
555 BOOST_CHECK_EQUAL(ret[0].d_name, target);
556}
557
e9f9b8ec
RG
558BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
559 std::unique_ptr<SyncRes> sr;
560 init();
561 initSR(sr, true, false);
562
563 primeHints();
564
565 const DNSName target("powerdns.com.");
566 g_useIncomingECS = true;
567 g_ednsdomains.add(target);
568
569 EDNSSubnetOpts incomingECS;
570 incomingECS.source = Netmask("192.0.2.128/32");
571 sr->setIncomingECSFound(true);
572 sr->setIncomingECS(incomingECS);
573
574 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
575
576 BOOST_REQUIRE(srcmask);
577 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
578 return 0;
579 });
580
581 vector<DNSRecord> ret;
582 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
583 BOOST_CHECK_EQUAL(res, 2);
584}
585
586BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
587 std::unique_ptr<SyncRes> sr;
588 init();
589 initSR(sr, true, false);
590
591 primeHints();
592
593 const DNSName target("powerdns.com.");
594 g_useIncomingECS = true;
595 g_ednssubnets.addMask("192.0.2.1/32");
596
597 EDNSSubnetOpts incomingECS;
598 incomingECS.source = Netmask("2001:DB8::FF/128");
599 sr->setIncomingECSFound(true);
600 sr->setIncomingECS(incomingECS);
601
602 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
603
604 if (isRootServer(ip)) {
605 BOOST_REQUIRE(!srcmask);
606
607 setLWResult(res, 0, true, false, true);
608 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
609 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
610 return 1;
611 } else if (ip == ComboAddress("192.0.2.1:53")) {
612
613 BOOST_REQUIRE(srcmask);
614 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
615
616 setLWResult(res, 0, true, false, false);
617 addRecordToLW(res, domain, QType::A, "192.0.2.2");
618 return 1;
619 }
620
621 return 0;
622 });
623
624 vector<DNSRecord> ret;
625 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
626 BOOST_CHECK_EQUAL(res, 0);
778bcea6
RG
627 BOOST_REQUIRE_EQUAL(ret.size(), 1);
628 BOOST_CHECK(ret[0].d_type == QType::A);
629 BOOST_CHECK_EQUAL(ret[0].d_name, target);
630}
631
632BOOST_AUTO_TEST_CASE(test_following_cname) {
633 std::unique_ptr<SyncRes> sr;
634 init();
635 initSR(sr, true, false);
636
637 primeHints();
638
639 const DNSName target("cname.powerdns.com.");
640 const DNSName cnameTarget("cname-target.powerdns.com");
641
642 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
643
644 if (isRootServer(ip)) {
778bcea6
RG
645 setLWResult(res, 0, true, false, true);
646 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
647 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
648 return 1;
649 } else if (ip == ComboAddress("192.0.2.1:53")) {
650
651 if (domain == target) {
652 setLWResult(res, 0, true, false, false);
653 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
654 return 1;
655 }
656 else if (domain == cnameTarget) {
657 setLWResult(res, 0, true, false, false);
658 addRecordToLW(res, domain, QType::A, "192.0.2.2");
659 }
660
661 return 1;
662 }
663
664 return 0;
665 });
666
667 vector<DNSRecord> ret;
668 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
669 BOOST_CHECK_EQUAL(res, 0);
670 BOOST_REQUIRE_EQUAL(ret.size(), 2);
671 BOOST_CHECK(ret[0].d_type == QType::CNAME);
672 BOOST_CHECK_EQUAL(ret[0].d_name, target);
673 BOOST_CHECK(ret[1].d_type == QType::A);
674 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
675}
676
4fff116b
RG
677BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
678 std::unique_ptr<SyncRes> sr;
679 init();
680 initSR(sr, true, false);
681
682 primeHints();
683
684 /* In this test we directly get the NS server for cname.powerdns.com.,
685 and we don't know whether it's also authoritative for
686 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
687 the additional A record for cname-target.powerdns.com. */
688 const DNSName target("cname.powerdns.com.");
689 const DNSName cnameTarget("cname-target.powerdns.com");
690
691 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
692
693 if (isRootServer(ip)) {
694
695 setLWResult(res, 0, true, false, true);
696
697 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
698 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
699 return 1;
700 } else if (ip == ComboAddress("192.0.2.1:53")) {
701
702 if (domain == target) {
703 setLWResult(res, 0, true, false, false);
704 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
705 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
706 return 1;
707 } else if (domain == cnameTarget) {
708 setLWResult(res, 0, true, false, false);
709 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
710 return 1;
711 }
712
713 return 1;
714 }
715
716 return 0;
717 });
718
719 vector<DNSRecord> ret;
720 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
721 BOOST_CHECK_EQUAL(res, 0);
722 BOOST_REQUIRE_EQUAL(ret.size(), 2);
723 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
724 BOOST_CHECK_EQUAL(ret[0].d_name, target);
725 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
726 BOOST_REQUIRE(ret[1].d_type == QType::A);
727 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
728 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
729}
730
778bcea6
RG
731BOOST_AUTO_TEST_CASE(test_cname_loop) {
732 std::unique_ptr<SyncRes> sr;
733 init();
734 initSR(sr, true, false);
735
736 primeHints();
737
738 size_t count = 0;
739 const DNSName target("cname.powerdns.com.");
740
741 sr->setAsyncCallback([target,&count](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
742
743 count++;
744
745 if (isRootServer(ip)) {
746 BOOST_REQUIRE(!srcmask);
747
748 setLWResult(res, 0, true, false, true);
749 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
750 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
751 return 1;
752 } else if (ip == ComboAddress("192.0.2.1:53")) {
753
754 if (domain == target) {
755 setLWResult(res, 0, true, false, false);
756 addRecordToLW(res, domain, QType::CNAME, domain.toString());
757 return 1;
758 }
759
760 return 1;
761 }
762
763 return 0;
764 });
765
766 vector<DNSRecord> ret;
767 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
768 BOOST_CHECK_EQUAL(res, 2);
769 BOOST_CHECK_EQUAL(count, 2);
e9f9b8ec
RG
770}
771
4fff116b
RG
772BOOST_AUTO_TEST_CASE(test_cname_depth) {
773 std::unique_ptr<SyncRes> sr;
774 init();
775 initSR(sr, true, false);
776
777 primeHints();
778
779 size_t depth = 0;
780 const DNSName target("cname.powerdns.com.");
781
782 sr->setAsyncCallback([target,&depth](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
783
784 if (isRootServer(ip)) {
785 BOOST_REQUIRE(!srcmask);
786
787 setLWResult(res, 0, true, false, true);
788 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
789 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
790 return 1;
791 } else if (ip == ComboAddress("192.0.2.1:53")) {
792
793 setLWResult(res, 0, true, false, false);
794 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
795 depth++;
796 return 1;
797 }
798
799 return 0;
800 });
801
802 vector<DNSRecord> ret;
803 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
804 BOOST_CHECK_EQUAL(res, 2);
805 /* we have an arbitrary limit at 10 when following a CNAME chain */
806 BOOST_CHECK_EQUAL(depth, 10 + 2);
807}
808
30ee601a
RG
809/*
810 TODO:
811
778bcea6 812// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
30ee601a
RG
813
814check RPZ (nameservers name blocked, name server IP blocked)
815check that wantsRPZ false skip the RPZ checks
816
817check that we are asking the more specific nameservers
818
819check that we correctly ignore unauth data?
820
821check out of band support
822
823check throttled
824
825check blocked
826
827check we query the fastest auth available first?
828
829check we correctly store slow servers
830
30ee601a
RG
831if possible, check preoutquery
832
4fff116b 833check depth limit (CNAME and referral)
30ee601a
RG
834
835check time limit
836
837check we correctly populate the cache from the results
838
839check we correctly populate the negcache
840
841check we honor s_minimumTTL and s_maxcachettl
842
30ee601a
RG
843check delegation only
844
845check root NX trust
846
30ee601a
RG
847nxdomain answer
848nodata answer
849*/
850
851BOOST_AUTO_TEST_SUITE_END()