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

PowerDNS / pdns / 13012068652

28 Jan 2025 01:59PM UTC coverage: 64.71% (+0.01%) from 64.699%
13012068652

Pull #14724

github

web-flow
Merge b15562560 into db18c3a17
Pull Request #14724: dnsdist: Add meson support

38328 of 90334 branches covered (42.43%)

Branch coverage included in aggregate %.

361 of 513 new or added lines in 35 files covered. (70.37%)

42 existing lines in 13 files now uncovered.

128150 of 166934 relevant lines covered (76.77%)

4540890.91 hits per line

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

75.01
/pdns/dnsdistdist/dnsdist-lua-ffi.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

23
#include "dnsdist-async.hh"
24
#include "dnsdist-cache.hh"
25
#include "dnsdist-dnsparser.hh"
26
#include "dnsdist-dynblocks.hh"
27
#include "dnsdist-ecs.hh"
28
#include "dnsdist-lua-ffi.hh"
29
#include "dnsdist-mac-address.hh"
30
#include "dnsdist-metrics.hh"
31
#include "dnsdist-lua-network.hh"
32
#include "dnsdist-lua.hh"
33
#include "dnsdist-ecs.hh"
34
#include "dnsdist-rings.hh"
35
#include "dnsdist-self-answers.hh"
36
#include "dnsdist-svc.hh"
37
#include "dnsdist-snmp.hh"
38
#include "dolog.hh"
39

40
uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq)
41
{
24✔
42
  return dq->dq->ids.qtype;
24✔
43
}
24✔
44

45
uint16_t dnsdist_ffi_dnsquestion_get_qclass(const dnsdist_ffi_dnsquestion_t* dq)
46
{
10✔
47
  return dq->dq->ids.qclass;
10✔
48
}
10✔
49

50
uint16_t dnsdist_ffi_dnsquestion_get_id(const dnsdist_ffi_dnsquestion_t* dq)
51
{
372✔
52
  if (dq == nullptr) {
372✔
53
    return 0;
2✔
54
  }
2✔
55
  return ntohs(dq->dq->getHeader()->id);
370✔
56
}
372✔
57

58
static void dnsdist_ffi_comboaddress_to_raw(const ComboAddress& ca, const void** addr, size_t* addrSize)
59
{
12✔
60
  if (ca.isIPv4()) {
12✔
61
    *addr = &ca.sin4.sin_addr.s_addr;
6✔
62
    *addrSize = sizeof(ca.sin4.sin_addr.s_addr);
6✔
63
  }
6✔
64
  else {
6✔
65
    *addr = &ca.sin6.sin6_addr.s6_addr;
6✔
66
    *addrSize = sizeof(ca.sin6.sin6_addr.s6_addr);
6✔
67
  }
6✔
68
}
12✔
69

70
void dnsdist_ffi_dnsquestion_get_localaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize)
71
{
4✔
72
  dnsdist_ffi_comboaddress_to_raw(dq->dq->ids.origDest, addr, addrSize);
4✔
73
}
4✔
74

75
bool dnsdist_ffi_dnsquestion_is_remote_v6(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
76
{
4✔
77
  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr) {
4!
78
    return false;
2✔
79
  }
2✔
80

81
  return dnsQuestion->dq->ids.origRemote.isIPv6();
2✔
82
}
4✔
83

84
void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize)
85
{
6✔
86
  dnsdist_ffi_comboaddress_to_raw(dq->dq->ids.origRemote, addr, addrSize);
6✔
87
}
6✔
88

89
size_t dnsdist_ffi_dnsquestion_get_mac_addr(const dnsdist_ffi_dnsquestion_t* dq, void* buffer, size_t bufferSize)
90
{
6✔
91
  if (dq == nullptr) {
6✔
92
    return 0;
2✔
93
  }
2✔
94
  auto ret = dnsdist::MacAddressesCache::get(dq->dq->ids.origRemote, reinterpret_cast<unsigned char*>(buffer), bufferSize);
4✔
95
  if (ret != 0) {
4!
96
    return 0;
4✔
97
  }
4✔
98

99
  return 6;
×
100
}
4✔
101

102
uint64_t dnsdist_ffi_dnsquestion_get_elapsed_us(const dnsdist_ffi_dnsquestion_t* dq)
103
{
4✔
104
  if (dq == nullptr) {
4✔
105
    return 0;
2✔
106
  }
2✔
107

108
  return static_cast<uint64_t>(std::round(dq->dq->ids.queryRealTime.udiff()));
2✔
109
}
4✔
110

111
void dnsdist_ffi_dnsquestion_get_masked_remoteaddr(dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize, uint8_t bits)
112
{
2✔
113
  dq->maskedRemote = Netmask(dq->dq->ids.origRemote, bits).getMaskedNetwork();
2✔
114
  dnsdist_ffi_comboaddress_to_raw(dq->maskedRemote, addr, addrSize);
2✔
115
}
2✔
116

117
uint16_t dnsdist_ffi_dnsquestion_get_local_port(const dnsdist_ffi_dnsquestion_t* dq)
118
{
2✔
119
  return dq->dq->ids.origDest.getPort();
2✔
120
}
2✔
121

122
uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq)
123
{
4✔
124
  return dq->dq->ids.origRemote.getPort();
4✔
125
}
4✔
126

127
void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize)
128
{
206✔
129
  const auto& storage = dq->dq->ids.qname.getStorage();
206✔
130
  *qname = storage.data();
206✔
131
  *qnameSize = storage.size();
206✔
132
}
206✔
133

134
size_t dnsdist_ffi_dnsquestion_get_qname_hash(const dnsdist_ffi_dnsquestion_t* dq, size_t init)
135
{
2✔
136
  return dq->dq->ids.qname.hash(init);
2✔
137
}
2✔
138

139
int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq)
140
{
10✔
141
  return dq->dq->getHeader()->rcode;
10✔
142
}
10✔
143

144
void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
145
{
192✔
146
  return dq->dq->getMutableHeader();
192✔
147
}
192✔
148

149
uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
150
{
196✔
151
  return dq->dq->getData().size();
196✔
152
}
196✔
153

154
size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t* dq)
155
{
4✔
156
  return dq->dq->getData().size();
4✔
157
}
4✔
158

159
bool dnsdist_ffi_dnsquestion_set_size(dnsdist_ffi_dnsquestion_t* dq, size_t newSize)
160
{
4✔
161
  try {
4✔
162
    dq->dq->getMutableData().resize(newSize);
4✔
163
    return true;
4✔
164
  }
4✔
165
  catch (const std::exception& e) {
4✔
166
    return false;
2✔
167
  }
2✔
168
}
4✔
169

170
uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t* dq)
171
{
10✔
172
  return dq->dq->getHeader()->opcode;
10✔
173
}
10✔
174

175
bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t* dq)
176
{
6✔
177
  return dq->dq->overTCP();
6✔
178
}
6✔
179

180
dnsdist_ffi_protocol_type dnsdist_ffi_dnsquestion_get_protocol(const dnsdist_ffi_dnsquestion_t* dq)
181
{
16✔
182
  if (dq != nullptr) {
16✔
183
    auto proto = dq->dq->getProtocol();
14✔
184
    if (proto == dnsdist::Protocol::DoUDP) {
14✔
185
      return dnsdist_ffi_protocol_type_doudp;
4✔
186
    }
4✔
187
    else if (proto == dnsdist::Protocol::DoTCP) {
10✔
188
      return dnsdist_ffi_protocol_type_dotcp;
2✔
189
    }
2✔
190
    else if (proto == dnsdist::Protocol::DNSCryptUDP) {
8✔
191
      return dnsdist_ffi_protocol_type_dnscryptudp;
2✔
192
    }
2✔
193
    else if (proto == dnsdist::Protocol::DNSCryptTCP) {
6✔
194
      return dnsdist_ffi_protocol_type_dnscrypttcp;
2✔
195
    }
2✔
196
    else if (proto == dnsdist::Protocol::DoT) {
4✔
197
      return dnsdist_ffi_protocol_type_dot;
2✔
198
    }
2✔
199
    else if (proto == dnsdist::Protocol::DoH) {
2!
200
      return dnsdist_ffi_protocol_type_doh;
2✔
201
    }
2✔
202
  }
14✔
203
  return dnsdist_ffi_protocol_type_doudp;
2✔
204
}
16✔
205

206
bool dnsdist_ffi_dnsquestion_get_skip_cache(const dnsdist_ffi_dnsquestion_t* dq)
207
{
4✔
208
  return dq->dq->ids.skipCache;
4✔
209
}
4✔
210

211
bool dnsdist_ffi_dnsquestion_get_use_ecs(const dnsdist_ffi_dnsquestion_t* dq)
212
{
4✔
213
  return dq->dq->useECS;
4✔
214
}
4✔
215

216
bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* dq)
217
{
4✔
218
  return dq->dq->ecsOverride;
4✔
219
}
4✔
220

221
uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq)
222
{
4✔
223
  return dq->dq->ecsPrefixLength;
4✔
224
}
4✔
225

226
bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq)
227
{
6✔
228
  return dq->dq->ids.tempFailureTTL != boost::none;
6✔
229
}
6✔
230

231
uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquestion_t* dq)
232
{
4✔
233
  if (dq->dq->ids.tempFailureTTL) {
4✔
234
    return *dq->dq->ids.tempFailureTTL;
2✔
235
  }
2✔
236
  return 0;
2✔
237
}
4✔
238

239
bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
240
{
10✔
241
  return (dnsdist::getEDNSZ(*dnsQuestion->dq) & EDNS_HEADER_FLAG_DO) != 0;
10✔
242
}
10✔
243

244
uint8_t dnsdist_ffi_dnsquestion_get_edns_version(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
245
{
8✔
246
  auto version = dnsdist::getEDNSVersion(*dnsQuestion->dq);
8✔
247
  return version ? *version : 0U;
8!
248
}
8✔
249

250
uint8_t dnsdist_ffi_dnsquestion_get_edns_extended_rcode(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
251
{
8✔
252
  auto rcode = dnsdist::getEDNSExtendedRCode(*dnsQuestion->dq);
8✔
253
  return rcode ? *rcode : 0U;
8!
254
}
8✔
255

256
void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize)
257
{
2✔
258
  *sniSize = dq->dq->sni.size();
2✔
259
  *sni = dq->dq->sni.c_str();
2✔
260
}
2✔
261

262
const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t* dq, const char* label)
263
{
16✔
264
  const char* result = nullptr;
16✔
265

266
  if (dq != nullptr && dq->dq != nullptr && dq->dq->ids.qTag != nullptr) {
16!
267
    const auto it = dq->dq->ids.qTag->find(label);
10✔
268
    if (it != dq->dq->ids.qTag->cend()) {
10!
269
      result = it->second.c_str();
10✔
270
    }
10✔
271
  }
10✔
272

273
  return result;
16✔
274
}
16✔
275

276
size_t dnsdist_ffi_dnsquestion_get_tag_raw(const dnsdist_ffi_dnsquestion_t* dq, const char* label, char* buffer, size_t bufferSize)
277
{
14✔
278
  if (dq == nullptr || dq->dq == nullptr || dq->dq->ids.qTag == nullptr || label == nullptr || buffer == nullptr || bufferSize == 0) {
14!
279
    return 0;
4✔
280
  }
4✔
281

282
  const auto it = dq->dq->ids.qTag->find(label);
10✔
283
  if (it == dq->dq->ids.qTag->cend()) {
10✔
284
    return 0;
2✔
285
  }
2✔
286

287
  if (it->second.size() > bufferSize) {
8✔
288
    return 0;
2✔
289
  }
2✔
290

291
  memcpy(buffer, it->second.c_str(), it->second.size());
6✔
292
  return it->second.size();
6✔
293
}
8✔
294

295
const char* dnsdist_ffi_dnsquestion_get_http_path(dnsdist_ffi_dnsquestion_t* dq)
296
{
4✔
297
  if (!dq->httpPath) {
4!
298
    if (dq->dq->ids.du) {
4✔
299
#if defined(HAVE_DNS_OVER_HTTPS)
2✔
300
      dq->httpPath = dq->dq->ids.du->getHTTPPath();
2✔
301
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
302
    }
2✔
303
    else if (dq->dq->ids.doh3u) {
2!
304
#if defined(HAVE_DNS_OVER_HTTP3)
305
      dq->httpPath = dq->dq->ids.doh3u->getHTTPPath();
306
#endif /* HAVE_DNS_OVER_HTTP3 */
307
    }
×
308
  }
4✔
309
  if (dq->httpPath) {
4✔
310
    return dq->httpPath->c_str();
2✔
311
  }
2✔
312
  return nullptr;
2✔
313
}
4✔
314

315
const char* dnsdist_ffi_dnsquestion_get_http_query_string(dnsdist_ffi_dnsquestion_t* dq)
316
{
4✔
317
  if (!dq->httpQueryString) {
4!
318
    if (dq->dq->ids.du) {
4✔
319
#ifdef HAVE_DNS_OVER_HTTPS
2✔
320
      dq->httpQueryString = dq->dq->ids.du->getHTTPQueryString();
2✔
321
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
322
    }
2✔
323
    else if (dq->dq->ids.doh3u) {
2!
324
#if defined(HAVE_DNS_OVER_HTTP3)
325
      dq->httpQueryString = dq->dq->ids.doh3u->getHTTPQueryString();
326
#endif /* HAVE_DNS_OVER_HTTP3 */
327
    }
×
328
  }
4✔
329
  if (dq->httpQueryString) {
4✔
330
    return dq->httpQueryString->c_str();
2✔
331
  }
2✔
332
  return nullptr;
2✔
333
}
4✔
334

335
const char* dnsdist_ffi_dnsquestion_get_http_host(dnsdist_ffi_dnsquestion_t* dq)
336
{
4✔
337
  if (!dq->httpHost) {
4!
338
    if (dq->dq->ids.du) {
4✔
339
#ifdef HAVE_DNS_OVER_HTTPS
2✔
340
      dq->httpHost = dq->dq->ids.du->getHTTPHost();
2✔
341
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
342
    }
2✔
343
    else if (dq->dq->ids.doh3u) {
2!
344
#if defined(HAVE_DNS_OVER_HTTP3)
345
      dq->httpHost = dq->dq->ids.doh3u->getHTTPHost();
346
#endif /* HAVE_DNS_OVER_HTTP3 */
347
    }
×
348
  }
4✔
349
  if (dq->httpHost) {
4✔
350
    return dq->httpHost->c_str();
2✔
351
  }
2✔
352
  return nullptr;
2✔
353
}
4✔
354

355
const char* dnsdist_ffi_dnsquestion_get_http_scheme(dnsdist_ffi_dnsquestion_t* dq)
356
{
4✔
357
  if (!dq->httpScheme) {
4!
358
    if (dq->dq->ids.du) {
4✔
359
#ifdef HAVE_DNS_OVER_HTTPS
2✔
360
      dq->httpScheme = dq->dq->ids.du->getHTTPScheme();
2✔
361
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
362
    }
2✔
363
    else if (dq->dq->ids.doh3u) {
2!
364
#if defined(HAVE_DNS_OVER_HTTP3)
365
      dq->httpScheme = dq->dq->ids.doh3u->getHTTPScheme();
366
#endif /* HAVE_DNS_OVER_HTTP3 */
367
    }
×
368
  }
4✔
369
  if (dq->httpScheme) {
4✔
370
    return dq->httpScheme->c_str();
2✔
371
  }
2✔
372
  return nullptr;
2✔
373
}
4✔
374

375
static void fill_edns_option(const EDNSOptionViewValue& value, dnsdist_ffi_ednsoption_t& option)
376
{
16✔
377
  option.len = value.size;
16✔
378
  option.data = nullptr;
16✔
379

380
  if (value.size > 0) {
16!
381
    option.data = value.content;
16✔
382
  }
16✔
383
}
16✔
384

385
// returns the length of the resulting 'out' array. 'out' is not set if the length is 0
386
size_t dnsdist_ffi_dnsquestion_get_edns_options(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_ednsoption_t** out)
387
{
12✔
388
  if (dq->dq->ednsOptions == nullptr) {
12!
389
    parseEDNSOptions(*(dq->dq));
12✔
390

391
    if (dq->dq->ednsOptions == nullptr) {
12!
392
      return 0;
×
393
    }
×
394
  }
12✔
395

396
  size_t totalCount = 0;
12✔
397
  for (const auto& option : *dq->dq->ednsOptions) {
14✔
398
    totalCount += option.second.values.size();
14✔
399
  }
14✔
400

401
  if (!dq->ednsOptionsVect) {
12!
402
    dq->ednsOptionsVect = std::make_unique<std::vector<dnsdist_ffi_ednsoption_t>>();
12✔
403
  }
12✔
404
  dq->ednsOptionsVect->clear();
12✔
405
  dq->ednsOptionsVect->resize(totalCount);
12✔
406
  size_t pos = 0;
12✔
407
  for (const auto& option : *dq->dq->ednsOptions) {
14✔
408
    for (const auto& entry : option.second.values) {
16✔
409
      fill_edns_option(entry, dq->ednsOptionsVect->at(pos));
16✔
410
      dq->ednsOptionsVect->at(pos).optionCode = option.first;
16✔
411
      pos++;
16✔
412
    }
16✔
413
  }
14✔
414

415
  if (totalCount > 0) {
12✔
416
    *out = dq->ednsOptionsVect->data();
10✔
417
  }
10✔
418

419
  return totalCount;
12✔
420
}
12✔
421

422
size_t dnsdist_ffi_dnsquestion_get_http_headers(dnsdist_ffi_dnsquestion_t* dq, [[maybe_unused]] const dnsdist_ffi_http_header_t** out)
423
{
4✔
424
#if defined(HAVE_DNS_OVER_HTTPS) || defined(HAVE_DNS_OVER_HTTP3)
3✔
425
  const auto processHeaders = [&dq](const std::unordered_map<std::string, std::string>& headers) {
3✔
426
    if (headers.empty()) {
2!
427
      return;
428
    }
429
    dq->httpHeaders = std::make_unique<std::unordered_map<std::string, std::string>>(headers);
2✔
430
    if (!dq->httpHeadersVect) {
2!
431
      dq->httpHeadersVect = std::make_unique<std::vector<dnsdist_ffi_http_header_t>>();
2✔
432
    }
2✔
433
    dq->httpHeadersVect->clear();
2✔
434
    dq->httpHeadersVect->resize(dq->httpHeaders->size());
2✔
435
    size_t pos = 0;
2✔
436
    for (const auto& header : *dq->httpHeaders) {
11✔
437
      dq->httpHeadersVect->at(pos).name = header.first.c_str();
11✔
438
      dq->httpHeadersVect->at(pos).value = header.second.c_str();
11✔
439
      ++pos;
11✔
440
    }
11✔
441
  };
2✔
442

443
#if defined(HAVE_DNS_OVER_HTTPS)
3✔
444
  if (dq->dq->ids.du) {
3✔
445
    const auto& headers = dq->dq->ids.du->getHTTPHeaders();
2✔
446
    processHeaders(headers);
2✔
447
  }
2✔
448
#endif /* HAVE_DNS_OVER_HTTPS */
3✔
449
#if defined(HAVE_DNS_OVER_HTTP3)
3✔
450
  if (dq->dq->ids.doh3u) {
3!
451
    const auto& headers = dq->dq->ids.doh3u->getHTTPHeaders();
452
    processHeaders(headers);
453
  }
454
#endif /* HAVE_DNS_OVER_HTTP3 */
3✔
455

456
  if (!dq->httpHeadersVect) {
3✔
457
    return 0;
1✔
458
  }
1✔
459

460
  if (!dq->httpHeadersVect->empty()) {
2!
461
    *out = dq->httpHeadersVect->data();
2✔
462
  }
2✔
463
  return dq->httpHeadersVect->size();
2✔
464
#else /* HAVE_DNS_OVER_HTTPS || HAVE_DNS_OVER_HTTP3 */
465
  return 0;
1✔
466
#endif /* HAVE_DNS_OVER_HTTPS || HAVE_DNS_OVER_HTTP3 */
1✔
467
}
4✔
468

469
size_t dnsdist_ffi_dnsquestion_get_tag_array(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_tag_t** out)
470
{
4✔
471
  if (dq == nullptr || dq->dq == nullptr || dq->dq->ids.qTag == nullptr || dq->dq->ids.qTag->size() == 0) {
4!
472
    return 0;
2✔
473
  }
2✔
474

475
  if (!dq->tagsVect) {
2!
476
    dq->tagsVect = std::make_unique<std::vector<dnsdist_ffi_tag_t>>();
2✔
477
  }
2✔
478
  dq->tagsVect->clear();
2✔
479
  dq->tagsVect->resize(dq->dq->ids.qTag->size());
2✔
480
  size_t pos = 0;
2✔
481

482
  for (const auto& tag : *dq->dq->ids.qTag) {
2✔
483
    auto& entry = dq->tagsVect->at(pos);
2✔
484
    entry.name = tag.first.c_str();
2✔
485
    entry.value = tag.second.c_str();
2✔
486
    ++pos;
2✔
487
  }
2✔
488

489
  if (!dq->tagsVect->empty()) {
2!
490
    *out = dq->tagsVect->data();
2✔
491
  }
2✔
492

493
  return dq->tagsVect->size();
2✔
494
}
4✔
495

496
void dnsdist_ffi_dnsquestion_set_result(dnsdist_ffi_dnsquestion_t* dq, const char* str, size_t strSize)
497
{
8✔
498
  dq->result = std::string(str, strSize);
8✔
499
}
8✔
500

501
void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, [[maybe_unused]] uint16_t statusCode, [[maybe_unused]] const char* body, [[maybe_unused]] size_t bodyLen, [[maybe_unused]] const char* contentType)
502
{
4✔
503
#if defined(HAVE_DNS_OVER_HTTPS)
3✔
504
  if (dq->dq->ids.du) {
3✔
505
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): C API
506
    PacketBuffer bodyVect(body, body + bodyLen);
2✔
507
    dq->dq->ids.du->setHTTPResponse(statusCode, std::move(bodyVect), contentType);
2✔
508
    dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [](dnsheader& header) {
2✔
509
      header.qr = true;
2✔
510
      return true;
2✔
511
    });
2✔
512
  }
2✔
513
#endif
3✔
514
#if defined(HAVE_DNS_OVER_HTTP3)
3✔
515
  if (dq->dq->ids.doh3u) {
3!
516
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): C API
517
    PacketBuffer bodyVect(body, body + bodyLen);
518
    dq->dq->ids.doh3u->setHTTPResponse(statusCode, std::move(bodyVect), contentType);
519
    dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [](dnsheader& header) {
520
      header.qr = true;
521
      return true;
522
    });
523
  }
524
#endif
3✔
525
}
4✔
526

527
void dnsdist_ffi_dnsquestion_set_extended_dns_error(dnsdist_ffi_dnsquestion_t* dnsQuestion, uint16_t infoCode, const char* extraText, size_t extraTextSize)
528
{
2✔
529
  EDNSExtendedError ede;
2✔
530
  ede.infoCode = infoCode;
2✔
531
  if (extraText != nullptr && extraTextSize > 0) {
2!
532
    ede.extraText = std::string(extraText, extraTextSize);
2✔
533
  }
2✔
534
  dnsQuestion->dq->ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
2✔
535
}
2✔
536

