• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.7
/pdns/dnsdistdist/test-dnsdist_cc.cc
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#ifndef BOOST_TEST_DYN_LINK
23
#define BOOST_TEST_DYN_LINK
24
#endif
25

26
#define BOOST_TEST_NO_MAIN
27

28
#include <boost/test/unit_test.hpp>
29
#include <unistd.h>
30

31
#include "dnsdist.hh"
32
#include "dnsdist-ecs.hh"
33
#include "dnsdist-internal-queries.hh"
34
#include "dnsdist-snmp.hh"
35
#include "dnsdist-tcp.hh"
36
#include "dnsdist-xsk.hh"
37

38
#include "dolog.hh"
39
#include "dnsname.hh"
40
#include "dnsparser.hh"
41
#include "dnswriter.hh"
42
#include "ednsoptions.hh"
43
#include "ednscookies.hh"
44
#include "ednssubnet.hh"
45

46
ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
47
{
×
48
  return ProcessQueryResult::Drop;
×
49
}
×
50

51
bool processResponseAfterRules(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
52
{
×
53
  return false;
×
54
}
×
55

56
bool applyRulesToResponse(const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, DNSResponse& dnsResponse)
57
{
12✔
58
  return true;
12✔
59
}
12✔
60

61
bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
62
{
×
63
  return false;
×
64
}
×
65

66
bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& downstream, uint16_t queryID, DNSQuestion& dnsQuestion, PacketBuffer& query, bool actuallySend)
67
{
1✔
68
  return true;
1✔
69
}
1✔
70

71
namespace dnsdist
72
{
73
std::unique_ptr<CrossProtocolQuery> getInternalQueryFromDQ(DNSQuestion& dnsQuestion, bool isResponse)
74
{
×
75
  return nullptr;
×
76
}
×
77
}
78

79
// NOLINTNEXTLINE(readability-convert-member-functions-to-static): only a stub
80
bool DNSDistSNMPAgent::sendBackendStatusChangeTrap([[maybe_unused]] DownstreamState const& backend)
81
{
×
82
  return false;
×
83
}
×
84

85
#ifdef HAVE_XSK
86
namespace dnsdist::xsk
87
{
88
bool XskProcessQuery(ClientState& clientState, XskPacket& packet)
89
{
×
90
  return false;
×
91
}
×
92
}
93
#endif /* HAVE_XSK */
94

95
bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, InternalQueryState&& ids)
96
{
×
97
  return false;
×
98
}
×
99

100
BOOST_AUTO_TEST_SUITE(test_dnsdist_cc)
101

102
static const uint16_t ECSSourcePrefixV4 = 24;
103
static const uint16_t ECSSourcePrefixV6 = 56;
104

105
static void validateQuery(const PacketBuffer& packet, bool hasEdns = true, uint16_t additionals = 0, uint16_t answers = 0, uint16_t authorities = 0)
106
{
58✔
107
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
108
  MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
58✔
109

110
  BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
58✔
111

112
  BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
58✔
113
  BOOST_CHECK_EQUAL(mdp.d_header.ancount, answers);
58✔
114
  BOOST_CHECK_EQUAL(mdp.d_header.nscount, authorities);
58✔
115
  uint16_t expectedARCount = additionals + (hasEdns ? 1U : 0U);
58✔
116
  BOOST_CHECK_EQUAL(mdp.d_header.arcount, expectedARCount);
58✔
117
}
58✔
118

119
static void validateECS(const PacketBuffer& packet, const ComboAddress& expected)
120
{
34✔
121
  InternalQueryState ids;
34✔
122
  ids.protocol = dnsdist::Protocol::DoUDP;
34✔
123
  ids.origRemote = ComboAddress("::1");
34✔
124
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
125
  ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
34✔
126
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
127
  DNSQuestion dnsQuestion(ids, const_cast<PacketBuffer&>(packet));
34✔
128
  BOOST_CHECK(parseEDNSOptions(dnsQuestion));
34✔
129
  BOOST_REQUIRE(dnsQuestion.ednsOptions != nullptr);
34✔
130
  BOOST_CHECK_EQUAL(dnsQuestion.ednsOptions->size(), 1U);
34✔
131
  const auto& ecsOption = dnsQuestion.ednsOptions->find(EDNSOptionCode::ECS);
34✔
132
  BOOST_REQUIRE(ecsOption != dnsQuestion.ednsOptions->cend());
34✔
133

134
  string expectedOption;
34✔
135
  generateECSOption(expected, expectedOption, expected.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
34✔
136
  /* we need to skip the option code and length, which are not included */
137
  BOOST_REQUIRE_EQUAL(ecsOption->second.values.size(), 1U);
34✔
138
  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));
34✔
139
}
34✔
140

141
static void validateResponse(const PacketBuffer& packet, bool hasEdns, uint8_t additionalCount = 0)
142
{
22✔
143
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
144
  MOADNSParser mdp(false, reinterpret_cast<const char*>(packet.data()), packet.size());
22✔
145

146
  BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
22✔
147

148
  BOOST_CHECK_EQUAL(mdp.d_header.qr, 1U);
22✔
149
  BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
22✔
150
  BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1U);
22✔
151
  BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
22✔
152
  BOOST_CHECK_EQUAL(mdp.d_header.arcount, (hasEdns ? 1U : 0U) + additionalCount);
22✔
153
}
22✔
154

155
BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
156
{
2✔
157
  bool ednsAdded = false;
2✔
158
  bool ecsAdded = false;
2✔
159
  ComboAddress remote("192.0.2.1");
2✔
160
  DNSName name("www.powerdns.com.");
2✔
161
  string newECSOption;
2✔
162
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
163

164
  PacketBuffer query;
2✔
165
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
166
  packetWriter.getHeader()->rd = 1;
2✔
167
  uint16_t len = query.size();
2✔
168

169
  /* large enough packet */
170
  PacketBuffer packet = query;
2✔
171

172
  unsigned int consumed = 0;
2✔
173
  uint16_t qtype = 0;
2✔
174
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
175
  DNSName qname(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
176
  BOOST_CHECK_EQUAL(qname, name);
2✔
177
  BOOST_CHECK(qtype == QType::A);
2✔
178

179
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
180
  BOOST_CHECK(packet.size() > query.size());
2✔
181
  BOOST_CHECK_EQUAL(ednsAdded, true);
2✔
182
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
183
  validateQuery(packet);
2✔
184
  validateECS(packet, remote);
2✔
185
  PacketBuffer queryWithEDNS = packet;
2✔
186

187
  /* not large enough packet */
188
  packet = query;
2✔
189

190
  ednsAdded = false;
2✔
191
  ecsAdded = false;
2✔
192
  consumed = 0;
2✔
193
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
194
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
195
  BOOST_CHECK_EQUAL(qname, name);
2✔
196
  BOOST_CHECK(qtype == QType::A);
2✔
197

198
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
199
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
200
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
201
  packet.resize(query.size());
2✔
202
  validateQuery(packet, false);
2✔
203

204
  /* packet with trailing data (overriding it) */
205
  packet = query;
2✔
206
  ednsAdded = false;
2✔
207
  ecsAdded = false;
2✔
208
  consumed = 0;
2✔
209
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
210
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
211
  BOOST_CHECK_EQUAL(qname, name);
2✔
212
  BOOST_CHECK(qtype == QType::A);
2✔
213
  /* add trailing data */
214
  const size_t trailingDataSize = 10;
2✔
215
  /* Making sure we have enough room to allow for fake trailing data */
216
  packet.resize(packet.size() + trailingDataSize);
2✔
217
  for (size_t idx = 0; idx < trailingDataSize; idx++) {
22✔
218
    packet[len + idx] = 'A';
20✔
219
  }
20✔
220

221
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
222
  BOOST_REQUIRE_EQUAL(packet.size(), queryWithEDNS.size());
2✔
223
  BOOST_CHECK_EQUAL(memcmp(queryWithEDNS.data(), packet.data(), queryWithEDNS.size()), 0);
2✔
224
  BOOST_CHECK_EQUAL(ednsAdded, true);
2✔
225
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
226
  validateQuery(packet);
2✔
227
}
2✔
228

229
BOOST_AUTO_TEST_CASE(addECSWithoutEDNSButWithAnswer)
230
{
2✔
231
  /* this might happen for NOTIFY queries where, according to rfc1996:
232
     "If ANCOUNT>0, then the answer section represents an
233
     unsecure hint at the new RRset for this <QNAME,QCLASS,QTYPE>".
234
  */
235
  bool ednsAdded = false;
2✔
236
  bool ecsAdded = false;
2✔
237
  ComboAddress remote("192.0.2.1");
2✔
238
  DNSName name("www.powerdns.com.");
2✔
239
  string newECSOption;
2✔
240
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
241

242
  PacketBuffer query;
2✔
243
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
244
  packetWriter.getHeader()->rd = 1;
2✔
245
  packetWriter.startRecord(name, QType::A, 60, QClass::IN, DNSResourceRecord::ANSWER, false);
2✔
246
  packetWriter.xfrIP(remote.sin4.sin_addr.s_addr);
2✔
247
  packetWriter.commit();
2✔
248
  uint16_t len = query.size();
2✔
249

250
  /* large enough packet */
251
  PacketBuffer packet = query;
2✔
252

253
  unsigned int consumed = 0;
2✔
254
  uint16_t qtype = 0;
2✔
255
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
256
  DNSName qname(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
257
  BOOST_CHECK_EQUAL(qname, name);
2✔
258
  BOOST_CHECK(qtype == QType::A);
2✔
259

260
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
261
  BOOST_CHECK(packet.size() > query.size());
2✔
262
  BOOST_CHECK_EQUAL(ednsAdded, true);
2✔
263
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
264
  validateQuery(packet, true, 0, 1);
2✔
265
  validateECS(packet, remote);
2✔
266
  PacketBuffer queryWithEDNS = packet;
2✔
267

268
  /* not large enough packet */
269
  packet = query;
2✔
270

271
  ednsAdded = false;
2✔
272
  ecsAdded = false;
2✔
273
  consumed = 0;
2✔
274
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
275
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
276
  BOOST_CHECK_EQUAL(qname, name);
2✔
277
  BOOST_CHECK(qtype == QType::A);
2✔
278

279
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
280
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
281
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
282
  packet.resize(query.size());
2✔
283
  validateQuery(packet, false, 0, 1);
2✔
284

285
  /* packet with trailing data (overriding it) */
286
  packet = query;
2✔
287
  ednsAdded = false;
2✔
288
  ecsAdded = false;
2✔
289
  consumed = 0;
2✔
290
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
291
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
292
  BOOST_CHECK_EQUAL(qname, name);
2✔
293
  BOOST_CHECK(qtype == QType::A);
2✔
294
  /* add trailing data */
295
  const size_t trailingDataSize = 10;
2✔
296
  /* Making sure we have enough room to allow for fake trailing data */
297
  packet.resize(packet.size() + trailingDataSize);
2✔
298
  for (size_t idx = 0; idx < trailingDataSize; idx++) {
22✔
299
    packet[len + idx] = 'A';
20✔
300
  }
20✔
301

302
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
303
  BOOST_REQUIRE_EQUAL(packet.size(), queryWithEDNS.size());
2✔
304
  BOOST_CHECK_EQUAL(memcmp(queryWithEDNS.data(), packet.data(), queryWithEDNS.size()), 0);
2✔
305
  BOOST_CHECK_EQUAL(ednsAdded, true);
2✔
306
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
307
  validateQuery(packet, true, 0, 1);
2✔
308
}
2✔
309

310
BOOST_AUTO_TEST_CASE(addECSWithoutEDNSAlreadyParsed)
311
{
2✔
312
  InternalQueryState ids;
2✔
313
  ids.origRemote = ComboAddress("192.0.2.1");
2✔
314
  ids.protocol = dnsdist::Protocol::DoUDP;
2✔
315
  bool ednsAdded = false;
2✔
316
  bool ecsAdded = false;
2✔
317
  DNSName name("www.powerdns.com.");
2✔
318

319
  PacketBuffer query;
2✔
320
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
321
  packetWriter.getHeader()->rd = 1;
2✔
322

323
  auto packet = query;
2✔
324
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
325
  ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
2✔
326
  BOOST_CHECK_EQUAL(ids.qname, name);
2✔
327
  BOOST_CHECK(ids.qtype == QType::A);
2✔
328
  BOOST_CHECK(ids.qclass == QClass::IN);
2✔
329

330
  DNSQuestion dnsQuestion(ids, packet);
2✔
331
  /* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
332
  BOOST_CHECK(!parseEDNSOptions(dnsQuestion));
2✔
333

334
  /* And now we add our own ECS */
335
  BOOST_CHECK(handleEDNSClientSubnet(dnsQuestion, ednsAdded, ecsAdded));
2✔
336
  BOOST_CHECK_GT(packet.size(), query.size());
2✔
337
  BOOST_CHECK_EQUAL(ednsAdded, true);
2✔
338
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
339
  validateQuery(packet);
2✔
340
  validateECS(packet, ids.origRemote);
2✔
341

342
  /* trailing data */
343
  packet = query;
2✔
344
  packet.resize(2048);
2✔
345

346
  ednsAdded = false;
2✔
347
  ecsAdded = false;
2✔
348
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
349
  ids.qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
2✔
350
  BOOST_CHECK_EQUAL(ids.qname, name);
2✔
351
  BOOST_CHECK(ids.qtype == QType::A);
2✔
352
  BOOST_CHECK(ids.qclass == QClass::IN);
2✔
353
  DNSQuestion dnsQuestion2(ids, packet);
2✔
354

355
  BOOST_CHECK(handleEDNSClientSubnet(dnsQuestion2, ednsAdded, ecsAdded));
2✔
356
  BOOST_CHECK_GT(packet.size(), query.size());
2✔
357
  BOOST_CHECK_LT(packet.size(), 2048U);
2✔
358
  BOOST_CHECK_EQUAL(ednsAdded, true);
2✔
359
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
360
  validateQuery(packet);
2✔
361
  validateECS(packet, ids.origRemote);
2✔
362
}
2✔
363

364
BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS)
365
{
2✔
366
  bool ednsAdded = false;
2✔
367
  bool ecsAdded = false;
2✔
368
  ComboAddress remote;
2✔
369
  DNSName name("www.powerdns.com.");
2✔
370
  string newECSOption;
2✔
371
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
372

373
  PacketBuffer query;
2✔
374
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
375
  packetWriter.getHeader()->rd = 1;
2✔
376
  packetWriter.addOpt(512, 0, 0);
2✔
377
  packetWriter.commit();
2✔
378

379
  auto packet = query;
2✔
380

381
  unsigned int consumed = 0;
2✔
382
  uint16_t qtype = 0;
2✔
383
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
384
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
385
  BOOST_CHECK_EQUAL(qname, name);
2✔
386
  BOOST_CHECK(qtype == QType::A);
2✔
387

388
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
389
  BOOST_CHECK(packet.size() > query.size());
2✔
390
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
391
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
392
  validateQuery(packet);
2✔
393
  validateECS(packet, remote);
2✔
394

395
  /* not large enough packet */
396
  consumed = 0;
2✔
397
  ednsAdded = false;
2✔
398
  ecsAdded = false;
2✔
399
  packet = query;
2✔
400
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
401
  qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
402
  BOOST_CHECK_EQUAL(qname, name);
2✔
403
  BOOST_CHECK(qtype == QType::A);
2✔
404

405
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, false, newECSOption));
2✔
406
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
407
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
408
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
409
  validateQuery(packet);
