]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/misc.hh
d14f3a9c4e102d39ae9be77f197b885685bc7b53
[thirdparty/pdns.git] / pdns / misc.hh
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2015 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
8
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
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 St, 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);