]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
rec: Add CNAME unit tests for `SyncRes`
[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
140static void initSR(std::unique_ptr<SyncRes>& sr, bool edns0, bool dnssec)
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);
147 t_sstorage->domainmap = g_initialDomainMap;
148 t_sstorage->negcache.clear();
149 t_sstorage->nsSpeeds.clear();
150 t_sstorage->ednsstatus.clear();
151 t_sstorage->throttle.clear();
152 t_sstorage->fails.clear();
153 t_sstorage->dnssecmap.clear();
154}
155
156static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
157{
158 res->d_rcode = rcode;
159 res->d_aabit = aa;
160 res->d_tcbit = tc;
161 res->d_haveEDNS = edns;
162}
163
164static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
165{
166 DNSRecord rec;
167 rec.d_place = place;
168 rec.d_name = name;
169 rec.d_type = type;
170 rec.d_ttl = ttl;
171
172 if (type == QType::NS) {
173 rec.d_content = std::make_shared<NSRecordContent>(DNSName(content));
174 }
175 else if (type == QType::A) {
176 rec.d_content = std::make_shared<ARecordContent>(ComboAddress(content));
177 }
778bcea6 178 else if (type == QType::AAAA) {
30ee601a
RG
179 rec.d_content = std::make_shared<AAAARecordContent>(ComboAddress(content));
180 }
778bcea6
RG
181 else if (type == QType::CNAME) {
182 rec.d_content = std::make_shared<CNAMERecordContent>(DNSName(content));
183 }
30ee601a
RG
184 else {
185 rec.d_content = shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(type, QClass::IN, content));
186 }
187
188 res->d_records.push_back(rec);
189}
190
191static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
192{
193 addRecordToLW(res, DNSName(name), type, content, place, ttl);
194}
195
196static bool isRootServer(const ComboAddress& ip)
197{
198 for (size_t idx = 0; idx < rootIps4Count; idx++) {
199 if (ip.toString() == rootIps4[idx]) {
200 return true;
201 }
202 }
203
204 for (size_t idx = 0; idx < rootIps6Count; idx++) {
205 if (ip.toString() == rootIps6[idx]) {
206 return true;
207 }
208 }
209 return false;
210}
211
212/* Real tests */
213
214BOOST_AUTO_TEST_SUITE(syncres_cc)
215
216BOOST_AUTO_TEST_CASE(test_root_primed) {
217 std::unique_ptr<SyncRes> sr;
218 init();
219 initSR(sr, true, false);
220
221 primeHints();
222
223 /* we are primed, we should be able to resolve NS . without any query */
224 vector<DNSRecord> ret;
225 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
226 BOOST_CHECK_EQUAL(res, 0);
227 BOOST_CHECK_EQUAL(ret.size(), 13);
228}
229
230BOOST_AUTO_TEST_CASE(test_root_not_primed) {
231 std::unique_ptr<SyncRes> sr;
232 init(false);
233 initSR(sr, true, false);
234
235 size_t queriesCount = 0;
236
237 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) {
238 queriesCount++;
239
240 if (domain == g_rootdnsname && type == QType::NS) {
241 setLWResult(res, 0, true, false, true);
242 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
243 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
244 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
245
246 return 1;
247 }
248
249 return 0;
250 });
251
252 /* we are not primed yet, so SyncRes will have to call primeHints()
253 then call getRootNS(), for which at least one of the root servers needs to answer */
254 vector<DNSRecord> ret;
255 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
256 BOOST_CHECK_EQUAL(res, 0);
257 BOOST_CHECK_EQUAL(ret.size(), 1);
258 BOOST_CHECK_EQUAL(queriesCount, 2);
259}
260
261BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
262 std::unique_ptr<SyncRes> sr;
263 init();
264 initSR(sr, true, false);
265 std::set<ComboAddress> downServers;
266
267 /* we are not primed yet, so SyncRes will have to call primeHints()
268 then call getRootNS(), for which at least one of the root servers needs to answer.
269 None will, so it should ServFail.
270 */
271 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) {
272
273 downServers.insert(ip);
274 return 0;
275 });
276
277 vector<DNSRecord> ret;
278 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
279 BOOST_CHECK_EQUAL(res, 2);
280 BOOST_CHECK_EQUAL(ret.size(), 0);
281 BOOST_CHECK(downServers.size() > 0);
282 /* we explicitly refuse to mark the root servers down */
283 for (const auto& server : downServers) {
284 BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 0);
285 }
286}
287
288BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
289 std::unique_ptr<SyncRes> sr;
290 init();
291 initSR(sr, true, false);
292
293 ComboAddress noEDNSServer;
294 size_t queriesWithEDNS = 0;
295 size_t queriesWithoutEDNS = 0;
296
297 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) {
298 if (EDNS0Level != 0) {
299 queriesWithEDNS++;
300 noEDNSServer = ip;
301
302 setLWResult(res, RCode::FormErr);
303 return 1;
304 }
305
306 queriesWithoutEDNS++;
307
308 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
309 setLWResult(res, 0, true, false, false);
310 addRecordToLW(res, domain, QType::A, "192.0.2.1");
311 return 1;
312 }
313
314 return 0;
315 });
316
317 primeHints();
318
319 /* fake that the root NS doesn't handle EDNS, check that we fallback */
320 vector<DNSRecord> ret;
321 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
322 BOOST_CHECK_EQUAL(res, 0);
323 BOOST_CHECK_EQUAL(ret.size(), 1);
324 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
325 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
326 BOOST_CHECK_EQUAL(t_sstorage->ednsstatus.size(), 1);
327 BOOST_CHECK_EQUAL(t_sstorage->ednsstatus[noEDNSServer].mode, SyncRes::EDNSStatus::NOEDNS);
328}
329
330BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
331 std::unique_ptr<SyncRes> sr;
332 init();
333 initSR(sr, true, false);
334
335 size_t queriesWithEDNS = 0;
336 size_t queriesWithoutEDNS = 0;
337
338 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) {
339 if (EDNS0Level != 0) {
340 queriesWithEDNS++;
341 setLWResult(res, RCode::NotImp);
342 return 1;
343 }
344
345 queriesWithoutEDNS++;
346
347 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
348 setLWResult(res, 0, true, false, false);
349 addRecordToLW(res, domain, QType::A, "192.0.2.1");
350 return 1;
351 }
352
353 return 0;
354 });
355
356 primeHints();
357
358 /* fake that the NS doesn't handle EDNS, check that we fallback */
359 vector<DNSRecord> ret;
360 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
361 BOOST_CHECK_EQUAL(res, 0);
362 BOOST_CHECK_EQUAL(ret.size(), 1);
363 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
364 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
365}
366
367BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
368 std::unique_ptr<SyncRes> sr;
369 init();
370 initSR(sr, true, false);
371
372 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) {
373 if (!doTCP) {
374 setLWResult(res, 0, false, true, false);
375 return 1;
376 }
377 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
378 setLWResult(res, 0, true, false, false);
379 addRecordToLW(res, domain, QType::A, "192.0.2.1");
380 return 1;
381 }
382
383 return 0;
384 });
385
386 primeHints();
387
388 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
389 vector<DNSRecord> ret;
390 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
391 BOOST_CHECK_EQUAL(res, 0);
392}
393
394BOOST_AUTO_TEST_CASE(test_all_nss_down) {
395 std::unique_ptr<SyncRes> sr;
396 init();
397 initSR(sr, true, false);
398 std::set<ComboAddress> downServers;
399
400 primeHints();
401
402 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) {
403
404 if (isRootServer(ip)) {
405 setLWResult(res, 0, true, false, true);
406 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
407 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
408 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
409 return 1;
410 }
411 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
412 setLWResult(res, 0, true, false, true);
413 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
414 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
415 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
416 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
417 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
418 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
419 return 1;
420 }
421 else {
422 downServers.insert(ip);
423 return 0;
424 }
425 });
426
427 vector<DNSRecord> ret;
428 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
429 BOOST_CHECK_EQUAL(res, 2);
430 BOOST_CHECK_EQUAL(ret.size(), 0);
431 BOOST_CHECK_EQUAL(downServers.size(), 4);
432
433 for (const auto& server : downServers) {
434 BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 1);
435 }
436}
437
438BOOST_AUTO_TEST_CASE(test_glued_referral) {
439 std::unique_ptr<SyncRes> sr;
440 init();
441 initSR(sr, true, false);
442
443 primeHints();
444
445 const DNSName target("powerdns.com.");
446
447 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) {
448 /* this will cause issue with qname minimization if we ever implement it */
449 if (domain != target) {
450 return 0;
451 }
452
453 if (isRootServer(ip)) {
454 setLWResult(res, 0, true, false, true);
455 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
456 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
457 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
458 return 1;
459 }
460 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
461 setLWResult(res, 0, true, false, true);
462 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
463 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
464 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
465 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
466 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
467 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
468 return 1;
469 }
470 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")) {
471 setLWResult(res, 0, true, false, true);
472 addRecordToLW(res, target, QType::A, "192.0.2.4");
473 return 1;
474 }
475 else {
476 return 0;
477 }
478 });
479
480 vector<DNSRecord> ret;
481 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
482 BOOST_CHECK_EQUAL(res, 0);
483 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 484 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
485 BOOST_CHECK_EQUAL(ret[0].d_name, target);
486}
487
488BOOST_AUTO_TEST_CASE(test_glueless_referral) {
489 std::unique_ptr<SyncRes> sr;
490 init();
491 initSR(sr, true, false);
492
493 primeHints();
494
495 const DNSName target("powerdns.com.");
496
497 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) {
498
499 if (isRootServer(ip)) {
500 setLWResult(res, 0, true, false, true);
501
502 if (domain.isPartOf(DNSName("com."))) {
503 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
504 } else if (domain.isPartOf(DNSName("org."))) {
505 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
506 }
507 else {
508 setLWResult(res, RCode::NXDomain, false, false, true);
509 return 1;
510 }
511
512 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
513 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
514 return 1;
515 }
516 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
517 if (domain == target) {
518 setLWResult(res, 0, true, false, true);
519 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
520 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
521 return 1;
522 }
523 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
524 setLWResult(res, 0, true, false, true);
525 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
526 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
527 return 1;
528 }
529 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
530 setLWResult(res, 0, true, false, true);
531 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
532 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
533 return 1;
534 }
535
536 setLWResult(res, RCode::NXDomain, false, false, true);
537 return 1;
538 }
539 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")) {
540 setLWResult(res, 0, true, false, true);
541 addRecordToLW(res, target, QType::A, "192.0.2.4");
542 return 1;
543 }
544 else {
545 return 0;
546 }
547 });
548
549 vector<DNSRecord> ret;
550 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
551 BOOST_CHECK_EQUAL(res, 0);
552 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 553 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
554 BOOST_CHECK_EQUAL(ret[0].d_name, target);
555}
556
e9f9b8ec
RG
557BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
558 std::unique_ptr<SyncRes> sr;
559 init();
560 initSR(sr, true, false);
561
562 primeHints();
563
564 const DNSName target("powerdns.com.");
565 g_useIncomingECS = true;
566 g_ednsdomains.add(target);
567
568 EDNSSubnetOpts incomingECS;
569 incomingECS.source = Netmask("192.0.2.128/32");
570 sr->setIncomingECSFound(true);
571 sr->setIncomingECS(incomingECS);
572
573 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) {
574
575 BOOST_REQUIRE(srcmask);
576 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
577 return 0;
578 });
579
580 vector<DNSRecord> ret;
581 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
582 BOOST_CHECK_EQUAL(res, 2);
583}
584
585BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
586 std::unique_ptr<SyncRes> sr;
587 init();
588 initSR(sr, true, false);
589
590 primeHints();
591
592 const DNSName target("powerdns.com.");
593 g_useIncomingECS = true;
594 g_ednssubnets.addMask("192.0.2.1/32");
595
596 EDNSSubnetOpts incomingECS;
597 incomingECS.source = Netmask("2001:DB8::FF/128");
598 sr->setIncomingECSFound(true);
599 sr->setIncomingECS(incomingECS);
600
601 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) {
602
603 if (isRootServer(ip)) {
604 BOOST_REQUIRE(!srcmask);
605
606 setLWResult(res, 0, true, false, true);
607 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
608 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
609 return 1;
610 } else if (ip == ComboAddress("192.0.2.1:53")) {
611
612 BOOST_REQUIRE(srcmask);
613 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
614
615 setLWResult(res, 0, true, false, false);
616 addRecordToLW(res, domain, QType::A, "192.0.2.2");
617 return 1;
618 }
619
620 return 0;
621 });
622
623 vector<DNSRecord> ret;
624 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
625 BOOST_CHECK_EQUAL(res, 0);
778bcea6
RG
626 BOOST_REQUIRE_EQUAL(ret.size(), 1);
627 BOOST_CHECK(ret[0].d_type == QType::A);
628 BOOST_CHECK_EQUAL(ret[0].d_name, target);
629}
630
631BOOST_AUTO_TEST_CASE(test_following_cname) {
632 std::unique_ptr<SyncRes> sr;
633 init();
634 initSR(sr, true, false);
635
636 primeHints();
637
638 const DNSName target("cname.powerdns.com.");
639 const DNSName cnameTarget("cname-target.powerdns.com");
640
641 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) {
642
643 if (isRootServer(ip)) {
644 BOOST_REQUIRE(!srcmask);
645
646 setLWResult(res, 0, true, false, true);
647 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
648 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
649 return 1;
650 } else if (ip == ComboAddress("192.0.2.1:53")) {
651
652 if (domain == target) {
653 setLWResult(res, 0, true, false, false);
654 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
655 return 1;
656 }
657 else if (domain == cnameTarget) {
658 setLWResult(res, 0, true, false, false);
659 addRecordToLW(res, domain, QType::A, "192.0.2.2");
660 }
661
662 return 1;
663 }
664
665 return 0;
666 });
667
668 vector<DNSRecord> ret;
669 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
670 BOOST_CHECK_EQUAL(res, 0);
671 BOOST_REQUIRE_EQUAL(ret.size(), 2);
672 BOOST_CHECK(ret[0].d_type == QType::CNAME);
673 BOOST_CHECK_EQUAL(ret[0].d_name, target);
674 BOOST_CHECK(ret[1].d_type == QType::A);
675 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
676}
677
678BOOST_AUTO_TEST_CASE(test_cname_loop) {
679 std::unique_ptr<SyncRes> sr;
680 init();
681 initSR(sr, true, false);
682
683 primeHints();
684
685 size_t count = 0;
686 const DNSName target("cname.powerdns.com.");
687
688 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) {
689
690 count++;
691
692 if (isRootServer(ip)) {
693 BOOST_REQUIRE(!srcmask);
694
695 setLWResult(res, 0, true, false, true);
696 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
697 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
698 return 1;
699 } else if (ip == ComboAddress("192.0.2.1:53")) {
700
701 if (domain == target) {
702 setLWResult(res, 0, true, false, false);
703 addRecordToLW(res, domain, QType::CNAME, domain.toString());
704 return 1;
705 }
706
707 return 1;
708 }
709
710 return 0;
711 });
712
713 vector<DNSRecord> ret;
714 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
715 BOOST_CHECK_EQUAL(res, 2);
716 BOOST_CHECK_EQUAL(count, 2);
e9f9b8ec
RG
717}
718
30ee601a
RG
719/*
720 TODO:
721
778bcea6 722// 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
723
724check RPZ (nameservers name blocked, name server IP blocked)
725check that wantsRPZ false skip the RPZ checks
726
727check that we are asking the more specific nameservers
728
729check that we correctly ignore unauth data?
730
731check out of band support
732
733check throttled
734
735check blocked
736
737check we query the fastest auth available first?
738
739check we correctly store slow servers
740
30ee601a
RG
741if possible, check preoutquery
742
743check depth limit
744
745check time limit
746
747check we correctly populate the cache from the results
748
749check we correctly populate the negcache
750
751check we honor s_minimumTTL and s_maxcachettl
752
30ee601a
RG
753check we follow referral
754
755check delegation only
756
757check root NX trust
758
759check direct answer (done I think?)
760
30ee601a
RG
761nxdomain answer
762nodata answer
763*/
764
765BOOST_AUTO_TEST_SUITE_END()