2✔
410
}
2✔
411

412
BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECSAlreadyParsed)
413
{
2✔
414
  InternalQueryState ids;
2✔
415
  ids.origRemote = ComboAddress("2001:DB8::1");
2✔
416
  ids.protocol = dnsdist::Protocol::DoUDP;
2✔
417
  bool ednsAdded = false;
2✔
418
  bool ecsAdded = false;
2✔
419
  DNSName name("www.powerdns.com.");
2✔
420

421
  PacketBuffer query;
2✔
422
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
423
  packetWriter.getHeader()->rd = 1;
2✔
424
  packetWriter.addOpt(512, 0, 0);
2✔
425
  packetWriter.commit();
2✔
426

427
  auto packet = query;
2✔
428
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
429
  ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
2✔
430
  BOOST_CHECK_EQUAL(ids.qname, name);
2✔
431
  BOOST_CHECK(ids.qtype == QType::A);
2✔
432
  BOOST_CHECK(ids.qclass == QClass::IN);
2✔
433

434
  DNSQuestion dnsQuestion(ids, packet);
2✔
435
  /* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
436
  BOOST_CHECK(parseEDNSOptions(dnsQuestion));
2✔
437

438
  /* And now we add our own ECS */
439
  BOOST_CHECK(handleEDNSClientSubnet(dnsQuestion, ednsAdded, ecsAdded));
2✔
440
  BOOST_CHECK_GT(packet.size(), query.size());
2✔
441
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
442
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
443
  validateQuery(packet);
2✔
444
  validateECS(packet, ids.origRemote);
2✔
445

446
  /* trailing data */
447
  packet = query;
2✔
448
  packet.resize(2048);
2✔
449
  ednsAdded = false;
2✔
450
  ecsAdded = false;
2✔
451
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
452
  ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
2✔
453
  BOOST_CHECK_EQUAL(ids.qname, name);
2✔
454
  BOOST_CHECK(ids.qtype == QType::A);
2✔
455
  BOOST_CHECK(ids.qclass == QClass::IN);
2✔
456
  DNSQuestion dnsQuestion2(ids, packet);
2✔
457

458
  BOOST_CHECK(handleEDNSClientSubnet(dnsQuestion2, ednsAdded, ecsAdded));
2✔
459
  BOOST_CHECK_GT(packet.size(), query.size());
2✔
460
  BOOST_CHECK_LT(packet.size(), 2048U);
2✔
461
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
462
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
463
  validateQuery(packet);
2✔
464
  validateECS(packet, ids.origRemote);
2✔
465
}
2✔
466

467
BOOST_AUTO_TEST_CASE(replaceECSWithSameSize)
468
{
2✔
469
  bool ednsAdded = false;
2✔
470
  bool ecsAdded = false;
2✔
471
  ComboAddress remote("192.168.1.25");
2✔
472
  DNSName name("www.powerdns.com.");
2✔
473
  ComboAddress origRemote("127.0.0.1");
2✔
474
  string newECSOption;
2✔
475
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
476

477
  PacketBuffer query;
2✔
478
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
479
  packetWriter.getHeader()->rd = 1;
2✔
480
  EDNSSubnetOpts ecsOpts;
2✔
481
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
482
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
483
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
484
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
485
  packetWriter.addOpt(512, 0, 0, opts);
2✔
486
  packetWriter.commit();
2✔
487

488
  /* large enough packet */
489
  auto packet = query;
2✔
490

491
  unsigned int consumed = 0;
2✔
492
  uint16_t qtype = 0;
2✔
493
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
494
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
495
  BOOST_CHECK_EQUAL(qname, name);
2✔
496
  BOOST_CHECK(qtype == QType::A);
2✔
497

498
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
499
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
500
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
501
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
502
  validateQuery(packet);
2✔
503
  validateECS(packet, remote);
2✔
504
}
2✔
505

506
BOOST_AUTO_TEST_CASE(replaceECSWithSameSizeAlreadyParsed)
507
{
2✔
508
  bool ednsAdded = false;
2✔
509
  bool ecsAdded = false;
2✔
510
  ComboAddress remote("192.168.1.25");
2✔
511
  ComboAddress origRemote("127.0.0.1");
2✔
512
  InternalQueryState ids;
2✔
513
  ids.origRemote = remote;
2✔
514
  ids.protocol = dnsdist::Protocol::DoUDP;
2✔
515
  ids.qname = DNSName("www.powerdns.com.");
2✔
516

517
  PacketBuffer query;
2✔
518
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, ids.qname, QType::A, QClass::IN, 0);
2✔
519
  packetWriter.getHeader()->rd = 1;
2✔
520
  EDNSSubnetOpts ecsOpts;
2✔
521
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
522
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
523
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
524
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
525
  packetWriter.addOpt(512, 0, 0, opts);
2✔
526
  packetWriter.commit();
2✔
527

528
  auto packet = query;
2✔
529

530
  unsigned int consumed = 0;
2✔
531
  uint16_t qtype = 0;
2✔
532
  uint16_t qclass = 0;
2✔
533
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
534
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
2✔
535
  BOOST_CHECK_EQUAL(qname, ids.qname);
2✔
536
  BOOST_CHECK(qtype == QType::A);
2✔
537
  BOOST_CHECK(qclass == QClass::IN);
2✔
538

539
  DNSQuestion dnsQuestion(ids, packet);
2✔
540
  dnsQuestion.ecsOverride = true;
2✔
541

542
  /* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
543
  BOOST_CHECK(parseEDNSOptions(dnsQuestion));
2✔
544

545
  /* And now we add our own ECS */
546
  BOOST_CHECK(handleEDNSClientSubnet(dnsQuestion, ednsAdded, ecsAdded));
2✔
547
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
548
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
549
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
550
  validateQuery(packet);
2✔
551
  validateECS(packet, remote);
2✔
552
}
2✔
553

554
BOOST_AUTO_TEST_CASE(replaceECSWithSmaller)
555
{
2✔
556
  bool ednsAdded = false;
2✔
557
  bool ecsAdded = false;
2✔
558
  ComboAddress remote("192.168.1.25");
2✔
559
  DNSName name("www.powerdns.com.");
2✔
560
  ComboAddress origRemote("127.0.0.1");
2✔
561
  string newECSOption;
2✔
562
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
563

564
  PacketBuffer query;
2✔
565
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
566
  packetWriter.getHeader()->rd = 1;
2✔
567
  EDNSSubnetOpts ecsOpts;
2✔
568
  ecsOpts.source = Netmask(origRemote, 32);
2✔
569
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
570
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
571
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
572
  packetWriter.addOpt(512, 0, 0, opts);
2✔
573
  packetWriter.commit();
2✔
574

575
  auto packet = query;
2✔
576

577
  unsigned int consumed = 0;
2✔
578
  uint16_t qtype = 0;
2✔
579
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
580
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
581
  BOOST_CHECK_EQUAL(qname, name);
2✔
582
  BOOST_CHECK(qtype == QType::A);
2✔
583

584
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
585
  BOOST_CHECK(packet.size() < query.size());
2✔
586
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
587
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
588
  validateQuery(packet);
2✔
589
  validateECS(packet, remote);
2✔
590
}
2✔
591

