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

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

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

73.74
/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
{
25✔
42
  return dq->dq->ids.qtype;
25✔
43
}
25✔
44

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

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

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

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

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

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

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

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

99
  return 6;
×
100
}
6✔
101

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

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

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

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

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

127
const char* dnsdist_ffi_dnsquestion_get_incoming_interface(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
128
{
12✔
129
  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || dnsQuestion->dq->ids.cs == nullptr) {
12!
130
    return nullptr;
6✔
131
  }
6✔
132
  return dnsQuestion->dq->ids.cs->interface.c_str();
6✔
133
}
12✔
134

135
void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize)
136
{
207✔
137
  const auto& storage = dq->dq->ids.qname.getStorage();
207✔
138
  *qname = storage.data();
207✔
139
  *qnameSize = storage.size();
207✔
140
}
207✔
141

142
size_t dnsdist_ffi_dnsquestion_get_qname_hash(const dnsdist_ffi_dnsquestion_t* dq, size_t init)
143
{
3✔
144
  return dq->dq->ids.qname.hash(init);
3✔
145
}
3✔
146

147
int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq)
148
{
11✔
149
  return dq->dq->getHeader()->rcode;
11✔
150
}
11✔
151

152
void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
153
{
193✔
154
  return dq->dq->getMutableHeader();
193✔
155
}
193✔
156

157
uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
158
{
198✔
159
  return dq->dq->getData().size();
198✔
160
}
198✔
161

162
size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t* dq)
163
{
6✔
164
  return dq->dq->getData().size();
6✔
165
}
6✔
166

167
bool dnsdist_ffi_dnsquestion_set_size(dnsdist_ffi_dnsquestion_t* dq, size_t newSize)
168
{
6✔
169
  try {
6✔
170
    dq->dq->getMutableData().resize(newSize);
6✔
171
    return true;
6✔
172
  }
6✔
173
  catch (const std::exception& e) {
6✔
174
    return false;
3✔
175
  }
3✔
176
}
6✔
177

178
uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t* dq)
179
{
11✔
180
  return dq->dq->getHeader()->opcode;
11✔
181
}
11✔
182

183
bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t* dq)
184
{
7✔
185
  return dq->dq->overTCP();
7✔
186
}
7✔
187

188
dnsdist_ffi_protocol_type dnsdist_ffi_dnsquestion_get_protocol(const dnsdist_ffi_dnsquestion_t* dq)
189
{
24✔
190
  if (dq != nullptr) {
24✔
191
    auto proto = dq->dq->getProtocol();
21✔
192
    if (proto == dnsdist::Protocol::DoUDP) {
21✔
193
      return dnsdist_ffi_protocol_type_doudp;
6✔
194
    }
6✔
195
    else if (proto == dnsdist::Protocol::DoTCP) {
15✔
196
      return dnsdist_ffi_protocol_type_dotcp;
3✔
197
    }
3✔
198
    else if (proto == dnsdist::Protocol::DNSCryptUDP) {
12✔
199
      return dnsdist_ffi_protocol_type_dnscryptudp;
3✔
200
    }
3✔
201
    else if (proto == dnsdist::Protocol::DNSCryptTCP) {
9✔
202
      return dnsdist_ffi_protocol_type_dnscrypttcp;
3✔
203
    }
3✔
204
    else if (proto == dnsdist::Protocol::DoT) {
6✔
205
      return dnsdist_ffi_protocol_type_dot;
3✔
206
    }
3✔
207
    else if (proto == dnsdist::Protocol::DoH) {
3!
208
      return dnsdist_ffi_protocol_type_doh;
3✔
209
    }
3✔
210
  }
21✔
211
  return dnsdist_ffi_protocol_type_doudp;
3✔
212
}
24✔
213

214
bool dnsdist_ffi_dnsquestion_get_skip_cache(const dnsdist_ffi_dnsquestion_t* dq)
215
{
6✔
216
  return dq->dq->ids.skipCache;
6✔
217
}
6✔
218

219
bool dnsdist_ffi_dnsquestion_get_use_ecs(const dnsdist_ffi_dnsquestion_t* dq)
220
{
6✔
221
  return dq->dq->useECS;
6✔
222
}
6✔
223

224
bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* dq)
225
{
6✔
226
  return dq->dq->ecsOverride;
6✔
227
}
6✔
228

229
uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq)
230
{
6✔
231
  return dq->dq->ecsPrefixLength;
6✔
232
}
6✔
233

234
bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq)
235
{
9✔
236
  return dq->dq->ids.tempFailureTTL != boost::none;
9✔
237
}
9✔
238

239
uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquestion_t* dq)
240
{
6✔
241
  if (dq->dq->ids.tempFailureTTL) {
6✔
242
    return *dq->dq->ids.tempFailureTTL;
3✔
243
  }
3✔
244
  return 0;
3✔
245
}
6✔
246

247
bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
248
{
11✔
249
  return (dnsdist::getEDNSZ(*dnsQuestion->dq) & EDNS_HEADER_FLAG_DO) != 0;
11✔
250
}
11✔
251

252
uint8_t dnsdist_ffi_dnsquestion_get_edns_version(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
253
{
8✔
254
  auto version = dnsdist::getEDNSVersion(*dnsQuestion->dq);
8✔
255
  return version ? *version : 0U;
8!
256
}
8✔
257

258
uint8_t dnsdist_ffi_dnsquestion_get_edns_extended_rcode(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
259
{
8✔
260
  auto rcode = dnsdist::getEDNSExtendedRCode(*dnsQuestion->dq);
8✔
261
  return rcode ? *rcode : 0U;
8!
262
}
8✔
263

264
void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize)
265
{
3✔
266
  *sniSize = dq->dq->sni.size();
3✔
267
  *sni = dq->dq->sni.c_str();
3✔
268
}
3✔
269

270
const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t* dq, const char* label)
271
{
20✔
272
  const char* result = nullptr;
20✔
273

274
  if (dq != nullptr && dq->dq != nullptr && dq->dq->ids.qTag != nullptr) {
20!
275
    const auto it = dq->dq->ids.qTag->find(label);
11✔
276
    if (it != dq->dq->ids.qTag->cend()) {
11!
277
      result = it->second.c_str();
11✔
278
    }
11✔
279
  }
11✔
280

281
  return result;
20✔
282
}
20✔
283

284
size_t dnsdist_ffi_dnsquestion_get_tag_raw(const dnsdist_ffi_dnsquestion_t* dq, const char* label, char* buffer, size_t bufferSize)
285
{
21✔
286
  if (dq == nullptr || dq->dq == nullptr || dq->dq->ids.qTag == nullptr || label == nullptr || buffer == nullptr || bufferSize == 0) {
21!
287
    return 0;
6✔
288
  }
6✔
289

290
  const auto it = dq->dq->ids.qTag->find(label);
15✔
291
  if (it == dq->dq->ids.qTag->cend()) {
15✔
292
    return 0;
3✔
293
  }
3✔
294

295
  if (it->second.size() > bufferSize) {
12✔
296
    return 0;
3✔
297
  }
3✔
298

299
  memcpy(buffer, it->second.c_str(), it->second.size());
9✔
300
  return it->second.size();
9✔
301
}
12✔
302

303
const char* dnsdist_ffi_dnsquestion_get_http_path(dnsdist_ffi_dnsquestion_t* dq)
304
{
5✔
305
  if (!dq->httpPath) {
5!
306
    if (dq->dq->ids.du) {
5✔
307
#if defined(HAVE_DNS_OVER_HTTPS)
2✔
308
      dq->httpPath = dq->dq->ids.du->getHTTPPath();
2✔
309
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
310
    }
2✔
311
    else if (dq->dq->ids.doh3u) {
3!
312
#if defined(HAVE_DNS_OVER_HTTP3)
313
      dq->httpPath = dq->dq->ids.doh3u->getHTTPPath();
314
#endif /* HAVE_DNS_OVER_HTTP3 */
315
    }
×
316
  }
5✔
317
  if (dq->httpPath) {
5✔
318
    return dq->httpPath->c_str();
2✔
319
  }
2✔
320
  return nullptr;
3✔
321
}
5✔
322

323
const char* dnsdist_ffi_dnsquestion_get_http_query_string(dnsdist_ffi_dnsquestion_t* dq)
324
{
5✔
325
  if (!dq->httpQueryString) {
5!
326
    if (dq->dq->ids.du) {
5✔
327
#ifdef HAVE_DNS_OVER_HTTPS
2✔
328
      dq->httpQueryString = dq->dq->ids.du->getHTTPQueryString();
2✔
329
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
330
    }
2✔
331
    else if (dq->dq->ids.doh3u) {
3!
332
#if defined(HAVE_DNS_OVER_HTTP3)
333
      dq->httpQueryString = dq->dq->ids.doh3u->getHTTPQueryString();
334
#endif /* HAVE_DNS_OVER_HTTP3 */
335
    }
×
336
  }
5✔
337
  if (dq->httpQueryString) {
5✔
338
    return dq->httpQueryString->c_str();
2✔
339
  }
2✔
340
  return nullptr;
3✔
341
}
5✔
342

343
const char* dnsdist_ffi_dnsquestion_get_http_host(dnsdist_ffi_dnsquestion_t* dq)
344
{
5✔
345
  if (!dq->httpHost) {
5!
346
    if (dq->dq->ids.du) {
5✔
347
#ifdef HAVE_DNS_OVER_HTTPS
2✔
348
      dq->httpHost = dq->dq->ids.du->getHTTPHost();
2✔
349
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
350
    }
2✔
351
    else if (dq->dq->ids.doh3u) {
3!
352
#if defined(HAVE_DNS_OVER_HTTP3)
353
      dq->httpHost = dq->dq->ids.doh3u->getHTTPHost();
354
#endif /* HAVE_DNS_OVER_HTTP3 */
355
    }
×
356
  }
5✔
357
  if (dq->httpHost) {
5✔
358
    return dq->httpHost->c_str();
2✔
359
  }
2✔
360
  return nullptr;
3✔
361
}
5✔
362

363
const char* dnsdist_ffi_dnsquestion_get_http_scheme(dnsdist_ffi_dnsquestion_t* dq)
364
{
5✔
365
  if (!dq->httpScheme) {
5!
366
    if (dq->dq->ids.du) {
5✔
367
#ifdef HAVE_DNS_OVER_HTTPS
2✔
368
      dq->httpScheme = dq->dq->ids.du->getHTTPScheme();
2✔
369
#endif /* HAVE_DNS_OVER_HTTPS */
2✔
370
    }
2✔
371
    else if (dq->dq->ids.doh3u) {
3!
372
#if defined(HAVE_DNS_OVER_HTTP3)
373
      dq->httpScheme = dq->dq->ids.doh3u->getHTTPScheme();
374
#endif /* HAVE_DNS_OVER_HTTP3 */
375
    }
×
376
  }
5✔
377
  if (dq->httpScheme) {
5✔
378
    return dq->httpScheme->c_str();
2✔
379
  }
2✔
380
  return nullptr;
3✔
381
}
5✔
382

383
static void fill_edns_option(const EDNSOptionViewValue& value, dnsdist_ffi_ednsoption_t& option)
384
{
16✔
385
  option.len = value.size;
16✔
386
  option.data = nullptr;
16✔
387

388
  if (value.size > 0) {
16!
389
    option.data = value.content;
16✔
390
  }
16✔
391
}
16✔
392

393
// returns the length of the resulting 'out' array. 'out' is not set if the length is 0
394
size_t dnsdist_ffi_dnsquestion_get_edns_options(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_ednsoption_t** out)
395
{
12✔
396
  if (dq->dq->ednsOptions == nullptr) {
12!
397
    parseEDNSOptions(*(dq->dq));
12✔
398

399
    if (dq->dq->ednsOptions == nullptr) {
12!
400
      return 0;
×
401
    }
×
402
  }
12✔
403

404
  size_t totalCount = 0;
12✔
405
  for (const auto& option : *dq->dq->ednsOptions) {
14✔
406
    totalCount += option.second.values.size();
14✔
407
  }
14✔
408

409
  if (!dq->ednsOptionsVect) {
12!
410
    dq->ednsOptionsVect = std::make_unique<std::vector<dnsdist_ffi_ednsoption_t>>();
12✔
411
  }
12✔
412
  dq->ednsOptionsVect->clear();
12✔
413
  dq->ednsOptionsVect->resize(totalCount);
12✔
414
  size_t pos = 0;
12✔
415
  for (const auto& option : *dq->dq->ednsOptions) {
14✔
416
    for (const auto& entry : option.second.values) {
16✔
417
      fill_edns_option(entry, dq->ednsOptionsVect->at(pos));
16✔
418
      dq->ednsOptionsVect->at(pos).optionCode = option.first;
16✔
419
      pos++;
16✔
420
    }
16✔
421
  }
14✔
422

423
  if (totalCount > 0) {
12✔
424
    *out = dq->ednsOptionsVect->data();
10✔
425
  }
10✔
426

427
  return totalCount;
12✔
428
}
12✔
429

