]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-dnsdist_cc.cc
dnsdist: Set a correct EDNS OPT RR for self-generated answers
[thirdparty/pdns.git] / pdns / test-dnsdist_cc.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #define BOOST_TEST_DYN_LINK
23 #define BOOST_TEST_NO_MAIN
24
25 #include <boost/test/unit_test.hpp>
26
27 #include "dnsdist.hh"
28 #include "dnsdist-ecs.hh"
29 #include "dolog.hh"
30 #include "dnsname.hh"
31 #include "dnsparser.hh"
32 #include "dnswriter.hh"
33 #include "ednsoptions.hh"
34 #include "ednscookies.hh"
35 #include "ednssubnet.hh"
36 #include <unistd.h>
37
38 BOOST_AUTO_TEST_SUITE(dnsdist_cc)
39
40 bool g_syslog{true};
41 bool g_verbose{true};
42
43 static const uint16_t ECSSourcePrefixV4 = 24;
44 static const uint16_t ECSSourcePrefixV6 = 56;
45
46 static void validateQuery(const char * packet, size_t packetSize, bool hasEdns=true)
47 {
48 MOADNSParser mdp(true, packet, packetSize);
49
50 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
51
52 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
53 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0);
54 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
55 BOOST_CHECK_EQUAL(mdp.d_header.arcount, (hasEdns ? 1 : 0));
56 }
57
58 static void validateResponse(const char * packet, size_t packetSize, bool hasEdns, uint8_t additionalCount=0)
59 {
60 MOADNSParser mdp(false, packet, packetSize);
61
62 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
63
64 BOOST_CHECK_EQUAL(mdp.d_header.qr, 1);
65 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
66 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1);
67 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
68 BOOST_CHECK_EQUAL(mdp.d_header.arcount, (hasEdns ? 1 : 0) + additionalCount);
69 }
70
71 BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
72 {
73 bool ednsAdded = false;
74 bool ecsAdded = false;
75 ComboAddress remote;
76 DNSName name("www.powerdns.com.");
77
78 vector<uint8_t> query;
79 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
80 pw.getHeader()->rd = 1;
81 uint16_t len = query.size();
82
83 /* large enough packet */
84 char packet[1500];
85 memcpy(packet, query.data(), query.size());
86
87 unsigned int consumed = 0;
88 uint16_t qtype;
89 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
90 BOOST_CHECK_EQUAL(qname, name);
91 BOOST_CHECK(qtype == QType::A);
92
93 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
94 BOOST_CHECK((size_t) len > query.size());
95 BOOST_CHECK_EQUAL(ednsAdded, true);
96 BOOST_CHECK_EQUAL(ecsAdded, false);
97 validateQuery(packet, len);
98
99 /* not large enough packet */
100 ednsAdded = false;
101 ecsAdded = false;
102 consumed = 0;
103 len = query.size();
104 qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
105 BOOST_CHECK_EQUAL(qname, name);
106 BOOST_CHECK(qtype == QType::A);
107
108 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
109 BOOST_CHECK_EQUAL((size_t) len, query.size());
110 BOOST_CHECK_EQUAL(ednsAdded, false);
111 BOOST_CHECK_EQUAL(ecsAdded, false);
112 validateQuery(reinterpret_cast<char*>(query.data()), len, false);
113 }
114
115 BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) {
116 bool ednsAdded = false;
117 bool ecsAdded = false;
118 ComboAddress remote;
119 DNSName name("www.powerdns.com.");
120
121 vector<uint8_t> query;
122 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
123 pw.getHeader()->rd = 1;
124 pw.addOpt(512, 0, 0);
125 pw.commit();
126 uint16_t len = query.size();
127
128 /* large enough packet */
129 char packet[1500];
130 memcpy(packet, query.data(), query.size());
131
132 unsigned int consumed = 0;
133 uint16_t qtype;
134 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
135 BOOST_CHECK_EQUAL(qname, name);
136 BOOST_CHECK(qtype == QType::A);
137
138 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
139 BOOST_CHECK((size_t) len > query.size());
140 BOOST_CHECK_EQUAL(ednsAdded, false);
141 BOOST_CHECK_EQUAL(ecsAdded, true);
142 validateQuery(packet, len);
143
144 /* not large enough packet */
145 consumed = 0;
146 ednsAdded = false;
147 ecsAdded = false;
148 len = query.size();
149 qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
150 BOOST_CHECK_EQUAL(qname, name);
151 BOOST_CHECK(qtype == QType::A);
152
153 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
154 BOOST_CHECK_EQUAL((size_t) len, query.size());
155 BOOST_CHECK_EQUAL(ednsAdded, false);
156 BOOST_CHECK_EQUAL(ecsAdded, false);
157 validateQuery(reinterpret_cast<char*>(query.data()), len);
158 }
159
160 BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) {
161 bool ednsAdded = false;
162 bool ecsAdded = false;
163 ComboAddress remote("192.168.1.25");
164 DNSName name("www.powerdns.com.");
165 ComboAddress origRemote("127.0.0.1");
166
167 vector<uint8_t> query;
168 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
169 pw.getHeader()->rd = 1;
170 EDNSSubnetOpts ecsOpts;
171 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
172 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
173 DNSPacketWriter::optvect_t opts;
174 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
175 pw.addOpt(512, 0, 0, opts);
176 pw.commit();
177 uint16_t len = query.size();
178
179 /* large enough packet */
180 char packet[1500];
181 memcpy(packet, query.data(), query.size());
182
183 unsigned int consumed = 0;
184 uint16_t qtype;
185 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
186 BOOST_CHECK_EQUAL(qname, name);
187 BOOST_CHECK(qtype == QType::A);
188
189 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
190 BOOST_CHECK_EQUAL((size_t) len, query.size());
191 BOOST_CHECK_EQUAL(ednsAdded, false);
192 BOOST_CHECK_EQUAL(ecsAdded, false);
193 validateQuery(packet, len);
194 }
195
196 BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) {
197 bool ednsAdded = false;
198 bool ecsAdded = false;
199 ComboAddress remote("192.168.1.25");
200 DNSName name("www.powerdns.com.");
201 ComboAddress origRemote("127.0.0.1");
202
203 vector<uint8_t> query;
204 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
205 pw.getHeader()->rd = 1;
206 EDNSSubnetOpts ecsOpts;
207 ecsOpts.source = Netmask(origRemote, 32);
208 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
209 DNSPacketWriter::optvect_t opts;
210 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
211 pw.addOpt(512, 0, 0, opts);
212 pw.commit();
213 uint16_t len = query.size();
214
215 /* large enough packet */
216 char packet[1500];
217 memcpy(packet, query.data(), query.size());
218
219 unsigned int consumed = 0;
220 uint16_t qtype;
221 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
222 BOOST_CHECK_EQUAL(qname, name);
223 BOOST_CHECK(qtype == QType::A);
224
225 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
226 BOOST_CHECK((size_t) len < query.size());
227 BOOST_CHECK_EQUAL(ednsAdded, false);
228 BOOST_CHECK_EQUAL(ecsAdded, false);
229 validateQuery(packet, len);
230 }
231
232 BOOST_AUTO_TEST_CASE(replaceECSWithLarger) {
233 bool ednsAdded = false;
234 bool ecsAdded = false;
235 ComboAddress remote("192.168.1.25");
236 DNSName name("www.powerdns.com.");
237 ComboAddress origRemote("127.0.0.1");
238
239 vector<uint8_t> query;
240 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
241 pw.getHeader()->rd = 1;
242 EDNSSubnetOpts ecsOpts;
243 ecsOpts.source = Netmask(origRemote, 8);
244 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
245 DNSPacketWriter::optvect_t opts;
246 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
247 pw.addOpt(512, 0, 0, opts);
248 pw.commit();
249 uint16_t len = query.size();
250
251 /* large enough packet */
252 char packet[1500];
253 memcpy(packet, query.data(), query.size());
254
255 unsigned int consumed = 0;
256 uint16_t qtype;
257 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
258 BOOST_CHECK_EQUAL(qname, name);
259 BOOST_CHECK(qtype == QType::A);
260
261 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
262 BOOST_CHECK((size_t) len > query.size());
263 BOOST_CHECK_EQUAL(ednsAdded, false);
264 BOOST_CHECK_EQUAL(ecsAdded, false);
265 validateQuery(packet, len);
266
267 /* not large enough packet */
268 ednsAdded = false;
269 ecsAdded = false;
270 consumed = 0;
271 len = query.size();
272 qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
273 BOOST_CHECK_EQUAL(qname, name);
274 BOOST_CHECK(qtype == QType::A);
275
276 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6));
277 BOOST_CHECK_EQUAL((size_t) len, query.size());
278 BOOST_CHECK_EQUAL(ednsAdded, false);
279 BOOST_CHECK_EQUAL(ecsAdded, false);
280 validateQuery(reinterpret_cast<char*>(query.data()), len);
281 }
282
283 BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) {
284 DNSName name("www.powerdns.com.");
285
286 vector<uint8_t> response;
287 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
288 pw.getHeader()->qr = 1;
289 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
290 pw.xfr32BitInt(0x01020304);
291 pw.addOpt(512, 0, 0);
292 pw.commit();
293 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
294 pw.xfr32BitInt(0x01020304);
295 pw.commit();
296
297 vector<uint8_t> newResponse;
298 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
299 BOOST_CHECK_EQUAL(res, 0);
300
301 unsigned int consumed = 0;
302 uint16_t qtype;
303 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
304 BOOST_CHECK_EQUAL(qname, name);
305 BOOST_CHECK(qtype == QType::A);
306 size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
307 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
308
309 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
310 }
311
312 BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) {
313 DNSName name("www.powerdns.com.");
314
315 vector<uint8_t> response;
316 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
317 pw.getHeader()->qr = 1;
318 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
319 pw.xfr32BitInt(0x01020304);
320 pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
321 pw.xfr32BitInt(0x01020304);
322 pw.commit();
323 pw.addOpt(512, 0, 0);
324 pw.commit();
325 pw.startRecord(DNSName("yetanother.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
326 pw.xfr32BitInt(0x01020304);
327 pw.commit();
328
329 vector<uint8_t> newResponse;
330 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
331 BOOST_CHECK_EQUAL(res, 0);
332
333 unsigned int consumed = 0;
334 uint16_t qtype;
335 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
336 BOOST_CHECK_EQUAL(qname, name);
337 BOOST_CHECK(qtype == QType::A);
338 size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
339 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
340
341 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 2);
342 }
343
344 BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) {
345 DNSName name("www.powerdns.com.");
346
347 vector<uint8_t> response;
348 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
349 pw.getHeader()->qr = 1;
350 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
351 pw.xfr32BitInt(0x01020304);
352 pw.commit();
353 pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
354 pw.xfr32BitInt(0x01020304);
355 pw.commit();
356 pw.addOpt(512, 0, 0);
357 pw.commit();
358
359 vector<uint8_t> newResponse;
360 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
361
362 BOOST_CHECK_EQUAL(res, 0);
363
364 unsigned int consumed = 0;
365 uint16_t qtype;
366 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
367 BOOST_CHECK_EQUAL(qname, name);
368 BOOST_CHECK(qtype == QType::A);
369 size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
370 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
371
372 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
373 }
374
375 BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) {
376 DNSName name("www.powerdns.com.");
377 ComboAddress origRemote("127.0.0.1");
378
379 vector<uint8_t> response;
380 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
381 pw.getHeader()->qr = 1;
382 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
383 pw.xfr32BitInt(0x01020304);
384
385 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
386 pw.xfr32BitInt(0x01020304);
387 pw.commit();
388
389 EDNSSubnetOpts ecsOpts;
390 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
391 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
392 DNSPacketWriter::optvect_t opts;
393 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
394 pw.addOpt(512, 0, 0, opts);
395 pw.commit();
396
397 uint16_t optStart;
398 size_t optLen = 0;
399 bool last = false;
400
401 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
402 BOOST_CHECK_EQUAL(res, 0);
403 BOOST_CHECK_EQUAL(last, true);
404
405 size_t responseLen = response.size();
406 size_t existingOptLen = optLen;
407 BOOST_CHECK(existingOptLen < responseLen);
408 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
409 BOOST_CHECK_EQUAL(res, 0);
410 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
411 responseLen -= (existingOptLen - optLen);
412
413 unsigned int consumed = 0;
414 uint16_t qtype;
415 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
416 BOOST_CHECK_EQUAL(qname, name);
417 BOOST_CHECK(qtype == QType::A);
418
419 validateResponse((const char *) response.data(), responseLen, true, 1);
420 }
421
422 BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) {
423 DNSName name("www.powerdns.com.");
424 ComboAddress origRemote("127.0.0.1");
425
426 vector<uint8_t> response;
427 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
428 pw.getHeader()->qr = 1;
429 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
430 pw.xfr32BitInt(0x01020304);
431
432 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
433 pw.xfr32BitInt(0x01020304);
434 pw.commit();
435
436 EDNSSubnetOpts ecsOpts;
437 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV6);
438 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
439 EDNSCookiesOpt cookiesOpt;
440 cookiesOpt.client = string("deadbeef");
441 cookiesOpt.server = string("deadbeef");
442 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
443 DNSPacketWriter::optvect_t opts;
444 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
445 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
446 pw.addOpt(512, 0, 0, opts);
447 pw.commit();
448
449 uint16_t optStart;
450 size_t optLen = 0;
451 bool last = false;
452
453 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
454 BOOST_CHECK_EQUAL(res, 0);
455 BOOST_CHECK_EQUAL(last, true);
456
457 size_t responseLen = response.size();
458 size_t existingOptLen = optLen;
459 BOOST_CHECK(existingOptLen < responseLen);
460 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
461 BOOST_CHECK_EQUAL(res, 0);
462 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
463 responseLen -= (existingOptLen - optLen);
464
465 unsigned int consumed = 0;
466 uint16_t qtype;
467 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
468 BOOST_CHECK_EQUAL(qname, name);
469 BOOST_CHECK(qtype == QType::A);
470
471 validateResponse((const char *) response.data(), responseLen, true, 1);
472 }
473
474 BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) {
475 DNSName name("www.powerdns.com.");
476 ComboAddress origRemote("127.0.0.1");
477
478 vector<uint8_t> response;
479 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
480 pw.getHeader()->qr = 1;
481 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
482 pw.xfr32BitInt(0x01020304);
483
484 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
485 pw.xfr32BitInt(0x01020304);
486 pw.commit();
487
488 EDNSSubnetOpts ecsOpts;
489 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
490 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
491
492 EDNSCookiesOpt cookiesOpt;
493 cookiesOpt.client = string("deadbeef");
494 cookiesOpt.server = string("deadbeef");
495 string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt);
496 string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt);
497
498 DNSPacketWriter::optvect_t opts;
499 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1));
500 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
501 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2));
502 pw.addOpt(512, 0, 0, opts);
503 pw.commit();
504
505 uint16_t optStart;
506 size_t optLen = 0;
507 bool last = false;
508
509 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
510 BOOST_CHECK_EQUAL(res, 0);
511 BOOST_CHECK_EQUAL(last, true);
512
513 size_t responseLen = response.size();
514 size_t existingOptLen = optLen;
515 BOOST_CHECK(existingOptLen < responseLen);
516 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
517 BOOST_CHECK_EQUAL(res, 0);
518 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
519 responseLen -= (existingOptLen - optLen);
520
521 unsigned int consumed = 0;
522 uint16_t qtype;
523 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
524 BOOST_CHECK_EQUAL(qname, name);
525 BOOST_CHECK(qtype == QType::A);
526
527 validateResponse((const char *) response.data(), responseLen, true, 1);
528 }
529
530 BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) {
531 DNSName name("www.powerdns.com.");
532 ComboAddress origRemote("127.0.0.1");
533
534 vector<uint8_t> response;
535 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
536 pw.getHeader()->qr = 1;
537 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
538 pw.xfr32BitInt(0x01020304);
539
540 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
541 pw.xfr32BitInt(0x01020304);
542 pw.commit();
543
544 EDNSCookiesOpt cookiesOpt;
545 cookiesOpt.client = string("deadbeef");
546 cookiesOpt.server = string("deadbeef");
547 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
548 EDNSSubnetOpts ecsOpts;
549 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
550 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
551 DNSPacketWriter::optvect_t opts;
552 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
553 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
554 pw.addOpt(512, 0, 0, opts);
555 pw.commit();
556
557 uint16_t optStart;
558 size_t optLen = 0;
559 bool last = false;
560
561 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
562 BOOST_CHECK_EQUAL(res, 0);
563 BOOST_CHECK_EQUAL(last, true);
564
565 size_t responseLen = response.size();
566 size_t existingOptLen = optLen;
567 BOOST_CHECK(existingOptLen < responseLen);
568 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
569 BOOST_CHECK_EQUAL(res, 0);
570 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
571 responseLen -= (existingOptLen - optLen);
572
573 unsigned int consumed = 0;
574 uint16_t qtype;
575 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
576 BOOST_CHECK_EQUAL(qname, name);
577 BOOST_CHECK(qtype == QType::A);
578
579 validateResponse((const char *) response.data(), responseLen, true, 1);
580 }
581
582 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) {
583 DNSName name("www.powerdns.com.");
584 ComboAddress origRemote("127.0.0.1");
585
586 vector<uint8_t> response;
587 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
588 pw.getHeader()->qr = 1;
589 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
590 pw.xfr32BitInt(0x01020304);
591
592 EDNSSubnetOpts ecsOpts;
593 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
594 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
595 DNSPacketWriter::optvect_t opts;
596 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
597 pw.addOpt(512, 0, 0, opts);
598 pw.commit();
599
600 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
601 pw.xfr32BitInt(0x01020304);
602 pw.commit();
603
604 vector<uint8_t> newResponse;
605 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
606 BOOST_CHECK_EQUAL(res, 0);
607
608 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
609
610 unsigned int consumed = 0;
611 uint16_t qtype;
612 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
613 BOOST_CHECK_EQUAL(qname, name);
614 BOOST_CHECK(qtype == QType::A);
615
616 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
617 }
618
619 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) {
620 DNSName name("www.powerdns.com.");
621 ComboAddress origRemote("127.0.0.1");
622
623 vector<uint8_t> response;
624 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
625 pw.getHeader()->qr = 1;
626 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
627 pw.xfr32BitInt(0x01020304);
628
629 EDNSSubnetOpts ecsOpts;
630 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
631 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
632 EDNSCookiesOpt cookiesOpt;
633 cookiesOpt.client = string("deadbeef");
634 cookiesOpt.server = string("deadbeef");
635 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
636 DNSPacketWriter::optvect_t opts;
637 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
638 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
639 pw.addOpt(512, 0, 0, opts);
640 pw.commit();
641
642 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
643 pw.xfr32BitInt(0x01020304);
644 pw.commit();
645
646 vector<uint8_t> newResponse;
647 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
648 BOOST_CHECK_EQUAL(res, 0);
649
650 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
651
652 unsigned int consumed = 0;
653 uint16_t qtype;
654 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
655 BOOST_CHECK_EQUAL(qname, name);
656 BOOST_CHECK(qtype == QType::A);
657
658 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
659 }
660
661 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) {
662 DNSName name("www.powerdns.com.");
663 ComboAddress origRemote("127.0.0.1");
664
665 vector<uint8_t> response;
666 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
667 pw.getHeader()->qr = 1;
668 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
669 pw.xfr32BitInt(0x01020304);
670
671 EDNSSubnetOpts ecsOpts;
672 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
673 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
674 EDNSCookiesOpt cookiesOpt;
675 cookiesOpt.client = string("deadbeef");
676 cookiesOpt.server = string("deadbeef");
677 string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt);
678 string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt);
679 DNSPacketWriter::optvect_t opts;
680 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1));
681 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
682 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2));
683 pw.addOpt(512, 0, 0, opts);
684 pw.commit();
685
686 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
687 pw.xfr32BitInt(0x01020304);
688 pw.commit();
689
690 vector<uint8_t> newResponse;
691 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
692 BOOST_CHECK_EQUAL(res, 0);
693
694 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
695
696 unsigned int consumed = 0;
697 uint16_t qtype;
698 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
699 BOOST_CHECK_EQUAL(qname, name);
700 BOOST_CHECK(qtype == QType::A);
701
702 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
703 }
704
705 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
706 DNSName name("www.powerdns.com.");
707 ComboAddress origRemote("127.0.0.1");
708
709 vector<uint8_t> response;
710 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
711 pw.getHeader()->qr = 1;
712 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
713 pw.xfr32BitInt(0x01020304);
714
715 EDNSSubnetOpts ecsOpts;
716 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
717 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
718 EDNSCookiesOpt cookiesOpt;
719 cookiesOpt.client = string("deadbeef");
720 cookiesOpt.server = string("deadbeef");
721 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
722 DNSPacketWriter::optvect_t opts;
723 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
724 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
725 pw.addOpt(512, 0, 0, opts);
726 pw.commit();
727
728 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
729 pw.xfr32BitInt(0x01020304);
730 pw.commit();
731
732 vector<uint8_t> newResponse;
733 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
734 BOOST_CHECK_EQUAL(res, 0);
735
736 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
737
738 unsigned int consumed = 0;
739 uint16_t qtype;
740 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
741 BOOST_CHECK_EQUAL(qname, name);
742 BOOST_CHECK(qtype == QType::A);
743
744 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
745 }
746
747 static DNSQuestion getDNSQuestion(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& realTime, vector<uint8_t>& query, size_t len)
748 {
749 dnsheader* dh = reinterpret_cast<dnsheader*>(query.data());
750
751 DNSQuestion dq(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, dh, query.size(), len, false, &realTime);
752 return dq;
753 }
754
755 static DNSQuestion turnIntoResponse(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& queryRealTime, vector<uint8_t>& query, bool resizeBuffer=true)
756 {
757 size_t length = query.size();
758 if (resizeBuffer) {
759 query.resize(4096);
760 }
761
762 auto dq = getDNSQuestion(qname, qtype, qclass, lc, rem, queryRealTime, query, length);
763
764 BOOST_CHECK(addEDNSToQueryTurnedResponse(dq));
765
766 return dq;
767 }
768
769 static int getZ(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, vector<uint8_t>& query)
770 {
771 ComboAddress lc("127.0.0.1");
772 ComboAddress rem("127.0.0.1");
773 struct timespec queryRealTime;
774 gettime(&queryRealTime, true);
775 size_t length = query.size();
776 DNSQuestion dq = getDNSQuestion(qname, qtype, qclass, lc, rem, queryRealTime, query, length);
777
778 return getEDNSZ(dq);
779 }
780
781 BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
782
783 DNSName qname("www.powerdns.com.");
784 uint16_t qtype = QType::A;
785 uint16_t qclass = QClass::IN;
786 EDNSSubnetOpts ecsOpts;
787 ecsOpts.source = Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4);
788 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
789 EDNSCookiesOpt cookiesOpt;
790 cookiesOpt.client = string("deadbeef");
791 cookiesOpt.server = string("deadbeef");
792 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
793 DNSPacketWriter::optvect_t opts;
794 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
795 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
796
797 {
798 /* no EDNS */
799 vector<uint8_t> query;
800 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
801 pw.commit();
802
803 BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
804 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(query.data()), query.size()), 0);
805 }
806
807 {
808 /* truncated EDNS */
809 vector<uint8_t> query;
810 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
811 pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
812 pw.commit();
813
814 query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
815 BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
816 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(query.data()), query.size()), 512);
817 }
818
819 {
820 /* valid EDNS, no options, DO not set */
821 vector<uint8_t> query;
822 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
823 pw.addOpt(512, 0, 0);
824 pw.commit();
825
826 BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
827 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(query.data()), query.size()), 512);
828 }
829
830 {
831 /* valid EDNS, no options, DO set */
832 vector<uint8_t> query;
833 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
834 pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
835 pw.commit();
836
837 BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), EDNS_HEADER_FLAG_DO);
838 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(query.data()), query.size()), 512);
839 }
840
841 {
842 /* valid EDNS, options, DO not set */
843 vector<uint8_t> query;
844 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
845 pw.addOpt(512, 0, 0, opts);
846 pw.commit();
847
848 BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
849 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(query.data()), query.size()), 512);
850 }
851
852 {
853 /* valid EDNS, options, DO set */
854 vector<uint8_t> query;
855 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
856 pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts);
857 pw.commit();
858
859 BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), EDNS_HEADER_FLAG_DO);
860 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(query.data()), query.size()), 512);
861 }
862
863 }
864
865 BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
866
867 DNSName qname("www.powerdns.com.");
868 uint16_t qtype = QType::A;
869 uint16_t qclass = QClass::IN;
870 EDNSSubnetOpts ecsOpts;
871 ecsOpts.source = Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4);
872 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
873 EDNSCookiesOpt cookiesOpt;
874 cookiesOpt.client = string("deadbeef");
875 cookiesOpt.server = string("deadbeef");
876 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
877 DNSPacketWriter::optvect_t opts;
878 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
879 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
880 ComboAddress lc("127.0.0.1");
881 ComboAddress rem("127.0.0.1");
882 struct timespec queryRealTime;
883 gettime(&queryRealTime, true);
884
885 {
886 /* no EDNS */
887 vector<uint8_t> query;
888 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
889 pw.getHeader()->qr = 1;
890 pw.getHeader()->rcode = RCode::NXDomain;
891 pw.commit();
892
893 auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
894 BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
895 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(dq.dh), dq.len), 0);
896 }
897
898 {
899 /* truncated EDNS */
900 vector<uint8_t> query;
901 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
902 pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
903 pw.commit();
904
905 query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
906 auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
907 BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
908 /* 512, because we don't touch a broken OPT record */
909 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(dq.dh), dq.len), 512);
910 }
911
912 {
913 /* valid EDNS, no options, DO not set */
914 vector<uint8_t> query;
915 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
916 pw.addOpt(512, 0, 0);
917 pw.commit();
918
919 auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
920 BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
921 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(dq.dh), dq.len), g_PayloadSizeSelfGenAnswers);
922 }
923
924 {
925 /* valid EDNS, no options, DO set */
926 vector<uint8_t> query;
927 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
928 pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
929 pw.commit();
930
931 auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
932 BOOST_CHECK_EQUAL(getEDNSZ(dq), EDNS_HEADER_FLAG_DO);
933 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(dq.dh), dq.len), g_PayloadSizeSelfGenAnswers);
934 }
935
936 {
937 /* valid EDNS, options, DO not set */
938 vector<uint8_t> query;
939 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
940 pw.addOpt(512, 0, 0, opts);
941 pw.commit();
942
943 auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
944 BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
945 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(dq.dh), dq.len), g_PayloadSizeSelfGenAnswers);
946 }
947
948 {
949 /* valid EDNS, options, DO set */
950 vector<uint8_t> query;
951 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
952 pw.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts);
953 pw.commit();
954
955 auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
956 BOOST_CHECK_EQUAL(getEDNSZ(dq), EDNS_HEADER_FLAG_DO);
957 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSize(reinterpret_cast<const char*>(dq.dh), dq.len), g_PayloadSizeSelfGenAnswers);
958 }
959 }
960
961 BOOST_AUTO_TEST_SUITE_END();