]>
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" |
886e2cf2 | 14 | |
c7f29d3e | 15 | BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc) |
886e2cf2 RG |
16 | |
17 | BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) { | |
18 | const size_t maxEntries = 150000; | |
19 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
20 | BOOST_CHECK_EQUAL(PC.getSize(), 0); | |
5ffb2f83 CH |
21 | struct timespec queryTime; |
22 | gettime(&queryTime); // does not have to be accurate ("realTime") in tests | |
886e2cf2 RG |
23 | |
24 | size_t counter=0; | |
25 | size_t skipped=0; | |
1ea747c0 | 26 | ComboAddress remote; |
d7728daf | 27 | bool dnssecOK = false; |
886e2cf2 RG |
28 | try { |
29 | for(counter = 0; counter < 100000; ++counter) { | |
490dc586 | 30 | DNSName a=DNSName(std::to_string(counter))+DNSName(" hello"); |
886e2cf2 RG |
31 | BOOST_CHECK_EQUAL(DNSName(a.toString()), a); |
32 | ||
33 | vector<uint8_t> query; | |
34 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
35 | pwQ.getHeader()->rd = 1; | |
36 | ||
37 | vector<uint8_t> response; | |
38 | DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); | |
39 | pwR.getHeader()->rd = 1; | |
40 | pwR.getHeader()->ra = 1; | |
41 | pwR.getHeader()->qr = 1; | |
42 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
f627611d | 43 | pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER); |
886e2cf2 RG |
44 | pwR.xfr32BitInt(0x01020304); |
45 | pwR.commit(); | |
46 | uint16_t responseLen = response.size(); | |
47 | ||
48 | char responseBuf[4096]; | |
49 | uint16_t responseBufSize = sizeof(responseBuf); | |
50 | uint32_t key = 0; | |
78e3ac9e | 51 | boost::optional<Netmask> subnet; |
8dcdbdb1 | 52 | auto dh = reinterpret_cast<dnsheader*>(query.data()); |
e7c732b8 | 53 | DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime); |
d7728daf | 54 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK); |
886e2cf2 | 55 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 56 | BOOST_CHECK(!subnet); |
886e2cf2 | 57 | |
d7728daf | 58 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none); |
886e2cf2 | 59 | |
d7728daf | 60 | found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true); |
886e2cf2 RG |
61 | if (found == true) { |
62 | BOOST_CHECK_EQUAL(responseBufSize, responseLen); | |
63 | int match = memcmp(responseBuf, response.data(), responseLen); | |
64 | BOOST_CHECK_EQUAL(match, 0); | |
78e3ac9e | 65 | BOOST_CHECK(!subnet); |
886e2cf2 RG |
66 | } |
67 | else { | |
68 | skipped++; | |
69 | } | |
70 | } | |
71 | ||
72 | BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions()); | |
73 | BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped); | |
74 | ||
75 | size_t deleted=0; | |
76 | size_t delcounter=0; | |
77 | for(delcounter=0; delcounter < counter/1000; ++delcounter) { | |
490dc586 | 78 | DNSName a=DNSName(std::to_string(delcounter))+DNSName(" hello"); |
886e2cf2 RG |
79 | vector<uint8_t> query; |
80 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
81 | pwQ.getHeader()->rd = 1; | |
82 | char responseBuf[4096]; | |
83 | uint16_t responseBufSize = sizeof(responseBuf); | |
84 | uint32_t key = 0; | |
78e3ac9e | 85 | boost::optional<Netmask> subnet; |
e7c732b8 | 86 | DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime); |
d7728daf | 87 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK); |
886e2cf2 | 88 | if (found == true) { |
f627611d RG |
89 | auto removed = PC.expungeByName(a); |
90 | BOOST_CHECK_EQUAL(removed, 1); | |
91 | deleted += removed; | |
886e2cf2 RG |
92 | } |
93 | } | |
94 | BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted); | |
95 | ||
96 | size_t matches=0; | |
97 | vector<DNSResourceRecord> entry; | |
98 | size_t expected=counter-skipped-deleted; | |
99 | for(; delcounter < counter; ++delcounter) { | |
490dc586 | 100 | DNSName a(DNSName(std::to_string(delcounter))+DNSName(" hello")); |
886e2cf2 RG |
101 | vector<uint8_t> query; |
102 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
103 | pwQ.getHeader()->rd = 1; | |
104 | uint16_t len = query.size(); | |
105 | uint32_t key = 0; | |
78e3ac9e | 106 | boost::optional<Netmask> subnet; |
886e2cf2 RG |
107 | char response[4096]; |
108 | uint16_t responseSize = sizeof(response); | |
e7c732b8 | 109 | DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), len, query.size(), false, &queryTime); |
d7728daf | 110 | if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key, subnet, dnssecOK)) { |
490dc586 | 111 | matches++; |
886e2cf2 RG |
112 | } |
113 | } | |
490dc586 | 114 | |
6d1a9248 | 115 | /* in the unlikely event that the test took so long that the entries did expire.. */ |
f627611d RG |
116 | auto expired = PC.purgeExpired(); |
117 | BOOST_CHECK_EQUAL(matches + expired, expected); | |
118 | ||
119 | auto remaining = PC.getSize(); | |
120 | auto removed = PC.expungeByName(DNSName(" hello"), QType::ANY, true); | |
490dc586 | 121 | BOOST_CHECK_EQUAL(PC.getSize(), 0); |
f627611d | 122 | BOOST_CHECK_EQUAL(removed, remaining); |
886e2cf2 RG |
123 | } |
124 | catch(PDNSException& e) { | |
125 | cerr<<"Had error: "<<e.reason<<endl; | |
126 | throw; | |
127 | } | |
128 | } | |
129 | ||
acb8f5d5 CH |
130 | BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) { |
131 | const size_t maxEntries = 150000; | |
132 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
5ffb2f83 CH |
133 | struct timespec queryTime; |
134 | gettime(&queryTime); // does not have to be accurate ("realTime") in tests | |
acb8f5d5 CH |
135 | |
136 | ComboAddress remote; | |
d7728daf | 137 | bool dnssecOK = false; |
acb8f5d5 CH |
138 | try { |
139 | DNSName a = DNSName("servfail"); | |
140 | BOOST_CHECK_EQUAL(DNSName(a.toString()), a); | |
141 | ||
142 | vector<uint8_t> query; | |
143 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
144 | pwQ.getHeader()->rd = 1; | |
145 | ||
146 | vector<uint8_t> response; | |
147 | DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); | |
148 | pwR.getHeader()->rd = 1; | |
149 | pwR.getHeader()->ra = 0; | |
150 | pwR.getHeader()->qr = 1; | |
151 | pwR.getHeader()->rcode = RCode::ServFail; | |
152 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
153 | pwR.commit(); | |
154 | uint16_t responseLen = response.size(); | |
155 | ||
156 | char responseBuf[4096]; | |
157 | uint16_t responseBufSize = sizeof(responseBuf); | |
158 | uint32_t key = 0; | |
78e3ac9e | 159 | boost::optional<Netmask> subnet; |
8dcdbdb1 | 160 | auto dh = reinterpret_cast<dnsheader*>(query.data()); |
e7c732b8 | 161 | DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime); |
d7728daf | 162 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK); |
acb8f5d5 | 163 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 164 | BOOST_CHECK(!subnet); |
acb8f5d5 CH |
165 | |
166 | // Insert with failure-TTL of 0 (-> should not enter cache). | |
d7728daf RG |
167 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(0)); |
168 | found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true); | |
acb8f5d5 | 169 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 170 | BOOST_CHECK(!subnet); |
acb8f5d5 | 171 | |
56459632 | 172 | // Insert with failure-TTL non-zero (-> should enter cache). |
d7728daf RG |
173 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(300)); |
174 | found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true); | |
acb8f5d5 | 175 | BOOST_CHECK_EQUAL(found, true); |
78e3ac9e | 176 | BOOST_CHECK(!subnet); |
acb8f5d5 CH |
177 | } |
178 | catch(PDNSException& e) { | |
179 | cerr<<"Had error: "<<e.reason<<endl; | |
180 | throw; | |
181 | } | |
182 | } | |
183 | ||
47698274 RG |
184 | BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) { |
185 | const size_t maxEntries = 150000; | |
186 | DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); | |
187 | ||
188 | struct timespec queryTime; | |
189 | gettime(&queryTime); // does not have to be accurate ("realTime") in tests | |
190 | ||
191 | ComboAddress remote; | |
d7728daf | 192 | bool dnssecOK = false; |
47698274 RG |
193 | try { |
194 | DNSName name("nodata"); | |
195 | vector<uint8_t> query; | |
196 | DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0); | |
197 | pwQ.getHeader()->rd = 1; | |
198 | ||
199 | vector<uint8_t> response; | |
200 | DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0); | |
201 | pwR.getHeader()->rd = 1; | |
202 | pwR.getHeader()->ra = 0; | |
203 | pwR.getHeader()->qr = 1; | |
204 | pwR.getHeader()->rcode = RCode::NoError; | |
205 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
206 | pwR.commit(); | |
207 | pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY); | |
208 | pwR.commit(); | |
209 | pwR.addOpt(4096, 0, 0); | |
210 | pwR.commit(); | |
211 | ||
212 | uint16_t responseLen = response.size(); | |
213 | ||
214 | char responseBuf[4096]; | |
215 | uint16_t responseBufSize = sizeof(responseBuf); | |
216 | uint32_t key = 0; | |
78e3ac9e | 217 | boost::optional<Netmask> subnet; |
8dcdbdb1 | 218 | auto dh = reinterpret_cast<dnsheader*>(query.data()); |
e7c732b8 | 219 | DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime); |
d7728daf | 220 | bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK); |
47698274 | 221 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 222 | BOOST_CHECK(!subnet); |
47698274 | 223 | |
d7728daf RG |
224 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NoError, boost::none); |
225 | found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true); | |
47698274 | 226 | BOOST_CHECK_EQUAL(found, true); |
78e3ac9e RG |
227 | BOOST_CHECK(!subnet); |
228 | ||
47698274 RG |
229 | sleep(2); |
230 | /* it should have expired by now */ | |
d7728daf | 231 | found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true); |
47698274 | 232 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 233 | BOOST_CHECK(!subnet); |
47698274 RG |
234 | } |
235 | catch(const PDNSException& e) { | |
236 | cerr<<"Had error: "<<e.reason<<endl; | |
237 | throw; | |
238 | } | |
239 | } | |
240 | ||
241 | BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) { | |
242 | const size_t maxEntries = 150000; | |
243 | DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1); | |
244 | ||
245 | struct timespec queryTime; | |
246 | gettime(&queryTime); // does not have to be accurate ("realTime") in tests | |
247 | ||
248 | ComboAddress remote; | |
d7728daf | 249 | bool dnssecOK = false; |
47698274 RG |
250 | try { |
251 | DNSName name("nxdomain"); | |
252 | vector<uint8_t> query; | |
253 | DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0); | |
254 | pwQ.getHeader()->rd = 1; | |
255 | ||
256 | vector<uint8_t> response; | |
257 | DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0); | |
258 | pwR.getHeader()->rd = 1; | |
259 | pwR.getHeader()->ra = 0; | |
260 | pwR.getHeader()->qr = 1; | |
261 | pwR.getHeader()->rcode = RCode::NXDomain; | |
262 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
263 | pwR.commit(); | |
264 | pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY); | |
265 | pwR.commit(); | |
266 | pwR.addOpt(4096, 0, 0); | |
267 | pwR.commit(); | |
268 | ||
269 | uint16_t responseLen = response.size(); | |
270 | ||
271 | char responseBuf[4096]; | |
272 | uint16_t responseBufSize = sizeof(responseBuf); | |
273 | uint32_t key = 0; | |
78e3ac9e | 274 | boost::optional<Netmask> subnet; |
8dcdbdb1 | 275 | auto dh = reinterpret_cast<dnsheader*>(query.data()); |
e7c732b8 | 276 | DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime); |
d7728daf | 277 | bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK); |
47698274 | 278 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 279 | BOOST_CHECK(!subnet); |
47698274 | 280 | |
d7728daf RG |
281 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NXDomain, boost::none); |
282 | found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true); | |
47698274 | 283 | BOOST_CHECK_EQUAL(found, true); |
78e3ac9e RG |
284 | BOOST_CHECK(!subnet); |
285 | ||
47698274 RG |
286 | sleep(2); |
287 | /* it should have expired by now */ | |
d7728daf | 288 | found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true); |
47698274 | 289 | BOOST_CHECK_EQUAL(found, false); |
78e3ac9e | 290 | BOOST_CHECK(!subnet); |
47698274 RG |
291 | } |
292 | catch(const PDNSException& e) { | |
293 | cerr<<"Had error: "<<e.reason<<endl; | |
294 | throw; | |
295 | } | |
296 | } | |
297 | ||
886e2cf2 RG |
298 | static DNSDistPacketCache PC(500000); |
299 | ||
af619119 | 300 | static void *threadMangler(void* off) |
886e2cf2 | 301 | { |
5ffb2f83 CH |
302 | struct timespec queryTime; |
303 | gettime(&queryTime); // does not have to be accurate ("realTime") in tests | |
886e2cf2 | 304 | try { |
1ea747c0 | 305 | ComboAddress remote; |
d7728daf | 306 | bool dnssecOK = false; |
af619119 | 307 | unsigned int offset=(unsigned int)(unsigned long)off; |
886e2cf2 RG |
308 | for(unsigned int counter=0; counter < 100000; ++counter) { |
309 | DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset)); | |
310 | vector<uint8_t> query; | |
311 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
312 | pwQ.getHeader()->rd = 1; | |
313 | ||
314 | vector<uint8_t> response; | |
315 | DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); | |
316 | pwR.getHeader()->rd = 1; | |
317 | pwR.getHeader()->ra = 1; | |
318 | pwR.getHeader()->qr = 1; | |
319 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
320 | pwR.startRecord(a, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER); | |
321 | pwR.xfr32BitInt(0x01020304); | |
322 | pwR.commit(); | |
323 | uint16_t responseLen = response.size(); | |
324 | ||
325 | char responseBuf[4096]; | |
326 | uint16_t responseBufSize = sizeof(responseBuf); | |
327 | uint32_t key = 0; | |
78e3ac9e | 328 | boost::optional<Netmask> subnet; |
8dcdbdb1 | 329 | auto dh = reinterpret_cast<dnsheader*>(query.data()); |
e7c732b8 | 330 | DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime); |
d7728daf | 331 | PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK); |
886e2cf2 | 332 | |
d7728daf | 333 | PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none); |
886e2cf2 RG |
334 | } |
335 | } | |
336 | catch(PDNSException& e) { | |
337 | cerr<<"Had error: "<<e.reason<<endl; | |
338 | throw; | |
339 | } | |
340 | return 0; | |
341 | } | |
342 | ||
343 | AtomicCounter g_missing; | |
344 | ||
af619119 | 345 | static void *threadReader(void* off) |
886e2cf2 | 346 | { |
d7728daf | 347 | bool dnssecOK = false; |
5ffb2f83 CH |
348 | struct timespec queryTime; |
349 | gettime(&queryTime); // does not have to be accurate ("realTime") in tests | |
886e2cf2 RG |
350 | try |
351 | { | |
af619119 | 352 | unsigned int offset=(unsigned int)(unsigned long)off; |
886e2cf2 | 353 | vector<DNSResourceRecord> entry; |
1ea747c0 | 354 | ComboAddress remote; |
886e2cf2 RG |
355 | for(unsigned int counter=0; counter < 100000; ++counter) { |
356 | DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset)); | |
357 | vector<uint8_t> query; | |
358 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
359 | pwQ.getHeader()->rd = 1; | |
360 | ||
361 | char responseBuf[4096]; | |
362 | uint16_t responseBufSize = sizeof(responseBuf); | |
363 | uint32_t key = 0; | |
78e3ac9e | 364 | boost::optional<Netmask> subnet; |
e7c732b8 | 365 | DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime); |
d7728daf | 366 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK); |
886e2cf2 RG |
367 | if (!found) { |
368 | g_missing++; | |
369 | } | |
370 | } | |
371 | } | |
372 | catch(PDNSException& e) { | |
373 | cerr<<"Had error in threadReader: "<<e.reason<<endl; | |
374 | throw; | |
375 | } | |
376 | return 0; | |
377 | } | |
378 | ||
379 | BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) { | |
380 | try { | |
381 | pthread_t tid[4]; | |
382 | for(int i=0; i < 4; ++i) | |
383 | pthread_create(&tid[i], 0, threadMangler, (void*)(i*1000000UL)); | |
384 | void* res; | |
385 | for(int i=0; i < 4 ; ++i) | |
386 | pthread_join(tid[i], &res); | |
387 | ||
388 | BOOST_CHECK_EQUAL(PC.getSize() + PC.getDeferredInserts() + PC.getInsertCollisions(), 400000); | |
389 | BOOST_CHECK_SMALL(1.0*PC.getInsertCollisions(), 10000.0); | |
390 | ||
391 | for(int i=0; i < 4; ++i) | |
392 | pthread_create(&tid[i], 0, threadReader, (void*)(i*1000000UL)); | |
393 | for(int i=0; i < 4 ; ++i) | |
394 | pthread_join(tid[i], &res); | |
395 | ||
396 | BOOST_CHECK((PC.getDeferredInserts() + PC.getDeferredLookups() + PC.getInsertCollisions()) >= g_missing); | |
397 | } | |
398 | catch(PDNSException& e) { | |
399 | cerr<<"Had error: "<<e.reason<<endl; | |
400 | throw; | |
401 | } | |
402 | ||
403 | } | |
404 | ||
78e3ac9e RG |
405 | BOOST_AUTO_TEST_CASE(test_PCCollision) { |
406 | const size_t maxEntries = 150000; | |
407 | DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true); | |
408 | BOOST_CHECK_EQUAL(PC.getSize(), 0); | |
409 | ||
410 | DNSName qname("www.powerdns.com."); | |
411 | uint16_t qtype = QType::AAAA; | |
412 | uint16_t qid = 0x42; | |
413 | uint32_t key; | |
414 | uint32_t secondKey; | |
415 | boost::optional<Netmask> subnetOut; | |
d7728daf | 416 | bool dnssecOK = false; |
78e3ac9e RG |
417 | |
418 | /* lookup for a query with an ECS value of 10.0.118.46/32, | |
419 | insert a corresponding response */ | |
420 | { | |
421 | vector<uint8_t> query; | |
422 | DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0); | |
423 | pwQ.getHeader()->rd = 1; | |
424 | pwQ.getHeader()->id = qid; | |
425 | DNSPacketWriter::optvect_t ednsOptions; | |
426 | EDNSSubnetOpts opt; | |
427 | opt.source = Netmask("10.0.118.46/32"); | |
428 | ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt))); | |
429 | pwQ.addOpt(512, 0, 0, ednsOptions); | |
430 | pwQ.commit(); | |
431 | ||
432 | char responseBuf[4096]; | |
433 | uint16_t responseBufSize = sizeof(responseBuf); | |
434 | ComboAddress remote("192.0.2.1"); | |
435 | struct timespec queryTime; | |
436 | gettime(&queryTime); | |
e7c732b8 | 437 | DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime); |
d7728daf | 438 | bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK); |
78e3ac9e RG |
439 | BOOST_CHECK_EQUAL(found, false); |
440 | BOOST_REQUIRE(subnetOut); | |
441 | BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); | |
442 | ||
443 | vector<uint8_t> response; | |
444 | DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0); | |
445 | pwR.getHeader()->rd = 1; | |
446 | pwR.getHeader()->id = qid; | |
447 | pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER); | |
448 | ComboAddress v6("::1"); | |
449 | pwR.xfrCAWithoutPort(6, v6); | |
450 | pwR.commit(); | |
451 | pwR.addOpt(512, 0, 0, ednsOptions); | |
452 | pwR.commit(); | |
453 | ||
d7728daf | 454 | PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none); |
78e3ac9e RG |
455 | BOOST_CHECK_EQUAL(PC.getSize(), 1); |
456 | ||
d7728daf | 457 | found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK); |
78e3ac9e RG |
458 | BOOST_CHECK_EQUAL(found, true); |
459 | BOOST_REQUIRE(subnetOut); | |
460 | BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); | |
461 | } | |
462 | ||
463 | /* now lookup for the same query with an ECS value of 10.0.123.193/32 | |
464 | we should get the same key (collision) but no match */ | |
465 | { | |
466 | vector<uint8_t> query; | |
467 | DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0); | |
468 | pwQ.getHeader()->rd = 1; | |
469 | pwQ.getHeader()->id = qid; | |
470 | DNSPacketWriter::optvect_t ednsOptions; | |
471 | EDNSSubnetOpts opt; | |
472 | opt.source = Netmask("10.0.123.193/32"); | |
473 | ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt))); | |
474 | pwQ.addOpt(512, 0, 0, ednsOptions); | |
475 | pwQ.commit(); | |
476 | ||
477 | char responseBuf[4096]; | |
478 | uint16_t responseBufSize = sizeof(responseBuf); | |
479 | ComboAddress remote("192.0.2.1"); | |
480 | struct timespec queryTime; | |
481 | gettime(&queryTime); | |
e7c732b8 | 482 | DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime); |
d7728daf | 483 | bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &secondKey, subnetOut, dnssecOK); |
78e3ac9e RG |
484 | BOOST_CHECK_EQUAL(found, false); |
485 | BOOST_CHECK_EQUAL(secondKey, key); | |
486 | BOOST_REQUIRE(subnetOut); | |
487 | BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString()); | |
488 | BOOST_CHECK_EQUAL(PC.getLookupCollisions(), 1); | |
489 | } | |
490 | } | |
491 | ||
d7728daf RG |
492 | BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) { |
493 | const size_t maxEntries = 150000; | |
494 | DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true); | |
495 | BOOST_CHECK_EQUAL(PC.getSize(), 0); | |
496 | ||
497 | DNSName qname("www.powerdns.com."); | |
498 | uint16_t qtype = QType::AAAA; | |
499 | uint16_t qid = 0x42; | |
500 | uint32_t key; | |
501 | boost::optional<Netmask> subnetOut; | |
502 | ||
503 | /* lookup for a query with DNSSEC OK, | |
504 | insert a corresponding response with DO set, | |
505 | check that it doesn't match without DO, but does with it */ | |
506 | { | |
507 | vector<uint8_t> query; | |
508 | DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0); | |
509 | pwQ.getHeader()->rd = 1; | |
510 | pwQ.getHeader()->id = qid; | |
511 | pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO); | |
512 | pwQ.commit(); | |
513 | ||
514 | char responseBuf[4096]; | |
515 | uint16_t responseBufSize = sizeof(responseBuf); | |
516 | ComboAddress remote("192.0.2.1"); | |
517 | struct timespec queryTime; | |
518 | gettime(&queryTime); | |
519 | DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime); | |
520 | bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true); | |
521 | BOOST_CHECK_EQUAL(found, false); | |
522 | ||
523 | vector<uint8_t> response; | |
524 | DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0); | |
525 | pwR.getHeader()->rd = 1; | |
526 | pwR.getHeader()->id = qid; | |
527 | pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER); | |
528 | ComboAddress v6("::1"); | |
529 | pwR.xfrCAWithoutPort(6, v6); | |
530 | pwR.commit(); | |
531 | pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO); | |
532 | pwR.commit(); | |
533 | ||
534 | PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none); | |
535 | BOOST_CHECK_EQUAL(PC.getSize(), 1); | |
536 | ||
537 | found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, false); | |
538 | BOOST_CHECK_EQUAL(found, false); | |
539 | ||
540 | found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true); | |
541 | BOOST_CHECK_EQUAL(found, true); | |
542 | } | |
543 | ||
544 | } | |
545 | ||
886e2cf2 | 546 | BOOST_AUTO_TEST_SUITE_END() |