430
size_t dnsdist_ffi_dnsquestion_get_http_headers([[maybe_unused]] dnsdist_ffi_dnsquestion_t* ref, [[maybe_unused]] const dnsdist_ffi_http_header_t** out)
431
{
5✔
432
#if defined(HAVE_DNS_OVER_HTTPS) || defined(HAVE_DNS_OVER_HTTP3)
4✔
433
  const auto processHeaders = [&ref](const std::unordered_map<std::string, std::string>& headers) {
4✔
434
    if (headers.empty()) {
2!
435
      return;
436
    }
437
    ref->httpHeaders = std::make_unique<std::unordered_map<std::string, std::string>>(headers);
2✔
438
    if (!ref->httpHeadersVect) {
2!
439
      ref->httpHeadersVect = std::make_unique<std::vector<dnsdist_ffi_http_header_t>>();
2✔
440
    }
2✔
441
    ref->httpHeadersVect->clear();
2✔
442
    ref->httpHeadersVect->resize(ref->httpHeaders->size());
2✔
443
    size_t pos = 0;
2✔
444
    for (const auto& header : *ref->httpHeaders) {
11✔
445
      ref->httpHeadersVect->at(pos).name = header.first.c_str();
11✔
446
      ref->httpHeadersVect->at(pos).value = header.second.c_str();
11✔
447
      ++pos;
11✔
448
    }
11✔
449
  };
2✔
450

451
#if defined(HAVE_DNS_OVER_HTTPS)
4✔
452
  if (ref->dq->ids.du) {
4✔
453
    const auto& headers = ref->dq->ids.du->getHTTPHeaders();
2✔
454
    processHeaders(headers);
2✔
455
  }
2✔
456
#endif /* HAVE_DNS_OVER_HTTPS */
4✔
457
#if defined(HAVE_DNS_OVER_HTTP3)
4✔
458
  if (ref->dq->ids.doh3u) {
4!
459
    const auto& headers = ref->dq->ids.doh3u->getHTTPHeaders();
460
    processHeaders(headers);
461
  }
462
#endif /* HAVE_DNS_OVER_HTTP3 */
4✔
463

464
  if (!ref->httpHeadersVect) {
4✔
465
    return 0;
2✔
466
  }
2✔
467

468
  if (!ref->httpHeadersVect->empty()) {
2!
469
    *out = ref->httpHeadersVect->data();
2✔
470
  }
2✔
471
  return ref->httpHeadersVect->size();
2✔
472
#else /* HAVE_DNS_OVER_HTTPS || HAVE_DNS_OVER_HTTP3 */
473
  return 0;
1✔
474
#endif /* HAVE_DNS_OVER_HTTPS || HAVE_DNS_OVER_HTTP3 */
1✔
475
}
5✔
476

477
size_t dnsdist_ffi_dnsquestion_get_tag_array(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_tag_t** out)
478
{
6✔
479
  if (dq == nullptr || dq->dq == nullptr || dq->dq->ids.qTag == nullptr || dq->dq->ids.qTag->size() == 0) {
6!
480
    return 0;
3✔
481
  }
3✔
482

483
  if (!dq->tagsVect) {
3!
484
    dq->tagsVect = std::make_unique<std::vector<dnsdist_ffi_tag_t>>();
3✔
485
  }
3✔
486
  dq->tagsVect->clear();
3✔
487
  dq->tagsVect->resize(dq->dq->ids.qTag->size());
3✔
488
  size_t pos = 0;
3✔
489

490
  for (const auto& tag : *dq->dq->ids.qTag) {
3✔
491
    auto& entry = dq->tagsVect->at(pos);
3✔
492
    entry.name = tag.first.c_str();
3✔
493
    entry.value = tag.second.c_str();
3✔
494
    ++pos;
3✔
495
  }
3✔
496

497
  if (!dq->tagsVect->empty()) {
3!
498
    *out = dq->tagsVect->data();
3✔
499
  }
3✔
500

501
  return dq->tagsVect->size();
3✔
502
}
6✔
503

504
void dnsdist_ffi_dnsquestion_set_result(dnsdist_ffi_dnsquestion_t* dq, const char* str, size_t strSize)
505
{
10✔
506
  dq->result = std::string(str, strSize);
10✔
507
}
10✔
508

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

535
void dnsdist_ffi_dnsquestion_set_extended_dns_error(dnsdist_ffi_dnsquestion_t* dnsQuestion, uint16_t infoCode, const char* extraText, size_t extraTextSize)
536
{
4✔
537
  EDNSExtendedError ede;
4✔
538
  ede.infoCode = infoCode;
4✔
539
  if (extraText != nullptr && extraTextSize > 0) {
4!
540
    ede.extraText = std::string(extraText, extraTextSize);
2✔
541
  }
2✔
542
  dnsQuestion->dq->ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
4✔
543
}
4✔
544

545
void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
546
{
6✔
547
  dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [rcode](dnsheader& header) {
6✔
548
    header.rcode = rcode;
6✔
549
    header.qr = true;
6✔
550
    return true;
6✔
551
  });
6✔
552
}
6✔
553

554
void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
555
{
3✔
556
  dq->dq->getMutableData().resize(len);
3✔
557
}
3✔
558

559
void dnsdist_ffi_dnsquestion_set_skip_cache(dnsdist_ffi_dnsquestion_t* dq, bool skipCache)
560
{
3✔
561
  dq->dq->ids.skipCache = skipCache;
3✔
562
}
3✔
563

564
void dnsdist_ffi_dnsquestion_set_use_ecs(dnsdist_ffi_dnsquestion_t* dq, bool useECS)
565
{
3✔
566
  dq->dq->useECS = useECS;
3✔
567
}
3✔
568

569
void dnsdist_ffi_dnsquestion_set_ecs_override(dnsdist_ffi_dnsquestion_t* dq, bool ecsOverride)
570
{
3✔
571
  dq->dq->ecsOverride = ecsOverride;
3✔
572
}
3✔
573

574
void dnsdist_ffi_dnsquestion_set_ecs_prefix_length(dnsdist_ffi_dnsquestion_t* dq, uint16_t ecsPrefixLength)
575
{
3✔
576
  dq->dq->ecsPrefixLength = ecsPrefixLength;
3✔
577
}
3✔
578

579
void dnsdist_ffi_dnsquestion_set_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t tempFailureTTL)
580
{
3✔
581
  dq->dq->ids.tempFailureTTL = tempFailureTTL;
3✔
582
}
3✔
583

584
void dnsdist_ffi_dnsquestion_unset_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq)
585
{
3✔
586
  dq->dq->ids.tempFailureTTL = boost::none;
3✔
587
}
3✔
588

589
void dnsdist_ffi_dnsquestion_set_tag(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value)
590
{
11✔
591
  dq->dq->setTag(label, value);
11✔
592
}
11✔
593

594
void dnsdist_ffi_dnsquestion_set_tag_raw(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value, size_t valueSize)
595
{
7✔
596
  dq->dq->setTag(label, std::string(value, valueSize));
7✔
597
}
7✔
598

599
void dnsdist_ffi_dnsquestion_set_requestor_id(dnsdist_ffi_dnsquestion_t* dq, const char* value, size_t valueSize)
600
{
9✔
601
  if (!dq || !dq->dq || !value) {
9!
602
    return;
6✔
603
  }
6✔
604
  if (!dq->dq->ids.d_protoBufData) {
3!
605
    dq->dq->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
×
606
  }
×
607
  dq->dq->ids.d_protoBufData->d_requestorID = std::string(value, valueSize);
3✔
608
}
3✔
609

610
void dnsdist_ffi_dnsquestion_set_device_id(dnsdist_ffi_dnsquestion_t* dq, const char* value, size_t valueSize)
611
{
9✔
612
  if (!dq || !dq->dq || !value) {
9!
613
    return;
6✔
614
  }
6✔
615
  if (!dq->dq->ids.d_protoBufData) {
3!
616
    dq->dq->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
3✔
617
  }
3✔
618
  dq->dq->ids.d_protoBufData->d_deviceID = std::string(value, valueSize);
3✔
619
}
3✔
620

621
void dnsdist_ffi_dnsquestion_set_device_name(dnsdist_ffi_dnsquestion_t* dq, const char* value, size_t valueSize)
622
{
9✔
623
  if (!dq || !dq->dq || !value) {
9!
624
    return;
6✔
625
  }
6✔
626
  if (!dq->dq->ids.d_protoBufData) {
3!
627
    dq->dq->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
×
628
  }
×
629
  dq->dq->ids.d_protoBufData->d_deviceName = std::string(value, valueSize);
3✔
630
}
3✔
631

632
size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out)
633
{
6✔
634
  dq->trailingData = dq->dq->getTrailingData();
6✔
635
  if (!dq->trailingData.empty()) {
6✔
636
    *out = dq->trailingData.data();
3✔
637
  }
3✔
638

639
  return dq->trailingData.size();
6✔
640
}
6✔
641

642
bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen)
643
{
3✔
644
  return dq->dq->setTrailingData(std::string(data, dataLen));
3✔
645
}
3✔
646

647
void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen)
648
{
×
649
  if (g_snmpAgent != nullptr && dnsdist::configuration::getImmutableConfiguration().d_snmpTrapsEnabled) {
×
650
    g_snmpAgent->sendDNSTrap(*dq->dq, std::string(reason, reasonLen));
×
651
  }
×
652
}
×
653

654
void dnsdist_ffi_dnsquestion_spoof_packet(dnsdist_ffi_dnsquestion_t* dq, const char* raw, size_t len)
655
{
2✔
656
  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
657
  dnsdist::self_answers::generateAnswerFromRawPacket(*dq->dq, PacketBuffer(raw, raw + len));
2✔
658
}
2✔
659

660
void dnsdist_ffi_dnsquestion_spoof_raw(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
661
{
4✔
662
  std::vector<std::string> data;
4✔
663
  data.reserve(valuesCount);
4✔
664

665
  for (size_t idx = 0; idx < valuesCount; idx++) {
12✔
666
    data.emplace_back(values[idx].value, values[idx].size);
8✔
667
  }
8✔
668

669
  dnsdist::ResponseConfig config{};
4✔
670
  dnsdist::self_answers::generateAnswerFromRDataEntries(*dq->dq, data, std::nullopt, config);
4✔
671
}
4✔
672

673
void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
674
{
3✔
675
  std::vector<ComboAddress> data;
3✔
676
  data.reserve(valuesCount);
3✔
677

678
  for (size_t idx = 0; idx < valuesCount; idx++) {
9✔
679
    if (values[idx].size == 4) {
6✔
680
      sockaddr_in sin;
3✔
681
      sin.sin_family = AF_INET;
3✔
682
      sin.sin_port = 0;
3✔
683
      memcpy(&sin.sin_addr.s_addr, values[idx].value, sizeof(sin.sin_addr.s_addr));
3✔
684
      data.emplace_back(&sin);
3✔
685
    }
3✔
686
    else if (values[idx].size == 16) {
3!
687
      sockaddr_in6 sin6;
3✔
688
      sin6.sin6_family = AF_INET6;
3✔
689
      sin6.sin6_port = 0;
3✔
690
      sin6.sin6_scope_id = 0;
3✔
691
      sin6.sin6_flowinfo = 0;
3✔
692
      memcpy(&sin6.sin6_addr.s6_addr, values[idx].value, sizeof(sin6.sin6_addr.s6_addr));
3✔
693
      data.emplace_back(&sin6);
3✔
694
    }
3✔
695
  }
6✔
696

697
  dnsdist::ResponseConfig config{};
3✔
698
  dnsdist::self_answers::generateAnswerFromIPAddresses(*dq->dq, data, config);
3✔
699
}
3✔
700

701
void dnsdist_ffi_dnsquestion_set_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t max)
702
{
3✔
703
  if (dq != nullptr && dq->dq != nullptr) {
3!
704
    dq->dq->ids.ttlCap = max;
3✔
705
  }
3✔
706
}
3✔
707

708
bool dnsdist_ffi_dnsquestion_set_restartable(dnsdist_ffi_dnsquestion_t* dq)
709
{
6✔
710
  if (dq == nullptr || dq->dq == nullptr) {
6!
711
    return false;
3✔
712
  }
3✔
713

714
  dq->dq->ids.d_packet = std::make_unique<PacketBuffer>(dq->dq->getData());
3✔
715
  return true;
3✔
716
}
6✔
717

