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, uint16_t additionals
=0, uint16_t answers
=0, uint16_t authorities
=0)
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
, 1U);
52 BOOST_CHECK_EQUAL(mdp
.d_header
.ancount
, answers
);
53 BOOST_CHECK_EQUAL(mdp
.d_header
.nscount
, authorities
);
54 uint16_t expectedARCount
= additionals
+ (hasEdns
? 1U : 0U) + (hasXPF
? 1U : 0U);
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(), 1U);
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(), 1U);
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
, 1U);
86 BOOST_CHECK_EQUAL(mdp
.d_header
.qdcount
, 1U);
87 BOOST_CHECK_EQUAL(mdp
.d_header
.ancount
, 1U);
88 BOOST_CHECK_EQUAL(mdp
.d_header
.nscount
, 0U);
89 BOOST_CHECK_EQUAL(mdp
.d_header
.arcount
, (hasEdns
? 1U : 0U) + 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
, true);
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
, true);
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
, true);
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
, true);
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(replaceECSFollowedByTSIG
) {
641 bool ednsAdded
= false;
642 bool ecsAdded
= false;
643 ComboAddress
remote("192.168.1.25");
644 DNSName
name("www.powerdns.com.");
645 ComboAddress
origRemote("127.0.0.1");
647 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
649 vector
<uint8_t> query
;
650 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
651 pw
.getHeader()->rd
= 1;
652 EDNSSubnetOpts ecsOpts
;
653 ecsOpts
.source
= Netmask(origRemote
, 8);
654 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
655 DNSPacketWriter::optvect_t opts
;
656 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
657 pw
.addOpt(512, 0, 0, opts
);
658 pw
.startRecord(DNSName("tsigname."), QType::TSIG
, 0, QClass::ANY
, DNSResourceRecord::ADDITIONAL
, false);
660 uint16_t len
= query
.size();
662 /* large enough packet */
664 memcpy(packet
, query
.data(), query
.size());
666 unsigned int consumed
= 0;
668 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
669 BOOST_CHECK_EQUAL(qname
, name
);
670 BOOST_CHECK(qtype
== QType::A
);
672 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
673 BOOST_CHECK((size_t) len
> query
.size());
674 BOOST_CHECK_EQUAL(ednsAdded
, false);
675 BOOST_CHECK_EQUAL(ecsAdded
, false);
676 validateQuery(packet
, len
, true, false, 1);
677 validateECS(packet
, len
, remote
);
679 /* not large enough packet */
684 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
685 BOOST_CHECK_EQUAL(qname
, name
);
686 BOOST_CHECK(qtype
== QType::A
);
688 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
689 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
690 BOOST_CHECK_EQUAL(ednsAdded
, false);
691 BOOST_CHECK_EQUAL(ecsAdded
, false);
692 validateQuery(reinterpret_cast<char*>(query
.data()), len
, true, false, 1);
695 BOOST_AUTO_TEST_CASE(replaceECSAfterAN
) {
696 bool ednsAdded
= false;
697 bool ecsAdded
= false;
698 ComboAddress
remote("192.168.1.25");
699 DNSName
name("www.powerdns.com.");
700 ComboAddress
origRemote("127.0.0.1");
702 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
704 vector
<uint8_t> query
;
705 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
706 pw
.getHeader()->rd
= 1;
707 pw
.startRecord(DNSName("powerdns.com."), QType::A
, 0, QClass::IN
, DNSResourceRecord::ANSWER
, true);
709 EDNSSubnetOpts ecsOpts
;
710 ecsOpts
.source
= Netmask(origRemote
, 8);
711 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
712 DNSPacketWriter::optvect_t opts
;
713 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
714 pw
.addOpt(512, 0, 0, opts
);
716 uint16_t len
= query
.size();
718 /* large enough packet */
720 memcpy(packet
, query
.data(), query
.size());
722 unsigned int consumed
= 0;
724 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
725 BOOST_CHECK_EQUAL(qname
, name
);
726 BOOST_CHECK(qtype
== QType::A
);
728 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
729 BOOST_CHECK((size_t) len
> query
.size());
730 BOOST_CHECK_EQUAL(ednsAdded
, false);
731 BOOST_CHECK_EQUAL(ecsAdded
, false);
732 validateQuery(packet
, len
, true, false, 0, 1, 0);
733 validateECS(packet
, len
, remote
);
735 /* not large enough packet */
740 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
741 BOOST_CHECK_EQUAL(qname
, name
);
742 BOOST_CHECK(qtype
== QType::A
);
744 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
745 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
746 BOOST_CHECK_EQUAL(ednsAdded
, false);
747 BOOST_CHECK_EQUAL(ecsAdded
, false);
748 validateQuery(reinterpret_cast<char*>(query
.data()), len
, true, false, 0, 1, 0);
751 BOOST_AUTO_TEST_CASE(replaceECSAfterAuth
) {
752 bool ednsAdded
= false;
753 bool ecsAdded
= false;
754 ComboAddress
remote("192.168.1.25");
755 DNSName
name("www.powerdns.com.");
756 ComboAddress
origRemote("127.0.0.1");
758 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
760 vector
<uint8_t> query
;
761 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
762 pw
.getHeader()->rd
= 1;
763 pw
.startRecord(DNSName("powerdns.com."), QType::A
, 0, QClass::IN
, DNSResourceRecord::AUTHORITY
, true);
765 EDNSSubnetOpts ecsOpts
;
766 ecsOpts
.source
= Netmask(origRemote
, 8);
767 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
768 DNSPacketWriter::optvect_t opts
;
769 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
770 pw
.addOpt(512, 0, 0, opts
);
772 uint16_t len
= query
.size();
774 /* large enough packet */
776 memcpy(packet
, query
.data(), query
.size());
778 unsigned int consumed
= 0;
780 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
781 BOOST_CHECK_EQUAL(qname
, name
);
782 BOOST_CHECK(qtype
== QType::A
);
784 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
785 BOOST_CHECK((size_t) len
> query
.size());
786 BOOST_CHECK_EQUAL(ednsAdded
, false);
787 BOOST_CHECK_EQUAL(ecsAdded
, false);
788 validateQuery(packet
, len
, true, false, 0, 0, 1);
789 validateECS(packet
, len
, remote
);
791 /* not large enough packet */
796 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
797 BOOST_CHECK_EQUAL(qname
, name
);
798 BOOST_CHECK(qtype
== QType::A
);
800 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
801 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
802 BOOST_CHECK_EQUAL(ednsAdded
, false);
803 BOOST_CHECK_EQUAL(ecsAdded
, false);
804 validateQuery(reinterpret_cast<char*>(query
.data()), len
, true, false, 0, 0, 1);
807 BOOST_AUTO_TEST_CASE(replaceECSBetweenTwoRecords
) {
808 bool ednsAdded
= false;
809 bool ecsAdded
= false;
810 ComboAddress
remote("192.168.1.25");
811 DNSName
name("www.powerdns.com.");
812 ComboAddress
origRemote("127.0.0.1");
814 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
816 vector
<uint8_t> query
;
817 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
818 pw
.getHeader()->rd
= 1;
819 EDNSSubnetOpts ecsOpts
;
820 ecsOpts
.source
= Netmask(origRemote
, 8);
821 string origECSOption
= makeEDNSSubnetOptsString(ecsOpts
);
822 DNSPacketWriter::optvect_t opts
;
823 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOption
));
824 pw
.startRecord(DNSName("additional"), QType::A
, 0, QClass::IN
, DNSResourceRecord::ADDITIONAL
, false);
825 pw
.xfr32BitInt(0x01020304);
826 pw
.addOpt(512, 0, 0, opts
);
827 pw
.startRecord(DNSName("tsigname."), QType::TSIG
, 0, QClass::ANY
, DNSResourceRecord::ADDITIONAL
, false);
829 uint16_t len
= query
.size();
831 /* large enough packet */
833 memcpy(packet
, query
.data(), query
.size());
835 unsigned int consumed
= 0;
837 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
838 BOOST_CHECK_EQUAL(qname
, name
);
839 BOOST_CHECK(qtype
== QType::A
);
841 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
842 BOOST_CHECK((size_t) len
> query
.size());
843 BOOST_CHECK_EQUAL(ednsAdded
, false);
844 BOOST_CHECK_EQUAL(ecsAdded
, false);
845 validateQuery(packet
, len
, true, false, 2);
846 validateECS(packet
, len
, remote
);
848 /* not large enough packet */
853 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
854 BOOST_CHECK_EQUAL(qname
, name
);
855 BOOST_CHECK(qtype
== QType::A
);
857 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
858 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
859 BOOST_CHECK_EQUAL(ednsAdded
, false);
860 BOOST_CHECK_EQUAL(ecsAdded
, false);
861 validateQuery(reinterpret_cast<char*>(query
.data()), len
, true, false, 2);
864 BOOST_AUTO_TEST_CASE(insertECSInEDNSBetweenTwoRecords
) {
865 bool ednsAdded
= false;
866 bool ecsAdded
= false;
867 ComboAddress
remote("192.168.1.25");
868 DNSName
name("www.powerdns.com.");
869 ComboAddress
origRemote("127.0.0.1");
871 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
873 vector
<uint8_t> query
;
874 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
875 pw
.getHeader()->rd
= 1;
876 pw
.startRecord(DNSName("additional"), QType::A
, 0, QClass::IN
, DNSResourceRecord::ADDITIONAL
, false);
877 pw
.xfr32BitInt(0x01020304);
878 pw
.addOpt(512, 0, 0);
879 pw
.startRecord(DNSName("tsigname."), QType::TSIG
, 0, QClass::ANY
, DNSResourceRecord::ADDITIONAL
, false);
881 uint16_t len
= query
.size();
883 /* large enough packet */
885 memcpy(packet
, query
.data(), query
.size());
887 unsigned int consumed
= 0;
889 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
890 BOOST_CHECK_EQUAL(qname
, name
);
891 BOOST_CHECK(qtype
== QType::A
);
893 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
894 BOOST_CHECK((size_t) len
> query
.size());
895 BOOST_CHECK_EQUAL(ednsAdded
, false);
896 BOOST_CHECK_EQUAL(ecsAdded
, true);
897 validateQuery(packet
, len
, true, false, 2);
898 validateECS(packet
, len
, remote
);
900 /* not large enough packet */
905 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
906 BOOST_CHECK_EQUAL(qname
, name
);
907 BOOST_CHECK(qtype
== QType::A
);
909 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
910 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
911 BOOST_CHECK_EQUAL(ednsAdded
, false);
912 BOOST_CHECK_EQUAL(ecsAdded
, false);
913 validateQuery(reinterpret_cast<char*>(query
.data()), len
, true, false, 2);
916 BOOST_AUTO_TEST_CASE(insertECSAfterTSIG
) {
917 bool ednsAdded
= false;
918 bool ecsAdded
= false;
919 ComboAddress
remote("192.168.1.25");
920 DNSName
name("www.powerdns.com.");
921 ComboAddress
origRemote("127.0.0.1");
923 generateECSOption(remote
, newECSOption
, remote
.sin4
.sin_family
== AF_INET
? ECSSourcePrefixV4
: ECSSourcePrefixV6
);
925 vector
<uint8_t> query
;
926 DNSPacketWriter
pw(query
, name
, QType::A
, QClass::IN
, 0);
927 pw
.getHeader()->rd
= 1;
928 pw
.startRecord(DNSName("tsigname."), QType::TSIG
, 0, QClass::ANY
, DNSResourceRecord::ADDITIONAL
, false);
930 uint16_t len
= query
.size();
932 /* large enough packet */
934 memcpy(packet
, query
.data(), query
.size());
936 unsigned int consumed
= 0;
938 DNSName
qname(packet
, len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
939 BOOST_CHECK_EQUAL(qname
, name
);
940 BOOST_CHECK(qtype
== QType::A
);
942 BOOST_CHECK(handleEDNSClientSubnet(packet
, sizeof packet
, consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
943 BOOST_CHECK((size_t) len
> query
.size());
944 BOOST_CHECK_EQUAL(ednsAdded
, true);
945 BOOST_CHECK_EQUAL(ecsAdded
, true);
946 /* the MOADNSParser does not allow anything except XPF after a TSIG */
947 BOOST_CHECK_THROW(validateQuery(packet
, len
, true, false, 1), MOADNSException
);
948 validateECS(packet
, len
, remote
);
950 /* not large enough packet */
955 qname
= DNSName(reinterpret_cast<char*>(query
.data()), len
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
956 BOOST_CHECK_EQUAL(qname
, name
);
957 BOOST_CHECK(qtype
== QType::A
);
959 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query
.data()), query
.size(), consumed
, &len
, ednsAdded
, ecsAdded
, true, newECSOption
, false));
960 BOOST_CHECK_EQUAL((size_t) len
, query
.size());
961 BOOST_CHECK_EQUAL(ednsAdded
, false);
962 BOOST_CHECK_EQUAL(ecsAdded
, false);
963 validateQuery(reinterpret_cast<char*>(query
.data()), len
, true, false);
967 BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst
) {
968 DNSName
name("www.powerdns.com.");
970 vector
<uint8_t> response
;
971 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
972 pw
.getHeader()->qr
= 1;
973 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
974 pw
.xfr32BitInt(0x01020304);
975 pw
.addOpt(512, 0, 0);
977 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
978 pw
.xfr32BitInt(0x01020304);
981 vector
<uint8_t> newResponse
;
982 int res
= rewriteResponseWithoutEDNS(std::string((const char *) response
.data(), response
.size()), newResponse
);
983 BOOST_CHECK_EQUAL(res
, 0);
985 unsigned int consumed
= 0;
987 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
988 BOOST_CHECK_EQUAL(qname
, name
);
989 BOOST_CHECK(qtype
== QType::A
);
990 size_t const ednsOptRRSize
= sizeof(struct dnsrecordheader
) + 1 /* root in OPT RR */;
991 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - ednsOptRRSize
);
993 validateResponse((const char *) newResponse
.data(), newResponse
.size(), false, 1);
996 BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary
) {
997 DNSName
name("www.powerdns.com.");
999 vector
<uint8_t> response
;
1000 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1001 pw
.getHeader()->qr
= 1;
1002 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1003 pw
.xfr32BitInt(0x01020304);
1004 pw
.startRecord(DNSName("other.powerdns.com."), QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1005 pw
.xfr32BitInt(0x01020304);
1007 pw
.addOpt(512, 0, 0);
1009 pw
.startRecord(DNSName("yetanother.powerdns.com."), QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1010 pw
.xfr32BitInt(0x01020304);
1013 vector
<uint8_t> newResponse
;
1014 int res
= rewriteResponseWithoutEDNS(std::string((const char *) response
.data(), response
.size()), newResponse
);
1015 BOOST_CHECK_EQUAL(res
, 0);
1017 unsigned int consumed
= 0;
1019 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1020 BOOST_CHECK_EQUAL(qname
, name
);
1021 BOOST_CHECK(qtype
== QType::A
);
1022 size_t const ednsOptRRSize
= sizeof(struct dnsrecordheader
) + 1 /* root in OPT RR */;
1023 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - ednsOptRRSize
);
1025 validateResponse((const char *) newResponse
.data(), newResponse
.size(), false, 2);
1028 BOOST_AUTO_TEST_CASE(removeEDNSWhenLast
) {
1029 DNSName
name("www.powerdns.com.");
1031 vector
<uint8_t> response
;
1032 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1033 pw
.getHeader()->qr
= 1;
1034 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1035 pw
.xfr32BitInt(0x01020304);
1037 pw
.startRecord(DNSName("other.powerdns.com."), QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1038 pw
.xfr32BitInt(0x01020304);
1040 pw
.addOpt(512, 0, 0);
1043 vector
<uint8_t> newResponse
;
1044 int res
= rewriteResponseWithoutEDNS(std::string((const char *) response
.data(), response
.size()), newResponse
);
1046 BOOST_CHECK_EQUAL(res
, 0);
1048 unsigned int consumed
= 0;
1050 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1051 BOOST_CHECK_EQUAL(qname
, name
);
1052 BOOST_CHECK(qtype
== QType::A
);
1053 size_t const ednsOptRRSize
= sizeof(struct dnsrecordheader
) + 1 /* root in OPT RR */;
1054 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - ednsOptRRSize
);
1056 validateResponse((const char *) newResponse
.data(), newResponse
.size(), false, 1);
1059 BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption
) {
1060 DNSName
name("www.powerdns.com.");
1061 ComboAddress
origRemote("127.0.0.1");
1063 vector
<uint8_t> response
;
1064 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1065 pw
.getHeader()->qr
= 1;
1066 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1067 pw
.xfr32BitInt(0x01020304);
1069 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1070 pw
.xfr32BitInt(0x01020304);
1073 EDNSSubnetOpts ecsOpts
;
1074 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1075 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1076 DNSPacketWriter::optvect_t opts
;
1077 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1078 pw
.addOpt(512, 0, 0, opts
);
1085 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
1086 BOOST_CHECK_EQUAL(res
, 0);
1087 BOOST_CHECK_EQUAL(last
, true);
1089 size_t responseLen
= response
.size();
1090 size_t existingOptLen
= optLen
;
1091 BOOST_CHECK(existingOptLen
< responseLen
);
1092 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
1093 BOOST_CHECK_EQUAL(res
, 0);
1094 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
1095 responseLen
-= (existingOptLen
- optLen
);
1097 unsigned int consumed
= 0;
1099 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1100 BOOST_CHECK_EQUAL(qname
, name
);
1101 BOOST_CHECK(qtype
== QType::A
);
1103 validateResponse((const char *) response
.data(), responseLen
, true, 1);
1106 BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption
) {
1107 DNSName
name("www.powerdns.com.");
1108 ComboAddress
origRemote("127.0.0.1");
1110 vector
<uint8_t> response
;
1111 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1112 pw
.getHeader()->qr
= 1;
1113 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1114 pw
.xfr32BitInt(0x01020304);
1116 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1117 pw
.xfr32BitInt(0x01020304);
1120 EDNSSubnetOpts ecsOpts
;
1121 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV6
);
1122 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1123 EDNSCookiesOpt cookiesOpt
;
1124 cookiesOpt
.client
= string("deadbeef");
1125 cookiesOpt
.server
= string("deadbeef");
1126 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1127 DNSPacketWriter::optvect_t opts
;
1128 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1129 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1130 pw
.addOpt(512, 0, 0, opts
);
1137 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
1138 BOOST_CHECK_EQUAL(res
, 0);
1139 BOOST_CHECK_EQUAL(last
, true);
1141 size_t responseLen
= response
.size();
1142 size_t existingOptLen
= optLen
;
1143 BOOST_CHECK(existingOptLen
< responseLen
);
1144 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
1145 BOOST_CHECK_EQUAL(res
, 0);
1146 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
1147 responseLen
-= (existingOptLen
- optLen
);
1149 unsigned int consumed
= 0;
1151 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1152 BOOST_CHECK_EQUAL(qname
, name
);
1153 BOOST_CHECK(qtype
== QType::A
);
1155 validateResponse((const char *) response
.data(), responseLen
, true, 1);
1158 BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption
) {
1159 DNSName
name("www.powerdns.com.");
1160 ComboAddress
origRemote("127.0.0.1");
1162 vector
<uint8_t> response
;
1163 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1164 pw
.getHeader()->qr
= 1;
1165 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1166 pw
.xfr32BitInt(0x01020304);
1168 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1169 pw
.xfr32BitInt(0x01020304);
1172 EDNSSubnetOpts ecsOpts
;
1173 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1174 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1176 EDNSCookiesOpt cookiesOpt
;
1177 cookiesOpt
.client
= string("deadbeef");
1178 cookiesOpt
.server
= string("deadbeef");
1179 string cookiesOptionStr1
= makeEDNSCookiesOptString(cookiesOpt
);
1180 string cookiesOptionStr2
= makeEDNSCookiesOptString(cookiesOpt
);
1182 DNSPacketWriter::optvect_t opts
;
1183 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr1
));
1184 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1185 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr2
));
1186 pw
.addOpt(512, 0, 0, opts
);
1193 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
1194 BOOST_CHECK_EQUAL(res
, 0);
1195 BOOST_CHECK_EQUAL(last
, true);
1197 size_t responseLen
= response
.size();
1198 size_t existingOptLen
= optLen
;
1199 BOOST_CHECK(existingOptLen
< responseLen
);
1200 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
1201 BOOST_CHECK_EQUAL(res
, 0);
1202 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
1203 responseLen
-= (existingOptLen
- optLen
);
1205 unsigned int consumed
= 0;
1207 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1208 BOOST_CHECK_EQUAL(qname
, name
);
1209 BOOST_CHECK(qtype
== QType::A
);
1211 validateResponse((const char *) response
.data(), responseLen
, true, 1);
1214 BOOST_AUTO_TEST_CASE(removeECSWhenLastOption
) {
1215 DNSName
name("www.powerdns.com.");
1216 ComboAddress
origRemote("127.0.0.1");
1218 vector
<uint8_t> response
;
1219 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1220 pw
.getHeader()->qr
= 1;
1221 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1222 pw
.xfr32BitInt(0x01020304);
1224 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1225 pw
.xfr32BitInt(0x01020304);
1228 EDNSCookiesOpt cookiesOpt
;
1229 cookiesOpt
.client
= string("deadbeef");
1230 cookiesOpt
.server
= string("deadbeef");
1231 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1232 EDNSSubnetOpts ecsOpts
;
1233 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1234 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1235 DNSPacketWriter::optvect_t opts
;
1236 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1237 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1238 pw
.addOpt(512, 0, 0, opts
);
1245 int res
= locateEDNSOptRR(std::string((char *) response
.data(), response
.size()), &optStart
, &optLen
, &last
);
1246 BOOST_CHECK_EQUAL(res
, 0);
1247 BOOST_CHECK_EQUAL(last
, true);
1249 size_t responseLen
= response
.size();
1250 size_t existingOptLen
= optLen
;
1251 BOOST_CHECK(existingOptLen
< responseLen
);
1252 res
= removeEDNSOptionFromOPT(reinterpret_cast<char *>(response
.data()) + optStart
, &optLen
, EDNSOptionCode::ECS
);
1253 BOOST_CHECK_EQUAL(res
, 0);
1254 BOOST_CHECK_EQUAL(optLen
, existingOptLen
- (origECSOptionStr
.size() + 4));
1255 responseLen
-= (existingOptLen
- optLen
);
1257 unsigned int consumed
= 0;
1259 DNSName
qname((const char*) response
.data(), responseLen
, sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1260 BOOST_CHECK_EQUAL(qname
, name
);
1261 BOOST_CHECK(qtype
== QType::A
);
1263 validateResponse((const char *) response
.data(), responseLen
, true, 1);
1266 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption
) {
1267 DNSName
name("www.powerdns.com.");
1268 ComboAddress
origRemote("127.0.0.1");
1270 vector
<uint8_t> response
;
1271 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1272 pw
.getHeader()->qr
= 1;
1273 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1274 pw
.xfr32BitInt(0x01020304);
1276 EDNSSubnetOpts ecsOpts
;
1277 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1278 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1279 DNSPacketWriter::optvect_t opts
;
1280 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1281 pw
.addOpt(512, 0, 0, opts
);
1284 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1285 pw
.xfr32BitInt(0x01020304);
1288 vector
<uint8_t> newResponse
;
1289 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
1290 BOOST_CHECK_EQUAL(res
, 0);
1292 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
1294 unsigned int consumed
= 0;
1296 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1297 BOOST_CHECK_EQUAL(qname
, name
);
1298 BOOST_CHECK(qtype
== QType::A
);
1300 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
1303 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption
) {
1304 DNSName
name("www.powerdns.com.");
1305 ComboAddress
origRemote("127.0.0.1");
1307 vector
<uint8_t> response
;
1308 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1309 pw
.getHeader()->qr
= 1;
1310 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1311 pw
.xfr32BitInt(0x01020304);
1313 EDNSSubnetOpts ecsOpts
;
1314 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1315 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1316 EDNSCookiesOpt cookiesOpt
;
1317 cookiesOpt
.client
= string("deadbeef");
1318 cookiesOpt
.server
= string("deadbeef");
1319 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1320 DNSPacketWriter::optvect_t opts
;
1321 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1322 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1323 pw
.addOpt(512, 0, 0, opts
);
1326 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1327 pw
.xfr32BitInt(0x01020304);
1330 vector
<uint8_t> newResponse
;
1331 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
1332 BOOST_CHECK_EQUAL(res
, 0);
1334 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
1336 unsigned int consumed
= 0;
1338 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1339 BOOST_CHECK_EQUAL(qname
, name
);
1340 BOOST_CHECK(qtype
== QType::A
);
1342 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
1345 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption
) {
1346 DNSName
name("www.powerdns.com.");
1347 ComboAddress
origRemote("127.0.0.1");
1349 vector
<uint8_t> response
;
1350 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1351 pw
.getHeader()->qr
= 1;
1352 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1353 pw
.xfr32BitInt(0x01020304);
1355 EDNSSubnetOpts ecsOpts
;
1356 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1357 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1358 EDNSCookiesOpt cookiesOpt
;
1359 cookiesOpt
.client
= string("deadbeef");
1360 cookiesOpt
.server
= string("deadbeef");
1361 string cookiesOptionStr1
= makeEDNSCookiesOptString(cookiesOpt
);
1362 string cookiesOptionStr2
= makeEDNSCookiesOptString(cookiesOpt
);
1363 DNSPacketWriter::optvect_t opts
;
1364 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr1
));
1365 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1366 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr2
));
1367 pw
.addOpt(512, 0, 0, opts
);
1370 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1371 pw
.xfr32BitInt(0x01020304);
1374 vector
<uint8_t> newResponse
;
1375 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
1376 BOOST_CHECK_EQUAL(res
, 0);
1378 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
1380 unsigned int consumed
= 0;
1382 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1383 BOOST_CHECK_EQUAL(qname
, name
);
1384 BOOST_CHECK(qtype
== QType::A
);
1386 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
1389 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption
) {
1390 DNSName
name("www.powerdns.com.");
1391 ComboAddress
origRemote("127.0.0.1");
1393 vector
<uint8_t> response
;
1394 DNSPacketWriter
pw(response
, name
, QType::A
, QClass::IN
, 0);
1395 pw
.getHeader()->qr
= 1;
1396 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
, true);
1397 pw
.xfr32BitInt(0x01020304);
1399 EDNSSubnetOpts ecsOpts
;
1400 ecsOpts
.source
= Netmask(origRemote
, ECSSourcePrefixV4
);
1401 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1402 EDNSCookiesOpt cookiesOpt
;
1403 cookiesOpt
.client
= string("deadbeef");
1404 cookiesOpt
.server
= string("deadbeef");
1405 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1406 DNSPacketWriter::optvect_t opts
;
1407 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1408 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1409 pw
.addOpt(512, 0, 0, opts
);
1412 pw
.startRecord(name
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ADDITIONAL
, true);
1413 pw
.xfr32BitInt(0x01020304);
1416 vector
<uint8_t> newResponse
;
1417 int res
= rewriteResponseWithoutEDNSOption(std::string((const char *) response
.data(), response
.size()), EDNSOptionCode::ECS
, newResponse
);
1418 BOOST_CHECK_EQUAL(res
, 0);
1420 BOOST_CHECK_EQUAL(newResponse
.size(), response
.size() - (origECSOptionStr
.size() + 4));
1422 unsigned int consumed
= 0;
1424 DNSName
qname((const char*) newResponse
.data(), newResponse
.size(), sizeof(dnsheader
), false, &qtype
, NULL
, &consumed
);
1425 BOOST_CHECK_EQUAL(qname
, name
);
1426 BOOST_CHECK(qtype
== QType::A
);
1428 validateResponse((const char *) newResponse
.data(), newResponse
.size(), true, 1);
1431 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
)
1433 dnsheader
* dh
= reinterpret_cast<dnsheader
*>(query
.data());
1435 return DNSQuestion(&qname
, qtype
, qclass
, qname
.wirelength(), &lc
, &rem
, dh
, query
.size(), len
, false, &realTime
);
1438 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)
1440 size_t length
= query
.size();
1445 auto dq
= getDNSQuestion(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
, length
);
1447 BOOST_CHECK(addEDNSToQueryTurnedResponse(dq
));
1452 static int getZ(const DNSName
& qname
, const uint16_t qtype
, const uint16_t qclass
, vector
<uint8_t>& query
)
1454 ComboAddress
lc("127.0.0.1");
1455 ComboAddress
rem("127.0.0.1");
1456 struct timespec queryRealTime
;
1457 gettime(&queryRealTime
, true);
1458 size_t length
= query
.size();
1459 DNSQuestion dq
= getDNSQuestion(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
, length
);
1461 return getEDNSZ(dq
);
1464 BOOST_AUTO_TEST_CASE(test_getEDNSZ
) {
1467 uint16_t udpPayloadSize
;
1468 DNSName
qname("www.powerdns.com.");
1469 uint16_t qtype
= QType::A
;
1470 uint16_t qclass
= QClass::IN
;
1471 EDNSSubnetOpts ecsOpts
;
1472 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1473 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1474 EDNSCookiesOpt cookiesOpt
;
1475 cookiesOpt
.client
= string("deadbeef");
1476 cookiesOpt
.server
= string("deadbeef");
1477 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1478 DNSPacketWriter::optvect_t opts
;
1479 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1480 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1484 vector
<uint8_t> query
;
1485 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1488 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1489 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), false);
1490 BOOST_CHECK_EQUAL(z
, 0);
1491 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1495 /* truncated EDNS */
1496 vector
<uint8_t> query
;
1497 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1498 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1501 query
.resize(query
.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
1502 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1503 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), false);
1504 BOOST_CHECK_EQUAL(z
, 0);
1505 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1509 /* valid EDNS, no options, DO not set */
1510 vector
<uint8_t> query
;
1511 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1512 pw
.addOpt(512, 0, 0);
1515 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1516 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1517 BOOST_CHECK_EQUAL(z
, 0);
1518 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1522 /* valid EDNS, no options, DO set */
1523 vector
<uint8_t> query
;
1524 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1525 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1528 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), EDNS_HEADER_FLAG_DO
);
1529 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1530 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1531 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1535 /* valid EDNS, options, DO not set */
1536 vector
<uint8_t> query
;
1537 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1538 pw
.addOpt(512, 0, 0, opts
);
1541 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), 0);
1542 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1543 BOOST_CHECK_EQUAL(z
, 0);
1544 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1548 /* valid EDNS, options, DO set */
1549 vector
<uint8_t> query
;
1550 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1551 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
, opts
);
1554 BOOST_CHECK_EQUAL(getZ(qname
, qtype
, qclass
, query
), EDNS_HEADER_FLAG_DO
);
1555 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query
.data()), query
.size(), &udpPayloadSize
, &z
), true);
1556 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1557 BOOST_CHECK_EQUAL(udpPayloadSize
, 512);
1562 BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse
) {
1565 uint16_t udpPayloadSize
;
1566 DNSName
qname("www.powerdns.com.");
1567 uint16_t qtype
= QType::A
;
1568 uint16_t qclass
= QClass::IN
;
1569 EDNSSubnetOpts ecsOpts
;
1570 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1571 string origECSOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1572 EDNSCookiesOpt cookiesOpt
;
1573 cookiesOpt
.client
= string("deadbeef");
1574 cookiesOpt
.server
= string("deadbeef");
1575 string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1576 DNSPacketWriter::optvect_t opts
;
1577 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1578 opts
.push_back(make_pair(EDNSOptionCode::ECS
, origECSOptionStr
));
1579 ComboAddress
lc("127.0.0.1");
1580 ComboAddress
rem("127.0.0.1");
1581 struct timespec queryRealTime
;
1582 gettime(&queryRealTime
, true);
1586 vector
<uint8_t> query
;
1587 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1588 pw
.getHeader()->qr
= 1;
1589 pw
.getHeader()->rcode
= RCode::NXDomain
;
1592 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1593 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1594 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), false);
1595 BOOST_CHECK_EQUAL(z
, 0);
1596 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1600 /* truncated EDNS */
1601 vector
<uint8_t> query
;
1602 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1603 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1606 query
.resize(query
.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
1607 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1608 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1609 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), false);
1610 BOOST_CHECK_EQUAL(z
, 0);
1611 BOOST_CHECK_EQUAL(udpPayloadSize
, 0);
1615 /* valid EDNS, no options, DO not set */
1616 vector
<uint8_t> query
;
1617 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1618 pw
.addOpt(512, 0, 0);
1621 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1622 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1623 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1624 BOOST_CHECK_EQUAL(z
, 0);
1625 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1629 /* valid EDNS, no options, DO set */
1630 vector
<uint8_t> query
;
1631 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1632 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
1635 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1636 BOOST_CHECK_EQUAL(getEDNSZ(dq
), EDNS_HEADER_FLAG_DO
);
1637 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1638 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1639 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1643 /* valid EDNS, options, DO not set */
1644 vector
<uint8_t> query
;
1645 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1646 pw
.addOpt(512, 0, 0, opts
);
1649 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1650 BOOST_CHECK_EQUAL(getEDNSZ(dq
), 0);
1651 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1652 BOOST_CHECK_EQUAL(z
, 0);
1653 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1657 /* valid EDNS, options, DO set */
1658 vector
<uint8_t> query
;
1659 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1660 pw
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
, opts
);
1663 auto dq
= turnIntoResponse(qname
, qtype
, qclass
, lc
, rem
, queryRealTime
, query
);
1664 BOOST_CHECK_EQUAL(getEDNSZ(dq
), EDNS_HEADER_FLAG_DO
);
1665 BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq
.dh
), dq
.len
, &udpPayloadSize
, &z
), true);
1666 BOOST_CHECK_EQUAL(z
, EDNS_HEADER_FLAG_DO
);
1667 BOOST_CHECK_EQUAL(udpPayloadSize
, g_PayloadSizeSelfGenAnswers
);
1671 BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart
) {
1672 const DNSName
qname("www.powerdns.com.");
1673 const uint16_t qtype
= QType::A
;
1674 const uint16_t qclass
= QClass::IN
;
1675 EDNSSubnetOpts ecsOpts
;
1676 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1677 const string ecsOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1678 DNSPacketWriter::optvect_t opts
;
1679 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1680 const ComboAddress
lc("127.0.0.1");
1681 const ComboAddress
rem("127.0.0.1");
1682 uint16_t optRDPosition
;
1685 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
;
1689 vector
<uint8_t> query
;
1690 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1691 pw
.getHeader()->qr
= 1;
1692 pw
.getHeader()->rcode
= RCode::NXDomain
;
1695 int res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1697 BOOST_CHECK_EQUAL(res
, ENOENT
);
1699 /* truncated packet (should not matter) */
1700 query
.resize(query
.size() - 1);
1701 res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1703 BOOST_CHECK_EQUAL(res
, ENOENT
);
1707 /* valid EDNS, no options */
1708 vector
<uint8_t> query
;
1709 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1710 pw
.addOpt(512, 0, 0);
1713 int res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1715 BOOST_CHECK_EQUAL(res
, 0);
1716 BOOST_CHECK_EQUAL(optRDPosition
, optRDExpectedOffset
);
1717 BOOST_CHECK_EQUAL(remaining
, query
.size() - optRDExpectedOffset
);
1719 /* truncated packet */
1720 query
.resize(query
.size() - 1);
1722 res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1723 BOOST_CHECK_EQUAL(res
, ENOENT
);
1727 /* valid EDNS, options */
1728 vector
<uint8_t> query
;
1729 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1730 pw
.addOpt(512, 0, 0, opts
);
1733 int res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1735 BOOST_CHECK_EQUAL(res
, 0);
1736 BOOST_CHECK_EQUAL(optRDPosition
, optRDExpectedOffset
);
1737 BOOST_CHECK_EQUAL(remaining
, query
.size() - optRDExpectedOffset
);
1739 /* truncated options (should not matter for this test) */
1740 query
.resize(query
.size() - 1);
1741 res
= getEDNSOptionsStart(reinterpret_cast<const char*>(query
.data()), qname
.wirelength(), query
.size(), &optRDPosition
, &remaining
);
1742 BOOST_CHECK_EQUAL(res
, 0);
1743 BOOST_CHECK_EQUAL(optRDPosition
, optRDExpectedOffset
);
1744 BOOST_CHECK_EQUAL(remaining
, query
.size() - optRDExpectedOffset
);
1749 BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt
) {
1751 auto locateEDNSOption
= [](const vector
<uint8_t>& query
, uint16_t code
, size_t* optContentStart
, uint16_t* optContentLen
) {
1755 std::string
packetStr(reinterpret_cast<const char*>(query
.data()), query
.size());
1756 int res
= locateEDNSOptRR(packetStr
, &optStart
, &optLen
, &last
);
1762 if (optLen
< optRecordMinimumSize
) {
1766 if (optStart
< query
.size() && packetStr
.at(optStart
) != 0) {
1767 // OPT RR Name != '.'
1771 return isEDNSOptionInOpt(packetStr
, optStart
, optLen
, code
, optContentStart
, optContentLen
);
1774 const DNSName
qname("www.powerdns.com.");
1775 const uint16_t qtype
= QType::A
;
1776 const uint16_t qclass
= QClass::IN
;
1777 EDNSSubnetOpts ecsOpts
;
1778 ecsOpts
.source
= Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4
);
1779 const string ecsOptionStr
= makeEDNSSubnetOptsString(ecsOpts
);
1780 const size_t sizeOfECSContent
= ecsOptionStr
.size();
1781 const size_t sizeOfECSOption
= /* option code */ 2 + /* option length */ 2 + sizeOfECSContent
;
1782 EDNSCookiesOpt cookiesOpt
;
1783 cookiesOpt
.client
= string("deadbeef");
1784 cookiesOpt
.server
= string("deadbeef");
1785 const string cookiesOptionStr
= makeEDNSCookiesOptString(cookiesOpt
);
1786 const size_t sizeOfCookieOption
= /* option code */ 2 + /* option length */ 2 + cookiesOpt
.client
.size() + cookiesOpt
.server
.size();
1788 DNSPacketWriter::optvect_t opts;
1789 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
1790 opts.push_back(make_pair(EDNSOptionCode::ECS, ecsOptionStr));
1791 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
1793 const ComboAddress
lc("127.0.0.1");
1794 const ComboAddress
rem("127.0.0.1");
1795 size_t optContentStart
;
1796 uint16_t optContentLen
;
1798 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
;
1802 vector
<uint8_t> query
;
1803 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1804 pw
.getHeader()->qr
= 1;
1805 pw
.getHeader()->rcode
= RCode::NXDomain
;
1808 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1809 BOOST_CHECK_EQUAL(found
, false);
1811 /* truncated packet (should not matter here) */
1812 query
.resize(query
.size() - 1);
1813 found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1814 BOOST_CHECK_EQUAL(found
, false);
1818 /* valid EDNS, no options */
1819 vector
<uint8_t> query
;
1820 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1821 pw
.addOpt(512, 0, 0);
1824 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1825 BOOST_CHECK_EQUAL(found
, false);
1827 /* truncated packet */
1828 query
.resize(query
.size() - 1);
1829 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::out_of_range
);
1833 /* valid EDNS, two cookie options but no ECS */
1834 vector
<uint8_t> query
;
1835 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1836 DNSPacketWriter::optvect_t opts
;
1837 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1838 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1839 pw
.addOpt(512, 0, 0, opts
);
1842 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1843 BOOST_CHECK_EQUAL(found
, false);
1845 /* truncated packet */
1846 query
.resize(query
.size() - 1);
1847 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::range_error
);
1851 /* valid EDNS, two ECS */
1852 vector
<uint8_t> query
;
1853 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1854 DNSPacketWriter::optvect_t opts
;
1855 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1856 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1857 pw
.addOpt(512, 0, 0, opts
);
1860 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1861 BOOST_CHECK_EQUAL(found
, true);
1862 if (found
== true) {
1863 BOOST_CHECK_EQUAL(optContentStart
, optRDExpectedOffset
+ sizeof(uint16_t) /* RD len */ + /* option code */ 2 + /* option length */ 2);
1864 BOOST_CHECK_EQUAL(optContentLen
, sizeOfECSContent
);
1867 /* truncated packet */
1868 query
.resize(query
.size() - 1);
1869 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::range_error
);
1873 /* valid EDNS, one ECS between two cookies */
1874 vector
<uint8_t> query
;
1875 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1876 DNSPacketWriter::optvect_t opts
;
1877 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1878 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1879 opts
.push_back(make_pair(EDNSOptionCode::COOKIE
, cookiesOptionStr
));
1880 pw
.addOpt(512, 0, 0, opts
);
1883 bool found
= locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
);
1884 BOOST_CHECK_EQUAL(found
, true);
1885 if (found
== true) {
1886 BOOST_CHECK_EQUAL(optContentStart
, optRDExpectedOffset
+ sizeof(uint16_t) /* RD len */ + sizeOfCookieOption
+ /* option code */ 2 + /* option length */ 2);
1887 BOOST_CHECK_EQUAL(optContentLen
, sizeOfECSContent
);
1890 /* truncated packet */
1891 query
.resize(query
.size() - 1);
1892 BOOST_CHECK_THROW(locateEDNSOption(query
, EDNSOptionCode::ECS
, &optContentStart
, &optContentLen
), std::range_error
);
1896 /* valid EDNS, one 65002 after an ECS */
1897 vector
<uint8_t> query
;
1898 DNSPacketWriter
pw(query
, qname
, qtype
, qclass
, 0);
1899 DNSPacketWriter::optvect_t opts
;
1900 opts
.push_back(make_pair(EDNSOptionCode::ECS
, ecsOptionStr
));
1901 opts
.push_back(make_pair(65535, cookiesOptionStr
));
1902 pw
.addOpt(512, 0, 0, opts
);
1905 bool found
= locateEDNSOption(query
, 65535, &optContentStart
, &optContentLen
);
1906 BOOST_CHECK_EQUAL(found
, true);
1907 if (found
== true) {
1908 BOOST_CHECK_EQUAL(optContentStart
, optRDExpectedOffset
+ sizeof(uint16_t) /* RD len */ + sizeOfECSOption
+ /* option code */ 2 + /* option length */ 2);
1909 BOOST_CHECK_EQUAL(optContentLen
, cookiesOptionStr
.size());
1912 /* truncated packet */
1913 query
.resize(query
.size() - 1);
1914 BOOST_CHECK_THROW(locateEDNSOption(query
, 65002, &optContentStart
, &optContentLen
), std::range_error
);
1918 BOOST_AUTO_TEST_SUITE_END();