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