]>
Commit | Line | Data |
---|---|---|
1c2d079d | 1 | #ifndef BOOST_TEST_DYN_LINK |
886e2cf2 | 2 | #define BOOST_TEST_DYN_LINK |
1c2d079d FM |
3 | #endif |
4 | ||
886e2cf2 RG |
5 | #define BOOST_TEST_NO_MAIN |
6 | ||
7 | #include <boost/test/unit_test.hpp> | |
8 | ||
78e3ac9e | 9 | #include "ednscookies.hh" |
8dcdbdb1 | 10 | #include "ednsoptions.hh" |
78e3ac9e | 11 | #include "ednssubnet.hh" |
1ea747c0 | 12 | #include "dnsdist.hh" |
886e2cf2 | 13 | #include "iputils.hh" |
886e2cf2 | 14 | #include "dnswriter.hh" |
1ea747c0 | 15 | #include "dnsdist-cache.hh" |
5ffb2f83 | 16 | #include "gettime.hh" |
fa980c59 | 17 | #include "packetcache.hh" |
886e2cf2 | 18 | |
c7f29d3e | 19 | BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc) |
886e2cf2 | 20 | |
d84ea5be RG |
21 | static bool receivedOverUDP = true; |
22 | ||
886e2cf2 RG |
23 | BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) { |
24 | const size_t maxEntries = 150000; | |
25 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
690b86b7 | 26 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); |
886e2cf2 | 27 | |
592b1d99 RG |
28 | size_t counter = 0; |
29 | size_t skipped = 0; | |
d7728daf | 30 | bool dnssecOK = false; |
f6e76e12 | 31 | const time_t now = time(nullptr); |
592b1d99 RG |
32 | InternalQueryState ids; |
33 | ids.qtype = QType::A; | |
34 | ids.qclass = QClass::IN; | |
35 | ids.protocol = dnsdist::Protocol::DoUDP; | |
36 | ||
886e2cf2 | 37 | try { |
f6e76e12 | 38 | for (counter = 0; counter < 100000; ++counter) { |
592b1d99 RG |
39 | auto a = DNSName(std::to_string(counter))+DNSName(" hello"); |
40 | ids.qname = a; | |
886e2cf2 | 41 | |
32fbb2ab RG |
42 | PacketBuffer query; |
43 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0); | |
886e2cf2 RG |
44 | pwQ.getHeader()->rd = 1; |
45 | ||
32fbb2ab RG |
46 | PacketBuffer response; |
47 | GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::A, QClass::IN, 0); | |
886e2cf2 RG |
48 | pwR.getHeader()->rd = 1; |
49 | pwR.getHeader()->ra = 1; | |
50 | pwR.getHeader()->qr = 1; | |
51 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
f627611d | 52 | pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); |
886e2cf2 RG |
53 | pwR.xfr32BitInt(0x01020304); |
54 | pwR.commit(); | |
886e2cf2 | 55 | |
886e2cf2 | 56 | uint32_t key = 0; |
78e3ac9e | 57 | boost::optional<Netmask> subnet; |
80a210f2 RG |
58 | DNSQuestion dnsQuestion(ids, query); |
59 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
886e2cf2 | 60 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 61 | BOOST_CHECK(!subnet); |
886e2cf2 | 62 | |
80a210f2 | 63 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); |
886e2cf2 | 64 | |
80a210f2 | 65 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); |
886e2cf2 | 66 | if (found == true) { |
80a210f2 RG |
67 | BOOST_CHECK_EQUAL(dnsQuestion.getData().size(), response.size()); |
68 | int match = memcmp(dnsQuestion.getData().data(), response.data(), dnsQuestion.getData().size()); | |
886e2cf2 | 69 | BOOST_CHECK_EQUAL(match, 0); |
78e3ac9e | 70 | BOOST_CHECK(!subnet); |
886e2cf2 RG |
71 | } |
72 | else { | |
73 | skipped++; | |
74 | } | |
75 | } | |
76 | ||
77 | BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions()); | |
78 | BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped); | |
79 | ||
80 | size_t deleted=0; | |
81 | size_t delcounter=0; | |
f6e76e12 | 82 | for (delcounter=0; delcounter < counter/1000; ++delcounter) { |
592b1d99 | 83 | ids.qname = DNSName(std::to_string(delcounter))+DNSName(" hello"); |
32fbb2ab | 84 | PacketBuffer query; |
592b1d99 | 85 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0); |
886e2cf2 | 86 | pwQ.getHeader()->rd = 1; |
886e2cf2 | 87 | uint32_t key = 0; |
78e3ac9e | 88 | boost::optional<Netmask> subnet; |
80a210f2 RG |
89 | DNSQuestion dnsQuestion(ids, query); |
90 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
886e2cf2 | 91 | if (found == true) { |
592b1d99 | 92 | auto removed = PC.expungeByName(ids.qname); |
690b86b7 | 93 | BOOST_CHECK_EQUAL(removed, 1U); |
f627611d | 94 | deleted += removed; |
886e2cf2 RG |
95 | } |
96 | } | |
97 | BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted); | |
98 | ||
99 | size_t matches=0; | |
886e2cf2 | 100 | size_t expected=counter-skipped-deleted; |
f6e76e12 | 101 | for (; delcounter < counter; ++delcounter) { |
592b1d99 | 102 | ids.qname = DNSName(std::to_string(delcounter))+DNSName(" hello"); |
32fbb2ab | 103 | PacketBuffer query; |
592b1d99 | 104 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0); |
886e2cf2 | 105 | pwQ.getHeader()->rd = 1; |
886e2cf2 | 106 | uint32_t key = 0; |
78e3ac9e | 107 | boost::optional<Netmask> subnet; |
80a210f2 RG |
108 | DNSQuestion dnsQuestion(ids, query); |
109 | if (PC.get(dnsQuestion, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) { | |
490dc586 | 110 | matches++; |
886e2cf2 RG |
111 | } |
112 | } | |
490dc586 | 113 | |
6d1a9248 | 114 | /* in the unlikely event that the test took so long that the entries did expire.. */ |
f6e76e12 | 115 | auto expired = PC.purgeExpired(0, now); |
f627611d RG |
116 | BOOST_CHECK_EQUAL(matches + expired, expected); |
117 | ||
118 | auto remaining = PC.getSize(); | |
119 | auto removed = PC.expungeByName(DNSName(" hello"), QType::ANY, true); | |
690b86b7 | 120 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); |
f627611d | 121 | BOOST_CHECK_EQUAL(removed, remaining); |
af9f7f64 RG |
122 | |
123 | /* nothing to remove */ | |
124 | BOOST_CHECK_EQUAL(PC.purgeExpired(0, now), 0U); | |
886e2cf2 | 125 | } |
f6e76e12 RG |
126 | catch (const PDNSException& e) { |
127 | cerr<<"Had error: "<<e.reason<<endl; | |
128 | throw; | |
129 | } | |
130 | } | |
131 | ||
132 | BOOST_AUTO_TEST_CASE(test_PacketCacheSharded) { | |
133 | const size_t maxEntries = 150000; | |
134 | const size_t numberOfShards = 10; | |
135 | DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, numberOfShards); | |
136 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); | |
f6e76e12 RG |
137 | |
138 | size_t counter = 0; | |
139 | size_t skipped = 0; | |
140 | ComboAddress remote; | |
141 | bool dnssecOK = false; | |
142 | const time_t now = time(nullptr); | |
592b1d99 RG |
143 | InternalQueryState ids; |
144 | ids.qtype = QType::AAAA; | |
145 | ids.qclass = QClass::IN; | |
146 | ids.protocol = dnsdist::Protocol::DoUDP; | |
f6e76e12 RG |
147 | |
148 | try { | |
149 | for (counter = 0; counter < 100000; ++counter) { | |
592b1d99 | 150 | ids.qname = DNSName(std::to_string(counter) + ".powerdns.com."); |
f6e76e12 RG |
151 | |
152 | PacketBuffer query; | |
592b1d99 | 153 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::AAAA, QClass::IN, 0); |
f6e76e12 RG |
154 | pwQ.getHeader()->rd = 1; |
155 | ||
156 | PacketBuffer response; | |
592b1d99 | 157 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::AAAA, QClass::IN, 0); |
f6e76e12 RG |
158 | pwR.getHeader()->rd = 1; |
159 | pwR.getHeader()->ra = 1; | |
160 | pwR.getHeader()->qr = 1; | |
161 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
592b1d99 | 162 | pwR.startRecord(ids.qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER); |
80a210f2 | 163 | ComboAddress v6addr("2001:db8::1"); |
e1911853 | 164 | pwR.xfrCAWithoutPort(6, v6addr); |
f6e76e12 RG |
165 | pwR.commit(); |
166 | ||
167 | uint32_t key = 0; | |
168 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
169 | DNSQuestion dnsQuestion(ids, query); |
170 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
f6e76e12 RG |
171 | BOOST_CHECK_EQUAL(found, false); |
172 | BOOST_CHECK(!subnet); | |
173 | ||
80a210f2 | 174 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::AAAA, QClass::IN, response, receivedOverUDP, 0, boost::none); |
f6e76e12 | 175 | |
80a210f2 | 176 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); |
f6e76e12 | 177 | if (found == true) { |
80a210f2 RG |
178 | BOOST_CHECK_EQUAL(dnsQuestion.getData().size(), response.size()); |
179 | int match = memcmp(dnsQuestion.getData().data(), response.data(), dnsQuestion.getData().size()); | |
f6e76e12 RG |
180 | BOOST_CHECK_EQUAL(match, 0); |
181 | BOOST_CHECK(!subnet); | |
182 | } | |
183 | else { | |
184 | skipped++; | |
185 | } | |
186 | } | |
187 | ||
188 | BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions()); | |
189 | BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped); | |
190 | ||
191 | size_t matches = 0; | |
192 | for (counter = 0; counter < 100000; ++counter) { | |
592b1d99 | 193 | ids.qname = DNSName(std::to_string(counter) + ".powerdns.com."); |
f6e76e12 RG |
194 | |
195 | PacketBuffer query; | |
592b1d99 | 196 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::AAAA, QClass::IN, 0); |
f6e76e12 RG |
197 | pwQ.getHeader()->rd = 1; |
198 | uint32_t key = 0; | |
199 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
200 | DNSQuestion dnsQuestion(ids, query); |
201 | if (PC.get(dnsQuestion, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) { | |
f6e76e12 RG |
202 | matches++; |
203 | } | |
204 | } | |
205 | ||
206 | BOOST_CHECK_EQUAL(matches, counter - skipped); | |
207 | ||
208 | auto remaining = PC.getSize(); | |
209 | ||
210 | /* no entry should have expired */ | |
211 | auto expired = PC.purgeExpired(0, now); | |
212 | BOOST_CHECK_EQUAL(expired, 0U); | |
213 | ||
214 | /* but after the TTL .. let's ask for at most 1k entries */ | |
b8a0a4a8 | 215 | auto removed = PC.purgeExpired(1000, now + 7200 + 3600); |
f6e76e12 RG |
216 | BOOST_CHECK_EQUAL(removed, remaining - 1000U); |
217 | BOOST_CHECK_EQUAL(PC.getSize(), 1000U); | |
218 | ||
219 | /* now remove everything */ | |
b8a0a4a8 | 220 | removed = PC.purgeExpired(0, now + 7200 + 3600); |
f6e76e12 RG |
221 | BOOST_CHECK_EQUAL(removed, 1000U); |
222 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); | |
af9f7f64 RG |
223 | |
224 | /* nothing to remove */ | |
225 | BOOST_CHECK_EQUAL(PC.purgeExpired(0, now), 0U); | |
f6e76e12 RG |
226 | } |
227 | catch (const PDNSException& e) { | |
886e2cf2 RG |
228 | cerr<<"Had error: "<<e.reason<<endl; |
229 | throw; | |
230 | } | |
231 | } | |
232 | ||
30014e5f RG |
233 | BOOST_AUTO_TEST_CASE(test_PacketCacheTCP) { |
234 | const size_t maxEntries = 150000; | |
235 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
592b1d99 RG |
236 | InternalQueryState ids; |
237 | ids.qtype = QType::A; | |
238 | ids.qclass = QClass::IN; | |
239 | ids.protocol = dnsdist::Protocol::DoUDP; | |
30014e5f RG |
240 | |
241 | ComboAddress remote; | |
242 | bool dnssecOK = false; | |
243 | try { | |
592b1d99 RG |
244 | DNSName a("tcp"); |
245 | ids.qname = a; | |
30014e5f RG |
246 | |
247 | PacketBuffer query; | |
248 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::AAAA, QClass::IN, 0); | |
249 | pwQ.getHeader()->rd = 1; | |
250 | ||
251 | PacketBuffer response; | |
252 | GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::AAAA, QClass::IN, 0); | |
253 | pwR.getHeader()->rd = 1; | |
254 | pwR.getHeader()->ra = 1; | |
255 | pwR.getHeader()->qr = 1; | |
256 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
257 | pwR.startRecord(a, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
80a210f2 | 258 | ComboAddress v6addr("2001:db8::1"); |
e1911853 | 259 | pwR.xfrCAWithoutPort(6, v6addr); |
30014e5f RG |
260 | pwR.commit(); |
261 | ||
262 | { | |
263 | /* UDP */ | |
264 | uint32_t key = 0; | |
265 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
266 | DNSQuestion dnsQuestion(ids, query); |
267 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
30014e5f RG |
268 | BOOST_CHECK_EQUAL(found, false); |
269 | BOOST_CHECK(!subnet); | |
270 | ||
80a210f2 RG |
271 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); |
272 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
30014e5f RG |
273 | BOOST_CHECK_EQUAL(found, true); |
274 | BOOST_CHECK(!subnet); | |
275 | } | |
276 | ||
277 | { | |
278 | /* same but over TCP */ | |
279 | uint32_t key = 0; | |
280 | boost::optional<Netmask> subnet; | |
592b1d99 | 281 | ids.protocol = dnsdist::Protocol::DoTCP; |
80a210f2 RG |
282 | DNSQuestion dnsQuestion(ids, query); |
283 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); | |
30014e5f RG |
284 | BOOST_CHECK_EQUAL(found, false); |
285 | BOOST_CHECK(!subnet); | |
286 | ||
80a210f2 RG |
287 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); |
288 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); | |
30014e5f RG |
289 | BOOST_CHECK_EQUAL(found, true); |
290 | BOOST_CHECK(!subnet); | |
291 | } | |
292 | } | |
293 | catch(PDNSException& e) { | |
294 | cerr<<"Had error: "<<e.reason<<endl; | |
295 | throw; | |
296 | } | |
297 | } | |
298 | ||
acb8f5d5 CH |
299 | BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) { |
300 | const size_t maxEntries = 150000; | |
301 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
592b1d99 RG |
302 | InternalQueryState ids; |
303 | ids.qtype = QType::A; | |
304 | ids.qclass = QClass::IN; | |
305 | ids.protocol = dnsdist::Protocol::DoUDP; | |
acb8f5d5 CH |
306 | |
307 | ComboAddress remote; | |
d7728daf | 308 | bool dnssecOK = false; |
acb8f5d5 CH |
309 | try { |
310 | DNSName a = DNSName("servfail"); | |
592b1d99 | 311 | ids.qname = a; |
acb8f5d5 | 312 | |
32fbb2ab RG |
313 | PacketBuffer query; |
314 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0); | |
acb8f5d5 CH |
315 | pwQ.getHeader()->rd = 1; |
316 | ||
32fbb2ab RG |
317 | PacketBuffer response; |
318 | GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::A, QClass::IN, 0); | |
acb8f5d5 CH |
319 | pwR.getHeader()->rd = 1; |
320 | pwR.getHeader()->ra = 0; | |
321 | pwR.getHeader()->qr = 1; | |
322 | pwR.getHeader()->rcode = RCode::ServFail; | |
323 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
324 | pwR.commit(); | |
acb8f5d5 | 325 | |
acb8f5d5 | 326 | uint32_t key = 0; |
78e3ac9e | 327 | boost::optional<Netmask> subnet; |
80a210f2 RG |
328 | DNSQuestion dnsQuestion(ids, query); |
329 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
acb8f5d5 | 330 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 331 | BOOST_CHECK(!subnet); |
acb8f5d5 CH |
332 | |
333 | // Insert with failure-TTL of 0 (-> should not enter cache). | |
80a210f2 RG |
334 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(0)); |
335 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
acb8f5d5 | 336 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 337 | BOOST_CHECK(!subnet); |
acb8f5d5 | 338 | |
56459632 | 339 | // Insert with failure-TTL non-zero (-> should enter cache). |
80a210f2 RG |
340 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(300)); |
341 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
acb8f5d5 | 342 | BOOST_CHECK_EQUAL(found, true); |
78e3ac9e | 343 | BOOST_CHECK(!subnet); |
acb8f5d5 CH |
344 | } |
345 | catch(PDNSException& e) { | |
346 | cerr<<"Had error: "<<e.reason<<endl; | |
347 | throw; | |
348 | } | |
349 | } | |
350 | ||
47698274 RG |
351 | BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) { |
352 | const size_t maxEntries = 150000; | |
353 | DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); | |
354 | ||
592b1d99 RG |
355 | ComboAddress remote; |
356 | bool dnssecOK = false; | |
357 | InternalQueryState ids; | |
358 | ids.qtype = QType::A; | |
359 | ids.qclass = QClass::IN; | |
360 | ids.protocol = dnsdist::Protocol::DoUDP; | |
47698274 | 361 | |
47698274 RG |
362 | try { |
363 | DNSName name("nodata"); | |
592b1d99 | 364 | ids.qname = name; |
32fbb2ab RG |
365 | PacketBuffer query; |
366 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0); | |
47698274 RG |
367 | pwQ.getHeader()->rd = 1; |
368 | ||
32fbb2ab RG |
369 | PacketBuffer response; |
370 | GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0); | |
47698274 RG |
371 | pwR.getHeader()->rd = 1; |
372 | pwR.getHeader()->ra = 0; | |
373 | pwR.getHeader()->qr = 1; | |
374 | pwR.getHeader()->rcode = RCode::NoError; | |
375 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
376 | pwR.commit(); | |
377 | pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY); | |
378 | pwR.commit(); | |
379 | pwR.addOpt(4096, 0, 0); | |
380 | pwR.commit(); | |
381 | ||
47698274 | 382 | uint32_t key = 0; |
78e3ac9e | 383 | boost::optional<Netmask> subnet; |
80a210f2 RG |
384 | DNSQuestion dnsQuestion(ids, query); |
385 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
47698274 | 386 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 387 | BOOST_CHECK(!subnet); |
47698274 | 388 | |
80a210f2 RG |
389 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); |
390 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
47698274 | 391 | BOOST_CHECK_EQUAL(found, true); |
78e3ac9e RG |
392 | BOOST_CHECK(!subnet); |
393 | ||
47698274 RG |
394 | sleep(2); |
395 | /* it should have expired by now */ | |
80a210f2 | 396 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); |
47698274 | 397 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 398 | BOOST_CHECK(!subnet); |
47698274 RG |
399 | } |
400 | catch(const PDNSException& e) { | |
401 | cerr<<"Had error: "<<e.reason<<endl; | |
402 | throw; | |
403 | } | |
404 | } | |
405 | ||
406 | BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) { | |
407 | const size_t maxEntries = 150000; | |
408 | DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); | |
409 | ||
592b1d99 RG |
410 | InternalQueryState ids; |
411 | ids.qtype = QType::A; | |
412 | ids.qclass = QClass::IN; | |
413 | ids.protocol = dnsdist::Protocol::DoUDP; | |
47698274 RG |
414 | |
415 | ComboAddress remote; | |
d7728daf | 416 | bool dnssecOK = false; |
47698274 RG |
417 | try { |
418 | DNSName name("nxdomain"); | |
592b1d99 | 419 | ids.qname = name; |
32fbb2ab RG |
420 | PacketBuffer query; |
421 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0); | |
47698274 RG |
422 | pwQ.getHeader()->rd = 1; |
423 | ||
32fbb2ab RG |
424 | PacketBuffer response; |
425 | GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0); | |
47698274 RG |
426 | pwR.getHeader()->rd = 1; |
427 | pwR.getHeader()->ra = 0; | |
428 | pwR.getHeader()->qr = 1; | |
429 | pwR.getHeader()->rcode = RCode::NXDomain; | |
430 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
431 | pwR.commit(); | |
432 | pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY); | |
433 | pwR.commit(); | |
434 | pwR.addOpt(4096, 0, 0); | |
435 | pwR.commit(); | |
436 | ||
47698274 | 437 | uint32_t key = 0; |
78e3ac9e | 438 | boost::optional<Netmask> subnet; |
80a210f2 RG |
439 | DNSQuestion dnsQuestion(ids, query); |
440 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
47698274 | 441 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 442 | BOOST_CHECK(!subnet); |
47698274 | 443 | |
80a210f2 RG |
444 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none); |
445 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
47698274 | 446 | BOOST_CHECK_EQUAL(found, true); |
78e3ac9e RG |
447 | BOOST_CHECK(!subnet); |
448 | ||
47698274 RG |
449 | sleep(2); |
450 | /* it should have expired by now */ | |
80a210f2 | 451 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); |
47698274 | 452 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 453 | BOOST_CHECK(!subnet); |
47698274 RG |
454 | } |
455 | catch(const PDNSException& e) { | |
456 | cerr<<"Had error: "<<e.reason<<endl; | |
457 | throw; | |
458 | } | |
459 | } | |
460 | ||
0c8759d8 RG |
461 | BOOST_AUTO_TEST_CASE(test_PacketCacheTruncated) { |
462 | const size_t maxEntries = 150000; | |
463 | DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); | |
464 | ||
592b1d99 RG |
465 | InternalQueryState ids; |
466 | ids.qtype = QType::A; | |
467 | ids.qclass = QClass::IN; | |
468 | ids.protocol = dnsdist::Protocol::DoUDP; | |
d5d15da1 | 469 | ids.queryRealTime.start(); // does not have to be accurate ("realTime") in tests |
0c8759d8 RG |
470 | bool dnssecOK = false; |
471 | ||
472 | try { | |
592b1d99 | 473 | ids.qname = DNSName("truncated"); |
0c8759d8 | 474 | PacketBuffer query; |
592b1d99 | 475 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0); |
0c8759d8 RG |
476 | pwQ.getHeader()->rd = 1; |
477 | ||
478 | PacketBuffer response; | |
592b1d99 | 479 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::A, QClass::IN, 0); |
0c8759d8 RG |
480 | pwR.getHeader()->rd = 1; |
481 | pwR.getHeader()->ra = 0; | |
482 | pwR.getHeader()->qr = 1; | |
483 | pwR.getHeader()->tc = 1; | |
484 | pwR.getHeader()->rcode = RCode::NoError; | |
485 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
486 | pwR.commit(); | |
592b1d99 | 487 | pwR.startRecord(ids.qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); |
0c8759d8 RG |
488 | pwR.xfr32BitInt(0x01020304); |
489 | pwR.commit(); | |
490 | ||
491 | uint32_t key = 0; | |
492 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
493 | DNSQuestion dnsQuestion(ids, query); |
494 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
0c8759d8 RG |
495 | BOOST_CHECK_EQUAL(found, false); |
496 | BOOST_CHECK(!subnet); | |
497 | ||
80a210f2 | 498 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none); |
0c8759d8 RG |
499 | |
500 | bool allowTruncated = true; | |
80a210f2 | 501 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated); |
0c8759d8 RG |
502 | BOOST_CHECK_EQUAL(found, true); |
503 | BOOST_CHECK(!subnet); | |
504 | ||
505 | allowTruncated = false; | |
80a210f2 | 506 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated); |
0c8759d8 RG |
507 | BOOST_CHECK_EQUAL(found, false); |
508 | } | |
509 | catch(const PDNSException& e) { | |
510 | cerr<<"Had error: "<<e.reason<<endl; | |
511 | throw; | |
512 | } | |
513 | } | |
514 | ||
7b71c89b RG |
515 | BOOST_AUTO_TEST_CASE(test_PacketCacheMaximumSize) { |
516 | const size_t maxEntries = 150000; | |
517 | DNSDistPacketCache packetCache(maxEntries, 86400, 1); | |
518 | InternalQueryState ids; | |
519 | ids.qtype = QType::A; | |
520 | ids.qclass = QClass::IN; | |
521 | ids.protocol = dnsdist::Protocol::DoUDP; | |
522 | ||
523 | ComboAddress remote; | |
524 | bool dnssecOK = false; | |
525 | ids.qname = DNSName("maximum.size"); | |
526 | ||
527 | PacketBuffer query; | |
528 | uint16_t queryID{0}; | |
529 | { | |
530 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::AAAA, QClass::IN, 0); | |
531 | pwQ.getHeader()->rd = 1; | |
532 | queryID = pwQ.getHeader()->id; | |
533 | } | |
534 | ||
535 | PacketBuffer response; | |
536 | { | |
537 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::AAAA, QClass::IN, 0); | |
538 | pwR.getHeader()->rd = 1; | |
539 | pwR.getHeader()->ra = 1; | |
540 | pwR.getHeader()->qr = 1; | |
541 | pwR.getHeader()->id = queryID; | |
542 | pwR.startRecord(ids.qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
80a210f2 RG |
543 | ComboAddress v6addr("2001:db8::1"); |
544 | pwR.xfrCAWithoutPort(6, v6addr); | |
7b71c89b RG |
545 | pwR.commit(); |
546 | } | |
547 | ||
548 | /* first, we set the maximum entry size to the response packet size */ | |
549 | packetCache.setMaximumEntrySize(response.size()); | |
550 | ||
551 | { | |
552 | /* UDP */ | |
553 | uint32_t key = 0; | |
554 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
555 | DNSQuestion dnsQuestion(ids, query); |
556 | bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
7b71c89b RG |
557 | BOOST_CHECK_EQUAL(found, false); |
558 | BOOST_CHECK(!subnet); | |
559 | ||
80a210f2 RG |
560 | packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); |
561 | found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
7b71c89b RG |
562 | BOOST_CHECK_EQUAL(found, true); |
563 | BOOST_CHECK(!subnet); | |
564 | } | |
565 | ||
566 | { | |
567 | /* same but over TCP */ | |
568 | uint32_t key = 0; | |
569 | boost::optional<Netmask> subnet; | |
570 | ids.protocol = dnsdist::Protocol::DoTCP; | |
80a210f2 RG |
571 | DNSQuestion dnsQuestion(ids, query); |
572 | bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); | |
7b71c89b RG |
573 | BOOST_CHECK_EQUAL(found, false); |
574 | BOOST_CHECK(!subnet); | |
575 | ||
80a210f2 RG |
576 | packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); |
577 | found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); | |
7b71c89b RG |
578 | BOOST_CHECK_EQUAL(found, true); |
579 | BOOST_CHECK(!subnet); | |
580 | } | |
581 | ||
582 | /* then we set it slightly below response packet size */ | |
583 | packetCache.expunge(0); | |
584 | packetCache.setMaximumEntrySize(response.size() - 1); | |
585 | { | |
586 | /* UDP */ | |
587 | uint32_t key = 0; | |
588 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
589 | DNSQuestion dnsQuestion(ids, query); |
590 | bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
7b71c89b RG |
591 | BOOST_CHECK_EQUAL(found, false); |
592 | BOOST_CHECK(!subnet); | |
593 | ||
80a210f2 RG |
594 | packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); |
595 | found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
7b71c89b RG |
596 | BOOST_CHECK_EQUAL(found, false); |
597 | } | |
598 | ||
599 | { | |
600 | /* same but over TCP */ | |
601 | uint32_t key = 0; | |
602 | boost::optional<Netmask> subnet; | |
603 | ids.protocol = dnsdist::Protocol::DoTCP; | |
80a210f2 RG |
604 | DNSQuestion dnsQuestion(ids, query); |
605 | bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); | |
7b71c89b RG |
606 | BOOST_CHECK_EQUAL(found, false); |
607 | BOOST_CHECK(!subnet); | |
608 | ||
80a210f2 RG |
609 | packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); |
610 | found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); | |
7b71c89b RG |
611 | BOOST_CHECK_EQUAL(found, false); |
612 | } | |
613 | ||
614 | /* now we generate a very big response packet, it should be cached over TCP and UDP (although in practice dnsdist will refuse to cache it for the UDP case) */ | |
615 | packetCache.expunge(0); | |
616 | response.clear(); | |
617 | { | |
618 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::AAAA, QClass::IN, 0); | |
619 | pwR.getHeader()->rd = 1; | |
620 | pwR.getHeader()->ra = 1; | |
621 | pwR.getHeader()->qr = 1; | |
622 | pwR.getHeader()->id = queryID; | |
623 | for (size_t idx = 0; idx < 1000; idx++) { | |
624 | pwR.startRecord(ids.qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
80a210f2 RG |
625 | ComboAddress v6addr("2001:db8::1"); |
626 | pwR.xfrCAWithoutPort(6, v6addr); | |
7b71c89b RG |
627 | } |
628 | pwR.commit(); | |
629 | } | |
630 | ||
631 | BOOST_REQUIRE_GT(response.size(), 4096U); | |
632 | packetCache.setMaximumEntrySize(response.size()); | |
633 | ||
634 | { | |
635 | /* UDP */ | |
636 | uint32_t key = 0; | |
637 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
638 | DNSQuestion dnsQuestion(ids, query); |
639 | bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
7b71c89b RG |
640 | BOOST_CHECK_EQUAL(found, false); |
641 | BOOST_CHECK(!subnet); | |
642 | ||
80a210f2 RG |
643 | packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); |
644 | found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
7b71c89b RG |
645 | BOOST_CHECK_EQUAL(found, true); |
646 | } | |
647 | ||
648 | { | |
649 | /* same but over TCP */ | |
650 | uint32_t key = 0; | |
651 | boost::optional<Netmask> subnet; | |
652 | ids.protocol = dnsdist::Protocol::DoTCP; | |
80a210f2 RG |
653 | DNSQuestion dnsQuestion(ids, query); |
654 | bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP); | |
7b71c89b RG |
655 | BOOST_CHECK_EQUAL(found, false); |
656 | BOOST_CHECK(!subnet); | |
657 | ||
80a210f2 RG |
658 | packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none); |
659 | found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true); | |
7b71c89b RG |
660 | BOOST_CHECK_EQUAL(found, true); |
661 | } | |
662 | } | |
663 | ||
dd026b9c | 664 | static DNSDistPacketCache g_PC(500000); |
886e2cf2 | 665 | |
f0941861 | 666 | static void threadMangler(unsigned int offset) |
886e2cf2 | 667 | { |
592b1d99 RG |
668 | InternalQueryState ids; |
669 | ids.qtype = QType::A; | |
670 | ids.qclass = QClass::IN; | |
671 | ids.protocol = dnsdist::Protocol::DoUDP; | |
592b1d99 | 672 | |
886e2cf2 | 673 | try { |
1ea747c0 | 674 | ComboAddress remote; |
d7728daf | 675 | bool dnssecOK = false; |
886e2cf2 | 676 | for(unsigned int counter=0; counter < 100000; ++counter) { |
592b1d99 | 677 | ids.qname = DNSName("hello ")+DNSName(std::to_string(counter+offset)); |
32fbb2ab | 678 | PacketBuffer query; |
592b1d99 | 679 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0); |
886e2cf2 RG |
680 | pwQ.getHeader()->rd = 1; |
681 | ||
32fbb2ab | 682 | PacketBuffer response; |
592b1d99 | 683 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::A, QClass::IN, 0); |
886e2cf2 RG |
684 | pwR.getHeader()->rd = 1; |
685 | pwR.getHeader()->ra = 1; | |
686 | pwR.getHeader()->qr = 1; | |
687 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
592b1d99 | 688 | pwR.startRecord(ids.qname, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER); |
886e2cf2 RG |
689 | pwR.xfr32BitInt(0x01020304); |
690 | pwR.commit(); | |
886e2cf2 | 691 | |
886e2cf2 | 692 | uint32_t key = 0; |
78e3ac9e | 693 | boost::optional<Netmask> subnet; |
80a210f2 RG |
694 | DNSQuestion dnsQuestion(ids, query); |
695 | g_PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
886e2cf2 | 696 | |
80a210f2 | 697 | g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); |
886e2cf2 RG |
698 | } |
699 | } | |
700 | catch(PDNSException& e) { | |
701 | cerr<<"Had error: "<<e.reason<<endl; | |
702 | throw; | |
703 | } | |
886e2cf2 RG |
704 | } |
705 | ||
706 | AtomicCounter g_missing; | |
707 | ||
f0941861 | 708 | static void threadReader(unsigned int offset) |
886e2cf2 | 709 | { |
592b1d99 RG |
710 | InternalQueryState ids; |
711 | ids.qtype = QType::A; | |
712 | ids.qclass = QClass::IN; | |
713 | ids.qname = DNSName("www.powerdns.com."); | |
714 | ids.protocol = dnsdist::Protocol::DoUDP; | |
592b1d99 | 715 | bool dnssecOK = false; |
886e2cf2 RG |
716 | try |
717 | { | |
1ea747c0 | 718 | ComboAddress remote; |
886e2cf2 | 719 | for(unsigned int counter=0; counter < 100000; ++counter) { |
592b1d99 | 720 | ids.qname = DNSName("hello ")+DNSName(std::to_string(counter+offset)); |
32fbb2ab | 721 | PacketBuffer query; |
592b1d99 | 722 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0); |
886e2cf2 RG |
723 | pwQ.getHeader()->rd = 1; |
724 | ||
886e2cf2 | 725 | uint32_t key = 0; |
78e3ac9e | 726 | boost::optional<Netmask> subnet; |
80a210f2 RG |
727 | DNSQuestion dnsQuestion(ids, query); |
728 | bool found = g_PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
886e2cf2 RG |
729 | if (!found) { |
730 | g_missing++; | |
731 | } | |
732 | } | |
733 | } | |
734 | catch(PDNSException& e) { | |
735 | cerr<<"Had error in threadReader: "<<e.reason<<endl; | |
736 | throw; | |
737 | } | |
886e2cf2 RG |
738 | } |
739 | ||
740 | BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) { | |
741 | try { | |
f0941861 RG |
742 | std::vector<std::thread> threads; |
743 | for (int i = 0; i < 4; ++i) { | |
744 | threads.push_back(std::thread(threadMangler, i*1000000UL)); | |
745 | } | |
746 | ||
747 | for (auto& t : threads) { | |
748 | t.join(); | |
749 | } | |
750 | ||
751 | threads.clear(); | |
886e2cf2 | 752 | |
690b86b7 | 753 | BOOST_CHECK_EQUAL(g_PC.getSize() + g_PC.getDeferredInserts() + g_PC.getInsertCollisions(), 400000U); |
dd026b9c | 754 | BOOST_CHECK_SMALL(1.0*g_PC.getInsertCollisions(), 10000.0); |
886e2cf2 | 755 | |
f0941861 RG |
756 | for (int i = 0; i < 4; ++i) { |
757 | threads.push_back(std::thread(threadReader, i*1000000UL)); | |
758 | } | |
759 | ||
760 | for (auto& t : threads) { | |
761 | t.join(); | |
762 | } | |
886e2cf2 | 763 | |
dd026b9c | 764 | BOOST_CHECK((g_PC.getDeferredInserts() + g_PC.getDeferredLookups() + g_PC.getInsertCollisions()) >= g_missing); |
886e2cf2 RG |
765 | } |
766 | catch(PDNSException& e) { | |
767 | cerr<<"Had error: "<<e.reason<<endl; | |
768 | throw; | |
769 | } | |
770 | ||
771 | } | |
772 | ||
78e3ac9e RG |
773 | BOOST_AUTO_TEST_CASE(test_PCCollision) { |
774 | const size_t maxEntries = 150000; | |
775 | DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true); | |
690b86b7 | 776 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); |
78e3ac9e | 777 | |
592b1d99 RG |
778 | InternalQueryState ids; |
779 | ids.qtype = QType::AAAA; | |
780 | ids.qclass = QClass::IN; | |
781 | ids.qname = DNSName("www.powerdns.com."); | |
782 | ids.protocol = dnsdist::Protocol::DoUDP; | |
78e3ac9e RG |
783 | uint16_t qid = 0x42; |
784 | uint32_t key; | |
785 | uint32_t secondKey; | |
786 | boost::optional<Netmask> subnetOut; | |
d7728daf | 787 | bool dnssecOK = false; |
78e3ac9e | 788 | |
fa980c59 | 789 | /* lookup for a query with a first ECS value, |
78e3ac9e RG |
790 | insert a corresponding response */ |
791 | { | |
32fbb2ab | 792 | PacketBuffer query; |
592b1d99 | 793 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, QClass::IN, 0); |
78e3ac9e RG |
794 | pwQ.getHeader()->rd = 1; |
795 | pwQ.getHeader()->id = qid; | |
32fbb2ab | 796 | GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions; |
78e3ac9e | 797 | EDNSSubnetOpts opt; |
fa980c59 | 798 | opt.source = Netmask("10.0.59.220/32"); |
e32a8d46 | 799 | ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); |
78e3ac9e RG |
800 | pwQ.addOpt(512, 0, 0, ednsOptions); |
801 | pwQ.commit(); | |
802 | ||
78e3ac9e | 803 | ComboAddress remote("192.0.2.1"); |
d5d15da1 | 804 | ids.queryRealTime.start(); |
80a210f2 RG |
805 | DNSQuestion dnsQuestion(ids, query); |
806 | bool found = PC.get(dnsQuestion, 0, &key, subnetOut, dnssecOK, receivedOverUDP); | |
78e3ac9e RG |
807 | BOOST_CHECK_EQUAL(found, false); |
808 | BOOST_REQUIRE(subnetOut); | |
809 | BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); | |
810 | ||
32fbb2ab | 811 | PacketBuffer response; |
592b1d99 | 812 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, ids.qtype, QClass::IN, 0); |
78e3ac9e RG |
813 | pwR.getHeader()->rd = 1; |
814 | pwR.getHeader()->id = qid; | |
592b1d99 | 815 | pwR.startRecord(ids.qname, ids.qtype, 100, QClass::IN, DNSResourceRecord::ANSWER); |
80a210f2 RG |
816 | ComboAddress v6addr("::1"); |
817 | pwR.xfrCAWithoutPort(6, v6addr); | |
78e3ac9e RG |
818 | pwR.commit(); |
819 | pwR.addOpt(512, 0, 0, ednsOptions); | |
820 | pwR.commit(); | |
821 | ||
592b1d99 | 822 | PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, ids.qname, ids.qtype, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); |
690b86b7 | 823 | BOOST_CHECK_EQUAL(PC.getSize(), 1U); |
78e3ac9e | 824 | |
80a210f2 | 825 | found = PC.get(dnsQuestion, 0, &key, subnetOut, dnssecOK, receivedOverUDP); |
78e3ac9e RG |
826 | BOOST_CHECK_EQUAL(found, true); |
827 | BOOST_REQUIRE(subnetOut); | |
828 | BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); | |
829 | } | |
830 | ||
fa980c59 | 831 | /* now lookup for the same query with a different ECS value, |
78e3ac9e RG |
832 | we should get the same key (collision) but no match */ |
833 | { | |
32fbb2ab | 834 | PacketBuffer query; |
592b1d99 | 835 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, QClass::IN, 0); |
78e3ac9e RG |
836 | pwQ.getHeader()->rd = 1; |
837 | pwQ.getHeader()->id = qid; | |
32fbb2ab | 838 | GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions; |
78e3ac9e | 839 | EDNSSubnetOpts opt; |
fa980c59 | 840 | opt.source = Netmask("10.0.167.48/32"); |
e32a8d46 | 841 | ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); |
78e3ac9e RG |
842 | pwQ.addOpt(512, 0, 0, ednsOptions); |
843 | pwQ.commit(); | |
844 | ||
78e3ac9e | 845 | ComboAddress remote("192.0.2.1"); |
d5d15da1 | 846 | ids.queryRealTime.start(); |
80a210f2 RG |
847 | DNSQuestion dnsQuestion(ids, query); |
848 | bool found = PC.get(dnsQuestion, 0, &secondKey, subnetOut, dnssecOK, receivedOverUDP); | |
78e3ac9e RG |
849 | BOOST_CHECK_EQUAL(found, false); |
850 | BOOST_CHECK_EQUAL(secondKey, key); | |
851 | BOOST_REQUIRE(subnetOut); | |
852 | BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); | |
690b86b7 | 853 | BOOST_CHECK_EQUAL(PC.getLookupCollisions(), 1U); |
78e3ac9e | 854 | } |
fa980c59 RG |
855 | |
856 | #if 0 | |
857 | /* to be able to compute a new collision if the packet cache hashing code is updated */ | |
858 | { | |
859 | DNSDistPacketCache pc(10000); | |
32fbb2ab | 860 | GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions; |
fa980c59 RG |
861 | EDNSSubnetOpts opt; |
862 | std::map<uint32_t, Netmask> colMap; | |
863 | size_t collisions = 0; | |
864 | size_t total = 0; | |
865 | //qname = DNSName("collision-with-ecs-parsing.cache.tests.powerdns.com."); | |
866 | ||
867 | for (size_t idxA = 0; idxA < 256; idxA++) { | |
868 | for (size_t idxB = 0; idxB < 256; idxB++) { | |
869 | for (size_t idxC = 0; idxC < 256; idxC++) { | |
32fbb2ab | 870 | PacketBuffer secondQuery; |
592b1d99 | 871 | GenericDNSPacketWriter<PacketBuffer> pwFQ(secondQuery, ids.qname, QType::AAAA, QClass::IN, 0); |
fa980c59 RG |
872 | pwFQ.getHeader()->rd = 1; |
873 | pwFQ.getHeader()->qr = false; | |
874 | pwFQ.getHeader()->id = 0x42; | |
875 | opt.source = Netmask("10." + std::to_string(idxA) + "." + std::to_string(idxB) + "." + std::to_string(idxC) + "/32"); | |
876 | ednsOptions.clear(); | |
e32a8d46 | 877 | ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); |
fa980c59 RG |
878 | pwFQ.addOpt(512, 0, 0, ednsOptions); |
879 | pwFQ.commit(); | |
592b1d99 | 880 | secondKey = pc.getKey(ids.qname.toDNSString(), ids.qname.wirelength(), secondQuery, false); |
e32a8d46 | 881 | auto pair = colMap.emplace(secondKey, opt.source); |
fa980c59 RG |
882 | total++; |
883 | if (!pair.second) { | |
884 | collisions++; | |
885 | cerr<<"Collision between "<<colMap[secondKey].toString()<<" and "<<opt.source.toString()<<" for key "<<secondKey<<endl; | |
886 | goto done; | |
887 | } | |
888 | } | |
889 | } | |
890 | } | |
891 | done: | |
892 | cerr<<"collisions: "<<collisions<<endl; | |
893 | cerr<<"total: "<<total<<endl; | |
894 | } | |
895 | #endif | |
78e3ac9e RG |
896 | } |
897 | ||
d7728daf RG |
898 | BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) { |
899 | const size_t maxEntries = 150000; | |
900 | DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true); | |
690b86b7 | 901 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); |
d7728daf | 902 | |
592b1d99 RG |
903 | InternalQueryState ids; |
904 | ids.qtype = QType::AAAA; | |
905 | ids.qclass = QClass::IN; | |
906 | ids.qname = DNSName("www.powerdns.com."); | |
907 | ids.protocol = dnsdist::Protocol::DoUDP; | |
d7728daf RG |
908 | uint16_t qid = 0x42; |
909 | uint32_t key; | |
910 | boost::optional<Netmask> subnetOut; | |
911 | ||
912 | /* lookup for a query with DNSSEC OK, | |
913 | insert a corresponding response with DO set, | |
914 | check that it doesn't match without DO, but does with it */ | |
915 | { | |
32fbb2ab | 916 | PacketBuffer query; |
592b1d99 | 917 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, QClass::IN, 0); |
d7728daf RG |
918 | pwQ.getHeader()->rd = 1; |
919 | pwQ.getHeader()->id = qid; | |
920 | pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO); | |
921 | pwQ.commit(); | |
922 | ||
d7728daf | 923 | ComboAddress remote("192.0.2.1"); |
d5d15da1 | 924 | ids.queryRealTime.start(); |
592b1d99 | 925 | ids.origRemote = remote; |
80a210f2 RG |
926 | DNSQuestion dnsQuestion(ids, query); |
927 | bool found = PC.get(dnsQuestion, 0, &key, subnetOut, true, receivedOverUDP); | |
d7728daf RG |
928 | BOOST_CHECK_EQUAL(found, false); |
929 | ||
32fbb2ab | 930 | PacketBuffer response; |
592b1d99 | 931 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, ids.qtype, QClass::IN, 0); |
d7728daf RG |
932 | pwR.getHeader()->rd = 1; |
933 | pwR.getHeader()->id = qid; | |
592b1d99 | 934 | pwR.startRecord(ids.qname, ids.qtype, 100, QClass::IN, DNSResourceRecord::ANSWER); |
80a210f2 RG |
935 | ComboAddress v6addr("::1"); |
936 | pwR.xfrCAWithoutPort(6, v6addr); | |
d7728daf RG |
937 | pwR.commit(); |
938 | pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO); | |
939 | pwR.commit(); | |
940 | ||
592b1d99 | 941 | PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, ids.qname, ids.qtype, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none); |
690b86b7 | 942 | BOOST_CHECK_EQUAL(PC.getSize(), 1U); |
d7728daf | 943 | |
80a210f2 | 944 | found = PC.get(dnsQuestion, 0, &key, subnetOut, false, receivedOverUDP); |
d7728daf RG |
945 | BOOST_CHECK_EQUAL(found, false); |
946 | ||
80a210f2 | 947 | found = PC.get(dnsQuestion, 0, &key, subnetOut, true, receivedOverUDP); |
d7728daf RG |
948 | BOOST_CHECK_EQUAL(found, true); |
949 | } | |
950 | ||
951 | } | |
952 | ||
fec4382e RG |
953 | BOOST_AUTO_TEST_CASE(test_PacketCacheInspection) { |
954 | const size_t maxEntries = 100; | |
955 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
956 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); | |
fec4382e RG |
957 | |
958 | ComboAddress remote; | |
959 | bool dnssecOK = false; | |
960 | ||
961 | uint32_t key = 0; | |
962 | ||
963 | /* insert powerdns.com A 192.0.2.1, 192.0.2.2 */ | |
964 | { | |
965 | DNSName qname("powerdns.com"); | |
966 | PacketBuffer query; | |
967 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0); | |
968 | pwQ.getHeader()->rd = 1; | |
969 | ||
970 | PacketBuffer response; | |
971 | GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0); | |
972 | pwR.getHeader()->rd = 1; | |
973 | pwR.getHeader()->ra = 1; | |
974 | pwR.getHeader()->qr = 1; | |
975 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
976 | { | |
977 | ComboAddress addr("192.0.2.1"); | |
978 | pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
979 | pwR.xfrCAWithoutPort(4, addr); | |
980 | pwR.commit(); | |
981 | } | |
982 | { | |
983 | ComboAddress addr("192.0.2.2"); | |
984 | pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
985 | pwR.xfrCAWithoutPort(4, addr); | |
986 | pwR.commit(); | |
987 | } | |
988 | ||
989 | PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); | |
990 | BOOST_CHECK_EQUAL(PC.getSize(), key); | |
991 | } | |
992 | ||
993 | /* insert powerdns1.com A 192.0.2.3, 192.0.2.4, AAAA 2001:db8::3, 2001:db8::4 */ | |
994 | { | |
995 | DNSName qname("powerdns1.com"); | |
996 | PacketBuffer query; | |
997 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0); | |
998 | pwQ.getHeader()->rd = 1; | |
999 | ||
1000 | PacketBuffer response; | |
1001 | GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0); | |
1002 | pwR.getHeader()->rd = 1; | |
1003 | pwR.getHeader()->ra = 1; | |
1004 | pwR.getHeader()->qr = 1; | |
1005 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
1006 | { | |
1007 | ComboAddress addr("192.0.2.3"); | |
1008 | pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
1009 | pwR.xfrCAWithoutPort(4, addr); | |
1010 | pwR.commit(); | |
1011 | } | |
1012 | { | |
1013 | ComboAddress addr("192.0.2.4"); | |
1014 | pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
1015 | pwR.xfrCAWithoutPort(4, addr); | |
1016 | pwR.commit(); | |
1017 | } | |
1018 | { | |
1019 | ComboAddress addr("2001:db8::3"); | |
1020 | pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL); | |
1021 | pwR.xfrCAWithoutPort(6, addr); | |
1022 | pwR.commit(); | |
1023 | } | |
1024 | { | |
1025 | ComboAddress addr("2001:db8::4"); | |
1026 | pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL); | |
1027 | pwR.xfrCAWithoutPort(6, addr); | |
1028 | pwR.commit(); | |
1029 | } | |
1030 | ||
1031 | PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); | |
1032 | BOOST_CHECK_EQUAL(PC.getSize(), key); | |
1033 | } | |
1034 | ||
1035 | /* insert powerdns2.com NODATA */ | |
1036 | { | |
1037 | DNSName qname("powerdns2.com"); | |
1038 | PacketBuffer query; | |
1039 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0); | |
1040 | pwQ.getHeader()->rd = 1; | |
1041 | ||
1042 | PacketBuffer response; | |
1043 | GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0); | |
1044 | pwR.getHeader()->rd = 1; | |
1045 | pwR.getHeader()->ra = 1; | |
1046 | pwR.getHeader()->qr = 1; | |
1047 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
1048 | pwR.commit(); | |
1049 | pwR.startRecord(qname, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY); | |
1050 | pwR.commit(); | |
1051 | pwR.addOpt(4096, 0, 0); | |
1052 | pwR.commit(); | |
1053 | ||
1054 | PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); | |
1055 | BOOST_CHECK_EQUAL(PC.getSize(), key); | |
1056 | } | |
1057 | ||
1058 | /* insert powerdns3.com AAAA 2001:db8::4, 2001:db8::5 */ | |
1059 | { | |
1060 | DNSName qname("powerdns3.com"); | |
1061 | PacketBuffer query; | |
1062 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0); | |
1063 | pwQ.getHeader()->rd = 1; | |
1064 | ||
1065 | PacketBuffer response; | |
1066 | GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0); | |
1067 | pwR.getHeader()->rd = 1; | |
1068 | pwR.getHeader()->ra = 1; | |
1069 | pwR.getHeader()->qr = 1; | |
1070 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
1071 | { | |
1072 | ComboAddress addr("2001:db8::4"); | |
1073 | pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL); | |
1074 | pwR.xfrCAWithoutPort(6, addr); | |
1075 | pwR.commit(); | |
1076 | } | |
1077 | { | |
1078 | ComboAddress addr("2001:db8::5"); | |
1079 | pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL); | |
1080 | pwR.xfrCAWithoutPort(6, addr); | |
1081 | pwR.commit(); | |
1082 | } | |
1083 | ||
1084 | PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); | |
1085 | BOOST_CHECK_EQUAL(PC.getSize(), key); | |
1086 | } | |
1087 | ||
1088 | /* insert powerdns4.com A 192.0.2.1 */ | |
1089 | { | |
1090 | DNSName qname("powerdns4.com"); | |
1091 | PacketBuffer query; | |
1092 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0); | |
1093 | pwQ.getHeader()->rd = 1; | |
1094 | ||
1095 | PacketBuffer response; | |
1096 | GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0); | |
1097 | pwR.getHeader()->rd = 1; | |
1098 | pwR.getHeader()->ra = 1; | |
1099 | pwR.getHeader()->qr = 1; | |
1100 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
1101 | { | |
1102 | ComboAddress addr("192.0.2.1"); | |
1103 | pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL); | |
1104 | pwR.xfrCAWithoutPort(4, addr); | |
1105 | pwR.commit(); | |
1106 | } | |
1107 | ||
1108 | PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none); | |
1109 | BOOST_CHECK_EQUAL(PC.getSize(), key); | |
1110 | } | |
1111 | ||
1112 | { | |
1113 | auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.1")); | |
1114 | BOOST_CHECK_EQUAL(domains.size(), 2U); | |
1115 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns.com")), 1U); | |
1116 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns4.com")), 1U); | |
1117 | } | |
1118 | { | |
1119 | auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.2")); | |
1120 | BOOST_CHECK_EQUAL(domains.size(), 1U); | |
1121 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns.com")), 1U); | |
1122 | } | |
1123 | { | |
1124 | auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.3")); | |
1125 | BOOST_CHECK_EQUAL(domains.size(), 1U); | |
1126 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U); | |
1127 | } | |
1128 | { | |
1129 | auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.4")); | |
1130 | BOOST_CHECK_EQUAL(domains.size(), 1U); | |
1131 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U); | |
1132 | } | |
1133 | { | |
1134 | auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.5")); | |
1135 | BOOST_CHECK_EQUAL(domains.size(), 0U); | |
1136 | } | |
1137 | { | |
1138 | auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::3")); | |
1139 | BOOST_CHECK_EQUAL(domains.size(), 1U); | |
1140 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U); | |
1141 | } | |
1142 | { | |
1143 | auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::4")); | |
1144 | BOOST_CHECK_EQUAL(domains.size(), 2U); | |
1145 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U); | |
1146 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns3.com")), 1U); | |
1147 | } | |
1148 | { | |
1149 | auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::5")); | |
1150 | BOOST_CHECK_EQUAL(domains.size(), 1U); | |
1151 | BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns3.com")), 1U); | |
1152 | } | |
1153 | ||
1154 | { | |
1155 | auto records = PC.getRecordsForDomain(DNSName("powerdns.com")); | |
1156 | BOOST_CHECK_EQUAL(records.size(), 2U); | |
1157 | BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.1")), 1U); | |
1158 | BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.2")), 1U); | |
1159 | } | |
1160 | ||
1161 | { | |
1162 | auto records = PC.getRecordsForDomain(DNSName("powerdns1.com")); | |
1163 | BOOST_CHECK_EQUAL(records.size(), 4U); | |
1164 | BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.3")), 1U); | |
1165 | BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.4")), 1U); | |
1166 | BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::3")), 1U); | |
1167 | BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U); | |
1168 | } | |
1169 | ||
1170 | { | |
1171 | auto records = PC.getRecordsForDomain(DNSName("powerdns2.com")); | |
1172 | BOOST_CHECK_EQUAL(records.size(), 0U); | |
1173 | } | |
1174 | ||
1175 | { | |
1176 | auto records = PC.getRecordsForDomain(DNSName("powerdns3.com")); | |
1177 | BOOST_CHECK_EQUAL(records.size(), 2U); | |
1178 | BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U); | |
1179 | BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U); | |
1180 | } | |
1181 | ||
1182 | { | |
1183 | auto records = PC.getRecordsForDomain(DNSName("powerdns4.com")); | |
1184 | BOOST_CHECK_EQUAL(records.size(), 1U); | |
1185 | BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.1")), 1U); | |
1186 | } | |
1187 | ||
1188 | { | |
1189 | auto records = PC.getRecordsForDomain(DNSName("powerdns5.com")); | |
1190 | BOOST_CHECK_EQUAL(records.size(), 0U); | |
1191 | } | |
1192 | } | |
1193 | ||
8eff5c8d RG |
1194 | BOOST_AUTO_TEST_CASE(test_PacketCacheXFR) { |
1195 | const size_t maxEntries = 150000; | |
1196 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
1197 | BOOST_CHECK_EQUAL(PC.getSize(), 0U); | |
1198 | ||
1199 | const std::set<QType> xfrTypes = { QType::AXFR, QType::IXFR }; | |
1200 | for (const auto& type : xfrTypes) { | |
1201 | bool dnssecOK = false; | |
8eff5c8d RG |
1202 | InternalQueryState ids; |
1203 | ids.qtype = type; | |
1204 | ids.qclass = QClass::IN; | |
1205 | ids.protocol = dnsdist::Protocol::DoUDP; | |
1206 | ids.qname = DNSName("powerdns.com."); | |
1207 | ||
1208 | PacketBuffer query; | |
1209 | GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, ids.qclass, 0); | |
1210 | pwQ.getHeader()->rd = 1; | |
1211 | ||
1212 | PacketBuffer response; | |
1213 | GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, ids.qtype, ids.qclass, 0); | |
1214 | pwR.getHeader()->rd = 1; | |
1215 | pwR.getHeader()->ra = 1; | |
1216 | pwR.getHeader()->qr = 1; | |
1217 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
1218 | pwR.startRecord(ids.qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); | |
1219 | pwR.xfr32BitInt(0x01020304); | |
1220 | pwR.commit(); | |
1221 | ||
1222 | uint32_t key = 0; | |
1223 | boost::optional<Netmask> subnet; | |
80a210f2 RG |
1224 | DNSQuestion dnsQuestion(ids, query); |
1225 | bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP); | |
8eff5c8d RG |
1226 | BOOST_CHECK_EQUAL(found, false); |
1227 | BOOST_CHECK(!subnet); | |
1228 | ||
80a210f2 RG |
1229 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, ids.qtype, ids.qclass, response, receivedOverUDP, 0, boost::none); |
1230 | found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true); | |
8eff5c8d RG |
1231 | BOOST_CHECK_EQUAL(found, false); |
1232 | } | |
1233 | } | |
1234 | ||
886e2cf2 | 1235 | BOOST_AUTO_TEST_SUITE_END() |