718
size_t dnsdist_ffi_servers_list_get_count(const dnsdist_ffi_servers_list_t* list)
719
{
22✔
720
  return list->ffiServers.size();
22✔
721
}
22✔
722

723
void dnsdist_ffi_servers_list_get_server(const dnsdist_ffi_servers_list_t* list, size_t idx, const dnsdist_ffi_server_t** out)
724
{
×
725
  *out = &list->ffiServers.at(idx);
×
726
}
×
727

728
size_t dnsdist_ffi_servers_list_chashed(const dnsdist_ffi_servers_list_t* list, const dnsdist_ffi_dnsquestion_t* dq, size_t hash)
729
{
×
730
  (void)dq;
×
731
  auto serverPosition = chashedFromHash(list->servers, hash);
×
732
  if (!serverPosition) {
×
733
    throw std::runtime_error("Unable to find servers in server list");
×
734
  }
×
735
  return *serverPosition;
×
736
}
×
737

738
size_t dnsdist_ffi_servers_list_whashed(const dnsdist_ffi_servers_list_t* list, const dnsdist_ffi_dnsquestion_t* dq, size_t hash)
739
{
×
740
  (void)dq;
×
741
  auto serverPosition = whashedFromHash(list->servers, hash);
×
742
  if (!serverPosition) {
×
743
    throw std::runtime_error("Unable to find servers in server list");
×
744
  }
×
745
  return *serverPosition;
×
746
}
×
747

748
uint64_t dnsdist_ffi_server_get_outstanding(const dnsdist_ffi_server_t* server)
749
{
3✔
750
  return server->server->outstanding;
3✔
751
}
3✔
752

753
int dnsdist_ffi_server_get_weight(const dnsdist_ffi_server_t* server)
754
{
3✔
755
  return server->server->d_config.d_weight;
3✔
756
}
3✔
757

758
int dnsdist_ffi_server_get_order(const dnsdist_ffi_server_t* server)
759
{
3✔
760
  return server->server->d_config.order;
3✔
761
}
3✔
762

763
double dnsdist_ffi_server_get_latency(const dnsdist_ffi_server_t* server)
764
{
3✔
765
  return server->server->getRelevantLatencyUsec();
3✔
766
}
3✔
767

768
bool dnsdist_ffi_server_is_up(const dnsdist_ffi_server_t* server)
769
{
3✔
770
  return server->server->isUp();
3✔
771
}
3✔
772

773
const char* dnsdist_ffi_server_get_name(const dnsdist_ffi_server_t* server)
774
{
3✔
775
  return server->server->getName().c_str();
3✔
776
}
3✔
777

778
const char* dnsdist_ffi_server_get_name_with_addr(const dnsdist_ffi_server_t* server)
779
{
3✔
780
  return server->server->getNameWithAddr().c_str();
3✔
781
}
3✔
782

783
void dnsdist_ffi_dnsresponse_set_min_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t min)
784
{
3✔
785
  dnsdist_ffi_dnsresponse_limit_ttl(dr, min, std::numeric_limits<uint32_t>::max());
3✔
786
}
3✔
787

788
void dnsdist_ffi_dnsresponse_set_max_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t max)
789
{
3✔
790
  dnsdist_ffi_dnsresponse_limit_ttl(dr, 0, max);
3✔
791
}
3✔
792

793
void dnsdist_ffi_dnsresponse_limit_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t min, uint32_t max)
794
{
9✔
795
  if (dr != nullptr && dr->dr != nullptr) {
9!
796
    dnsdist::PacketMangling::restrictDNSPacketTTLs(dr->dr->getMutableData(), min, max);
9✔
797
  }
9✔
798
}
9✔
799

800
void dnsdist_ffi_dnsresponse_set_max_returned_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t max)
801
{
3✔
802
  if (dr != nullptr && dr->dr != nullptr) {
3!
803
    dr->dr->ids.ttlCap = max;
3✔
804
  }
3✔
805
}
3✔
806

807
void dnsdist_ffi_dnsresponse_clear_records_type(dnsdist_ffi_dnsresponse_t* dr, uint16_t qtype)
808
{
8✔
809
  if (dr != nullptr && dr->dr != nullptr) {
8!
810
    clearDNSPacketRecordTypes(dr->dr->getMutableData(), std::unordered_set<QType>{qtype});
5✔
811
  }
5✔
812
}
8✔
813

814
bool dnsdist_ffi_dnsresponse_rebase(dnsdist_ffi_dnsresponse_t* dr, const char* initialName, size_t initialNameSize)
815
{
11✔
816
  if (dr == nullptr || dr->dr == nullptr || initialName == nullptr || initialNameSize == 0) {
11!
817
    return false;
3✔
818
  }
3✔
819

820
  try {
8✔
821
    DNSName parsed(initialName, initialNameSize, 0, false);
8✔
822

823
    if (!dnsdist::changeNameInDNSPacket(dr->dr->getMutableData(), dr->dr->ids.qname, parsed)) {
8!
824
      return false;
×
825
    }
×
826

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

836
  return true;
5✔
837
}
8✔
838

839
bool dnsdist_ffi_dnsresponse_get_stale_cache_hit(const dnsdist_ffi_dnsresponse_t* dnsResponse)
840
{
3✔
841
  return dnsResponse->dr->ids.staleCacheHit;
3✔
842
}
3✔
843

844
uint8_t dnsdist_ffi_dnsresponse_get_restart_count(const dnsdist_ffi_dnsresponse_t* dnsResponse)
845
{
3✔
846
  return dnsResponse->dr->ids.restartCount;
3✔
847
}
3✔
848

849
bool dnsdist_ffi_dnsquestion_set_async(dnsdist_ffi_dnsquestion_t* dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
850
{
101✔
851
  try {
101✔
852
    dq->dq->asynchronous = true;
101✔
853
    return dnsdist::suspendQuery(*dq->dq, asyncID, queryID, timeoutMs);
101✔
854
  }
101✔
855
  catch (const std::exception& e) {
101✔
856
    vinfolog("Error in dnsdist_ffi_dnsquestion_set_async: %s", e.what());
×
857
  }
×
858
  catch (...) {
101✔
859
    vinfolog("Exception in dnsdist_ffi_dnsquestion_set_async");
×
860
  }
×
861

862
  return false;
×
863
}
101✔
864

865
bool dnsdist_ffi_dnsresponse_set_async(dnsdist_ffi_dnsquestion_t* dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
866
{
83✔
867
  try {
83✔
868
    dq->dq->asynchronous = true;
83✔
869
    auto dr = dynamic_cast<DNSResponse*>(dq->dq);
83✔
870
    if (!dr) {
83!
871
      vinfolog("Passed a DNSQuestion instead of a DNSResponse to dnsdist_ffi_dnsresponse_set_async");
×
872
      return false;
×
873
    }
×
874

875
    return dnsdist::suspendResponse(*dr, asyncID, queryID, timeoutMs);
83✔
876
  }
83✔
877
  catch (const std::exception& e) {
83✔
878
    vinfolog("Error in dnsdist_ffi_dnsresponse_set_async: %s", e.what());
×
879
  }
×
880
  catch (...) {
83✔
881
    vinfolog("Exception in dnsdist_ffi_dnsresponse_set_async");
×
882
  }
×
883
  return false;
×
884
}
83✔
885

886
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)
887
{
104✔
888
  if (!dnsdist::g_asyncHolder) {
104!
889
    vinfolog("Unable to resume, no asynchronous holder");
×
890
    return false;
×
891
  }
×
892

893
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
104✔
894
  if (!query) {
104!
895
    vinfolog("Unable to resume, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
896
    return false;
×
897
  }
×
898

899
  auto& ids = query->query.d_idstate;
104✔
900
  if (tag != nullptr && tagSize > 0) {
104!
901
    if (!ids.qTag) {
104✔
902
      ids.qTag = std::make_unique<QTag>();
83✔
903
    }
83✔
904
    (*ids.qTag)[std::string(tag, tagSize)] = std::string(tagValue, tagValueSize);
104✔
905
  }
104✔
906

907
  ids.skipCache = !useCache;
104✔
908

909
  return dnsdist::queueQueryResumptionEvent(std::move(query));
104✔
910
}
104✔
911

912
bool dnsdist_ffi_set_rcode_from_async(uint16_t asyncID, uint16_t queryID, uint8_t rcode, bool clearAnswers)
913
{
18✔
914
  if (!dnsdist::g_asyncHolder) {
18!
915
    return false;
×
916
  }
×
917

918
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
18✔
919
  if (!query) {
18!
920
    vinfolog("Unable to resume with a custom response code, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
921
    return false;
×
922
  }
×
923

924
  if (!dnsdist::setInternalQueryRCode(query->query.d_idstate, query->query.d_buffer, rcode, clearAnswers)) {
18!
925
    return false;
×
926
  }
×
927

928
  query->query.d_idstate.skipCache = true;
18✔
929

930
  return dnsdist::queueQueryResumptionEvent(std::move(query));
18✔
931
}
18✔
932

933
static bool setAlternateName(PacketBuffer& packet, InternalQueryState& ids, std::string_view alternateName, std::string_view tag, std::string_view tagValue, std::string_view formerNameTagName)
934
{
11✔
935
  const DNSName originalName = ids.qname;
11✔
936
  try {
11✔
937
    DNSName parsed(alternateName.data(), alternateName.size(), 0, false);
11✔
938

939
    // edit qname in query packet
940
    if (!dnsdist::changeNameInDNSPacket(packet, originalName, parsed)) {
11!
941
      return false;
×
942
    }
×
943
    if (ids.d_packet) {
11!
944
      *ids.d_packet = packet;
×
945
    }
×
946
    // set qname to new one
947
    ids.qname = std::move(parsed);
11✔
948
  }
11✔
949
  catch (const std::exception& e) {
11✔
950
    vinfolog("Error rebasing packet on a new DNSName: %s", e.what());
×
951
    return false;
×
952
  }
×
953

954
  // save existing qname in tag
955
  if (!formerNameTagName.empty()) {
11✔
956
    if (!ids.qTag) {
5!
957
      ids.qTag = std::make_unique<QTag>();
5✔
958
    }
5✔
959
    (*ids.qTag)[std::string(formerNameTagName)] = originalName.getStorage();
5✔
960
  }
5✔
961

962
  if (!tag.empty()) {
11✔
963
    if (!ids.qTag) {
8!
964
      ids.qTag = std::make_unique<QTag>();
×
965
    }
×
966
    (*ids.qTag)[std::string(tag)] = tagValue;
8✔
967
  }
8✔
968

969
  ids.skipCache = true;
11✔
970
  return true;
11✔
971
}
11✔
972

973
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)
974
{
×
975
  if (!dnsdist::g_asyncHolder) {
×
976
    return false;
×
977
  }
×
978

979
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
×
980
  if (!query) {
×
981
    vinfolog("Unable to resume with an alternate name, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
982
    return false;
×
983
  }
×
984

985
  auto& ids = query->query.d_idstate;
×
986
  PacketBuffer packet;
×
987
  if (query->d_isResponse) {
×
988
    if (!ids.d_packet) {
×
989
      return false;
×
990
    }
×
991
    packet = std::move(*ids.d_packet);
×
992
  }
×
993
  else {
×
994
    packet = std::move(query->query.d_buffer);
×
995
  }
×
996

997
  auto wasOK = setAlternateName(packet, ids, std::string_view(alternateName, alternateNameSize), std::string_view(tag, tagSize), std::string_view(tagValue, tagValueSize), std::string_view(formerNameTagName, formerNameTagSize));
×
998
  if (!wasOK) {
×
999
    return false;
×
1000
  }
×
1001

1002
  if (query->d_isResponse) {
×
1003
    query->d_isResponse = false;
×
1004
  }
×
1005
  query->query.d_buffer = std::move(packet);
×
1006

1007
  // resume as query
1008
  return dnsdist::queueQueryResumptionEvent(std::move(query));
×
1009
}
×
1010

1011
bool dnsdist_ffi_dnsquestion_set_alternate_name(dnsdist_ffi_dnsquestion_t* dnsQuestion, const char* alternateName, size_t alternateNameSize, const char* tag, size_t tagSize, const char* tagValue, size_t tagValueSize, const char* formerNameTagName, size_t formerNameTagSize)
1012
{
20✔
1013
  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || alternateName == nullptr || alternateNameSize == 0) {
20!
1014
    return false;
9✔
1015
  }
9✔
1016

1017
  auto& ids = dnsQuestion->dq->ids;
11✔
1018
  auto& packet = dnsQuestion->dq->getMutableData();
11✔
1019
  return setAlternateName(packet, ids, std::string_view(alternateName, alternateNameSize), std::string_view(tag, tagSize), std::string_view(tagValue, tagValueSize), std::string_view(formerNameTagName, formerNameTagSize));
11✔
1020
}
20✔
1021

1022
bool dnsdist_ffi_drop_from_async(uint16_t asyncID, uint16_t queryID)
1023
{
18✔
1024
  if (!dnsdist::g_asyncHolder) {
18!
1025
    return false;
×
1026
  }
×
1027

1028
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
18✔
1029
  if (!query) {
18!
1030
    vinfolog("Unable to drop, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
1031
    return false;
×
1032
  }
×
1033

1034
  auto sender = query->getTCPQuerySender();
18✔
1035
  if (!sender) {
18!
1036
    return false;
×
1037
  }
×
1038

1039
  struct timeval now;
18✔
1040
  gettimeofday(&now, nullptr);
18✔
1041
  TCPResponse tresponse(std::move(query->query));
18✔
1042
  sender->notifyIOError(now, std::move(tresponse));
18✔
1043

1044
  return true;
18✔
1045
}
18✔
1046

1047
bool dnsdist_ffi_set_answer_from_async(uint16_t asyncID, uint16_t queryID, const char* raw, size_t rawSize)
1048
{
18✔
1049
  if (rawSize < sizeof(dnsheader)) {
18!
1050
    return false;
×
1051
  }
×
1052
  if (!dnsdist::g_asyncHolder) {
18!
1053
    return false;
×
1054
  }
×
1055

1056
  auto query = dnsdist::g_asyncHolder->get(asyncID, queryID);
18✔
1057
  if (!query) {
18!
1058
    vinfolog("Unable to resume with a custom answer, no object found for asynchronous ID %d and query ID %d", asyncID, queryID);
×
1059
    return false;
×
1060
  }
×
1061

1062
  dnsheader_aligned alignedHeader(query->query.d_buffer.data());
18✔
1063
  auto oldID = alignedHeader->id;
18✔
1064
  query->query.d_buffer.clear();
18✔
1065
  query->query.d_buffer.insert(query->query.d_buffer.begin(), raw, raw + rawSize);
18✔
1066

1067
  dnsdist::PacketMangling::editDNSHeaderFromPacket(query->query.d_buffer, [oldID](dnsheader& header) {
18✔
1068
    header.id = oldID;
18✔
1069
    return true;
18✔
1070
  });
18✔
1071
  query->query.d_idstate.skipCache = true;
18✔
1072

1073
  return dnsdist::queueQueryResumptionEvent(std::move(query));
18✔
1074
}
18✔
1075

1076
static constexpr char s_lua_ffi_code[] = R"FFICodeContent(
1077
  local ffi = require("ffi")
1078
  local C = ffi.C
1079

1080
  ffi.cdef[[
1081
)FFICodeContent"
1082
#include "dnsdist-lua-ffi-interface.inc"
1083
                                         R"FFICodeContent(
1084
  ]]
1085

1086
)FFICodeContent";
1087

1088
const char* getLuaFFIWrappers()
1089
{
827✔
1090
  return s_lua_ffi_code;
827✔
1091
}
827✔
1092

1093
void setupLuaLoadBalancingContext(LuaContext& luaCtx)
1094
{
4✔
1095
  setupLuaBindings(luaCtx, true, false);
4✔
1096
  setupLuaBindingsDNSQuestion(luaCtx);
4✔
1097
  setupLuaBindingsLogging(luaCtx);
4✔
1098
  setupLuaBindingsKVS(luaCtx, true);
4✔
1099
  setupLuaVars(luaCtx);
4✔
1100

1101
#ifdef LUAJIT_VERSION
4✔
1102
  luaCtx.executeCode(getLuaFFIWrappers());
4✔
1103
#endif
4✔
1104
}
4✔
1105

1106
void setupLuaFFIPerThreadContext(LuaContext& luaCtx)
1107
{
9✔
1108
  setupLuaVars(luaCtx);
9✔
1109
  setupLuaBindingsLogging(luaCtx);
9✔
1110

1111
#ifdef LUAJIT_VERSION
9✔
1112
  luaCtx.executeCode(getLuaFFIWrappers());
9✔
1113
#endif
9✔
1114
}
9✔
1115

1116
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)
1117
{
9✔
1118
  try {
9✔
1119
    ComboAddress src, dst;
9✔
1120
    if (addrSize != sizeof(src.sin4.sin_addr) && addrSize != sizeof(src.sin6.sin6_addr.s6_addr)) {
9!
1121
      return 0;
3✔
1122
    }
3✔
1123

1124
    src = makeComboAddressFromRaw(addrSize == sizeof(src.sin4.sin_addr) ? 4 : 6, reinterpret_cast<const char*>(srcAddr), addrSize);
6!
1125
    src.sin4.sin_port = htons(srcPort);
6✔
1126
    dst = makeComboAddressFromRaw(addrSize == sizeof(dst.sin4.sin_addr) ? 4 : 6, reinterpret_cast<const char*>(dstAddr), addrSize);
6!
1127
    dst.sin4.sin_port = htons(dstPort);
6✔
1128

1129
    std::vector<ProxyProtocolValue> valuesVect;
6✔
1130
    if (valuesCount > 0) {
6!
1131
      valuesVect.reserve(valuesCount);
6✔
1132
      for (size_t idx = 0; idx < valuesCount; idx++) {
12✔
1133
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1134
        valuesVect.push_back({std::string(values[idx].value, values[idx].size), values[idx].type});
6✔
1135
      }
6✔
1136
    }
6✔
1137

1138
    std::string payload = makeProxyHeader(tcp, src, dst, valuesVect);
6✔
1139
    if (payload.size() > outSize) {
6✔
1140
      return 0;
3✔
1141
    }
3✔
1142

1143
    memcpy(out, payload.c_str(), payload.size());
3✔
1144

1145
    return payload.size();
3✔
1146
  }
6✔
1147
  catch (const std::exception& e) {
9✔
1148
    vinfolog("Exception in dnsdist_ffi_generate_proxy_protocol_payload: %s", e.what());
×
1149
    return 0;
×
1150
  }
×
1151
  catch (...) {
9✔
1152
    vinfolog("Unhandled exception in dnsdist_ffi_generate_proxy_protocol_payload");
×
1153
    return 0;
×
1154
  }
×
1155
}
9✔
1156

1157
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)
1158
{
×
1159
  std::vector<ProxyProtocolValue> valuesVect;
×
1160
  if (valuesCount > 0) {
×
1161
    valuesVect.reserve(valuesCount);
×
1162
    for (size_t idx = 0; idx < valuesCount; idx++) {
×
1163
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1164
      valuesVect.push_back({std::string(values[idx].value, values[idx].size), values[idx].type});
×
1165
    }
×
1166
  }
×
1167

1168
  std::string payload = makeProxyHeader(dq->dq->overTCP(), dq->dq->ids.origRemote, dq->dq->ids.origDest, valuesVect);
×
1169
  if (payload.size() > outSize) {
×
1170
    return 0;
×
1171
  }
×
1172

1173
  memcpy(out, payload.c_str(), payload.size());
×
1174

1175
  return payload.size();
×
1176
}
×
1177

