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