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

PowerDNS / pdns / 18743945403

23 Oct 2025 09:29AM UTC coverage: 65.845% (+0.02%) from 65.829%
18743945403

Pull #16356

github

web-flow
Merge 8a2027ef1 into efa3637e8
Pull Request #16356: auth 5.0: backport "pdnsutil: fix b2b-migrate to from sql to non-sql"

42073 of 92452 branches covered (45.51%)

Branch coverage included in aggregate %.

128008 of 165855 relevant lines covered (77.18%)

6379935.17 hits per line

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

84.87
/pdns/misc.hh
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
#pragma once
23
#include <cinttypes>
24
#include <cstring>
25
#include <cstdio>
26
#include <regex.h>
27
#include <climits>
28
#include <type_traits>
29

30
#include <boost/algorithm/string.hpp>
31

32
#include "dns.hh"
33
#include <atomic>
34
#include <sys/time.h>
35
#include <sys/types.h>
36
#include <sys/socket.h>
37
#include <ctime>
38
#include <syslog.h>
39
#include <stdexcept>
40
#include <string>
41
#include <cctype>
42
#include <utility>
43
#include <vector>
44

45
#include "namespaces.hh"
46

47
class DNSName;
48
#if defined(PDNS_AUTH)
49
class ZoneName;
50
#else
51
using ZoneName = DNSName;
52
#endif
53

54
// Do not change to "using TSIGHashEnum ..." until you know CodeQL does not choke on it
55
typedef enum
56
{
57
  TSIG_MD5,
58
  TSIG_SHA1,
59
  TSIG_SHA224,
60
  TSIG_SHA256,
61
  TSIG_SHA384,
62
  TSIG_SHA512,
63
  TSIG_GSS,
64
} TSIGHashEnum;
65

66
namespace pdns
67
{
68
/**
69
 * \brief Retrieves the errno-based error message in a reentrant way.
70
 *
71
 * This internally handles the portability issues around using
72
 * `strerror_r` and returns a `std::string` that owns the error
73
 * message's contents.
74
 *
75
 * \param[in] errnum The errno value.
76
 *
77
 * \return The `std::string` error message.
78
 */
79
auto getMessageFromErrno(int errnum) -> std::string;
80

81
#if defined(HAVE_LIBCRYPTO)
82
namespace OpenSSL
83
{
84
  /**
85
   * \brief Throws a `std::runtime_error` with the current OpenSSL error.
86
   *
87
   * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
88
   */
89
  [[nodiscard]] auto error(const std::string& errorMessage) -> std::runtime_error;
90

91
  /**
92
   * \brief Throws a `std::runtime_error` with a name and the current OpenSSL error.
93
   *
94
   * \param[in] componentName The name of the component to mark the error message with.
95
   * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
96
   */
97
  [[nodiscard]] auto error(const std::string& componentName, const std::string& errorMessage) -> std::runtime_error;
98
}
99
#endif // HAVE_LIBCRYPTO
100
}
101

102
string nowTime();
103
string unquotify(const string &item);
104
string humanDuration(time_t passed);
105
void stripLine(string &line);
106
std::optional<string> getHostname();
107
std::string getCarbonHostName();
108
string urlEncode(const string &text);
109
int waitForData(int fileDesc, int seconds, int useconds = 0);
110
int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
111
int waitForMultiData(const set<int>& fds, const int seconds, const int useconds, int* fd);
112
int waitForRWData(int fileDesc, bool waitForRead, int seconds, int useconds, bool* error = nullptr, bool* disconnected = nullptr);
113
bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum);
114
DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum);
115

116
int logFacilityToLOG(unsigned int facility);
117
std::optional<int> logFacilityFromString(std::string facilityStr);
118

119
template<typename Container>
120
void
121
stringtok (Container &container, string const &in,
122
           const char * const delimiters = " \t\n")
123
{
1,566,575✔
124
  const string::size_type len = in.length();
1,566,575✔
125
  string::size_type i = 0;
1,566,575✔
126

127
  while (i<len) {
4,315,962✔
128
    // eat leading whitespace
129
    i = in.find_first_not_of (delimiters, i);
4,248,533✔
130
    if (i == string::npos)
4,248,533!
131
      return;   // nothing left but white space
2✔
132

133
    // find the end of the token
134
    string::size_type j = in.find_first_of (delimiters, i);
4,248,531✔
135

136
    // push token
137
    if (j == string::npos) {
4,248,531✔
138
      container.push_back (in.substr(i));
1,499,144✔
139
      return;
1,499,144✔
140
    } else
1,499,144✔
141
      container.push_back (in.substr(i, j-i));
2,749,387✔
142

143
    // set up for next loop
144
    i = j + 1;
2,749,387✔
145
  }
2,749,387✔
146
}
1,566,575✔
147

148
template<typename T> bool rfc1982LessThan(T lhs, T rhs)
149
{
229✔
150
  static_assert(std::is_unsigned_v<T>, "rfc1982LessThan only works for unsigned types");
229✔
151
  return static_cast<std::make_signed_t<T>>(lhs - rhs) < 0;
229✔
152
}
229✔
153

154
template<typename T> bool rfc1982LessThanOrEqual(T lhs, T rhs)
155
{
30,123✔
156
  static_assert(std::is_unsigned_v<T>, "rfc1982LessThanOrEqual only works for unsigned types");
30,123✔
157
  return static_cast<std::make_signed_t<T>>(lhs - rhs) <= 0;
30,123✔
158
}
30,123✔
159

160
// fills container with ranges, so {posbegin,posend}
161
template <typename Container>
162
void
163
vstringtok (Container &container, string const &in,
164
           const char * const delimiters = " \t\n")
165
{
4,318,338✔
166
  const string::size_type len = in.length();
4,318,338✔
167
  string::size_type i = 0;
4,318,338✔
168

169
  while (i<len) {
18,338,443✔
170
    // eat leading whitespace
171
    i = in.find_first_not_of (delimiters, i);
18,331,071✔
172
    if (i == string::npos)
18,331,071!
173
      return;   // nothing left but white space
×
174

175
    // find the end of the token
176
    string::size_type j = in.find_first_of (delimiters, i);
18,331,071✔
177

178
    // push token
179
    if (j == string::npos) {
18,331,071✔
180
      container.emplace_back(i, len);
4,310,966✔
181
      return;
4,310,966✔
182
    } else
4,310,966✔
183
      container.emplace_back(i, j);
14,020,105✔
184

185
    // set up for next loop
186
    i = j + 1;
14,020,105✔
187
  }
14,020,105✔
188
}
4,318,338✔
189

190
size_t writen2(int fd, const void *buf, size_t count);
191
inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
83✔
192
size_t readn2(int fileDesc, void* buffer, size_t len);
193
size_t readn2WithTimeout(int fd, void* buffer, size_t len, const struct timeval& idleTimeout, const struct timeval& totalTimeout={0,0}, bool allowIncomplete=false);
194
size_t writen2WithTimeout(int fd, const void * buffer, size_t len, const struct timeval& timeout);
195

196
void toLowerInPlace(string& str);
197
const string toLower(const string &upper);
198
const string toLowerCanonic(const string &upper);
199
bool IpToU32(const string &str, uint32_t *ip);
200
string U32ToIP(uint32_t);
201

202
inline string stringerror(int err = errno)
203
{
1,593✔
204
  return pdns::getMessageFromErrno(err);
1,593✔
205
}
1,593✔
206

207
string bitFlip(const string &str);
208

209
void dropPrivs(int uid, int gid);
210
void cleanSlashes(string &str);
211

212
#if defined(_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
213
/** CPUTime measurements */
214
class CPUTime
215
{
216
public:
217
  void start()
218
  {
×
219
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &d_start);
×
220
  }
×
221
  uint64_t ndiff()
222
  {
×
223
    struct timespec now;
×
224
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
×
225
    return 1000000000ULL*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec);
×
226
  }
×
227
private:
228
  struct timespec d_start;
229
};
230
#endif
231

232
/** The DTime class can be used for timing statistics with microsecond resolution.
233
On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
234
class DTime
235
{
236
public:
237
  //!< Does not set the timer for you! Saves lots of gettimeofday() calls
238
  DTime() = default;
2,446,236✔
239
  DTime(const DTime &dt) = default;
240
  DTime & operator=(const DTime &dt) = default;
241
  inline time_t time() const;
242
  inline void set();  //!< Reset the timer
243
  inline int udiff(bool reset = true); //!< Return the number of microseconds since the timer was last set.
244

245
  int udiffNoReset() //!< Return the number of microseconds since the timer was last set.
246
  {
257,596✔
247
    return udiff(false);
257,596✔
248
  }
257,596✔
249
  void setTimeval(const struct timeval& tv)
250
  {
126,516✔
251
    d_set=tv;
126,516✔
252
  }
126,516✔
253
  struct timeval getTimeval() const
254
  {
21,388✔
255
    return d_set;
21,388✔
256
  }
21,388✔
257
private:
258
struct timeval d_set{0, 0};
259
};
260

261
inline time_t DTime::time() const
262
{
×
263
  return d_set.tv_sec;
×
264
}
×
265

266
inline void DTime::set()
267
{
15,304✔
268
  gettimeofday(&d_set, nullptr);
15,304✔
269
}
15,304✔
270

271
inline int DTime::udiff(bool reset)
272
{
638,328✔
273
  struct timeval now;
638,328✔
274
  gettimeofday(&now, nullptr);
638,328✔
275

276
  int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
638,328✔
277

278
  if (reset) {
638,328✔
279
    d_set = now;
371,651✔
280
  }
371,651✔
281

282
  return ret;
638,328✔
283
}
638,328✔
284

285
inline void toLowerInPlace(string& str)
286
{
8,491,375✔
287
  const size_t length = str.length();
8,491,375✔
288
  char c;
8,491,375✔
289
  for (size_t i = 0; i < length; ++i) {
162,141,895✔
290
    c = dns_tolower(str[i]);
153,650,520✔
291
    if (c != str[i]) {
153,650,520✔
292
      str[i] = c;
995,356✔
293
    }
995,356✔
294
  }
153,650,520✔
295
}
8,491,375✔
296

297
inline const string toLower(const string &upper)
298
{
2,844,464✔
299
  string reply(upper);
2,844,464✔
300

301
  toLowerInPlace(reply);
2,844,464✔
302

303
  return reply;
2,844,464✔
304
}
2,844,464✔
305

306
inline const string toLowerCanonic(const string &upper)
307
{
218✔
308
  string reply(upper);
218✔
309
  if (!reply.empty()) {
218!
310
    const auto length = reply.length();
218✔
311
    if (reply[length - 1] == '.') {
218!
312
      reply.resize(length - 1);
218✔
313
    }
218✔
314
    toLowerInPlace(reply);
218✔
315
  }
218✔
316
  return reply;
218✔
317
}
218✔
318

319
// Make s uppercase:
320
inline string toUpper( const string& s )
321
{
6,731,244✔
322
  string r(s);
6,731,244✔
323
  for (size_t i = 0; i < s.length(); ++i) {
24,603,248✔
324
    r[i] = dns_toupper(r[i]);
17,872,004✔
325
  }
17,872,004✔
326
  return r;
6,731,244✔
327
}
6,731,244✔
328

329
inline double getTime()
330
{
×
331
  struct timeval now;
×
332
  gettimeofday(&now,0);
×
333

×
334
  return now.tv_sec+now.tv_usec/1000000.0;
×
335
}
×
336

337
[[noreturn]] inline void unixDie(const string &why)
338
{
7✔
339
  throw runtime_error(why + ": " + stringerror(errno));
7✔
340
}
7✔
341

342
string makeHexDump(const string& str, const string& sep = " ");
343
//! Convert the hexstring in to a byte string
344
string makeBytesFromHex(const string &in);
345

346
void normalizeTV(struct timeval& tv);
347
struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
348
struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
349

350
inline float makeFloat(const struct timeval& tv)
351
{
60,533✔
352
  return tv.tv_sec + tv.tv_usec/1000000.0f;
60,533✔
353
}
60,533✔
354
inline uint64_t uSec(const struct timeval& tv)
355
{
22,230✔
356
  return tv.tv_sec * 1000000 + tv.tv_usec;
22,230✔
357
}
22,230✔
358

359
inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
360
{
569,354✔
361
  return std::tie(lhs.tv_sec, lhs.tv_usec) < std::tie(rhs.tv_sec, rhs.tv_usec);
569,354✔
362
}
569,354✔
363
inline bool operator<=(const struct timeval& lhs, const struct timeval& rhs)
364
{
4,197✔
365
  return std::tie(lhs.tv_sec, lhs.tv_usec) <= std::tie(rhs.tv_sec, rhs.tv_usec);
4,197✔
366
}
4,197✔
367

368
inline bool operator<(const struct timespec& lhs, const struct timespec& rhs)
369
{
239,455✔
370
  return std::tie(lhs.tv_sec, lhs.tv_nsec) < std::tie(rhs.tv_sec, rhs.tv_nsec);
239,455✔
371
}
239,455✔
372

373

374
inline int pdns_ilexicographical_compare_three_way(std::string_view a, std::string_view b)  __attribute__((pure));
375
inline int pdns_ilexicographical_compare_three_way(std::string_view a, std::string_view b)
376
{
140,601,099✔
377
  const unsigned char *aPtr = (const unsigned char*)a.data(), *bPtr = (const unsigned char*)b.data();
140,601,099✔
378
  const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length();
140,601,099✔
379
  while(aPtr != aEptr && bPtr != bEptr) {
710,290,605✔
380
    if (*aPtr != *bPtr) {
691,191,947✔
381
      if (int rc = dns_tolower(*aPtr) - dns_tolower(*bPtr); rc != 0) {
121,507,719✔
382
        return rc;
121,502,441✔
383
      }
121,502,441✔
384
    }
121,502,362✔
385
    aPtr++;
569,689,506✔
386
    bPtr++;
569,689,506✔
387
  }
569,689,506✔
388
  // At this point, one of the strings has been completely processed.
389
  // Either both have the same length, and they are equal, or one of them
390
  // is larger, and compares as higher.
391
  if (aPtr == aEptr) {
19,130,352✔
392
    if (bPtr != bEptr) {
16,220,897✔
393
      return -1; // a < b
122,253✔
394
    }
122,253✔
395
  }
16,220,897✔
396
  else {
2,150,393,102✔
397
    return 1; // a > b
2,150,393,102✔
398
  }
2,150,393,102✔
399
  return 0; // a == b
16,098,644✔
400
}
19,098,658✔
401

402
inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)  __attribute__((pure));
403
inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
404
{
10,759✔
405
  return pdns_ilexicographical_compare_three_way(a, b) < 0;
10,759✔
406
}
10,759✔
407

408
inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
409
inline bool pdns_iequals(const std::string& a, const std::string& b)
410
{
13,791,999✔
411
  if (a.length() != b.length())
13,791,999✔
412
    return false;
9,288,540✔
413

414
  return pdns_ilexicographical_compare_three_way(a, b) == 0;
4,503,459✔
415
}
13,791,999✔
416

417
inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure));
418
inline bool pdns_iequals_ch(const char a, const char b)
419
{
×
420
  if ((a != b) && (dns_tolower(a) != dns_tolower(b)))
×
421
    return false;
×
422

423
  return true;
×
424
}
×
425

426

427
typedef unsigned long AtomicCounterInner;
428
typedef std::atomic<AtomicCounterInner> AtomicCounter ;
429

430
// FIXME400 this should probably go?
431
struct CIStringCompare
432
{
433
  bool operator()(const string& a, const string& b) const
434
  {
10,591✔
435
    return pdns_ilexicographical_compare(a, b);
10,591✔
436
  }
10,591✔
437
};
438

439
struct CIStringComparePOSIX
440
{
441
   bool operator() (const std::string& lhs, const std::string& rhs) const
442
   {
16,411✔
443
      const std::locale &loc = std::locale("POSIX");
16,411✔
444
      auto lhsIter = lhs.begin();
16,411✔
445
      auto rhsIter = rhs.begin();
16,411✔
446
      while (lhsIter != lhs.end()) {
528,545!
447
        if (rhsIter == rhs.end() || std::tolower(*rhsIter,loc) < std::tolower(*lhsIter,loc)) {
528,545!
448
          return false;
6,397✔
449
        }
6,397✔
450
        if (std::tolower(*lhsIter,loc) < std::tolower(*rhsIter,loc)) {
522,148✔
451
          return true;
10,014✔
452
        }
10,014✔
453
        ++lhsIter;++rhsIter;
512,134✔
454
      }
512,134✔
455
      return rhsIter != rhs.end();
×
456
   }
16,411✔
457
};
458

459
struct CIStringPairCompare
460
{
461
  bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
462
  {
93✔
463
    if(pdns_ilexicographical_compare(a.first, b.first))
93✔
464
        return true;
45✔
465
    if(pdns_ilexicographical_compare(b.first, a.first))
48✔
466
        return false;
9✔
467
    return a.second < b.second;
39✔
468
  }
48✔
469
};
470

471
inline size_t pdns_ci_find(const string& haystack, const string& needle)
472
{
×
473
  string::const_iterator it = std::search(haystack.begin(), haystack.end(),
×
474
    needle.begin(), needle.end(), pdns_iequals_ch);
×
475
  if (it == haystack.end()) {
×
476
    // not found
477
    return string::npos;
×
478
  } else {
×
479
    return it - haystack.begin();
×
480
  }
×
481
}
×
482

483
pair<string, string> splitField(const string& inp, char sepa);
484

485
inline bool isCanonical(std::string_view qname)
486
{
4,320,664✔
487
  return boost::ends_with(qname, ".");
4,320,664✔
488
}
4,320,664✔
489

490
inline DNSName toCanonic(const ZoneName& zone, const string& qname)
491
{
37,865✔
492
  if(qname.size()==1 && qname[0]=='@')
37,865!
493
    return DNSName(zone);
×
494
  if(isCanonical(qname))
37,865✔
495
    return DNSName(qname);
27,734✔
496
  return DNSName(qname) += DNSName(zone);
10,131✔
497
}
37,865✔
498

499
string stripDot(const string& dom);
500

501
int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
502
int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
503
int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
504
bool stringfgets(FILE* fp, std::string& line);
505

506
template<typename Index>
507
std::pair<typename Index::iterator,bool>
508
replacing_insert(Index& i,const typename Index::value_type& x)
509
{
2,815✔
510
  std::pair<typename Index::iterator,bool> res=i.insert(x);
2,815✔
511
  if(!res.second)res.second=i.replace(res.first,x);
2,815✔
512
  return res;
2,815✔
513
}
2,815✔
514

515
/** very small regex wrapper */
516
class Regex
517
{
518
public:
519
  /** constructor that accepts the expression to regex */
520
  Regex(const string &expr);
521

522
  ~Regex()
523
  {
22✔
524
    regfree(&d_preg);
22✔
525
  }
22✔
526
  /** call this to find out if 'line' matches your expression */
527
  bool match(const string &line) const
528
  {
1,374✔
529
    return regexec(&d_preg,line.c_str(),0,0,0)==0;
1,374✔
530
  }
1,374✔
531
  bool match(const DNSName& name) const
532
  {
×
533
    return match(name.toStringNoDot());
×
534
  }
×
535

536
private:
537
  regex_t d_preg;
538
};
539

540
class SimpleMatch
541
{
542
public:
543
  SimpleMatch(string mask, bool caseFold = false) :
544
    d_mask(std::move(mask)), d_fold(caseFold)
545
  {
112✔
546
  }
112✔
547

548
  bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend) const
549
  {
2,319,479✔
550
    for(;;++mi) {
2,417,295✔
551
      if (mi == mend) {
2,417,295✔
552
        return vi == vend;
38✔
553
      } else if (*mi == '?') {
2,417,257✔
554
        if (vi == vend) return false;
12✔
555
        ++vi;
9✔
556
      } else if (*mi == '*') {
2,417,245✔
557
        while(mi != mend && *mi == '*') ++mi;
246,186✔
558
        if (mi == mend) return true;
123,093✔
559
        while(vi != vend) {
2,237,177✔
560
          if (match(mi,mend,vi,vend)) return true;
2,114,151✔
561
          ++vi;
2,114,122✔
562
        }
2,114,122✔
563
        return false;
123,026✔
564
      } else {
2,294,152✔
565
        if ((mi == mend && vi != vend)||
2,294,152!
566
            (mi != mend && vi == vend)) return false;
2,294,152!
567
        if (d_fold) {
2,291,748✔
568
          if (dns_tolower(*mi) != dns_tolower(*vi)) return false;
2,291,658✔
569
        } else {
2,291,748✔
570
          if (*mi != *vi) return false;
90✔
571
        }
90✔
572
        ++vi;
97,807✔
573
      }
97,807✔
574
    }
2,417,295✔
575
  }
2,319,479✔
576

577
  bool match(const string& value) const {
205,328✔
578
    return match(d_mask.begin(), d_mask.end(), value.begin(), value.end());
205,328✔
579
  }
205,328✔
580

581
  bool match(const DNSName& name) const {
×
582
    return match(name.toStringNoDot());
×
583
  }
×
584

585
#if defined(PDNS_AUTH) // [
586
  bool match(const ZoneName& name) const {
1,382✔
587
    return match(name.toStringNoDot());
1,382✔
588
  }
1,382✔
589
#endif // ]
590

591
private:
592
  const string d_mask;
593
  const bool d_fold;
594
};
595

596
union ComboAddress;
597

598
// An aligned type to hold cmsgbufs. See https://man.openbsd.org/CMSG_DATA
599
typedef union { struct cmsghdr hdr; char buf[256]; } cmsgbuf_aligned;
600

601
/* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */
602
void addCMsgSrcAddr(struct msghdr* msgh, cmsgbuf_aligned* cbuf, const ComboAddress* source, int itfIndex);
603

604
unsigned int getFilenumLimit(bool hardOrSoft=0);
605
void setFilenumLimit(unsigned int lim);
606
bool readFileIfThere(const char* fname, std::string* line);
607
bool setSocketTimestamps(int fd);
608

609
//! Sets the socket into blocking mode.
610
bool setBlocking( int sock );
611

612
void setDscp(int sock, unsigned short family, uint8_t dscp);
613

614
//! Sets the socket into non-blocking mode.
615
bool setNonBlocking( int sock );
616
bool setTCPNoDelay(int sock);
617
bool setReuseAddr(int sock);
618
bool isNonBlocking(int sock);
619
bool setReceiveSocketErrors(int sock, int af);
620
int closesocket(int socket);
621
bool setCloseOnExec(int sock);
622

623
size_t getPipeBufferSize(int fd);
624
bool setPipeBufferSize(int fd, size_t size);
625

626
uint64_t udpErrorStats(const std::string& str);
627
uint64_t udp6ErrorStats(const std::string& str);
628
uint64_t tcpErrorStats(const std::string& str);
629
uint64_t getRealMemoryUsage(const std::string&);
630
uint64_t getSpecialMemoryUsage(const std::string&);
631
uint64_t getOpenFileDescriptors(const std::string&);
632
uint64_t getCPUTimeUser(const std::string&);
633
uint64_t getCPUTimeSystem(const std::string&);
634
uint64_t getCPUIOWait(const std::string&);
635
uint64_t getCPUSteal(const std::string&);
636
std::string getMACAddress(const ComboAddress& ca);
637
int getMACAddress(const ComboAddress& ca, char* dest, size_t len);
638

639
template<typename T>
640
const T& defTer(const T& a, const T& b)
641
{
9✔
642
  return a ? a : b;
9!
643
}
9✔
644

645
template<typename P, typename T>
646
T valueOrEmpty(const P val) {
92✔
647
  if (!val) return T{};
92!
648
  return T(val);
92✔
649
}
92✔
650

651

652
// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
653
template <typename Integer,
654
typename std::enable_if_t<std::is_integral_v<Integer>, bool> = true>
655
const char* addS(Integer siz, const char* singular = "", const char *plural = "s")
656
{
94✔
657
  if (siz == 1) {
94✔
658
    return singular;
29✔
659
  }
29✔
660
  return plural;
65✔
661
}
94✔
662

663
template <typename C,
664
typename std::enable_if_t<std::is_class_v<C>, bool> = true>
665
const char* addS(const C& c, const char* singular = "", const char *plural = "s")
666
{
667
  return addS(c.size(), singular, plural);
668
}
669

670
template<typename C>
671
const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key)
672
{
5,432✔
673
  auto fnd = c.find(key);
5,432✔
674
  if(fnd == c.end())
5,432!
675
    return 0;
68✔
676
  return &fnd->second;
5,364✔
677
}
5,432✔
678

679
double DiffTime(const struct timespec& first, const struct timespec& second);
680
double DiffTime(const struct timeval& first, const struct timeval& second);
681
uid_t strToUID(const string &str);
682
gid_t strToGID(const string &str);
683

684
namespace pdns
685
{
686
/**
687
 * \brief Does a checked conversion from one integer type to another.
688
 *
689
 * \warning The source type `F` and target type `T` must have the same
690
 * signedness, otherwise a compilation error is thrown.
691
 *
692
 * \exception std::out_of_range Thrown if the source value does not fit
693
 * in the target type.
694
 *
695
 * \param[in] from The source value of type `F`.
696
 *
697
 * \return The target value of type `T`.
698
 */
699
template <typename T, typename F>
700
auto checked_conv(F from) -> T
701
{
5,599,510✔
702
  static_assert(std::numeric_limits<F>::is_integer, "checked_conv: The `F` type must be an integer");
5,599,510✔
703
  static_assert(std::numeric_limits<T>::is_integer, "checked_conv: The `T` type must be an integer");
5,599,510✔
704
  static_assert((std::numeric_limits<F>::is_signed && std::numeric_limits<T>::is_signed) || (!std::numeric_limits<F>::is_signed && !std::numeric_limits<T>::is_signed),
5,599,510✔
705
                "checked_conv: The `T` and `F` types must either both be signed or unsigned");
5,599,510✔
706

707
  constexpr auto tMin = std::numeric_limits<T>::min();
5,599,510✔
708
  if constexpr (std::numeric_limits<F>::min() != tMin) {
5,390,759✔
709
    if (from < tMin) {
1,749,985!
710
      string s = "checked_conv: source value " + std::to_string(from) + " is smaller than target's minimum possible value " + std::to_string(tMin);
529,371✔
711
      throw std::out_of_range(s);
529,371✔
712
    }
529,371✔
713
  }
1,749,985✔
714

715
  constexpr auto tMax = std::numeric_limits<T>::max();
1,958,737✔
716
  if constexpr (std::numeric_limits<F>::max() != tMax) {
5,599,510✔
717
    if (from > tMax) {
5,598,211✔
718
      string s = "checked_conv: source value " + std::to_string(from) + " is larger than target's maximum possible value " + std::to_string(tMax);
26✔
719
      throw std::out_of_range(s);
26✔
720
    }
26✔
721
  }
5,598,211✔
722

723
  return static_cast<T>(from);
5,598,184✔
724
}
1,982,515✔
725

726
/**
727
 * \brief Performs a conversion from `std::string&` to integer.
728
 *
729
 * This function internally calls `std::stoll` and `std::stoull` to do
730
 * the conversion from `std::string&` and calls `pdns::checked_conv` to
731
 * do the checked conversion from `long long`/`unsigned long long` to
732
 * `T`.
733
 *
734
 * \warning The target type `T` must be an integer, otherwise a
735
 * compilation error is thrown.
736
 *
737
 * \exception std:stoll Throws what std::stoll throws.
738
 *
739
 * \exception std::stoull Throws what std::stoull throws.
740
 *
741
 * \exception pdns::checked_conv Throws what pdns::checked_conv throws.
742
 *
743
 * \param[in] str The input string to be converted.
744
 *
745
 * \param[in] idx Location to store the index at which processing
746
 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
747
 *
748
 * \param[in] base The numerical base for conversion.
749
 *
750
 * \return `str` converted to integer `T`, or 0 if `str` is empty.
751
 */
752
template <typename T>
753
auto checked_stoi(const std::string& str, size_t* idx = nullptr, int base = 10) -> T
754
{
5,617,662✔
755
  static_assert(std::numeric_limits<T>::is_integer, "checked_stoi: The `T` type must be an integer");
5,617,662✔
756

757
  if (str.empty()) {
5,617,662!
758
    if (idx != nullptr) {
17,118!
759
      *idx = 0;
×
760
    }
×
761

762
    return 0; // compatibility
17,118✔
763
  }
17,118✔
764

765
  if constexpr (std::is_unsigned_v<T>) {
5,600,544✔
766
    return pdns::checked_conv<T>(std::stoull(str, idx, base));
1,983,729✔
767
  }
1,750,484✔
768
  else {
1,750,490✔
769
    return pdns::checked_conv<T>(std::stoll(str, idx, base));
1,750,490✔
770
  }
1,750,490✔
771
}
5,600,544✔
772

773
/**
774
 * \brief Performs a conversion from `std::string&` to integer.
775
 *
776
 * This function internally calls `pdns::checked_stoi` and stores its
777
 * result in `out`.
778
 *
779
 * \exception pdns::checked_stoi Throws what pdns::checked_stoi throws.
780
 *
781
 * \param[out] out `str` converted to integer `T`, or 0 if `str` is
782
 * empty.
783
 *
784
 * \param[in] str The input string to be converted.
785
 *
786
 * \param[in] idx Location to store the index at which processing
787
 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
788
 *
789
 * \param[in] base The numerical base for conversion.
790
 *
791
 * \return `str` converted to integer `T`, or 0 if `str` is empty.
792
 */
793
template <typename T>
794
auto checked_stoi_into(T& out, const std::string& str, size_t* idx = nullptr, int base = 10)
795
{
2,807,700✔
796
  out = checked_stoi<T>(str, idx, base);
2,807,700✔
797
}
2,807,700✔
798
}
799

800
bool isSettingThreadCPUAffinitySupported();
801
int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus);
802

803
std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath);
804

805
DNSName reverseNameFromIP(const ComboAddress& ip);
806

807
size_t parseRFC1035CharString(const std::string &in, std::string &val); // from ragel
808
size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, vector<std::string> &val); // from ragel
809
size_t parseSVCBValueList(const std::string &in, vector<std::string> &val);
810

811
std::string makeLuaString(const std::string& in);
812

813
bool constantTimeStringEquals(const std::string& a, const std::string& b);
814

815
// Used in NID and L64 records
816
struct NodeOrLocatorID { uint8_t content[8]; };
817

818
struct FDWrapper
819
{
820
  FDWrapper() = default;
21,415✔
821
  FDWrapper(int desc): d_fd(desc) {}
28,156✔
822
  FDWrapper(const FDWrapper&) = delete;
823
  FDWrapper& operator=(const FDWrapper& rhs) = delete;
824

825

826
  ~FDWrapper()
827
  {
86,858✔
828
    reset();
86,858✔
829
  }
86,858✔
830

831
  FDWrapper(FDWrapper&& rhs) noexcept : d_fd(rhs.d_fd)
70,642✔
832
  {
74,536✔
833
    rhs.d_fd = -1;
74,536✔
834
  }
74,536✔
835

836
  FDWrapper& operator=(FDWrapper&& rhs) noexcept
837
  {
21,875✔
838
    if (d_fd >= 0) {
21,875✔
839
      close(d_fd);
6✔
840
    }
6✔
841
    d_fd = rhs.d_fd;
21,875✔
842
    rhs.d_fd = -1;
21,875✔
843
    return *this;
21,875✔
844
  }
21,875✔
845

846
  [[nodiscard]] int getHandle() const
847
  {
6,563,001✔
848
    return d_fd;
6,563,001✔
849
  }
6,563,001✔
850

851
  operator int() const
852
  {
8,235✔
853
    return d_fd;
8,235✔
854
  }
8,235✔
855

856
  int reset()
857
  {
86,876✔
858
    int ret = 0;
86,876✔
859
    if (d_fd >= 0) {
86,876✔
860
      ret = close(d_fd);
1,058✔
861
    }
1,058✔
862
    d_fd = -1;
86,876✔
863
    return ret;
86,876✔
864
  }
86,876✔
865

866
  int release()
867
  {
544✔
868
    auto ret = d_fd;
544✔
869
    d_fd = -1;
544✔
870
    return ret;
544✔
871
  }
544✔
872

873
private:
874
  int d_fd{-1};
875
};
876

877
namespace pdns
878
{
879
[[nodiscard]] std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor);
880

881
struct FilePtrDeleter
882
{
883
  /* using a deleter instead of decltype(&fclose) has two big advantages:
884
     - the deleter is included in the type and does not have to be passed
885
       when creating a new object (easier to use, less memory usage, in theory
886
       better inlining)
887
     - we avoid the annoying "ignoring attributes on template argument ‘int (*)(FILE*)’"
888
       warning from the compiler, which is there because fclose is tagged as __nonnull((1))
889
  */
890
  void operator()(FILE* filePtr) const noexcept {
547✔
891
    fclose(filePtr);
547✔
892
  }
547✔
893
};
894

895
using UniqueFilePtr = std::unique_ptr<FILE, FilePtrDeleter>;
896

897
UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist = true, bool appendIfExists = false);
898
}
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