]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-dnsdist_cc.cc
Merge pull request #5523 from rubenk/fix-typos-in-logmessage
[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>
26
27#include "dnsdist.hh"
28#include "dnsdist-ecs.hh"
29#include "dolog.hh"
30#include "dnsname.hh"
31#include "dnsparser.hh"
32#include "dnswriter.hh"
5c3b5e7f 33#include "ednsoptions.hh"
ff73f02b 34#include "ednscookies.hh"
ca404e94
RG
35#include "ednssubnet.hh"
36#include <unistd.h>
37
38BOOST_AUTO_TEST_SUITE(dnsdist_cc)
39
40bool g_console{true};
bbfaaa6f 41bool g_syslog{true};
ca404e94
RG
42bool g_verbose{true};
43
ff0902ec
RG
44static const uint16_t ECSSourcePrefixV4 = 24;
45static const uint16_t ECSSourcePrefixV6 = 56;
46
ca404e94
RG
47static void validateQuery(const char * packet, size_t packetSize)
48{
27c0050c 49 MOADNSParser mdp(true, packet, packetSize);
7b146b98 50
ca404e94
RG
51 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
52
53 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
54 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0);
55 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
56 BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1);
57}
58
ff73f02b 59static void validateResponse(const char * packet, size_t packetSize, bool hasEdns, uint8_t additionalCount=0)
7b146b98 60{
27c0050c 61 MOADNSParser mdp(false, packet, packetSize);
7b146b98
RG
62
63 BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
64
65 BOOST_CHECK_EQUAL(mdp.d_header.qr, 1);
66 BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1);
67 BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1);
68 BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0);
ff73f02b 69 BOOST_CHECK_EQUAL(mdp.d_header.arcount, (hasEdns ? 1 : 0) + additionalCount);
7b146b98
RG
70}
71
ca404e94
RG
72BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
73{
74 string largerPacket;
75 bool ednsAdded = false;
ff73f02b 76 bool ecsAdded = false;
ca404e94
RG
77 ComboAddress remote;
78 DNSName name("www.powerdns.com.");
79
80 vector<uint8_t> query;
7b146b98 81 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94 82 pw.getHeader()->rd = 1;
ac688aff 83 uint16_t len = query.size();
7b146b98 84
ca404e94
RG
85 /* large enough packet */
86 char packet[1500];
87 memcpy(packet, query.data(), query.size());
88
89 unsigned int consumed = 0;
90 uint16_t qtype;
91 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
92 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
93 BOOST_CHECK(qtype == QType::A);
94
ff0902ec 95 handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
96 BOOST_CHECK((size_t) len > query.size());
97 BOOST_CHECK_EQUAL(largerPacket.size(), 0);
98 BOOST_CHECK_EQUAL(ednsAdded, true);
ff73f02b 99 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94 100 validateQuery(packet, len);
7b146b98 101
24c48018 102 /* not large enough packet */
ca404e94
RG
103 consumed = 0;
104 len = query.size();
105 qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
106 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
107 BOOST_CHECK(qtype == QType::A);
108
ff0902ec 109 handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
110 BOOST_CHECK_EQUAL((size_t) len, query.size());
111 BOOST_CHECK(largerPacket.size() > query.size());
112 BOOST_CHECK_EQUAL(ednsAdded, true);
ff73f02b 113 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94
RG
114 validateQuery(largerPacket.c_str(), largerPacket.size());
115}
116
117BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) {
118 string largerPacket;
119 bool ednsAdded = false;
ff73f02b 120 bool ecsAdded = false;
ca404e94 121 ComboAddress remote;
7b146b98 122 DNSName name("www.powerdns.com.");
ca404e94
RG
123
124 vector<uint8_t> query;
7b146b98 125 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
126 pw.getHeader()->rd = 1;
127 pw.addOpt(512, 0, 0);
128 pw.commit();
ac688aff 129 uint16_t len = query.size();
7b146b98 130
ca404e94
RG
131 /* large enough packet */
132 char packet[1500];
133 memcpy(packet, query.data(), query.size());
134
135 unsigned int consumed = 0;
136 uint16_t qtype;
137 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
138 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
139 BOOST_CHECK(qtype == QType::A);
140
ff0902ec 141 handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
142 BOOST_CHECK((size_t) len > query.size());
143 BOOST_CHECK_EQUAL(largerPacket.size(), 0);
144 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 145 BOOST_CHECK_EQUAL(ecsAdded, true);
ca404e94 146 validateQuery(packet, len);
7b146b98 147
24c48018 148 /* not large enough packet */
ca404e94
RG
149 consumed = 0;
150 len = query.size();
151 qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
152 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
153 BOOST_CHECK(qtype == QType::A);
154
ff0902ec 155 handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
156 BOOST_CHECK_EQUAL((size_t) len, query.size());
157 BOOST_CHECK(largerPacket.size() > query.size());
158 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 159 BOOST_CHECK_EQUAL(ecsAdded, true);
ca404e94
RG
160 validateQuery(largerPacket.c_str(), largerPacket.size());
161}
162
163BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) {
164 string largerPacket;
165 bool ednsAdded = false;
ff73f02b 166 bool ecsAdded = false;
ca404e94 167 ComboAddress remote("192.168.1.25");
7b146b98 168 DNSName name("www.powerdns.com.");
ca404e94
RG
169 ComboAddress origRemote("127.0.0.1");
170
171 vector<uint8_t> query;
7b146b98 172 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
173 pw.getHeader()->rd = 1;
174 EDNSSubnetOpts ecsOpts;
ff0902ec 175 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ca404e94
RG
176 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
177 DNSPacketWriter::optvect_t opts;
5c3b5e7f 178 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
ca404e94
RG
179 pw.addOpt(512, 0, 0, opts);
180 pw.commit();
ac688aff 181 uint16_t len = query.size();
7b146b98 182
ca404e94
RG
183 /* large enough packet */
184 char packet[1500];
185 memcpy(packet, query.data(), query.size());
186
187 unsigned int consumed = 0;
188 uint16_t qtype;
189 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
190 BOOST_CHECK_EQUAL(qname, name);
7b146b98 191 BOOST_CHECK(qtype == QType::A);
ca404e94 192
ff0902ec 193 handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
194 BOOST_CHECK_EQUAL((size_t) len, query.size());
195 BOOST_CHECK_EQUAL(largerPacket.size(), 0);
196 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 197 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94
RG
198 validateQuery(packet, len);
199}
200
201BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) {
202 string largerPacket;
203 bool ednsAdded = false;
ff73f02b 204 bool ecsAdded = false;
ca404e94 205 ComboAddress remote("192.168.1.25");
7b146b98 206 DNSName name("www.powerdns.com.");
ca404e94
RG
207 ComboAddress origRemote("127.0.0.1");
208
209 vector<uint8_t> query;
7b146b98 210 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
211 pw.getHeader()->rd = 1;
212 EDNSSubnetOpts ecsOpts;
213 ecsOpts.source = Netmask(origRemote, 32);
214 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
215 DNSPacketWriter::optvect_t opts;
5c3b5e7f 216 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
ca404e94
RG
217 pw.addOpt(512, 0, 0, opts);
218 pw.commit();
ac688aff 219 uint16_t len = query.size();
7b146b98 220
ca404e94
RG
221 /* large enough packet */
222 char packet[1500];
223 memcpy(packet, query.data(), query.size());
224
225 unsigned int consumed = 0;
226 uint16_t qtype;
227 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
228 BOOST_CHECK_EQUAL(qname, name);
7b146b98 229 BOOST_CHECK(qtype == QType::A);
ca404e94 230
ff0902ec 231 handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
232 BOOST_CHECK((size_t) len < query.size());
233 BOOST_CHECK_EQUAL(largerPacket.size(), 0);
234 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 235 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94
RG
236 validateQuery(packet, len);
237}
238
239BOOST_AUTO_TEST_CASE(replaceECSWithLarger) {
240 string largerPacket;
241 bool ednsAdded = false;
ff73f02b 242 bool ecsAdded = false;
ca404e94 243 ComboAddress remote("192.168.1.25");
7b146b98 244 DNSName name("www.powerdns.com.");
ca404e94
RG
245 ComboAddress origRemote("127.0.0.1");
246
247 vector<uint8_t> query;
7b146b98 248 DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
ca404e94
RG
249 pw.getHeader()->rd = 1;
250 EDNSSubnetOpts ecsOpts;
251 ecsOpts.source = Netmask(origRemote, 8);
252 string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
253 DNSPacketWriter::optvect_t opts;
5c3b5e7f 254 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
ca404e94
RG
255 pw.addOpt(512, 0, 0, opts);
256 pw.commit();
ac688aff 257 uint16_t len = query.size();
7b146b98 258
ca404e94
RG
259 /* large enough packet */
260 char packet[1500];
261 memcpy(packet, query.data(), query.size());
262
263 unsigned int consumed = 0;
264 uint16_t qtype;
265 DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
266 BOOST_CHECK_EQUAL(qname, name);
7b146b98 267 BOOST_CHECK(qtype == QType::A);
ca404e94 268
ff0902ec 269 handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
270 BOOST_CHECK((size_t) len > query.size());
271 BOOST_CHECK_EQUAL(largerPacket.size(), 0);
272 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 273 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94
RG
274 validateQuery(packet, len);
275
24c48018 276 /* not large enough packet */
ca404e94
RG
277 consumed = 0;
278 len = query.size();
279 qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
280 BOOST_CHECK_EQUAL(qname, name);
7b146b98
RG
281 BOOST_CHECK(qtype == QType::A);
282
ff0902ec 283 handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
ca404e94
RG
284 BOOST_CHECK_EQUAL((size_t) len, query.size());
285 BOOST_CHECK(largerPacket.size() > query.size());
286 BOOST_CHECK_EQUAL(ednsAdded, false);
ff73f02b 287 BOOST_CHECK_EQUAL(ecsAdded, false);
ca404e94
RG
288 validateQuery(largerPacket.c_str(), largerPacket.size());
289}
290
ff73f02b 291BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) {
7b146b98
RG
292 DNSName name("www.powerdns.com.");
293
294 vector<uint8_t> response;
295 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
296 pw.getHeader()->qr = 1;
297 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
298 pw.xfr32BitInt(0x01020304);
299 pw.addOpt(512, 0, 0);
300 pw.commit();
ff73f02b
RG
301 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
302 pw.xfr32BitInt(0x01020304);
303 pw.commit();
7b146b98
RG
304
305 vector<uint8_t> newResponse;
306 int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse);
ff73f02b
RG
307 BOOST_CHECK_EQUAL(res, 0);
308
309 unsigned int consumed = 0;
310 uint16_t qtype;
311 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
312 BOOST_CHECK_EQUAL(qname, name);
313 BOOST_CHECK(qtype == QType::A);
314 size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
315 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
316
317 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
318}
319
320BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) {
321 DNSName name("www.powerdns.com.");
322
323 vector<uint8_t> response;
324 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
325 pw.getHeader()->qr = 1;
326 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
327 pw.xfr32BitInt(0x01020304);
328 pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
329 pw.xfr32BitInt(0x01020304);
330 pw.commit();
331 pw.addOpt(512, 0, 0);
332 pw.commit();
333 pw.startRecord(DNSName("yetanother.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
334 pw.xfr32BitInt(0x01020304);
335 pw.commit();
7b146b98 336
ff73f02b
RG
337 vector<uint8_t> newResponse;
338 int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse);
7b146b98
RG
339 BOOST_CHECK_EQUAL(res, 0);
340
341 unsigned int consumed = 0;
342 uint16_t qtype;
343 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
344 BOOST_CHECK_EQUAL(qname, name);
345 BOOST_CHECK(qtype == QType::A);
346 size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
347 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
348
ff73f02b
RG
349 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 2);
350}
351
352BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) {
353 DNSName name("www.powerdns.com.");
354
355 vector<uint8_t> response;
356 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
357 pw.getHeader()->qr = 1;
358 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
359 pw.xfr32BitInt(0x01020304);
360 pw.commit();
361 pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
362 pw.xfr32BitInt(0x01020304);
363 pw.commit();
364 pw.addOpt(512, 0, 0);
365 pw.commit();
366
367 vector<uint8_t> newResponse;
368 int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse);
369
370 BOOST_CHECK_EQUAL(res, 0);
371
372 unsigned int consumed = 0;
373 uint16_t qtype;
374 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
375 BOOST_CHECK_EQUAL(qname, name);
376 BOOST_CHECK(qtype == QType::A);
377 size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
378 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
379
380 validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
381}
382
383BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) {
384 DNSName name("www.powerdns.com.");
385 ComboAddress origRemote("127.0.0.1");
386
387 vector<uint8_t> response;
388 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
389 pw.getHeader()->qr = 1;
390 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
391 pw.xfr32BitInt(0x01020304);
392
393 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
394 pw.xfr32BitInt(0x01020304);
395 pw.commit();
396
397 EDNSSubnetOpts ecsOpts;
ff0902ec 398 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
399 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
400 DNSPacketWriter::optvect_t opts;
401 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
402 pw.addOpt(512, 0, 0, opts);
403 pw.commit();
404
405 char * optStart = NULL;
406 size_t optLen = 0;
407 bool last = false;
408
409 int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last);
410 BOOST_CHECK_EQUAL(res, 0);
411 BOOST_CHECK_EQUAL(last, true);
412
413 size_t responseLen = response.size();
414 size_t existingOptLen = optLen;
415 BOOST_CHECK(existingOptLen < responseLen);
416 res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS);
417 BOOST_CHECK_EQUAL(res, 0);
418 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
419 responseLen -= (existingOptLen - optLen);
420
421 unsigned int consumed = 0;
422 uint16_t qtype;
423 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
424 BOOST_CHECK_EQUAL(qname, name);
425 BOOST_CHECK(qtype == QType::A);
426
427 validateResponse((const char *) response.data(), responseLen, true, 1);
428}
429
430BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) {
431 DNSName name("www.powerdns.com.");
432 ComboAddress origRemote("127.0.0.1");
433
434 vector<uint8_t> response;
435 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
436 pw.getHeader()->qr = 1;
437 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
438 pw.xfr32BitInt(0x01020304);
439
440 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
441 pw.xfr32BitInt(0x01020304);
442 pw.commit();
443
444 EDNSSubnetOpts ecsOpts;
ff0902ec 445 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV6);
ff73f02b
RG
446 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
447 EDNSCookiesOpt cookiesOpt;
448 cookiesOpt.client = string("deadbeef");
449 cookiesOpt.server = string("deadbeef");
450 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
451 DNSPacketWriter::optvect_t opts;
452 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
453 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
454 pw.addOpt(512, 0, 0, opts);
455 pw.commit();
456
457 char * optStart = NULL;
458 size_t optLen = 0;
459 bool last = false;
460
461 int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last);
462 BOOST_CHECK_EQUAL(res, 0);
463 BOOST_CHECK_EQUAL(last, true);
464
465 size_t responseLen = response.size();
466 size_t existingOptLen = optLen;
467 BOOST_CHECK(existingOptLen < responseLen);
468 res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS);
469 BOOST_CHECK_EQUAL(res, 0);
470 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
471 responseLen -= (existingOptLen - optLen);
472
473 unsigned int consumed = 0;
474 uint16_t qtype;
475 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
476 BOOST_CHECK_EQUAL(qname, name);
477 BOOST_CHECK(qtype == QType::A);
478
479 validateResponse((const char *) response.data(), responseLen, true, 1);
480}
481
482BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) {
483 DNSName name("www.powerdns.com.");
484 ComboAddress origRemote("127.0.0.1");
485
486 vector<uint8_t> response;
487 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
488 pw.getHeader()->qr = 1;
489 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
490 pw.xfr32BitInt(0x01020304);
491
492 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
493 pw.xfr32BitInt(0x01020304);
494 pw.commit();
495
496 EDNSSubnetOpts ecsOpts;
ff0902ec 497 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
498 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
499
500 EDNSCookiesOpt cookiesOpt;
501 cookiesOpt.client = string("deadbeef");
502 cookiesOpt.server = string("deadbeef");
503 string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt);
504 string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt);
505
506 DNSPacketWriter::optvect_t opts;
507 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1));
508 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
509 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2));
510 pw.addOpt(512, 0, 0, opts);
511 pw.commit();
512
513 char * optStart = NULL;
514 size_t optLen = 0;
515 bool last = false;
516
517 int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last);
518 BOOST_CHECK_EQUAL(res, 0);
519 BOOST_CHECK_EQUAL(last, true);
520
521 size_t responseLen = response.size();
522 size_t existingOptLen = optLen;
523 BOOST_CHECK(existingOptLen < responseLen);
524 res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS);
525 BOOST_CHECK_EQUAL(res, 0);
526 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
527 responseLen -= (existingOptLen - optLen);
528
529 unsigned int consumed = 0;
530 uint16_t qtype;
531 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
532 BOOST_CHECK_EQUAL(qname, name);
533 BOOST_CHECK(qtype == QType::A);
534
535 validateResponse((const char *) response.data(), responseLen, true, 1);
536}
537
538BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) {
539 DNSName name("www.powerdns.com.");
540 ComboAddress origRemote("127.0.0.1");
541
542 vector<uint8_t> response;
543 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
544 pw.getHeader()->qr = 1;
545 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
546 pw.xfr32BitInt(0x01020304);
547
548 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
549 pw.xfr32BitInt(0x01020304);
550 pw.commit();
551
552 EDNSCookiesOpt cookiesOpt;
553 cookiesOpt.client = string("deadbeef");
554 cookiesOpt.server = string("deadbeef");
555 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
556 EDNSSubnetOpts ecsOpts;
ff0902ec 557 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
558 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
559 DNSPacketWriter::optvect_t opts;
560 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
561 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
562 pw.addOpt(512, 0, 0, opts);
563 pw.commit();
564
565 char * optStart = NULL;
566 size_t optLen = 0;
567 bool last = false;
568
569 int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last);
570 BOOST_CHECK_EQUAL(res, 0);
571 BOOST_CHECK_EQUAL(last, true);
572
573 size_t responseLen = response.size();
574 size_t existingOptLen = optLen;
575 BOOST_CHECK(existingOptLen < responseLen);
576 res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS);
577 BOOST_CHECK_EQUAL(res, 0);
578 BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
579 responseLen -= (existingOptLen - optLen);
580
581 unsigned int consumed = 0;
582 uint16_t qtype;
583 DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
584 BOOST_CHECK_EQUAL(qname, name);
585 BOOST_CHECK(qtype == QType::A);
586
587 validateResponse((const char *) response.data(), responseLen, true, 1);
588}
589
590BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) {
591 DNSName name("www.powerdns.com.");
592 ComboAddress origRemote("127.0.0.1");
593
594 vector<uint8_t> response;
595 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
596 pw.getHeader()->qr = 1;
597 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
598 pw.xfr32BitInt(0x01020304);
599
600 EDNSSubnetOpts ecsOpts;
ff0902ec 601 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
602 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
603 DNSPacketWriter::optvect_t opts;
604 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
605 pw.addOpt(512, 0, 0, opts);
606 pw.commit();
607
608 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
609 pw.xfr32BitInt(0x01020304);
610 pw.commit();
611
612 vector<uint8_t> newResponse;
613 int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse);
614 BOOST_CHECK_EQUAL(res, 0);
615
616 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
617
618 unsigned int consumed = 0;
619 uint16_t qtype;
620 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
621 BOOST_CHECK_EQUAL(qname, name);
622 BOOST_CHECK(qtype == QType::A);
623
624 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
625}
626
627BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) {
628 DNSName name("www.powerdns.com.");
629 ComboAddress origRemote("127.0.0.1");
630
631 vector<uint8_t> response;
632 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
633 pw.getHeader()->qr = 1;
634 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
635 pw.xfr32BitInt(0x01020304);
636
637 EDNSSubnetOpts ecsOpts;
ff0902ec 638 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
639 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
640 EDNSCookiesOpt cookiesOpt;
641 cookiesOpt.client = string("deadbeef");
642 cookiesOpt.server = string("deadbeef");
643 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
644 DNSPacketWriter::optvect_t opts;
645 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
646 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
647 pw.addOpt(512, 0, 0, opts);
648 pw.commit();
649
650 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
651 pw.xfr32BitInt(0x01020304);
652 pw.commit();
653
654 vector<uint8_t> newResponse;
655 int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse);
656 BOOST_CHECK_EQUAL(res, 0);
657
658 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
659
660 unsigned int consumed = 0;
661 uint16_t qtype;
662 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
663 BOOST_CHECK_EQUAL(qname, name);
664 BOOST_CHECK(qtype == QType::A);
665
666 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
667}
668
669BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) {
670 DNSName name("www.powerdns.com.");
671 ComboAddress origRemote("127.0.0.1");
672
673 vector<uint8_t> response;
674 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
675 pw.getHeader()->qr = 1;
676 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
677 pw.xfr32BitInt(0x01020304);
678
679 EDNSSubnetOpts ecsOpts;
ff0902ec 680 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
681 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
682 EDNSCookiesOpt cookiesOpt;
683 cookiesOpt.client = string("deadbeef");
684 cookiesOpt.server = string("deadbeef");
685 string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt);
686 string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt);
687 DNSPacketWriter::optvect_t opts;
688 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1));
689 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
690 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2));
691 pw.addOpt(512, 0, 0, opts);
692 pw.commit();
693
694 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
695 pw.xfr32BitInt(0x01020304);
696 pw.commit();
697
698 vector<uint8_t> newResponse;
699 int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse);
700 BOOST_CHECK_EQUAL(res, 0);
701
702 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
703
704 unsigned int consumed = 0;
705 uint16_t qtype;
706 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
707 BOOST_CHECK_EQUAL(qname, name);
708 BOOST_CHECK(qtype == QType::A);
709
710 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
711}
712
713BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
714 DNSName name("www.powerdns.com.");
715 ComboAddress origRemote("127.0.0.1");
716
717 vector<uint8_t> response;
718 DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0);
719 pw.getHeader()->qr = 1;
720 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
721 pw.xfr32BitInt(0x01020304);
722
723 EDNSSubnetOpts ecsOpts;
ff0902ec 724 ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
ff73f02b
RG
725 string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
726 EDNSCookiesOpt cookiesOpt;
727 cookiesOpt.client = string("deadbeef");
728 cookiesOpt.server = string("deadbeef");
729 string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt);
730 DNSPacketWriter::optvect_t opts;
731 opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr));
732 opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr));
733 pw.addOpt(512, 0, 0, opts);
734 pw.commit();
735
736 pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
737 pw.xfr32BitInt(0x01020304);
738 pw.commit();
739
740 vector<uint8_t> newResponse;
741 int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse);
742 BOOST_CHECK_EQUAL(res, 0);
743
744 BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
745
746 unsigned int consumed = 0;
747 uint16_t qtype;
748 DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
749 BOOST_CHECK_EQUAL(qname, name);
750 BOOST_CHECK(qtype == QType::A);
751
752 validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
7b146b98
RG
753}
754
ca404e94 755BOOST_AUTO_TEST_SUITE_END();