]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-dnsdist_cc.cc
dnsdist: Add SetNegativeAndSOAAction() and its Lua binding
[thirdparty/pdns.git] / pdns / test-dnsdist_cc.cc
CommitLineData
ca404e94 1/*
6edbf68a
PL
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 */
ca404e94
RG
22#define BOOST_TEST_DYN_LINK
23#define BOOST_TEST_NO_MAIN
24
25#include <boost/test/unit_test.hpp>
53c57da7 26#include <unistd.h>
ca404e94
RG
27
28#include "dnsdist.hh"
29#include "dnsdist-ecs.hh"
53c57da7
RG
30#include "dnsdist-xpf.hh"
31
ca404e94
RG
32#include "dolog.hh"
33#include "dnsname.hh"
34#include "dnsparser.hh"
35#include "dnswriter.hh"
5c3b5e7f 36#include "ednsoptions.hh"
ff73f02b 37#include "ednscookies.hh"
ca404e94 38#include "ednssubnet.hh"
ca404e94 39
c7f29d3e 40BOOST_AUTO_TEST_SUITE(test_dnsdist_cc)
ca404e94 41
ff0902ec
RG
42static const uint16_t ECSSourcePrefixV4 = 24;
43static const uint16_t ECSSourcePrefixV6 = 56;
44
f8a01c44 45static 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)
ca404e94 46{
27c0050c 47 MOADNSParser mdp(true, packet, packetSize);
7b146b98 48
ca404e94
RG
49 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
50
690b86b7 51 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
f8a01c44
RG
52 BOOST_CHECK_EQUAL(mdp.d_header.ancount, answers);
53 BOOST_CHECK_EQUAL(mdp.d_header.nscount, authorities);
be90d6bd 54 uint16_t expectedARCount = additionals + (hasEdns ? 1U : 0U) + (hasXPF ? 1U : 0U);
53c57da7 55 BOOST_CHECK_EQUAL(mdp.d_header.arcount, expectedARCount);
ca404e94
RG
56}
57
cbf4e13a
RG
58static 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);
690b86b7 68 BOOST_CHECK_EQUAL(dq.ednsOptions->size(), 1U);
cbf4e13a
RG
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 */
690b86b7 75 BOOST_REQUIRE_EQUAL(ecsOption->second.values.size(), 1U);
cbf4e13a
RG
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
ff73f02b 79static void validateResponse(const char * packet, size_t packetSize, bool hasEdns, uint8_t additionalCount=0)
7b146b98 80{
27c0050c 81 MOADNSParser mdp(false, packet, packetSize);
7b146b98
RG
82
83 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
84
690b86b7
OM
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);
7b146b98
RG
90}
91
53c57da7
RG
92BOOST_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
ca404e94
RG
210BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
211{
ca404e94 212 bool ednsAdded = false;
ff73f02b 213 bool ecsAdded = false;
cbf4e13a 214 ComboAddress remote("192.0.2.1");
ca404e94 215 DNSName name("www.powerdns.com.");
cbf4e13a
RG
216 string newECSOption;
217 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
218
219 vector<uint8_t> query;
7b146b98 220 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94 221 pw.getHeader()->rd = 1;
ac688aff 222 uint16_t len = query.size();
7b146b98 223
ca404e94
RG
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;
53c57da7 230 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
ca404e94 231 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
232 BOOST_CHECK(qtype == QType::A);
233
be90d6bd 234 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
53c57da7 235 BOOST_CHECK(static_cast<size_t>(len) > query.size());
ca404e94 236 BOOST_CHECK_EQUAL(ednsAdded, true);
be90d6bd 237 BOOST_CHECK_EQUAL(ecsAdded, true);
ca404e94 238 validateQuery(packet, len);
cbf4e13a 239 validateECS(packet, len, remote);
53c57da7
RG
240 vector<uint8_t> queryWithEDNS;
241 queryWithEDNS.resize(len);
242 memcpy(queryWithEDNS.data(), packet, len);
7b146b98 243
24c48018 244 /* not large enough packet */
0beaa5c8
RG
245 ednsAdded = false;
246 ecsAdded = false;
ca404e94
RG
247 consumed = 0;
248 len = query.size();
53c57da7 249 qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
ca404e94 250 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
251 BOOST_CHECK(qtype == QType::A);
252
be90d6bd 253 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
53c57da7 254 BOOST_CHECK_EQUAL(static_cast<size_t>(len), query.size());
0beaa5c8 255 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 256 BOOST_CHECK_EQUAL(ecsAdded, false);
0beaa5c8 257 validateQuery(reinterpret_cast<char*>(query.data()), len, false);
53c57da7
RG
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;
be90d6bd 276 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
53c57da7
RG
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);
be90d6bd 280 BOOST_CHECK_EQUAL(ecsAdded, true);
53c57da7
RG
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;
be90d6bd 299 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, true));
53c57da7
RG
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);
be90d6bd 306 BOOST_CHECK_EQUAL(ecsAdded, true);
53c57da7 307 validateQuery(packet, len);
ca404e94
RG
308}
309
cbf4e13a
RG
310BOOST_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 */
be90d6bd 338 BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded, false));
cbf4e13a
RG
339 BOOST_CHECK_GT(static_cast<size_t>(dq.len), query.size());
340 BOOST_CHECK_EQUAL(ednsAdded, true);
be90d6bd 341 BOOST_CHECK_EQUAL(ecsAdded, true);
cbf4e13a
RG
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
be90d6bd 355 BOOST_CHECK(!handleEDNSClientSubnet(dq2, ednsAdded, ecsAdded, false));
cbf4e13a
RG
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
ca404e94 362BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) {
ca404e94 363 bool ednsAdded = false;
ff73f02b 364 bool ecsAdded = false;
ca404e94 365 ComboAddress remote;
7b146b98 366 DNSName name("www.powerdns.com.");
cbf4e13a
RG
367 string newECSOption;
368 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
369
370 vector<uint8_t> query;
7b146b98 371 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
372 pw.getHeader()->rd = 1;
373 pw.addOpt(512, 0, 0);
374 pw.commit();
ac688aff 375 uint16_t len = query.size();
7b146b98 376
ca404e94
RG
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);
7b146b98
RG
385 BOOST_CHECK(qtype == QType::A);
386
be90d6bd 387 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
ca404e94 388 BOOST_CHECK((size_t) len > query.size());
ca404e94 389 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 390 BOOST_CHECK_EQUAL(ecsAdded, true);
ca404e94 391 validateQuery(packet, len);
cbf4e13a 392 validateECS(packet, len, remote);
7b146b98 393
24c48018 394 /* not large enough packet */
ca404e94 395 consumed = 0;
0beaa5c8
RG
396 ednsAdded = false;
397 ecsAdded = false;
ca404e94 398 len = query.size();
0beaa5c8 399 qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
ca404e94 400 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
401 BOOST_CHECK(qtype == QType::A);
402
be90d6bd 403 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
ca404e94 404 BOOST_CHECK_EQUAL((size_t) len, query.size());
ca404e94 405 BOOST_CHECK_EQUAL(ednsAdded, false);
0beaa5c8
RG
406 BOOST_CHECK_EQUAL(ecsAdded, false);
407 validateQuery(reinterpret_cast<char*>(query.data()), len);
ca404e94
RG
408}
409
cbf4e13a
RG
410BOOST_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 */
be90d6bd 439 BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded, false));
cbf4e13a
RG
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
be90d6bd 456 BOOST_CHECK(!handleEDNSClientSubnet(dq2, ednsAdded, ecsAdded, false));
cbf4e13a
RG
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
ca404e94 463BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) {
ca404e94 464 bool ednsAdded = false;
ff73f02b 465 bool ecsAdded = false;
ca404e94 466 ComboAddress remote("192.168.1.25");
7b146b98 467 DNSName name("www.powerdns.com.");
ca404e94 468 ComboAddress origRemote("127.0.0.1");
cbf4e13a
RG
469 string newECSOption;
470 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
471
472 vector<uint8_t> query;
7b146b98 473 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
474 pw.getHeader()->rd = 1;
475 EDNSSubnetOpts ecsOpts;
ff0902ec 476 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ca404e94
RG
477 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
478 DNSPacketWriter::optvect_t opts;
5c3b5e7f 479 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
ca404e94
RG
480 pw.addOpt(512, 0, 0, opts);
481 pw.commit();
ac688aff 482 uint16_t len = query.size();
7b146b98 483
ca404e94
RG
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);
7b146b98 492 BOOST_CHECK(qtype == QType::A);
ca404e94 493
be90d6bd 494 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
ca404e94 495 BOOST_CHECK_EQUAL((size_t) len, query.size());
ca404e94 496 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 497 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94 498 validateQuery(packet, len);
cbf4e13a
RG
499 validateECS(packet, len, remote);
500}
501
502BOOST_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 */
be90d6bd 539 BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded, false));
cbf4e13a
RG
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);
ca404e94
RG
545}
546
547BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) {
ca404e94 548 bool ednsAdded = false;
ff73f02b 549 bool ecsAdded = false;
ca404e94 550 ComboAddress remote("192.168.1.25");
7b146b98 551 DNSName name("www.powerdns.com.");
ca404e94 552 ComboAddress origRemote("127.0.0.1");
cbf4e13a
RG
553 string newECSOption;
554 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
555
556 vector<uint8_t> query;
7b146b98 557 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
558 pw.getHeader()->rd = 1;
559 EDNSSubnetOpts ecsOpts;
560 ecsOpts.source = Netmask(origRemote, 32);
561 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
562 DNSPacketWriter::optvect_t opts;
5c3b5e7f 563 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
ca404e94
RG
564 pw.addOpt(512, 0, 0, opts);
565 pw.commit();
ac688aff 566 uint16_t len = query.size();
7b146b98 567
ca404e94
RG
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);
7b146b98 576 BOOST_CHECK(qtype == QType::A);
ca404e94 577
be90d6bd 578 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
ca404e94 579 BOOST_CHECK((size_t) len < query.size());
ca404e94 580 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 581 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94 582 validateQuery(packet, len);
cbf4e13a 583 validateECS(packet, len, remote);
ca404e94
RG
584}
585
586BOOST_AUTO_TEST_CASE(replaceECSWithLarger) {
ca404e94 587 bool ednsAdded = false;
ff73f02b 588 bool ecsAdded = false;
ca404e94 589 ComboAddress remote("192.168.1.25");
7b146b98 590 DNSName name("www.powerdns.com.");
ca404e94 591 ComboAddress origRemote("127.0.0.1");
cbf4e13a
RG
592 string newECSOption;
593 generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
594
595 vector<uint8_t> query;
7b146b98 596 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
597 pw.getHeader()->rd = 1;
598 EDNSSubnetOpts ecsOpts;
599 ecsOpts.source = Netmask(origRemote, 8);
600 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
601 DNSPacketWriter::optvect_t opts;
5c3b5e7f 602 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
ca404e94
RG
603 pw.addOpt(512, 0, 0, opts);
604 pw.commit();
ac688aff 605 uint16_t len = query.size();
7b146b98 606
ca404e94
RG
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);
7b146b98 615 BOOST_CHECK(qtype == QType::A);
ca404e94 616
be90d6bd 617 BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
ca404e94 618 BOOST_CHECK((size_t) len > query.size());
ca404e94 619 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 620 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94 621 validateQuery(packet, len);
cbf4e13a 622 validateECS(packet, len, remote);
ca404e94 623
24c48018 624 /* not large enough packet */
0beaa5c8
RG
625 ednsAdded = false;
626 ecsAdded = false;
ca404e94
RG
627 consumed = 0;
628 len = query.size();
0beaa5c8 629 qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
ca404e94 630 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
631 BOOST_CHECK(qtype == QType::A);
632
be90d6bd 633 BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
ca404e94 634 BOOST_CHECK_EQUAL((size_t) len, query.size());
ca404e94 635 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 636 BOOST_CHECK_EQUAL(ecsAdded, false);
0beaa5c8 637 validateQuery(reinterpret_cast<char*>(query.data()), len);
ca404e94
RG
638}
639
be90d6bd
RG
640BOOST_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
f8a01c44
RG
695BOOST_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
751BOOST_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
be90d6bd
RG
807BOOST_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
864BOOST_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
916BOOST_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
f8a01c44 966
ff73f02b 967BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) {
7b146b98
RG
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();
ff73f02b
RG
977 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
978 pw.xfr32BitInt(0x01020304);
979 pw.commit();
7b146b98
RG
980
981 vector<uint8_t> newResponse;
11d5d247 982 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
ff73f02b
RG
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
996BOOST_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();
7b146b98 1012
ff73f02b 1013 vector<uint8_t> newResponse;
11d5d247 1014 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
7b146b98
RG
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
ff73f02b
RG
1025 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 2);
1026}
1027
1028BOOST_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;
11d5d247 1044 int res = rewriteResponseWithoutEDNS(std::string((const char *) response.data(), response.size()), newResponse);
ff73f02b
RG
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
1059BOOST_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;
ff0902ec 1074 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
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
11d5d247 1081 uint16_t optStart;
ff73f02b
RG
1082 size_t optLen = 0;
1083 bool last = false;
1084
11d5d247 1085 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
ff73f02b
RG
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);
11d5d247 1092 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
ff73f02b
RG
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
1106BOOST_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;
ff0902ec 1121 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV6);
ff73f02b
RG
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
11d5d247 1133 uint16_t optStart;
ff73f02b
RG
1134 size_t optLen = 0;
1135 bool last = false;
1136
11d5d247 1137 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
ff73f02b
RG
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);
11d5d247 1144 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
ff73f02b
RG
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
1158BOOST_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;
ff0902ec 1173 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
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
11d5d247 1189 uint16_t optStart;
ff73f02b
RG
1190 size_t optLen = 0;
1191 bool last = false;
1192
11d5d247 1193 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
ff73f02b
RG
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);
11d5d247 1200 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
ff73f02b
RG
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
1214BOOST_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;
ff0902ec 1233 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
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
11d5d247 1241 uint16_t optStart;
ff73f02b
RG
1242 size_t optLen = 0;
1243 bool last = false;
1244
11d5d247 1245 int res = locateEDNSOptRR(std::string((char *) response.data(), response.size()), &optStart, &optLen, &last);
ff73f02b
RG
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);
11d5d247 1252 res = removeEDNSOptionFromOPT(reinterpret_cast<char *>(response.data()) + optStart, &optLen, EDNSOptionCode::ECS);
ff73f02b
RG
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
1266BOOST_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;
ff0902ec 1277 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
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;
11d5d247 1289 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
ff73f02b
RG
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
1303BOOST_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;
ff0902ec 1314 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
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;
11d5d247 1331 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
ff73f02b
RG
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
1345BOOST_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;
ff0902ec 1356 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
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;
11d5d247 1375 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
ff73f02b
RG
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
1389BOOST_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;
ff0902ec 1400 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
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;
11d5d247 1417 int res = rewriteResponseWithoutEDNSOption(std::string((const char *) response.data(), response.size()), EDNSOptionCode::ECS, newResponse);
ff73f02b
RG
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);
7b146b98
RG
1429}
1430
e7c732b8
RG
1431static 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
dd1a3034 1435 return DNSQuestion(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, dh, query.size(), len, false, &realTime);
e7c732b8
RG
1436}
1437
1438static 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
1452static 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
1464BOOST_AUTO_TEST_CASE(test_getEDNSZ) {
1465
e0fd37ec
RG
1466 uint16_t z;
1467 uint16_t udpPayloadSize;
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
1558 }
1559
1560}
1561
1562BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse) {
1563
e0fd37ec
RG
1564 uint16_t z;
1565 uint16_t udpPayloadSize;
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
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);
e0fd37ec
RG
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);
e7c732b8
RG
1668 }
1669}
1670
65ece584
RG
1671BOOST_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
1749BOOST_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
2aa2c0aa 1762 if (optLen < optRecordMinimumSize) {
65ece584
RG
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();
3167201e 1781 const size_t sizeOfECSOption = /* option code */ 2 + /* option length */ 2 + sizeOfECSContent;
65ece584
RG
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);
5e1f23ca
RG
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 }
65ece584
RG
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);
5e1f23ca
RG
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 }
65ece584
RG
1889
1890 /* truncated packet */
1891 query.resize(query.size() - 1);
1892 BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::range_error);
1893 }
3167201e
RG
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 }
65ece584
RG
1916}
1917
af9f750c
RG
1918BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA) {
1919 struct timespec queryTime;
1920 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
1921 ComboAddress remote;
1922 DNSName name("www.powerdns.com.");
1923
1924 vector<uint8_t> query;
1925 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
1926 pw.getHeader()->rd = 1;
1927 const uint16_t len = query.size();
1928
1929 /* test NXD */
1930 {
1931 char packet[1500];
1932 memcpy(packet, query.data(), query.size());
1933
1934 unsigned int consumed = 0;
1935 uint16_t qtype;
1936 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
1937 auto dh = reinterpret_cast<dnsheader*>(packet);
1938 DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
1939
1940 BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5));
1941 BOOST_CHECK(static_cast<size_t>(dq.len) > query.size());
1942 MOADNSParser mdp(true, packet, dq.len);
1943
1944 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
1945 BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain);
1946 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
1947 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0);
1948 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
1949 BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2);
1950 BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2);
1951 BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
1952 BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
1953 BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
1954 BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
1955 BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
1956 }
1957
1958 /* test No Data */
1959 {
1960 char packet[1500];
1961 memcpy(packet, query.data(), query.size());
1962
1963 unsigned int consumed = 0;
1964 uint16_t qtype;
1965 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
1966 auto dh = reinterpret_cast<dnsheader*>(packet);
1967 DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
1968
1969 BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5));
1970 BOOST_CHECK(static_cast<size_t>(dq.len) > query.size());
1971 MOADNSParser mdp(true, packet, dq.len);
1972
1973 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
1974 BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError);
1975 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
1976 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0);
1977 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
1978 BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2);
1979 BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2);
1980 BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
1981 BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
1982 BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
1983 BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
1984 BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
1985 }
1986}
1987
ca404e94 1988BOOST_AUTO_TEST_SUITE_END();