]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-dnsparser_cc.cc
auth: switch circleci mssql image
[thirdparty/pdns.git] / pdns / test-dnsparser_cc.cc
CommitLineData
47698274
RG
1#define BOOST_TEST_DYN_LINK
2#define BOOST_TEST_NO_MAIN
3
4#ifdef HAVE_CONFIG_H
5#include "config.h"
6#endif
7
8#include <boost/test/unit_test.hpp>
9
10#include "dnsparser.hh"
11
12BOOST_AUTO_TEST_SUITE(test_dnsparser_cc)
13
14BOOST_AUTO_TEST_CASE(test_editDNSPacketTTL) {
15
16 auto generatePacket = [](uint32_t ttl) {
17 DNSName name("powerdns.com.");
18 ComboAddress v4("1.2.3.4");
19 ComboAddress v6("2001:db8::1");
20
21 vector<uint8_t> packet;
22 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
23 pwR.getHeader()->qr = 1;
24
25 /* record we want to see altered */
26 pwR.startRecord(name, QType::A, ttl, QClass::IN, DNSResourceRecord::ANSWER);
27 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
28 pwR.commit();
29
30 /* same record but different TTL (yeah, don't do that but it's just a test) */
31 pwR.startRecord(name, QType::A, 100, QClass::IN, DNSResourceRecord::ANSWER);
32 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
33 pwR.commit();
34
35 /* different type */
36 pwR.startRecord(name, QType::AAAA, 42, QClass::IN, DNSResourceRecord::ANSWER);
37 pwR.xfrIP6(std::string(reinterpret_cast<const char*>(v6.sin6.sin6_addr.s6_addr), 16));
38 pwR.commit();
39
40 /* different class */
41 pwR.startRecord(name, QType::A, 42, QClass::CHAOS, DNSResourceRecord::ANSWER);
42 pwR.commit();
43
44 /* different section */
45 pwR.startRecord(name, QType::A, 42, QClass::IN, DNSResourceRecord::AUTHORITY);
46 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
47 pwR.commit();
48
49 return packet;
50 };
51
52 auto firstPacket = generatePacket(42);
53 auto expectedAlteredPacket = generatePacket(84);
54
55 size_t called = 0;
56 editDNSPacketTTL(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size(), [&called](uint8_t section, uint16_t class_, uint16_t type, uint32_t ttl) {
57
58 called++;
59
60 /* only updates the TTL of IN/A, in answer, with an existing ttl of 42 */
61 if (section == 1 && class_ == QClass::IN && type == QType::A && ttl == 42) {
62 return 84;
63 }
64 return 0;
65 });
66
67 /* check that we have been for all records */
68 BOOST_CHECK_EQUAL(called, 5);
69
70 BOOST_REQUIRE_EQUAL(firstPacket.size(), expectedAlteredPacket.size());
71 for (size_t idx = 0; idx < firstPacket.size(); idx++) {
72 BOOST_CHECK_EQUAL(firstPacket.at(idx), expectedAlteredPacket.at(idx));
73 }
74 BOOST_CHECK(firstPacket == expectedAlteredPacket);
75
76 /* now call it with a truncated packet, missing the last TTL and rdata,
77 we should only be called 4 times but everything else should be fine. */
78 called = 0;
79 editDNSPacketTTL(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size() - sizeof(uint32_t) - /* rdata length */ sizeof (uint16_t) - /* IPv4 payload in rdata */ 4, [&called](uint8_t section, uint16_t class_, uint16_t type, uint32_t ttl) {
80
81 called++;
82
83 /* only updates the TTL of IN/A, in answer, with an existing ttl of 42 */
84 if (section == 1 && class_ == QClass::IN && type == QType::A && ttl == 42) {
85 return 84;
86 }
87 return 0;
88 });
89
90 /* check that we have been for all records */
91 BOOST_CHECK_EQUAL(called, 4);
92 BOOST_CHECK(firstPacket == expectedAlteredPacket);
93}
94
95BOOST_AUTO_TEST_CASE(test_ageDNSPacket) {
96
97 auto generatePacket = [](uint32_t ttl) {
98 DNSName name("powerdns.com.");
99 ComboAddress v4("1.2.3.4");
100 ComboAddress v6("2001:db8::1");
101
102 vector<uint8_t> packet;
103 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
104 pwR.getHeader()->qr = 1;
105
106 /* record we want to see altered */
107 pwR.startRecord(name, QType::A, ttl, QClass::IN, DNSResourceRecord::ANSWER);
108 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
109 pwR.commit();
110
111 pwR.addOpt(4096, 0, 0);
112 pwR.commit();
113
114 return packet;
115 };
116
117 auto firstPacket = generatePacket(3600);
118 auto expectedAlteredPacket = generatePacket(1800);
119
120 ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size(), 1800);
121
122 BOOST_REQUIRE_EQUAL(firstPacket.size(), expectedAlteredPacket.size());
123 for (size_t idx = 0; idx < firstPacket.size(); idx++) {
124 BOOST_CHECK_EQUAL(firstPacket.at(idx), expectedAlteredPacket.at(idx));
125 }
126 BOOST_CHECK(firstPacket == expectedAlteredPacket);
127
128 /* now call it with a truncated packet, missing the last TTL and rdata,
129 the packet should not be altered. */
130 ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size() - sizeof(uint32_t) - /* rdata length */ sizeof (uint16_t) - /* IPv4 payload in rdata */ 4 - /* size of OPT record */ 11, 900);
131
132 BOOST_CHECK(firstPacket == expectedAlteredPacket);
133
134 /* now remove more than the remaining TTL, not that while TTL are,
135 per rfc1035 errata, "a 32 bit unsigned integer" so we should be
136 able to expect unsigned overflow to apply, but rfc2181 specifies
137 a maximum of "2^31 - 1". */
138 ageDNSPacket(reinterpret_cast<char*>(firstPacket.data()), firstPacket.size(), 1801);
139
140 uint32_t ttl = std::numeric_limits<uint32_t>::max();
141
142 expectedAlteredPacket = generatePacket(ttl);
143 BOOST_REQUIRE_EQUAL(firstPacket.size(), expectedAlteredPacket.size());
144 for (size_t idx = 0; idx < firstPacket.size(); idx++) {
145 BOOST_CHECK_EQUAL(firstPacket.at(idx), expectedAlteredPacket.at(idx));
146 }
147 BOOST_CHECK(firstPacket == expectedAlteredPacket);
148}
149
150BOOST_AUTO_TEST_CASE(test_getDNSPacketMinTTL) {
151
152 const DNSName name("powerdns.com.");
153 const ComboAddress v4("1.2.3.4");
154 const ComboAddress v6("2001:db8::1");
155
156 {
157 /* no records */
158 vector<uint8_t> packet;
159 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
160 pwR.getHeader()->qr = 1;
161 pwR.commit();
162
163 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), nullptr);
164 BOOST_CHECK_EQUAL(result, std::numeric_limits<uint32_t>::max());
165 }
166
167 {
168 /* only one record, not an OPT one */
169 uint32_t ttl = 42;
170 vector<uint8_t> packet;
171 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
172 pwR.getHeader()->qr = 1;
173 pwR.commit();
174
175 pwR.startRecord(name, QType::A, ttl, QClass::IN, DNSResourceRecord::ANSWER);
176 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
177 pwR.commit();
178
179 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), nullptr);
180 BOOST_CHECK_EQUAL(result, ttl);
181 }
182
183 {
184 /* only one record, an OPT one */
185 vector<uint8_t> packet;
186 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
187 pwR.getHeader()->qr = 1;
188 pwR.commit();
189
190 pwR.addOpt(4096, 0, 0);
191 pwR.commit();
192
193 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), nullptr);
194 BOOST_CHECK_EQUAL(result, std::numeric_limits<uint32_t>::max());
195 }
196
197 {
198 /* records with different TTLs, should return the lower */
199 vector<uint8_t> packet;
200 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
201 pwR.getHeader()->qr = 1;
202 pwR.commit();
203
204 pwR.startRecord(name, QType::A, 257, QClass::IN, DNSResourceRecord::ANSWER);
205 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
206 pwR.commit();
207
208 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::AUTHORITY);
209 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
210 pwR.commit();
211
212 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
213 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
214 pwR.commit();
215
216 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), nullptr);
217 BOOST_CHECK_EQUAL(result, 255);
218 }
219
220 {
221 /* SOA record in answer, seenAuthSOA should not be set */
222 vector<uint8_t> packet;
223 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
224 pwR.getHeader()->qr = 1;
225 pwR.commit();
226
227 pwR.startRecord(name, QType::SOA, 257, QClass::IN, DNSResourceRecord::ANSWER);
228 pwR.commit();
229
230 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::AUTHORITY);
231 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
232 pwR.commit();
233
234 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
235 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
236 pwR.commit();
237
238 bool seenAuthSOA = false;
239 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), &seenAuthSOA);
240 BOOST_CHECK_EQUAL(result, 255);
241 BOOST_CHECK_EQUAL(seenAuthSOA, false);
242 }
243
244 {
245 /* one SOA record in auth, seenAuthSOA should be set */
246 vector<uint8_t> packet;
247 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
248 pwR.getHeader()->qr = 1;
249 pwR.commit();
250
251 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::ANSWER);
252 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
253 pwR.commit();
254
255 pwR.startRecord(name, QType::SOA, 257, QClass::IN, DNSResourceRecord::AUTHORITY);
256 pwR.commit();
257
258 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
259 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
260 pwR.commit();
261
262 bool seenAuthSOA = false;
263 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), &seenAuthSOA);
264 BOOST_CHECK_EQUAL(result, 255);
265 BOOST_CHECK_EQUAL(seenAuthSOA, true);
266 }
267
268 {
269 /* one SOA record of the wrong qclass in auth, seenAuthSOA should not be set */
270 vector<uint8_t> packet;
271 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
272 pwR.getHeader()->qr = 1;
273 pwR.commit();
274
275 pwR.startRecord(name, QType::A, 257, QClass::IN, DNSResourceRecord::ANSWER);
276 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
277 pwR.commit();
278
279 pwR.startRecord(name, QType::SOA, 255, QClass::CHAOS, DNSResourceRecord::AUTHORITY);
280 pwR.commit();
281
282 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
283 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
284 pwR.commit();
285
286 bool seenAuthSOA = false;
287 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), &seenAuthSOA);
288 BOOST_CHECK_EQUAL(result, 255);
289 BOOST_CHECK_EQUAL(seenAuthSOA, false);
290 }
291
292 {
293 /* one A record in auth, seenAuthSOA should not be set */
294 vector<uint8_t> packet;
295 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
296 pwR.getHeader()->qr = 1;
297 pwR.commit();
298
299 pwR.startRecord(name, QType::A, 257, QClass::IN, DNSResourceRecord::AUTHORITY);
300 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
301 pwR.commit();
302
303 bool seenAuthSOA = false;
304 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), &seenAuthSOA);
305 BOOST_CHECK_EQUAL(result, 257);
306 BOOST_CHECK_EQUAL(seenAuthSOA, false);
307 }
308
309 {
310 /* one SOA record in additional, seenAuthSOA should not be set */
311 vector<uint8_t> packet;
312 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
313 pwR.getHeader()->qr = 1;
314 pwR.commit();
315
cfd669b4 316 pwR.startRecord(name, QType::SOA, 255, QClass::IN, DNSResourceRecord::ADDITIONAL);
47698274
RG
317 pwR.commit();
318
319 bool seenAuthSOA = false;
320 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size(), &seenAuthSOA);
321 BOOST_CHECK_EQUAL(result, 255);
322 BOOST_CHECK_EQUAL(seenAuthSOA, false);
323 }
324
325 {
326 /* truncated packet, no exception should be raised */
327 /* one SOA record in auth, seenAuthSOA should be set */
328 vector<uint8_t> packet;
329 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
330 pwR.getHeader()->qr = 1;
331 pwR.commit();
332
333 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::ANSWER);
334 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
335 pwR.commit();
336
337 pwR.startRecord(name, QType::SOA, 257, QClass::IN, DNSResourceRecord::AUTHORITY);
338 pwR.commit();
339
340 pwR.startRecord(name, QType::A, 254, QClass::IN, DNSResourceRecord::ADDITIONAL);
341 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
342 pwR.commit();
343
344 bool seenAuthSOA = false;
345 auto result = getDNSPacketMinTTL(reinterpret_cast<char*>(packet.data()), packet.size() - sizeof(uint32_t) - /* rdata length */ sizeof (uint16_t) - /* IPv4 payload in rdata */ 4, &seenAuthSOA);
346 BOOST_CHECK_EQUAL(result, 255);
347 BOOST_CHECK_EQUAL(seenAuthSOA, true);
348 }
349}
350
351BOOST_AUTO_TEST_CASE(test_getDNSPacketLength) {
352
353 const DNSName name("powerdns.com.");
354 const ComboAddress v4("1.2.3.4");
355 const ComboAddress v6("2001:db8::1");
356
357 {
358 /* no records */
359 vector<uint8_t> packet;
360 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
361 pwR.getHeader()->qr = 1;
362 pwR.commit();
363
364 auto result = getDNSPacketLength(reinterpret_cast<char*>(packet.data()), packet.size());
365 BOOST_CHECK_EQUAL(result, packet.size());
366 }
367
368 {
369 /* several records */
370 vector<uint8_t> packet;
371 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
372 pwR.getHeader()->qr = 1;
373 pwR.commit();
374
375 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::ANSWER);
376 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
377 pwR.commit();
378
379 pwR.startRecord(name, QType::SOA, 257, QClass::IN, DNSResourceRecord::AUTHORITY);
380 pwR.commit();
381
382 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
383 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
384 pwR.commit();
385
386 pwR.addOpt(4096, 0, 0);
387 pwR.commit();
388
389 auto result = getDNSPacketLength(reinterpret_cast<char*>(packet.data()), packet.size());
390 BOOST_CHECK_EQUAL(result, packet.size());
391 }
392
393 {
394 /* trailing data */
395 vector<uint8_t> packet;
396 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
397 pwR.getHeader()->qr = 1;
398 pwR.commit();
399
400 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::ANSWER);
401 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
402 pwR.commit();
403
404 pwR.startRecord(name, QType::SOA, 257, QClass::IN, DNSResourceRecord::AUTHORITY);
405 pwR.commit();
406
407 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
408 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
409 pwR.commit();
410
411 pwR.addOpt(4096, 0, 0);
412 pwR.commit();
413
414 auto realSize = packet.size();
415 packet.resize(realSize + 512);
416 auto result = getDNSPacketLength(reinterpret_cast<char*>(packet.data()), packet.size());
417 BOOST_CHECK_EQUAL(result, realSize);
418 }
419
53c57da7
RG
420 {
421 /* truncated packet, should return the full size */
422 vector<uint8_t> packet;
423 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
424 pwR.getHeader()->qr = 1;
425 pwR.commit();
426
427 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::ANSWER);
428 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
429 pwR.commit();
430
431 pwR.startRecord(name, QType::SOA, 257, QClass::IN, DNSResourceRecord::AUTHORITY);
432 pwR.commit();
433
434 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
435 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
436 pwR.commit();
437
438 pwR.addOpt(4096, 0, 0);
439 pwR.commit();
440
441 size_t fakeSize = packet.size()-1;
442 auto result = getDNSPacketLength(reinterpret_cast<char*>(packet.data()), fakeSize);
443 BOOST_CHECK_EQUAL(result, fakeSize);
444 }
445
47698274
RG
446}
447
448BOOST_AUTO_TEST_CASE(test_getRecordsOfTypeCount) {
449 const DNSName name("powerdns.com.");
450 const ComboAddress v4("1.2.3.4");
451 const ComboAddress v6("2001:db8::1");
452
453 {
454 vector<uint8_t> packet;
455 DNSPacketWriter pwR(packet, name, QType::A, QClass::IN, 0);
456 pwR.getHeader()->qr = 1;
457 pwR.commit();
458
459 pwR.startRecord(name, QType::A, 255, QClass::IN, DNSResourceRecord::ANSWER);
460 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
461 pwR.commit();
462
463 pwR.startRecord(name, QType::SOA, 257, QClass::IN, DNSResourceRecord::AUTHORITY);
464 pwR.commit();
465
466 pwR.startRecord(name, QType::A, 256, QClass::IN, DNSResourceRecord::ADDITIONAL);
467 pwR.xfrIP(v4.sin4.sin_addr.s_addr);
468 pwR.commit();
469
470 pwR.addOpt(4096, 0, 0);
471 pwR.commit();
472
473 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 0, QType::A), 1);
474 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 0, QType::SOA), 0);
475 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 1, QType::A), 1);
476 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 1, QType::SOA), 0);
477 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 2, QType::A), 0);
478 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 2, QType::SOA), 1);
479 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 3, QType::A), 1);
480 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 3, QType::SOA), 0);
481
482 BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 4, QType::SOA), 0);
483}
484
485}
486
487BOOST_AUTO_TEST_SUITE_END()