592
BOOST_AUTO_TEST_CASE(replaceECSWithLarger)
593
{
2✔
594
  bool ednsAdded = false;
2✔
595
  bool ecsAdded = false;
2✔
596
  ComboAddress remote("192.168.1.25");
2✔
597
  DNSName name("www.powerdns.com.");
2✔
598
  ComboAddress origRemote("127.0.0.1");
2✔
599
  string newECSOption;
2✔
600
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
601

602
  PacketBuffer query;
2✔
603
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
604
  packetWriter.getHeader()->rd = 1;
2✔
605
  EDNSSubnetOpts ecsOpts;
2✔
606
  // smaller (less specific so less bits) option
607
  static_assert(8 < ECSSourcePrefixV4, "The ECS scope should be smaller");
2✔
608
  ecsOpts.source = Netmask(origRemote, 8);
2✔
609
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
610
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
611
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
612
  packetWriter.addOpt(512, 0, 0, opts);
2✔
613
  packetWriter.commit();
2✔
614

615
  /* large enough packet */
616
  auto packet = query;
2✔
617

618
  unsigned int consumed = 0;
2✔
619
  uint16_t qtype = 0;
2✔
620
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
621
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
622
  BOOST_CHECK_EQUAL(qname, name);
2✔
623
  BOOST_CHECK(qtype == QType::A);
2✔
624

625
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
626
  BOOST_CHECK(packet.size() > query.size());
2✔
627
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
628
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
629
  validateQuery(packet);
2✔
630
  validateECS(packet, remote);
2✔
631

632
  /* not large enough packet */
633
  packet = query;
2✔
634

635
  ednsAdded = false;
2✔
636
  ecsAdded = false;
2✔
637
  consumed = 0;
2✔
638
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
639
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
640
  BOOST_CHECK_EQUAL(qname, name);
2✔
641
  BOOST_CHECK(qtype == QType::A);
2✔
642

643
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
644
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
645
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
646
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
647
  validateQuery(packet);
2✔
648
}
2✔
649

650
BOOST_AUTO_TEST_CASE(replaceECSFollowedByTSIG)
651
{
2✔
652
  bool ednsAdded = false;
2✔
653
  bool ecsAdded = false;
2✔
654
  ComboAddress remote("192.168.1.25");
2✔
655
  DNSName name("www.powerdns.com.");
2✔
656
  ComboAddress origRemote("127.0.0.1");
2✔
657
  string newECSOption;
2✔
658
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
659

660
  PacketBuffer query;
2✔
661
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
662
  packetWriter.getHeader()->rd = 1;
2✔
663
  EDNSSubnetOpts ecsOpts;
2✔
664
  ecsOpts.source = Netmask(origRemote, 8);
2✔
665
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
666
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
667
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
668
  packetWriter.addOpt(512, 0, 0, opts);
2✔
669
  packetWriter.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
2✔
670
  packetWriter.commit();
2✔
671

672
  /* large enough packet */
673
  auto packet = query;
2✔
674

675
  unsigned int consumed = 0;
2✔
676
  uint16_t qtype = 0;
2✔
677
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
678
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
679
  BOOST_CHECK_EQUAL(qname, name);
2✔
680
  BOOST_CHECK(qtype == QType::A);
2✔
681

682
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
683
  BOOST_CHECK(packet.size() > query.size());
2✔
684
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
685
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
686
  validateQuery(packet, true, 1);
2✔
687
  validateECS(packet, remote);
2✔
688

689
  /* not large enough packet */
690
  packet = query;
2✔
691

692
  ednsAdded = false;
2✔
693
  ecsAdded = false;
2✔
694
  consumed = 0;
2✔
695
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
696
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
697
  BOOST_CHECK_EQUAL(qname, name);
2✔
698
  BOOST_CHECK(qtype == QType::A);
2✔
699

700
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
701
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
702
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
703
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
704
  validateQuery(packet, true, 1);
2✔
705
}
2✔
706

707
BOOST_AUTO_TEST_CASE(replaceECSAfterAN)
708
{
2✔
709
  bool ednsAdded = false;
2✔
710
  bool ecsAdded = false;
2✔
711
  ComboAddress remote("192.168.1.25");
2✔
712
  DNSName name("www.powerdns.com.");
2✔
713
  ComboAddress origRemote("127.0.0.1");
2✔
714
  string newECSOption;
2✔
715
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
716

717
  PacketBuffer query;
2✔
718
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
719
  packetWriter.getHeader()->rd = 1;
2✔
720
  packetWriter.startRecord(DNSName("powerdns.com."), QType::A, 0, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
721
  packetWriter.commit();
2✔
722
  EDNSSubnetOpts ecsOpts;
2✔
723
  ecsOpts.source = Netmask(origRemote, 8);
2✔
724
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
725
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
726
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
727
  packetWriter.addOpt(512, 0, 0, opts);
2✔
728
  packetWriter.commit();
2✔
729

730
  /* large enough packet */
731
  auto packet = query;
2✔
732

733
  unsigned int consumed = 0;
2✔
734
  uint16_t qtype = 0;
2✔
735
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
736
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
737
  BOOST_CHECK_EQUAL(qname, name);
2✔
738
  BOOST_CHECK(qtype == QType::A);
2✔
739

740
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
741
  BOOST_CHECK(packet.size() > query.size());
2✔
742
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
743
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
744
  validateQuery(packet, true, 0, 1, 0);
2✔
745
  validateECS(packet, remote);
2✔
746

747
  /* not large enough packet */
748
  packet = query;
2✔
749

750
  ednsAdded = false;
2✔
751
  ecsAdded = false;
2✔
752
  consumed = 0;
2✔
753
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
754
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
755
  BOOST_CHECK_EQUAL(qname, name);
2✔
756
  BOOST_CHECK(qtype == QType::A);
2✔
757

758
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
759
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
760
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
761
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
762
  validateQuery(packet, true, 0, 1, 0);
2✔
763
}
2✔
764

765
BOOST_AUTO_TEST_CASE(replaceECSAfterAuth)
766
{
2✔
767
  bool ednsAdded = false;
2✔
768
  bool ecsAdded = false;
2✔
769
  ComboAddress remote("192.168.1.25");
2✔
770
  DNSName name("www.powerdns.com.");
2✔
771
  ComboAddress origRemote("127.0.0.1");
2✔
772
  string newECSOption;
2✔
773
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
774

775
  PacketBuffer query;
2✔
776
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
777
  packetWriter.getHeader()->rd = 1;
2✔
778
  packetWriter.startRecord(DNSName("powerdns.com."), QType::A, 0, QClass::IN, DNSResourceRecord::AUTHORITY, true);
2✔
779
  packetWriter.commit();
2✔
780
  EDNSSubnetOpts ecsOpts;
2✔
781
  ecsOpts.source = Netmask(origRemote, 8);
2✔
782
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
783
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
784
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
785
  packetWriter.addOpt(512, 0, 0, opts);
2✔
786
  packetWriter.commit();
2✔
787

788
  /* large enough packet */
789
  auto packet = query;
2✔
790

791
  unsigned int consumed = 0;
2✔
792
  uint16_t qtype = 0;
2✔
793
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
794
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
795
  BOOST_CHECK_EQUAL(qname, name);
2✔
796
  BOOST_CHECK(qtype == QType::A);
2✔
797

798
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
799
  BOOST_CHECK(packet.size() > query.size());
2✔
800
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
801
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
802
  validateQuery(packet, true, 0, 0, 1);
2✔
803
  validateECS(packet, remote);
2✔
804

805
  /* not large enough packet */
806
  packet = query;
2✔
807

808
  ednsAdded = false;
2✔
809
  ecsAdded = false;
2✔
810
  consumed = 0;
2✔
811
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
812
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
813
  BOOST_CHECK_EQUAL(qname, name);
2✔
814
  BOOST_CHECK(qtype == QType::A);
2✔
815

816
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
817
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
818
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
819
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
820
  validateQuery(packet, true, 0, 0, 1);
2✔
821
}
2✔
822

823
BOOST_AUTO_TEST_CASE(replaceECSBetweenTwoRecords)
824
{
2✔
825
  bool ednsAdded = false;
2✔
826
  bool ecsAdded = false;
2✔
827
  ComboAddress remote("192.168.1.25");
2✔
828
  DNSName name("www.powerdns.com.");
2✔
829
  ComboAddress origRemote("127.0.0.1");
2✔
830
  string newECSOption;
2✔
831
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
832

833
  PacketBuffer query;
2✔
834
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
835
  packetWriter.getHeader()->rd = 1;
2✔
836
  EDNSSubnetOpts ecsOpts;
2✔
837
  ecsOpts.source = Netmask(origRemote, 8);
2✔
838
  string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
2✔
839
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
840
  opts.emplace_back(EDNSOptionCode::ECS, origECSOption);
2✔
841
  packetWriter.startRecord(DNSName("additional"), QType::A, 0, QClass::IN, DNSResourceRecord::ADDITIONAL, false);
2✔
842
  packetWriter.xfr32BitInt(0x01020304);
2✔
843
  packetWriter.addOpt(512, 0, 0, opts);
2✔
844
  packetWriter.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
2✔
845
  packetWriter.commit();
2✔
846

847
  /* large enough packet */
848
  auto packet = query;
2✔
849

850
  unsigned int consumed = 0;
2✔
851
  uint16_t qtype = 0;
2✔
852
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
853
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
854
  BOOST_CHECK_EQUAL(qname, name);
2✔
855
  BOOST_CHECK(qtype == QType::A);
2✔
856

857
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
858
  BOOST_CHECK(packet.size() > query.size());
2✔
859
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
860
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
861
  validateQuery(packet, true, 2);
2✔
862
  validateECS(packet, remote);
2✔
863

864
  /* not large enough packet */
865
  packet = query;
2✔
866

867
  ednsAdded = false;
2✔
868
  ecsAdded = false;
2✔
869
  consumed = 0;
2✔
870
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
871
  qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
872
  BOOST_CHECK_EQUAL(qname, name);
2✔
873
  BOOST_CHECK(qtype == QType::A);
2✔
874

875
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
876
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
877
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
878
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
879
  validateQuery(packet, true, 2);
2✔
880
}
2✔
881

882
BOOST_AUTO_TEST_CASE(insertECSInEDNSBetweenTwoRecords)
883
{
2✔
884
  bool ednsAdded = false;
2✔
885
  bool ecsAdded = false;
2✔
886
  ComboAddress remote("192.168.1.25");
2✔
887
  DNSName name("www.powerdns.com.");
2✔
888
  ComboAddress origRemote("127.0.0.1");
2✔
889
  string newECSOption;
2✔
890
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
891

892
  PacketBuffer query;
2✔
893
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
894
  packetWriter.getHeader()->rd = 1;
2✔
895
  packetWriter.startRecord(DNSName("additional"), QType::A, 0, QClass::IN, DNSResourceRecord::ADDITIONAL, false);
2✔
896
  packetWriter.xfr32BitInt(0x01020304);
2✔
897
  packetWriter.addOpt(512, 0, 0);
2✔
898
  packetWriter.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
2✔
899
  packetWriter.commit();
2✔
900

901
  /* large enough packet */
902
  auto packet = query;
2✔
903

904
  unsigned int consumed = 0;
2✔
905
  uint16_t qtype = 0;
2✔
906
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
907
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
908
  BOOST_CHECK_EQUAL(qname, name);
2✔
909
  BOOST_CHECK(qtype == QType::A);
2✔
910

911
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
912
  BOOST_CHECK(packet.size() > query.size());
2✔
913
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
914
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
915
  validateQuery(packet, true, 2);
2✔
916
  validateECS(packet, remote);
2✔
917

918
  /* not large enough packet */
919
  packet = query;
2✔
920

921
  ednsAdded = false;
2✔
922
  ecsAdded = false;
2✔
923
  consumed = 0;
2✔
924
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
925
  qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
926
  BOOST_CHECK_EQUAL(qname, name);
2✔
927
  BOOST_CHECK(qtype == QType::A);
2✔
928

929
  BOOST_CHECK(!handleEDNSClientSubnet(query, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
930
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
931
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
932
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
933
  validateQuery(packet, true, 2);
2✔
934
}
2✔
935

936
BOOST_AUTO_TEST_CASE(insertECSAfterTSIG)
937
{
2✔
938
  bool ednsAdded = false;
2✔
939
  bool ecsAdded = false;
2✔
940
  ComboAddress remote("192.168.1.25");
2✔
941
  DNSName name("www.powerdns.com.");
2✔
942
  ComboAddress origRemote("127.0.0.1");
2✔
943
  string newECSOption;
2✔
944
  generateECSOption(remote, newECSOption, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
2!
945

946
  PacketBuffer query;
2✔
947
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
948
  packetWriter.getHeader()->rd = 1;
2✔
949
  packetWriter.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
2✔
950
  packetWriter.commit();
2✔
951

952
  /* large enough packet */
953
  auto packet = query;
2✔
954

955
  unsigned int consumed = 0;
2✔
956
  uint16_t qtype = 0;
2✔
957
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
958
  DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
959
  BOOST_CHECK_EQUAL(qname, name);
2✔
960
  BOOST_CHECK(qtype == QType::A);
2✔
961

962
  BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
963
  BOOST_CHECK(packet.size() > query.size());
2✔
964
  BOOST_CHECK_EQUAL(ednsAdded, true);
2✔
965
  BOOST_CHECK_EQUAL(ecsAdded, true);
2✔
966
  /* the MOADNSParser does not allow anything after a TSIG */
967
  BOOST_CHECK_THROW(validateQuery(packet, true, 1), MOADNSException);
2✔
968
  validateECS(packet, remote);
2✔
969

970
  /* not large enough packet */
971
  packet = query;
2✔
972

973
  ednsAdded = false;
2✔
974
  ecsAdded = false;
2✔
975
  consumed = 0;
2✔
976
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
977
  qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
978
  BOOST_CHECK_EQUAL(qname, name);
2✔
979
  BOOST_CHECK(qtype == QType::A);
2✔
980

981
  BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
2✔
982
  BOOST_CHECK_EQUAL(packet.size(), query.size());
2✔
983
  BOOST_CHECK_EQUAL(ednsAdded, false);
2✔
984
  BOOST_CHECK_EQUAL(ecsAdded, false);
2✔
985
  validateQuery(packet, true);
2✔
986
}
2✔
987

988
BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst)
989
{
2✔
990
  DNSName name("www.powerdns.com.");
2✔
991

992
  PacketBuffer response;
2✔
993
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
994
  packetWriter.getHeader()->qr = 1;
2✔
995
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
996
  packetWriter.xfr32BitInt(0x01020304);
2✔
997
  packetWriter.addOpt(512, 0, 0);
2✔
998
  packetWriter.commit();
2✔
999
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1000
  packetWriter.xfr32BitInt(0x01020304);
2✔
1001
  packetWriter.commit();
2✔
1002

1003
  PacketBuffer newResponse;
2✔
1004
  int res = rewriteResponseWithoutEDNS(response, newResponse);
2✔
1005
  BOOST_CHECK_EQUAL(res, 0);
2✔
1006

1007
  unsigned int consumed = 0;
2✔
1008
  uint16_t qtype = 0;
2✔
1009
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1010
  DNSName qname(reinterpret_cast<const char*>(newResponse.data()), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1011
  BOOST_CHECK_EQUAL(qname, name);
2✔
1012
  BOOST_CHECK(qtype == QType::A);
2✔
1013
  size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
2✔
1014
  BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
2✔
1015

1016
  validateResponse(newResponse, false, 1);
2✔
1017
}
2✔
1018

1019
BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary)
1020
{
2✔
1021
  DNSName name("www.powerdns.com.");
2✔
1022

1023
  PacketBuffer response;
2✔
1024
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1025
  packetWriter.getHeader()->qr = 1;
2✔
1026
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1027
  packetWriter.xfr32BitInt(0x01020304);
2✔
1028
  packetWriter.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1029
  packetWriter.xfr32BitInt(0x01020304);
2✔
1030
  packetWriter.commit();
2✔
1031
  packetWriter.addOpt(512, 0, 0);
2✔
1032
  packetWriter.commit();
2✔
1033
  packetWriter.startRecord(DNSName("yetanother.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1034
  packetWriter.xfr32BitInt(0x01020304);
2✔
1035
  packetWriter.commit();
2✔
1036

1037
  PacketBuffer newResponse;
2✔
1038
  int res = rewriteResponseWithoutEDNS(response, newResponse);
2✔
1039
  BOOST_CHECK_EQUAL(res, 0);
2✔
1040

1041
  unsigned int consumed = 0;
2✔
1042
  uint16_t qtype = 0;
2✔
1043
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1044
  DNSName qname(reinterpret_cast<const char*>(newResponse.data()), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1045
  BOOST_CHECK_EQUAL(qname, name);
2✔
1046
  BOOST_CHECK(qtype == QType::A);
2✔
1047
  size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
2✔
1048
  BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
2✔
1049

1050
  validateResponse(newResponse, false, 2);
2✔
1051
}
2✔
1052

1053
BOOST_AUTO_TEST_CASE(removeEDNSWhenLast)
1054
{
2✔
1055
  DNSName name("www.powerdns.com.");
2✔
1056

1057
  PacketBuffer response;
2✔
1058
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1059
  packetWriter.getHeader()->qr = 1;
2✔
1060
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1061
  packetWriter.xfr32BitInt(0x01020304);
2✔
1062
  packetWriter.commit();
2✔
1063
  packetWriter.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1064
  packetWriter.xfr32BitInt(0x01020304);
2✔
1065
  packetWriter.commit();
2✔
1066
  packetWriter.addOpt(512, 0, 0);
2✔
1067
  packetWriter.commit();
2✔
1068

1069
  PacketBuffer newResponse;
2✔
1070
  int res = rewriteResponseWithoutEDNS(response, newResponse);
2✔
1071

1072
  BOOST_CHECK_EQUAL(res, 0);
2✔
1073

1074
  unsigned int consumed = 0;
2✔
1075
  uint16_t qtype = 0;
2✔
1076
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1077
  DNSName qname(reinterpret_cast<const char*>(newResponse.data()), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1078
  BOOST_CHECK_EQUAL(qname, name);
2✔
1079
  BOOST_CHECK(qtype == QType::A);
2✔
1080
  size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
2✔
1081
  BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
2✔
1082

1083
  validateResponse(newResponse, false, 1);
2✔
1084
}
2✔
1085

1086
BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption)
1087
{
2✔
1088
  DNSName name("www.powerdns.com.");
2✔
1089
  ComboAddress origRemote("127.0.0.1");
2✔
1090

1091
  PacketBuffer response;
2✔
1092
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1093
  packetWriter.getHeader()->qr = 1;
2✔
1094
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1095
  packetWriter.xfr32BitInt(0x01020304);
2✔
1096

1097
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1098
  packetWriter.xfr32BitInt(0x01020304);
2✔
1099
  packetWriter.commit();
2✔
1100

1101
  EDNSSubnetOpts ecsOpts;
2✔
1102
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
1103
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1104
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1105
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1106
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1107
  packetWriter.commit();
2✔
1108

1109
  uint16_t optStart = 0;
2✔
1110
  size_t optLen = 0;
2✔
1111
  bool last = false;
2✔
1112

1113
  int res = locateEDNSOptRR(response, &optStart, &optLen, &last);
2✔
1114
  BOOST_CHECK_EQUAL(res, 0);
2✔
1115
  BOOST_CHECK_EQUAL(last, true);
2✔
1116

1117
  size_t responseLen = response.size();
2✔
1118
  size_t existingOptLen = optLen;
2✔
1119
  BOOST_CHECK(existingOptLen < responseLen);
2✔
1120
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1121
  res = removeEDNSOptionFromOPT(reinterpret_cast<char*>(&response.at(optStart)), &optLen, EDNSOptionCode::ECS);
2✔
1122
  BOOST_CHECK_EQUAL(res, 0);
2✔
1123
  BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
2✔
1124
  responseLen -= (existingOptLen - optLen);
2✔
1125

1126
  unsigned int consumed = 0;
2✔
1127
  uint16_t qtype = 0;
2✔
1128
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1129
  DNSName qname(reinterpret_cast<const char*>(response.data()), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1130
  BOOST_CHECK_EQUAL(qname, name);
2✔
1131
  BOOST_CHECK(qtype == QType::A);
2✔
1132

1133
  validateResponse(response, true, 1);
2✔
1134
}
2✔
1135

1136
BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption)
1137
{
2✔
1138
  DNSName name("www.powerdns.com.");
2✔
1139
  ComboAddress origRemote("127.0.0.1");
2✔
1140

1141
  PacketBuffer response;
2✔
1142
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1143
  packetWriter.getHeader()->qr = 1;
2✔
1144
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1145
  packetWriter.xfr32BitInt(0x01020304);
2✔
1146

1147
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1148
  packetWriter.xfr32BitInt(0x01020304);
2✔
1149
  packetWriter.commit();
2✔
1150

1151
  EDNSSubnetOpts ecsOpts;
2✔
1152
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV6);
2✔
1153
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1154
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1155
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
1156
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1157
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1158
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
1159
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1160
  packetWriter.commit();
2✔
1161

1162
  uint16_t optStart = 0;
2✔
1163
  size_t optLen = 0;
2✔
1164
  bool last = false;
2✔
1165

1166
  int res = locateEDNSOptRR(response, &optStart, &optLen, &last);
2✔
1167
  BOOST_CHECK_EQUAL(res, 0);
2✔
1168
  BOOST_CHECK_EQUAL(last, true);
2✔
1169

1170
  size_t responseLen = response.size();
2✔
1171
  size_t existingOptLen = optLen;
2✔
1172
  BOOST_CHECK(existingOptLen < responseLen);
2✔
1173
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1174
  res = removeEDNSOptionFromOPT(reinterpret_cast<char*>(&response.at(optStart)), &optLen, EDNSOptionCode::ECS);
2✔
1175
  BOOST_CHECK_EQUAL(res, 0);
2✔
1176
  BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
2✔
1177
  responseLen -= (existingOptLen - optLen);
2✔
1178

1179
  unsigned int consumed = 0;
2✔
1180
  uint16_t qtype = 0;
2✔
1181
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1182
  DNSName qname(reinterpret_cast<const char*>(response.data()), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1183
  BOOST_CHECK_EQUAL(qname, name);
2✔
1184
  BOOST_CHECK(qtype == QType::A);
2✔
1185

1186
  validateResponse(response, true, 1);
2✔
1187
}
2✔
1188

1189
BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption)
1190
{
2✔
1191
  DNSName name("www.powerdns.com.");
2✔
1192
  ComboAddress origRemote("127.0.0.1");
2✔
1193

1194
  PacketBuffer response;
2✔
1195
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1196
  packetWriter.getHeader()->qr = 1;
2✔
1197
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1198
  packetWriter.xfr32BitInt(0x01020304);
2✔
1199

1200
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1201
  packetWriter.xfr32BitInt(0x01020304);
2✔
1202
  packetWriter.commit();
2✔
1203

1204
  EDNSSubnetOpts ecsOpts;
2✔
1205
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
1206
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1207

1208
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1209
  string cookiesOptionStr1 = cookiesOpt.makeOptString();
2✔
1210
  string cookiesOptionStr2 = cookiesOpt.makeOptString();
2✔
1211

1212
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1213
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr1);
2✔
1214
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1215
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr2);
2✔
1216
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1217
  packetWriter.commit();
2✔
1218

1219
  uint16_t optStart = 0;
2✔
1220
  size_t optLen = 0;
2✔
1221
  bool last = false;
2✔
1222

1223
  int res = locateEDNSOptRR(response, &optStart, &optLen, &last);
2✔
1224
  BOOST_CHECK_EQUAL(res, 0);
2✔
1225
  BOOST_CHECK_EQUAL(last, true);
2✔
1226

1227
  size_t responseLen = response.size();
2✔
1228
  size_t existingOptLen = optLen;
2✔
1229
  BOOST_CHECK(existingOptLen < responseLen);
2✔
1230
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1231
  res = removeEDNSOptionFromOPT(reinterpret_cast<char*>(&response.at(optStart)), &optLen, EDNSOptionCode::ECS);
2✔
1232
  BOOST_CHECK_EQUAL(res, 0);
2✔
1233
  BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
2✔
1234
  responseLen -= (existingOptLen - optLen);
2✔
1235

1236
  unsigned int consumed = 0;
2✔
1237
  uint16_t qtype = 0;
2✔
1238
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1239
  DNSName qname(reinterpret_cast<const char*>(response.data()), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1240
  BOOST_CHECK_EQUAL(qname, name);
2✔
1241
  BOOST_CHECK(qtype == QType::A);
2✔
1242

1243
  validateResponse(response, true, 1);
2✔
1244
}
2✔
1245

1246
BOOST_AUTO_TEST_CASE(removeECSWhenLastOption)
1247
{
2✔
1248
  DNSName name("www.powerdns.com.");
2✔
1249
  ComboAddress origRemote("127.0.0.1");
2✔
1250

1251
  PacketBuffer response;
2✔
1252
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1253
  packetWriter.getHeader()->qr = 1;
2✔
1254
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1255
  packetWriter.xfr32BitInt(0x01020304);
2✔
1256

1257
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1258
  packetWriter.xfr32BitInt(0x01020304);
2✔
1259
  packetWriter.commit();
2✔
1260

1261
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1262
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
1263
  EDNSSubnetOpts ecsOpts;
2✔
1264
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
1265
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1266
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1267
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
1268
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1269
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1270
  packetWriter.commit();
2✔
1271

1272
  uint16_t optStart = 0;
2✔
1273
  size_t optLen = 0;
2✔
1274
  bool last = false;
2✔
1275

1276
  int res = locateEDNSOptRR(response, &optStart, &optLen, &last);
2✔
1277
  BOOST_CHECK_EQUAL(res, 0);
2✔
1278
  BOOST_CHECK_EQUAL(last, true);
2✔
1279

1280
  size_t responseLen = response.size();
2✔
1281
  size_t existingOptLen = optLen;
2✔
1282
  BOOST_CHECK(existingOptLen < responseLen);
2✔
1283
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1284
  res = removeEDNSOptionFromOPT(reinterpret_cast<char*>(&response.at(optStart)), &optLen, EDNSOptionCode::ECS);
2✔
1285
  BOOST_CHECK_EQUAL(res, 0);
2✔
1286
  BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4));
2✔
1287
  responseLen -= (existingOptLen - optLen);
2✔
1288

1289
  unsigned int consumed = 0;
2✔
1290
  uint16_t qtype = 0;
2✔
1291
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1292
  DNSName qname(reinterpret_cast<const char*>(response.data()), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1293
  BOOST_CHECK_EQUAL(qname, name);
2✔
1294
  BOOST_CHECK(qtype == QType::A);
2✔
1295

1296
  validateResponse(response, true, 1);
2✔
1297
}
2✔
1298

1299
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption)
1300
{
2✔
1301
  DNSName name("www.powerdns.com.");
2✔
1302
  ComboAddress origRemote("127.0.0.1");
2✔
1303

1304
  PacketBuffer response;
2✔
1305
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1306
  packetWriter.getHeader()->qr = 1;
2✔
1307
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1308
  packetWriter.xfr32BitInt(0x01020304);
2✔
1309

1310
  EDNSSubnetOpts ecsOpts;
2✔
1311
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
1312
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1313
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1314
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1315
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1316
  packetWriter.commit();
2✔
1317

1318
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1319
  packetWriter.xfr32BitInt(0x01020304);
2✔
1320
  packetWriter.commit();
2✔
1321

1322
  PacketBuffer newResponse;
2✔
1323
  int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
2✔
1324
  BOOST_CHECK_EQUAL(res, 0);
2✔
1325

1326
  BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
2✔
1327

1328
  unsigned int consumed = 0;
2✔
1329
  uint16_t qtype = 0;
2✔
1330
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1331
  DNSName qname(reinterpret_cast<const char*>(newResponse.data()), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1332
  BOOST_CHECK_EQUAL(qname, name);
2✔
1333
  BOOST_CHECK(qtype == QType::A);
2✔
1334

1335
  validateResponse(newResponse, true, 1);
2✔
1336
}
2✔
1337

1338
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption)
1339
{
2✔
1340
  DNSName name("www.powerdns.com.");
2✔
1341
  ComboAddress origRemote("127.0.0.1");
2✔
1342

1343
  PacketBuffer response;
2✔
1344
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1345
  packetWriter.getHeader()->qr = 1;
2✔
1346
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1347
  packetWriter.xfr32BitInt(0x01020304);
2✔
1348

1349
  EDNSSubnetOpts ecsOpts;
2✔
1350
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
1351
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1352
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1353
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
1354
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1355
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1356
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
1357
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1358
  packetWriter.commit();
2✔
1359

1360
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1361
  packetWriter.xfr32BitInt(0x01020304);
2✔
1362
  packetWriter.commit();
2✔
1363

1364
  PacketBuffer newResponse;
2✔
1365
  int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
2✔
1366
  BOOST_CHECK_EQUAL(res, 0);
2✔
1367

1368
  BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
2✔
1369

1370
  unsigned int consumed = 0;
2✔
1371
  uint16_t qtype = 0;
2✔
1372
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1373
  DNSName qname(reinterpret_cast<const char*>(newResponse.data()), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1374
  BOOST_CHECK_EQUAL(qname, name);
2✔
1375
  BOOST_CHECK(qtype == QType::A);
2✔
1376

1377
  validateResponse(newResponse, true, 1);
2✔
1378
}
2✔
1379

1380
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption)
1381
{
2✔
1382
  DNSName name("www.powerdns.com.");
2✔
1383
  ComboAddress origRemote("127.0.0.1");
2✔
1384

1385
  PacketBuffer response;
2✔
1386
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1387
  packetWriter.getHeader()->qr = 1;
2✔
1388
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1389
  packetWriter.xfr32BitInt(0x01020304);
2✔
1390

1391
  EDNSSubnetOpts ecsOpts;
2✔
1392
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
1393
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1394
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1395
  string cookiesOptionStr1 = cookiesOpt.makeOptString();
2✔
1396
  string cookiesOptionStr2 = cookiesOpt.makeOptString();
2✔
1397
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1398
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr1);
2✔
1399
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1400
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr2);
2✔
1401
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1402
  packetWriter.commit();
2✔
1403

1404
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1405
  packetWriter.xfr32BitInt(0x01020304);
2✔
1406
  packetWriter.commit();
2✔
1407

1408
  PacketBuffer newResponse;
2✔
1409
  int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
2✔
1410
  BOOST_CHECK_EQUAL(res, 0);
2✔
1411

1412
  BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
2✔
1413

1414
  unsigned int consumed = 0;
2✔
1415
  uint16_t qtype = 0;
2✔
1416
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1417
  DNSName qname(reinterpret_cast<const char*>(newResponse.data()), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1418
  BOOST_CHECK_EQUAL(qname, name);
2✔
1419
  BOOST_CHECK(qtype == QType::A);
2✔
1420

1421
  validateResponse(newResponse, true, 1);
2✔
1422
}
2✔
1423

1424
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption)
1425
{
2✔
1426
  DNSName name("www.powerdns.com.");
2✔
1427
  ComboAddress origRemote("127.0.0.1");
2✔
1428

1429
  PacketBuffer response;
2✔
1430
  GenericDNSPacketWriter<PacketBuffer> packetWriter(response, name, QType::A, QClass::IN, 0);
2✔
1431
  packetWriter.getHeader()->qr = 1;
2✔
1432
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true);
2✔
1433
  packetWriter.xfr32BitInt(0x01020304);
2✔
1434

1435
  EDNSSubnetOpts ecsOpts;
2✔
1436
  ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4);
2✔
1437
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1438
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1439
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
1440
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1441
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
1442
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1443
  packetWriter.addOpt(512, 0, 0, opts);
2✔
1444
  packetWriter.commit();
2✔
1445

1446
  packetWriter.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true);
2✔
1447
  packetWriter.xfr32BitInt(0x01020304);
2✔
1448
  packetWriter.commit();
2✔
1449

1450
  PacketBuffer newResponse;
2✔
1451
  int res = rewriteResponseWithoutEDNSOption(response, EDNSOptionCode::ECS, newResponse);
2✔
1452
  BOOST_CHECK_EQUAL(res, 0);
2✔
1453

1454
  BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4));
2✔
1455

1456
  unsigned int consumed = 0;
2✔
1457
  uint16_t qtype = 0;
2✔
1458
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1459
  DNSName qname(reinterpret_cast<const char*>(newResponse.data()), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
2✔
1460
  BOOST_CHECK_EQUAL(qname, name);
2✔
1461
  BOOST_CHECK(qtype == QType::A);
2✔
1462

1463
  validateResponse(newResponse, true, 1);
2✔
1464
}
2✔
1465

1466
static DNSQuestion turnIntoResponse(InternalQueryState& ids, PacketBuffer& query, bool resizeBuffer = true)
1467
{
12✔
1468
  if (resizeBuffer) {
12✔
1469
    query.resize(4096);
10✔
1470
  }
10✔
1471

1472
  auto dnsQuestion = DNSQuestion(ids, query);
12✔
1473

1474
  BOOST_CHECK(addEDNSToQueryTurnedResponse(dnsQuestion));
12✔
1475

1476
  return dnsQuestion;
12✔
1477
}
12✔
1478

1479
static int getZ(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, PacketBuffer& query)
1480
{
12✔
1481
  InternalQueryState ids;
12✔
1482
  ids.protocol = dnsdist::Protocol::DoUDP;
12✔
1483
  ids.qname = qname;
12✔
1484
  ids.qtype = qtype;
12✔
1485
  ids.qclass = qclass;
12✔
1486
  ids.origDest = ComboAddress("127.0.0.1");
12✔
1487
  ids.origRemote = ComboAddress("127.0.0.1");
12✔
1488
  ids.queryRealTime.start();
12✔
1489

1490
  auto dnsQuestion = DNSQuestion(ids, query);
12✔
1491

1492
  return dnsdist::getEDNSZ(dnsQuestion);
12✔
1493
}
12✔
1494

1495
BOOST_AUTO_TEST_CASE(test_getEDNSZ)
1496
{
2✔
1497
  uint16_t zValue = 0;
2✔
1498
  uint16_t udpPayloadSize = 0;
2✔
1499
  DNSName qname("www.powerdns.com.");
2✔
1500
  uint16_t qtype = QType::A;
2✔
1501
  uint16_t qclass = QClass::IN;
2✔
1502
  EDNSSubnetOpts ecsOpts;
2✔
1503
  ecsOpts.source = Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4);
2✔
1504
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1505
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1506
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
1507
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1508
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
1509
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1510

1511
  {
2✔
1512
    /* no EDNS */
1513
    PacketBuffer query;
2✔
1514
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1515
    packetWriter.commit();
2✔
1516

1517
    BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
2✔
1518
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1519
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query.data()), query.size(), &udpPayloadSize, &zValue), false);
2✔
1520
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1521
    BOOST_CHECK_EQUAL(udpPayloadSize, 0);
2✔
1522
  }
2✔
1523

1524
  {
2✔
1525
    /* truncated EDNS */
1526
    PacketBuffer query;
2✔
1527
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1528
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
2✔
1529
    packetWriter.commit();
2✔
1530

1531
    query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
2✔
1532
    BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
2✔
1533
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1534
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query.data()), query.size(), &udpPayloadSize, &zValue), false);
2✔
1535
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1536
    BOOST_CHECK_EQUAL(udpPayloadSize, 0);
2✔
1537
  }
2✔
1538

1539
  {
2✔
1540
    /* valid EDNS, no options, DO not set */
1541
    PacketBuffer query;
2✔
1542
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1543
    packetWriter.addOpt(512, 0, 0);
2✔
1544
    packetWriter.commit();
2✔
1545

1546
    BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
2✔
1547
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1548
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query.data()), query.size(), &udpPayloadSize, &zValue), true);
2✔
1549
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1550
    BOOST_CHECK_EQUAL(udpPayloadSize, 512);
2✔
1551
  }
2✔
1552

1553
  {
2✔
1554
    /* valid EDNS, no options, DO set */
1555
    PacketBuffer query;
2✔
1556
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1557
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
2✔
1558
    packetWriter.commit();
2✔
1559

1560
    BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), EDNS_HEADER_FLAG_DO);
2✔
1561
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1562
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query.data()), query.size(), &udpPayloadSize, &zValue), true);
2✔
1563
    BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
2✔
1564
    BOOST_CHECK_EQUAL(udpPayloadSize, 512);
2✔
1565
  }
2✔
1566

1567
  {
2✔
1568
    /* valid EDNS, options, DO not set */
1569
    PacketBuffer query;
2✔
1570
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1571
    packetWriter.addOpt(512, 0, 0, opts);
2✔
1572
    packetWriter.commit();
2✔
1573

1574
    BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), 0);
2✔
1575
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1576
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query.data()), query.size(), &udpPayloadSize, &zValue), true);
2✔
1577
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1578
    BOOST_CHECK_EQUAL(udpPayloadSize, 512);
2✔
1579
  }
2✔
1580

1581
  {
2✔
1582
    /* valid EDNS, options, DO set */
1583
    PacketBuffer query;
2✔
1584
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1585
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts);
2✔
1586
    packetWriter.commit();
2✔
1587

1588
    BOOST_CHECK_EQUAL(getZ(qname, qtype, qclass, query), EDNS_HEADER_FLAG_DO);
2✔
1589
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1590
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(query.data()), query.size(), &udpPayloadSize, &zValue), true);
2✔
1591
    BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
2✔
1592
    BOOST_CHECK_EQUAL(udpPayloadSize, 512);
2✔
1593
  }
2✔
1594
}
2✔
1595

1596
BOOST_AUTO_TEST_CASE(test_getEDNSVersion)
1597
{
2✔
1598
  const DNSName qname("www.powerdns.com.");
2✔
1599
  const uint16_t qtype = QType::A;
2✔
1600
  const uint16_t qclass = QClass::IN;
2✔
1601
  const GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1602

1603
  auto getVersion = [&qname](PacketBuffer& query) {
8✔
1604
    InternalQueryState ids;
8✔
1605
    ids.protocol = dnsdist::Protocol::DoUDP;
8✔
1606
    ids.qname = qname;
8✔
1607
    ids.qtype = qtype;
8✔
1608
    ids.qclass = qclass;
8✔
1609
    ids.origDest = ComboAddress("127.0.0.1");
8✔
1610
    ids.origRemote = ComboAddress("127.0.0.1");
8✔
1611
    ids.queryRealTime.start();
8✔
1612

1613
    auto dnsQuestion = DNSQuestion(ids, query);
8✔
1614

1615
    return dnsdist::getEDNSVersion(dnsQuestion);
8✔
1616
  };
8✔
1617

1618
  {
2✔
1619
    /* no EDNS */
1620
    PacketBuffer query;
2✔
1621
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1622
    packetWriter.commit();
2✔
1623

1624
    BOOST_CHECK(getVersion(query) == std::nullopt);
2✔
1625
  }
2✔
1626

1627
  {
2✔
1628
    /* truncated EDNS */
1629
    PacketBuffer query;
2✔
1630
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1631
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
2✔
1632
    packetWriter.commit();
2✔
1633

1634
    query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* TTL */ 2));
2✔
1635
    BOOST_CHECK(getVersion(query) == std::nullopt);
2✔
1636
  }
2✔
1637

1638
  {
2✔
1639
    /* valid EDNS, no options */
1640
    PacketBuffer query;
2✔
1641
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1642
    packetWriter.addOpt(512, 0, 0);
2✔
1643
    packetWriter.commit();
2✔
1644

1645
    BOOST_CHECK_EQUAL(*getVersion(query), 0U);
2✔
1646
  }
2✔
1647

1648
  {
2✔
1649
    /* EDNS version 255 */
1650
    PacketBuffer query;
2✔
1651
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1652
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts, 255U);
2✔
1653
    packetWriter.commit();
2✔
1654

1655
    BOOST_CHECK_EQUAL(*getVersion(query), 255U);
2✔
1656
  }
2✔
1657
}
2✔
1658

1659
BOOST_AUTO_TEST_CASE(test_getEDNSExtendedRCode)
1660
{
2✔
1661
  const DNSName qname("www.powerdns.com.");
2✔
1662
  const uint16_t qtype = QType::A;
2✔
1663
  const uint16_t qclass = QClass::IN;
2✔
1664

1665
  auto getExtendedRCode = [&qname](PacketBuffer& query) {
8✔
1666
    InternalQueryState ids;
8✔
1667
    ids.protocol = dnsdist::Protocol::DoUDP;
8✔
1668
    ids.qname = qname;
8✔
1669
    ids.qtype = qtype;
8✔
1670
    ids.qclass = qclass;
8✔
1671
    ids.origDest = ComboAddress("127.0.0.1");
8✔
1672
    ids.origRemote = ComboAddress("127.0.0.1");
8✔
1673
    ids.queryRealTime.start();
8✔
1674

1675
    auto dnsQuestion = DNSQuestion(ids, query);
8✔
1676

1677
    return dnsdist::getEDNSExtendedRCode(dnsQuestion);
8✔
1678
  };
8✔
1679

1680
  {
2✔
1681
    /* no EDNS */
1682
    PacketBuffer query;
2✔
1683
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1684
    packetWriter.commit();
2✔
1685

1686
    BOOST_CHECK(getExtendedRCode(query) == std::nullopt);
2✔
1687
  }
2✔
1688

1689
  {
2✔
1690
    /* truncated EDNS */
1691
    PacketBuffer query;
2✔
1692
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1693
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
2✔
1694
    packetWriter.commit();
2✔
1695

1696
    query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* TTL */ 2));
2✔
1697
    BOOST_CHECK(getExtendedRCode(query) == std::nullopt);
2✔
1698
  }
2✔
1699

1700
  {
2✔
1701
    /* valid EDNS, no options */
1702
    PacketBuffer query;
2✔
1703
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1704
    packetWriter.addOpt(512, 0, 0);
2✔
1705
    packetWriter.commit();
2✔
1706

1707
    BOOST_CHECK_EQUAL(*getExtendedRCode(query), 0U);
2✔
1708
  }
2✔
1709

1710
  {
2✔
1711
    /* EDNS extended RCode 4095 (15 for the normal RCode, 255 for the EDNS part) */
1712
    PacketBuffer query;
2✔
1713
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1714
    packetWriter.addOpt(512, 4095U, EDNS_HEADER_FLAG_DO);
2✔
1715
    packetWriter.commit();
2✔
1716

1717
    BOOST_CHECK_EQUAL(*getExtendedRCode(query), 255U);
2✔
1718
  }
2✔
1719
}
2✔
1720

1721
BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
1722
{
2✔
1723
  InternalQueryState ids;
2✔
1724
  ids.qname = DNSName("www.powerdns.com.");
2✔
1725
  ids.qtype = QType::A;
2✔
1726
  ids.qclass = QClass::IN;
2✔
1727
  ids.origDest = ComboAddress("127.0.0.1");
2✔
1728
  ids.origRemote = ComboAddress("127.0.0.1");
2✔
1729
  ids.queryRealTime.start();
2✔
1730
  uint16_t zValue = 0;
2✔
1731
  uint16_t udpPayloadSize = 0;
2✔
1732
  EDNSSubnetOpts ecsOpts;
2✔
1733
  ecsOpts.source = Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4);
2✔
1734
  string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1735
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1736
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
1737
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1738
  opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
1739
  opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr);
2✔
1740

1741
  {
2✔
1742
    /* no EDNS */
1743
    PacketBuffer query;
2✔
1744
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, ids.qname, ids.qtype, ids.qclass, 0);
2✔
1745
    packetWriter.getHeader()->qr = 1;
2✔
1746
    packetWriter.getHeader()->rcode = RCode::NXDomain;
2✔
1747
    packetWriter.commit();
2✔
1748

1749
    auto dnsQuestion = turnIntoResponse(ids, query);
2✔
1750
    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
2✔
1751
    BOOST_CHECK(dnsdist::getEDNSVersion(dnsQuestion) == std::nullopt);
2✔
1752
    BOOST_CHECK(dnsdist::getEDNSExtendedRCode(dnsQuestion) == std::nullopt);
2✔
1753
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1754
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), false);
2✔
1755
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1756
    BOOST_CHECK_EQUAL(udpPayloadSize, 0);
2✔
1757
  }
2✔
1758

1759
  {
2✔
1760
    /* truncated EDNS */
1761
    PacketBuffer query;
2✔
1762
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, ids.qname, ids.qtype, ids.qclass, 0);
2✔
1763
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
2✔
1764
    packetWriter.commit();
2✔
1765

1766
    query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
2✔
1767
    auto dnsQuestion = turnIntoResponse(ids, query, false);
2✔
1768
    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
2✔
1769
    BOOST_CHECK(dnsdist::getEDNSVersion(dnsQuestion) == std::nullopt);
2✔
1770
    BOOST_CHECK(dnsdist::getEDNSExtendedRCode(dnsQuestion) == std::nullopt);
2✔
1771
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1772
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), false);
2✔
1773
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1774
    BOOST_CHECK_EQUAL(udpPayloadSize, 0);
2✔
1775
  }
2✔
1776

1777
  {
2✔
1778
    /* valid EDNS, no options, DO not set */
1779
    PacketBuffer query;
2✔
1780
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, ids.qname, ids.qtype, ids.qclass, 0);
2✔
1781
    packetWriter.addOpt(512, 0, 0);
2✔
1782
    packetWriter.commit();
2✔
1783

1784
    auto dnsQuestion = turnIntoResponse(ids, query);
2✔
1785
    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
2✔
1786
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
2✔
1787
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
2✔
1788
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1789
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
2✔
1790
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1791
    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
2✔
1792
  }
2✔
1793

1794
  {
2✔
1795
    /* valid EDNS, no options, DO set */
1796
    PacketBuffer query;
2✔
1797
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, ids.qname, ids.qtype, ids.qclass, 0);
2✔
1798
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
2✔
1799
    packetWriter.commit();
2✔
1800

1801
    auto dnsQuestion = turnIntoResponse(ids, query);
2✔
1802
    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
2✔
1803
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
2✔
1804
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
2✔
1805
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1806
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
2✔
1807
    BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
2✔
1808
    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
2✔
1809
  }
2✔
1810

1811
  {
2✔
1812
    /* valid EDNS, options, DO not set */
1813
    PacketBuffer query;
2✔
1814
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, ids.qname, ids.qtype, ids.qclass, 0);
2✔
1815
    packetWriter.addOpt(512, 0, 0, opts);
2✔
1816
    packetWriter.commit();
2✔
1817

1818
    auto dnsQuestion = turnIntoResponse(ids, query);
2✔
1819
    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
2✔
1820
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
2✔
1821
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
2✔
1822
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1823
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
2✔
1824
    BOOST_CHECK_EQUAL(zValue, 0);
2✔
1825
    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
2✔
1826
  }
2✔
1827

1828
  {
2✔
1829
    /* valid EDNS, options, DO set */
1830
    PacketBuffer query;
2✔
1831
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, ids.qname, ids.qtype, ids.qclass, 0);
2✔
1832
    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts);
2✔
1833
    packetWriter.commit();
2✔
1834

1835
    auto dnsQuestion = turnIntoResponse(ids, query);
2✔
1836
    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
2✔
1837
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
2✔
1838
    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
2✔
1839
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1840
    BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
2✔
1841
    BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
2✔
1842
    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
2✔
1843
  }
2✔
1844
}
2✔
1845

1846
BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart)
1847
{
2✔
1848
  const DNSName qname("www.powerdns.com.");
2✔
1849
  const uint16_t qtype = QType::A;
2✔
1850
  const uint16_t qclass = QClass::IN;
2✔
1851
  EDNSSubnetOpts ecsOpts;
2✔
1852
  ecsOpts.source = Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4);
2✔
1853
  const string ecsOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1854
  GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
1855
  opts.emplace_back(EDNSOptionCode::ECS, ecsOptionStr);
2✔
1856
  const ComboAddress rem("127.0.0.1");
2✔
1857
  uint16_t optRDPosition = 0;
2✔
1858
  size_t remaining = 0;
2✔
1859

1860
  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;
2✔
1861

1862
  {
2✔
1863
    /* no EDNS */
1864
    PacketBuffer query;
2✔
1865
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1866
    packetWriter.getHeader()->qr = 1;
2✔
1867
    packetWriter.getHeader()->rcode = RCode::NXDomain;
2✔
1868
    packetWriter.commit();
2✔
1869

1870
    int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
2✔
1871

1872
    BOOST_CHECK_EQUAL(res, ENOENT);
2✔
1873

1874
    /* truncated packet (should not matter) */
1875
    query.resize(query.size() - 1);
2✔
1876
    res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
2✔
1877

1878
    BOOST_CHECK_EQUAL(res, ENOENT);
2✔
1879
  }
2✔
1880

1881
  {
2✔
1882
    /* valid EDNS, no options */
1883
    PacketBuffer query;
2✔
1884
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1885
    packetWriter.addOpt(512, 0, 0);
2✔
1886
    packetWriter.commit();
2✔
1887

1888
    int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
2✔
1889

1890
    BOOST_CHECK_EQUAL(res, 0);
2✔
1891
    BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
2✔
1892
    BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
2✔
1893

1894
    /* truncated packet */
1895
    query.resize(query.size() - 1);
2✔
1896

1897
    res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
2✔
1898
    BOOST_CHECK_EQUAL(res, ENOENT);
2✔
1899
  }
2✔
1900

1901
  {
2✔
1902
    /* valid EDNS, options */
1903
    PacketBuffer query;
2✔
1904
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1905
    packetWriter.addOpt(512, 0, 0, opts);
2✔
1906
    packetWriter.commit();
2✔
1907

1908
    int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
2✔
1909

1910
    BOOST_CHECK_EQUAL(res, 0);
2✔
1911
    BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
2✔
1912
    BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
2✔
1913

1914
    /* truncated options (should not matter for this test) */
1915
    query.resize(query.size() - 1);
2✔
1916
    res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
2✔
1917
    BOOST_CHECK_EQUAL(res, 0);
2✔
1918
    BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
2✔
1919
    BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
2✔
1920
  }
2✔
1921
}
2✔
1922

1923
BOOST_AUTO_TEST_CASE(test_isEDNSOptionInOpt)
1924
{
2✔
1925

1926
  auto locateEDNSOption = [](const PacketBuffer& query, uint16_t code, size_t* optContentStart, uint16_t* optContentLen) {
24✔
1927
    uint16_t optStart = 0;
24✔
1928
    size_t optLen = 0;
24✔
1929
    bool last = false;
24✔
1930
    int res = locateEDNSOptRR(query, &optStart, &optLen, &last);
24✔
1931
    if (res != 0) {
24✔
1932
      // no EDNS OPT RR
1933
      return false;
4✔
1934
    }
4✔
1935

1936
    if (optLen < optRecordMinimumSize) {
20!
1937
      return false;
×
1938
    }
×
1939

1940
    if (optStart < query.size() && query.at(optStart) != 0) {
20!
1941
      // OPT RR Name != '.'
1942
      return false;
×
1943
    }
×
1944

1945
    return isEDNSOptionInOpt(query, optStart, optLen, code, optContentStart, optContentLen);
20✔
1946
  };
20✔
1947

1948
  const DNSName qname("www.powerdns.com.");
2✔
1949
  const uint16_t qtype = QType::A;
2✔
1950
  const uint16_t qclass = QClass::IN;
2✔
1951
  EDNSSubnetOpts ecsOpts;
2✔
1952
  ecsOpts.source = Netmask(ComboAddress("127.0.0.1"), ECSSourcePrefixV4);
2✔
1953
  const string ecsOptionStr = makeEDNSSubnetOptsString(ecsOpts);
2✔
1954
  const size_t sizeOfECSContent = ecsOptionStr.size();
2✔
1955
  const size_t sizeOfECSOption = /* option code */ 2 + /* option length */ 2 + sizeOfECSContent;
2✔
1956
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
1957
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
1958
  const size_t sizeOfCookieOption = /* option code */ 2 + /* option length */ 2 + cookiesOpt.size();
2✔
1959
  /*
1960
    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
1961
    opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
1962
    opts.emplace_back(EDNSOptionCode::ECS, ecsOptionStr);
1963
    opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
1964
  */
1965
  const ComboAddress rem("127.0.0.1");
2✔
1966
  size_t optContentStart{std::numeric_limits<size_t>::max()};
2✔
1967
  uint16_t optContentLen{0};
2✔
1968

1969
  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;
2✔
1970

1971
  {
2✔
1972
    /* no EDNS */
1973
    PacketBuffer query;
2✔
1974
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1975
    packetWriter.getHeader()->qr = 1;
2✔
1976
    packetWriter.getHeader()->rcode = RCode::NXDomain;
2✔
1977
    packetWriter.commit();
2✔
1978

1979
    bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
2✔
1980
    BOOST_CHECK_EQUAL(found, false);
2✔
1981

1982
    /* truncated packet (should not matter here) */
1983
    query.resize(query.size() - 1);
2✔
1984
    found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
2✔
1985
    BOOST_CHECK_EQUAL(found, false);
2✔
1986
  }
2✔
1987

1988
  {
2✔
1989
    /* valid EDNS, no options */
1990
    PacketBuffer query;
2✔
1991
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
1992
    packetWriter.addOpt(512, 0, 0);
2✔
1993
    packetWriter.commit();
2✔
1994

1995
    bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
2✔
1996
    BOOST_CHECK_EQUAL(found, false);
2✔
1997

1998
    /* truncated packet */
1999
    query.resize(query.size() - 1);
2✔
2000
    BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::out_of_range);
2✔
2001
  }
2✔
2002

2003
  {
2✔
2004
    /* valid EDNS, two cookie options but no ECS */
2005
    PacketBuffer query;
2✔
2006
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
2007
    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
2008
    opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
2009
    opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
2010
    packetWriter.addOpt(512, 0, 0, opts);
2✔
2011
    packetWriter.commit();
2✔
2012

2013
    bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
2✔
2014
    BOOST_CHECK_EQUAL(found, false);
2✔
2015

2016
    /* truncated packet */
2017
    query.resize(query.size() - 1);
2✔
2018
    BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::range_error);
2✔
2019
  }
2✔
2020

2021
  {
2✔
2022
    /* valid EDNS, two ECS */
2023
    PacketBuffer query;
2✔
2024
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
2025
    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
2026
    opts.emplace_back(EDNSOptionCode::ECS, ecsOptionStr);
2✔
2027
    opts.emplace_back(EDNSOptionCode::ECS, ecsOptionStr);
2✔
2028
    packetWriter.addOpt(512, 0, 0, opts);
2✔
2029
    packetWriter.commit();
2✔
2030

2031
    bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
2✔
2032
    BOOST_CHECK_EQUAL(found, true);
2✔
2033
    if (found) {
2!
2034
      BOOST_CHECK_EQUAL(optContentStart, optRDExpectedOffset + sizeof(uint16_t) /* RD len */ + /* option code */ 2 + /* option length */ 2);
2✔
2035
      BOOST_CHECK_EQUAL(optContentLen, sizeOfECSContent);
2✔
2036
    }
2✔
2037

2038
    /* truncated packet */
2039
    query.resize(query.size() - 1);
2✔
2040
    BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::range_error);
2✔
2041
  }
2✔
2042

2043
  {
2✔
2044
    /* valid EDNS, one ECS between two cookies */
2045
    PacketBuffer query;
2✔
2046
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
2047
    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
2048
    opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
2049
    opts.emplace_back(EDNSOptionCode::ECS, ecsOptionStr);
2✔
2050
    opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr);
2✔
2051
    packetWriter.addOpt(512, 0, 0, opts);
2✔
2052
    packetWriter.commit();
2✔
2053

2054
    bool found = locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen);
2✔
2055
    BOOST_CHECK_EQUAL(found, true);
2✔
2056
    if (found) {
2!
2057
      BOOST_CHECK_EQUAL(optContentStart, optRDExpectedOffset + sizeof(uint16_t) /* RD len */ + sizeOfCookieOption + /* option code */ 2 + /* option length */ 2);
2✔
2058
      BOOST_CHECK_EQUAL(optContentLen, sizeOfECSContent);
2✔
2059
    }
2✔
2060

2061
    /* truncated packet */
2062
    query.resize(query.size() - 1);
2✔
2063
    BOOST_CHECK_THROW(locateEDNSOption(query, EDNSOptionCode::ECS, &optContentStart, &optContentLen), std::range_error);
2✔
2064
  }
2✔
2065

2066
  {
2✔
2067
    /* valid EDNS, one 65002 after an ECS */
2068
    PacketBuffer query;
2✔
2069
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
2✔
2070
    GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
2✔
2071
    opts.emplace_back(EDNSOptionCode::ECS, ecsOptionStr);
2✔
2072
    opts.emplace_back(65535, cookiesOptionStr);
2✔
2073
    packetWriter.addOpt(512, 0, 0, opts);
2✔
2074
    packetWriter.commit();
2✔
2075

2076
    bool found = locateEDNSOption(query, 65535, &optContentStart, &optContentLen);
2✔
2077
    BOOST_CHECK_EQUAL(found, true);
2✔
2078
    if (found) {
2!
2079
      BOOST_CHECK_EQUAL(optContentStart, optRDExpectedOffset + sizeof(uint16_t) /* RD len */ + sizeOfECSOption + /* option code */ 2 + /* option length */ 2);
2✔
2080
      BOOST_CHECK_EQUAL(optContentLen, cookiesOptionStr.size());
2✔
2081
    }
2✔
2082

2083
    /* truncated packet */
2084
    query.resize(query.size() - 1);
2✔
2085
    BOOST_CHECK_THROW(locateEDNSOption(query, 65002, &optContentStart, &optContentLen), std::range_error);
2✔
2086
  }
2✔
2087
}
2✔
2088

2089
BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
2090
{
2✔
2091
  InternalQueryState ids;
2✔
2092
  ids.origRemote = ComboAddress("192.0.2.1");
2✔
2093
  ids.protocol = dnsdist::Protocol::DoUDP;
2✔
2094

2095
  ComboAddress remote;
2✔
2096
  DNSName name("www.powerdns.com.");
2✔
2097

2098
  PacketBuffer query;
2✔
2099
  PacketBuffer queryWithEDNS;
2✔
2100
  GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
2101
  packetWriter.getHeader()->rd = 1;
2✔
2102
  GenericDNSPacketWriter<PacketBuffer> packetWriterEDNS(queryWithEDNS, name, QType::A, QClass::IN, 0);
2✔
2103
  packetWriterEDNS.getHeader()->rd = 1;
2✔
2104
  packetWriterEDNS.addOpt(1232, 0, 0);
2✔
2105
  packetWriterEDNS.commit();
2✔
2106

2107
  /* test NXD */
2108
  {
2✔
2109
    /* no incoming EDNS */
2110
    auto packet = query;
2✔
2111
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2112
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2113
    DNSQuestion dnsQuestion(ids, packet);
2✔
2114

2115
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4, 5, false));
2✔
2116
    BOOST_CHECK(packet.size() > query.size());
