2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
22 #define BOOST_TEST_DYN_LINK
23 #define BOOST_TEST_NO_MAIN
25 #include <boost/test/unit_test.hpp>
29 #include "dnsdist-ecs.hh"
30 #include "dnsdist-xpf.hh"
34 #include "dnsparser.hh"
35 #include "dnswriter.hh"
36 #include "ednsoptions.hh"
37 #include "ednscookies.hh"
38 #include "ednssubnet.hh"
40 BOOST_AUTO_TEST_SUITE(test_dnsdist_cc
)
42 static const uint16_t ECSSourcePrefixV4
= 24;
43 static const uint16_t ECSSourcePrefixV6
= 56;
45 static void validateQuery(const char * packet
, size_t packetSize
, bool hasEdns
=true, bool hasXPF
=false)
47 MOADNSParser
mdp(true, packet
, packetSize
);
49 BOOST_CHECK_EQUAL(mdp
.d_qname
.toString(), "www.powerdns.com.");
51 BOOST_CHECK_EQUAL(mdp
.d_header
.qdcount
, 1);
52 BOOST_CHECK_EQUAL(mdp
.d_header
.ancount
, 0);
53 BOOST_CHECK_EQUAL(mdp
.d_header
.nscount
, 0);
54 uint16_t expectedARCount
= 0 + (hasEdns
? 1 : 0) + (hasXPF
? 1 : 0);
55 BOOST_CHECK_EQUAL(mdp
.d_header
.arcount
, expectedARCount
);
58 static void validateECS(const char* packet
, size_t packetSize
, const ComboAddress
& expected
)
60 ComboAddress
rem("::1");
61 unsigned int consumed
= 0;
64 DNSName
qname(packet
, packetSize
, sizeof(dnsheader
), false, &qtype
, &qclass
, &consumed
);
65 DNSQuestion
dq(&qname
, qtype
, qclass
, consumed
, nullptr, &rem
, const_cast<dnsheader
*>(reinterpret_cast<const dnsheader
*>(packet
)), packetSize
, packetSize
, false, nullptr);
66 BOOST_CHECK(parseEDNSOptions(dq
));
67 BOOST_REQUIRE(dq
.ednsOptions
!= nullptr);
68 BOOST_CHECK_EQUAL(dq
.ednsOptions
->size(), 1);
69 const auto& ecsOption
= dq
.ednsOptions
->find(EDNSOptionCode::ECS
);
70 BOOST_REQUIRE(ecsOption
!= dq
.ednsOptions
->cend());
72 string expectedOption
;
73 generateECSOption(expected
, expectedOption
, expected
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
74 /* we need to skip the option code and length, which are not included */
75 BOOST_REQUIRE_EQUAL(ecsOption
->second
.values
.size(), 1);
76 BOOST_CHECK_EQUAL(expectedOption
.substr(EDNS_OPTION_CODE_SIZE
+ EDNS_OPTION_LENGTH_SIZE
), std::string(ecsOption
->second
.values
.at(0).content
, ecsOption
->second
.values
.at(0).size
));
79 static void validateResponse(const char * packet
, size_t packetSize
, bool hasEdns
, uint8_t additionalCount
=0)
81 MOADNSParser
mdp(false, packet
, packetSize
);
83 BOOST_CHECK_EQUAL(mdp
.d_qname
.toString(), "www.powerdns.com.");
85 BOOST_CHECK_EQUAL(mdp
.d_header
.qr
, 1);
86 BOOST_CHECK_EQUAL(mdp
.d_header
.qdcount
, 1);
87 BOOST_CHECK_EQUAL(mdp
.d_header
.ancount
, 1);
88 BOOST_CHECK_EQUAL(mdp
.d_header
.nscount
, 0);
89 BOOST_CHECK_EQUAL(mdp
.d_header
.arcount
, (hasEdns
? 1 : 0) + additionalCount
);
92 BOOST_AUTO_TEST_CASE(test_addXPF
)
94 static const uint16_t xpfOptionCode
= 65422;
96 struct timespec queryTime
;
97 gettime(&queryTime
); // does not have to be accurate ("realTime") in tests
99 DNSName
name("www.powerdns.com.");
101 vector
<uint8_t> query
;
102 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
103 pw
.getHeader()->rd
= 1;
104 const uint16_t len
= query
.size();
105 vector
<uint8_t> queryWithXPF
;
109 memcpy(packet
, query
.data(), query
.size());
111 /* large enough packet */
112 unsigned int consumed
= 0;
114 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
115 BOOST_CHECK_EQUAL(qname
, name
);
116 BOOST_CHECK(qtype
== QType::A
);
118 auto dh
= reinterpret_cast<dnsheader
*>(packet
);
119 DNSQuestion
dq(&qname
, qtype
, QClass::IN
, qname
.wirelength(), &remote
, &remote
, dh
, sizeof(packet
), query
.size(), false, &queryTime
);
121 BOOST_CHECK(addXPF(dq
, xpfOptionCode
, false));
122 BOOST_CHECK(static_cast<size_t>(dq
.len
) > query
.size());
123 validateQuery(packet
, dq
.len
, false, true);
124 queryWithXPF
.resize(dq
.len
);
125 memcpy(queryWithXPF
.data(), packet
, dq
.len
);
130 memcpy(packet
, query
.data(), query
.size());
132 /* not large enough packet */
133 unsigned int consumed
= 0;
135 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
136 BOOST_CHECK_EQUAL(qname
, name
);
137 BOOST_CHECK(qtype
== QType::A
);
139 auto dh
= reinterpret_cast<dnsheader
*>(packet
);
140 DNSQuestion
dq(&qname
, qtype
, QClass::IN
, qname
.wirelength(), &remote
, &remote
, dh
, sizeof(packet
), query
.size(), false, &queryTime
);
143 BOOST_CHECK(!addXPF(dq
, xpfOptionCode
, false));
144 BOOST_CHECK_EQUAL(static_cast<size_t>(dq
.len
), query
.size());
145 validateQuery(packet
, dq
.len
, false, false);
150 memcpy(packet
, query
.data(), query
.size());
152 /* packet with trailing data (overriding it) */
153 unsigned int consumed
= 0;
155 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
156 BOOST_CHECK_EQUAL(qname
, name
);
157 BOOST_CHECK(qtype
== QType::A
);
159 auto dh
= reinterpret_cast<dnsheader
*>(packet
);
160 DNSQuestion
dq(&qname
, qtype
, QClass::IN
, qname
.wirelength(), &remote
, &remote
, dh
, sizeof(packet
), query
.size(), false, &queryTime
);
162 /* add trailing data */
163 const size_t trailingDataSize
= 10;
164 /* Making sure we have enough room to allow for fake trailing data */
165 BOOST_REQUIRE(sizeof(packet
) > dq
.len
&& (sizeof(packet
) - dq
.len
) > trailingDataSize
);
166 for (size_t idx
= 0; idx
< trailingDataSize
; idx
++) {
167 packet
[dq
.len
+ idx
] = 'A';
169 dq
.len
+= trailingDataSize
;
171 BOOST_CHECK(addXPF(dq
, xpfOptionCode
, false));
172 BOOST_CHECK_EQUAL(static_cast<size_t>(dq
.len
), queryWithXPF
.size());
173 BOOST_CHECK_EQUAL(memcmp(queryWithXPF
.data(), packet
, queryWithXPF
.size()), 0);
174 validateQuery(packet
, dq
.len
, false, true);
179 memcpy(packet
, query
.data(), query
.size());
181 /* packet with trailing data (preserving trailing data) */
182 unsigned int consumed
= 0;
184 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
185 BOOST_CHECK_EQUAL(qname
, name
);
186 BOOST_CHECK(qtype
== QType::A
);
188 auto dh
= reinterpret_cast<dnsheader
*>(packet
);
189 DNSQuestion
dq(&qname
, qtype
, QClass::IN
, qname
.wirelength(), &remote
, &remote
, dh
, sizeof(packet
), query
.size(), false, &queryTime
);
191 /* add trailing data */
192 const size_t trailingDataSize
= 10;
193 /* Making sure we have enough room to allow for fake trailing data */
194 BOOST_REQUIRE(sizeof(packet
) > dq
.len
&& (sizeof(packet
) - dq
.len
) > trailingDataSize
);
195 for (size_t idx
= 0; idx
< trailingDataSize
; idx
++) {
196 packet
[dq
.len
+ idx
] = 'A';
198 dq
.len
+= trailingDataSize
;
200 BOOST_CHECK(addXPF(dq
, xpfOptionCode
, true));
201 BOOST_CHECK(static_cast<size_t>(dq
.len
) > queryWithXPF
.size());
202 BOOST_CHECK_EQUAL(memcmp(queryWithXPF
.data(), packet
, queryWithXPF
.size()), 0);
203 for (size_t idx
= 0; idx
< trailingDataSize
; idx
++) {
204 BOOST_CHECK_EQUAL(packet
[queryWithXPF
.size() + idx
], 'A');
206 validateQuery(packet
, dq
.len
, false, true);
210 BOOST_AUTO_TEST_CASE(addECSWithoutEDNS
)
212 bool ednsAdded
= false;
213 bool ecsAdded
= false;
214 ComboAddress
remote("192.0.2.1");
215 DNSName
name("www.powerdns.com.");
217 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
219 vector
<uint8_t> query
;
220 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
221 pw
.getHeader()->rd
= 1;
222 uint16_t len
= query
.size();
224 /* large enough packet */
226 memcpy(packet
, query
.data(), query
.size());
228 unsigned int consumed
= 0;
230 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
231 BOOST_CHECK_EQUAL(qname
, name
);
232 BOOST_CHECK(qtype
== QType::A
);
234 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, &ednsAdded
, &ecsAdded
, false, newECSOption
, false));
235 BOOST_CHECK(static_cast<size_t>(len
) > query
.size());
236 BOOST_CHECK_EQUAL(ednsAdded
, true);
237 BOOST_CHECK_EQUAL(ecsAdded
, false);
238 validateQuery(packet
, len
);
239 validateECS(packet
, len
, remote
);
240 vector
<uint8_t> queryWithEDNS
;
241 queryWithEDNS
.resize(len
);
242 memcpy(queryWithEDNS
.data(), packet
, len
);
244 /* not large enough packet */
249 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
250 BOOST_CHECK_EQUAL(qname
, name
);
251 BOOST_CHECK(qtype
== QType::A
);
253 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, &ednsAdded
, &ecsAdded
, false, newECSOption
, false));
254 BOOST_CHECK_EQUAL(static_cast<size_t>(len
), query
.size());
255 BOOST_CHECK_EQUAL(ednsAdded
, false);
256 BOOST_CHECK_EQUAL(ecsAdded
, false);
257 validateQuery(reinterpret_cast<char*>(query
.data()), len
, false);
259 /* packet with trailing data (overriding it) */
260 memcpy(packet
, query
.data(), query
.size());
265 qname
= DNSName(packet
, len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
266 BOOST_CHECK_EQUAL(qname
, name
);
267 BOOST_CHECK(qtype
== QType::A
);
268 /* add trailing data */
269 const size_t trailingDataSize
= 10;
270 /* Making sure we have enough room to allow for fake trailing data */
271 BOOST_REQUIRE(sizeof(packet
) > len
&& (sizeof(packet
) - len
) > trailingDataSize
);
272 for (size_t idx
= 0; idx
< trailingDataSize
; idx
++) {
273 packet
[len
+ idx
] = 'A';
275 len
+= trailingDataSize
;
276 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, &ednsAdded
, &ecsAdded
, false, newECSOption
, false));
277 BOOST_REQUIRE_EQUAL(static_cast<size_t>(len
), queryWithEDNS
.size());
278 BOOST_CHECK_EQUAL(memcmp(queryWithEDNS
.data(), packet
, queryWithEDNS
.size()), 0);
279 BOOST_CHECK_EQUAL(ednsAdded
, true);
280 BOOST_CHECK_EQUAL(ecsAdded
, false);
281 validateQuery(packet
, len
);
283 /* packet with trailing data (preserving trailing data) */
284 memcpy(packet
, query
.data(), query
.size());
289 qname
= DNSName(packet
, len
, sizeof(dnsheader
), false, &qtype
, nullptr, &consumed
);
290 BOOST_CHECK_EQUAL(qname
, name
);
291 BOOST_CHECK(qtype
== QType::A
);
292 /* add trailing data */
293 /* Making sure we have enough room to allow for fake trailing data */
294 BOOST_REQUIRE(sizeof(packet
) > len
&& (sizeof(packet
) - len
) > trailingDataSize
);
295 for (size_t idx
= 0; idx
< trailingDataSize
; idx
++) {
296 packet
[len
+ idx
] = 'A';
298 len
+= trailingDataSize
;
299 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, &ednsAdded
, &ecsAdded
, false, newECSOption
, true));
300 BOOST_REQUIRE_EQUAL(static_cast<size_t>(len
), queryWithEDNS
.size() + trailingDataSize
);
301 BOOST_CHECK_EQUAL(memcmp(queryWithEDNS
.data(), packet
, queryWithEDNS
.size()), 0);
302 for (size_t idx
= 0; idx
< trailingDataSize
; idx
++) {
303 BOOST_CHECK_EQUAL(packet
[queryWithEDNS
.size() + idx
], 'A');
305 BOOST_CHECK_EQUAL(ednsAdded
, true);
306 BOOST_CHECK_EQUAL(ecsAdded
, false);
307 validateQuery(packet
, len
);
310 BOOST_AUTO_TEST_CASE(addECSWithoutEDNSAlreadyParsed
)
312 bool ednsAdded
= false;
313 bool ecsAdded
= false;
314 ComboAddress
remote("192.0.2.1");
315 DNSName
name("www.powerdns.com.");
317 vector
<uint8_t> query
;
318 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
319 pw
.getHeader()->rd
= 1;
321 /* large enough packet */
323 memcpy(packet
, query
.data(), query
.size());
325 unsigned int consumed
= 0;
328 DNSName
qname(packet
, query
.size(), sizeof(dnsheader
), false, &qtype
, &qclass
, &consumed
);
329 BOOST_CHECK_EQUAL(qname
, name
);
330 BOOST_CHECK(qtype
== QType::A
);
331 BOOST_CHECK(qclass
== QClass::IN
);
333 DNSQuestion
dq(&qname
, qtype
, qclass
, consumed
, nullptr, &remote
, reinterpret_cast<dnsheader
*>(packet
), sizeof(packet
), query
.size(), false, nullptr);
334 /* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
335 BOOST_CHECK(!parseEDNSOptions(dq
));
337 /* And now we add our own ECS */
338 BOOST_CHECK(handleEDNSClientSubnet(dq
, &ednsAdded
, &ecsAdded
, false));
339 BOOST_CHECK_GT(static_cast<size_t>(dq
.len
), query
.size());
340 BOOST_CHECK_EQUAL(ednsAdded
, true);
341 BOOST_CHECK_EQUAL(ecsAdded
, false);
342 validateQuery(packet
, dq
.len
);
343 validateECS(packet
, dq
.len
, remote
);
345 /* not large enough packet */
349 qname
= DNSName(reinterpret_cast<char*>(query
.data()), query
.size(), sizeof(dnsheader
), false, &qtype
, &qclass
, &consumed
);
350 BOOST_CHECK_EQUAL(qname
, name
);
351 BOOST_CHECK(qtype
== QType::A
);
352 BOOST_CHECK(qclass
== QClass::IN
);
353 DNSQuestion
dq2(&qname
, qtype
, qclass
, consumed
, nullptr, &remote
, reinterpret_cast<dnsheader
*>(query
.data()), query
.size(), query
.size(), false, nullptr);
355 BOOST_CHECK(!handleEDNSClientSubnet(dq2
, &ednsAdded
, &ecsAdded
, false));
356 BOOST_CHECK_EQUAL(static_cast<size_t>(dq2
.len
), query
.size());
357 BOOST_CHECK_EQUAL(ednsAdded
, false);
358 BOOST_CHECK_EQUAL(ecsAdded
, false);
359 validateQuery(reinterpret_cast<char*>(query
.data()), dq2
.len
, false);
362 BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS
) {
363 bool ednsAdded
= false;
364 bool ecsAdded
= false;
366 DNSName
name("www.powerdns.com.");
368 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
370 vector
<uint8_t> query
;
371 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
372 pw
.getHeader()->rd
= 1;
373 pw
.addOpt(512, 0, 0);
375 uint16_t len
= query
.size();
377 /* large enough packet */
379 memcpy(packet
, query
.data(), query
.size());
381 unsigned int consumed
= 0;
383 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
384 BOOST_CHECK_EQUAL(qname
, name
);
385 BOOST_CHECK(qtype
== QType::A
);
387 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, &ednsAdded
, &ecsAdded
, false, newECSOption
, false));
388 BOOST_CHECK((size_t) len
> query
.size());
389 BOOST_CHECK_EQUAL(ednsAdded
, false);
390 BOOST_CHECK_EQUAL(ecsAdded
, true);
391 validateQuery(packet
, len
);
392 validateECS(packet
, len
, remote
);
394 /* not large enough packet */
399 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
400 BOOST_CHECK_EQUAL(qname
, name
);
401 BOOST_CHECK(qtype
== QType::A
);
403 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, &ednsAdded
, &ecsAdded
, false, newECSOption
, false));
404 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
405 BOOST_CHECK_EQUAL(ednsAdded
, false);
406 BOOST_CHECK_EQUAL(ecsAdded
, false);
407 validateQuery(reinterpret_cast<char*>(query
.data()), len
);
410 BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECSAlreadyParsed
) {
411 bool ednsAdded
= false;
412 bool ecsAdded
= false;
413 ComboAddress
remote("2001:DB8::1");
414 DNSName
name("www.powerdns.com.");
416 vector
<uint8_t> query
;
417 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
418 pw
.getHeader()->rd
= 1;
419 pw
.addOpt(512, 0, 0);
422 /* large enough packet */
424 memcpy(packet
, query
.data(), query
.size());
426 unsigned int consumed
= 0;
429 DNSName
qname(packet
, query
.size(), sizeof(dnsheader
), false, &qtype
, &qclass
, &consumed
);
430 BOOST_CHECK_EQUAL(qname
, name
);
431 BOOST_CHECK(qtype
== QType::A
);
432 BOOST_CHECK(qclass
== QClass::IN
);
434 DNSQuestion
dq(&qname
, qtype
, qclass
, consumed
, nullptr, &remote
, reinterpret_cast<dnsheader
*>(packet
), sizeof(packet
), query
.size(), false, nullptr);
435 /* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
436 BOOST_CHECK(parseEDNSOptions(dq
));
438 /* And now we add our own ECS */
439 BOOST_CHECK(handleEDNSClientSubnet(dq
, &ednsAdded
, &ecsAdded
, false));
440 BOOST_CHECK_GT(static_cast<size_t>(dq
.len
), query
.size());
441 BOOST_CHECK_EQUAL(ednsAdded
, false);
442 BOOST_CHECK_EQUAL(ecsAdded
, true);
443 validateQuery(packet
, dq
.len
);
444 validateECS(packet
, dq
.len
, remote
);
446 /* not large enough packet */
450 qname
= DNSName(reinterpret_cast<char*>(query
.data()), query
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
451 BOOST_CHECK_EQUAL(qname
, name
);
452 BOOST_CHECK(qtype
== QType::A
);
453 BOOST_CHECK(qclass
== QClass::IN
);
454 DNSQuestion
dq2(&qname
, qtype
, qclass
, consumed
, nullptr, &remote
, reinterpret_cast<dnsheader
*>(query
.data()), query
.size(), query
.size(), false, nullptr);
456 BOOST_CHECK(!handleEDNSClientSubnet(dq2
, &ednsAdded
, &ecsAdded
, false));
457 BOOST_CHECK_EQUAL(static_cast<size_t>(dq2
.len
), query
.size());
458 BOOST_CHECK_EQUAL(ednsAdded
, false);
459 BOOST_CHECK_EQUAL(ecsAdded
, false);
460 validateQuery(reinterpret_cast<char*>(query
.data()), dq2
.len
);
463 BOOST_AUTO_TEST_CASE(replaceECSWithSameSize
) {
464 bool ednsAdded
= false;
465 bool ecsAdded
= false;
466 ComboAddress
remote("192.168.1.25");
467 DNSName
name("www.powerdns.com.");
468 ComboAddress
origRemote("127.0.0.1");
470 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
472 vector
<uint8_t> query
;
473 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
474 pw
.getHeader()->rd
= 1;
475 EDNSSubnetOpts ecsOpts
;
476 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
477 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
478 DNSPacketWriter::optvect_t opts
;
479 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
480 pw
.addOpt(512, 0, 0, opts
);
482 uint16_t len
= query
.size();
484 /* large enough packet */
486 memcpy(packet
, query
.data(), query
.size());
488 unsigned int consumed
= 0;
490 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
491 BOOST_CHECK_EQUAL(qname
, name
);
492 BOOST_CHECK(qtype
== QType::A
);
494 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, &ednsAdded
, &ecsAdded
, true, newECSOption
, false));
495 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
496 BOOST_CHECK_EQUAL(ednsAdded
, false);
497 BOOST_CHECK_EQUAL(ecsAdded
, false);
498 validateQuery(packet
, len
);
499 validateECS(packet
, len
, remote
);
502 BOOST_AUTO_TEST_CASE(replaceECSWithSameSizeAlreadyParsed
) {
503 bool ednsAdded
= false;
504 bool ecsAdded
= false;
505 ComboAddress
remote("192.168.1.25");
506 DNSName
name("www.powerdns.com.");
507 ComboAddress
origRemote("127.0.0.1");
509 vector
<uint8_t> query
;
510 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
511 pw
.getHeader()->rd
= 1;
512 EDNSSubnetOpts ecsOpts
;
513 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
514 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
515 DNSPacketWriter::optvect_t opts
;
516 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
517 pw
.addOpt(512, 0, 0, opts
);
520 /* large enough packet */
522 memcpy(packet
, query
.data(), query
.size());
524 unsigned int consumed
= 0;
527 DNSName
qname(packet
, query
.size(), sizeof(dnsheader
), false, &qtype
, &qclass
, &consumed
);
528 BOOST_CHECK_EQUAL(qname
, name
);
529 BOOST_CHECK(qtype
== QType::A
);
530 BOOST_CHECK(qclass
== QClass::IN
);
532 DNSQuestion
dq(&qname
, qtype
, qclass
, consumed
, nullptr, &remote
, reinterpret_cast<dnsheader
*>(packet
), sizeof(packet
), query
.size(), false, nullptr);
533 dq
.ecsOverride
= true;
535 /* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
536 BOOST_CHECK(parseEDNSOptions(dq
));
538 /* And now we add our own ECS */
539 BOOST_CHECK(handleEDNSClientSubnet(dq
, &ednsAdded
, &ecsAdded
, false));
540 BOOST_CHECK_EQUAL(static_cast<size_t>(dq
.len
), query
.size());
541 BOOST_CHECK_EQUAL(ednsAdded
, false);
542 BOOST_CHECK_EQUAL(ecsAdded
, false);
543 validateQuery(packet
, dq
.len
);
544 validateECS(packet
, dq
.len
, remote
);
547 BOOST_AUTO_TEST_CASE(replaceECSWithSmaller
) {
548 bool ednsAdded
= false;
549 bool ecsAdded
= false;
550 ComboAddress
remote("192.168.1.25");
551 DNSName
name("www.powerdns.com.");
552 ComboAddress
origRemote("127.0.0.1");
554 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
556 vector
<uint8_t> query
;
557 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
558 pw
.getHeader()->rd
= 1;
559 EDNSSubnetOpts ecsOpts
;
560 ecsOpts
.source
= Netmask(origRemote
, 32);
561 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
562 DNSPacketWriter::optvect_t opts
;
563 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
564 pw
.addOpt(512, 0, 0, opts
);
566 uint16_t len
= query
.size();
568 /* large enough packet */
570 memcpy(packet
, query
.data(), query
.size());
572 unsigned int consumed
= 0;
574 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
575 BOOST_CHECK_EQUAL(qname
, name
);
576 BOOST_CHECK(qtype
== QType::A
);
578 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, &ednsAdded
, &ecsAdded
, true, newECSOption
, false));
579 BOOST_CHECK((size_t) len
< query
.size());
580 BOOST_CHECK_EQUAL(ednsAdded
, false);
581 BOOST_CHECK_EQUAL(ecsAdded
, false);
582 validateQuery(packet
, len
);
583 validateECS(packet
, len
, remote
);
586 BOOST_AUTO_TEST_CASE(replaceECSWithLarger
) {
587 bool ednsAdded
= false;
588 bool ecsAdded
= false;
589 ComboAddress
remote("192.168.1.25");
590 DNSName
name("www.powerdns.com.");
591 ComboAddress
origRemote("127.0.0.1");
593 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
595 vector
<uint8_t> query
;
596 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
597 pw
.getHeader()->rd
= 1;
598 EDNSSubnetOpts ecsOpts
;
599 ecsOpts
.source
= Netmask(origRemote
, 8);
600 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
601 DNSPacketWriter::optvect_t opts
;
602 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
603 pw
.addOpt(512, 0, 0, opts
);
605 uint16_t len
= query
.size();
607 /* large enough packet */
609 memcpy(packet
, query
.data(), query
.size());
611 unsigned int consumed
= 0;
613 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
614 BOOST_CHECK_EQUAL(qname
, name
);
615 BOOST_CHECK(qtype
== QType::A
);
617 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, &ednsAdded
, &ecsAdded
, true, newECSOption
, false));
618 BOOST_CHECK((size_t) len
> query
.size());
619 BOOST_CHECK_EQUAL(ednsAdded
, false);
620 BOOST_CHECK_EQUAL(ecsAdded
, false);
621 validateQuery(packet
, len
);
622 validateECS(packet
, len
, remote
);
624 /* not large enough packet */
629 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
630 BOOST_CHECK_EQUAL(qname
, name
);
631 BOOST_CHECK(qtype
== QType::A
);
633 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, &ednsAdded
, &ecsAdded
, true, newECSOption
, false));
634 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
635 BOOST_CHECK_EQUAL(ednsAdded
, false);
636 BOOST_CHECK_EQUAL(ecsAdded
, false);
637 validateQuery(reinterpret_cast<char*>(query
.data()), len
);
640 BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst
) {
641 DNSName
name("www.powerdns.com.");
643 vector
<uint8_t> response
;
644 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
645 pw
.getHeader()->qr
= 1;
646 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
647 pw
.xfr32BitInt(0x01020304);
648 pw
.addOpt(512, 0, 0);
650 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
651 pw
.xfr32BitInt(0x01020304);
654 vector
<uint8_t> newResponse
;
655 int res
= rewriteResponseWithoutEDNS(std::string((const char *) response
.data(), response
.size()), newResponse
);
656 BOOST_CHECK_EQUAL(res
, 0);
658 unsigned int consumed
= 0;
660 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
661 BOOST_CHECK_EQUAL(qname
, name
);
662 BOOST_CHECK(qtype
== QType::A
);
663 size_t const ednsOptRRSize
= sizeof(struct dnsrecordheader
) + 1 /* root in OPT RR */;
664 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - ednsOptRRSize
);
666 validateResponse((const char *) newResponse
.data(), newResponse
.size(), false, 1);
669 BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary
) {
670 DNSName
name("www.powerdns.com.");
672 vector
<uint8_t> response
;
673 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
674 pw
.getHeader()->qr
= 1;
675 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
676 pw
.xfr32BitInt(0x01020304);
677 pw
.startRecord(DNSName("other.powerdns.com."), QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
678 pw
.xfr32BitInt(0x01020304);
680 pw
.addOpt(512, 0, 0);
682 pw
.startRecord(DNSName("yetanother.powerdns.com."), QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
683 pw
.xfr32BitInt(0x01020304);
686 vector
<uint8_t> newResponse
;
687 int res
= rewriteResponseWithoutEDNS(std::string((const char *) response
.data(), response
.size()), newResponse
);
688 BOOST_CHECK_EQUAL(res
, 0);
690 unsigned int consumed
= 0;
692 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
693 BOOST_CHECK_EQUAL(qname
, name
);
694 BOOST_CHECK(qtype
== QType::A
);
695 size_t const ednsOptRRSize
= sizeof(struct dnsrecordheader
) + 1 /* root in OPT RR */;
696 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - ednsOptRRSize
);
698 validateResponse((const char *) newResponse
.data(), newResponse
.size(), false, 2);
701 BOOST_AUTO_TEST_CASE(removeEDNSWhenLast
) {
702 DNSName
name("www.powerdns.com.");
704 vector
<uint8_t> response
;
705 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
706 pw
.getHeader()->qr
= 1;
707 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
708 pw
.xfr32BitInt(0x01020304);
710 pw
.startRecord(DNSName("other.powerdns.com."), QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
711 pw
.xfr32BitInt(0x01020304);
713 pw
.addOpt(512, 0, 0);
716 vector
<uint8_t> newResponse
;
717 int res
= rewriteResponseWithoutEDNS(std::string((const char *) response
.data(), response
.size()), newResponse
);
719 BOOST_CHECK_EQUAL(res
, 0);
721 unsigned int consumed
= 0;
723 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
724 BOOST_CHECK_EQUAL(qname
, name
);
725 BOOST_CHECK(qtype
== QType::A
);
726 size_t const ednsOptRRSize
= sizeof(struct dnsrecordheader
) + 1 /* root in OPT RR */;
727 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - ednsOptRRSize
);
729 validateResponse((const char *) newResponse
.data(), newResponse
.size(), false, 1);
732 BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption
) {
733 DNSName
name("www.powerdns.com.");
734 ComboAddress
origRemote("127.0.0.1");
736 vector
<uint8_t> response
;
737 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
738 pw
.getHeader()->qr
= 1;
739 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
740 pw
.xfr32BitInt(0x01020304);
742 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
743 pw
.xfr32BitInt(0x01020304);
746 EDNSSubnetOpts ecsOpts
;
747 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
748 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
749 DNSPacketWriter::optvect_t opts
;
750 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
751 pw
.addOpt(512, 0, 0, opts
);
758 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
759 BOOST_CHECK_EQUAL(res
, 0);
760 BOOST_CHECK_EQUAL(last
, true);
762 size_t responseLen
= response
.size();
763 size_t existingOptLen
= optLen
;
764 BOOST_CHECK(existingOptLen
< responseLen
);
765 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
766 BOOST_CHECK_EQUAL(res
, 0);
767 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
768 responseLen
-= (existingOptLen
- optLen
);
770 unsigned int consumed
= 0;
772 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
773 BOOST_CHECK_EQUAL(qname
, name
);
774 BOOST_CHECK(qtype
== QType::A
);
776 validateResponse((const char *) response
.data(), responseLen
, true, 1);
779 BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption
) {
780 DNSName
name("www.powerdns.com.");
781 ComboAddress
origRemote("127.0.0.1");
783 vector
<uint8_t> response
;
784 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
785 pw
.getHeader()->qr
= 1;
786 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
787 pw
.xfr32BitInt(0x01020304);
789 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
790 pw
.xfr32BitInt(0x01020304);
793 EDNSSubnetOpts ecsOpts
;
794 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV6
);
795 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
796 EDNSCookiesOpt cookiesOpt
;
797 cookiesOpt
.client
= string("deadbeef");
798 cookiesOpt
.server
= string("deadbeef");
799 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
800 DNSPacketWriter::optvect_t opts
;
801 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
802 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
803 pw
.addOpt(512, 0, 0, opts
);
810 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
811 BOOST_CHECK_EQUAL(res
, 0);
812 BOOST_CHECK_EQUAL(last
, true);
814 size_t responseLen
= response
.size();
815 size_t existingOptLen
= optLen
;
816 BOOST_CHECK(existingOptLen
< responseLen
);
817 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
818 BOOST_CHECK_EQUAL(res
, 0);
819 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
820 responseLen
-= (existingOptLen
- optLen
);
822 unsigned int consumed
= 0;
824 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
825 BOOST_CHECK_EQUAL(qname
, name
);
826 BOOST_CHECK(qtype
== QType::A
);
828 validateResponse((const char *) response
.data(), responseLen
, true, 1);
831 BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption
) {
832 DNSName
name("www.powerdns.com.");
833 ComboAddress
origRemote("127.0.0.1");
835 vector
<uint8_t> response
;
836 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
837 pw
.getHeader()->qr
= 1;
838 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
839 pw
.xfr32BitInt(0x01020304);
841 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
842 pw
.xfr32BitInt(0x01020304);
845 EDNSSubnetOpts ecsOpts
;
846 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
847 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
849 EDNSCookiesOpt cookiesOpt
;
850 cookiesOpt
.client
= string("deadbeef");
851 cookiesOpt
.server
= string("deadbeef");
852 string cookiesOptionStr1
= makeEDNSCookiesOptString(cookiesOpt
);
853 string cookiesOptionStr2
= makeEDNSCookiesOptString(cookiesOpt
);
855 DNSPacketWriter::optvect_t opts
;
856 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr1
));
857 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
858 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr2
));
859 pw
.addOpt(512, 0, 0, opts
);
866 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
867 BOOST_CHECK_EQUAL(res
, 0);
868 BOOST_CHECK_EQUAL(last
, true);
870 size_t responseLen
= response
.size();
871 size_t existingOptLen
= optLen
;
872 BOOST_CHECK(existingOptLen
< responseLen
);
873 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
874 BOOST_CHECK_EQUAL(res
, 0);
875 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
876 responseLen
-= (existingOptLen
- optLen
);
878 unsigned int consumed
= 0;
880 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
881 BOOST_CHECK_EQUAL(qname
, name
);
882 BOOST_CHECK(qtype
== QType::A
);
884 validateResponse((const char *) response
.data(), responseLen
, true, 1);
887 BOOST_AUTO_TEST_CASE(removeECSWhenLastOption
) {
888 DNSName
name("www.powerdns.com.");
889 ComboAddress
origRemote("127.0.0.1");
891 vector
<uint8_t> response
;
892 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
893 pw
.getHeader()->qr
= 1;
894 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
895 pw
.xfr32BitInt(0x01020304);
897 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
898 pw
.xfr32BitInt(0x01020304);
901 EDNSCookiesOpt cookiesOpt
;
902 cookiesOpt
.client
= string("deadbeef");
903 cookiesOpt
.server
= string("deadbeef");
904 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
905 EDNSSubnetOpts ecsOpts
;
906 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
907 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
908 DNSPacketWriter::optvect_t opts
;
909 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
910 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
911 pw
.addOpt(512, 0, 0, opts
);
918 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
919 BOOST_CHECK_EQUAL(res
, 0);
920 BOOST_CHECK_EQUAL(last
, true);
922 size_t responseLen
= response
.size();
923 size_t existingOptLen
= optLen
;
924 BOOST_CHECK(existingOptLen
< responseLen
);
925 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
926 BOOST_CHECK_EQUAL(res
, 0);
927 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
928 responseLen
-= (existingOptLen
- optLen
);
930 unsigned int consumed
= 0;
932 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
933 BOOST_CHECK_EQUAL(qname
, name
);
934 BOOST_CHECK(qtype
== QType::A
);
936 validateResponse((const char *) response
.data(), responseLen
, true, 1);
939 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption
) {
940 DNSName
name("www.powerdns.com.");
941 ComboAddress
origRemote("127.0.0.1");
943 vector
<uint8_t> response
;
944 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
945 pw
.getHeader()->qr
= 1;
946 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
947 pw
.xfr32BitInt(0x01020304);
949 EDNSSubnetOpts ecsOpts
;
950 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
951 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
952 DNSPacketWriter::optvect_t opts
;
953 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
954 pw
.addOpt(512, 0, 0, opts
);
957 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
958 pw
.xfr32BitInt(0x01020304);
961 vector
<uint8_t> newResponse
;
962 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
963 BOOST_CHECK_EQUAL(res
, 0);
965 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
967 unsigned int consumed
= 0;
969 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
970 BOOST_CHECK_EQUAL(qname
, name
);
971 BOOST_CHECK(qtype
== QType::A
);
973 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
976 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption
) {
977 DNSName
name("www.powerdns.com.");
978 ComboAddress
origRemote("127.0.0.1");
980 vector
<uint8_t> response
;
981 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
982 pw
.getHeader()->qr
= 1;
983 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
984 pw
.xfr32BitInt(0x01020304);
986 EDNSSubnetOpts ecsOpts
;
987 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
988 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
989 EDNSCookiesOpt cookiesOpt
;
990 cookiesOpt
.client
= string("deadbeef");
991 cookiesOpt
.server
= string("deadbeef");
992 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
993 DNSPacketWriter::optvect_t opts
;
994 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
995 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
996 pw
.addOpt(512, 0, 0, opts
);
999 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1000 pw
.xfr32BitInt(0x01020304);
1003 vector
<uint8_t> newResponse
;
1004 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
1005 BOOST_CHECK_EQUAL(res
, 0);
1007 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
1009 unsigned int consumed
= 0;
1011 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1012 BOOST_CHECK_EQUAL(qname
, name
);
1013 BOOST_CHECK(qtype
== QType::A
);
1015 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
1018 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption
) {
1019 DNSName
name("www.powerdns.com.");
1020 ComboAddress
origRemote("127.0.0.1");
1022 vector
<uint8_t> response
;
1023 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1024 pw
.getHeader()->qr
= 1;
1025 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1026 pw
.xfr32BitInt(0x01020304);
1028 EDNSSubnetOpts ecsOpts
;
1029 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1030 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1031 EDNSCookiesOpt cookiesOpt
;
1032 cookiesOpt
.client
= string("deadbeef");
1033 cookiesOpt
.server
= string("deadbeef");
1034 string cookiesOptionStr1
= makeEDNSCookiesOptString(cookiesOpt
);
1035 string cookiesOptionStr2
= makeEDNSCookiesOptString(cookiesOpt
);
1036 DNSPacketWriter::optvect_t opts
;
1037 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr1
));
1038 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1039 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr2
));
1040 pw
.addOpt(512, 0, 0, opts
);
1043 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1044 pw
.xfr32BitInt(0x01020304);
1047 vector
<uint8_t> newResponse
;
1048 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
1049 BOOST_CHECK_EQUAL(res
, 0);
1051 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
1053 unsigned int consumed
= 0;
1055 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1056 BOOST_CHECK_EQUAL(qname
, name
);
1057 BOOST_CHECK(qtype
== QType::A
);
1059 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
1062 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption
) {
1063 DNSName
name("www.powerdns.com.");
1064 ComboAddress
origRemote("127.0.0.1");
1066 vector
<uint8_t> response
;
1067 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1068 pw
.getHeader()->qr
= 1;
1069 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1070 pw
.xfr32BitInt(0x01020304);
1072 EDNSSubnetOpts ecsOpts
;
1073 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1074 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1075 EDNSCookiesOpt cookiesOpt
;
1076 cookiesOpt
.client
= string("deadbeef");
1077 cookiesOpt
.server
= string("deadbeef");
1078 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1079 DNSPacketWriter::optvect_t opts
;
1080 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1081 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1082 pw
.addOpt(512, 0, 0, opts
);
1085 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1086 pw
.xfr32BitInt(0x01020304);
1089 vector
<uint8_t> newResponse
;
1090 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
1091 BOOST_CHECK_EQUAL(res
, 0);
1093 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
1095 unsigned int consumed
= 0;
1097 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1098 BOOST_CHECK_EQUAL(qname
, name
);
1099 BOOST_CHECK(qtype
== QType::A
);
1101 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
1104 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
)
1106 dnsheader
* dh
= reinterpret_cast<dnsheader
*>(query
.data());
1108 DNSQuestion
dq(&qname
, qtype
, qclass
, qname
.wirelength(), &lc
, &rem
, dh
, query
.size(), len
, false, &realTime
);
1112 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)
1114 size_t length
= query
.size();
1119 auto dq
= getDNSQuestion(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
, length
);
1121 BOOST_CHECK(addEDNSToQueryTurnedResponse(dq
));
1126 static int getZ(const DNSName
& qname
, const uint16_t qtype
, const uint16_t qclass
, vector
<uint8_t>& query
)
1128 ComboAddress
lc("127.0.0.1");
1129 ComboAddress
rem("127.0.0.1");
1130 struct timespec queryRealTime
;
1131 gettime(&queryRealTime
, true);
1132 size_t length
= query
.size();
1133 DNSQuestion dq
= getDNSQuestion(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
, length
);
1135 return getEDNSZ(dq
);
1138 BOOST_AUTO_TEST_CASE(test_getEDNSZ
) {
1141 uint16_t udpPayloadSize
;
1142 DNSName
qname("www.powerdns.com.");
1143 uint16_t qtype
= QType::A
;
1144 uint16_t qclass
= QClass::IN
;
1145 EDNSSubnetOpts ecsOpts
;
1146 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1147 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1148 EDNSCookiesOpt cookiesOpt
;
1149 cookiesOpt
.client
= string("deadbeef");
1150 cookiesOpt
.server
= string("deadbeef");
1151 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1152 DNSPacketWriter::optvect_t opts
;
1153 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1154 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1158 vector
<uint8_t> query
;
1159 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1162 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1163 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), false);
1164 BOOST_CHECK_EQUAL(z
, 0);
1165 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1169 /* truncated EDNS */
1170 vector
<uint8_t> query
;
1171 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1172 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1175 query
.resize(query
.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
1176 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1177 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), false);
1178 BOOST_CHECK_EQUAL(z
, 0);
1179 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1183 /* valid EDNS, no options, DO not set */
1184 vector
<uint8_t> query
;
1185 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1186 pw
.addOpt(512, 0, 0);
1189 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1190 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1191 BOOST_CHECK_EQUAL(z
, 0);
1192 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1196 /* valid EDNS, no options, DO set */
1197 vector
<uint8_t> query
;
1198 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1199 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1202 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), EDNS_HEADER_FLAG_DO
);
1203 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1204 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1205 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1209 /* valid EDNS, options, DO not set */
1210 vector
<uint8_t> query
;
1211 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1212 pw
.addOpt(512, 0, 0, opts
);
1215 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1216 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1217 BOOST_CHECK_EQUAL(z
, 0);
1218 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1222 /* valid EDNS, options, DO set */
1223 vector
<uint8_t> query
;
1224 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1225 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
, opts
);
1228 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), EDNS_HEADER_FLAG_DO
);
1229 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1230 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1231 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1236 BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse
) {
1239 uint16_t udpPayloadSize
;
1240 DNSName
qname("www.powerdns.com.");
1241 uint16_t qtype
= QType::A
;
1242 uint16_t qclass
= QClass::IN
;
1243 EDNSSubnetOpts ecsOpts
;
1244 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1245 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1246 EDNSCookiesOpt cookiesOpt
;
1247 cookiesOpt
.client
= string("deadbeef");
1248 cookiesOpt
.server
= string("deadbeef");
1249 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1250 DNSPacketWriter::optvect_t opts
;
1251 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1252 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1253 ComboAddress
lc("127.0.0.1");
1254 ComboAddress
rem("127.0.0.1");
1255 struct timespec queryRealTime
;
1256 gettime(&queryRealTime
, true);
1260 vector
<uint8_t> query
;
1261 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1262 pw
.getHeader()->qr
= 1;
1263 pw
.getHeader()->rcode
= RCode::NXDomain
;
1266 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1267 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1268 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), false);
1269 BOOST_CHECK_EQUAL(z
, 0);
1270 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1274 /* truncated EDNS */
1275 vector
<uint8_t> query
;
1276 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1277 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1280 query
.resize(query
.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
1281 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1282 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1283 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), false);
1284 BOOST_CHECK_EQUAL(z
, 0);
1285 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1289 /* valid EDNS, no options, DO not set */
1290 vector
<uint8_t> query
;
1291 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1292 pw
.addOpt(512, 0, 0);
1295 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1296 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1297 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1298 BOOST_CHECK_EQUAL(z
, 0);
1299 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1303 /* valid EDNS, no options, DO set */
1304 vector
<uint8_t> query
;
1305 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1306 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1309 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1310 BOOST_CHECK_EQUAL(getEDNSZ(dq
), EDNS_HEADER_FLAG_DO
);
1311 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1312 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1313 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1317 /* valid EDNS, options, DO not set */
1318 vector
<uint8_t> query
;
1319 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1320 pw
.addOpt(512, 0, 0, opts
);
1323 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1324 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1325 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1326 BOOST_CHECK_EQUAL(z
, 0);
1327 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1331 /* valid EDNS, options, DO set */
1332 vector
<uint8_t> query
;
1333 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1334 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
, opts
);
1337 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1338 BOOST_CHECK_EQUAL(getEDNSZ(dq
), EDNS_HEADER_FLAG_DO
);
1339 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1340 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1341 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1345 BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart
) {
1346 const DNSName
qname("www.powerdns.com.");
1347 const uint16_t qtype
= QType::A
;
1348 const uint16_t qclass
= QClass::IN
;
1349 EDNSSubnetOpts ecsOpts
;
1350 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1351 const string ecsOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1352 DNSPacketWriter::optvect_t opts
;
1353 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1354 const ComboAddress
lc("127.0.0.1");
1355 const ComboAddress
rem("127.0.0.1");
1356 uint16_t optRDPosition
;
1359 const size_t optRDExpectedOffset
= sizeof(dnsheader
) + qname
.wirelength() + DNS_TYPE_SIZE
+ DNS_CLASS_SIZE
+ /* root */ 1 + DNS_TYPE_SIZE
+ DNS_CLASS_SIZE
+ DNS_TTL_SIZE
;
1363 vector
<uint8_t> query
;
1364 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1365 pw
.getHeader()->qr
= 1;
1366 pw
.getHeader()->rcode
= RCode::NXDomain
;
1369 int res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1371 BOOST_CHECK_EQUAL(res
, ENOENT
);
1373 /* truncated packet (should not matter) */
1374 query
.resize(query
.size() - 1);
1375 res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1377 BOOST_CHECK_EQUAL(res
, ENOENT
);
1381 /* valid EDNS, no options */
1382 vector
<uint8_t> query
;
1383 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1384 pw
.addOpt(512, 0, 0);
1387 int res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1389 BOOST_CHECK_EQUAL(res
, 0);
1390 BOOST_CHECK_EQUAL(optRDPosition
, optRDExpectedOffset
);
1391 BOOST_CHECK_EQUAL(remaining
, query
.size() - optRDExpectedOffset
);
1393 /* truncated packet */
1394 query
.resize(query
.size() - 1);
1396 res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1397 BOOST_CHECK_EQUAL(res
, ENOENT
);
1401 /* valid EDNS, options */
1402 vector
<uint8_t> query
;
1403 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1404 pw
.addOpt(512, 0, 0, opts
);
1407 int res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1409 BOOST_CHECK_EQUAL(res
, 0);
1410 BOOST_CHECK_EQUAL(optRDPosition
, optRDExpectedOffset
);
1411 BOOST_CHECK_EQUAL(remaining
, query
.size() - optRDExpectedOffset
);
1413 /* truncated options (should not matter for this test) */
1414 query
.resize(query
.size() - 1);
1415 res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1416 BOOST_CHECK_EQUAL(res
, 0);
1417 BOOST_CHECK_EQUAL(optRDPosition
, optRDExpectedOffset
);
1418 BOOST_CHECK_EQUAL(remaining
, query
.size() - optRDExpectedOffset
);
1423 BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt
) {
1425 auto locateEDNSOption
= [](const vector
<uint8_t>& query
, uint16_t code
, size_t* optContentStart
, uint16_t* optContentLen
) {
1429 std::string
packetStr(reinterpret_cast<const char*>(query
.data()), query
.size());
1430 int res
= locateEDNSOptRR(packetStr
, &optStart
, &optLen
, &last
);
1436 if (optLen
< optRecordMinimumSize
) {
1440 if (optStart
< query
.size() && packetStr
.at(optStart
) != 0) {
1441 // OPT RR Name != '.'
1445 return isEDNSOptionInOpt(packetStr
, optStart
, optLen
, code
, optContentStart
, optContentLen
);
1448 const DNSName
qname("www.powerdns.com.");
1449 const uint16_t qtype
= QType::A
;
1450 const uint16_t qclass
= QClass::IN
;
1451 EDNSSubnetOpts ecsOpts
;
1452 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1453 const string ecsOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1454 const size_t sizeOfECSContent
= ecsOptionStr
.size();
1455 EDNSCookiesOpt cookiesOpt
;
1456 cookiesOpt
.client
= string("deadbeef");
1457 cookiesOpt
.server
= string("deadbeef");
1458 const string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1459 const size_t sizeOfCookieOption
= /* option code */ 2 + /* option length */ 2 + cookiesOpt
.client
.size() + cookiesOpt
.server
.size();
1461 DNSPacketWriter::optvect_t opts;
1462 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
1463 opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
1464 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
1466 const ComboAddress
lc("127.0.0.1");
1467 const ComboAddress
rem("127.0.0.1");
1468 size_t optContentStart
;
1469 uint16_t optContentLen
;
1471 const size_t optRDExpectedOffset
= sizeof(dnsheader
) + qname
.wirelength() + DNS_TYPE_SIZE
+ DNS_CLASS_SIZE
+ /* root */ 1 + DNS_TYPE_SIZE
+ DNS_CLASS_SIZE
+ DNS_TTL_SIZE
;
1475 vector
<uint8_t> query
;
1476 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1477 pw
.getHeader()->qr
= 1;
1478 pw
.getHeader()->rcode
= RCode::NXDomain
;
1481 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1482 BOOST_CHECK_EQUAL(found
, false);
1484 /* truncated packet (should not matter here) */
1485 query
.resize(query
.size() - 1);
1486 found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1487 BOOST_CHECK_EQUAL(found
, false);
1491 /* valid EDNS, no options */
1492 vector
<uint8_t> query
;
1493 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1494 pw
.addOpt(512, 0, 0);
1497 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1498 BOOST_CHECK_EQUAL(found
, false);
1500 /* truncated packet */
1501 query
.resize(query
.size() - 1);
1502 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::out_of_range
);
1506 /* valid EDNS, two cookie options but no ECS */
1507 vector
<uint8_t> query
;
1508 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1509 DNSPacketWriter::optvect_t opts
;
1510 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1511 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1512 pw
.addOpt(512, 0, 0, opts
);
1515 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1516 BOOST_CHECK_EQUAL(found
, false);
1518 /* truncated packet */
1519 query
.resize(query
.size() - 1);
1520 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::range_error
);
1524 /* valid EDNS, two ECS */
1525 vector
<uint8_t> query
;
1526 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1527 DNSPacketWriter::optvect_t opts
;
1528 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1529 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1530 pw
.addOpt(512, 0, 0, opts
);
1533 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1534 BOOST_CHECK_EQUAL(found
, true);
1535 if (found
== true) {
1536 BOOST_CHECK_EQUAL(optContentStart
, optRDExpectedOffset
+ sizeof(uint16_t) /* RD len */ + /* option code */ 2 + /* option length */ 2);
1537 BOOST_CHECK_EQUAL(optContentLen
, sizeOfECSContent
);
1540 /* truncated packet */
1541 query
.resize(query
.size() - 1);
1542 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::range_error
);
1546 /* valid EDNS, one ECS between two cookies */
1547 vector
<uint8_t> query
;
1548 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1549 DNSPacketWriter::optvect_t opts
;
1550 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1551 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1552 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1553 pw
.addOpt(512, 0, 0, opts
);
1556 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1557 BOOST_CHECK_EQUAL(found
, true);
1558 if (found
== true) {
1559 BOOST_CHECK_EQUAL(optContentStart
, optRDExpectedOffset
+ sizeof(uint16_t) /* RD len */ + sizeOfCookieOption
+ /* option code */ 2 + /* option length */ 2);
1560 BOOST_CHECK_EQUAL(optContentLen
, sizeOfECSContent
);
1563 /* truncated packet */
1564 query
.resize(query
.size() - 1);
1565 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::range_error
);
1569 BOOST_AUTO_TEST_SUITE_END();