1178
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)
1179
{
12✔
1180
  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || values == nullptr || valuesCount == 0) {
12!
1181
    return false;
9✔
1182
  }
9✔
1183

1184
  if (!dnsQuestion->dq->proxyProtocolValues) {
3!
1185
    dnsQuestion->dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
3✔
1186
  }
3✔
1187

1188
  dnsQuestion->dq->proxyProtocolValues->reserve(dnsQuestion->dq->proxyProtocolValues->size() + valuesCount);
3✔
1189
  for (size_t idx = 0; idx < valuesCount; idx++) {
6✔
1190
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): the Lua FFI API is a C API..
1191
    dnsQuestion->dq->proxyProtocolValues->push_back({std::string(values[idx].value, values[idx].size), values[idx].type});
3✔
1192
  }
3✔
1193

1194
  return true;
3✔
1195
}
12✔
1196

1197
size_t dnsdist_ffi_dnsquestion_get_proxy_protocol_values(dnsdist_ffi_dnsquestion_t* dnsQuestion, const dnsdist_ffi_proxy_protocol_value_t** out)
1198
{
14✔
1199
  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || !dnsQuestion->dq->proxyProtocolValues) {
14!
1200
    return 0;
9✔
1201
  }
9✔
1202

1203
  if (out == nullptr) {
5!
1204
    return dnsQuestion->proxyProtocolValuesVect->size();
×
1205
  }
×
1206

1207
  dnsQuestion->proxyProtocolValuesVect = std::make_unique<std::vector<dnsdist_ffi_proxy_protocol_value_t>>(dnsQuestion->dq->proxyProtocolValues->size());
5✔
1208
  for (size_t counter = 0; counter < dnsQuestion->dq->proxyProtocolValues->size(); ++counter) {
18✔
1209
    const auto& entry = dnsQuestion->dq->proxyProtocolValues->at(counter);
13✔
1210
    auto& targetEntry = dnsQuestion->proxyProtocolValuesVect->at(counter);
13✔
1211
    targetEntry.size = entry.content.size();
13✔
1212
    targetEntry.value = entry.content.data();
13✔
1213
    targetEntry.type = entry.type;
13✔
1214
  }
13✔
1215

1216
  *out = dnsQuestion->proxyProtocolValuesVect->data();
5✔
1217
  return dnsQuestion->proxyProtocolValuesVect->size();
5✔
1218
}
5✔
1219

1220
struct dnsdist_ffi_domain_list_t
1221
{
1222
  std::vector<std::string> d_domains;
1223
};
1224
struct dnsdist_ffi_address_list_t
1225
{
1226
  std::vector<std::string> d_addresses;
1227
};
1228

1229
const char* dnsdist_ffi_domain_list_get(const dnsdist_ffi_domain_list_t* list, size_t idx)
1230
{
9✔
1231
  if (list == nullptr || idx >= list->d_domains.size()) {
9✔
1232
    return nullptr;
6✔
1233
  }
6✔
1234

1235
  return list->d_domains.at(idx).c_str();
3✔
1236
}
9✔
1237

1238
void dnsdist_ffi_domain_list_free(dnsdist_ffi_domain_list_t* list)
1239
{
3✔
1240
  delete list;
3✔
1241
}
3✔
1242

1243
const char* dnsdist_ffi_address_list_get(const dnsdist_ffi_address_list_t* list, size_t idx)
1244
{
9✔
1245
  if (list == nullptr || idx >= list->d_addresses.size()) {
9✔
1246
    return nullptr;
6✔
1247
  }
6✔
1248

1249
  return list->d_addresses.at(idx).c_str();
3✔
1250
}
9✔
1251

1252
void dnsdist_ffi_address_list_free(dnsdist_ffi_address_list_t* list)
1253
{
3✔
1254
  delete list;
3✔
1255
}
3✔
1256

1257
size_t dnsdist_ffi_packetcache_get_domain_list_by_addr(const char* poolName, const char* addr, dnsdist_ffi_domain_list_t** out)
1258
{
18✔
1259
  if (poolName == nullptr || addr == nullptr || out == nullptr) {
18!
1260
    return 0;
3✔
1261
  }
3✔
1262

1263
  ComboAddress ca;
15✔
1264
  try {
15✔
1265
    ca = ComboAddress(addr);
15✔
1266
  }
15✔
1267
  catch (const std::exception& e) {
15✔
1268
    vinfolog("Error parsing address passed to dnsdist_ffi_packetcache_get_domain_list_by_addr: %s", e.what());
×
1269
    return 0;
×
1270
  }
×
1271
  catch (const PDNSException& e) {
15✔
1272
    vinfolog("Error parsing address passed to dnsdist_ffi_packetcache_get_domain_list_by_addr: %s", e.reason);
3!
1273
    return 0;
3✔
1274
  }
3✔
1275

1276
  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
12✔
1277
  auto poolIt = pools.find(poolName);
12✔
1278
  if (poolIt == pools.end()) {
12✔
1279
    return 0;
3✔
1280
  }
3✔
1281

1282
  const auto& pool = poolIt->second;
9✔
1283
  if (!pool.packetCache) {
9✔
1284
    return 0;
3✔
1285
  }
3✔
1286

1287
  auto domains = pool.packetCache->getDomainsContainingRecords(ca);
6✔
1288
  if (domains.size() == 0) {
6✔
1289
    return 0;
3✔
1290
  }
3✔
1291

1292
  auto list = std::make_unique<dnsdist_ffi_domain_list_t>();
3✔
1293
  list->d_domains.reserve(domains.size());
3✔
1294
  for (const auto& domain : domains) {
3✔
1295
    try {
3✔
1296
      list->d_domains.push_back(domain.toString());
3✔
1297
    }
3✔
1298
    catch (const std::exception& e) {
3✔
1299
      vinfolog("Error converting domain to string in dnsdist_ffi_packetcache_get_domain_list_by_addr: %s", e.what());
×
1300
    }
×
1301
  }
3✔
1302

1303
  size_t count = list->d_domains.size();
3✔
1304
  if (count > 0) {
3!
1305
    *out = list.release();
3✔
1306
  }
3✔
1307
  return count;
3✔
1308
}
3✔
1309

1310
size_t dnsdist_ffi_packetcache_get_address_list_by_domain(const char* poolName, const char* domain, dnsdist_ffi_address_list_t** out)
1311
{
18✔
1312
  if (poolName == nullptr || domain == nullptr || out == nullptr) {
18!
1313
    return 0;
3✔
1314
  }
3✔
1315

1316
  DNSName name;
15✔
1317
  try {
15✔
1318
    name = DNSName(domain);
15✔
1319
  }
15✔
1320
  catch (const std::exception& e) {
15✔
1321
    vinfolog("Error parsing domain passed to dnsdist_ffi_packetcache_get_address_list_by_domain: %s", e.what());
3!
1322
    return 0;
3✔
1323
  }
3✔
1324

1325
  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
12✔
1326
  auto poolIt = pools.find(poolName);
12✔
1327
  if (poolIt == pools.end()) {
12✔
1328
    return 0;
3✔
1329
  }
3✔
1330

1331
  const auto& pool = poolIt->second;
9✔
1332
  if (!pool.packetCache) {
9✔
1333
    return 0;
3✔
1334
  }
3✔
1335

1336
  auto addresses = pool.packetCache->getRecordsForDomain(name);
6✔
1337
  if (addresses.size() == 0) {
6✔
1338
    return 0;
3✔
1339
  }
3✔
1340

1341
  auto list = std::make_unique<dnsdist_ffi_address_list_t>();
3✔
1342
  list->d_addresses.reserve(addresses.size());
3✔
1343
  for (const auto& addr : addresses) {
3✔
1344
    try {
3✔
1345
      list->d_addresses.push_back(addr.toString());
3✔
1346
    }
3✔
1347
    catch (const std::exception& e) {
3✔
1348
      vinfolog("Error converting address to string in dnsdist_ffi_packetcache_get_address_list_by_domain: %s", e.what());
×
1349
    }
×
1350
  }
3✔
1351

1352
  size_t count = list->d_addresses.size();
3✔
1353
  if (count > 0) {
3!
1354
    *out = list.release();
3✔
1355
  }
3✔
1356
  return count;
3✔
1357
}
3✔
1358

1359
struct dnsdist_ffi_ring_entry_list_t
1360
{
1361
  struct entry
1362
  {
1363
    std::string qname;
1364
    std::string requestor;
1365
    std::string macAddr;
1366
    std::string ds;
1367
    dnsheader dh;
1368
    double age;
1369
    unsigned int latency;
1370
    uint16_t size;
1371
    uint16_t qtype;
1372
    dnsdist::Protocol protocol;
1373
    bool isResponse;
1374
  };
1375

1376
  std::vector<entry> d_entries;
1377
};
1378

1379
bool dnsdist_ffi_ring_entry_is_response(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1380
{
15✔
1381
  if (list == nullptr || idx >= list->d_entries.size()) {
15!
1382
    return false;
3✔
1383
  }
3✔
1384

1385
  return list->d_entries.at(idx).isResponse;
12✔
1386
}
15✔
1387

1388
double dnsdist_ffi_ring_entry_get_age(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1389
{
15✔
1390
  if (list == nullptr || idx >= list->d_entries.size()) {
15!
1391
    return 0;
3✔
1392
  }
3✔
1393

1394
  return list->d_entries.at(idx).age;
12✔
1395
}
15✔
1396

1397
const char* dnsdist_ffi_ring_entry_get_name(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1398
{
9✔
1399
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1400
    return nullptr;
3✔
1401
  }
3✔
1402

1403
  return list->d_entries.at(idx).qname.c_str();
6✔
1404
}
9✔
1405

1406
uint16_t dnsdist_ffi_ring_entry_get_type(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1407
{
9✔
1408
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1409
    return 0;
3✔
1410
  }
3✔
1411

1412
  return list->d_entries.at(idx).qtype;
6✔
1413
}
9✔
1414

1415
const char* dnsdist_ffi_ring_entry_get_requestor(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1416
{
9✔
1417
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1418
    return nullptr;
3✔
1419
  }
3✔
1420

1421
  return list->d_entries.at(idx).requestor.c_str();
6✔
1422
}
9✔
1423

1424
const char* dnsdist_ffi_ring_entry_get_backend(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1425
{
6✔
1426
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1427
    return nullptr;
3✔
1428
  }
3✔
1429

1430
  return list->d_entries.at(idx).ds.c_str();
3✔
1431
}
6✔
1432

1433
uint8_t dnsdist_ffi_ring_entry_get_protocol(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1434
{
9✔
1435
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1436
    return 0;
3✔
1437
  }
3✔
1438

1439
  return list->d_entries.at(idx).protocol.toNumber();
6✔
1440
}
9✔
1441

1442
uint16_t dnsdist_ffi_ring_entry_get_size(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1443
{
9✔
1444
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1445
    return 0;
3✔
1446
  }
3✔
1447

1448
  return list->d_entries.at(idx).size;
6✔
1449
}
9✔
1450

1451
uint16_t dnsdist_ffi_ring_entry_get_latency(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1452
{
6✔
1453
  if (list == nullptr || idx >= list->d_entries.size()) {
6!
1454
    return 0;
3✔
1455
  }
3✔
1456

1457
  return list->d_entries.at(idx).latency;
3✔
1458
}
6✔
1459

1460
uint16_t dnsdist_ffi_ring_entry_get_id(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1461
{
9✔
1462
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1463
    return 0;
3✔
1464
  }
3✔
1465

1466
  return ntohs(list->d_entries.at(idx).dh.id);
6✔
1467
}
9✔
1468

1469
uint8_t dnsdist_ffi_ring_entry_get_rcode(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1470
{
9✔
1471
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1472
    return 0;
3✔
1473
  }
3✔
1474

1475
  return list->d_entries.at(idx).dh.rcode;
6✔
1476
}
9✔
1477

1478
bool dnsdist_ffi_ring_entry_get_aa(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1479
{
9✔
1480
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1481
    return false;
3✔
1482
  }
3✔
1483

1484
  return list->d_entries.at(idx).dh.aa == 1;
6✔
1485
}
9✔
1486

1487
bool dnsdist_ffi_ring_entry_get_rd(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1488
{
9✔
1489
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1490
    return false;
3✔
1491
  }
3✔
1492

1493
  return list->d_entries.at(idx).dh.rd == 1;
6✔
1494
}
9✔
1495

1496
bool dnsdist_ffi_ring_entry_get_tc(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1497
{
9✔
1498
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1499
    return false;
3✔
1500
  }
3✔
1501

1502
  return list->d_entries.at(idx).dh.tc == 1;
6✔
1503
}
9✔
1504

1505
uint16_t dnsdist_ffi_ring_entry_get_ancount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1506
{
9✔
1507
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1508
    return 0;
3✔
1509
  }
3✔
1510

1511
  return ntohs(list->d_entries.at(idx).dh.ancount);
6✔
1512
}
9✔
1513

1514
uint16_t dnsdist_ffi_ring_entry_get_nscount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1515
{
9✔
1516
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1517
    return 0;
3✔
1518
  }
3✔
1519

1520
  return ntohs(list->d_entries.at(idx).dh.nscount);
6✔
1521
}
9✔
1522

1523
uint16_t dnsdist_ffi_ring_entry_get_arcount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1524
{
9✔
1525
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1526
    return 0;
3✔
1527
  }
3✔
1528

1529
  return ntohs(list->d_entries.at(idx).dh.arcount);
6✔
1530
}
9✔
1531

1532
bool dnsdist_ffi_ring_entry_has_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1533
{
9✔
1534
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1535
    return false;
3✔
1536
  }
3✔
1537

1538
  return !list->d_entries.at(idx).macAddr.empty();
6✔
1539
}
9✔
1540

1541
const char* dnsdist_ffi_ring_entry_get_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
1542
{
9✔
1543
  if (list == nullptr || idx >= list->d_entries.size()) {
9!
1544
    return nullptr;
3✔
1545
  }
3✔
1546

1547
  return list->d_entries.at(idx).macAddr.data();
6✔
1548
}
9✔
1549

1550
void dnsdist_ffi_ring_entry_list_free(dnsdist_ffi_ring_entry_list_t* list)
1551
{
6✔
1552
  delete list;
6✔
1553
}
6✔
1554

1555
template <typename T>
1556
static void addRingEntryToList(std::unique_ptr<dnsdist_ffi_ring_entry_list_t>& list, const struct timespec& now, const T& entry)
1557
{
12✔
1558
  auto age = DiffTime(entry.when, now);
12✔
1559

1560
  constexpr bool response = std::is_same_v<T, Rings::Response>;
12✔
1561
  if constexpr (!response) {
12✔
1562
#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
1563
    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};
1564
#else
1565
    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};
6✔
1566
#endif
6✔
1567
    list->d_entries.push_back(std::move(tmp));
6✔
1568
  }
1569
  else {
6✔
1570
    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};
6✔
1571
    list->d_entries.push_back(std::move(tmp));
6✔
1572
  }
6✔
1573
}
12✔
1574

1575
size_t dnsdist_ffi_ring_get_entries(dnsdist_ffi_ring_entry_list_t** out)
1576
{
6✔
1577
  if (out == nullptr) {
6✔
1578
    return 0;
3✔
1579
  }
3✔
1580
  auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
3✔
1581
  struct timespec now
3✔
1582
  {
3✔
1583
  };
3✔
1584
  gettime(&now);
3✔
1585

1586
  for (const auto& shard : g_rings.d_shards) {
30✔
1587
    {
30✔
1588
      auto ql = shard->queryRing.lock();
30✔
1589
      for (const auto& entry : *ql) {
30✔
1590
        addRingEntryToList(list, now, entry);
3✔
1591
      }
3✔
1592
    }
30✔
1593
    {
30✔
1594
      auto rl = shard->respRing.lock();
30✔
1595
      for (const auto& entry : *rl) {
30✔
1596
        addRingEntryToList(list, now, entry);
3✔
1597
      }
3✔
1598
    }
30✔
1599
  }
30✔
1600

1601
  auto count = list->d_entries.size();
3✔
1602
  if (count > 0) {
3!
1603
    *out = list.release();
3✔
1604
  }
3✔
1605
  return count;
3✔
1606
}
6✔
1607

1608
size_t dnsdist_ffi_ring_get_entries_by_addr(const char* addr, dnsdist_ffi_ring_entry_list_t** out)
1609
{
15✔
1610
  if (out == nullptr || addr == nullptr) {
15✔
1611
    return 0;
6✔
1612
  }
6✔
1613
  ComboAddress ca;
9✔
1614
  try {
9✔
1615
    ca = ComboAddress(addr);
9✔
1616
  }
9✔
1617
  catch (const std::exception& e) {
9✔
1618
    vinfolog("Unable to convert address in dnsdist_ffi_ring_get_entries_by_addr: %s", e.what());
×
1619
    return 0;
×
1620
  }
×
1621
  catch (const PDNSException& e) {
9✔
1622
    vinfolog("Unable to convert address in dnsdist_ffi_ring_get_entries_by_addr: %s", e.reason);
3!
1623
    return 0;
3✔
1624
  }
3✔
1625

1626
  auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
6✔
1627
  struct timespec now
6✔
1628
  {
6✔
1629
  };
6✔
1630
  gettime(&now);
6✔
1631

1632
  auto compare = ComboAddress::addressOnlyEqual();
6✔
1633
  for (const auto& shard : g_rings.d_shards) {
60✔
1634
    {
60✔
1635
      auto ql = shard->queryRing.lock();
60✔
1636
      for (const auto& entry : *ql) {
60✔
1637
        if (!compare(entry.requestor, ca)) {
6✔
1638
          continue;
3✔
1639
        }
3✔
1640

1641
        addRingEntryToList(list, now, entry);
3✔
1642
      }
3✔
1643
    }
60✔
1644
    {
60✔
1645
      auto rl = shard->respRing.lock();
60✔
1646
      for (const auto& entry : *rl) {
60✔
1647
        if (!compare(entry.requestor, ca)) {
6✔
1648
          continue;
3✔
1649
        }
3✔
1650

1651
        addRingEntryToList(list, now, entry);
3✔
1652
      }
3✔
1653
    }
60✔
1654
  }
60✔
1655

1656
  auto count = list->d_entries.size();
6✔
1657
  if (count > 0) {
6✔
1658
    *out = list.release();
3✔
1659
  }
3✔
1660
  return count;
6✔
1661
}
9✔
1662

1663
size_t dnsdist_ffi_ring_get_entries_by_mac(const char* addr, dnsdist_ffi_ring_entry_list_t** out)
1664
{
3✔
1665
  if (out == nullptr || addr == nullptr) {
3!
1666
    return 0;
3✔
1667
  }
3✔
1668

1669
#if !defined(DNSDIST_RINGS_WITH_MACADDRESS)
×
1670
  return 0;
×
1671
#else
1672
  auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
1673
  struct timespec now
1674
  {
1675
  };
1676
  gettime(&now);
1677

1678
  for (const auto& shard : g_rings.d_shards) {
1679
    auto ql = shard->queryRing.lock();
1680
    for (const auto& entry : *ql) {
1681
      if (memcmp(addr, entry.macaddress.data(), entry.macaddress.size()) != 0) {
1682
        continue;
1683
      }
1684

1685
      addRingEntryToList(list, now, entry);
1686
    }
1687
  }
1688

1689
  auto count = list->d_entries.size();
1690
  if (count > 0) {
1691
    *out = list.release();
1692
  }
1693
  return count;
1694
#endif
1695
}
3✔
1696

1697
struct dnsdist_ffi_network_endpoint_t
1698
{
1699
  dnsdist::NetworkEndpoint d_endpoint;
1700
};
1701

1702
bool dnsdist_ffi_network_endpoint_new(const char* path, size_t pathSize, dnsdist_ffi_network_endpoint_t** out)
1703
{
12✔
1704
  if (path == nullptr || pathSize == 0 || out == nullptr) {
12✔
1705
    return false;
9✔
1706
  }
9✔
1707
  try {
3✔
1708
    dnsdist::NetworkEndpoint endpoint(std::string(path, pathSize));
3✔
1709
    *out = new dnsdist_ffi_network_endpoint_t{std::move(endpoint)};
3✔
1710
    return true;
3✔
1711
  }
3✔
1712
  catch (const std::exception& e) {
3✔
1713
    vinfolog("Error creating a new network endpoint: %s", e.what());
3!
1714
    return false;
3✔
1715
  }
3✔
1716
}
3✔
1717

1718
bool dnsdist_ffi_network_endpoint_is_valid(const dnsdist_ffi_network_endpoint_t* endpoint)
1719
{
3✔
1720
  return endpoint != nullptr;
3✔
1721
}
3✔
1722

1723
bool dnsdist_ffi_network_endpoint_send(const dnsdist_ffi_network_endpoint_t* endpoint, const char* payload, size_t payloadSize)
1724
{
6✔
1725
  if (endpoint != nullptr && payload != nullptr && payloadSize != 0) {
6!
1726
    return endpoint->d_endpoint.send(std::string_view(payload, payloadSize));
×
1727
  }
×
1728
  return false;
6✔
1729
}
6✔
1730

1731
void dnsdist_ffi_network_endpoint_free(dnsdist_ffi_network_endpoint_t* endpoint)
1732
{
3✔
1733
  delete endpoint;
3✔
1734
}
3✔
1735

1736
struct dnsdist_ffi_dnspacket_t
1737
{
1738
  dnsdist::DNSPacketOverlay overlay;
1739
};
1740

1741
bool dnsdist_ffi_dnspacket_parse(const char* packet, size_t packetSize, dnsdist_ffi_dnspacket_t** out)
1742
{
9✔
1743
  if (packet == nullptr || out == nullptr || packetSize < sizeof(dnsheader)) {
9!
1744
    return false;
3✔
1745
  }
3✔
1746

1747
  try {
6✔
1748
    dnsdist::DNSPacketOverlay overlay(std::string_view(packet, packetSize));
6✔
1749
    *out = new dnsdist_ffi_dnspacket_t{std::move(overlay)};
6✔
1750
    return true;
6✔
1751
  }
6✔
1752
  catch (const std::exception& e) {
6✔
1753
    vinfolog("Error in dnsdist_ffi_dnspacket_parse: %s", e.what());
3!
1754
  }
3✔
1755
  catch (...) {
6✔
1756
    vinfolog("Error in dnsdist_ffi_dnspacket_parse");
×
1757
  }
×
1758
  return false;
3✔
1759
}
6✔
1760

1761
void dnsdist_ffi_dnspacket_get_qname_raw(const dnsdist_ffi_dnspacket_t* packet, const char** qname, size_t* qnameSize)
1762
{
6✔
1763
  if (packet == nullptr || qname == nullptr || qnameSize == nullptr) {
6!
1764
    return;
3✔
1765
  }
3✔
1766
  const auto& storage = packet->overlay.d_qname.getStorage();
3✔
1767
  *qname = storage.data();
3✔
1768
  *qnameSize = storage.size();
3✔
1769
}
3✔
1770

1771
uint16_t dnsdist_ffi_dnspacket_get_qtype(const dnsdist_ffi_dnspacket_t* packet)
1772
{
6✔
1773
  if (packet != nullptr) {
6✔
1774
    return packet->overlay.d_qtype;
3✔
1775
  }
3✔
1776
  return 0;
3✔
1777
}
6✔
1778

1779
uint16_t dnsdist_ffi_dnspacket_get_qclass(const dnsdist_ffi_dnspacket_t* packet)
1780
{
6✔
1781
  if (packet != nullptr) {
6✔
1782
    return packet->overlay.d_qclass;
3✔
1783
  }
3✔
1784
  return 0;
3✔
1785
}
6✔
1786

1787
uint16_t dnsdist_ffi_dnspacket_get_records_count_in_section(const dnsdist_ffi_dnspacket_t* packet, uint8_t section)
1788
{
18✔
1789
  if (packet == nullptr || section > DNSResourceRecord::ADDITIONAL) {
18✔
1790
    return 0;
6✔
1791
  }
6✔
1792

1793
  uint16_t count = 0;
12✔
1794
  for (const auto& record : packet->overlay.d_records) {
36✔
1795
    if (record.d_place == section) {
36✔
1796
      count++;
9✔
1797
    }
9✔
1798
  }
36✔
1799

1800
  return count;
12✔
1801
}
18✔
1802

1803
void dnsdist_ffi_dnspacket_get_record_name_raw(const dnsdist_ffi_dnspacket_t* packet, size_t idx, const char** name, size_t* nameSize)
1804
{
9✔
1805
  if (packet == nullptr || name == nullptr || nameSize == nullptr || idx >= packet->overlay.d_records.size()) {
9!
1806
    return;
3✔
1807
  }
3✔
1808
  const auto& storage = packet->overlay.d_records.at(idx).d_name.getStorage();
6✔
1809
  *name = storage.data();
6✔
1810
  *nameSize = storage.size();
6✔
1811
}
6✔
1812

1813
uint16_t dnsdist_ffi_dnspacket_get_record_type(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1814
{
9✔
1815
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
9!
1816
    return 0;
3✔
1817
  }
3✔
1818
  return packet->overlay.d_records.at(idx).d_type;
6✔
1819
}
9✔
1820

1821
uint16_t dnsdist_ffi_dnspacket_get_record_class(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1822
{
9✔
1823
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
9!
1824
    return 0;
3✔
1825
  }
3✔
1826
  return packet->overlay.d_records.at(idx).d_class;
6✔
1827
}
9✔
1828

1829
uint32_t dnsdist_ffi_dnspacket_get_record_ttl(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1830
{
9✔
1831
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
9!
1832
    return 0;
3✔
1833
  }
3✔
1834
  return packet->overlay.d_records.at(idx).d_ttl;
6✔
1835
}
9✔
1836

1837
uint16_t dnsdist_ffi_dnspacket_get_record_content_length(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1838
{
9✔
1839
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
9!
1840
    return 0;
3✔
1841
  }
3✔
1842
  return packet->overlay.d_records.at(idx).d_contentLength;
6✔
1843
}
9✔
1844

1845
uint16_t dnsdist_ffi_dnspacket_get_record_content_offset(const dnsdist_ffi_dnspacket_t* packet, size_t idx)
1846
{
9✔
1847
  if (packet == nullptr || idx >= packet->overlay.d_records.size()) {
9!
1848
    return 0;
3✔
1849
  }
3✔
1850
  return packet->overlay.d_records.at(idx).d_contentOffset;
6✔
1851
}
9✔
1852

1853
size_t dnsdist_ffi_dnspacket_get_name_at_offset_raw(const char* packet, size_t packetSize, size_t offset, char* name, size_t nameSize)
1854
{
15✔
1855
  if (packet == nullptr || name == nullptr || nameSize == 0 || offset >= packetSize) {
15!
1856
    return 0;
6✔
1857
  }
6✔
1858
  try {
9✔
1859
    DNSName parsed(packet, packetSize, offset, true);
9✔
1860
    const auto& storage = parsed.getStorage();
9✔
1861
    if (nameSize < storage.size()) {
9✔
1862
      return 0;
3✔
1863
    }
3✔
1864
    memcpy(name, storage.data(), storage.size());
6✔
1865
    return storage.size();
6✔
1866
  }
9✔
1867
  catch (const std::exception& e) {
9✔
1868
    vinfolog("Error parsing DNSName via dnsdist_ffi_dnspacket_get_name_at_offset_raw: %s", e.what());
3!
1869
  }
3✔
1870
  return 0;
3✔
1871
}
9✔
1872

1873
bool dnsdist_ffi_dnspacket_parse_a_record(const char* raw, const dnsdist_ffi_dnspacket_t* packet, size_t idx, char* addr, size_t* addrSize)
1874
{
×
1875
  if (raw == nullptr || packet == nullptr || addr == nullptr || addrSize == nullptr || idx >= packet->overlay.d_records.size()) {
×
1876
    return false;
×
1877
  }
×
1878

1879
  const auto& record = packet->overlay.d_records.at(idx);
×
1880
  if (record.d_type != QType::A || record.d_contentLength != 4) {
×
1881
    return false;
×
1882
  }
×
1883

1884
  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
1885
  memcpy(addr, &raw[record.d_contentOffset], 4);
×
1886
  *addrSize = record.d_contentLength;
×
1887

1888
  return true;
×
1889
}
×
1890

1891
bool dnsdist_ffi_dnspacket_parse_aaaa_record(const char* raw, const dnsdist_ffi_dnspacket_t* packet, size_t idx, char* addr, size_t* addrSize)
1892
{
×
1893
  if (raw == nullptr || packet == nullptr || addr == nullptr || addrSize == nullptr || idx >= packet->overlay.d_records.size()) {
×
1894
    return false;
×
1895
  }
×
1896

1897
  const auto& record = packet->overlay.d_records.at(idx);
×
1898
  if (record.d_type != QType::AAAA || record.d_contentLength != 16) {
×
1899
    return false;
×
1900
  }
×
1901

1902
  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
1903
  memcpy(addr, &raw[record.d_contentOffset], 16);
×
1904
  *addrSize = record.d_contentLength;
×
1905

1906
  return true;
×
1907
}
×
1908

1909
bool dnsdist_ffi_dnspacket_parse_address_record(const char* raw, const dnsdist_ffi_dnspacket_t* packet, size_t idx, char* addr, size_t* addrSize)
1910
{
×
1911
  if (raw == nullptr || packet == nullptr || addr == nullptr || addrSize == nullptr || idx >= packet->overlay.d_records.size()) {
×
1912
    return false;
×
1913
  }
×
1914

1915
  const auto& record = packet->overlay.d_records.at(idx);
×
1916
  if (record.d_type == QType::A && record.d_contentLength == 4) {
×
1917
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
1918
    memcpy(addr, &raw[record.d_contentOffset], 4);
×
1919
    *addrSize = record.d_contentLength;
×
1920

1921
    return true;
×
1922
  }
×
1923

1924
  if (record.d_type == QType::AAAA && record.d_contentLength == 16) {
×
1925
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
1926
    memcpy(addr, &raw[record.d_contentOffset], 16);
×
1927
    *addrSize = record.d_contentLength;
×
1928

1929
    return true;
×
1930
  }
×
1931

1932
  return false;
×
1933
}
×
1934

1935
bool dnsdist_ffi_dnspacket_parse_cname_record(const char* raw, const dnsdist_ffi_dnspacket_t* packet, size_t idx, char* name, size_t* nameSize)
1936
{
×
1937
  if (raw == nullptr || packet == nullptr || name == nullptr || nameSize == nullptr || idx >= packet->overlay.d_records.size()) {
×
1938
    return false;
×
1939
  }
×
1940

1941
  const auto& record = packet->overlay.d_records.at(idx);
×
1942
  if (record.d_type != QType::CNAME) {
×
1943
    return false;
×
1944
  }
×
1945

1946
  DNSName parsed(raw, record.d_contentOffset + record.d_contentLength, record.d_contentOffset, true);
×
1947
  const auto& storage = parsed.getStorage();
×
1948
  memcpy(name, storage.data(), storage.size());
×
1949
  *nameSize = storage.size();
×
1950

1951
  return true;
×
1952
}
×
1953

1954
void dnsdist_ffi_dnspacket_free(dnsdist_ffi_dnspacket_t* packet)
1955
{
3✔
1956
  if (packet != nullptr) {
3!
1957
    delete packet;
3✔
1958
  }
3✔
1959
}
3✔
1960

1961
bool dnsdist_ffi_metric_declare(const char* name, size_t nameLen, const char* type, const char* description, const char* customName)
1962
{
×
1963
  if (name == nullptr || nameLen == 0 || type == nullptr || description == nullptr) {
×
1964
    return false;
×
1965
  }
×
1966
  auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName != nullptr ? std::optional<std::string>(customName) : std::nullopt, false);
×
1967
  return !result;
×
1968
}
×
1969

1970
void dnsdist_ffi_metric_inc(const char* metricName, size_t metricNameLen)
1971
{
×
1972
  auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), 1U, std::nullopt);
×
1973
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1974
    return;
×
1975
  }
×
1976
}
×
1977

1978
void dnsdist_ffi_metric_inc_by(const char* metricName, size_t metricNameLen, uint64_t value)
1979
{
×
1980
  auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), value, std::nullopt);
×
1981
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1982
    return;
×
1983
  }
×
1984
}
×
1985

1986
void dnsdist_ffi_metric_dec(const char* metricName, size_t metricNameLen)
1987
{
×
1988
  auto result = dnsdist::metrics::decrementCustomCounter(std::string_view(metricName, metricNameLen), 1U, std::nullopt);
×
1989
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1990
    return;
×
1991
  }
×
1992
}
×
1993

1994
void dnsdist_ffi_metric_set(const char* metricName, size_t metricNameLen, double value)
1995
{
×
1996
  auto result = dnsdist::metrics::setCustomGauge(std::string_view(metricName, metricNameLen), value, std::nullopt);
×
1997
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
1998
    return;
×
1999
  }
×
2000
}
×
2001

2002
double dnsdist_ffi_metric_get(const char* metricName, size_t metricNameLen, bool isCounter)
2003
{
×
2004
  (void)isCounter;
×
2005
  auto result = dnsdist::metrics::getCustomMetric(std::string_view(metricName, metricNameLen), {});
×
2006
  if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
×
2007
    return 0.;
×
2008
  }
×
2009
  return std::get<double>(result);
×
2010
}
×
2011

2012
const char* dnsdist_ffi_network_message_get_payload(const dnsdist_ffi_network_message_t* msg)
2013
{
×
2014
  if (msg != nullptr) {
×
2015
    return msg->payload.c_str();
×
2016
  }
×
2017
  return nullptr;
×
2018
}
×
2019

2020
size_t dnsdist_ffi_network_message_get_payload_size(const dnsdist_ffi_network_message_t* msg)
2021
{
×
2022
  if (msg != nullptr) {
×
2023
    return msg->payload.size();
×
2024
  }
×
2025
  return 0;
×
2026
}
×
2027

2028
uint16_t dnsdist_ffi_network_message_get_endpoint_id(const dnsdist_ffi_network_message_t* msg)
2029
{
×
2030
  if (msg != nullptr) {
×
2031
    return msg->endpointID;
×
2032
  }
×
2033
  return 0;
×
2034
}
×
2035

2036
#ifndef DISABLE_DYNBLOCKS
2037
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)
2038
{
2039
  try {
2040
    ComboAddress clientIPCA;
2041
    try {
2042
      clientIPCA = ComboAddress(address);
2043
    }
2044
    catch (const std::exception& exp) {
2045
      errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.what());
2046
      return false;
2047
    }
2048
    catch (const PDNSException& exp) {
2049
      errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.reason);
2050
      return false;
2051
    }
2052

2053
    AddressAndPortRange target(clientIPCA, clientIPMask, clientIPPortMask);
2054

2055
    timespec now{};
2056
    gettime(&now);
2057
    timespec until{now};
2058
    until.tv_sec += duration;
2059
    DynBlock dblock{message, until, DNSName(), static_cast<DNSAction::Action>(action)};
2060

2061
    auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
2062
    if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
×
2063
      dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
2064
      dblock.tagSettings->d_name = tagKey;
2065
      if (tagValue != nullptr) {
×
2066
        dblock.tagSettings->d_value = tagValue;
2067
      }
2068
    }
2069
    if (dnsdist::DynamicBlocks::addOrRefreshBlock(dynamicRules, now, target, std::move(dblock), false)) {
×
2070
      dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
2071
      return true;
2072
    }
2073
  }
2074
  catch (const std::exception& exp) {
2075
    errlog("Exception in dnsdist_ffi_dynamic_blocks_add: %s", exp.what());
2076
  }
2077
  catch (const PDNSException& exp) {
2078
    errlog("Exception in dnsdist_ffi_dynamic_blocks_add: %s", exp.reason);
2079
  }
2080
  catch (...) {
2081
    errlog("Exception in dnsdist_ffi_dynamic_blocks_add");
2082
  }
2083
  return false;
2084
}
2085

2086
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)
2087
{
2088
  try {
2089
    DNSName domain;
2090
    try {
2091
      domain = DNSName(suffix);
2092
      domain.makeUsLowerCase();
2093
    }
2094
    catch (const std::exception& exp) {
2095
      errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.what());
2096
      return false;
2097
    }
2098
    catch (const PDNSException& exp) {
2099
      errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.reason);
2100
      return false;
2101
    }
2102

2103
    timespec now{};
2104
    gettime(&now);
2105
    timespec until{now};
2106
    until.tv_sec += duration;
2107
    DynBlock dblock{message, until, domain, static_cast<DNSAction::Action>(action)};
2108
    auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
2109
    if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
×
2110
      dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
2111
      dblock.tagSettings->d_name = tagKey;
2112
      if (tagValue != nullptr) {
×
2113
        dblock.tagSettings->d_value = tagValue;
2114
      }
2115
    }
2116
    if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(smtBlocks, now, std::move(dblock), false)) {
×
2117
      dnsdist::DynamicBlocks::setSuffixDynamicRules(std::move(smtBlocks));
2118
      return true;
2119
    }
2120
  }
2121
  catch (const std::exception& exp) {
2122
    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.what());
2123
  }
2124
  catch (const PDNSException& exp) {
2125
    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.reason);
2126
  }
2127
  catch (...) {
2128
    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add");
2129
  }
2130
  return false;
2131
}
2132

2133
struct dnsdist_ffi_dynamic_blocks_list_t
2134
{
2135
  std::vector<dnsdist_ffi_dynamic_block_entry_t> d_entries;
2136
};
2137

2138
size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out)
2139
{
2140
  if (out == nullptr) {
×
2141
    return 0;
2142
  }
2143

2144
  auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
2145

2146
  timespec now{};
2147
  gettime(&now);
2148

2149
  const auto& dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
2150
  for (const auto& entry : dynamicRules) {
×
2151
    const auto& client = entry.first;
2152
    const auto& details = entry.second;
2153
    if (!(now < details.until)) {
×
2154
      continue;
2155
    }
2156

2157
    uint64_t counter = details.blocks;
2158
    if (g_defaultBPFFilter && details.bpf) {
×
2159
      counter += g_defaultBPFFilter->getHits(client.getNetwork());
2160
    }
2161
    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});
×
2162
  }
2163

2164
  auto count = list->d_entries.size();
2165
  *out = list.release();
2166
  return count;
2167
}
2168

2169
size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out)
2170
{
2171
  if (out == nullptr) {
×
2172
    return 0;
2173
  }
2174

2175
  auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
2176

2177
  timespec now{};
2178
  gettime(&now);
2179

2180
  const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
2181
  const auto& smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRules();
2182
  smtBlocks.visit([&now, &list, defaultAction](const SuffixMatchTree<DynBlock>& node) {
2183
    if (!(now < node.d_value.until)) {
×
2184
      return;
2185
    }
2186
    auto entry = node.d_value;
2187
    string key("empty");
2188
    if (!entry.domain.empty()) {
×
2189
      key = entry.domain.toString();
2190
    }
2191
    if (entry.action == DNSAction::Action::None) {
×
2192
      entry.action = defaultAction;
2193
    }
2194
    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});
2195
  });
2196

2197
  auto count = list->d_entries.size();
2198
  *out = list.release();
2199
  return count;
2200
}
2201

2202
const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(const dnsdist_ffi_dynamic_blocks_list_t* list, size_t idx)
2203
{
2204
  if (list == nullptr) {
×
2205
    return nullptr;
2206
  }
2207

2208
  if (idx >= list->d_entries.size()) {
×
2209
    return nullptr;
2210
  }
2211

2212
  return &list->d_entries.at(idx);
2213
}
2214

2215
void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t* list)
2216
{
2217
  if (list == nullptr) {
×
2218
    return;
2219
  }
2220

2221
  for (auto& entry : list->d_entries) {
×
2222
    // NOLINTNEXTLINE(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc): this is a C API, RAII is not an option
2223
    free(entry.key);
2224
    // NOLINTNEXTLINE(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc): this is a C API, RAII is not an option
2225
    free(entry.reason);
2226
  }
2227

2228
  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): this is a C API, RAII is not an option
2229
  delete list;
2230
}
2231

2232
#endif /* DISABLE_DYNBLOCKS */
2233

2234
uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataSize, bool caseInsensitive)
2235
{
12✔
2236
  if (data == nullptr || dataSize == 0) {
12!
2237
    return seed;
6✔
2238
  }
6✔
2239

2240
  if (caseInsensitive) {
6✔
2241
    return burtleCI(data, dataSize, seed);
3✔
2242
  }
3✔
2243

2244
  return burtle(data, dataSize, seed);
3✔
2245
}
6✔
2246

2247
struct dnsdist_ffi_svc_record_parameters
2248
{
2249
  SVCRecordParameters parameters;
2250
};
2251

2252
bool dnsdist_ffi_svc_record_parameters_new(const char* targetName, uint16_t priority, bool noDefaultALPN, dnsdist_ffi_svc_record_parameters** out)
2253
{
23✔
2254
  if (targetName == nullptr || out == nullptr) {
23✔
2255
    return false;
6✔
2256
  }
6✔
2257
  try {
17✔
2258
    auto parameters = std::make_unique<dnsdist_ffi_svc_record_parameters>();
17✔
2259
    parameters->parameters.target = DNSName(targetName);
17✔
2260
    parameters->parameters.priority = priority;
17✔
2261
    parameters->parameters.noDefaultAlpn = noDefaultALPN;
17✔
2262
    *out = parameters.release();
17✔
2263
    return true;
17✔
2264
  }
17✔
2265
  catch (const std::exception& exp) {
17✔
2266
    errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.what());
×
2267
  }
×
2268
  catch (const PDNSException& exp) {
17✔
2269
    errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.reason);
×
2270
  }
×
2271
  catch (...) {
17✔
2272
    errlog("Exception in dnsdist_ffi_svc_record_parameters_new");
×
2273
  }
×
2274

2275
  return false;
×
2276
}
17✔
2277

2278
void dnsdist_ffi_svc_record_parameters_set_port(dnsdist_ffi_svc_record_parameters* parameters, uint16_t port)
2279
{
20✔
2280
  if (parameters == nullptr) {
20✔
2281
    return;
3✔
2282
  }
3✔
2283
  parameters->parameters.port = port;
17✔
2284
}
17✔
2285

2286
void dnsdist_ffi_svc_record_parameters_set_ech(dnsdist_ffi_svc_record_parameters* parameters, const char* ech, size_t echLen)
2287
{
6✔
2288
  if (parameters == nullptr || ech == nullptr || echLen == 0) {
6!
2289
    return;
3✔
2290
  }
3✔
2291
  parameters->parameters.ech = std::string(ech, echLen);
3✔
2292
}
3✔
2293

2294
void dnsdist_ffi_svc_record_parameters_set_additional_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key, const char* value, size_t valueLen)
2295
{
15✔
2296
  if (parameters == nullptr || (value == nullptr && valueLen != 0)) {
15!
2297
    return;
3✔
2298
  }
3✔
2299
  parameters->parameters.additionalParams.emplace_back(key, std::string(value, valueLen));
12✔
2300
}
12✔
2301

2302
void dnsdist_ffi_svc_record_parameters_add_mandatory_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key)
2303
{
20✔
2304
  if (parameters == nullptr) {
20✔
2305
    return;
3✔
2306
  }
3✔
2307
  parameters->parameters.mandatoryParams.insert(key);
17✔
2308
}
17✔
2309

2310
void dnsdist_ffi_svc_record_parameters_add_alpn(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
2311
{
23✔
2312
  if (parameters == nullptr || value == nullptr || valueLen == 0) {
23!
2313
    return;
6✔
2314
  }
6✔
2315
  parameters->parameters.alpns.emplace_back(value, valueLen);
17✔
2316
}
17✔
2317

2318
void dnsdist_ffi_svc_record_parameters_add_ipv4_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
2319
{
19✔
2320
  if (parameters == nullptr || value == nullptr || valueLen == 0) {
19!
2321
    return;
6✔
2322
  }
6✔
2323
  try {
13✔
2324
    parameters->parameters.ipv4hints.emplace_back(ComboAddress(std::string(value, valueLen)));
13✔
2325
  }
13✔
2326
  catch (const std::exception& exp) {
13✔
2327
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
×
2328
  }
×
2329
  catch (const PDNSException& exp) {
13✔
2330
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
×
2331
  }
×
2332
  catch (...) {
13✔
2333
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
×
2334
  }
×
2335
}
13✔
2336

2337
void dnsdist_ffi_svc_record_parameters_add_ipv6_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
2338
{
19✔
2339
  if (parameters == nullptr || value == nullptr || valueLen == 0) {
19!
2340
    return;
6✔
2341
  }
6✔
2342
  try {
13✔
2343
    parameters->parameters.ipv6hints.emplace_back(ComboAddress(std::string(value, valueLen)));
13✔
2344
  }
13✔
2345
  catch (const std::exception& exp) {
13✔
2346
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
×
2347
  }
×
2348
  catch (const PDNSException& exp) {
13✔
2349
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
×
2350
  }
×
2351
  catch (...) {
13✔
2352
    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
×
2353
  }
×
2354
}
13✔
2355

2356
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)
2357
{
14✔
2358
  if (dnsQuestion == nullptr || parametersList == nullptr || parametersListSize == 0) {
14!
2359
    return false;
3✔
2360
  }
3✔
2361
  std::vector<SVCRecordParameters> parameters;
11✔
2362
  parameters.reserve(parametersListSize);
11✔
2363
  for (size_t idx = 0; idx < parametersListSize; idx++) {
28✔
2364
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
2365
    const auto* parameter = parametersList[idx];
17✔
2366
    if (parameter == nullptr) {
17!
2367
      return false;
×
2368
    }
×
2369
    parameters.push_back(parameter->parameters);
17✔
2370
  }
17✔
2371
  return dnsdist::svc::generateSVCResponse(*dnsQuestion->dq, ttl, parameters);
11✔
2372
}
11✔
2373

2374
void dnsdist_ffi_svc_record_parameters_free(dnsdist_ffi_svc_record_parameters* parameters)
2375
{
17✔
2376
  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): this is a C API, RAII is not an option
2377
  delete parameters;
17✔
2378
}
17✔
2379

2380
void dnsdist_ffi_dnsquestion_meta_begin_key([[maybe_unused]] dnsdist_ffi_dnsquestion_t* dnsQuestion, [[maybe_unused]] const char* key, [[maybe_unused]] size_t keyLen)
2381
{
11✔
2382
#if !defined(DISABLE_PROTOBUF)
11✔
2383
  if (dnsQuestion == nullptr || key == nullptr || keyLen == 0) {
11✔
2384
    return;
6✔
2385
  }
6✔
2386

2387
  if (dnsQuestion->pbfWriter.valid()) {
5✔
2388
    vinfolog("Error in dnsdist_ffi_dnsquestion_meta_begin_key: the previous key has not been ended");
2!
2389
    return;
2✔
2390
  }
2✔
2391

2392
  dnsQuestion->pbfWriter = protozero::pbf_writer{dnsQuestion->dq->ids.d_rawProtobufContent};
3✔
2393
  dnsQuestion->pbfMetaWriter = protozero::pbf_writer{dnsQuestion->pbfWriter, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::Field::meta)};
3✔
2394
  dnsQuestion->pbfMetaWriter.add_string(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaField::key), protozero::data_view(key, keyLen));
3✔
2395
  dnsQuestion->pbfMetaValueWriter = protozero::pbf_writer {dnsQuestion->pbfMetaWriter, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaField::value)};
3✔
2396
#endif /* DISABLE_PROTOBUF */
3✔
2397
}
3✔
2398

2399
void dnsdist_ffi_dnsquestion_meta_add_str_value_to_key([[maybe_unused]] dnsdist_ffi_dnsquestion_t* dnsQuestion, [[maybe_unused]] const char* value, [[maybe_unused]] size_t valueLen)
2400
{
12✔
2401
#if !defined(DISABLE_PROTOBUF)
12✔
2402
  if (dnsQuestion == nullptr || value == nullptr || valueLen == 0) {
12✔
2403
    return;
6✔
2404
  }
6✔
2405

2406
  if (!dnsQuestion->pbfMetaValueWriter.valid()) {
6!
2407
    vinfolog("Error in dnsdist_ffi_dnsquestion_meta_add_str_value_to_key: trying to add a value without starting a key");
×
2408
    return;
2409
  }
2410

2411
  dnsQuestion->pbfMetaValueWriter.add_string(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaValueField::stringVal), protozero::data_view(value, valueLen));
6✔
2412
#endif /* DISABLE_PROTOBUF */
6✔
2413
}
6✔
2414

2415
void dnsdist_ffi_dnsquestion_meta_add_int64_value_to_key([[maybe_unused]] dnsdist_ffi_dnsquestion_t* dnsQuestion, [[maybe_unused]] int64_t value)
2416
{
7✔
2417
#if !defined(DISABLE_PROTOBUF)
7✔
2418
  if (dnsQuestion == nullptr) {
7✔
2419
    return;
2✔
2420
  }
2✔
2421

2422
  if (!dnsQuestion->pbfMetaValueWriter.valid()) {
5!
2423
    vinfolog("Error in dnsdist_ffi_dnsquestion_meta_add_int64_value_to_key: trying to add a value without starting a key");
×
2424
    return;
2425
  }
2426

2427
  dnsQuestion->pbfMetaValueWriter.add_uint64(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaValueField::intVal), value);
5✔
2428
#endif /* DISABLE_PROTOBUF */
5✔
2429
}
5✔
2430

2431
void dnsdist_ffi_dnsquestion_meta_end_key([[maybe_unused]] dnsdist_ffi_dnsquestion_t* dnsQuestion)
2432
{
7✔
2433
#if !defined(DISABLE_PROTOBUF)
7✔
2434
  if (dnsQuestion == nullptr) {
7✔
2435
    return;
2✔
2436
  }
2✔
2437

2438
  if (!dnsQuestion->pbfWriter.valid()) {
5✔
2439
    vinfolog("Error in dnsdist_ffi_dnsquestion_meta_end_key: trying to end a key that has not been started");
2!
2440
    return;
2✔
2441
  }
2✔
2442

2443
  try {
3✔
2444
    /* reset the pbf writer so that the sizes are properly updated */
2445
    dnsQuestion->pbfMetaValueWriter.commit();
3✔
2446
    dnsQuestion->pbfMetaWriter.commit();
3✔
2447
    dnsQuestion->pbfWriter = protozero::pbf_writer();
3✔
2448
  }
3✔
2449
  catch (const std::exception& exp) {
3✔
2450
    vinfolog("Error in dnsdist_ffi_dnsquestion_meta_end_key: %s", exp.what());
×
2451
  }
2452
#endif /* DISABLE_PROTOBUF */
3✔
2453
}
3✔
2454

2455
void dnsdist_ffi_dnsresponse_meta_begin_key([[maybe_unused]] dnsdist_ffi_dnsresponse_t* dnsResponse, [[maybe_unused]] const char* key, [[maybe_unused]] size_t keyLen)
2456
{
11✔
2457
#if !defined(DISABLE_PROTOBUF)
11✔
2458
  if (dnsResponse == nullptr || key == nullptr || keyLen == 0) {
11✔
2459
    return;
6✔
2460
  }
6✔
2461

2462
  if (dnsResponse->pbfWriter.valid()) {
5✔
2463
    vinfolog("Error in dnsdist_ffi_dnsresponse_meta_begin_key: the previous key has not been ended");
2!
2464
    return;
2✔
2465
  }
2✔
2466

2467
  dnsResponse->pbfWriter = protozero::pbf_writer{dnsResponse->dr->ids.d_rawProtobufContent};
3✔
2468
  dnsResponse->pbfMetaWriter = protozero::pbf_writer{dnsResponse->pbfWriter, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::Field::meta)};
3✔
2469
  dnsResponse->pbfMetaWriter.add_string(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaField::key), protozero::data_view(key, keyLen));
3✔
2470
  dnsResponse->pbfMetaValueWriter = protozero::pbf_writer {dnsResponse->pbfMetaWriter, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaField::value)};
3✔
2471
#endif /* DISABLE_PROTOBUF */
3✔
2472
}
3✔
2473

2474
void dnsdist_ffi_dnsresponse_meta_add_str_value_to_key([[maybe_unused]] dnsdist_ffi_dnsresponse_t* dnsResponse, [[maybe_unused]] const char* value, [[maybe_unused]] size_t valueLen)
2475
{
12✔
2476
#if !defined(DISABLE_PROTOBUF)
12✔
2477
  if (dnsResponse == nullptr || value == nullptr || valueLen == 0) {
12✔
2478
    return;
6✔
2479
  }
6✔
2480

2481
  if (!dnsResponse->pbfMetaValueWriter.valid()) {
6!
2482
    vinfolog("Error in dnsdist_ffi_dnsresponse_meta_add_str_value_to_key: trying to add a value without starting a key");
×
2483
    return;
2484
  }
2485

2486
  dnsResponse->pbfMetaValueWriter.add_string(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaValueField::stringVal), protozero::data_view(value, valueLen));
6✔
2487
#endif /* DISABLE_PROTOBUF */
6✔
2488
}
6✔
2489

2490
void dnsdist_ffi_dnsresponse_meta_add_int64_value_to_key([[maybe_unused]] dnsdist_ffi_dnsresponse_t* dnsResponse, [[maybe_unused]] int64_t value)
2491
{
7✔
2492
#if !defined(DISABLE_PROTOBUF)
7✔
2493
  if (dnsResponse == nullptr) {
7✔
2494
    return;
2✔
2495
  }
2✔
2496

2497
  if (!dnsResponse->pbfMetaValueWriter.valid()) {
5!
2498
    vinfolog("Error in dnsdist_ffi_dnsresponse_meta_add_int64_value_to_key: trying to add a value without starting a key");
×
2499
    return;
2500
  }
2501

2502
  dnsResponse->pbfMetaValueWriter.add_uint64(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::MetaValueField::intVal), value);
5✔
2503
#endif /* DISABLE_PROTOBUF */
5✔
2504
}
5✔
2505

2506
void dnsdist_ffi_dnsresponse_meta_end_key([[maybe_unused]] dnsdist_ffi_dnsresponse_t* dnsResponse)
2507
{
7✔
2508
#if !defined(DISABLE_PROTOBUF)
7✔
2509
  if (dnsResponse == nullptr) {
7✔
2510
    return;
2✔
2511
  }
2✔
2512

2513
  if (!dnsResponse->pbfWriter.valid()) {
5✔
2514
    vinfolog("Error in dnsdist_ffi_dnsresponse_meta_end_key: trying to end a key that has not been started");
2!
2515
    return;
2✔
2516
  }
2✔
2517

2518
  try {
3✔
2519
    /* reset the pbf writer so that the sizes are properly updated */
2520
    dnsResponse->pbfMetaValueWriter.commit();
3✔
2521
    dnsResponse->pbfMetaWriter.commit();
3✔
2522
    dnsResponse->pbfWriter = protozero::pbf_writer();
3✔
2523
  }
3✔
2524
  catch (const std::exception& exp) {
3✔
2525
    vinfolog("Error in dnsdist_ffi_dnsresponse_meta_end_key: %s", exp.what());
×
2526
  }
2527
#endif /* DISABLE_PROTOBUF */
3✔
2528
}
3✔
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