2✔
2117
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2118
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2119

2120
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2121
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain);
2✔
2122
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2123
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2124
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
2✔
2125
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
2✔
2126
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
2✔
2127
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2128
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2129
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2130
  }
2✔
2131
  {
2✔
2132
    /* now with incoming EDNS */
2133
    auto packet = queryWithEDNS;
2✔
2134
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2135
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2136
    DNSQuestion dnsQuestion(ids, packet);
2✔
2137

2138
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4, 5, false));
2✔
2139
    BOOST_CHECK(packet.size() > queryWithEDNS.size());
2✔
2140
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2141
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2142

2143
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2144
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain);
2✔
2145
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2146
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2147
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
2✔
2148
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
2✔
2149
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
2✔
2150
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2151
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2152
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2153
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
2✔
2154
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
2✔
2155
  }
2✔
2156

2157
  /* test No Data */
2158
  {
2✔
2159
    /* no incoming EDNS */
2160
    auto packet = query;
2✔
2161
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2162
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2163
    DNSQuestion dnsQuestion(ids, packet);
2✔
2164

2165
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4, 5, false));
2✔
2166
    BOOST_CHECK(packet.size() > query.size());
2✔
2167
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2168
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2169

2170
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2171
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError);
2✔
2172
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2173
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2174
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
2✔
2175
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
2✔
2176
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
2✔
2177
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2178
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2179
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2180
  }
2✔
2181
  {
2✔
2182
    /* now with incoming EDNS */
2183
    auto packet = queryWithEDNS;
2✔
2184
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2185
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2186
    DNSQuestion dnsQuestion(ids, packet);
2✔
2187

2188
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4, 5, false));
2✔
2189
    BOOST_CHECK(packet.size() > queryWithEDNS.size());
2✔
2190
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2191
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2192

2193
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2194
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError);
2✔
2195
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2196
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2197
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
2✔
2198
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
2✔
2199
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
2✔
2200
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2201
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2202
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2203
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
2✔
2204
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
2✔
2205
  }
2✔
2206

2207
  /* SOA in the authority section*/
2208

2209
  /* test NXD */
2210
  {
2✔
2211
    /* no incoming EDNS */
2212
    auto packet = query;
2✔
2213
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2214
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2215
    DNSQuestion dnsQuestion(ids, packet);
2✔
2216

2217
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4,
2✔
2218
                                            5, true));
2✔
2219
    BOOST_CHECK(packet.size() > query.size());
2✔
2220
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2221
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2222

2223
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2224
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain);
2✔
2225
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2226
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2227
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
2✔
2228
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U);
2✔
2229
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
2✔
2230
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2231
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2232
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2233
  }
2✔
2234
  {
2✔
2235
    /* now with incoming EDNS */
2236
    auto packet = queryWithEDNS;
2✔
2237
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2238
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2239
    DNSQuestion dnsQuestion(ids, packet);
2✔
2240

2241
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4, 5, true));
2✔
2242
    BOOST_CHECK(packet.size() > queryWithEDNS.size());
2✔
2243
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2244
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2245

2246
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2247
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain);
2✔
2248
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2249
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2250
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
2✔
2251
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
2✔
2252
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
2✔
2253
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2254
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2255
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2256
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
2✔
2257
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
2✔
2258
  }
2✔
2259

2260
  /* test No Data */
2261
  {
2✔
2262
    /* no incoming EDNS */
2263
    auto packet = query;
2✔
2264
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2265
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2266
    DNSQuestion dnsQuestion(ids, packet);
2✔
2267

2268
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4, 5, true));
2✔
2269
    BOOST_CHECK(packet.size() > query.size());
2✔
2270
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2271
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2272

2273
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2274
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError);
2✔
2275
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2276
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2277
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
2✔
2278
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U);
2✔
2279
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
2✔
2280
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2281
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2282
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2283
  }
2✔
2284
  {
2✔
2285
    /* now with incoming EDNS */
2286
    auto packet = queryWithEDNS;
2✔
2287
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2288
    ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, nullptr);
2✔
2289
    DNSQuestion dnsQuestion(ids, packet);
2✔
2290

2291
    BOOST_CHECK(setNegativeAndAdditionalSOA(dnsQuestion, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4, 5, true));
2✔
2292
    BOOST_CHECK(packet.size() > queryWithEDNS.size());
2✔
2293
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2294
    MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
2✔
2295

2296
    BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
2✔
2297
    BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError);
2✔
2298
    BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2299
    BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2300
    BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
2✔
2301
    BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
2✔
2302
    BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
2✔
2303
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
2✔
2304
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
2✔
2305
    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
2✔
2306
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
2✔
2307
    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
2✔
2308
  }
2✔
2309
}
2✔
2310

2311
BOOST_AUTO_TEST_CASE(getEDNSOptionsWithoutEDNS)
2312
{
2✔
2313
  InternalQueryState ids;
2✔
2314
  ids.origRemote = ComboAddress("192.168.1.25");
2✔
2315
  ids.protocol = dnsdist::Protocol::DoUDP;
2✔
2316

2317
  const DNSName name("www.powerdns.com.");
2✔
2318
  const ComboAddress v4Addr("192.0.2.1");
2✔
2319

2320
  {
2✔
2321
    /* no EDNS and no other additional record */
2322
    PacketBuffer query;
2✔
2323
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
2324
    packetWriter.getHeader()->rd = 1;
2✔
2325
    packetWriter.commit();
2✔
2326

2327
    /* large enough packet */
2328
    auto packet = query;
2✔
2329

2330
    unsigned int consumed = 0;
2✔
2331
    uint16_t qtype = 0;
2✔
2332
    uint16_t qclass = 0;
2✔
2333
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2334
    DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
2✔
2335
    DNSQuestion dnsQuestion(ids, packet);
2✔
2336

2337
    BOOST_CHECK(!parseEDNSOptions(dnsQuestion));
2✔
2338
  }
2✔
2339

2340
  {
2✔
2341
    /* nothing in additional (so no EDNS) but a record in ANSWER */
2342
    PacketBuffer query;
2✔
2343
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
2344
    packetWriter.getHeader()->rd = 1;
2✔
2345
    packetWriter.startRecord(name, QType::A, 60, QClass::IN, DNSResourceRecord::ANSWER);
2✔
2346
    packetWriter.xfrIP(v4Addr.sin4.sin_addr.s_addr);
2✔
2347
    packetWriter.commit();
2✔
2348

2349
    /* large enough packet */
2350
    auto packet = query;
2✔
2351

2352
    unsigned int consumed = 0;
2✔
2353
    uint16_t qtype = 0;
2✔
2354
    uint16_t qclass = 0;
2✔
2355
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2356
    DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
2✔
2357
    DNSQuestion dnsQuestion(ids, packet);
2✔
2358

2359
    BOOST_CHECK(!parseEDNSOptions(dnsQuestion));
2✔
2360
  }
2✔
2361

2362
  {
2✔
2363
    /* nothing in additional (so no EDNS) but a record in AUTHORITY */
2364
    PacketBuffer query;
2✔
2365
    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
2✔
2366
    packetWriter.getHeader()->rd = 1;
2✔
2367
    packetWriter.startRecord(name, QType::A, 60, QClass::IN, DNSResourceRecord::AUTHORITY);
2✔
2368
    packetWriter.xfrIP(v4Addr.sin4.sin_addr.s_addr);
2✔
2369
    packetWriter.commit();
2✔
2370

2371
    /* large enough packet */
2372
    auto packet = query;
2✔
2373

2374
    unsigned int consumed = 0;
2✔
2375
    uint16_t qtype = 0;
2✔
2376
    uint16_t qclass = 0;
2✔
2377
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2378
    DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
2✔
2379
    DNSQuestion dnsQuestion(ids, packet);
2✔
2380

2381
    BOOST_CHECK(!parseEDNSOptions(dnsQuestion));
2✔
2382
  }
2✔
2383
}
2✔
2384

2385
BOOST_AUTO_TEST_CASE(test_setEDNSOption)
2386
{
2✔
2387
  InternalQueryState ids;
2✔
2388
  ids.origRemote = ComboAddress("192.0.2.1:42");
2✔
2389
  ids.origDest = ComboAddress("127.0.0.1:53");
2✔
2390
  ids.protocol = dnsdist::Protocol::DoUDP;
2✔
2391
  ids.qname = DNSName("powerdns.com.");
2✔
2392
  ids.qtype = QType::A;
2✔
2393
  ids.qclass = QClass::IN;
2✔
2394
  ids.queryRealTime.start();
2✔
2395

2396
  timespec expiredTime{};
2✔
2397
  /* the internal QPS limiter does not use the real time */
2398
  gettime(&expiredTime);
2✔
2399

2400
  PacketBuffer packet;
2✔
2401
  GenericDNSPacketWriter<PacketBuffer> packetWriter(packet, ids.qname, ids.qtype, ids.qclass, 0);
2✔
2402
  packetWriter.addOpt(4096, 0, EDNS_HEADER_FLAG_DO);
2✔
2403
  packetWriter.commit();
2✔
2404

2405
  DNSQuestion dnsQuestion(ids, packet);
2✔
2406

2407
  std::string result;
2✔
2408
  EDNSCookiesOpt cookiesOpt("deadbeefdeadbeef");
2✔
2409
  string cookiesOptionStr = cookiesOpt.makeOptString();
2✔
2410

2411
  BOOST_REQUIRE(setEDNSOption(dnsQuestion, EDNSOptionCode::COOKIE, cookiesOptionStr));
2✔
2412

2413
  const auto& data = dnsQuestion.getData();
2✔
2414
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2415
  MOADNSParser mdp(true, reinterpret_cast<const char*>(data.data()), data.size());
2✔
2416

2417
  BOOST_CHECK_EQUAL(mdp.d_qname.toString(), ids.qname.toString());
2✔
2418
  BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
2✔
2419
  BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
2✔
2420
  BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
2✔
2421
  BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
2✔
2422
  BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::OPT));
2✔
2423
  BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, g_rootdnsname);
2✔
2424

2425
  EDNS0Record edns0{};
2✔
2426
  BOOST_REQUIRE(getEDNS0Record(dnsQuestion.getData(), edns0));
2✔
2427
  BOOST_CHECK_EQUAL(edns0.version, 0U);
2✔
2428
  BOOST_CHECK_EQUAL(edns0.extRCode, 0U);
2✔
2429
  BOOST_CHECK_EQUAL(ntohs(edns0.extFlags), EDNS_HEADER_FLAG_DO);
2✔
2430

2431
  BOOST_REQUIRE(parseEDNSOptions(dnsQuestion));
2✔
2432
  BOOST_REQUIRE(dnsQuestion.ednsOptions != nullptr);
2✔
2433
  BOOST_CHECK_EQUAL(dnsQuestion.ednsOptions->size(), 1U);
2✔
2434
  const auto& ecsOption = dnsQuestion.ednsOptions->find(EDNSOptionCode::COOKIE);
2✔
2435
  BOOST_REQUIRE(ecsOption != dnsQuestion.ednsOptions->cend());
2✔
2436

2437
  BOOST_REQUIRE_EQUAL(ecsOption->second.values.size(), 1U);
2✔
2438
  BOOST_CHECK_EQUAL(cookiesOptionStr, std::string(ecsOption->second.values.at(0).content, ecsOption->second.values.at(0).size));
2✔
2439
}
2✔
2440

2441
BOOST_AUTO_TEST_SUITE_END();
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc