]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/misc.hh
rec: allow exception to proxy protocal usage for specific listen addresses
[thirdparty/pdns.git] / pdns / misc.hh
CommitLineData
12c86877 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
ea76bac0 22#pragma once
d2adfa5c 23#include <cinttypes>
8b3cfcd3 24#include <cstring>
f9822705 25#include <cstdio>
3ee84c3f 26#include <regex.h>
d2adfa5c 27#include <climits>
88bf3279 28#include <type_traits>
d190894c 29
905dae56 30#include <boost/algorithm/string.hpp>
12c86877 31
e67e250f 32#include "dns.hh"
ac0995bb 33#include <atomic>
76473b92
KM
34#include <sys/time.h>
35#include <sys/types.h>
36#include <sys/socket.h>
d2adfa5c 37#include <ctime>
76473b92 38#include <syslog.h>
a640a9d4 39#include <stdexcept>
12c86877 40#include <string>
d2adfa5c 41#include <cctype>
e67e250f
BH
42#include <vector>
43
10f4eea8 44#include "namespaces.hh"
42c83cbc
OM
45
46class DNSName;
d72aaada 47
d2adfa5c 48// Do not change to "using TSIGHashEnum ..." until you know CodeQL does not choke on it
bcb5b94e 49typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
da78b86e
FM
50namespace pdns
51{
52/**
53 * \brief Retrieves the errno-based error message in a reentrant way.
54 *
55 * This internally handles the portability issues around using
56 * `strerror_r` and returns a `std::string` that owns the error
57 * message's contents.
58 *
59 * \param[in] errnum The errno value.
60 *
61 * \return The `std::string` error message.
62 */
63auto getMessageFromErrno(int errnum) -> std::string;
66910c5d 64
799aa185 65#if defined(HAVE_LIBCRYPTO)
66910c5d
FM
66namespace OpenSSL
67{
68 /**
69 * \brief Throws a `std::runtime_error` with the current OpenSSL error.
70 *
71 * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
72 */
73 [[nodiscard]] auto error(const std::string& errorMessage) -> std::runtime_error;
74
75 /**
76 * \brief Throws a `std::runtime_error` with a name and the current OpenSSL error.
77 *
78 * \param[in] componentName The name of the component to mark the error message with.
79 * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
80 */
81 [[nodiscard]] auto error(const std::string& componentName, const std::string& errorMessage) -> std::runtime_error;
82}
83#endif // HAVE_LIBCRYPTO
da78b86e
FM
84}
85
cc3afe25 86string nowTime();
d2adfa5c 87string unquotify(const string &item);
12c86877 88string humanDuration(time_t passed);
f2c11a48 89bool stripDomainSuffix(string *qname, const string &domain);
12c86877 90void stripLine(string &line);
ff32c991
FM
91std::optional<string> getHostname();
92std::string getCarbonHostName();
12c86877 93string urlEncode(const string &text);
d2adfa5c 94int waitForData(int fileDesc, int seconds, int useconds = 0);
f4ff5929 95int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
d529011f 96int waitForMultiData(const set<int>& fds, const int seconds, const int useconds, int* fd);
d2adfa5c 97int waitForRWData(int fileDesc, bool waitForRead, int seconds, int useconds, bool* error = nullptr, bool* disconnected = nullptr);
21a3792f
KM
98bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum);
99DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum);
58044407 100
f8499e52 101int logFacilityToLOG(unsigned int facility);
bbce5bf0 102
6e01be56 103template<typename Container>
12c86877
BH
104void
105stringtok (Container &container, string const &in,
106 const char * const delimiters = " \t\n")
107{
108 const string::size_type len = in.length();
109 string::size_type i = 0;
3ddb9247 110
12c86877
BH
111 while (i<len) {
112 // eat leading whitespace
113 i = in.find_first_not_of (delimiters, i);
114 if (i == string::npos)
115 return; // nothing left but white space
3ddb9247 116
12c86877
BH
117 // find the end of the token
118 string::size_type j = in.find_first_of (delimiters, i);
3ddb9247 119
12c86877
BH
120 // push token
121 if (j == string::npos) {
122 container.push_back (in.substr(i));
123 return;
124 } else
125 container.push_back (in.substr(i, j-i));
3ddb9247 126
12c86877
BH
127 // set up for next loop
128 i = j + 1;
129 }
130}
8c3149f2 131
f7a69a4c
RA
132template<typename T> bool rfc1982LessThan(T a, T b)
133{
abb11ca4
RP
134 static_assert(std::is_unsigned_v<T>, "rfc1982LessThan only works for unsigned types");
135 return std::make_signed_t<T>(a - b) < 0;
f7a69a4c
RA
136}
137
0ab3fdc6 138// fills container with ranges, so {posbegin,posend}
8c3149f2
BH
139template <typename Container>
140void
141vstringtok (Container &container, string const &in,
142 const char * const delimiters = " \t\n")
143{
144 const string::size_type len = in.length();
145 string::size_type i = 0;
3ddb9247 146
8c3149f2
BH
147 while (i<len) {
148 // eat leading whitespace
149 i = in.find_first_not_of (delimiters, i);
150 if (i == string::npos)
151 return; // nothing left but white space
3ddb9247 152
8c3149f2
BH
153 // find the end of the token
154 string::size_type j = in.find_first_of (delimiters, i);
3ddb9247 155
8c3149f2
BH
156 // push token
157 if (j == string::npos) {
e32a8d46 158 container.emplace_back(i, len);
8c3149f2
BH
159 return;
160 } else
e32a8d46 161 container.emplace_back(i, j);
3ddb9247 162
8c3149f2
BH
163 // set up for next loop
164 i = j + 1;
165 }
166}
167
a683e8bd
RG
168size_t writen2(int fd, const void *buf, size_t count);
169inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
170size_t readn2(int fd, void* buffer, size_t len);
1342b949 171size_t readn2WithTimeout(int fd, void* buffer, size_t len, const struct timeval& idleTimeout, const struct timeval& totalTimeout={0,0}, bool allowIncomplete=false);
50111728 172size_t writen2WithTimeout(int fd, const void * buffer, size_t len, const struct timeval& timeout);
040712e0 173
5f2286f1 174void toLowerInPlace(string& str);
c3d9d009 175const string toLower(const string &upper);
b0d4fb45 176const string toLowerCanonic(const string &upper);
092f210a 177bool IpToU32(const string &str, uint32_t *ip);
5730f30c 178string U32ToIP(uint32_t);
c20313ec
OM
179
180inline string stringerror(int err = errno)
181{
182 return pdns::getMessageFromErrno(err);
183}
184
d88babea 185string bitFlip(const string &str);
12c86877
BH
186
187void dropPrivs(int uid, int gid);
12c86877
BH
188void cleanSlashes(string &str);
189
c6d04bdc 190#if defined(_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
df13e61d 191/** CPUTime measurements */
192class CPUTime
193{
194public:
195 void start()
196 {
197 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &d_start);
198 }
199 uint64_t ndiff()
200 {
201 struct timespec now;
202 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
203 return 1000000000ULL*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec);
204 }
205private:
206 struct timespec d_start;
207};
3ddb9247 208#endif
df13e61d 209
3ddb9247 210/** The DTime class can be used for timing statistics with microsecond resolution.
12c86877 211On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
3ddb9247 212class DTime
12c86877
BH
213{
214public:
c0833d0c
RG
215 //!< Does not set the timer for you! Saves lots of gettimeofday() calls
216 DTime() = default;
f238ce64
OM
217 DTime(const DTime &dt) = default;
218 DTime & operator=(const DTime &dt) = default;
c0833d0c 219 inline time_t time() const;
12c86877 220 inline void set(); //!< Reset the timer
c95554f3
RG
221 inline int udiff(bool reset = true); //!< Return the number of microseconds since the timer was last set.
222
223 int udiffNoReset() //!< Return the number of microseconds since the timer was last set.
224 {
225 return udiff(false);
226 }
88358c9b
BH
227 void setTimeval(const struct timeval& tv)
228 {
229 d_set=tv;
230 }
c0833d0c 231 struct timeval getTimeval() const
88358c9b
BH
232 {
233 return d_set;
234 }
12c86877 235private:
c0833d0c 236struct timeval d_set{0, 0};
12c86877 237};
85db02c5 238
c0833d0c
RG
239inline time_t DTime::time() const
240{
241 return d_set.tv_sec;
242}
243
12c86877
BH
244inline void DTime::set()
245{
c0833d0c 246 gettimeofday(&d_set, nullptr);
12c86877
BH
247}
248
c95554f3 249inline int DTime::udiff(bool reset)
12c86877
BH
250{
251 struct timeval now;
c0833d0c 252 gettimeofday(&now, nullptr);
c95554f3 253
fe213470 254 int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
c95554f3
RG
255
256 if (reset) {
257 d_set = now;
258 }
259
fe213470 260 return ret;
12c86877
BH
261}
262
5f2286f1 263inline void toLowerInPlace(string& str)
12c86877 264{
5f2286f1 265 const size_t length = str.length();
c536ca8d 266 char c;
3bb964fd 267 for (size_t i = 0; i < length; ++i) {
5f2286f1
RG
268 c = dns_tolower(str[i]);
269 if (c != str[i]) {
270 str[i] = c;
271 }
c536ca8d 272 }
5f2286f1
RG
273}
274
275inline const string toLower(const string &upper)
276{
277 string reply(upper);
278
279 toLowerInPlace(reply);
280
12c86877
BH
281 return reply;
282}
283
b0d4fb45
BH
284inline const string toLowerCanonic(const string &upper)
285{
286 string reply(upper);
287 if(!upper.empty()) {
705f31ae 288 unsigned int i, limit= ( unsigned int ) reply.length();
1352c9b6 289 unsigned char c;
c536ca8d 290 for(i = 0; i < limit ; i++) {
e3cacd48
BH
291 c = dns_tolower(upper[i]);
292 if(c != upper[i])
4957a608 293 reply[i] = c;
3ddb9247 294 }
e3cacd48 295 if(upper[i-1]=='.')
b0d4fb45
BH
296 reply.resize(i-1);
297 }
3ddb9247 298
b0d4fb45
BH
299 return reply;
300}
301
302
12c86877 303
52936200
BH
304// Make s uppercase:
305inline string toUpper( const string& s )
306{
4957a608
BH
307 string r(s);
308 for( unsigned int i = 0; i < s.length(); i++ ) {
315f45a0 309 r[i] = dns_toupper(r[i]);
4957a608
BH
310 }
311 return r;
52936200
BH
312}
313
a6d7640a
BH
314inline double getTime()
315{
316 struct timeval now;
15ad1a99 317 gettimeofday(&now,0);
3ddb9247 318
a6d7640a
BH
319 return now.tv_sec+now.tv_usec/1000000.0;
320}
321
a640a9d4
BH
322inline void unixDie(const string &why)
323{
a2a81d42 324 throw runtime_error(why+": "+stringerror());
a640a9d4
BH
325}
326
2db9c30e 327string makeHexDump(const string& str);
a02d0fa6
PL
328//! Convert the hexstring in to a byte string
329string makeBytesFromHex(const string &in);
88358c9b
BH
330
331void normalizeTV(struct timeval& tv);
d2adfa5c
OM
332struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
333struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
334
88358c9b
BH
335inline float makeFloat(const struct timeval& tv)
336{
705f31ae 337 return tv.tv_sec + tv.tv_usec/1000000.0f;
88358c9b 338}
a71665e5 339inline uint64_t uSec(const struct timeval& tv)
7ab9f171 340{
a71665e5 341 return tv.tv_sec * 1000000 + tv.tv_usec;
7ab9f171 342}
5b0ddd18 343
3ddb9247 344inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
5b0ddd18 345{
905dae56 346 return std::tie(lhs.tv_sec, lhs.tv_usec) < std::tie(rhs.tv_sec, rhs.tv_usec);
50111728
O
347}
348inline bool operator<=(const struct timeval& lhs, const struct timeval& rhs)
349{
905dae56 350 return std::tie(lhs.tv_sec, lhs.tv_usec) <= std::tie(rhs.tv_sec, rhs.tv_usec);
5b0ddd18
BH
351}
352
80a216c9 353inline bool operator<(const struct timespec& lhs, const struct timespec& rhs)
354{
905dae56 355 return std::tie(lhs.tv_sec, lhs.tv_nsec) < std::tie(rhs.tv_sec, rhs.tv_nsec);
80a216c9 356}
357
358
ec6480f3 359inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure));
8fb5b29a 360inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
7738a23f 361{
97a24230 362 const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str();
7fd7a590 363 const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length();
364 while(aPtr != aEptr && bPtr != bEptr) {
8fb5b29a
KM
365 if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr)))
366 return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0;
367 aPtr++;
368 bPtr++;
7738a23f 369 }
7fd7a590 370 if(aPtr == aEptr && bPtr == bEptr) // strings are equal (in length)
8fb5b29a 371 return false;
7fd7a590 372 return aPtr == aEptr; // true if first string was shorter
ec6480f3 373}
eff65ff8 374
ec6480f3 375inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
8fb5b29a 376inline bool pdns_iequals(const std::string& a, const std::string& b)
ec6480f3 377{
8fb5b29a
KM
378 if (a.length() != b.length())
379 return false;
380
ec6480f3 381 const char *aPtr = a.c_str(), *bPtr = b.c_str();
b10795de 382 const char *aEptr = aPtr + a.length();
383 while(aPtr != aEptr) {
8fb5b29a
KM
384 if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr)))
385 return false;
386 aPtr++;
387 bPtr++;
eff65ff8 388 }
8fb5b29a 389 return true;
ec6480f3
BH
390}
391
57cb86d8
CH
392inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure));
393inline bool pdns_iequals_ch(const char a, const char b)
394{
395 if ((a != b) && (dns_tolower(a) != dns_tolower(b)))
396 return false;
397
398 return true;
399}
400
1566533a 401
00c6f2b9
RG
402typedef unsigned long AtomicCounterInner;
403typedef std::atomic<AtomicCounterInner> AtomicCounter ;
1bc9e6bd 404
1e05b07c 405// FIXME400 this should probably go?
7587bcbe 406struct CIStringCompare
ec6480f3
BH
407{
408 bool operator()(const string& a, const string& b) const
eff65ff8 409 {
ec6480f3 410 return pdns_ilexicographical_compare(a, b);
eff65ff8 411 }
7738a23f 412};
eff65ff8 413
2aa1b703
AT
414struct CIStringComparePOSIX
415{
455eba69 416 bool operator() (const std::string& lhs, const std::string& rhs) const
2aa1b703 417 {
2aa1b703 418 const std::locale &loc = std::locale("POSIX");
455eba69
OM
419 auto lhsIter = lhs.begin();
420 auto rhsIter = rhs.begin();
421 while (lhsIter != lhs.end()) {
422 if (rhsIter == rhs.end() || std::tolower(*rhsIter,loc) < std::tolower(*lhsIter,loc)) {
423 return false;
424 }
425 if (std::tolower(*lhsIter,loc) < std::tolower(*rhsIter,loc)) {
426 return true;
427 }
428 ++lhsIter;++rhsIter;
2aa1b703 429 }
455eba69 430 return rhsIter != rhs.end();
2aa1b703
AT
431 }
432};
433
7587bcbe 434struct CIStringPairCompare
21f0f88b
BH
435{
436 bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
437 {
438 if(pdns_ilexicographical_compare(a.first, b.first))
439 return true;
440 if(pdns_ilexicographical_compare(b.first, a.first))
441 return false;
442 return a.second < b.second;
443 }
444};
445
57cb86d8
CH
446inline size_t pdns_ci_find(const string& haystack, const string& needle)
447{
448 string::const_iterator it = std::search(haystack.begin(), haystack.end(),
449 needle.begin(), needle.end(), pdns_iequals_ch);
450 if (it == haystack.end()) {
451 // not found
452 return string::npos;
453 } else {
454 return it - haystack.begin();
455 }
456}
21f0f88b 457
50c79a76 458pair<string, string> splitField(const string& inp, char sepa);
26cd1b3f 459
e720f311 460inline bool isCanonical(const string& qname)
26cd1b3f 461{
e720f311 462 if(qname.empty())
26cd1b3f 463 return false;
e720f311 464 return qname[qname.size()-1]=='.';
26cd1b3f
BH
465}
466
e720f311 467inline DNSName toCanonic(const DNSName& zone, const string& qname)
675fa24c 468{
e720f311 469 if(qname.size()==1 && qname[0]=='@')
8171ab83 470 return zone;
e720f311 471 if(isCanonical(qname))
8171ab83 472 return DNSName(qname);
e720f311 473 return DNSName(qname) += zone;
26cd1b3f 474}
da042e6e
BH
475
476string stripDot(const string& dom);
561434a6 477
f71bc087 478int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
76cb4593
CH
479int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
480int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
834942f1 481bool stringfgets(FILE* fp, std::string& line);
f0db590d
BH
482
483template<typename Index>
484std::pair<typename Index::iterator,bool>
485replacing_insert(Index& i,const typename Index::value_type& x)
486{
487 std::pair<typename Index::iterator,bool> res=i.insert(x);
488 if(!res.second)res.second=i.replace(res.first,x);
489 return res;
490}
491
3ee84c3f
BH
492/** very small regex wrapper */
493class Regex
494{
495public:
496 /** constructor that accepts the expression to regex */
497 Regex(const string &expr);
3ddb9247 498
3ee84c3f
BH
499 ~Regex()
500 {
501 regfree(&d_preg);
502 }
503 /** call this to find out if 'line' matches your expression */
6eecd4c2 504 bool match(const string &line) const
3ee84c3f
BH
505 {
506 return regexec(&d_preg,line.c_str(),0,0,0)==0;
507 }
6eecd4c2 508 bool match(const DNSName& name) const
60ee1829
AT
509 {
510 return match(name.toStringNoDot());
511 }
512
3ee84c3f
BH
513private:
514 regex_t d_preg;
515};
516
ac84f00c
AT
517class SimpleMatch
518{
519public:
8a70e507 520 SimpleMatch(const string &mask, bool caseFold = false): d_mask(mask), d_fold(caseFold)
ac84f00c 521 {
ac84f00c 522 }
1e05b07c 523
fe3b0645 524 bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend) const
ac84f00c 525 {
4b5da564 526 for(;;++mi) {
ac84f00c
AT
527 if (mi == mend) {
528 return vi == vend;
529 } else if (*mi == '?') {
530 if (vi == vend) return false;
4b5da564 531 ++vi;
ac84f00c 532 } else if (*mi == '*') {
17c75221 533 while(mi != mend && *mi == '*') ++mi;
fe3b0645 534 if (mi == mend) return true;
ac84f00c
AT
535 while(vi != vend) {
536 if (match(mi,mend,vi,vend)) return true;
4b5da564 537 ++vi;
ac84f00c
AT
538 }
539 return false;
540 } else {
541 if ((mi == mend && vi != vend)||
542 (mi != mend && vi == vend)) return false;
543 if (d_fold) {
544 if (dns_tolower(*mi) != dns_tolower(*vi)) return false;
545 } else {
546 if (*mi != *vi) return false;
547 }
4b5da564 548 ++vi;
ac84f00c
AT
549 }
550 }
551 }
552
fe3b0645 553 bool match(const string& value) const {
ac84f00c
AT
554 return match(d_mask.begin(), d_mask.end(), value.begin(), value.end());
555 }
556
fe3b0645 557 bool match(const DNSName& name) const {
ac84f00c
AT
558 return match(name.toStringNoDot());
559 }
560
561private:
fe3b0645
RG
562 const string d_mask;
563 const bool d_fold;
ac84f00c
AT
564};
565
65d8e171 566union ComboAddress;
7bec330a 567
00692909 568// An aligned type to hold cmsgbufs. See https://man.openbsd.org/CMSG_DATA
7bec330a
OM
569typedef union { struct cmsghdr hdr; char buf[256]; } cmsgbuf_aligned;
570
fbe2a2e0 571/* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */
7bec330a 572void addCMsgSrcAddr(struct msghdr* msgh, cmsgbuf_aligned* cbuf, const ComboAddress* source, int itfIndex);
3a8a4d68 573
574unsigned int getFilenumLimit(bool hardOrSoft=0);
575void setFilenumLimit(unsigned int lim);
4e9a20e6 576bool readFileIfThere(const char* fname, std::string* line);
915b0c39 577bool setSocketTimestamps(int fd);
15ad1a99 578
579//! Sets the socket into blocking mode.
580bool setBlocking( int sock );
581
582//! Sets the socket into non-blocking mode.
583bool setNonBlocking( int sock );
883a30a7 584bool setTCPNoDelay(int sock);
bf676f2f 585bool setReuseAddr(int sock);
18861f97 586bool isNonBlocking(int sock);
29bb743c 587bool setReceiveSocketErrors(int sock, int af);
d2adfa5c 588int closesocket(int socket);
3897b9e1 589bool setCloseOnExec(int sock);
74ad42dc 590
ee271fc4
RG
591size_t getPipeBufferSize(int fd);
592bool setPipeBufferSize(int fd, size_t size);
593
594uint64_t udpErrorStats(const std::string& str);
84d1d33a 595uint64_t udp6ErrorStats(const std::string& str);
e150c22c 596uint64_t tcpErrorStats(const std::string& str);
a1a787dc 597uint64_t getRealMemoryUsage(const std::string&);
330dcb5c 598uint64_t getSpecialMemoryUsage(const std::string&);
a9b6db56 599uint64_t getOpenFileDescriptors(const std::string&);
4f99f3d3
RG
600uint64_t getCPUTimeUser(const std::string&);
601uint64_t getCPUTimeSystem(const std::string&);
591d1bd3
RG
602uint64_t getCPUIOWait(const std::string&);
603uint64_t getCPUSteal(const std::string&);
6907f014 604std::string getMACAddress(const ComboAddress& ca);
6f238a33 605int getMACAddress(const ComboAddress& ca, char* dest, size_t len);
1c150f27 606
607template<typename T>
608const T& defTer(const T& a, const T& b)
609{
610 return a ? a : b;
611}
3555371a
AT
612
613template<typename P, typename T>
614T valueOrEmpty(const P val) {
615 if (!val) return T{};
616 return T(val);
617}
f5f96ff1 618
88bf3279 619
f5f96ff1 620// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
7f3b2173 621template <typename Integer,
abb11ca4 622typename std::enable_if_t<std::is_integral_v<Integer>, bool> = true>
7f3b2173 623const char* addS(Integer siz, const char* singular = "", const char *plural = "s")
f5f96ff1 624{
7f3b2173
O
625 if (siz == 1) {
626 return singular;
627 }
628 return plural;
f5f96ff1 629}
88bf3279 630
7f3b2173 631template <typename C,
abb11ca4 632typename std::enable_if_t<std::is_class_v<C>, bool> = true>
7f3b2173 633const char* addS(const C& c, const char* singular = "", const char *plural = "s")
88bf3279 634{
7f3b2173 635 return addS(c.size(), singular, plural);
88bf3279 636}
637
2ac8ae89 638template<typename C>
639const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key)
640{
641 auto fnd = c.find(key);
642 if(fnd == c.end())
643 return 0;
644 return &fnd->second;
645}
646
3fcaeeac 647double DiffTime(const struct timespec& first, const struct timespec& second);
648double DiffTime(const struct timeval& first, const struct timeval& second);
ffb07158 649uid_t strToUID(const string &str);
650gid_t strToGID(const string &str);
a5c4e4a6 651
a0383aad
FM
652namespace pdns
653{
654/**
655 * \brief Does a checked conversion from one integer type to another.
656 *
657 * \warning The source type `F` and target type `T` must have the same
658 * signedness, otherwise a compilation error is thrown.
659 *
660 * \exception std::out_of_range Thrown if the source value does not fit
661 * in the target type.
662 *
663 * \param[in] from The source value of type `F`.
664 *
665 * \return The target value of type `T`.
666 */
667template <typename T, typename F>
668auto checked_conv(F from) -> T
669{
670 static_assert(std::numeric_limits<F>::is_integer, "checked_conv: The `F` type must be an integer");
671 static_assert(std::numeric_limits<T>::is_integer, "checked_conv: The `T` type must be an integer");
672 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),
673 "checked_conv: The `T` and `F` types must either both be signed or unsigned");
674
bfd1f31b
FM
675 constexpr auto tMin = std::numeric_limits<T>::min();
676 if constexpr (std::numeric_limits<F>::min() != tMin) {
677 if (from < tMin) {
678 string s = "checked_conv: source value " + std::to_string(from) + " is smaller than target's minimum possible value " + std::to_string(tMin);
679 throw std::out_of_range(s);
680 }
681 }
682
683 constexpr auto tMax = std::numeric_limits<T>::max();
684 if constexpr (std::numeric_limits<F>::max() != tMax) {
685 if (from > tMax) {
686 string s = "checked_conv: source value " + std::to_string(from) + " is larger than target's maximum possible value " + std::to_string(tMax);
687 throw std::out_of_range(s);
688 }
a0383aad
FM
689 }
690
691 return static_cast<T>(from);
692}
693
694/**
695 * \brief Performs a conversion from `std::string&` to integer.
696 *
697 * This function internally calls `std::stoll` and `std::stoull` to do
698 * the conversion from `std::string&` and calls `pdns::checked_conv` to
699 * do the checked conversion from `long long`/`unsigned long long` to
700 * `T`.
701 *
702 * \warning The target type `T` must be an integer, otherwise a
703 * compilation error is thrown.
704 *
705 * \exception std:stoll Throws what std::stoll throws.
706 *
707 * \exception std::stoull Throws what std::stoull throws.
708 *
709 * \exception pdns::checked_conv Throws what pdns::checked_conv throws.
710 *
711 * \param[in] str The input string to be converted.
712 *
713 * \param[in] idx Location to store the index at which processing
222b61ff 714 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
a0383aad
FM
715 *
716 * \param[in] base The numerical base for conversion.
717 *
718 * \return `str` converted to integer `T`, or 0 if `str` is empty.
719 */
720template <typename T>
721auto checked_stoi(const std::string& str, size_t* idx = nullptr, int base = 10) -> T
722{
723 static_assert(std::numeric_limits<T>::is_integer, "checked_stoi: The `T` type must be an integer");
724
725 if (str.empty()) {
222b61ff
FM
726 if (idx != nullptr) {
727 *idx = 0;
728 }
729
a0383aad
FM
730 return 0; // compatibility
731 }
732
733 if constexpr (std::is_unsigned_v<T>) {
734 return pdns::checked_conv<T>(std::stoull(str, idx, base));
735 }
736 else {
737 return pdns::checked_conv<T>(std::stoll(str, idx, base));
738 }
739}
740
741/**
742 * \brief Performs a conversion from `std::string&` to integer.
743 *
744 * This function internally calls `pdns::checked_stoi` and stores its
745 * result in `out`.
746 *
747 * \exception pdns::checked_stoi Throws what pdns::checked_stoi throws.
748 *
749 * \param[out] out `str` converted to integer `T`, or 0 if `str` is
750 * empty.
751 *
752 * \param[in] str The input string to be converted.
753 *
754 * \param[in] idx Location to store the index at which processing
222b61ff 755 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
a0383aad
FM
756 *
757 * \param[in] base The numerical base for conversion.
758 *
759 * \return `str` converted to integer `T`, or 0 if `str` is empty.
760 */
761template <typename T>
762auto checked_stoi_into(T& out, const std::string& str, size_t* idx = nullptr, int base = 10)
763{
764 out = checked_stoi<T>(str, idx, base);
765}
766}
60a1c204 767
8fd25133
RG
768bool isSettingThreadCPUAffinitySupported();
769int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus);
5d4e1ef8
RG
770
771std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath);
ef3ee606
RG
772
773DNSName reverseNameFromIP(const ComboAddress& ip);
64d38231 774
b1a048a9 775size_t parseRFC1035CharString(const std::string &in, std::string &val); // from ragel
e701f9d4
PL
776size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, vector<std::string> &val); // from ragel
777size_t parseSVCBValueList(const std::string &in, vector<std::string> &val);
032382bc
PD
778
779std::string makeLuaString(const std::string& in);
786ed0ff 780
b2504b29
RG
781bool constantTimeStringEquals(const std::string& a, const std::string& b);
782
786ed0ff 783// Used in NID and L64 records
2c510d90 784struct NodeOrLocatorID { uint8_t content[8]; };
ae3b96d9
RG
785
786struct FDWrapper
787{
d2adfa5c
OM
788 FDWrapper() = default;
789 FDWrapper(int desc): d_fd(desc) {}
790 FDWrapper(const FDWrapper&) = delete;
791 FDWrapper& operator=(const FDWrapper& rhs) = delete;
ae3b96d9 792
ae3b96d9
RG
793
794 ~FDWrapper()
795 {
5841c6fd 796 reset();
ae3b96d9
RG
797 }
798
d2adfa5c 799 FDWrapper(FDWrapper&& rhs) noexcept : d_fd(rhs.d_fd)
ae3b96d9
RG
800 {
801 rhs.d_fd = -1;
802 }
803
d2adfa5c 804 FDWrapper& operator=(FDWrapper&& rhs) noexcept
ae3b96d9 805 {
54b2435e 806 if (d_fd != -1) {
ae3b96d9
RG
807 close(d_fd);
808 }
809 d_fd = rhs.d_fd;
810 rhs.d_fd = -1;
811 return *this;
812 }
813
d2adfa5c 814 [[nodiscard]] int getHandle() const
ae3b96d9
RG
815 {
816 return d_fd;
817 }
818
0adbef11
RG
819 operator int() const
820 {
821 return d_fd;
822 }
823
2f17d188 824 int reset()
5841c6fd 825 {
2f17d188 826 int ret = 0;
5841c6fd 827 if (d_fd != -1) {
2f17d188 828 ret = close(d_fd);
5841c6fd
RG
829 d_fd = -1;
830 }
2f17d188 831 return ret;
5841c6fd
RG
832 }
833
ae3b96d9
RG
834private:
835 int d_fd{-1};
836};
d3190b7d
RG
837
838namespace pdns
839{
840[[nodiscard]] std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor);
20b2f204
RG
841
842struct FilePtrDeleter
843{
844 /* using a deleter instead of decltype(&fclose) has two big advantages:
845 - the deleter is included in the type and does not have to be passed
846 when creating a new object (easier to use, less memory usage, in theory
847 better inlining)
848 - we avoid the annoying "ignoring attributes on template argument ‘int (*)(FILE*)’"
849 warning from the compiler, which is there because fclose is tagged as __nonnull((1))
850 */
07d4785d 851 void operator()(FILE* filePtr) const noexcept {
20b2f204
RG
852 fclose(filePtr);
853 }
854};
855
856using UniqueFilePtr = std::unique_ptr<FILE, FilePtrDeleter>;
b1564d45
RG
857
858UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist = true, bool appendIfExists = false);
d3190b7d 859}