537
void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
538
{
6✔
539
  dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [rcode](dnsheader& header) {
6✔
540
    header.rcode = rcode;
6✔
541
    header.qr = true;
6✔
542
    return true;
6✔
543
  });
6✔
544
}
6✔
545

546
void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
547
{
2✔
548
  dq->dq->getMutableData().resize(len);
2✔
549
}
2✔
550

551
void dnsdist_ffi_dnsquestion_set_skip_cache(dnsdist_ffi_dnsquestion_t* dq, bool skipCache)
552
{
2✔
553
  dq->dq->ids.skipCache = skipCache;
2✔
554
}
2✔
555

556
void dnsdist_ffi_dnsquestion_set_use_ecs(dnsdist_ffi_dnsquestion_t* dq, bool useECS)
557
{
2✔
558
  dq->dq->useECS = useECS;
2✔
559
}
2✔
560

561
void dnsdist_ffi_dnsquestion_set_ecs_override(dnsdist_ffi_dnsquestion_t* dq, bool ecsOverride)
562
{
2✔
563
  dq->dq->ecsOverride = ecsOverride;
2✔
564
}
2✔
565

566
void dnsdist_ffi_dnsquestion_set_ecs_prefix_length(dnsdist_ffi_dnsquestion_t* dq, uint16_t ecsPrefixLength)
567
{
2✔
568
  dq->dq->ecsPrefixLength = ecsPrefixLength;
2✔
569
}
2✔
570

571
void dnsdist_ffi_dnsquestion_set_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t tempFailureTTL)
572
{
2✔
573
  dq->dq->ids.tempFailureTTL = tempFailureTTL;
2✔
574
}
2✔
575

576
void dnsdist_ffi_dnsquestion_unset_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq)
577
{
2✔
578
  dq->dq->ids.tempFailureTTL = boost::none;
2✔
579
}
2✔
580

581
void dnsdist_ffi_dnsquestion_set_tag(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value)
582
{
10✔
583
  dq->dq->setTag(label, value);
10✔
584
}
10✔
585

586
void dnsdist_ffi_dnsquestion_set_tag_raw(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value, size_t valueSize)
587
{
6✔
588
  dq->dq->setTag(label, std::string(value, valueSize));
6✔
589
}
6✔
590

591
void dnsdist_ffi_dnsquestion_set_requestor_id(dnsdist_ffi_dnsquestion_t* dq, const char* value, size_t valueSize)
592
{
6✔
593
  if (!dq || !dq->dq || !value) {
6!
594
    return;
4✔
595
  }
4✔
596
  if (!dq->dq->ids.d_protoBufData) {
2!
597
    dq->dq->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
×
598
  }
×
599
  dq->dq->ids.d_protoBufData->d_requestorID = std::string(value, valueSize);
2✔
600
}
2✔
601

602
void dnsdist_ffi_dnsquestion_set_device_id(dnsdist_ffi_dnsquestion_t* dq, const char* value, size_t valueSize)
603
{
6✔
604
  if (!dq || !dq->dq || !value) {
6!
605
    return;
4✔
606
  }
4✔
607
  if (!dq->dq->ids.d_protoBufData) {
2!
608
    dq->dq->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
2✔
609
  }
2✔
610
  dq->dq->ids.d_protoBufData->d_deviceID = std::string(value, valueSize);
2✔
611
}
2✔
612

613
void dnsdist_ffi_dnsquestion_set_device_name(dnsdist_ffi_dnsquestion_t* dq, const char* value, size_t valueSize)
614
{
6✔
615
  if (!dq || !dq->dq || !value) {
6!
616
    return;
4✔
617
  }
4✔
618
  if (!dq->dq->ids.d_protoBufData) {
2!
619
    dq->dq->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
×
620
  }
×
621
  dq->dq->ids.d_protoBufData->d_deviceName = std::string(value, valueSize);
2✔
622
}
2✔
623

624
size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out)
625
{
4✔
626
  dq->trailingData = dq->dq->getTrailingData();
4✔
627
  if (!dq->trailingData.empty()) {
4✔
628
    *out = dq->trailingData.data();
2✔
629
  }
2✔
630

631
  return dq->trailingData.size();
4✔
632
}
4✔
633

634
bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen)
635
{
2✔
636
  return dq->dq->setTrailingData(std::string(data, dataLen));
2✔
637
}
2✔
638

639
void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen)
640
{
×
641
  if (g_snmpAgent != nullptr && dnsdist::configuration::getImmutableConfiguration().d_snmpTrapsEnabled) {
×
642
    g_snmpAgent->sendDNSTrap(*dq->dq, std::string(reason, reasonLen));
×
643
  }
×
644
}
×
645

646
void dnsdist_ffi_dnsquestion_spoof_packet(dnsdist_ffi_dnsquestion_t* dq, const char* raw, size_t len)
647
{
2✔
648
  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
649
  dnsdist::self_answers::generateAnswerFromRawPacket(*dq->dq, PacketBuffer(raw, raw + len));
2✔
650
}
2✔
651

652
void dnsdist_ffi_dnsquestion_spoof_raw(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
653
{
4✔
654
  std::vector<std::string> data;
4✔
655
  data.reserve(valuesCount);
4✔
656

657
  for (size_t idx = 0; idx < valuesCount; idx++) {
12✔
658
    data.emplace_back(values[idx].value, values[idx].size);
8✔
659
  }
8✔
660

661
  dnsdist::ResponseConfig config{};
4✔
662
  dnsdist::self_answers::generateAnswerFromRDataEntries(*dq->dq, data, std::nullopt, config);
4✔
663
}
4✔
664

665
void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
666
{
2✔
667
  std::vector<ComboAddress> data;
2✔
668
  data.reserve(valuesCount);
2✔
669

670
  for (size_t idx = 0; idx < valuesCount; idx++) {
6✔
671
    if (values[idx].size == 4) {
4✔
672
      sockaddr_in sin;
2✔
673
      sin.sin_family = AF_INET;
2✔
674
      sin.sin_port = 0;
2✔
675
      memcpy(&sin.sin_addr.s_addr, values[idx].value, sizeof(sin.sin_addr.s_addr));
2✔
676
      data.emplace_back(&sin);
2✔
677
    }
2✔
678
    else if (values[idx].size == 16) {
2!
679
      sockaddr_in6 sin6;
2✔
680
      sin6.sin6_family = AF_INET6;
2✔
681
      sin6.sin6_port = 0;
2✔
682
      sin6.sin6_scope_id = 0;
2✔
683
      sin6.sin6_flowinfo = 0;
2✔
684
      memcpy(&sin6.sin6_addr.s6_addr, values[idx].value, sizeof(sin6.sin6_addr.s6_addr));
2✔
685
      data.emplace_back(&sin6);
2✔
686
    }
2✔
687
  }
4✔
688

689
  dnsdist::ResponseConfig config{};
2✔
690
  dnsdist::self_answers::generateAnswerFromIPAddresses(*dq->dq, data, config);
2✔
691
}
2✔
692

693
void dnsdist_ffi_dnsquestion_set_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t max)
694
{
2✔
695
  if (dq != nullptr && dq->dq != nullptr) {
2!
696
    dq->dq->ids.ttlCap = max;
2✔
697
  }
2✔
698
}
2✔
699

700
bool dnsdist_ffi_dnsquestion_set_restartable(dnsdist_ffi_dnsquestion_t* dq)
701
{
4✔
702
  if (dq == nullptr || dq->dq == nullptr) {
4!
703
    return false;
2✔
704
  }
2✔
705

706
  dq->dq->ids.d_packet = std::make_unique<PacketBuffer>(dq->dq->getData());
2✔
707
  return true;
2✔
708
}
4✔
709

710
size_t dnsdist_ffi_servers_list_get_count(const dnsdist_ffi_servers_list_t* list)
711
{
22✔
712
  return list->ffiServers.size();
22✔
713
}
22✔
714

715
void dnsdist_ffi_servers_list_get_server(const dnsdist_ffi_servers_list_t* list, size_t idx, const dnsdist_ffi_server_t** out)
716
{
×
717
  *out = &list->ffiServers.at(idx);
×
718
}
×
719

720
static size_t dnsdist_ffi_servers_get_index_from_server(const ServerPolicy::NumberedServerVector& servers, const std::shared_ptr<DownstreamState>& server)
721
{
×
722
  for (const auto& pair : servers) {
×
723
    if (pair.second == server) {
×
724
      return pair.first - 1;
×
725
    }
×
726
  }
×
727
  throw std::runtime_error("Unable to find servers in server list");
×
728
}
×
729

730
size_t dnsdist_ffi_servers_list_chashed(const dnsdist_ffi_servers_list_t* list, const dnsdist_ffi_dnsquestion_t* dq, size_t hash)
731
{
×
NEW
732
  (void)dq;
×
733
  auto server = chashedFromHash(list->servers, hash);
×
734
  return dnsdist_ffi_servers_get_index_from_server(list->servers, server);
×
735
}
×
736

737
size_t dnsdist_ffi_servers_list_whashed(const dnsdist_ffi_servers_list_t* list, const dnsdist_ffi_dnsquestion_t* dq, size_t hash)
738
{
×
NEW
739
  (void)dq;
×
740
  auto server = whashedFromHash(list->servers, hash);
×
741
  return dnsdist_ffi_servers_get_index_from_server(list->servers, server);
×
742
}
×
743

744
uint64_t dnsdist_ffi_server_get_outstanding(const dnsdist_ffi_server_t* server)
745
{
2✔
746
  return server->server->outstanding;
2✔
747
}
2✔
748

749
int dnsdist_ffi_server_get_weight(const dnsdist_ffi_server_t* server)
750
{
2✔
751
  return server->server->d_config.d_weight;
2✔
752
}
2✔
753

754
int dnsdist_ffi_server_get_order(const dnsdist_ffi_server_t* server)
755
{
2✔
756
  return server->server->d_config.order;
2✔
757
}
2✔
758

759
double dnsdist_ffi_server_get_latency(const dnsdist_ffi_server_t* server)
760
{
2✔
761
  return server->server->getRelevantLatencyUsec();
2✔
762
}
2✔
763

764
bool dnsdist_ffi_server_is_up(const dnsdist_ffi_server_t* server)
765
{
2✔
766
  return server->server->isUp();
2✔
767
}
2✔
768

769
const char* dnsdist_ffi_server_get_name(const dnsdist_ffi_server_t* server)
770
{
2✔
771
  return server->server->getName().c_str();
2✔
772
}
2✔
773

774
const char* dnsdist_ffi_server_get_name_with_addr(const dnsdist_ffi_server_t* server)
775
{
2✔
776
  return server->server->getNameWithAddr().c_str();
2✔
777
}
2✔
778

779
void dnsdist_ffi_dnsresponse_set_min_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t min)
780
{
2✔
781
  dnsdist_ffi_dnsresponse_limit_ttl(dr, min, std::numeric_limits<uint32_t>::max());
2✔
782
}
2✔
783

784
void dnsdist_ffi_dnsresponse_set_max_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t max)
785
{
2✔
786
  dnsdist_ffi_dnsresponse_limit_ttl(dr, 0, max);
2✔
787
}
2✔
788

789
void dnsdist_ffi_dnsresponse_limit_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t min, uint32_t max)
790
{
6✔
791
  if (dr != nullptr && dr->dr != nullptr) {
6!
792
    dnsdist::PacketMangling::restrictDNSPacketTTLs(dr->dr->getMutableData(), min, max);
6✔
793
  }
6✔
794
}
6✔
795

796
void dnsdist_ffi_dnsresponse_set_max_returned_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t max)
797
{
2✔
798
  if (dr != nullptr && dr->dr != nullptr) {
2!
799
    dr->dr->ids.ttlCap = max;
2✔
800
  }
2✔
801
}
2✔
802

803
void dnsdist_ffi_dnsresponse_clear_records_type(dnsdist_ffi_dnsresponse_t* dr, uint16_t qtype)
804
{
6✔
805
  if (dr != nullptr && dr->dr != nullptr) {
6!
806
    clearDNSPacketRecordTypes(dr->dr->getMutableData(), std::unordered_set<QType>{qtype});
4✔
807
  }
4✔
808
}
6✔
809

810
bool dnsdist_ffi_dnsresponse_rebase(dnsdist_ffi_dnsresponse_t* dr, const char* initialName, size_t initialNameSize)
811
{
6✔
812
  if (dr == nullptr || dr->dr == nullptr || initialName == nullptr || initialNameSize == 0) {
6!
813
    return false;
2✔
814
  }
2✔
815

816
  try {
4✔
817
    DNSName parsed(initialName, initialNameSize, 0, false);
4✔
818

819
    if (!dnsdist::changeNameInDNSPacket(dr->dr->getMutableData(), dr->dr->ids.qname, parsed)) {
4!
820
      return false;
×
821
    }
×
822

823
    // set qname to new one
824
    dr->dr->ids.qname = std::move(parsed);
4✔
825
    dr->dr->ids.skipCache = true;
4✔
826
  }
4✔
827
  catch (const std::exception& e) {
4✔
828
    vinfolog("Error rebasing packet on a new DNSName: %s", e.what());
2!
829
    return false;
2✔
830
  }
2✔
831

832
  return true;
2✔
833
}
4✔
834

835
bool dnsdist_ffi_dnsquestion_set_async(dnsdist_ffi_dnsquestion_t* dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
836
{
101✔
837
  try {
101✔
838
    dq->dq->asynchronous = true;
101✔
839
    return dnsdist::suspendQuery(*dq->dq, asyncID, queryID, timeoutMs);
101✔
840
  }
101✔
841
  catch (const std::exception& e) {
101✔
842
    vinfolog("Error in dnsdist_ffi_dnsquestion_set_async: %s", e.what());
×
843
  }
×
844
  catch (...) {
101✔
845
    vinfolog("Exception in dnsdist_ffi_dnsquestion_set_async");
×
846
  }
×
847

848
  return false;
×
849
}
101✔
850

851
bool dnsdist_ffi_dnsresponse_set_async(dnsdist_ffi_dnsquestion_t* dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
852
{
83✔
853
  try {
83✔
854
    dq->dq->asynchronous = true;
83✔
855
    auto dr = dynamic_cast<DNSResponse*>(dq->dq);
83✔
856
    if (!dr) {
83!
857
      vinfolog("Passed a DNSQuestion instead of a DNSResponse to dnsdist_ffi_dnsresponse_set_async");
×
858
      return false;
×
859
    }
×
860

861
    return dnsdist::suspendResponse(*dr, asyncID, queryID, timeoutMs);
83✔
862
  }
83✔
863
  catch (const std::exception& e) {
83✔
864
    vinfolog("Error in dnsdist_ffi_dnsresponse_set_async: %s", e.what());
×
865
  }
×
866
  catch (...) {
83✔
867
    vinfolog("Exception in dnsdist_ffi_dnsresponse_set_async");
×
868
  }
×
869
  return false;
×
870
}
83✔
871

872
bool dnsdist_ffi_resume_from_async(uint16_t asyncID, uint16_t queryID, const char* tag, size_t tagSize, const char* tagValue, size_t tagValueSize, bool useCache)
873
{
104✔
874
  if (!dnsdist::g_asyncHolder) {
104!
875
    vinfolog("Unable to resume, no asynchronous holder");
×
876
    return false;
×
877
  }
×
878

879
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
104✔
880
  if (!query) {
104!
881
    vinfolog("Unable to resume, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
882
    return false;
×
883
  }
×
884

885
  auto& ids = query->query.d_idstate;
104✔
886
  if (tag != nullptr && tagSize > 0) {
104!
887
    if (!ids.qTag) {
104✔
888
      ids.qTag = std::make_unique<QTag>();
83✔
889
    }
83✔
890
    (*ids.qTag)[std::string(tag, tagSize)] = std::string(tagValue, tagValueSize);
104✔
891
  }
104✔
892

893
  ids.skipCache = !useCache;
104✔
894

895
  return dnsdist::queueQueryResumptionEvent(std::move(query));
104✔
896
}
104✔
897

898
bool dnsdist_ffi_set_rcode_from_async(uint16_t asyncID, uint16_t queryID, uint8_t rcode, bool clearAnswers)
899
{
18✔
900
  if (!dnsdist::g_asyncHolder) {
18!
901
    return false;
×
902
  }
×
903

904
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
18✔
905
  if (!query) {
18!
906
    vinfolog("Unable to resume with a custom response code, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
907
    return false;
×
908
  }
×
909

910
  if (!dnsdist::setInternalQueryRCode(query->query.d_idstate, query->query.d_buffer, rcode, clearAnswers)) {
18!
911
    return false;
×
912
  }
×
913

914
  query->query.d_idstate.skipCache = true;
18✔
915

916
  return dnsdist::queueQueryResumptionEvent(std::move(query));
18✔
917
}
18✔
918

919
bool dnsdist_ffi_resume_from_async_with_alternate_name(uint16_t asyncID, uint16_t queryID, const char* alternateName, size_t alternateNameSize, const char* tag, size_t tagSize, const char* tagValue, size_t tagValueSize, const char* formerNameTagName, size_t formerNameTagSize)
920
{
×
921
  if (!dnsdist::g_asyncHolder) {
×
922
    return false;
×
923
  }
×
924

925
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
×
926
  if (!query) {
×
927
    vinfolog("Unable to resume with an alternate name, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
928
    return false;
×
929
  }
×
930

931
  auto& ids = query->query.d_idstate;
×
932
  DNSName originalName = ids.qname;
×
933

934
  try {
×
935
    DNSName parsed(alternateName, alternateNameSize, 0, false);
×
936

937
    PacketBuffer initialPacket;
×
938
    if (query->d_isResponse) {
×
939
      if (!ids.d_packet) {
×
940
        return false;
×
941
      }
×
942
      initialPacket = std::move(*ids.d_packet);
×
943
    }
×
944
    else {
×
945
      initialPacket = std::move(query->query.d_buffer);
×
946
    }
×
947

948
    // edit qname in query packet
949
    if (!dnsdist::changeNameInDNSPacket(initialPacket, originalName, parsed)) {
×
950
      return false;
×
951
    }
×
952
    if (query->d_isResponse) {
×
953
      query->d_isResponse = false;
×
954
    }
×
955
    query->query.d_buffer = std::move(initialPacket);
×
956
    // set qname to new one
957
    ids.qname = std::move(parsed);
×
958
  }
×
959
  catch (const std::exception& e) {
×
960
    vinfolog("Error rebasing packet on a new DNSName: %s", e.what());
×
961
    return false;
×
962
  }
×
963

964
  // save existing qname in tag
965
  if (formerNameTagName != nullptr && formerNameTagSize > 0) {
×
966
    if (!ids.qTag) {
×
967
      ids.qTag = std::make_unique<QTag>();
×
968
    }
×
969
    (*ids.qTag)[std::string(formerNameTagName, formerNameTagSize)] = originalName.getStorage();
×
970
  }
×
971

972
  if (tag != nullptr && tagSize > 0) {
×
973
    if (!ids.qTag) {
×
974
      ids.qTag = std::make_unique<QTag>();
×
975
    }
×
976
    (*ids.qTag)[std::string(tag, tagSize)] = std::string(tagValue, tagValueSize);
×
977
  }
×
978

979
  ids.skipCache = true;
×
980

981
  // resume as query
982
  return dnsdist::queueQueryResumptionEvent(std::move(query));
×
983
}
×
984

985
bool dnsdist_ffi_drop_from_async(uint16_t asyncID, uint16_t queryID)
986
{
18✔
987
  if (!dnsdist::g_asyncHolder) {
18!
988
    return false;
×
989
  }
×
990

991
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
18✔
992
  if (!query) {
18!
993
    vinfolog("Unable to drop, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
994
    return false;
×
995
  }
×
996

997
  auto sender = query->getTCPQuerySender();
18✔
998
  if (!sender) {
18!
999
    return false;
×
1000
  }
×
1001

1002
  struct timeval now;
18✔
1003
  gettimeofday(&now, nullptr);
18✔
1004
  TCPResponse tresponse(std::move(query->query));
18✔
1005
  sender->notifyIOError(now, std::move(tresponse));
18✔
1006

1007
  return true;
18✔
1008
}
18✔
1009

1010
bool dnsdist_ffi_set_answer_from_async(uint16_t asyncID, uint16_t queryID, const char* raw, size_t rawSize)
1011
{
18✔
1012
  if (rawSize < sizeof(dnsheader)) {
18!
1013
    return false;
×
1014
  }
×
1015
  if (!dnsdist::g_asyncHolder) {
18!
1016
    return false;
×
1017
  }
×
1018

1019
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
18✔
1020
  if (!query) {
18!
1021
    vinfolog("Unable to resume with a custom answer, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
1022
    return false;
×
1023
  }
×
1024

1025
  dnsheader_aligned alignedHeader(query->query.d_buffer.data());
18✔
1026
  auto oldID = alignedHeader->id;
18✔
1027
  query->query.d_buffer.clear();
18✔
1028
  query->query.d_buffer.insert(query->query.d_buffer.begin(), raw, raw + rawSize);
18✔
1029

1030
  dnsdist::PacketMangling::editDNSHeaderFromPacket(query->query.d_buffer, [oldID](dnsheader& header) {
18✔
1031
    header.id = oldID;
18✔
1032
    return true;
18✔
1033
  });
18✔
1034
  query->query.d_idstate.skipCache = true;
18✔
1035

1036
  return dnsdist::queueQueryResumptionEvent(std::move(query));
18✔
1037
}
18✔
1038

1039
static constexpr char s_lua_ffi_code[] = R"FFICodeContent(
1040
  local ffi = require("ffi")
1041
  local C = ffi.C
1042

1043
  ffi.cdef[[
1044
)FFICodeContent"
1045
#include "dnsdist-lua-ffi-interface.inc"
1046
                                         R"FFICodeContent(
1047
  ]]
1048

1049
)FFICodeContent";
1050

1051
const char* getLuaFFIWrappers()
1052
{
686✔
1053
  return s_lua_ffi_code;
686✔
1054
}
686✔
1055

1056
void setupLuaLoadBalancingContext(LuaContext& luaCtx)
1057
{
4✔
1058
  setupLuaBindings(luaCtx, true, false);
4✔
1059
  setupLuaBindingsDNSQuestion(luaCtx);
4✔
1060
  setupLuaBindingsLogging(luaCtx);
4✔
1061
  setupLuaBindingsKVS(luaCtx, true);
4✔
1062
  setupLuaVars(luaCtx);
4✔
1063

1064
#ifdef LUAJIT_VERSION
4✔
1065
  luaCtx.executeCode(getLuaFFIWrappers());
4✔
1066
#endif
4✔
1067
}
4✔
1068

1069
void setupLuaFFIPerThreadContext(LuaContext& luaCtx)
1070
{
9✔
1071
  setupLuaVars(luaCtx);
9✔
1072
  setupLuaBindingsLogging(luaCtx);
9✔
1073

1074
#ifdef LUAJIT_VERSION
9✔
1075
  luaCtx.executeCode(getLuaFFIWrappers());
9✔
1076
#endif
9✔
1077
}
9✔
1078

1079
size_t dnsdist_ffi_generate_proxy_protocol_payload(const size_t addrSize, const void* srcAddr, const void* dstAddr, const uint16_t srcPort, const uint16_t dstPort, const bool tcp, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value* values, void* out, const size_t outSize)
1080
{
6✔
1081
  try {
6✔
1082
    ComboAddress src, dst;
6✔
1083
    if (addrSize != sizeof(src.sin4.sin_addr) && addrSize != sizeof(src.sin6.sin6_addr.s6_addr)) {
6!
1084
      return 0;
2✔
1085
    }
2✔
1086

1087
    src = makeComboAddressFromRaw(addrSize == sizeof(src.sin4.sin_addr) ? 4 : 6, reinterpret_cast<const char*>(srcAddr), addrSize);
4!
1088
    src.sin4.sin_port = htons(srcPort);
4✔
1089
    dst = makeComboAddressFromRaw(addrSize == sizeof(dst.sin4.sin_addr) ? 4 : 6, reinterpret_cast<const char*>(dstAddr), addrSize);
4!
1090
    dst.sin4.sin_port = htons(dstPort);
4✔
1091

1092
    std::vector<ProxyProtocolValue> valuesVect;
4✔
1093
    if (valuesCount > 0) {
4!
1094
      valuesVect.reserve(valuesCount);
4✔
1095
      for (size_t idx = 0; idx < valuesCount; idx++) {
8✔
1096
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1097
        valuesVect.push_back({std::string(values[idx].value, values[idx].size), values[idx].type});
4✔
1098
      }
4✔
1099
    }
4✔
1100

1101
    std::string payload = makeProxyHeader(tcp, src, dst, valuesVect);
4✔
1102
    if (payload.size() > outSize) {
4✔
1103
      return 0;
2✔
1104
    }
2✔
1105

1106
    memcpy(out, payload.c_str(), payload.size());
2✔
1107

1108
    return payload.size();
2✔
1109
  }
4✔
1110
  catch (const std::exception& e) {
6✔
1111
    vinfolog("Exception in dnsdist_ffi_generate_proxy_protocol_payload: %s", e.what());
×
1112
    return 0;
×
1113
  }
×
1114
  catch (...) {
6✔
1115
    vinfolog("Unhandled exception in dnsdist_ffi_generate_proxy_protocol_payload");
×
1116
    return 0;
×
1117
  }
×
1118
}
6✔
1119

1120
size_t dnsdist_ffi_dnsquestion_generate_proxy_protocol_payload(const dnsdist_ffi_dnsquestion_t* dq, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value* values, void* out, const size_t outSize)
1121
{
×
1122
  std::vector<ProxyProtocolValue> valuesVect;
×
1123
  if (valuesCount > 0) {
×
1124
    valuesVect.reserve(valuesCount);
×
1125
    for (size_t idx = 0; idx < valuesCount; idx++) {
×
1126
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1127
      valuesVect.push_back({std::string(values[idx].value, values[idx].size), values[idx].type});
×
1128
    }
×
1129
  }
×
1130

1131
  std::string payload = makeProxyHeader(dq->dq->overTCP(), dq->dq->ids.origRemote, dq->dq->ids.origDest, valuesVect);
×
1132
  if (payload.size() > outSize) {
×
1133
    return 0;
×
1134
  }
×
1135

1136
  memcpy(out, payload.c_str(), payload.size());
×
1137

1138
  return payload.size();
×
1139
}
×
1140

1141
bool dnsdist_ffi_dnsquestion_add_proxy_protocol_values(dnsdist_ffi_dnsquestion_t* dnsQuestion, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values)
1142
{
8✔
1143
  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || values == nullptr || valuesCount == 0) {
8!
1144
    return false;
6✔
1145
  }
6✔
1146

1147
  if (!dnsQuestion->dq->proxyProtocolValues) {
2!
1148
    dnsQuestion->dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
2✔
1149
  }
2✔
1150

1151
  dnsQuestion->dq->proxyProtocolValues->reserve(dnsQuestion->dq->proxyProtocolValues->size() + valuesCount);
2✔
1152
  for (size_t idx = 0; idx < valuesCount; idx++) {
4✔
1153
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): the Lua FFI API is a C API..
1154
    dnsQuestion->dq->proxyProtocolValues->push_back({std::string(values[idx].value, values[idx].size), values[idx].type});
2✔
1155
  }
2✔
1156

1157
  return true;
2✔
1158
}
8✔
1159

1160
size_t dnsdist_ffi_dnsquestion_get_proxy_protocol_values(dnsdist_ffi_dnsquestion_t* dnsQuestion, const dnsdist_ffi_proxy_protocol_value_t** out)
1161
{
10✔
1162
  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || !dnsQuestion->dq->proxyProtocolValues) {
10!
1163
    return 0;
6✔
1164
  }
6✔
1165

1166
  if (out == nullptr) {
4!
1167
    return dnsQuestion->proxyProtocolValuesVect->size();
×
1168
  }
×
1169

1170
  dnsQuestion->proxyProtocolValuesVect = std::make_unique<std::vector<dnsdist_ffi_proxy_protocol_value_t>>(dnsQuestion->dq->proxyProtocolValues->size());
4✔
1171
  for (size_t counter = 0; counter < dnsQuestion->dq->proxyProtocolValues->size(); ++counter) {
14✔
1172
    const auto& entry = dnsQuestion->dq->proxyProtocolValues->at(counter);
10✔
1173
    auto& targetEntry = dnsQuestion->proxyProtocolValuesVect->at(counter);
10✔
1174
    targetEntry.size = entry.content.size();
10✔
1175
    targetEntry.value = entry.content.data();
10✔
1176
    targetEntry.type = entry.type;
10✔
1177
  }
10✔
1178

1179
  *out = dnsQuestion->proxyProtocolValuesVect->data();
4✔
1180
  return dnsQuestion->proxyProtocolValuesVect->size();
4✔
1181
}
4✔
1182

1183
struct dnsdist_ffi_domain_list_t
1184
{
1185
  std::vector<std::string> d_domains;
1186
};
1187
struct dnsdist_ffi_address_list_t
1188
{
1189
  std::vector<std::string> d_addresses;
1190
};
1191

1192
const char* dnsdist_ffi_domain_list_get(const dnsdist_ffi_domain_list_t* list, size_t idx)
1193
{
6✔
1194
  if (list == nullptr || idx >= list->d_domains.size()) {
6✔
1195
    return nullptr;
4✔
1196
  }
4✔
1197

1198
  return list->d_domains.at(idx).c_str();
2✔
1199
}
6✔
1200

1201
void dnsdist_ffi_domain_list_free(dnsdist_ffi_domain_list_t* list)
1202
{
2✔
1203
  delete list;
2✔
1204
}
2✔
1205

1206
const char* dnsdist_ffi_address_list_get(const dnsdist_ffi_address_list_t* list, size_t idx)
1207
{
6✔
1208
  if (list == nullptr || idx >= list->d_addresses.size()) {
6✔
1209
    return nullptr;
4✔
1210
  }
4✔
1211

1212
  return list->d_addresses.at(idx).c_str();
2✔
1213
}
6✔
1214

1215
void dnsdist_ffi_address_list_free(dnsdist_ffi_address_list_t* list)
1216
{
2✔
1217
  delete list;
2✔
1218
}
2✔
1219

1220
size_t dnsdist_ffi_packetcache_get_domain_list_by_addr(const char* poolName, const char* addr, dnsdist_ffi_domain_list_t** out)
1221
{
12✔
1222
  if (poolName == nullptr || addr == nullptr || out == nullptr) {
12!
1223
    return 0;
2✔
1224
  }
2✔
1225

1226
  ComboAddress ca;
10✔
1227
  try {
10✔
1228
    ca = ComboAddress(addr);
10✔
1229
  }
10✔
1230
  catch (const std::exception& e) {
10✔
1231
    vinfolog("Error parsing address passed to dnsdist_ffi_packetcache_get_domain_list_by_addr: %s", e.what());
×
1232
    return 0;
×
1233
  }
×
1234
  catch (const PDNSException& e) {
10✔
1235
    vinfolog("Error parsing address passed to dnsdist_ffi_packetcache_get_domain_list_by_addr: %s", e.reason);
2!
1236
    return 0;
2✔
1237
  }
2✔
1238

1239
  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
8✔
1240
  auto poolIt = pools.find(poolName);
8✔
1241
  if (poolIt == pools.end()) {
8✔
1242
    return 0;
2✔
1243
  }
2✔
1244

1245
  auto pool = poolIt->second;
6✔
1246
  if (!pool->packetCache) {
6✔
1247
    return 0;
2✔
1248
  }
2✔
1249

1250
  auto domains = pool->packetCache->getDomainsContainingRecords(ca);
4✔
1251
  if (domains.size() == 0) {
4✔
1252
    return 0;
2✔
1253
  }
2✔
1254

1255
  auto list = std::make_unique<dnsdist_ffi_domain_list_t>();
2✔
1256
  list->d_domains.reserve(domains.size());
2✔
1257
  for (const auto& domain : domains) {
2✔
1258
    try {
2✔
1259
      list->d_domains.push_back(domain.toString());
2✔
1260
    }
2✔
1261
    catch (const std::exception& e) {
2✔
1262
      vinfolog("Error converting domain to string in dnsdist_ffi_packetcache_get_domain_list_by_addr: %s", e.what());
×
1263
    }
×
1264
  }
2✔
1265

1266
  size_t count = list->d_domains.size();
2✔
1267
  if (count > 0) {
2!
1268
    *out = list.release();
2✔
1269
  }
2✔
1270
  return count;
2✔
1271
}
2✔
1272

1273
size_t dnsdist_ffi_packetcache_get_address_list_by_domain(const char* poolName, const char* domain, dnsdist_ffi_address_list_t** out)
1274
{
12✔
1275
  if (poolName == nullptr || domain == nullptr || out == nullptr) {
12!
1276
    return 0;
2✔
1277
  }
2✔
1278

1279
  DNSName name;
10✔
1280
  try {
10✔
1281
    name = DNSName(domain);
10✔
1282
  }
10✔
1283
  catch (const std::exception& e) {
10✔
1284
    vinfolog("Error parsing domain passed to dnsdist_ffi_packetcache_get_address_list_by_domain: %s", e.what());
2!
1285
    return 0;
2✔
1286
  }
2✔
1287

1288
  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
8✔
1289
  auto poolIt = pools.find(poolName);
8✔
1290
  if (poolIt == pools.end()) {
8✔
1291
    return 0;
2✔
1292
  }
2✔
1293

1294
  auto pool = poolIt->second;
6✔
1295
  if (!pool->packetCache) {
6✔
1296
    return 0;
2✔
1297
  }
2✔
1298

1299
  auto addresses = pool->packetCache->getRecordsForDomain(name);
4✔
1300
  if (addresses.size() == 0) {
4✔
1301
    return 0;
2✔
1302
  }
2✔
1303

1304
  auto list = std::make_unique<dnsdist_ffi_address_list_t>();
2✔
1305
  list->d_addresses.reserve(addresses.size());
2✔
1306
  for (const auto& addr : addresses) {
2✔
1307
    try {
2✔
1308
      list->d_addresses.push_back(addr.toString());
2✔
1309
    }
2✔
1310
    catch (const std::exception& e) {
2✔
1311
      vinfolog("Error converting address to string in dnsdist_ffi_packetcache_get_address_list_by_domain: %s", e.what());
×
1312
    }
×
1313
  }
2✔
1314

1315
  size_t count = list->d_addresses.size();
2✔
1316
  if (count > 0) {
2!
1317
    *out = list.release();
2✔
1318
  }
2✔
1319
  return count;
2✔
1320
}
2✔
1321

1322
struct dnsdist_ffi_ring_entry_list_t
1323
{
1324
  struct entry
1325
  {
1326
    std::string qname;
1327
    std::string requestor;
1328
    std::string macAddr;
1329
    std::string ds;
1330
    dnsheader dh;
1331
    double age;
1332
    unsigned int latency;
1333
    uint16_t size;
1334
    uint16_t qtype;
1335
    dnsdist::Protocol protocol;
1336
    bool isResponse;
1337
  };
1338

1339
  std::vector<entry> d_entries;
1340
};
1341

1342
bool dnsdist_ffi_ring_entry_is_response(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1343
{
10✔
1344
  if (list == nullptr || idx >= list->d_entries.size()) {
10!
1345
    return false;
2✔
1346
  }
2✔
1347

1348
  return list->d_entries.at(idx).isResponse;
8✔
1349
}
10✔
1350

1351
double dnsdist_ffi_ring_entry_get_age(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1352
{
10✔
1353
  if (list == nullptr || idx >= list->d_entries.size()) {
10!
1354
    return 0;
2✔
1355
  }
2✔
1356

1357
  return list->d_entries.at(idx).age;
8✔
1358
}
10✔
1359

1360
const char* dnsdist_ffi_ring_entry_get_name(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1361
{
6✔
1362
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1363
    return nullptr;
2✔
1364
  }
2✔
1365

1366
  return list->d_entries.at(idx).qname.c_str();
4✔
1367
}
6✔
1368

1369
uint16_t dnsdist_ffi_ring_entry_get_type(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1370
{
6✔
1371
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1372
    return 0;
2✔
1373
  }
2✔
1374

1375
  return list->d_entries.at(idx).qtype;
4✔
1376
}
6✔
1377

1378
const char* dnsdist_ffi_ring_entry_get_requestor(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1379
{
6✔
1380
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1381
    return nullptr;
2✔
1382
  }
2✔
1383

1384
  return list->d_entries.at(idx).requestor.c_str();
4✔
1385
}
6✔
1386

1387
const char* dnsdist_ffi_ring_entry_get_backend(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1388
{
4✔
1389
  if (list == nullptr || idx >= list->d_entries.size()) {
4!
1390
    return nullptr;
2✔
1391
  }
2✔
1392

1393
  return list->d_entries.at(idx).ds.c_str();
2✔
1394
}
4✔
1395

1396
uint8_t dnsdist_ffi_ring_entry_get_protocol(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1397
{
6✔
1398
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1399
    return 0;
2✔
1400
  }
2✔
1401

1402
  return list->d_entries.at(idx).protocol.toNumber();
4✔
1403
}
6✔
1404

1405
uint16_t dnsdist_ffi_ring_entry_get_size(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1406
{
6✔
1407
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1408
    return 0;
2✔
1409
  }
2✔
1410

1411
  return list->d_entries.at(idx).size;
4✔
1412
}
6✔
1413

1414
uint16_t dnsdist_ffi_ring_entry_get_latency(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1415
{
4✔
1416
  if (list == nullptr || idx >= list->d_entries.size()) {
4!
1417
    return 0;
2✔
1418
  }
2✔
1419

1420
  return list->d_entries.at(idx).latency;
2✔
1421
}
4✔
1422

1423
uint16_t dnsdist_ffi_ring_entry_get_id(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1424
{
6✔
1425
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1426
    return 0;
2✔
1427
  }
2✔
1428

1429
  return ntohs(list->d_entries.at(idx).dh.id);
4✔
1430
}
6✔
1431

1432
uint8_t dnsdist_ffi_ring_entry_get_rcode(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1433
{
6✔
1434
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1435
    return 0;
2✔
1436
  }
2✔
1437

1438
  return list->d_entries.at(idx).dh.rcode;
4✔
1439
}
6✔
1440

1441
bool dnsdist_ffi_ring_entry_get_aa(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1442
{
6✔
1443
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1444
    return false;
2✔
1445
  }
2✔
1446

1447
  return list->d_entries.at(idx).dh.aa == 1;
4✔
1448
}
6✔
1449

1450
bool dnsdist_ffi_ring_entry_get_rd(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1451
{
6✔
1452
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1453
    return false;
2✔
1454
  }
2✔
1455

1456
  return list->d_entries.at(idx).dh.rd == 1;
4✔
1457
}
6✔
1458

1459
bool dnsdist_ffi_ring_entry_get_tc(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1460
{
6✔
1461
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1462
    return false;
2✔
1463
  }
2✔
1464

1465
  return list->d_entries.at(idx).dh.tc == 1;
4✔
1466
}
6✔
1467

1468
uint16_t dnsdist_ffi_ring_entry_get_ancount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1469
{
6✔
1470
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1471
    return 0;
2✔
1472
  }
2✔
1473

1474
  return ntohs(list->d_entries.at(idx).dh.ancount);
4✔
1475
}
6✔
1476

1477
uint16_t dnsdist_ffi_ring_entry_get_nscount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1478
{
6✔
1479
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1480
    return 0;
2✔
1481
  }
2✔
1482

1483
  return ntohs(list->d_entries.at(idx).dh.nscount);
4✔
1484
}
6✔
1485

1486
uint16_t dnsdist_ffi_ring_entry_get_arcount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1487
{
6✔
1488
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1489
    return 0;
2✔
1490
  }
2✔
1491

1492
  return ntohs(list->d_entries.at(idx).dh.arcount);
4✔
1493
}
6✔
1494

1495
bool dnsdist_ffi_ring_entry_has_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1496
{
6✔
1497
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1498
    return false;
2✔
1499
  }
2✔
1500

1501
  return !list->d_entries.at(idx).macAddr.empty();
4✔
1502
}
6✔
1503

1504
const char* dnsdist_ffi_ring_entry_get_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1505
{
6✔
1506
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1507
    return nullptr;
2✔
1508
  }
2✔
1509

1510
  return list->d_entries.at(idx).macAddr.data();
4✔
1511
}
6✔
1512

1513
void dnsdist_ffi_ring_entry_list_free(dnsdist_ffi_ring_entry_list_t* list)
1514
{
4✔
1515
  delete list;
4✔
1516
}
4✔
1517

1518
template <typename T>
1519
static void addRingEntryToList(std::unique_ptr<dnsdist_ffi_ring_entry_list_t>& list, const struct timespec& now, const T& entry)
1520
{
8✔
1521
  auto age = DiffTime(entry.when, now);
8✔
1522

1523
  constexpr bool response = std::is_same_v<T, Rings::Response>;
8✔
1524
  if constexpr (!response) {
8✔
1525
#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
1526
    dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string(), std::string(), entry.dh, age, 0, entry.size, entry.qtype, entry.protocol, response};
1527
#else
1528
    dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), std::string(), std::string(), entry.dh, age, 0, entry.size, entry.qtype, entry.protocol, response};
4✔
1529
#endif
4✔
1530
    list->d_entries.push_back(std::move(tmp));
4✔
1531
  }
4✔
1532
  else {
4✔
1533
    dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), std::string(), entry.ds.toStringWithPort(), entry.dh, age, entry.usec, entry.size, entry.qtype, entry.protocol, response};
4✔
1534
    list->d_entries.push_back(std::move(tmp));
4✔
1535
  }
4✔
1536
}
8✔
1537

1538
size_t dnsdist_ffi_ring_get_entries(dnsdist_ffi_ring_entry_list_t** out)
1539
{
4✔
1540
  if (out == nullptr) {
4✔
1541
    return 0;
2✔
1542
  }
2✔
1543
  auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
2✔
1544
  struct timespec now
2✔
1545
  {
2✔
1546
  };
2✔
1547
  gettime(&now);
2✔
1548

1549
  for (const auto& shard : g_rings.d_shards) {
20✔
1550
    {
20✔
1551
      auto ql = shard->queryRing.lock();
20✔
1552
      for (const auto& entry : *ql) {
20✔
1553
        addRingEntryToList(list, now, entry);
2✔
1554
      }
2✔
1555
    }
20✔
1556
    {
20✔
1557
      auto rl = shard->respRing.lock();
20✔
1558
      for (const auto& entry : *rl) {
20✔
1559
        addRingEntryToList(list, now, entry);
2✔
1560
      }
2✔
1561
    }
20✔
1562
  }
20✔
1563

1564
  auto count = list->d_entries.size();
2✔
1565
  if (count > 0) {
2!
1566
    *out = list.release();
2✔
1567
  }
2✔
1568
  return count;
2✔
1569
}
4✔
1570

1571
size_t dnsdist_ffi_ring_get_entries_by_addr(const char* addr, dnsdist_ffi_ring_entry_list_t** out)
1572
{
10✔
1573
  if (out == nullptr || addr == nullptr) {
10✔
1574
    return 0;
4✔
1575
  }
4✔
1576
  ComboAddress ca;
6✔
1577
  try {
6✔
1578
    ca = ComboAddress(addr);
6✔
1579
  }
6✔
1580
  catch (const std::exception& e) {
6✔
1581
    vinfolog("Unable to convert address in dnsdist_ffi_ring_get_entries_by_addr: %s", e.what());
×
1582
    return 0;
×
1583
  }
×
1584
  catch (const PDNSException& e) {
6✔
1585
    vinfolog("Unable to convert address in dnsdist_ffi_ring_get_entries_by_addr: %s", e.reason);
2!
1586
    return 0;
2✔
1587
  }
2✔
1588

1589
  auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
4✔
1590
  struct timespec now
4✔
1591
  {
4✔
1592
  };
4✔
1593
  gettime(&now);
4✔
1594

1595
  auto compare = ComboAddress::addressOnlyEqual();
4✔
1596
  for (const auto& shard : g_rings.d_shards) {
40✔
1597
    {
40✔
1598
      auto ql = shard->queryRing.lock();
40✔
1599
      for (const auto& entry : *ql) {
40✔
1600
        if (!compare(entry.requestor, ca)) {
4✔
1601
          continue;
2✔
1602
        }
2✔
1603

1604
        addRingEntryToList(list, now, entry);
2✔
1605
      }
2✔
1606
    }
40✔
1607
    {
40✔
1608
      auto rl = shard->respRing.lock();
40✔
1609
      for (const auto& entry : *rl) {
40✔
1610
        if (!compare(entry.requestor, ca)) {
4✔
1611
          continue;
2✔
1612
        }
2✔
1613

1614
        addRingEntryToList(list, now, entry);
2✔
1615
      }
2✔
1616
    }
40✔
1617
  }
40✔
1618

1619
  auto count = list->d_entries.size();
4✔
1620
  if (count > 0) {
4✔
1621
    *out = list.release();
2✔
1622
  }
2✔
1623
  return count;
4✔
1624
}
6✔
1625

1626
size_t dnsdist_ffi_ring_get_entries_by_mac(const char* addr, dnsdist_ffi_ring_entry_list_t** out)
1627
{
2✔
1628
  if (out == nullptr || addr == nullptr) {
2!
1629
    return 0;
2✔
1630
  }
2✔
1631

1632
#if !defined(DNSDIST_RINGS_WITH_MACADDRESS)
×
1633
  return 0;
×
1634
#else
1635
  auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
1636
  struct timespec now
1637
  {
1638
  };
1639
  gettime(&now);
1640

1641
  for (const auto& shard : g_rings.d_shards) {
1642
    auto ql = shard->queryRing.lock();
1643
    for (const auto& entry : *ql) {
1644
      if (memcmp(addr, entry.macaddress.data(), entry.macaddress.size()) != 0) {
1645
        continue;
1646
      }
1647

1648
      addRingEntryToList(list, now, entry);
1649
    }
1650
  }
1651

1652
  auto count = list->d_entries.size();
1653
  if (count > 0) {
1654
    *out = list.release();
1655
  }
1656
  return count;
1657
#endif
1658
}
2✔
1659

1660
struct dnsdist_ffi_network_endpoint_t
1661
{
1662
  dnsdist::NetworkEndpoint d_endpoint;
1663
};
1664

1665
bool dnsdist_ffi_network_endpoint_new(const char* path, size_t pathSize, dnsdist_ffi_network_endpoint_t** out)
1666
{
8✔
1667
  if (path == nullptr || pathSize == 0 || out == nullptr) {
8✔
1668
    return false;
6✔
1669
  }
6✔
1670
  try {
2✔
1671
    dnsdist::NetworkEndpoint endpoint(std::string(path, pathSize));
2✔
1672
    *out = new dnsdist_ffi_network_endpoint_t{std::move(endpoint)};
2✔
1673
    return true;
2✔
1674
  }
2✔
1675
  catch (const std::exception& e) {
2✔
1676
    vinfolog("Error creating a new network endpoint: %s", e.what());
2!
1677
    return false;
2✔
1678
  }
2✔
1679
}
2✔
1680

1681
bool dnsdist_ffi_network_endpoint_is_valid(const dnsdist_ffi_network_endpoint_t* endpoint)
1682
{
2✔
1683
  return endpoint != nullptr;
2✔
1684
}
2✔
1685

1686
bool dnsdist_ffi_network_endpoint_send(const dnsdist_ffi_network_endpoint_t* endpoint, const char* payload, size_t payloadSize)
1687
{
4✔
1688
  if (endpoint != nullptr && payload != nullptr && payloadSize != 0) {
4!
1689
    return endpoint->d_endpoint.send(std::string_view(payload, payloadSize));
×
1690
  }
×
1691
  return false;
4✔
1692
}
4✔
1693

1694
void dnsdist_ffi_network_endpoint_free(dnsdist_ffi_network_endpoint_t* endpoint)
1695
{
2✔
1696
  delete endpoint;
2✔
1697
}
2✔
1698

1699
struct dnsdist_ffi_dnspacket_t
1700
{
1701
  dnsdist::DNSPacketOverlay overlay;
1702
};
1703

1704
bool dnsdist_ffi_dnspacket_parse(const char* packet, size_t packetSize, dnsdist_ffi_dnspacket_t** out)
1705
{
6✔
1706
  if (packet == nullptr || out == nullptr || packetSize < sizeof(dnsheader)) {
6!
1707
    return false;
2✔
1708
  }
2✔
1709

1710
  try {
4✔
1711
    dnsdist::DNSPacketOverlay overlay(std::string_view(packet, packetSize));
4✔
1712
    *out = new dnsdist_ffi_dnspacket_t{std::move(overlay)};
4✔
1713
    return true;
4✔
1714
  }
4✔
1715
  catch (const std::exception& e) {
4✔
1716
    vinfolog("Error in dnsdist_ffi_dnspacket_parse: %s", e.what());
2!
1717
  }
2✔
1718
  catch (...) {
4✔
1719
    vinfolog("Error in dnsdist_ffi_dnspacket_parse");
×
1720
  }
×
1721
  return false;
2✔
1722
}
4✔
1723

1724
void dnsdist_ffi_dnspacket_get_qname_raw(const dnsdist_ffi_dnspacket_t* packet, const char** qname, size_t* qnameSize)
1725
{
4✔
1726
  if (packet == nullptr || qname == nullptr || qnameSize == nullptr) {
4!
1727
    return;
2✔
1728
  }
2✔
1729
  const auto& storage = packet->overlay.d_qname.getStorage();
2✔
1730
  *qname = storage.data();
2✔
1731
  *qnameSize = storage.size();
2✔
1732
}
2✔
1733

1734
uint16_t dnsdist_ffi_dnspacket_get_qtype(const dnsdist_ffi_dnspacket_t* packet)
1735
{
4✔
1736
  if (packet != nullptr) {
4✔
1737
    return packet->overlay.d_qtype;
2✔
1738
  }
2✔
1739
  return 0;
2✔
1740
}
4✔
1741

1742
uint16_t dnsdist_ffi_dnspacket_get_qclass(const dnsdist_ffi_dnspacket_t* packet)
1743
{
4✔
1744
  if (packet != nullptr) {
4✔
1745
    return packet->overlay.d_qclass;
2✔
1746
  }
2✔
1747
  return 0;
2✔
1748
}
4✔
1749

1750
uint16_t dnsdist_ffi_dnspacket_get_records_count_in_section(const dnsdist_ffi_dnspacket_t* packet, uint8_t section)
1751
{
12✔
1752
  if (packet == nullptr || section > DNSResourceRecord::ADDITIONAL) {
12✔
1753
    return 0;
4✔
1754
  }
4✔
1755

1756
  uint16_t count = 0;
8✔
1757
  for (const auto& record : packet->overlay.d_records) {
24✔
1758
    if (record.d_place == section) {
24✔
1759
      count++;
6✔
1760
    }
6✔
1761
  }
24✔
1762

1763
  return count;
8✔
1764
}
12✔
1765

1766
void dnsdist_ffi_dnspacket_get_record_name_raw(const dnsdist_ffi_dnspacket_t* packet, size_t idx, const char** name, size_t* nameSize)
1767
{
6✔
1768
  if (packet == nullptr || name == nullptr || nameSize == nullptr || idx >= packet->overlay.d_records.size()) {
6!
1769
    return;
2✔
1770
  }
2✔
1771
  const auto& storage = packet->overlay.d_records.at(idx).d_name.getStorage();
4✔
1772
  *name = storage.data();
4✔
1773
  *nameSize = storage.size();
4✔
1774
}
4✔
1775

1776
uint16_t dnsdist_ffi_dnspacket_get_record_type(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1777
{
6✔
1778
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
6!
1779
    return 0;
2✔
1780
  }
2✔
1781
  return packet->overlay.d_records.at(idx).d_type;
4✔
1782
}
6✔
1783

1784
uint16_t dnsdist_ffi_dnspacket_get_record_class(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1785
{
6✔
1786
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
6!
1787
    return 0;
2✔
1788
  }
2✔
1789
  return packet->overlay.d_records.at(idx).d_class;
4✔
1790
}
6✔
1791

1792
uint32_t dnsdist_ffi_dnspacket_get_record_ttl(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1793
{
6✔
1794
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
6!
1795
    return 0;
2✔
1796
  }
2✔
1797
  return packet->overlay.d_records.at(idx).d_ttl;
4✔
1798
}
6✔
1799

1800
uint16_t dnsdist_ffi_dnspacket_get_record_content_length(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1801
{
6✔
1802
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
6!
1803
    return 0;
2✔
1804
  }
2✔
1805
  return packet->overlay.d_records.at(idx).d_contentLength;
4✔
1806
}
6✔
1807

1808
uint16_t dnsdist_ffi_dnspacket_get_record_content_offset(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1809
{
6✔
1810
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
6!
1811
    return 0;
2✔
1812
  }
2✔
1813
  return packet->overlay.d_records.at(idx).d_contentOffset;
4✔
1814
}
6✔
1815

1816
size_t dnsdist_ffi_dnspacket_get_name_at_offset_raw(const char* packet, size_t packetSize, size_t offset, char* name, size_t nameSize)
1817
{
10✔
1818
  if (packet == nullptr || name == nullptr || nameSize == 0 || offset >= packetSize) {
10!
1819
    return 0;
4✔
1820
  }
4✔
1821
  try {
6✔
1822
    DNSName parsed(packet, packetSize, offset, true);
6✔
1823
    const auto& storage = parsed.getStorage();
6✔
1824
    if (nameSize < storage.size()) {
6✔
1825
      return 0;
2✔
1826
    }
2✔
1827
    memcpy(name, storage.data(), storage.size());
4✔
1828
    return storage.size();
4✔
1829
  }
6✔
1830
  catch (const std::exception& e) {
6✔
1831
    vinfolog("Error parsing DNSName via dnsdist_ffi_dnspacket_get_name_at_offset_raw: %s", e.what());
2!
1832
  }
2✔
1833
  return 0;
2✔
1834
}
6✔
1835

1836
void dnsdist_ffi_dnspacket_free(dnsdist_ffi_dnspacket_t* packet)
1837
{
2✔
1838
  if (packet != nullptr) {
2!
1839
    delete packet;
2✔
1840
  }
2✔
1841
}
2✔
1842

1843
bool dnsdist_ffi_metric_declare(const char* name, size_t nameLen, const char* type, const char* description, const char* customName)
1844
{
×
1845
  if (name == nullptr || nameLen == 0 || type == nullptr || description == nullptr) {
×
1846
    return false;
×
1847
  }
×
1848
  auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName != nullptr ? std::optional<std::string>(customName) : std::nullopt, false);
×
1849
  return !result;
×
1850
}
×
1851

1852
void dnsdist_ffi_metric_inc(const char* metricName, size_t metricNameLen)
1853
{
×
1854
  auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), 1U, {});
×
1855
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1856
    return;
×
1857
  }
×
1858
}
×
1859

1860
void dnsdist_ffi_metric_inc_by(const char* metricName, size_t metricNameLen, uint64_t value)
1861
{
×
1862
  auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), value, {});
×
1863
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1864
    return;
×
1865
  }
×
1866
}
×
1867

1868
void dnsdist_ffi_metric_dec(const char* metricName, size_t metricNameLen)
1869
{
×
1870
  auto result = dnsdist::metrics::decrementCustomCounter(std::string_view(metricName, metricNameLen), 1U, {});
×
1871
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1872
    return;
×
1873
  }
×
1874
}
×
1875

1876
void dnsdist_ffi_metric_set(const char* metricName, size_t metricNameLen, double value)
1877
{
×
1878
  auto result = dnsdist::metrics::setCustomGauge(std::string_view(metricName, metricNameLen), value, {});
×
1879
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1880
    return;
×
1881
  }
×
1882
}
×
1883

1884
double dnsdist_ffi_metric_get(const char* metricName, size_t metricNameLen, bool isCounter)
1885
{
×
NEW
1886
  (void)isCounter;
×
1887
  auto result = dnsdist::metrics::getCustomMetric(std::string_view(metricName, metricNameLen), {});
×
1888
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1889
    return 0.;
×
1890
  }
×
1891
  return std::get<double>(result);
×
1892
}
×
1893

1894
const char* dnsdist_ffi_network_message_get_payload(const dnsdist_ffi_network_message_t* msg)
1895
{
×
1896
  if (msg != nullptr) {
×
1897
    return msg->payload.c_str();
×
1898
  }
×
1899
  return nullptr;
×
1900
}
×
1901

1902
size_t dnsdist_ffi_network_message_get_payload_size(const dnsdist_ffi_network_message_t* msg)
1903
{
×
1904
  if (msg != nullptr) {
×
1905
    return msg->payload.size();
×
1906
  }
×
1907
  return 0;
×
1908
}
×
1909

1910
uint16_t dnsdist_ffi_network_message_get_endpoint_id(const dnsdist_ffi_network_message_t* msg)
1911
{
×
1912
  if (msg != nullptr) {
×
1913
    return msg->endpointID;
×
1914
  }
×
1915
  return 0;
×
1916
}
×
1917

1918
#ifndef DISABLE_DYNBLOCKS
1919
bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, uint8_t action, unsigned int duration, uint8_t clientIPMask, uint8_t clientIPPortMask, const char* tagKey, const char* tagValue)
1920
{
1921
  try {
1922
    ComboAddress clientIPCA;
1923
    try {
1924
      clientIPCA = ComboAddress(address);
1925
    }
1926
    catch (const std::exception& exp) {
1927
      errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.what());
1928
      return false;
1929
    }
1930
    catch (const PDNSException& exp) {
1931
      errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.reason);
1932
      return false;
1933
    }
1934

1935
    AddressAndPortRange target(clientIPCA, clientIPMask, clientIPPortMask);
1936

1937
    timespec now{};
1938
    gettime(&now);
1939
    timespec until{now};
1940
    until.tv_sec += duration;
1941
    DynBlock dblock{message, until, DNSName(), static_cast<DNSAction::Action>(action)};
1942

1943
    auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
1944
    if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
×
1945
      dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
1946
      dblock.tagSettings->d_name = tagKey;
1947
      if (tagValue != nullptr) {
×
1948
        dblock.tagSettings->d_value = tagValue;
1949
      }
1950
    }
1951
    if (dnsdist::DynamicBlocks::addOrRefreshBlock(dynamicRules, now, target, std::move(dblock), false)) {
×
1952
      dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
1953
      return true;
1954
    }
1955
  }
1956
  catch (const std::exception& exp) {
1957
    errlog("Exception in dnsdist_ffi_dynamic_blocks_add: %s", exp.what());
1958
  }
1959
  catch (const PDNSException& exp) {
1960
    errlog("Exception in dnsdist_ffi_dynamic_blocks_add: %s", exp.reason);
1961
  }
1962
  catch (...) {
1963
    errlog("Exception in dnsdist_ffi_dynamic_blocks_add");
1964
  }
1965
  return false;
1966
}
1967

1968
bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message, uint8_t action, unsigned int duration, const char* tagKey, const char* tagValue)
1969
{
1970
  try {
1971
    DNSName domain;
1972
    try {
1973
      domain = DNSName(suffix);
1974
      domain.makeUsLowerCase();
1975
    }
1976
    catch (const std::exception& exp) {
1977
      errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.what());
1978
      return false;
1979
    }
1980
    catch (const PDNSException& exp) {
1981
      errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.reason);
1982
      return false;
1983
    }
1984

1985
    timespec now{};
1986
    gettime(&now);
1987
    timespec until{now};
1988
    until.tv_sec += duration;
1989
    DynBlock dblock{message, until, domain, static_cast<DNSAction::Action>(action)};
1990
    auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
1991
    if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
×
1992
      dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
1993
      dblock.tagSettings->d_name = tagKey;
1994
      if (tagValue != nullptr) {
×
1995
        dblock.tagSettings->d_value = tagValue;
1996
      }
1997
    }
1998
    if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(smtBlocks, now, std::move(dblock), false)) {
×
1999
      dnsdist::DynamicBlocks::setSuffixDynamicRules(std::move(smtBlocks));
2000
      return true;
2001
    }
2002
  }
2003
  catch (const std::exception& exp) {
2004
    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.what());
2005
  }
2006
  catch (const PDNSException& exp) {
2007
    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.reason);
2008
  }
2009
  catch (...) {
2010
    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add");
2011
  }
2012
  return false;
2013
}
2014

2015
struct dnsdist_ffi_dynamic_blocks_list_t
2016
{
2017
  std::vector<dnsdist_ffi_dynamic_block_entry_t> d_entries;
2018
};
2019

2020
size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out)
2021
{
2022
  if (out == nullptr) {
×
2023
    return 0;
2024
  }
2025

2026
  auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
2027

2028
  timespec now{};
2029
  gettime(&now);
2030

2031
  const auto& dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
2032
  for (const auto& entry : dynamicRules) {
×
2033
    const auto& client = entry.first;
2034
    const auto& details = entry.second;
2035
    if (!(now < details.until)) {
×
2036
      continue;
2037
    }
2038

2039
    uint64_t counter = details.blocks;
2040
    if (g_defaultBPFFilter && details.bpf) {
×
2041
      counter += g_defaultBPFFilter->getHits(client.getNetwork());
2042
    }
2043
    list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
×
2044
  }
2045

2046
  auto count = list->d_entries.size();
2047
  *out = list.release();
2048
  return count;
2049
}
2050

2051
size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out)
2052
{
2053
  if (out == nullptr) {
×
2054
    return 0;
2055
  }
2056

2057
  auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
2058

2059
  timespec now{};
2060
  gettime(&now);
2061

2062
  const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
2063
  const auto& smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRules();
2064
  smtBlocks.visit([&now, &list, defaultAction](const SuffixMatchTree<DynBlock>& node) {
2065
    if (!(now < node.d_value.until)) {
×
2066
      return;
2067
    }
2068
    auto entry = node.d_value;
2069
    string key("empty");
2070
    if (!entry.domain.empty()) {
×
2071
      key = entry.domain.toString();
2072
    }
2073
    if (entry.action == DNSAction::Action::None) {
×
2074
      entry.action = defaultAction;
2075
    }
2076
    list->d_entries.push_back({strdup(key.c_str()), strdup(entry.reason.c_str()), entry.blocks, static_cast<uint64_t>(entry.until.tv_sec - now.tv_sec), static_cast<uint8_t>(entry.action), entry.bpf, entry.warning});
2077
  });
2078

2079
  auto count = list->d_entries.size();
2080
  *out = list.release();
2081
  return count;
2082
}
2083

2084
const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(const dnsdist_ffi_dynamic_blocks_list_t* list, size_t idx)
2085
{
2086
  if (list == nullptr) {
×
2087
    return nullptr;
2088
  }
2089

2090
  if (idx >= list->d_entries.size()) {
×
2091
    return nullptr;
2092
  }
2093

2094
  return &list->d_entries.at(idx);
2095
}
2096

2097
void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t* list)
2098
{
2099
  if (list == nullptr) {
×
2100
    return;
2101
  }
2102

2103
  for (auto& entry : list->d_entries) {
×
2104
    // NOLINTNEXTLINE(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc): this is a C API, RAII is not an option
2105
    free(entry.key);
2106
    // NOLINTNEXTLINE(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc): this is a C API, RAII is not an option
2107
    free(entry.reason);
2108
  }
2109

2110
  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): this is a C API, RAII is not an option
2111
  delete list;
2112
}
2113

2114
#endif /* DISABLE_DYNBLOCKS */
2115

2116
uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataSize, bool caseInsensitive)
2117
{
8✔
2118
  if (data == nullptr || dataSize == 0) {
8!
2119
    return seed;
4✔
2120
  }
4✔
2121

2122
  if (caseInsensitive) {
4✔
2123
    return burtleCI(data, dataSize, seed);
2✔
2124
  }
2✔
2125

2126
  return burtle(data, dataSize, seed);
2✔
2127
}
4✔
2128

2129
struct dnsdist_ffi_svc_record_parameters
2130
{
2131
  SVCRecordParameters parameters;
2132
};
2133

2134
bool dnsdist_ffi_svc_record_parameters_new(const char* targetName, uint16_t priority, bool noDefaultALPN, dnsdist_ffi_svc_record_parameters** out)
2135
{
20✔
2136
  if (targetName == nullptr || out == nullptr) {
20✔
2137
    return false;
4✔
2138
  }
4✔
2139
  try {
16✔
2140
    auto parameters = std::make_unique<dnsdist_ffi_svc_record_parameters>();
16✔
2141
    parameters->parameters.target = DNSName(targetName);
16✔
2142
    parameters->parameters.priority = priority;
16✔
2143
    parameters->parameters.noDefaultAlpn = noDefaultALPN;
16✔
2144
    *out = parameters.release();
16✔
2145
    return true;
16✔
2146
  }
16✔
2147
  catch (const std::exception& exp) {
16✔
2148
    errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.what());
×
2149
  }
×
2150
  catch (const PDNSException& exp) {
16✔
2151
    errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.reason);
×
2152
  }
×
2153
  catch (...) {
16✔
2154
    errlog("Exception in dnsdist_ffi_svc_record_parameters_new");
×
2155
  }
×
2156

2157
  return false;
×
2158
}
16✔
2159

2160
void dnsdist_ffi_svc_record_parameters_set_port(dnsdist_ffi_svc_record_parameters* parameters, uint16_t port)
2161
{
18✔
2162
  if (parameters == nullptr) {
18✔
2163
    return;
2✔
2164
  }
2✔
2165
  parameters->parameters.port = port;
16✔
2166
}
16✔
2167

2168
void dnsdist_ffi_svc_record_parameters_set_ech(dnsdist_ffi_svc_record_parameters* parameters, const char* ech, size_t echLen)
2169
{
4✔
2170
  if (parameters == nullptr || ech == nullptr || echLen == 0) {
4!
2171
    return;
2✔
2172
  }
2✔
2173
  parameters->parameters.ech = std::string(ech, echLen);
2✔
2174
}
2✔
2175

2176
void dnsdist_ffi_svc_record_parameters_set_additional_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key, const char* value, size_t valueLen)
2177
{
12✔
2178
  if (parameters == nullptr || (value == nullptr && valueLen != 0)) {
12!
2179
    return;
2✔
2180
  }
2✔
2181
  parameters->parameters.additionalParams.emplace_back(key, std::string(value, valueLen));
10✔
2182
}
10✔
2183

2184
void dnsdist_ffi_svc_record_parameters_add_mandatory_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key)
2185
{
18✔
2186
  if (parameters == nullptr) {
18✔
2187
    return;
2✔
2188
  }
2✔
2189
  parameters->parameters.mandatoryParams.insert(key);
16✔
2190
}
16✔
2191

2192
void dnsdist_ffi_svc_record_parameters_add_alpn(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
2193
{
20✔
2194
  if (parameters == nullptr || value == nullptr || valueLen == 0) {
20!
2195
    return;
4✔
2196
  }
4✔
2197
  parameters->parameters.alpns.emplace_back(value, valueLen);
16✔
2198
}
16✔
2199

2200
void dnsdist_ffi_svc_record_parameters_add_ipv4_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
2201
{
16✔
2202
  if (parameters == nullptr || value == nullptr || valueLen == 0) {
16!
2203
    return;
4✔
2204
  }
4✔
2205
  try {
12✔
2206
    parameters->parameters.ipv4hints.emplace_back(ComboAddress(std::string(value, valueLen)));
12✔
2207
  }
12✔
2208
  catch (const std::exception& exp) {
12✔
2209
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
×
2210
  }
×
2211
  catch (const PDNSException& exp) {
12✔
2212
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
×
2213
  }
×
2214
  catch (...) {
12✔
2215
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
×
2216
  }
×
2217
}
12✔
2218

2219
void dnsdist_ffi_svc_record_parameters_add_ipv6_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
2220
{
16✔
2221
  if (parameters == nullptr || value == nullptr || valueLen == 0) {
16!
2222
    return;
4✔
2223
  }
4✔
2224
  try {
12✔
2225
    parameters->parameters.ipv6hints.emplace_back(ComboAddress(std::string(value, valueLen)));
12✔
2226
  }
12✔
2227
  catch (const std::exception& exp) {
12✔
2228
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
×
2229
  }
×
2230
  catch (const PDNSException& exp) {
12✔
2231
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
×
2232
  }
×
2233
  catch (...) {
12✔
2234
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
×
2235
  }
×
2236
}
12✔
2237

2238
bool dnsdist_ffi_dnsquestion_generate_svc_response(dnsdist_ffi_dnsquestion_t* dnsQuestion, const dnsdist_ffi_svc_record_parameters** parametersList, size_t parametersListSize, uint32_t ttl)
2239
{
12✔
2240
  if (dnsQuestion == nullptr || parametersList == nullptr || parametersListSize == 0) {
12!
2241
    return false;
2✔
2242
  }
2✔
2243
  std::vector<SVCRecordParameters> parameters;
10✔
2244
  parameters.reserve(parametersListSize);
10✔
2245
  for (size_t idx = 0; idx < parametersListSize; idx++) {
26✔
2246
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
2247
    const auto* parameter = parametersList[idx];
16✔
2248
    if (parameter == nullptr) {
16!
2249
      return false;
×
2250
    }
×
2251
    parameters.push_back(parameter->parameters);
16✔
2252
  }
16✔
2253
  return dnsdist::svc::generateSVCResponse(*dnsQuestion->dq, ttl, parameters);
10✔
2254
}
10✔
2255

2256
void dnsdist_ffi_svc_record_parameters_free(dnsdist_ffi_svc_record_parameters* parameters)
2257
{
2✔
2258
  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): this is a C API, RAII is not an option
2259
  delete parameters;
2✔
2260
}
2✔
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