]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-dnsdist_cc.cc
3a5bd23c80cb716c23206e6cf422069fbde51a65
[thirdparty/pdns.git] / pdns / test-dnsdist_cc.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #define BOOST_TEST_DYN_LINK
23 #define BOOST_TEST_NO_MAIN
24
25 #include <boost/test/unit_test.hpp>
26 #include <unistd.h>
27
28 #include "dnsdist.hh"
29 #include "dnsdist-ecs.hh"
30 #include "dnsdist-xpf.hh"
31
32 #include "dolog.hh"
33 #include "dnsname.hh"
34 #include "dnsparser.hh"
35 #include "dnswriter.hh"
36 #include "ednsoptions.hh"
37 #include "ednscookies.hh"
38 #include "ednssubnet.hh"
39
40 BOOST_AUTO_TEST_SUITE(test_dnsdist_cc)
41
42 static const uint16_t ECSSourcePrefixV4 = 24;
43 static const uint16_t ECSSourcePrefixV6 = 56;
44
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)
46 {
47 MOADNSParser mdp(true, packet, packetSize);
48
49 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
50
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);
56 }
57
58 static void validateECS(const char* packet, size_t packetSize, const ComboAddress& expected)
59 {
60 ComboAddress rem("::1");
61 unsigned int consumed = 0;
62 uint16_t qtype;
63 uint16_t qclass;
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());
71
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));
77 }
78
79 static void validateResponse(const char * packet, size_t packetSize, bool hasEdns, uint8_t additionalCount=0)
80 {
81 MOADNSParser mdp(false, packet, packetSize);
82
83 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
84
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);
90 }
91
92 BOOST_AUTO_TEST_CASE(test_addXPF)
93 {
94 static const uint16_t xpfOptionCode = 65422;
95
96 struct timespec queryTime;
97 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
98 ComboAddress remote;
99 DNSName name("www.powerdns.com.");
100
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;
106
107 {
108 char packet[1500];
109 memcpy(packet, query.data(), query.size());
110
111 /* large enough packet */
112 unsigned int consumed = 0;
113 uint16_t qtype;
114 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
115 BOOST_CHECK_EQUAL(qname, name);
116 BOOST_CHECK(qtype == QType::A);
117
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);
120
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);
126 }
127
128 {
129 char packet[1500];
130 memcpy(packet, query.data(), query.size());
131
132 /* not large enough packet */
133 unsigned int consumed = 0;
134 uint16_t qtype;
135 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
136 BOOST_CHECK_EQUAL(qname, name);
137 BOOST_CHECK(qtype == QType::A);
138
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);
141 dq.size = dq.len;
142
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);
146 }
147
148 {
149 char packet[1500];
150 memcpy(packet, query.data(), query.size());
151
152 /* packet with trailing data (overriding it) */
153 unsigned int consumed = 0;
154 uint16_t qtype;
155 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
156 BOOST_CHECK_EQUAL(qname, name);
157 BOOST_CHECK(qtype == QType::A);
158
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);
161
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';
168 }
169 dq.len += trailingDataSize;
170
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);
175 }
176
177 {
178 char packet[1500];
179 memcpy(packet, query.data(), query.size());
180
181 /* packet with trailing data (preserving trailing data) */
182 unsigned int consumed = 0;
183 uint16_t qtype;
184 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
185 BOOST_CHECK_EQUAL(qname, name);
186 BOOST_CHECK(qtype == QType::A);
187
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);
190
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';
197 }
198 dq.len += trailingDataSize;
199
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');
205 }
206 validateQuery(packet, dq.len, false, true);
207 }
208 }
209
210 BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
211 {
212 bool ednsAdded = false;
213 bool ecsAdded = false;
214 ComboAddress remote("192.0.2.1");
215 DNSName name("www.powerdns.com.");
216 string newECSOption;
217 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
218
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();
223
224 /* large enough packet */
225 char packet[1500];
226 memcpy(packet, query.data(), query.size());
227
228 unsigned int consumed = 0;
229 uint16_t qtype;
230 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
231 BOOST_CHECK_EQUAL(qname, name);
232 BOOST_CHECK(qtype == QType::A);
233
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);
243
244 /* not large enough packet */
245 ednsAdded = false;
246 ecsAdded = false;
247 consumed = 0;
248 len = query.size();
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);
252
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);
258
259 /* packet with trailing data (overriding it) */
260 memcpy(packet, query.data(), query.size());
261 ednsAdded = false;
262 ecsAdded = false;
263 consumed = 0;
264 len = 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';
274 }
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);
282
283 /* packet with trailing data (preserving trailing data) */
284 memcpy(packet, query.data(), query.size());
285 ednsAdded = false;
286 ecsAdded = false;
287 consumed = 0;
288 len = 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';
297 }
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');
304 }
305 BOOST_CHECK_EQUAL(ednsAdded, true);
306 BOOST_CHECK_EQUAL(ecsAdded, true);
307 validateQuery(packet, len);
308 }
309
310 BOOST_AUTO_TEST_CASE(addECSWithoutEDNSAlreadyParsed)
311 {
312 bool ednsAdded = false;
313 bool ecsAdded = false;
314 ComboAddress remote("192.0.2.1");
315 DNSName name("www.powerdns.com.");
316
317 vector<uint8_t> query;
318 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
319 pw.getHeader()->rd = 1;
320
321 /* large enough packet */
322 char packet[1500];
323 memcpy(packet, query.data(), query.size());
324
325 unsigned int consumed = 0;
326 uint16_t qtype;
327 uint16_t qclass;
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);
332
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));
336
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);
344
345 /* not large enough packet */
346 ednsAdded = false;
347 ecsAdded = false;
348 consumed = 0;
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);
354
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);
360 }
361
362 BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) {
363 bool ednsAdded = false;
364 bool ecsAdded = false;
365 ComboAddress remote;
366 DNSName name("www.powerdns.com.");
367 string newECSOption;
368 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
369
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);
374 pw.commit();
375 uint16_t len = query.size();
376
377 /* large enough packet */
378 char packet[1500];
379 memcpy(packet, query.data(), query.size());
380
381 unsigned int consumed = 0;
382 uint16_t qtype;
383 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
384 BOOST_CHECK_EQUAL(qname, name);
385 BOOST_CHECK(qtype == QType::A);
386
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);
393
394 /* not large enough packet */
395 consumed = 0;
396 ednsAdded = false;
397 ecsAdded = false;
398 len = query.size();
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);
402
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);
408 }
409
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.");
415
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);
420 pw.commit();
421
422 /* large enough packet */
423 char packet[1500];
424 memcpy(packet, query.data(), query.size());
425
426 unsigned int consumed = 0;
427 uint16_t qtype;
428 uint16_t qclass;
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);
433
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));
437
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);
445
446 /* not large enough packet */
447 consumed = 0;
448 ednsAdded = false;
449 ecsAdded = false;
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);
455
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);
461 }
462
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");
469 string newECSOption;
470 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
471
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);
481 pw.commit();
482 uint16_t len = query.size();
483
484 /* large enough packet */
485 char packet[1500];
486 memcpy(packet, query.data(), query.size());
487
488 unsigned int consumed = 0;
489 uint16_t qtype;
490 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
491 BOOST_CHECK_EQUAL(qname, name);
492 BOOST_CHECK(qtype == QType::A);
493
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);
500 }
501
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");
508
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);
518 pw.commit();
519
520 /* large enough packet */
521 char packet[1500];
522 memcpy(packet, query.data(), query.size());
523
524 unsigned int consumed = 0;
525 uint16_t qtype;
526 uint16_t qclass;
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);
531
532 DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(packet), sizeof(packet), query.size(), false, nullptr);
533 dq.ecsOverride = true;
534
535 /* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
536 BOOST_CHECK(parseEDNSOptions(dq));
537
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);
545 }
546
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");
553 string newECSOption;
554 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
555
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);
565 pw.commit();
566 uint16_t len = query.size();
567
568 /* large enough packet */
569 char packet[1500];
570 memcpy(packet, query.data(), query.size());
571
572 unsigned int consumed = 0;
573 uint16_t qtype;
574 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
575 BOOST_CHECK_EQUAL(qname, name);
576 BOOST_CHECK(qtype == QType::A);
577
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);
584 }
585
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");
592 string newECSOption;
593 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
594
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);
604 pw.commit();
605 uint16_t len = query.size();
606
607 /* large enough packet */
608 char packet[1500];
609 memcpy(packet, query.data(), query.size());
610
611 unsigned int consumed = 0;
612 uint16_t qtype;
613 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
614 BOOST_CHECK_EQUAL(qname, name);
615 BOOST_CHECK(qtype == QType::A);
616
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);
623
624 /* not large enough packet */
625 ednsAdded = false;
626 ecsAdded = false;
627 consumed = 0;
628 len = query.size();
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);
632
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);
638 }
639
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");
646 string newECSOption;
647 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
648
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);
659 pw.commit();
660 uint16_t len = query.size();
661
662 /* large enough packet */
663 char packet[1500];
664 memcpy(packet, query.data(), query.size());
665
666 unsigned int consumed = 0;
667 uint16_t qtype;
668 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
669 BOOST_CHECK_EQUAL(qname, name);
670 BOOST_CHECK(qtype == QType::A);
671
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);
678
679 /* not large enough packet */
680 ednsAdded = false;
681 ecsAdded = false;
682 consumed = 0;
683 len = query.size();
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);
687
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);
693 }
694
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");
701 string newECSOption;
702 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
703
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);
708 pw.commit();
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);
715 pw.commit();
716 uint16_t len = query.size();
717
718 /* large enough packet */
719 char packet[1500];
720 memcpy(packet, query.data(), query.size());
721
722 unsigned int consumed = 0;
723 uint16_t qtype;
724 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
725 BOOST_CHECK_EQUAL(qname, name);
726 BOOST_CHECK(qtype == QType::A);
727
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);
734
735 /* not large enough packet */
736 ednsAdded = false;
737 ecsAdded = false;
738 consumed = 0;
739 len = query.size();
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);
743
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);
749 }
750
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");
757 string newECSOption;
758 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
759
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);
764 pw.commit();
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);
771 pw.commit();
772 uint16_t len = query.size();
773
774 /* large enough packet */
775 char packet[1500];
776 memcpy(packet, query.data(), query.size());
777
778 unsigned int consumed = 0;
779 uint16_t qtype;
780 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
781 BOOST_CHECK_EQUAL(qname, name);
782 BOOST_CHECK(qtype == QType::A);
783
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);
790
791 /* not large enough packet */
792 ednsAdded = false;
793 ecsAdded = false;
794 consumed = 0;
795 len = query.size();
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);
799
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);
805 }
806
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");
813 string newECSOption;
814 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
815
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);
828 pw.commit();
829 uint16_t len = query.size();
830
831 /* large enough packet */
832 char packet[1500];
833 memcpy(packet, query.data(), query.size());
834
835 unsigned int consumed = 0;
836 uint16_t qtype;
837 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
838 BOOST_CHECK_EQUAL(qname, name);
839 BOOST_CHECK(qtype == QType::A);
840
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);
847
848 /* not large enough packet */
849 ednsAdded = false;
850 ecsAdded = false;
851 consumed = 0;
852 len = query.size();
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);
856
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);
862 }
863
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");
870 string newECSOption;
871 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
872
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);
880 pw.commit();
881 uint16_t len = query.size();
882
883 /* large enough packet */
884 char packet[1500];
885 memcpy(packet, query.data(), query.size());
886
887 unsigned int consumed = 0;
888 uint16_t qtype;
889 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
890 BOOST_CHECK_EQUAL(qname, name);
891 BOOST_CHECK(qtype == QType::A);
892
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);
899
900 /* not large enough packet */
901 ednsAdded = false;
902 ecsAdded = false;
903 consumed = 0;
904 len = query.size();
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);
908
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);
914 }
915
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");
922 string newECSOption;
923 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
924
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);
929 pw.commit();
930 uint16_t len = query.size();
931
932 /* large enough packet */
933 char packet[1500];
934 memcpy(packet, query.data(), query.size());
935
936 unsigned int consumed = 0;
937 uint16_t qtype;
938 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
939 BOOST_CHECK_EQUAL(qname, name);
940 BOOST_CHECK(qtype == QType::A);
941
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);
949
950 /* not large enough packet */
951 ednsAdded = false;
952 ecsAdded = false;
953 consumed = 0;
954 len = query.size();
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);
958
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);
964 }
965
966
967 BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) {
968 DNSName name("www.powerdns.com.");
969
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);
976 pw.commit();
977 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
978 pw.xfr32BitInt(0x01020304);
979 pw.commit();
980
981 vector<uint8_t> newResponse;
982 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
983 BOOST_CHECK_EQUAL(res, 0);
984
985 unsigned int consumed = 0;
986 uint16_t qtype;
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);
992
993 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
994 }
995
996 BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) {
997 DNSName name("www.powerdns.com.");
998
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);
1006 pw.commit();
1007 pw.addOpt(512, 0, 0);
1008 pw.commit();
1009 pw.startRecord(DNSName("yetanother.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1010 pw.xfr32BitInt(0x01020304);
1011 pw.commit();
1012
1013 vector<uint8_t> newResponse;
1014 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
1015 BOOST_CHECK_EQUAL(res, 0);
1016
1017 unsigned int consumed = 0;
1018 uint16_t qtype;
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);
1024
1025 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 2);
1026 }
1027
1028 BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) {
1029 DNSName name("www.powerdns.com.");
1030
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);
1036 pw.commit();
1037 pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1038 pw.xfr32BitInt(0x01020304);
1039 pw.commit();
1040 pw.addOpt(512, 0, 0);
1041 pw.commit();
1042
1043 vector<uint8_t> newResponse;
1044 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
1045
1046 BOOST_CHECK_EQUAL(res, 0);
1047
1048 unsigned int consumed = 0;
1049 uint16_t qtype;
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);
1055
1056 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
1057 }
1058
1059 BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) {
1060 DNSName name("www.powerdns.com.");
1061 ComboAddress origRemote("127.0.0.1");
1062
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);
1068
1069 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1070 pw.xfr32BitInt(0x01020304);
1071 pw.commit();
1072
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);
1079 pw.commit();
1080
1081 uint16_t optStart;
1082 size_t optLen = 0;
1083 bool last = false;
1084
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);
1088
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);
1096
1097 unsigned int consumed = 0;
1098 uint16_t qtype;
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);
1102
1103 validateResponse((const char *) response.data(), responseLen, true, 1);
1104 }
1105
1106 BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) {
1107 DNSName name("www.powerdns.com.");
1108 ComboAddress origRemote("127.0.0.1");
1109
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);
1115
1116 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1117 pw.xfr32BitInt(0x01020304);
1118 pw.commit();
1119
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);
1131 pw.commit();
1132
1133 uint16_t optStart;
1134 size_t optLen = 0;
1135 bool last = false;
1136
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);
1140
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);
1148
1149 unsigned int consumed = 0;
1150 uint16_t qtype;
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);
1154
1155 validateResponse((const char *) response.data(), responseLen, true, 1);
1156 }
1157
1158 BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) {
1159 DNSName name("www.powerdns.com.");
1160 ComboAddress origRemote("127.0.0.1");
1161
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);
1167
1168 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1169 pw.xfr32BitInt(0x01020304);
1170 pw.commit();
1171
1172 EDNSSubnetOpts ecsOpts;
1173 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
1174 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
1175
1176 EDNSCookiesOpt cookiesOpt;
1177 cookiesOpt.client = string("deadbeef");
1178 cookiesOpt.server = string("deadbeef");
1179 string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt);
1180 string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt);
1181
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);
1187 pw.commit();
1188
1189 uint16_t optStart;
1190 size_t optLen = 0;
1191 bool last = false;
1192
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);
1196
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);
1204
1205 unsigned int consumed = 0;
1206 uint16_t qtype;
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);
1210
1211 validateResponse((const char *) response.data(), responseLen, true, 1);
1212 }
1213
1214 BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) {
1215 DNSName name("www.powerdns.com.");
1216 ComboAddress origRemote("127.0.0.1");
1217
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);
1223
1224 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1225 pw.xfr32BitInt(0x01020304);
1226 pw.commit();
1227
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);
1239 pw.commit();
1240
1241 uint16_t optStart;
1242 size_t optLen = 0;
1243 bool last = false;
1244
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);
1248
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);
1256
1257 unsigned int consumed = 0;
1258 uint16_t qtype;
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);
1262
1263 validateResponse((const char *) response.data(), responseLen, true, 1);
1264 }
1265
1266 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) {
1267 DNSName name("www.powerdns.com.");
1268 ComboAddress origRemote("127.0.0.1");
1269
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);
1275
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);
1282 pw.commit();
1283
1284 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1285 pw.xfr32BitInt(0x01020304);
1286 pw.commit();
1287
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);
1291
1292 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
1293
1294 unsigned int consumed = 0;
1295 uint16_t qtype;
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);
1299
1300 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
1301 }
1302
1303 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) {
1304 DNSName name("www.powerdns.com.");
1305 ComboAddress origRemote("127.0.0.1");
1306
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);
1312
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);
1324 pw.commit();
1325
1326 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1327 pw.xfr32BitInt(0x01020304);
1328 pw.commit();
1329
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);
1333
1334 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
1335
1336 unsigned int consumed = 0;
1337 uint16_t qtype;
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);
1341
1342 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
1343 }
1344
1345 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) {
1346 DNSName name("www.powerdns.com.");
1347 ComboAddress origRemote("127.0.0.1");
1348
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);
1354
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);
1368 pw.commit();
1369
1370 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1371 pw.xfr32BitInt(0x01020304);
1372 pw.commit();
1373
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);
1377
1378 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
1379
1380 unsigned int consumed = 0;
1381 uint16_t qtype;
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);
1385
1386 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
1387 }
1388
1389 BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
1390 DNSName name("www.powerdns.com.");
1391 ComboAddress origRemote("127.0.0.1");
1392
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);
1398
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);
1410 pw.commit();
1411
1412 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
1413 pw.xfr32BitInt(0x01020304);
1414 pw.commit();
1415
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);
1419
1420 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
1421
1422 unsigned int consumed = 0;
1423 uint16_t qtype;
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);
1427
1428 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
1429 }
1430
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)
1432 {
1433 dnsheader* dh = reinterpret_cast<dnsheader*>(query.data());
1434
1435 return DNSQuestion(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, dh, query.size(), len, false, &realTime);
1436 }
1437
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)
1439 {
1440 size_t length = query.size();
1441 if (resizeBuffer) {
1442 query.resize(4096);
1443 }
1444
1445 auto dq = getDNSQuestion(qname, qtype, qclass, lc, rem, queryRealTime, query, length);
1446
1447 BOOST_CHECK(addEDNSToQueryTurnedResponse(dq));
1448
1449 return dq;
1450 }
1451
1452 static int getZ(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, vector<uint8_t>& query)
1453 {
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);
1460
1461 return getEDNSZ(dq);
1462 }
1463
1464 BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
1465
1466 uint16_t z;
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));
1481
1482 {
1483 /* no EDNS */
1484 vector<uint8_t> query;
1485 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
1486 pw.commit();
1487
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);
1492 }
1493
1494 {
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);
1499 pw.commit();
1500
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);
1506 }
1507
1508 {
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);
1513 pw.commit();
1514
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);
1519 }
1520
1521 {
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);
1526 pw.commit();
1527
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);
1532 }
1533
1534 {
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);
1539 pw.commit();
1540
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);
1545 }
1546
1547 {
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);
1552 pw.commit();
1553
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);
1558 }
1559
1560 }
1561
1562 BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
1563
1564 uint16_t z;
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);
1583
1584 {
1585 /* no EDNS */
1586 vector<uint8_t> query;
1587 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
1588 pw.getHeader()->qr = 1;
1589 pw.getHeader()->rcode = RCode::NXDomain;
1590 pw.commit();
1591
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);
1597 }
1598
1599 {
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);
1604 pw.commit();
1605
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);
1612 }
1613
1614 {
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);
1619 pw.commit();
1620
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);
1626 }
1627
1628 {
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);
1633 pw.commit();
1634
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);
1640 }
1641
1642 {
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);
1647 pw.commit();
1648
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);
1654 }
1655
1656 {
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);
1661 pw.commit();
1662
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);
1668 }
1669 }
1670
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;
1683 size_t remaining;
1684
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;
1686
1687 {
1688 /* no EDNS */
1689 vector<uint8_t> query;
1690 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
1691 pw.getHeader()->qr = 1;
1692 pw.getHeader()->rcode = RCode::NXDomain;
1693 pw.commit();
1694
1695 int res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
1696
1697 BOOST_CHECK_EQUAL(res, ENOENT);
1698
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);
1702
1703 BOOST_CHECK_EQUAL(res, ENOENT);
1704 }
1705
1706 {
1707 /* valid EDNS, no options */
1708 vector<uint8_t> query;
1709 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
1710 pw.addOpt(512, 0, 0);
1711 pw.commit();
1712
1713 int res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
1714
1715 BOOST_CHECK_EQUAL(res, 0);
1716 BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
1717 BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
1718
1719 /* truncated packet */
1720 query.resize(query.size() - 1);
1721
1722 res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
1723 BOOST_CHECK_EQUAL(res, ENOENT);
1724 }
1725
1726 {
1727 /* valid EDNS, options */
1728 vector<uint8_t> query;
1729 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
1730 pw.addOpt(512, 0, 0, opts);
1731 pw.commit();
1732
1733 int res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
1734
1735 BOOST_CHECK_EQUAL(res, 0);
1736 BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
1737 BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
1738
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);
1745 }
1746
1747 }
1748
1749 BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt) {
1750
1751 auto locateEDNSOption = [](const vector<uint8_t>& query, uint16_t code, size_t* optContentStart, uint16_t* optContentLen) {
1752 uint16_t optStart;
1753 size_t optLen;
1754 bool last = false;
1755 std::string packetStr(reinterpret_cast<const char*>(query.data()), query.size());
1756 int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last);
1757 if (res != 0) {
1758 // no EDNS OPT RR
1759 return false;
1760 }
1761
1762 if (optLen < optRecordMinimumSize) {
1763 return false;
1764 }
1765
1766 if (optStart < query.size() && packetStr.at(optStart) != 0) {
1767 // OPT RR Name != '.'
1768 return false;
1769 }
1770
1771 return isEDNSOptionInOpt(packetStr, optStart, optLen, code, optContentStart, optContentLen);
1772 };
1773
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();
1787 /*
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));
1792 */
1793 const ComboAddress lc("127.0.0.1");
1794 const ComboAddress rem("127.0.0.1");
1795 size_t optContentStart;
1796 uint16_t optContentLen;
1797
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;
1799
1800 {
1801 /* no EDNS */
1802 vector<uint8_t> query;
1803 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
1804 pw.getHeader()->qr = 1;
1805 pw.getHeader()->rcode = RCode::NXDomain;
1806 pw.commit();
1807
1808 bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
1809 BOOST_CHECK_EQUAL(found, false);
1810
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);
1815 }
1816
1817 {
1818 /* valid EDNS, no options */
1819 vector<uint8_t> query;
1820 DNSPacketWriter pw(query, qname, qtype, qclass, 0);
1821 pw.addOpt(512, 0, 0);
1822 pw.commit();
1823
1824 bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
1825 BOOST_CHECK_EQUAL(found, false);
1826
1827 /* truncated packet */
1828 query.resize(query.size() - 1);
1829 BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::out_of_range);
1830 }
1831
1832 {
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);
1840 pw.commit();
1841
1842 bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
1843 BOOST_CHECK_EQUAL(found, false);
1844
1845 /* truncated packet */
1846 query.resize(query.size() - 1);
1847 BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::range_error);
1848 }
1849
1850 {
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);
1858 pw.commit();
1859
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);
1865 }
1866
1867 /* truncated packet */
1868 query.resize(query.size() - 1);
1869 BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::range_error);
1870 }
1871
1872 {
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);
1881 pw.commit();
1882
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);
1888 }
1889
1890 /* truncated packet */
1891 query.resize(query.size() - 1);
1892 BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::range_error);
1893 }
1894
1895 {
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);
1903 pw.commit();
1904
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());
1910 }
1911
1912 /* truncated packet */
1913 query.resize(query.size() - 1);
1914 BOOST_CHECK_THROW(locateEDNSOption(query, 65002, &optContentStart, &optContentLen), std::range_error);
1915 }
1916 }
1917
1918 BOOST_AUTO_TEST_SUITE_END();