]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/misc.hh
Merge pull request #7945 from pieterlexis/syncres-CNAME-cache-cleanup
[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
2a9094ef 23#include <errno.h>
61b26744 24#include <inttypes.h>
8b3cfcd3 25#include <cstring>
f9822705 26#include <cstdio>
3ee84c3f 27#include <regex.h>
58044407 28#include <limits.h>
88bf3279 29#include <type_traits>
ec6480f3 30#include <boost/algorithm/string.hpp>
f0db590d
BH
31#include <boost/multi_index_container.hpp>
32#include <boost/multi_index/ordered_index.hpp>
33#include <boost/tuple/tuple_comparison.hpp>
34#include <boost/multi_index/key_extractors.hpp>
35#include <boost/multi_index/sequenced_index.hpp>
d190894c 36
f0db590d 37using namespace ::boost::multi_index;
12c86877 38
e67e250f 39#include "dns.hh"
ac0995bb 40#include <atomic>
76473b92
KM
41#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <time.h>
45#include <syslog.h>
3de83124 46#include <deque>
a640a9d4 47#include <stdexcept>
12c86877
BH
48#include <string>
49#include <ctype.h>
e67e250f
BH
50#include <vector>
51
10f4eea8 52#include "namespaces.hh"
d72aaada
KM
53#include "dnsname.hh"
54
bcb5b94e 55typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
da15912b 56
cc3afe25 57string nowTime();
1d329048 58const string unquotify(const string &item);
12c86877 59string humanDuration(time_t passed);
f2c11a48 60bool stripDomainSuffix(string *qname, const string &domain);
12c86877
BH
61void stripLine(string &line);
62string getHostname();
63string urlEncode(const string &text);
a7d50153 64int waitForData(int fd, int seconds, int useconds=0);
f4ff5929 65int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
d529011f 66int waitForMultiData(const set<int>& fds, const int seconds, const int useconds, int* fd);
51959320 67int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error=nullptr, bool* disconnected=nullptr);
092f210a
BH
68uint16_t getShort(const unsigned char *p);
69uint16_t getShort(const char *p);
70uint32_t getLong(const unsigned char *p);
71uint32_t getLong(const char *p);
21a3792f
KM
72bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum);
73DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum);
58044407 74
f8499e52 75int logFacilityToLOG(unsigned int facility);
bbce5bf0 76
12c86877
BH
77struct ServiceTuple
78{
79 string host;
092f210a 80 uint16_t port;
12c86877
BH
81};
82void parseService(const string &descr, ServiceTuple &st);
83
84template <typename Container>
85void
86stringtok (Container &container, string const &in,
87 const char * const delimiters = " \t\n")
88{
89 const string::size_type len = in.length();
90 string::size_type i = 0;
3ddb9247 91
12c86877
BH
92 while (i<len) {
93 // eat leading whitespace
94 i = in.find_first_not_of (delimiters, i);
95 if (i == string::npos)
96 return; // nothing left but white space
3ddb9247 97
12c86877
BH
98 // find the end of the token
99 string::size_type j = in.find_first_of (delimiters, i);
3ddb9247 100
12c86877
BH
101 // push token
102 if (j == string::npos) {
103 container.push_back (in.substr(i));
104 return;
105 } else
106 container.push_back (in.substr(i, j-i));
3ddb9247 107
12c86877
BH
108 // set up for next loop
109 i = j + 1;
110 }
111}
8c3149f2 112
f7a69a4c
RA
113template<typename T> bool rfc1982LessThan(T a, T b)
114{
115 return ((signed)(a - b)) < 0;
116}
117
0ab3fdc6 118// fills container with ranges, so {posbegin,posend}
8c3149f2
BH
119template <typename Container>
120void
121vstringtok (Container &container, string const &in,
122 const char * const delimiters = " \t\n")
123{
124 const string::size_type len = in.length();
125 string::size_type i = 0;
3ddb9247 126
8c3149f2
BH
127 while (i<len) {
128 // eat leading whitespace
129 i = in.find_first_not_of (delimiters, i);
130 if (i == string::npos)
131 return; // nothing left but white space
3ddb9247 132
8c3149f2
BH
133 // find the end of the token
134 string::size_type j = in.find_first_of (delimiters, i);
3ddb9247 135
8c3149f2
BH
136 // push token
137 if (j == string::npos) {
138 container.push_back (make_pair(i, len));
139 return;
140 } else
141 container.push_back (make_pair(i, j));
3ddb9247 142
8c3149f2
BH
143 // set up for next loop
144 i = j + 1;
145 }
146}
147
a683e8bd
RG
148size_t writen2(int fd, const void *buf, size_t count);
149inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
150size_t readn2(int fd, void* buffer, size_t len);
9396d955 151size_t readn2WithTimeout(int fd, void* buffer, size_t len, int idleTimeout, int totalTimeout=0);
a683e8bd 152size_t writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout);
040712e0 153
c3d9d009 154const string toLower(const string &upper);
b0d4fb45 155const string toLowerCanonic(const string &upper);
092f210a 156bool IpToU32(const string &str, uint32_t *ip);
5730f30c 157string U32ToIP(uint32_t);
12c86877 158string stringerror();
d3b4137e 159string netstringerror();
12c86877 160string itoa(int i);
22c9c86a 161string uitoa(unsigned int i);
d88babea 162string bitFlip(const string &str);
12c86877
BH
163
164void dropPrivs(int uid, int gid);
165int makeGidNumeric(const string &group);
166int makeUidNumeric(const string &user);
167void cleanSlashes(string &str);
168
c6d04bdc 169#if defined(_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
df13e61d 170/** CPUTime measurements */
171class CPUTime
172{
173public:
174 void start()
175 {
176 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &d_start);
177 }
178 uint64_t ndiff()
179 {
180 struct timespec now;
181 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
182 return 1000000000ULL*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec);
183 }
184private:
185 struct timespec d_start;
186};
3ddb9247 187#endif
df13e61d 188
3ddb9247 189/** The DTime class can be used for timing statistics with microsecond resolution.
12c86877 190On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
3ddb9247 191class DTime
12c86877
BH
192{
193public:
eefd15f9 194 DTime(); //!< Does not set the timer for you! Saves lots of gettimeofday() calls
12c86877
BH
195 DTime(const DTime &dt);
196 time_t time();
197 inline void set(); //!< Reset the timer
198 inline int udiff(); //!< Return the number of microseconds since the timer was last set.
62c3a7b8 199 inline int udiffNoReset(); //!< Return the number of microseconds since the timer was last set.
88358c9b
BH
200 void setTimeval(const struct timeval& tv)
201 {
202 d_set=tv;
203 }
204 struct timeval getTimeval()
205 {
206 return d_set;
207 }
12c86877
BH
208private:
209 struct timeval d_set;
210};
85db02c5 211
12c86877
BH
212inline void DTime::set()
213{
15ad1a99 214 gettimeofday(&d_set,0);
12c86877
BH
215}
216
217inline int DTime::udiff()
62c3a7b8
BH
218{
219 int res=udiffNoReset();
15ad1a99 220 gettimeofday(&d_set,0);
62c3a7b8
BH
221 return res;
222}
223
224inline int DTime::udiffNoReset()
12c86877
BH
225{
226 struct timeval now;
12c86877 227
15ad1a99 228 gettimeofday(&now,0);
fe213470 229 int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
fe213470 230 return ret;
12c86877
BH
231}
232
c3d9d009 233inline const string toLower(const string &upper)
12c86877
BH
234{
235 string reply(upper);
2b3eefc3 236 const size_t length = reply.length();
c536ca8d 237 char c;
2b3eefc3 238 for(unsigned int i = 0; i < length; ++i) {
e3cacd48
BH
239 c = dns_tolower(upper[i]);
240 if( c != upper[i])
c536ca8d
BH
241 reply[i] = c;
242 }
12c86877
BH
243 return reply;
244}
245
b0d4fb45
BH
246inline const string toLowerCanonic(const string &upper)
247{
248 string reply(upper);
249 if(!upper.empty()) {
705f31ae 250 unsigned int i, limit= ( unsigned int ) reply.length();
1352c9b6 251 unsigned char c;
c536ca8d 252 for(i = 0; i < limit ; i++) {
e3cacd48
BH
253 c = dns_tolower(upper[i]);
254 if(c != upper[i])
4957a608 255 reply[i] = c;
3ddb9247 256 }
e3cacd48 257 if(upper[i-1]=='.')
b0d4fb45
BH
258 reply.resize(i-1);
259 }
3ddb9247 260
b0d4fb45
BH
261 return reply;
262}
263
264
12c86877 265
52936200
BH
266// Make s uppercase:
267inline string toUpper( const string& s )
268{
4957a608
BH
269 string r(s);
270 for( unsigned int i = 0; i < s.length(); i++ ) {
315f45a0 271 r[i] = dns_toupper(r[i]);
4957a608
BH
272 }
273 return r;
52936200
BH
274}
275
a6d7640a
BH
276inline double getTime()
277{
278 struct timeval now;
15ad1a99 279 gettimeofday(&now,0);
3ddb9247 280
a6d7640a
BH
281 return now.tv_sec+now.tv_usec/1000000.0;
282}
283
a640a9d4
BH
284inline void unixDie(const string &why)
285{
286 throw runtime_error(why+": "+strerror(errno));
287}
288
2db9c30e 289string makeHexDump(const string& str);
4950b140 290struct DNSRecord;
c77eccee 291struct DNSZoneRecord;
4950b140 292void shuffle(vector<DNSRecord>& rrs);
d190894c 293void shuffle(vector<DNSZoneRecord>& rrs);
90ba52e0 294
e325f20c 295void orderAndShuffle(vector<DNSRecord>& rrs);
88358c9b
BH
296
297void normalizeTV(struct timeval& tv);
298const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
299const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
300inline float makeFloat(const struct timeval& tv)
301{
705f31ae 302 return tv.tv_sec + tv.tv_usec/1000000.0f;
88358c9b 303}
5b0ddd18 304
3ddb9247 305inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
5b0ddd18
BH
306{
307 return make_pair(lhs.tv_sec, lhs.tv_usec) < make_pair(rhs.tv_sec, rhs.tv_usec);
308}
309
80a216c9 310inline bool operator<(const struct timespec& lhs, const struct timespec& rhs)
311{
312 return tie(lhs.tv_sec, lhs.tv_nsec) < tie(rhs.tv_sec, rhs.tv_nsec);
313}
314
315
ec6480f3 316inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure));
8fb5b29a 317inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
7738a23f 318{
97a24230 319 const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str();
7fd7a590 320 const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length();
321 while(aPtr != aEptr && bPtr != bEptr) {
8fb5b29a
KM
322 if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr)))
323 return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0;
324 aPtr++;
325 bPtr++;
7738a23f 326 }
7fd7a590 327 if(aPtr == aEptr && bPtr == bEptr) // strings are equal (in length)
8fb5b29a 328 return false;
7fd7a590 329 return aPtr == aEptr; // true if first string was shorter
ec6480f3 330}
eff65ff8 331
ec6480f3 332inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
8fb5b29a 333inline bool pdns_iequals(const std::string& a, const std::string& b)
ec6480f3 334{
8fb5b29a
KM
335 if (a.length() != b.length())
336 return false;
337
ec6480f3 338 const char *aPtr = a.c_str(), *bPtr = b.c_str();
b10795de 339 const char *aEptr = aPtr + a.length();
340 while(aPtr != aEptr) {
8fb5b29a
KM
341 if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr)))
342 return false;
343 aPtr++;
344 bPtr++;
eff65ff8 345 }
8fb5b29a 346 return true;
ec6480f3
BH
347}
348
57cb86d8
CH
349inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure));
350inline bool pdns_iequals_ch(const char a, const char b)
351{
352 if ((a != b) && (dns_tolower(a) != dns_tolower(b)))
353 return false;
354
355 return true;
356}
357
1566533a 358
00c6f2b9
RG
359typedef unsigned long AtomicCounterInner;
360typedef std::atomic<AtomicCounterInner> AtomicCounter ;
1bc9e6bd 361
ac0995bb 362// FIXME400 this should probably go?
3ddb9247 363struct CIStringCompare: public std::binary_function<string, string, bool>
ec6480f3
BH
364{
365 bool operator()(const string& a, const string& b) const
eff65ff8 366 {
ec6480f3 367 return pdns_ilexicographical_compare(a, b);
eff65ff8 368 }
7738a23f 369};
eff65ff8 370
2aa1b703
AT
371struct CIStringComparePOSIX
372{
373 bool operator() (const std::string& lhs, const std::string& rhs)
374 {
375 std::string::const_iterator a,b;
376 const std::locale &loc = std::locale("POSIX");
377 a=lhs.begin();b=rhs.begin();
378 while(a!=lhs.end()) {
379 if (b==rhs.end() || std::tolower(*b,loc)<std::tolower(*a,loc)) return false;
380 else if (std::tolower(*a,loc)<std::tolower(*b,loc)) return true;
4b5da564 381 ++a;++b;
2aa1b703
AT
382 }
383 return (b!=rhs.end());
384 }
385};
386
3ddb9247 387struct CIStringPairCompare: public std::binary_function<pair<string, uint16_t>, pair<string,uint16_t>, bool>
21f0f88b
BH
388{
389 bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
390 {
391 if(pdns_ilexicographical_compare(a.first, b.first))
392 return true;
393 if(pdns_ilexicographical_compare(b.first, a.first))
394 return false;
395 return a.second < b.second;
396 }
397};
398
57cb86d8
CH
399inline size_t pdns_ci_find(const string& haystack, const string& needle)
400{
401 string::const_iterator it = std::search(haystack.begin(), haystack.end(),
402 needle.begin(), needle.end(), pdns_iequals_ch);
403 if (it == haystack.end()) {
404 // not found
405 return string::npos;
406 } else {
407 return it - haystack.begin();
408 }
409}
21f0f88b 410
50c79a76 411pair<string, string> splitField(const string& inp, char sepa);
26cd1b3f 412
e720f311 413inline bool isCanonical(const string& qname)
26cd1b3f 414{
e720f311 415 if(qname.empty())
26cd1b3f 416 return false;
e720f311 417 return qname[qname.size()-1]=='.';
26cd1b3f
BH
418}
419
e720f311 420inline DNSName toCanonic(const DNSName& zone, const string& qname)
675fa24c 421{
e720f311 422 if(qname.size()==1 && qname[0]=='@')
8171ab83 423 return zone;
e720f311 424 if(isCanonical(qname))
8171ab83 425 return DNSName(qname);
e720f311 426 return DNSName(qname) += zone;
26cd1b3f 427}
da042e6e
BH
428
429string stripDot(const string& dom);
561434a6 430
f71bc087 431int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
76cb4593
CH
432int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
433int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
834942f1 434bool stringfgets(FILE* fp, std::string& line);
f0db590d
BH
435
436template<typename Index>
437std::pair<typename Index::iterator,bool>
438replacing_insert(Index& i,const typename Index::value_type& x)
439{
440 std::pair<typename Index::iterator,bool> res=i.insert(x);
441 if(!res.second)res.second=i.replace(res.first,x);
442 return res;
443}
444
3ee84c3f
BH
445/** very small regex wrapper */
446class Regex
447{
448public:
449 /** constructor that accepts the expression to regex */
450 Regex(const string &expr);
3ddb9247 451
3ee84c3f
BH
452 ~Regex()
453 {
454 regfree(&d_preg);
455 }
456 /** call this to find out if 'line' matches your expression */
6eecd4c2 457 bool match(const string &line) const
3ee84c3f
BH
458 {
459 return regexec(&d_preg,line.c_str(),0,0,0)==0;
460 }
6eecd4c2 461 bool match(const DNSName& name) const
60ee1829
AT
462 {
463 return match(name.toStringNoDot());
464 }
465
3ee84c3f
BH
466private:
467 regex_t d_preg;
468};
469
ac84f00c
AT
470class SimpleMatch
471{
472public:
8a70e507 473 SimpleMatch(const string &mask, bool caseFold = false): d_mask(mask), d_fold(caseFold)
ac84f00c 474 {
ac84f00c
AT
475 }
476
477 bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend)
478 {
4b5da564 479 for(;;++mi) {
ac84f00c
AT
480 if (mi == mend) {
481 return vi == vend;
482 } else if (*mi == '?') {
483 if (vi == vend) return false;
4b5da564 484 ++vi;
ac84f00c 485 } else if (*mi == '*') {
4b5da564 486 while(*mi == '*') ++mi;
ac84f00c
AT
487 if (mi == d_mask.end()) return true;
488 while(vi != vend) {
489 if (match(mi,mend,vi,vend)) return true;
4b5da564 490 ++vi;
ac84f00c
AT
491 }
492 return false;
493 } else {
494 if ((mi == mend && vi != vend)||
495 (mi != mend && vi == vend)) return false;
496 if (d_fold) {
497 if (dns_tolower(*mi) != dns_tolower(*vi)) return false;
498 } else {
499 if (*mi != *vi) return false;
500 }
4b5da564 501 ++vi;
ac84f00c
AT
502 }
503 }
504 }
505
506 bool match(const string& value) {
507 return match(d_mask.begin(), d_mask.end(), value.begin(), value.end());
508 }
509
510 bool match(const DNSName& name) {
511 return match(name.toStringNoDot());
512 }
513
514private:
515 string d_mask;
516 bool d_fold;
517};
518
65d8e171 519union ComboAddress;
fbe2a2e0
RG
520/* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */
521void addCMsgSrcAddr(struct msghdr* msgh, void* cmsgbuf, const ComboAddress* source, int itfIndex);
3a8a4d68 522
523unsigned int getFilenumLimit(bool hardOrSoft=0);
524void setFilenumLimit(unsigned int lim);
4e9a20e6 525bool readFileIfThere(const char* fname, std::string* line);
5c57a75a 526uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t init);
915b0c39 527bool setSocketTimestamps(int fd);
15ad1a99 528
529//! Sets the socket into blocking mode.
530bool setBlocking( int sock );
531
532//! Sets the socket into non-blocking mode.
533bool setNonBlocking( int sock );
883a30a7 534bool setTCPNoDelay(int sock);
bf676f2f 535bool setReuseAddr(int sock);
18861f97 536bool isNonBlocking(int sock);
29bb743c 537bool setReceiveSocketErrors(int sock, int af);
3897b9e1 538int closesocket(int fd);
539bool setCloseOnExec(int sock);
74ad42dc 540
ee271fc4
RG
541size_t getPipeBufferSize(int fd);
542bool setPipeBufferSize(int fd, size_t size);
543
544uint64_t udpErrorStats(const std::string& str);
a1a787dc 545uint64_t getRealMemoryUsage(const std::string&);
330dcb5c 546uint64_t getSpecialMemoryUsage(const std::string&);
a9b6db56 547uint64_t getOpenFileDescriptors(const std::string&);
4f99f3d3
RG
548uint64_t getCPUTimeUser(const std::string&);
549uint64_t getCPUTimeSystem(const std::string&);
6907f014 550std::string getMACAddress(const ComboAddress& ca);
74ad42dc 551template<typename T, typename... Args>
552std::unique_ptr<T> make_unique(Args&&... args)
553{
554 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
555}
1c150f27 556
557
558template<typename T>
559const T& defTer(const T& a, const T& b)
560{
561 return a ? a : b;
562}
3555371a
AT
563
564template<typename P, typename T>
565T valueOrEmpty(const P val) {
566 if (!val) return T{};
567 return T(val);
568}
f5f96ff1 569
88bf3279 570
f5f96ff1 571// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
88bf3279 572template <typename Integer>
573const char* addS(Integer siz, typename std::enable_if<std::is_integral<Integer>::value>::type*P=0)
f5f96ff1 574{
f5f96ff1 575 if(!siz || siz > 1)
576 return "s";
577 else return "";
578}
88bf3279 579
580template<typename C>
581const char* addS(const C& c, typename std::enable_if<std::is_class<C>::value>::type*P=0)
582{
583 return addS(c.size());
584}
585
2ac8ae89 586template<typename C>
587const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key)
588{
589 auto fnd = c.find(key);
590 if(fnd == c.end())
591 return 0;
592 return &fnd->second;
593}
594
3fcaeeac 595double DiffTime(const struct timespec& first, const struct timespec& second);
596double DiffTime(const struct timeval& first, const struct timeval& second);
ffb07158 597uid_t strToUID(const string &str);
598gid_t strToGID(const string &str);
a5c4e4a6
AT
599
600unsigned int pdns_stou(const std::string& str, size_t * idx = 0, int base = 10);
60a1c204 601
8fd25133
RG
602bool isSettingThreadCPUAffinitySupported();
603int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus);
5d4e1ef8
RG
604
605std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath);