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