]>
Commit | Line | Data |
---|---|---|
86675669 OM |
1 | #define BOOST_TEST_DYN_LINK |
2 | #include <boost/test/unit_test.hpp> | |
3 | ||
4 | #include "test-syncres_cc.hh" | |
5 | ||
6 | BOOST_AUTO_TEST_SUITE(syncres_cc2) | |
7 | ||
050e6877 | 8 | static void do_test_referral_depth(bool limited) |
42dcf516 | 9 | { |
86675669 OM |
10 | std::unique_ptr<SyncRes> sr; |
11 | initSR(sr); | |
12 | ||
13 | primeHints(); | |
14 | ||
15 | size_t queries = 0; | |
16 | const DNSName target("www.powerdns.com."); | |
17 | ||
42dcf516 OM |
18 | sr->setAsyncCallback([target, &queries](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, LWResult* res, bool* chained) { |
19 | queries++; | |
86675669 | 20 | |
42dcf516 OM |
21 | if (isRootServer(ip)) { |
22 | setLWResult(res, 0, false, false, true); | |
86675669 | 23 | |
42dcf516 OM |
24 | if (domain == DNSName("www.powerdns.com.")) { |
25 | addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
26 | } | |
27 | else if (domain == DNSName("ns.powerdns.com.")) { | |
28 | addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); | |
29 | } | |
30 | else if (domain == DNSName("ns1.powerdns.org.")) { | |
31 | addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); | |
32 | } | |
33 | else if (domain == DNSName("ns2.powerdns.org.")) { | |
34 | addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); | |
35 | } | |
36 | else if (domain == DNSName("ns3.powerdns.org.")) { | |
37 | addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800); | |
ca34b34f | 38 | addRecordToLW(res, "ns4.powerdns.org.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); |
42dcf516 | 39 | } |
86675669 | 40 | |
42dcf516 OM |
41 | return 1; |
42 | } | |
43 | else if (ip == ComboAddress("192.0.2.1:53")) { | |
42dcf516 | 44 | setLWResult(res, 0, true, false, false); |
ca34b34f OM |
45 | if (domain == DNSName("www.powerdns.com.")) { |
46 | addRecordToLW(res, domain, QType::A, "192.0.2.2"); | |
47 | } | |
48 | else { | |
49 | addRecordToLW(res, domain, QType::A, "192.0.2.1"); | |
50 | } | |
42dcf516 OM |
51 | return 1; |
52 | } | |
86675669 | 53 | |
42dcf516 OM |
54 | return 0; |
55 | }); | |
86675669 | 56 | |
46817cd2 OM |
57 | if (limited) { |
58 | /* Set the maximum depth low */ | |
59 | SyncRes::s_maxdepth = 10; | |
60 | try { | |
61 | vector<DNSRecord> ret; | |
62 | sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
63 | BOOST_CHECK(false); | |
64 | } | |
65 | catch (const ImmediateServFailException& e) { | |
66 | BOOST_CHECK(e.reason.find("max-recursion-depth") != string::npos); | |
67 | } | |
86675669 | 68 | } |
46817cd2 OM |
69 | else { |
70 | // Check if the setup with high limit is OK. | |
71 | SyncRes::s_maxdepth = 50; | |
72 | try { | |
73 | vector<DNSRecord> ret; | |
74 | int rcode = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
75 | BOOST_CHECK_EQUAL(rcode, RCode::NoError); | |
76 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); | |
77 | BOOST_CHECK_EQUAL(ret[0].d_name, target); | |
78 | BOOST_REQUIRE(ret[0].d_type == QType::A); | |
79 | BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2")); | |
80 | } | |
81 | catch (const ImmediateServFailException& e) { | |
82 | BOOST_CHECK(false); | |
83 | } | |
ca34b34f | 84 | } |
46817cd2 | 85 | } |
ca34b34f | 86 | |
46817cd2 OM |
87 | BOOST_AUTO_TEST_CASE(test_referral_depth) |
88 | { | |
89 | // Test with limit | |
90 | do_test_referral_depth(true); | |
91 | } | |
92 | ||
93 | BOOST_AUTO_TEST_CASE(test_referral_depth_ok) | |
94 | { | |
95 | // Test with default limit | |
96 | do_test_referral_depth(false); | |
86675669 OM |
97 | } |
98 | ||
42dcf516 OM |
99 | BOOST_AUTO_TEST_CASE(test_cname_qperq) |
100 | { | |
86675669 OM |
101 | std::unique_ptr<SyncRes> sr; |
102 | initSR(sr); | |
103 | ||
104 | primeHints(); | |
105 | ||
106 | size_t queries = 0; | |
107 | const DNSName target("cname.powerdns.com."); | |
108 | ||
42dcf516 OM |
109 | sr->setAsyncCallback([target, &queries](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, LWResult* res, bool* chained) { |
110 | queries++; | |
86675669 | 111 | |
42dcf516 | 112 | if (isRootServer(ip)) { |
86675669 | 113 | |
42dcf516 OM |
114 | setLWResult(res, 0, false, false, true); |
115 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
116 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); | |
117 | return 1; | |
118 | } | |
119 | else if (ip == ComboAddress("192.0.2.1:53")) { | |
86675669 | 120 | |
42dcf516 OM |
121 | setLWResult(res, 0, true, false, false); |
122 | addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com"); | |
123 | return 1; | |
124 | } | |
86675669 | 125 | |
42dcf516 OM |
126 | return 0; |
127 | }); | |
86675669 OM |
128 | |
129 | /* Set the maximum number of questions very low */ | |
130 | SyncRes::s_maxqperq = 5; | |
131 | ||
132 | try { | |
133 | vector<DNSRecord> ret; | |
134 | sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
135 | BOOST_CHECK(false); | |
136 | } | |
42dcf516 | 137 | catch (const ImmediateServFailException& e) { |
86675669 OM |
138 | BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq); |
139 | } | |
140 | } | |
141 | ||
42dcf516 OM |
142 | BOOST_AUTO_TEST_CASE(test_throttled_server) |
143 | { | |
86675669 OM |
144 | std::unique_ptr<SyncRes> sr; |
145 | initSR(sr); | |
146 | ||
147 | primeHints(); | |
148 | ||
149 | const DNSName target("throttled.powerdns.com."); | |
150 | const ComboAddress ns("192.0.2.1:53"); | |
151 | size_t queriesToNS = 0; | |
152 | ||
42dcf516 OM |
153 | sr->setAsyncCallback([target, ns, &queriesToNS](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, LWResult* res, bool* chained) { |
154 | if (isRootServer(ip)) { | |
86675669 | 155 | |
42dcf516 OM |
156 | setLWResult(res, 0, false, false, true); |
157 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
158 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
159 | return 1; | |
160 | } | |
161 | else if (ip == ns) { | |
86675669 | 162 | |
42dcf516 | 163 | queriesToNS++; |
86675669 | 164 | |
42dcf516 OM |
165 | setLWResult(res, 0, true, false, false); |
166 | addRecordToLW(res, domain, QType::A, "192.0.2.2"); | |
86675669 | 167 | |
42dcf516 OM |
168 | return 1; |
169 | } | |
86675669 | 170 | |
42dcf516 OM |
171 | return 0; |
172 | }); | |
86675669 OM |
173 | |
174 | /* mark ns as down */ | |
175 | time_t now = sr->getNow().tv_sec; | |
176 | SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000); | |
177 | ||
178 | vector<DNSRecord> ret; | |
179 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
180 | BOOST_CHECK_EQUAL(res, RCode::ServFail); | |
690b86b7 | 181 | BOOST_CHECK_EQUAL(ret.size(), 0U); |
86675669 | 182 | /* we should not have sent any queries to ns */ |
690b86b7 | 183 | BOOST_CHECK_EQUAL(queriesToNS, 0U); |
86675669 OM |
184 | } |
185 | ||
42dcf516 OM |
186 | BOOST_AUTO_TEST_CASE(test_throttled_server_count) |
187 | { | |
86675669 OM |
188 | std::unique_ptr<SyncRes> sr; |
189 | initSR(sr); | |
190 | ||
191 | primeHints(); | |
192 | ||
193 | const ComboAddress ns("192.0.2.1:53"); | |
194 | ||
195 | const size_t blocks = 10; | |
196 | /* mark ns as down for 'blocks' queries */ | |
197 | time_t now = sr->getNow().tv_sec; | |
198 | SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks); | |
199 | ||
200 | for (size_t idx = 0; idx < blocks; idx++) { | |
201 | BOOST_CHECK(SyncRes::isThrottled(now, ns)); | |
202 | } | |
203 | ||
204 | /* we have been throttled 'blocks' times, we should not be throttled anymore */ | |
205 | BOOST_CHECK(!SyncRes::isThrottled(now, ns)); | |
206 | } | |
207 | ||
42dcf516 OM |
208 | BOOST_AUTO_TEST_CASE(test_throttled_server_time) |
209 | { | |
86675669 OM |
210 | std::unique_ptr<SyncRes> sr; |
211 | initSR(sr); | |
212 | ||
213 | primeHints(); | |
214 | ||
215 | const ComboAddress ns("192.0.2.1:53"); | |
216 | ||
217 | const size_t seconds = 1; | |
218 | /* mark ns as down for 'seconds' seconds */ | |
219 | time_t now = sr->getNow().tv_sec; | |
220 | SyncRes::doThrottle(now, ns, seconds, 10000); | |
221 | ||
222 | BOOST_CHECK(SyncRes::isThrottled(now, ns)); | |
223 | ||
224 | /* we should not be throttled anymore */ | |
225 | BOOST_CHECK(!SyncRes::isThrottled(now + 2, ns)); | |
226 | } | |
227 | ||
42dcf516 OM |
228 | BOOST_AUTO_TEST_CASE(test_dont_query_server) |
229 | { | |
86675669 OM |
230 | std::unique_ptr<SyncRes> sr; |
231 | initSR(sr); | |
232 | ||
233 | primeHints(); | |
234 | ||
235 | const DNSName target("throttled.powerdns.com."); | |
236 | const ComboAddress ns("192.0.2.1:53"); | |
237 | size_t queriesToNS = 0; | |
238 | ||
42dcf516 OM |
239 | sr->setAsyncCallback([target, ns, &queriesToNS](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, LWResult* res, bool* chained) { |
240 | if (isRootServer(ip)) { | |
86675669 | 241 | |
42dcf516 OM |
242 | setLWResult(res, 0, false, false, true); |
243 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
244 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
245 | return 1; | |
246 | } | |
247 | else if (ip == ns) { | |
86675669 | 248 | |
42dcf516 | 249 | queriesToNS++; |
86675669 | 250 | |
42dcf516 OM |
251 | setLWResult(res, 0, true, false, false); |
252 | addRecordToLW(res, domain, QType::A, "192.0.2.2"); | |
86675669 | 253 | |
42dcf516 OM |
254 | return 1; |
255 | } | |
86675669 | 256 | |
42dcf516 OM |
257 | return 0; |
258 | }); | |
86675669 OM |
259 | |
260 | /* prevent querying this NS */ | |
261 | SyncRes::addDontQuery(Netmask(ns)); | |
262 | ||
263 | vector<DNSRecord> ret; | |
264 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
265 | BOOST_CHECK_EQUAL(res, RCode::ServFail); | |
690b86b7 | 266 | BOOST_CHECK_EQUAL(ret.size(), 0U); |
86675669 | 267 | /* we should not have sent any queries to ns */ |
690b86b7 | 268 | BOOST_CHECK_EQUAL(queriesToNS, 0U); |
86675669 OM |
269 | } |
270 | ||
42dcf516 OM |
271 | BOOST_AUTO_TEST_CASE(test_root_nx_trust) |
272 | { | |
86675669 OM |
273 | std::unique_ptr<SyncRes> sr; |
274 | initSR(sr); | |
275 | ||
276 | primeHints(); | |
277 | ||
278 | const DNSName target1("powerdns.com."); | |
279 | const DNSName target2("notpowerdns.com."); | |
280 | const ComboAddress ns("192.0.2.1:53"); | |
281 | size_t queriesCount = 0; | |
282 | ||
283 | sr->setAsyncCallback([target1, target2, ns, &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, LWResult* res, bool* chained) { | |
42dcf516 | 284 | queriesCount++; |
86675669 | 285 | |
42dcf516 | 286 | if (isRootServer(ip)) { |
86675669 | 287 | |
42dcf516 OM |
288 | if (domain == target1) { |
289 | setLWResult(res, RCode::NXDomain, true, false, true); | |
290 | addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); | |
291 | } | |
292 | else { | |
293 | setLWResult(res, 0, true, false, true); | |
294 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
295 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
296 | } | |
86675669 | 297 | |
42dcf516 OM |
298 | return 1; |
299 | } | |
300 | else if (ip == ns) { | |
86675669 | 301 | |
42dcf516 OM |
302 | setLWResult(res, 0, true, false, false); |
303 | addRecordToLW(res, domain, QType::A, "192.0.2.2"); | |
86675669 | 304 | |
42dcf516 OM |
305 | return 1; |
306 | } | |
86675669 | 307 | |
42dcf516 OM |
308 | return 0; |
309 | }); | |
86675669 OM |
310 | |
311 | SyncRes::s_maxnegttl = 3600; | |
312 | ||
313 | vector<DNSRecord> ret; | |
314 | int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
315 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
690b86b7 | 316 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 | 317 | /* one for target1 and one for the entire TLD */ |
690b86b7 | 318 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); |
86675669 OM |
319 | |
320 | ret.clear(); | |
321 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
322 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
690b86b7 | 323 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
324 | BOOST_CHECK_LE(ret[0].d_ttl, SyncRes::s_maxnegttl); |
325 | /* one for target1 and one for the entire TLD */ | |
690b86b7 | 326 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); |
86675669 OM |
327 | |
328 | /* we should have sent only one query */ | |
690b86b7 | 329 | BOOST_CHECK_EQUAL(queriesCount, 1U); |
86675669 OM |
330 | } |
331 | ||
42dcf516 OM |
332 | BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) |
333 | { | |
86675669 OM |
334 | std::unique_ptr<SyncRes> sr; |
335 | initSR(); | |
336 | initSR(sr, true, false); | |
337 | ||
338 | primeHints(); | |
339 | ||
340 | const DNSName target1("powerdns.com."); | |
341 | const DNSName target2("notpowerdns.com."); | |
342 | const ComboAddress ns("192.0.2.1:53"); | |
343 | size_t queriesCount = 0; | |
344 | ||
345 | /* This time the root denies target1 with a "com." SOA instead of a "." one. | |
346 | We should add target1 to the negcache, but not "com.". */ | |
347 | ||
348 | sr->setAsyncCallback([target1, target2, ns, &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, LWResult* res, bool* chained) { | |
42dcf516 | 349 | queriesCount++; |
86675669 | 350 | |
42dcf516 | 351 | if (isRootServer(ip)) { |
86675669 | 352 | |
42dcf516 OM |
353 | if (domain == target1) { |
354 | setLWResult(res, RCode::NXDomain, true, false, true); | |
355 | addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); | |
356 | } | |
357 | else { | |
358 | setLWResult(res, 0, true, false, true); | |
359 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
360 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
361 | } | |
86675669 | 362 | |
42dcf516 OM |
363 | return 1; |
364 | } | |
365 | else if (ip == ns) { | |
86675669 | 366 | |
42dcf516 OM |
367 | setLWResult(res, 0, true, false, false); |
368 | addRecordToLW(res, domain, QType::A, "192.0.2.2"); | |
86675669 | 369 | |
42dcf516 OM |
370 | return 1; |
371 | } | |
86675669 | 372 | |
42dcf516 OM |
373 | return 0; |
374 | }); | |
86675669 OM |
375 | |
376 | vector<DNSRecord> ret; | |
377 | int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
378 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
690b86b7 | 379 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 OM |
380 | |
381 | /* even with root-nx-trust on and a NX answer from the root, | |
382 | we should not have cached the entire TLD this time. */ | |
690b86b7 | 383 | BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U); |
86675669 OM |
384 | |
385 | ret.clear(); | |
386 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
387 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 388 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
389 | BOOST_CHECK_EQUAL(ret[0].d_name, target2); |
390 | BOOST_REQUIRE(ret[0].d_type == QType::A); | |
391 | BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2")); | |
392 | ||
690b86b7 | 393 | BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U); |
86675669 | 394 | |
690b86b7 | 395 | BOOST_CHECK_EQUAL(queriesCount, 3U); |
86675669 OM |
396 | } |
397 | ||
42dcf516 OM |
398 | BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) |
399 | { | |
86675669 OM |
400 | std::unique_ptr<SyncRes> sr; |
401 | initSR(sr); | |
402 | ||
403 | primeHints(); | |
404 | ||
405 | const DNSName target1("powerdns.com."); | |
406 | const DNSName target2("notpowerdns.com."); | |
407 | const ComboAddress ns("192.0.2.1:53"); | |
408 | size_t queriesCount = 0; | |
409 | ||
410 | sr->setAsyncCallback([target1, target2, ns, &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, LWResult* res, bool* chained) { | |
42dcf516 | 411 | queriesCount++; |
86675669 | 412 | |
42dcf516 | 413 | if (isRootServer(ip)) { |
86675669 | 414 | |
42dcf516 OM |
415 | if (domain == target1) { |
416 | setLWResult(res, RCode::NXDomain, true, false, true); | |
417 | addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); | |
418 | } | |
419 | else { | |
420 | setLWResult(res, 0, true, false, true); | |
421 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
422 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
423 | } | |
86675669 | 424 | |
42dcf516 OM |
425 | return 1; |
426 | } | |
427 | else if (ip == ns) { | |
86675669 | 428 | |
42dcf516 OM |
429 | setLWResult(res, 0, true, false, false); |
430 | addRecordToLW(res, domain, QType::A, "192.0.2.2"); | |
86675669 | 431 | |
42dcf516 OM |
432 | return 1; |
433 | } | |
86675669 | 434 | |
42dcf516 OM |
435 | return 0; |
436 | }); | |
86675669 OM |
437 | |
438 | SyncRes::s_rootNXTrust = false; | |
439 | ||
440 | vector<DNSRecord> ret; | |
441 | int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
442 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
690b86b7 | 443 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 | 444 | /* one for target1 */ |
690b86b7 | 445 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); |
86675669 OM |
446 | |
447 | ret.clear(); | |
448 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
449 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 450 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 | 451 | /* one for target1 */ |
690b86b7 | 452 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); |
86675669 OM |
453 | |
454 | /* we should have sent three queries */ | |
690b86b7 | 455 | BOOST_CHECK_EQUAL(queriesCount, 3U); |
86675669 OM |
456 | } |
457 | ||
42dcf516 OM |
458 | BOOST_AUTO_TEST_CASE(test_rfc8020_nothing_underneath) |
459 | { | |
157647ec PL |
460 | std::unique_ptr<SyncRes> sr; |
461 | initSR(sr); | |
d40a915b | 462 | SyncRes::s_hardenNXD = SyncRes::HardenNXD::Yes; |
157647ec PL |
463 | |
464 | primeHints(); | |
465 | ||
466 | const DNSName target1("www.powerdns.com."); // will be denied | |
467 | const DNSName target2("foo.www.powerdns.com."); | |
468 | const DNSName target3("bar.www.powerdns.com."); | |
469 | const DNSName target4("quux.bar.www.powerdns.com."); | |
470 | const ComboAddress ns("192.0.2.1:53"); | |
471 | size_t queriesCount = 0; | |
472 | ||
473 | sr->setAsyncCallback([ns, &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, LWResult* res, bool* chained) { | |
42dcf516 | 474 | queriesCount++; |
157647ec | 475 | |
42dcf516 OM |
476 | if (isRootServer(ip)) { |
477 | setLWResult(res, 0, false, false, true); | |
478 | addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
479 | addRecordToLW(res, "ns1.powerdns.com.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
480 | return 1; | |
481 | } | |
482 | else if (ip == ns) { | |
483 | setLWResult(res, RCode::NXDomain, true, false, false); | |
484 | addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); | |
485 | return 1; | |
486 | } | |
487 | return 0; | |
488 | }); | |
157647ec PL |
489 | |
490 | vector<DNSRecord> ret; | |
491 | int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
492 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
493 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
494 | BOOST_CHECK_EQUAL(queriesCount, 2U); | |
495 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
496 | |
497 | ret.clear(); | |
498 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
499 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
500 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
501 | BOOST_CHECK_EQUAL(queriesCount, 2U); | |
502 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
503 | |
504 | ret.clear(); | |
505 | res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret); | |
506 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
507 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
508 | BOOST_CHECK_EQUAL(queriesCount, 2U); | |
509 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
510 | |
511 | ret.clear(); | |
512 | res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret); | |
513 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
514 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
515 | BOOST_CHECK_EQUAL(queriesCount, 2U); | |
516 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
517 | |
518 | // Now test without RFC 8020 to see the cache and query count grow | |
d40a915b | 519 | SyncRes::s_hardenNXD = SyncRes::HardenNXD::No; |
157647ec PL |
520 | |
521 | // Already cached | |
522 | ret.clear(); | |
523 | res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
524 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
525 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
526 | BOOST_CHECK_EQUAL(queriesCount, 2U); | |
527 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
528 | |
529 | // New query | |
530 | ret.clear(); | |
531 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
532 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
533 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
534 | BOOST_CHECK_EQUAL(queriesCount, 3U); | |
535 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); | |
157647ec PL |
536 | |
537 | ret.clear(); | |
538 | res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret); | |
539 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
540 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
541 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
542 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 3U); | |
157647ec PL |
543 | |
544 | ret.clear(); | |
545 | res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret); | |
546 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
547 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
548 | BOOST_CHECK_EQUAL(queriesCount, 5U); | |
549 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 4U); | |
157647ec PL |
550 | |
551 | // reset | |
d40a915b | 552 | SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC; |
157647ec | 553 | } |
42dcf516 OM |
554 | |
555 | BOOST_AUTO_TEST_CASE(test_rfc8020_nothing_underneath_dnssec) | |
556 | { | |
be4f1994 OM |
557 | std::unique_ptr<SyncRes> sr; |
558 | initSR(sr, true); | |
559 | setDNSSECValidation(sr, DNSSECMode::ValidateAll); | |
560 | ||
561 | primeHints(); | |
562 | ||
563 | const DNSName parent1("com."); | |
564 | const DNSName parent2("powerdns.com."); | |
565 | const DNSName target1("www.powerdns.com."); // will be denied | |
566 | const DNSName target2("foo.www.powerdns.com."); | |
567 | const DNSName target3("bar.www.powerdns.com."); | |
568 | const DNSName target4("quux.bar.www.powerdns.com."); | |
569 | const ComboAddress ns("192.0.2.1:53"); | |
570 | ||
571 | testkeysset_t keys; | |
572 | ||
573 | auto luaconfsCopy = g_luaconfs.getCopy(); | |
574 | luaconfsCopy.dsAnchors.clear(); | |
575 | generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); | |
576 | generateKeyMaterial(parent1, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); | |
577 | generateKeyMaterial(parent2, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); | |
578 | g_luaconfs.setState(luaconfsCopy); | |
579 | ||
580 | size_t queriesCount = 0; | |
581 | ||
42dcf516 | 582 | sr->setAsyncCallback([target1, target2, target3, target4, &queriesCount, keys](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, LWResult* res, bool* chained) { |
be4f1994 OM |
583 | queriesCount++; |
584 | ||
585 | DNSName auth = domain; | |
586 | if (domain == target1 || domain == target2 || domain == target3 || domain == target4) { | |
587 | auth = DNSName("powerdns.com."); | |
588 | } | |
589 | if (type == QType::DS || type == QType::DNSKEY) { | |
590 | if (type == QType::DS && (domain == target1 || domain == target2 || domain == target3 || domain == target4)) { | |
591 | setLWResult(res, RCode::NXDomain, true, false, true); | |
592 | addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); | |
593 | addRRSIG(keys, res->d_records, auth, 300); | |
42dcf516 | 594 | addNSECRecordToLW(DNSName("wwa.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records); |
be4f1994 OM |
595 | addRRSIG(keys, res->d_records, auth, 300); |
596 | return 1; | |
597 | } | |
598 | else { | |
599 | return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); | |
600 | } | |
601 | } | |
602 | else { | |
603 | if (isRootServer(ip)) { | |
604 | setLWResult(res, 0, false, false, true); | |
605 | addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); | |
606 | addDS(DNSName("com."), 300, res->d_records, keys); | |
607 | addRRSIG(keys, res->d_records, DNSName("."), 300); | |
608 | addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); | |
609 | return 1; | |
610 | } | |
611 | else if (ip == ComboAddress("192.0.2.1:53")) { | |
612 | if (domain == DNSName("com.")) { | |
613 | setLWResult(res, 0, true, false, true); | |
614 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); | |
615 | addRRSIG(keys, res->d_records, domain, 300); | |
616 | addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); | |
617 | addRRSIG(keys, res->d_records, domain, 300); | |
618 | } | |
619 | else { | |
620 | setLWResult(res, 0, false, false, true); | |
621 | addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); | |
622 | addDS(auth, 300, res->d_records, keys); | |
623 | addRRSIG(keys, res->d_records, DNSName("com."), 300); | |
624 | addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); | |
625 | } | |
626 | return 1; | |
627 | } | |
628 | else if (ip == ComboAddress("192.0.2.2:53")) { | |
629 | if (type == QType::NS) { | |
630 | setLWResult(res, 0, true, false, true); | |
631 | if (domain == DNSName("powerdns.com.")) { | |
632 | addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); | |
633 | addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); | |
634 | addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); | |
635 | addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); | |
636 | } | |
be4f1994 OM |
637 | } |
638 | else { | |
639 | setLWResult(res, RCode::NXDomain, true, false, true); | |
640 | addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); | |
641 | addRRSIG(keys, res->d_records, auth, 300); | |
42dcf516 | 642 | addNSECRecordToLW(DNSName("wwa.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records); |
be4f1994 OM |
643 | addRRSIG(keys, res->d_records, auth, 300); |
644 | /* add wildcard denial */ | |
42dcf516 | 645 | addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records); |
be4f1994 OM |
646 | addRRSIG(keys, res->d_records, auth, 300); |
647 | } | |
648 | return 1; | |
649 | } | |
650 | } | |
651 | ||
652 | return 0; | |
653 | }); | |
654 | ||
655 | vector<DNSRecord> ret; | |
656 | int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
657 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
658 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
659 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
660 | BOOST_CHECK_EQUAL(queriesCount, 9U); | |
661 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
662 | ||
663 | ret.clear(); | |
664 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
665 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
666 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
667 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
668 | BOOST_CHECK_EQUAL(queriesCount, 9U); | |
669 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
670 | ||
671 | ret.clear(); | |
672 | res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret); | |
673 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
674 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
675 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
676 | BOOST_CHECK_EQUAL(queriesCount, 9U); | |
677 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
678 | ||
679 | ret.clear(); | |
680 | res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret); | |
681 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
682 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
683 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
684 | BOOST_CHECK_EQUAL(queriesCount, 9U); | |
685 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
686 | ||
687 | // Now test without RFC 8020 to see the cache and query count grow | |
688 | SyncRes::s_hardenNXD = SyncRes::HardenNXD::No; | |
689 | ||
690 | // Already cached | |
691 | ret.clear(); | |
692 | res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
693 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
694 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
695 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
696 | BOOST_CHECK_EQUAL(queriesCount, 9U); | |
697 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
698 | ||
699 | // New query | |
700 | ret.clear(); | |
701 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
702 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
703 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
704 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
705 | BOOST_CHECK_EQUAL(queriesCount, 11U); | |
706 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); | |
707 | ||
708 | ret.clear(); | |
709 | res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret); | |
710 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
711 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
712 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
713 | BOOST_CHECK_EQUAL(queriesCount, 13U); | |
714 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 3U); | |
715 | ||
716 | ret.clear(); | |
717 | res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret); | |
718 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
719 | BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); | |
720 | BOOST_CHECK_EQUAL(ret.size(), 6U); | |
721 | BOOST_CHECK_EQUAL(queriesCount, 15U); | |
722 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 4U); | |
723 | ||
724 | // reset | |
725 | SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC; | |
726 | } | |
157647ec | 727 | |
42dcf516 OM |
728 | BOOST_AUTO_TEST_CASE(test_rfc8020_nodata) |
729 | { | |
157647ec PL |
730 | std::unique_ptr<SyncRes> sr; |
731 | initSR(sr); | |
d40a915b | 732 | SyncRes::s_hardenNXD = SyncRes::HardenNXD::Yes; |
157647ec PL |
733 | |
734 | primeHints(); | |
735 | ||
736 | const DNSName target1("www.powerdns.com."); // TXT record will be denied | |
737 | const DNSName target2("bar.www.powerdns.com."); // will be NXD, but the www. NODATA should not interfere with 8020 processing | |
738 | const DNSName target3("quux.bar.www.powerdns.com."); // will be NXD, but will not yield a query | |
739 | const ComboAddress ns("192.0.2.1:53"); | |
740 | size_t queriesCount = 0; | |
741 | ||
742 | sr->setAsyncCallback([ns, target1, target2, target3, &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, LWResult* res, bool* chained) { | |
42dcf516 | 743 | queriesCount++; |
157647ec | 744 | |
42dcf516 OM |
745 | if (isRootServer(ip)) { |
746 | setLWResult(res, 0, false, false, true); | |
747 | addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
748 | addRecordToLW(res, "ns1.powerdns.com.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
749 | return 1; | |
750 | } | |
751 | else if (ip == ns) { | |
752 | if (domain == target1) { // NODATA for TXT, NOERROR for A | |
753 | if (type == QType::TXT) { | |
754 | setLWResult(res, RCode::NoError, true); | |
157647ec PL |
755 | addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); |
756 | return 1; | |
757 | } | |
42dcf516 OM |
758 | if (type == QType::A) { |
759 | setLWResult(res, RCode::NoError, true); | |
760 | addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400); | |
761 | return 1; | |
762 | } | |
157647ec | 763 | } |
42dcf516 OM |
764 | if (domain == target2 || domain == target3) { |
765 | setLWResult(res, RCode::NXDomain, true); | |
766 | addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); | |
767 | return 1; | |
768 | } | |
769 | } | |
770 | return 0; | |
771 | }); | |
157647ec PL |
772 | |
773 | vector<DNSRecord> ret; | |
774 | int res = sr->beginResolve(target1, QType(QType::TXT), QClass::IN, ret); | |
775 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
d40a915b OM |
776 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
777 | BOOST_CHECK_EQUAL(queriesCount, 2U); | |
778 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
779 | |
780 | ret.clear(); | |
781 | res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
782 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
d40a915b OM |
783 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
784 | BOOST_CHECK_EQUAL(queriesCount, 3U); | |
785 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
786 | |
787 | ret.clear(); | |
788 | res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); | |
789 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
790 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
791 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
792 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); | |
157647ec PL |
793 | |
794 | ret.clear(); | |
795 | res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret); | |
796 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
797 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
798 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
799 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); | |
157647ec PL |
800 | } |
801 | ||
42dcf516 OM |
802 | BOOST_AUTO_TEST_CASE(test_rfc8020_nodata_bis) |
803 | { | |
157647ec PL |
804 | std::unique_ptr<SyncRes> sr; |
805 | initSR(sr); | |
d40a915b | 806 | SyncRes::s_hardenNXD = SyncRes::HardenNXD::Yes; |
157647ec PL |
807 | |
808 | primeHints(); | |
809 | ||
810 | const DNSName target1("www.powerdns.com."); // TXT record will be denied | |
811 | const DNSName target2("bar.www.powerdns.com."); // will be NXD, but the www. NODATA should not interfere with 8020 processing | |
812 | const DNSName target3("quux.bar.www.powerdns.com."); // will be NXD, but will not yield a query | |
813 | const ComboAddress ns("192.0.2.1:53"); | |
814 | size_t queriesCount = 0; | |
815 | ||
816 | sr->setAsyncCallback([ns, target1, target2, target3, &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, LWResult* res, bool* chained) { | |
42dcf516 | 817 | queriesCount++; |
157647ec | 818 | |
42dcf516 OM |
819 | if (isRootServer(ip)) { |
820 | setLWResult(res, 0, false, false, true); | |
821 | addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
822 | addRecordToLW(res, "ns1.powerdns.com.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600); | |
823 | return 1; | |
824 | } | |
825 | else if (ip == ns) { | |
826 | if (domain == target1) { // NODATA for TXT, NOERROR for A | |
827 | if (type == QType::TXT) { | |
828 | setLWResult(res, RCode::NoError, true); | |
157647ec PL |
829 | addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); |
830 | return 1; | |
831 | } | |
42dcf516 OM |
832 | if (type == QType::A) { |
833 | setLWResult(res, RCode::NoError, true); | |
834 | addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400); | |
835 | return 1; | |
836 | } | |
157647ec | 837 | } |
42dcf516 OM |
838 | if (domain == target2 || domain == target3) { |
839 | setLWResult(res, RCode::NXDomain, true); | |
840 | addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); | |
841 | return 1; | |
842 | } | |
843 | } | |
844 | return 0; | |
845 | }); | |
157647ec PL |
846 | |
847 | vector<DNSRecord> ret; | |
848 | int res = sr->beginResolve(target1, QType(QType::TXT), QClass::IN, ret); | |
849 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
d40a915b OM |
850 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
851 | BOOST_CHECK_EQUAL(queriesCount, 2U); | |
852 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
853 | |
854 | ret.clear(); | |
855 | res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); | |
856 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
d40a915b OM |
857 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
858 | BOOST_CHECK_EQUAL(queriesCount, 3U); | |
859 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U); | |
157647ec PL |
860 | |
861 | ret.clear(); | |
862 | res = sr->beginResolve(target2, QType(QType::TXT), QClass::IN, ret); | |
863 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
864 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
865 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
866 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); | |
157647ec PL |
867 | |
868 | ret.clear(); | |
869 | res = sr->beginResolve(target3, QType(QType::TXT), QClass::IN, ret); | |
870 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
d40a915b OM |
871 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
872 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
873 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U); | |
157647ec PL |
874 | } |
875 | ||
42dcf516 OM |
876 | BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) |
877 | { | |
86675669 OM |
878 | std::unique_ptr<SyncRes> sr; |
879 | initSR(sr); | |
880 | ||
881 | primeHints(); | |
882 | ||
883 | const DNSName target("www.powerdns.com."); | |
884 | const DNSName cnameTarget("cname.powerdns.com."); | |
885 | ||
886 | SyncRes::addEDNSDomain(DNSName("powerdns.com.")); | |
887 | ||
888 | EDNSSubnetOpts incomingECS; | |
889 | incomingECS.source = Netmask("192.0.2.128/32"); | |
890 | sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS)); | |
891 | ||
42dcf516 OM |
892 | 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, LWResult* res, bool* chained) { |
893 | BOOST_REQUIRE(srcmask); | |
894 | BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); | |
86675669 | 895 | |
42dcf516 OM |
896 | if (isRootServer(ip)) { |
897 | setLWResult(res, 0, false, false, true); | |
898 | addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
899 | addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); | |
86675669 | 900 | |
42dcf516 | 901 | srcmask = boost::none; |
86675669 | 902 | |
42dcf516 OM |
903 | return 1; |
904 | } | |
905 | else if (ip == ComboAddress("192.0.2.1:53")) { | |
906 | if (domain == target) { | |
907 | /* Type 2 NXDOMAIN (rfc2308 section-2.1) */ | |
908 | setLWResult(res, RCode::NXDomain, true, false, true); | |
909 | addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); | |
910 | addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); | |
911 | } | |
912 | else if (domain == cnameTarget) { | |
913 | /* we shouldn't get there since the Type NXDOMAIN should have been enough, | |
86675669 | 914 | but we might if we still chase the CNAME. */ |
42dcf516 OM |
915 | setLWResult(res, RCode::NXDomain, true, false, true); |
916 | addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); | |
86675669 OM |
917 | } |
918 | ||
42dcf516 OM |
919 | return 1; |
920 | } | |
921 | ||
922 | return 0; | |
923 | }); | |
86675669 OM |
924 | |
925 | vector<DNSRecord> ret; | |
926 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
927 | BOOST_CHECK_EQUAL(res, RCode::NXDomain); | |
690b86b7 | 928 | BOOST_CHECK_EQUAL(ret.size(), 2U); |
86675669 | 929 | /* no negative cache entry because the response was variable */ |
690b86b7 | 930 | BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0U); |
86675669 OM |
931 | } |
932 | ||
42dcf516 OM |
933 | BOOST_AUTO_TEST_CASE(test_ecs_cache_limit_allowed) |
934 | { | |
86675669 OM |
935 | std::unique_ptr<SyncRes> sr; |
936 | initSR(sr); | |
937 | ||
938 | primeHints(); | |
939 | ||
940 | const DNSName target("www.powerdns.com."); | |
941 | ||
942 | SyncRes::addEDNSDomain(DNSName("powerdns.com.")); | |
943 | ||
944 | EDNSSubnetOpts incomingECS; | |
945 | incomingECS.source = Netmask("192.0.2.128/32"); | |
946 | sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS)); | |
947 | SyncRes::s_ecsipv4cachelimit = 24; | |
948 | ||
949 | 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, LWResult* res, bool* chained) { | |
42dcf516 OM |
950 | BOOST_REQUIRE(srcmask); |
951 | BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); | |
86675669 | 952 | |
42dcf516 OM |
953 | setLWResult(res, 0, true, false, true); |
954 | addRecordToLW(res, target, QType::A, "192.0.2.1"); | |
86675669 | 955 | |
42dcf516 OM |
956 | return 1; |
957 | }); | |
86675669 OM |
958 | |
959 | const time_t now = sr->getNow().tv_sec; | |
960 | vector<DNSRecord> ret; | |
961 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
962 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 963 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 OM |
964 | |
965 | /* should have been cached */ | |
966 | const ComboAddress who("192.0.2.128"); | |
967 | vector<DNSRecord> cached; | |
a7956123 | 968 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0); |
690b86b7 | 969 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
970 | } |
971 | ||
42dcf516 OM |
972 | BOOST_AUTO_TEST_CASE(test_ecs_cache_limit_no_ttl_limit_allowed) |
973 | { | |
86675669 OM |
974 | std::unique_ptr<SyncRes> sr; |
975 | initSR(sr); | |
976 | ||
977 | primeHints(); | |
978 | ||
979 | const DNSName target("www.powerdns.com."); | |
980 | ||
981 | SyncRes::addEDNSDomain(DNSName("powerdns.com.")); | |
982 | ||
983 | EDNSSubnetOpts incomingECS; | |
984 | incomingECS.source = Netmask("192.0.2.128/32"); | |
985 | sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS)); | |
986 | SyncRes::s_ecsipv4cachelimit = 16; | |
987 | ||
988 | 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, LWResult* res, bool* chained) { | |
42dcf516 OM |
989 | BOOST_REQUIRE(srcmask); |
990 | BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); | |
86675669 | 991 | |
42dcf516 OM |
992 | setLWResult(res, 0, true, false, true); |
993 | addRecordToLW(res, target, QType::A, "192.0.2.1"); | |
86675669 | 994 | |
42dcf516 OM |
995 | return 1; |
996 | }); | |
86675669 OM |
997 | |
998 | const time_t now = sr->getNow().tv_sec; | |
999 | vector<DNSRecord> ret; | |
1000 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1001 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 1002 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 OM |
1003 | |
1004 | /* should have been cached because /24 is more specific than /16 but TTL limit is nof effective */ | |
1005 | const ComboAddress who("192.0.2.128"); | |
1006 | vector<DNSRecord> cached; | |
a7956123 | 1007 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0); |
690b86b7 | 1008 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1009 | } |
1010 | ||
42dcf516 OM |
1011 | BOOST_AUTO_TEST_CASE(test_ecs_cache_ttllimit_allowed) |
1012 | { | |
1013 | std::unique_ptr<SyncRes> sr; | |
1014 | initSR(sr); | |
86675669 | 1015 | |
42dcf516 | 1016 | primeHints(); |
86675669 | 1017 | |
42dcf516 | 1018 | const DNSName target("www.powerdns.com."); |
86675669 | 1019 | |
42dcf516 | 1020 | SyncRes::addEDNSDomain(DNSName("powerdns.com.")); |
86675669 | 1021 | |
42dcf516 OM |
1022 | EDNSSubnetOpts incomingECS; |
1023 | incomingECS.source = Netmask("192.0.2.128/32"); | |
1024 | sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS)); | |
1025 | SyncRes::s_ecscachelimitttl = 30; | |
86675669 | 1026 | |
42dcf516 OM |
1027 | 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, LWResult* res, bool* chained) { |
1028 | BOOST_REQUIRE(srcmask); | |
1029 | BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); | |
86675669 | 1030 | |
42dcf516 OM |
1031 | setLWResult(res, 0, true, false, true); |
1032 | addRecordToLW(res, target, QType::A, "192.0.2.1"); | |
86675669 | 1033 | |
42dcf516 OM |
1034 | return 1; |
1035 | }); | |
86675669 | 1036 | |
42dcf516 OM |
1037 | const time_t now = sr->getNow().tv_sec; |
1038 | vector<DNSRecord> ret; | |
1039 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1040 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
1041 | BOOST_CHECK_EQUAL(ret.size(), 1U); | |
86675669 | 1042 | |
42dcf516 OM |
1043 | /* should have been cached */ |
1044 | const ComboAddress who("192.0.2.128"); | |
1045 | vector<DNSRecord> cached; | |
a7956123 | 1046 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0); |
42dcf516 | 1047 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1048 | } |
1049 | ||
42dcf516 OM |
1050 | BOOST_AUTO_TEST_CASE(test_ecs_cache_ttllimit_and_scope_allowed) |
1051 | { | |
1052 | std::unique_ptr<SyncRes> sr; | |
1053 | initSR(sr); | |
86675669 | 1054 | |
42dcf516 | 1055 | primeHints(); |
86675669 | 1056 | |
42dcf516 | 1057 | const DNSName target("www.powerdns.com."); |
86675669 | 1058 | |
42dcf516 | 1059 | SyncRes::addEDNSDomain(DNSName("powerdns.com.")); |
86675669 | 1060 | |
42dcf516 OM |
1061 | EDNSSubnetOpts incomingECS; |
1062 | incomingECS.source = Netmask("192.0.2.128/32"); | |
1063 | sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS)); | |
1064 | SyncRes::s_ecscachelimitttl = 100; | |
1065 | SyncRes::s_ecsipv4cachelimit = 24; | |
86675669 | 1066 | |
42dcf516 OM |
1067 | 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, LWResult* res, bool* chained) { |
1068 | BOOST_REQUIRE(srcmask); | |
1069 | BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); | |
86675669 | 1070 | |
42dcf516 OM |
1071 | setLWResult(res, 0, true, false, true); |
1072 | addRecordToLW(res, target, QType::A, "192.0.2.1"); | |
86675669 | 1073 | |
42dcf516 OM |
1074 | return 1; |
1075 | }); | |
86675669 | 1076 | |
42dcf516 OM |
1077 | const time_t now = sr->getNow().tv_sec; |
1078 | vector<DNSRecord> ret; | |
1079 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1080 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
1081 | BOOST_CHECK_EQUAL(ret.size(), 1U); | |
86675669 | 1082 | |
42dcf516 OM |
1083 | /* should have been cached */ |
1084 | const ComboAddress who("192.0.2.128"); | |
1085 | vector<DNSRecord> cached; | |
a7956123 | 1086 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0); |
42dcf516 | 1087 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1088 | } |
1089 | ||
42dcf516 OM |
1090 | BOOST_AUTO_TEST_CASE(test_ecs_cache_ttllimit_notallowed) |
1091 | { | |
1092 | std::unique_ptr<SyncRes> sr; | |
1093 | initSR(sr); | |
86675669 | 1094 | |
42dcf516 | 1095 | primeHints(); |
86675669 | 1096 | |
42dcf516 | 1097 | const DNSName target("www.powerdns.com."); |
86675669 | 1098 | |
42dcf516 | 1099 | SyncRes::addEDNSDomain(DNSName("powerdns.com.")); |
86675669 | 1100 | |
42dcf516 OM |
1101 | EDNSSubnetOpts incomingECS; |
1102 | incomingECS.source = Netmask("192.0.2.128/32"); | |
1103 | sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS)); | |
1104 | SyncRes::s_ecscachelimitttl = 100; | |
1105 | SyncRes::s_ecsipv4cachelimit = 16; | |
86675669 | 1106 | |
42dcf516 OM |
1107 | 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, LWResult* res, bool* chained) { |
1108 | BOOST_REQUIRE(srcmask); | |
1109 | BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); | |
86675669 | 1110 | |
42dcf516 OM |
1111 | setLWResult(res, 0, true, false, true); |
1112 | addRecordToLW(res, target, QType::A, "192.0.2.1"); | |
86675669 | 1113 | |
42dcf516 OM |
1114 | return 1; |
1115 | }); | |
86675669 | 1116 | |
42dcf516 OM |
1117 | const time_t now = sr->getNow().tv_sec; |
1118 | vector<DNSRecord> ret; | |
1119 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1120 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
1121 | BOOST_CHECK_EQUAL(ret.size(), 1U); | |
86675669 | 1122 | |
42dcf516 OM |
1123 | /* should have NOT been cached because TTL of 60 is too small and /24 is more specific than /16 */ |
1124 | const ComboAddress who("192.0.2.128"); | |
1125 | vector<DNSRecord> cached; | |
a7956123 | 1126 | BOOST_REQUIRE_LT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0); |
42dcf516 | 1127 | BOOST_REQUIRE_EQUAL(cached.size(), 0U); |
86675669 OM |
1128 | } |
1129 | ||
42dcf516 OM |
1130 | BOOST_AUTO_TEST_CASE(test_ns_speed) |
1131 | { | |
86675669 OM |
1132 | std::unique_ptr<SyncRes> sr; |
1133 | initSR(sr); | |
1134 | ||
1135 | primeHints(); | |
1136 | ||
1137 | const DNSName target("powerdns.com."); | |
1138 | ||
1139 | std::map<ComboAddress, uint64_t> nsCounts; | |
1140 | ||
42dcf516 OM |
1141 | sr->setAsyncCallback([target, &nsCounts](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, LWResult* res, bool* chained) { |
1142 | if (isRootServer(ip)) { | |
1143 | setLWResult(res, 0, false, false, true); | |
1144 | addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
1145 | addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
1146 | addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
86675669 | 1147 | |
42dcf516 OM |
1148 | addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); |
1149 | addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); | |
1150 | addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); | |
1151 | addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600); | |
1152 | addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600); | |
1153 | addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600); | |
86675669 | 1154 | |
42dcf516 OM |
1155 | return 1; |
1156 | } | |
1157 | else { | |
1158 | nsCounts[ip]++; | |
86675669 | 1159 | |
42dcf516 OM |
1160 | if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) { |
1161 | BOOST_CHECK_LT(nsCounts.size(), 3U); | |
86675669 | 1162 | |
42dcf516 | 1163 | /* let's time out on pdns-public-ns2.powerdns.com. */ |
86675669 OM |
1164 | return 0; |
1165 | } | |
42dcf516 OM |
1166 | else if (ip == ComboAddress("192.0.2.1:53")) { |
1167 | BOOST_CHECK_EQUAL(nsCounts.size(), 3U); | |
1168 | ||
1169 | setLWResult(res, 0, true, false, true); | |
1170 | addRecordToLW(res, domain, QType::A, "192.0.2.254"); | |
1171 | return 1; | |
1172 | } | |
86675669 OM |
1173 | |
1174 | return 0; | |
42dcf516 OM |
1175 | } |
1176 | ||
1177 | return 0; | |
1178 | }); | |
86675669 OM |
1179 | |
1180 | struct timeval now = sr->getNow(); | |
1181 | ||
1182 | /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one, | |
1183 | then pdns-public-ns1.powerdns.com. on IPv4 */ | |
b9715061 OM |
1184 | SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, now); |
1185 | SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, now); | |
1186 | SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, now); | |
1187 | SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, now); | |
1188 | SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, now); | |
1189 | SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, now); | |
86675669 OM |
1190 | |
1191 | vector<DNSRecord> ret; | |
1192 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1193 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 OM |
1194 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
1195 | BOOST_CHECK_EQUAL(nsCounts.size(), 3U); | |
1196 | BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1U); | |
1197 | BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1U); | |
1198 | BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1U); | |
86675669 OM |
1199 | } |
1200 | ||
42dcf516 OM |
1201 | BOOST_AUTO_TEST_CASE(test_flawed_nsset) |
1202 | { | |
86675669 OM |
1203 | std::unique_ptr<SyncRes> sr; |
1204 | initSR(sr); | |
1205 | ||
1206 | primeHints(); | |
1207 | ||
1208 | const DNSName target("powerdns.com."); | |
1209 | ||
1210 | 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, LWResult* res, bool* chained) { | |
42dcf516 OM |
1211 | if (isRootServer(ip)) { |
1212 | setLWResult(res, 0, false, false, true); | |
1213 | addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
86675669 | 1214 | |
42dcf516 | 1215 | addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); |
86675669 | 1216 | |
42dcf516 OM |
1217 | return 1; |
1218 | } | |
1219 | else if (ip == ComboAddress("192.0.2.1:53")) { | |
1220 | setLWResult(res, 0, true, false, true); | |
1221 | addRecordToLW(res, domain, QType::A, "192.0.2.254"); | |
1222 | return 1; | |
1223 | } | |
86675669 | 1224 | |
42dcf516 OM |
1225 | return 0; |
1226 | }); | |
86675669 OM |
1227 | |
1228 | /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */ | |
1229 | time_t now = sr->getNow().tv_sec; | |
1230 | std::vector<DNSRecord> records; | |
42dcf516 | 1231 | std::vector<shared_ptr<RRSIGRecordContent>> sigs; |
86675669 OM |
1232 | addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600); |
1233 | ||
a7956123 | 1234 | s_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>()); |
86675669 OM |
1235 | |
1236 | vector<DNSRecord> ret; | |
1237 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1238 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 1239 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 OM |
1240 | } |
1241 | ||
42dcf516 OM |
1242 | BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) |
1243 | { | |
86675669 OM |
1244 | std::unique_ptr<SyncRes> sr; |
1245 | initSR(sr); | |
1246 | ||
1247 | primeHints(); | |
1248 | ||
1249 | const DNSName target("powerdns.com."); | |
1250 | size_t queriesCount = 0; | |
1251 | ||
42dcf516 OM |
1252 | sr->setAsyncCallback([&queriesCount, 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, LWResult* res, bool* chained) { |
1253 | queriesCount++; | |
86675669 | 1254 | |
42dcf516 OM |
1255 | if (isRootServer(ip) && domain == target) { |
1256 | setLWResult(res, 0, false, false, true); | |
1257 | addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
1258 | addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
1259 | return 1; | |
1260 | } | |
1261 | else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")) { | |
1262 | setLWResult(res, 0, true, false, true); | |
1263 | addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); | |
1264 | return 1; | |
1265 | } | |
86675669 | 1266 | |
42dcf516 OM |
1267 | return 0; |
1268 | }); | |
86675669 OM |
1269 | |
1270 | vector<DNSRecord> ret; | |
1271 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1272 | BOOST_CHECK_EQUAL(res, RCode::ServFail); | |
690b86b7 | 1273 | BOOST_CHECK_EQUAL(ret.size(), 0U); |
86675669 | 1274 | /* one query to get NSs, then A and AAAA for each NS */ |
690b86b7 | 1275 | BOOST_CHECK_EQUAL(queriesCount, 5U); |
86675669 OM |
1276 | } |
1277 | ||
42dcf516 OM |
1278 | BOOST_AUTO_TEST_CASE(test_cache_hit) |
1279 | { | |
86675669 OM |
1280 | std::unique_ptr<SyncRes> sr; |
1281 | initSR(sr); | |
1282 | ||
1283 | primeHints(); | |
1284 | ||
1285 | const DNSName target("powerdns.com."); | |
1286 | ||
1287 | 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, LWResult* res, bool* chained) { | |
42dcf516 OM |
1288 | return 0; |
1289 | }); | |
86675669 | 1290 | |
ef2ea4bf | 1291 | /* we populate the cache with everything we need */ |
86675669 OM |
1292 | time_t now = sr->getNow().tv_sec; |
1293 | std::vector<DNSRecord> records; | |
42dcf516 | 1294 | std::vector<shared_ptr<RRSIGRecordContent>> sigs; |
86675669 OM |
1295 | |
1296 | addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600); | |
a7956123 | 1297 | s_RC->replace(now, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>()); |
86675669 OM |
1298 | |
1299 | vector<DNSRecord> ret; | |
1300 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1301 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 1302 | BOOST_CHECK_EQUAL(ret.size(), 1U); |
86675669 OM |
1303 | } |
1304 | ||
42dcf516 OM |
1305 | BOOST_AUTO_TEST_CASE(test_no_rd) |
1306 | { | |
86675669 OM |
1307 | std::unique_ptr<SyncRes> sr; |
1308 | initSR(sr); | |
1309 | ||
1310 | primeHints(); | |
1311 | ||
1312 | const DNSName target("powerdns.com."); | |
1313 | size_t queriesCount = 0; | |
1314 | ||
1315 | sr->setCacheOnly(); | |
1316 | ||
42dcf516 OM |
1317 | sr->setAsyncCallback([target, &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, LWResult* res, bool* chained) { |
1318 | queriesCount++; | |
1319 | return 0; | |
1320 | }); | |
86675669 OM |
1321 | |
1322 | vector<DNSRecord> ret; | |
1323 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1324 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 OM |
1325 | BOOST_CHECK_EQUAL(ret.size(), 0U); |
1326 | BOOST_CHECK_EQUAL(queriesCount, 0U); | |
86675669 OM |
1327 | } |
1328 | ||
42dcf516 OM |
1329 | BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) |
1330 | { | |
86675669 OM |
1331 | std::unique_ptr<SyncRes> sr; |
1332 | initSR(sr); | |
1333 | ||
1334 | primeHints(); | |
1335 | ||
1336 | const DNSName target("cachettl.powerdns.com."); | |
1337 | const ComboAddress ns("192.0.2.1:53"); | |
1338 | ||
42dcf516 OM |
1339 | sr->setAsyncCallback([target, ns](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, LWResult* res, bool* chained) { |
1340 | if (isRootServer(ip)) { | |
86675669 | 1341 | |
42dcf516 OM |
1342 | setLWResult(res, 0, false, false, true); |
1343 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
1344 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200); | |
1345 | return 1; | |
1346 | } | |
1347 | else if (ip == ns) { | |
86675669 | 1348 | |
42dcf516 OM |
1349 | setLWResult(res, 0, true, false, false); |
1350 | addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10); | |
86675669 | 1351 | |
42dcf516 OM |
1352 | return 1; |
1353 | } | |
86675669 | 1354 | |
42dcf516 OM |
1355 | return 0; |
1356 | }); | |
86675669 OM |
1357 | |
1358 | const time_t now = sr->getNow().tv_sec; | |
1359 | SyncRes::s_minimumTTL = 60; | |
1360 | SyncRes::s_maxcachettl = 3600; | |
1361 | ||
1362 | vector<DNSRecord> ret; | |
1363 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1364 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 1365 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
1366 | BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL); |
1367 | ||
1368 | const ComboAddress who; | |
1369 | vector<DNSRecord> cached; | |
a7956123 | 1370 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0); |
690b86b7 | 1371 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1372 | BOOST_REQUIRE_GT(cached[0].d_ttl, now); |
1373 | BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL); | |
1374 | ||
1375 | cached.clear(); | |
a7956123 | 1376 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::NS), false, &cached, who), 0); |
690b86b7 | 1377 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1378 | BOOST_REQUIRE_GT(cached[0].d_ttl, now); |
1379 | BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl); | |
1380 | } | |
1381 | ||
42dcf516 OM |
1382 | BOOST_AUTO_TEST_CASE(test_cache_min_max_ecs_ttl) |
1383 | { | |
86675669 OM |
1384 | std::unique_ptr<SyncRes> sr; |
1385 | initSR(sr); | |
1386 | ||
1387 | primeHints(); | |
1388 | ||
1389 | const DNSName target("cacheecsttl.powerdns.com."); | |
1390 | const ComboAddress ns("192.0.2.1:53"); | |
1391 | ||
1392 | EDNSSubnetOpts incomingECS; | |
1393 | incomingECS.source = Netmask("192.0.2.128/32"); | |
1394 | sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS)); | |
1395 | SyncRes::addEDNSDomain(target); | |
1396 | ||
42dcf516 OM |
1397 | sr->setAsyncCallback([target, ns](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, LWResult* res, bool* chained) { |
1398 | BOOST_REQUIRE(srcmask); | |
1399 | BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); | |
86675669 | 1400 | |
42dcf516 | 1401 | if (isRootServer(ip)) { |
86675669 | 1402 | |
42dcf516 OM |
1403 | setLWResult(res, 0, false, false, true); |
1404 | addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); | |
1405 | addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 20); | |
1406 | srcmask = boost::none; | |
86675669 | 1407 | |
42dcf516 OM |
1408 | return 1; |
1409 | } | |
1410 | else if (ip == ns) { | |
86675669 | 1411 | |
42dcf516 OM |
1412 | setLWResult(res, 0, true, false, false); |
1413 | addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10); | |
86675669 | 1414 | |
42dcf516 OM |
1415 | return 1; |
1416 | } | |
86675669 | 1417 | |
42dcf516 OM |
1418 | return 0; |
1419 | }); | |
86675669 OM |
1420 | |
1421 | const time_t now = sr->getNow().tv_sec; | |
1422 | SyncRes::s_minimumTTL = 60; | |
1423 | SyncRes::s_minimumECSTTL = 120; | |
1424 | SyncRes::s_maxcachettl = 3600; | |
1425 | ||
1426 | vector<DNSRecord> ret; | |
1427 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1428 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 1429 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
1430 | BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumECSTTL); |
1431 | ||
1432 | const ComboAddress who("192.0.2.128"); | |
1433 | vector<DNSRecord> cached; | |
a7956123 | 1434 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0); |
690b86b7 | 1435 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1436 | BOOST_REQUIRE_GT(cached[0].d_ttl, now); |
1437 | BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumECSTTL); | |
1438 | ||
1439 | cached.clear(); | |
a7956123 | 1440 | BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::NS), false, &cached, who), 0); |
690b86b7 | 1441 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1442 | BOOST_REQUIRE_GT(cached[0].d_ttl, now); |
1443 | BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl); | |
1444 | ||
1445 | cached.clear(); | |
a7956123 | 1446 | BOOST_REQUIRE_GT(s_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0); |
690b86b7 | 1447 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
86675669 OM |
1448 | BOOST_REQUIRE_GT(cached[0].d_ttl, now); |
1449 | BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_minimumTTL); | |
1450 | } | |
1451 | ||
42dcf516 OM |
1452 | BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) |
1453 | { | |
86675669 OM |
1454 | std::unique_ptr<SyncRes> sr; |
1455 | initSR(sr); | |
1456 | ||
1457 | primeHints(); | |
1458 | ||
1459 | const DNSName target("powerdns.com."); | |
1460 | ||
1461 | 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, LWResult* res, bool* chained) { | |
42dcf516 OM |
1462 | if (isRootServer(ip)) { |
1463 | setLWResult(res, 0, false, false, true); | |
1464 | addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); | |
86675669 | 1465 | |
42dcf516 | 1466 | addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); |
86675669 | 1467 | |
42dcf516 OM |
1468 | return 1; |
1469 | } | |
1470 | else if (ip == ComboAddress("192.0.2.1:53")) { | |
1471 | setLWResult(res, 0, true, false, true); | |
1472 | addRecordToLW(res, domain, QType::A, "192.0.2.2"); | |
1473 | return 1; | |
1474 | } | |
86675669 | 1475 | |
42dcf516 OM |
1476 | return 0; |
1477 | }); | |
86675669 OM |
1478 | |
1479 | /* we populate the cache with entries that expired 60s ago*/ | |
1480 | const time_t now = sr->getNow().tv_sec; | |
1481 | ||
1482 | std::vector<DNSRecord> records; | |
42dcf516 | 1483 | std::vector<shared_ptr<RRSIGRecordContent>> sigs; |
86675669 OM |
1484 | addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60); |
1485 | ||
a7956123 | 1486 | s_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>()); |
86675669 OM |
1487 | |
1488 | vector<DNSRecord> ret; | |
1489 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1490 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
690b86b7 | 1491 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
1492 | BOOST_REQUIRE(ret[0].d_type == QType::A); |
1493 | BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort()); | |
1494 | } | |
1495 | ||
1496 | BOOST_AUTO_TEST_SUITE_END() |