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