]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/misc.cc
Merge pull request #2733 from pieterlexis/deb-pkg-cleanup
[thirdparty/pdns.git] / pdns / misc.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
3a8a4d68 3 Copyright (C) 2002 - 2014 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
22dc646a
BH
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
f782fe38
MH
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.
12c86877
BH
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 21*/
705f31ae 22
870a0fe4
AT
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
705f31ae 26#include <sys/param.h>
22cf1fda 27#include <sys/socket.h>
3897b9e1 28#include <fcntl.h>
705f31ae
BH
29#include <netdb.h>
30#include <sys/time.h>
31#include <time.h>
3a8a4d68 32#include <sys/resource.h>
705f31ae 33#include <netinet/in.h>
76cb4593 34#include <sys/un.h>
705f31ae 35#include <unistd.h>
8290ad9f 36#include <fstream>
12c86877
BH
37#include "misc.hh"
38#include <vector>
39#include <sstream>
40#include <errno.h>
1258abe0 41#include <cstring>
c4bee46c 42#include <iostream>
705f31ae 43#include <algorithm>
6e2514e4 44#include <boost/optional.hpp>
fab091b9 45#include <poll.h>
12c86877 46#include <iomanip>
12c86877
BH
47#include <string.h>
48#include <stdlib.h>
49#include <stdio.h>
5c409fa2 50#include "pdnsexception.hh"
c6566265 51#include <sys/types.h>
040712e0 52#include <boost/algorithm/string.hpp>
65d8e171 53#include "iputils.hh"
040712e0 54
a61e8e59 55
1e08edde
BH
56bool g_singleThreaded;
57
040712e0
BH
58int writen2(int fd, const void *buf, size_t count)
59{
60 const char *ptr = (char*)buf;
61 const char *eptr = ptr + count;
3ddb9247 62
040712e0
BH
63 int res;
64 while(ptr != eptr) {
65 res = ::write(fd, ptr, eptr - ptr);
66 if(res < 0) {
67 if (errno == EAGAIN)
4957a608 68 throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN");
040712e0 69 else
4957a608 70 unixDie("failed in writen2");
040712e0
BH
71 }
72 else if (res == 0)
73 throw std::runtime_error("could not write all bytes, got eof in writen2");
3ddb9247 74
040712e0
BH
75 ptr += res;
76 }
3ddb9247 77
040712e0
BH
78 return count;
79}
80
36fbf590 81int readn2(int fd, void* buffer, unsigned int len)
82{
83 unsigned int pos=0;
84 int res;
85 for(;;) {
86 res = read(fd, (char*)buffer + pos, len - pos);
3ddb9247 87 if(res == 0)
36fbf590 88 throw runtime_error("EOF while writing message");
89 if(res < 0) {
90 if (errno == EAGAIN)
91 throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN");
92 else
93 unixDie("failed in writen2");
3ddb9247
PD
94 }
95
36fbf590 96 pos+=res;
97 if(pos == len)
98 break;
99 }
100 return len;
101}
102
12c86877 103
cc3afe25
BH
104string nowTime()
105{
106 time_t now=time(0);
107 string t=ctime(&now);
040712e0 108 boost::trim_right(t);
cc3afe25
BH
109 return t;
110}
12c86877 111
092f210a 112uint16_t getShort(const unsigned char *p)
0d8612f2
BH
113{
114 return p[0] * 256 + p[1];
115}
116
117
092f210a 118uint16_t getShort(const char *p)
0d8612f2
BH
119{
120 return getShort((const unsigned char *)p);
121}
122
092f210a 123uint32_t getLong(const unsigned char* p)
b636533b
BH
124{
125 return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
126}
127
092f210a 128uint32_t getLong(const char* p)
b636533b
BH
129{
130 return getLong((unsigned char *)p);
131}
132
0d8612f2
BH
133
134
f2c11a48
BH
135/** strips a domain suffix from a domain, returns true if it stripped */
136bool stripDomainSuffix(string *qname, const string &domain)
137{
c4bee46c 138 if(!endsOn(*qname, domain))
f2c11a48
BH
139 return false;
140
c4bee46c 141 if(toLower(*qname)==toLower(domain))
f2c11a48
BH
142 *qname="@";
143 else {
144 if((*qname)[qname->size()-domain.size()-1]!='.')
145 return false;
146
147 qname->resize(qname->size()-domain.size()-1);
148 }
149 return true;
150}
151
7738a23f 152/** Chops off the start of a domain, so goes from 'www.ds9a.nl' to 'ds9a.nl' to 'nl' to ''. Return zero on the empty string */
3ddb9247 153bool chopOff(string &domain)
728485ca
BH
154{
155 if(domain.empty())
156 return false;
157
158 string::size_type fdot=domain.find('.');
159
3ddb9247 160 if(fdot==string::npos)
728485ca 161 domain="";
f6a9e00a
BH
162 else {
163 string::size_type remain = domain.length() - (fdot + 1);
164 char tmp[remain];
165 memcpy(tmp, domain.c_str()+fdot+1, remain);
166 domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-)
167 }
728485ca
BH
168 return true;
169}
170
7738a23f
BH
171/** Chops off the start of a domain, so goes from 'www.ds9a.nl.' to 'ds9a.nl.' to 'nl.' to '.' Return zero on the empty string */
172bool chopOffDotted(string &domain)
173{
174 if(domain.empty() || (domain.size()==1 && domain[0]=='.'))
175 return false;
176
177 string::size_type fdot=domain.find('.');
02ac88c8
BH
178 if(fdot == string::npos)
179 return false;
7738a23f 180
3ddb9247 181 if(fdot==domain.size()-1)
7738a23f 182 domain=".";
f6a9e00a
BH
183 else {
184 string::size_type remain = domain.length() - (fdot + 1);
185 char tmp[remain];
186 memcpy(tmp, domain.c_str()+fdot+1, remain);
187 domain.assign(tmp, remain);
188 }
7738a23f
BH
189 return true;
190}
191
192
49bd5a20
BH
193bool ciEqual(const string& a, const string& b)
194{
195 if(a.size()!=b.size())
196 return false;
197
198 string::size_type pos=0, epos=a.size();
199 for(;pos < epos; ++pos)
200 if(dns_tolower(a[pos])!=dns_tolower(b[pos]))
201 return false;
202 return true;
203}
204
728485ca 205/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
3ddb9247 206bool endsOn(const string &domain, const string &suffix)
728485ca 207{
49bd5a20 208 if( suffix.empty() || ciEqual(domain, suffix) )
728485ca 209 return true;
7738a23f 210
728485ca
BH
211 if(domain.size()<=suffix.size())
212 return false;
3ddb9247 213
49bd5a20 214 string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
7738a23f 215
49bd5a20
BH
216 if(domain[dpos++]!='.')
217 return false;
728485ca 218
49bd5a20
BH
219 for(; dpos < domain.size(); ++dpos, ++spos)
220 if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
221 return false;
222
223 return true;
224}
f2c11a48 225
3ddb9247
PD
226// REMOVE ME
227bool dottedEndsOn(const DNSName &domain, const DNSName &suffix)
228{
229 return domain.isPartOf(suffix);
230}
231
232
7738a23f 233/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
3ddb9247 234bool dottedEndsOn(const string &domain, const string &suffix)
7738a23f
BH
235{
236 if( suffix=="." || ciEqual(domain, suffix) )
237 return true;
238
239 if(domain.size()<=suffix.size())
240 return false;
3ddb9247 241
7738a23f
BH
242 string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
243
244 if(domain[dpos++]!='.')
245 return false;
246
247 for(; dpos < domain.size(); ++dpos, ++spos)
248 if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
249 return false;
250
251 return true;
252}
253
32252594 254static void parseService4(const string &descr, ServiceTuple &st)
12c86877
BH
255{
256 vector<string>parts;
257 stringtok(parts,descr,":");
52936200 258 if(parts.empty())
3f81d239 259 throw PDNSException("Unable to parse '"+descr+"' as a service");
12c86877
BH
260 st.host=parts[0];
261 if(parts.size()>1)
262 st.port=atoi(parts[1].c_str());
263}
264
32252594
BH
265static void parseService6(const string &descr, ServiceTuple &st)
266{
267 string::size_type pos=descr.find(']');
268 if(pos == string::npos)
3f81d239 269 throw PDNSException("Unable to parse '"+descr+"' as an IPv6 service");
32252594
BH
270
271 st.host=descr.substr(1, pos-1);
272 if(pos + 2 < descr.length())
273 st.port=atoi(descr.c_str() + pos +2);
274}
275
276
277void parseService(const string &descr, ServiceTuple &st)
278{
279 if(descr.empty())
3f81d239 280 throw PDNSException("Unable to parse '"+descr+"' as a service");
32252594
BH
281
282 vector<string> parts;
283 stringtok(parts, descr, ":");
284
285 if(descr[0]=='[') {
286 parseService6(descr, st);
287 }
288 else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) {
289 st.host=descr;
290 }
291 else {
292 parseService4(descr, st);
293 }
294}
12c86877 295
1fb3f0fc 296// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
a7d50153 297int waitForData(int fd, int seconds, int useconds)
649a88df
BH
298{
299 return waitForRWData(fd, true, seconds, useconds);
300}
301
302int waitForRWData(int fd, bool waitForRead, int seconds, int useconds)
12c86877 303{
1258abe0
BH
304 int ret;
305
fab091b9
BH
306 struct pollfd pfd;
307 memset(&pfd, 0, sizeof(pfd));
308 pfd.fd = fd;
3ddb9247 309
649a88df 310 if(waitForRead)
fab091b9 311 pfd.events=POLLIN;
649a88df 312 else
fab091b9 313 pfd.events=POLLOUT;
1258abe0 314
6b3d4330 315 ret = poll(&pfd, 1, seconds * 1000 + useconds/1000);
1258abe0 316 if ( ret == -1 )
f4ff5929 317 errno = ETIMEDOUT; // ???
1258abe0 318
12c86877
BH
319 return ret;
320}
321
a71bee29 322// returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
f4ff5929
BH
323int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd)
324{
325 int ret;
326
327 struct pollfd pfds[2];
328 memset(&pfds[0], 0, 2*sizeof(struct pollfd));
329 pfds[0].fd = fd1;
330 pfds[1].fd = fd2;
3ddb9247 331
f4ff5929
BH
332 pfds[0].events= pfds[1].events = POLLIN;
333
334 int nsocks = 1 + (fd2 >= 0); // fd2 can optionally be -1
335
336 if(seconds >= 0)
337 ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000);
338 else
339 ret = poll(pfds, nsocks, -1);
340 if(!ret || ret < 0)
341 return ret;
3ddb9247 342
f4ff5929
BH
343 if((pfds[0].revents & POLLIN) && !(pfds[1].revents & POLLIN))
344 *fd = pfds[0].fd;
345 else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN))
346 *fd = pfds[1].fd;
347 else if(ret == 2) {
348 *fd = pfds[random()%2].fd;
349 }
350 else
351 *fd = -1; // should never happen
3ddb9247 352
f4ff5929
BH
353 return 1;
354}
355
12c86877
BH
356
357string humanDuration(time_t passed)
358{
359 ostringstream ret;
360 if(passed<60)
361 ret<<passed<<" seconds";
362 else if(passed<3600)
9e04108d 363 ret<<std::setprecision(2)<<passed/60.0<<" minutes";
12c86877 364 else if(passed<86400)
9e04108d 365 ret<<std::setprecision(3)<<passed/3600.0<<" hours";
12c86877 366 else if(passed<(86400*30.41))
9e04108d 367 ret<<std::setprecision(3)<<passed/86400.0<<" days";
12c86877 368 else
9e04108d 369 ret<<std::setprecision(3)<<passed/(86400*30.41)<<" months";
12c86877
BH
370
371 return ret.str();
372}
373
374DTime::DTime()
375{
eefd15f9 376// set(); // saves lots of gettimeofday calls
12c86877
BH
377}
378
379DTime::DTime(const DTime &dt)
380{
381 d_set=dt.d_set;
382}
383
384time_t DTime::time()
385{
386 return d_set.tv_sec;
387}
388
1d329048
BH
389const string unquotify(const string &item)
390{
391 if(item.size()<2)
392 return item;
393
394 string::size_type bpos=0, epos=item.size();
12c86877 395
3ddb9247 396 if(item[0]=='"')
1d329048 397 bpos=1;
c4bee46c 398
1d329048
BH
399 if(item[epos-1]=='"')
400 epos-=1;
401
c4bee46c 402 return item.substr(bpos,epos-bpos);
1d329048 403}
12c86877
BH
404
405void stripLine(string &line)
406{
bdf40704 407 string::size_type pos=line.find_first_of("\r\n");
12c86877
BH
408 if(pos!=string::npos) {
409 line.resize(pos);
410 }
411}
412
413string urlEncode(const string &text)
414{
415 string ret;
416 for(string::const_iterator i=text.begin();i!=text.end();++i)
417 if(*i==' ')ret.append("%20");
418 else ret.append(1,*i);
419 return ret;
420}
421
422string getHostname()
423{
0db70140 424#ifndef MAXHOSTNAMELEN
76473b92 425#define MAXHOSTNAMELEN 255
0db70140 426#endif
ac2bb9e7 427
12c86877
BH
428 char tmp[MAXHOSTNAMELEN];
429 if(gethostname(tmp, MAXHOSTNAMELEN))
430 return "UNKNOWN";
431
432 return tmp;
433}
434
435string itoa(int i)
436{
437 ostringstream o;
438 o<<i;
439 return o.str();
440}
441
22c9c86a
BH
442string uitoa(unsigned int i) // MSVC 6 doesn't grok overloading (un)signed
443{
444 ostringstream o;
445 o<<i;
446 return o.str();
447}
448
d88babea
KM
449string bitFlip(const string &str)
450{
451 string::size_type pos=0, epos=str.size();
452 string ret;
453 ret.reserve(epos);
454 for(;pos < epos; ++pos)
455 ret.append(1, ~str[pos]);
456 return ret;
457}
22c9c86a 458
12c86877
BH
459string stringerror()
460{
461 return strerror(errno);
462}
463
d3b4137e
BH
464string netstringerror()
465{
466 return stringerror();
467}
d3b4137e 468
12c86877
BH
469void cleanSlashes(string &str)
470{
471 string::const_iterator i;
472 string out;
473 for(i=str.begin();i!=str.end();++i) {
474 if(*i=='/' && i!=str.begin() && *(i-1)=='/')
475 continue;
476 out.append(1,*i);
477 }
478 str=out;
479}
480
7b35aa49 481
092f210a 482bool IpToU32(const string &str, uint32_t *ip)
525b8a7c 483{
4cf26303
BH
484 if(str.empty()) {
485 *ip=0;
486 return true;
487 }
3ddb9247 488
092c9cc4 489 struct in_addr inp;
3897b9e1 490 if(inet_aton(str.c_str(), &inp)) {
092c9cc4
BH
491 *ip=inp.s_addr;
492 return true;
493 }
494 return false;
525b8a7c
BH
495}
496
5730f30c
BH
497string U32ToIP(uint32_t val)
498{
499 char tmp[17];
3ddb9247 500 snprintf(tmp, sizeof(tmp)-1, "%u.%u.%u.%u",
4957a608
BH
501 (val >> 24)&0xff,
502 (val >> 16)&0xff,
503 (val >> 8)&0xff,
504 (val )&0xff);
5730f30c
BH
505 return tmp;
506}
507
37d3f960 508
2db9c30e
BH
509string makeHexDump(const string& str)
510{
511 char tmp[5];
512 string ret;
ea634573 513 ret.reserve((int)(str.size()*2.2));
2db9c30e
BH
514
515 for(string::size_type n=0;n<str.size();++n) {
516 sprintf(tmp,"%02x ", (unsigned char)str[n]);
517 ret+=tmp;
518 }
519 return ret;
520}
521
e67e250f
BH
522// shuffle, maintaining some semblance of order
523void shuffle(vector<DNSResourceRecord>& rrs)
524{
525 vector<DNSResourceRecord>::iterator first, second;
3ddb9247 526 for(first=rrs.begin();first!=rrs.end();++first)
e67e250f
BH
527 if(first->d_place==DNSResourceRecord::ANSWER && first->qtype.getCode() != QType::CNAME) // CNAME must come first
528 break;
529 for(second=first;second!=rrs.end();++second)
530 if(second->d_place!=DNSResourceRecord::ANSWER)
531 break;
3ddb9247 532
e67e250f
BH
533 if(second-first>1)
534 random_shuffle(first,second);
3ddb9247 535
e67e250f 536 // now shuffle the additional records
3ddb9247 537 for(first=second;first!=rrs.end();++first)
e67e250f
BH
538 if(first->d_place==DNSResourceRecord::ADDITIONAL && first->qtype.getCode() != QType::CNAME) // CNAME must come first
539 break;
540 for(second=first;second!=rrs.end();++second)
541 if(second->d_place!=DNSResourceRecord::ADDITIONAL)
542 break;
3ddb9247 543
e67e250f
BH
544 if(second-first>1)
545 random_shuffle(first,second);
546
547 // we don't shuffle the rest
548}
88358c9b 549
92476c8b
PD
550static bool comparePlace(DNSResourceRecord a, DNSResourceRecord b)
551{
552 return (a.d_place < b.d_place);
553}
554
555// make sure rrs is sorted in d_place order to avoid surprises later
556// then shuffle the parts that desire shuffling
557void orderAndShuffle(vector<DNSResourceRecord>& rrs)
558{
559 std::stable_sort(rrs.begin(), rrs.end(), comparePlace);
560 shuffle(rrs);
561}
88358c9b
BH
562
563void normalizeTV(struct timeval& tv)
564{
565 if(tv.tv_usec > 1000000) {
566 ++tv.tv_sec;
567 tv.tv_usec-=1000000;
568 }
569 else if(tv.tv_usec < 0) {
570 --tv.tv_sec;
571 tv.tv_usec+=1000000;
572 }
573}
574
575const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs)
576{
577 struct timeval ret;
578 ret.tv_sec=lhs.tv_sec + rhs.tv_sec;
579 ret.tv_usec=lhs.tv_usec + rhs.tv_usec;
580 normalizeTV(ret);
581 return ret;
582}
583
584const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
585{
586 struct timeval ret;
587 ret.tv_sec=lhs.tv_sec - rhs.tv_sec;
588 ret.tv_usec=lhs.tv_usec - rhs.tv_usec;
589 normalizeTV(ret);
590 return ret;
591}
50c79a76
BH
592
593pair<string, string> splitField(const string& inp, char sepa)
594{
595 pair<string, string> ret;
596 string::size_type cpos=inp.find(sepa);
597 if(cpos==string::npos)
598 ret.first=inp;
599 else {
600 ret.first=inp.substr(0, cpos);
601 ret.second=inp.substr(cpos+1);
602 }
603 return ret;
604}
6e2514e4 605
f8499e52 606int logFacilityToLOG(unsigned int facility)
6e2514e4 607{
6e2514e4
BH
608 switch(facility) {
609 case 0:
610 return LOG_LOCAL0;
611 case 1:
612 return(LOG_LOCAL1);
613 case 2:
614 return(LOG_LOCAL2);
615 case 3:
616 return(LOG_LOCAL3);
617 case 4:
618 return(LOG_LOCAL4);
619 case 5:
620 return(LOG_LOCAL5);
621 case 6:
622 return(LOG_LOCAL6);
623 case 7:
624 return(LOG_LOCAL7);
625 default:
f8499e52 626 return -1;
6e2514e4
BH
627 }
628}
da042e6e
BH
629
630string stripDot(const string& dom)
631{
632 if(dom.empty())
633 return dom;
634
635 if(dom[dom.size()-1]!='.')
636 return dom;
637
638 return dom.substr(0,dom.size()-1);
639}
4dadd22f
BH
640
641
642string labelReverse(const std::string& qname)
643{
644 if(qname.empty())
645 return qname;
646
ee6bba9e
BH
647 bool dotName = qname.find('.') != string::npos;
648
4dadd22f 649 vector<string> labels;
ee6bba9e 650 stringtok(labels, qname, ". ");
4dadd22f
BH
651 if(labels.size()==1)
652 return qname;
653
11d8a43f
BH
654 string ret; // vv const_reverse_iter http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
655 for(vector<string>::reverse_iterator iter = labels.rbegin(); iter != labels.rend(); ++iter) {
4dadd22f 656 if(iter != labels.rbegin())
ee6bba9e 657 ret.append(1, dotName ? ' ' : '.');
4dadd22f
BH
658 ret+=*iter;
659 }
660 return ret;
661}
662
663// do NOT feed trailing dots!
664// www.powerdns.com, powerdns.com -> www
665string makeRelative(const std::string& fqdn, const std::string& zone)
666{
667 if(zone.empty())
3ddb9247 668 return fqdn;
46d7ac33 669 if(toLower(fqdn) != toLower(zone))
4dadd22f
BH
670 return fqdn.substr(0, fqdn.size() - zone.length() - 1); // strip domain name
671 return "";
672}
75943e62
BH
673
674string dotConcat(const std::string& a, const std::string &b)
675{
676 if(a.empty() || b.empty())
677 return a+b;
3ddb9247 678 else
75943e62
BH
679 return a+"."+b;
680}
f71bc087
BH
681
682int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret)
683{
85db02c5
BH
684 if(addr.empty())
685 return -1;
686 string ourAddr(addr);
687 int port = -1;
688 if(addr[0]=='[') { // [::]:53 style address
689 string::size_type pos = addr.find(']');
690 if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':')
691 return -1;
692 ourAddr.assign(addr.c_str() + 1, pos-1);
3ddb9247 693 port = atoi(addr.c_str()+pos+2);
85db02c5 694 }
39d2d9b2 695 ret->sin6_scope_id=0;
696 ret->sin6_family=AF_INET6;
697
0c9de4fc 698 if(inet_pton(AF_INET6, ourAddr.c_str(), (void*)&ret->sin6_addr) != 1) {
699 struct addrinfo* res;
700 struct addrinfo hints;
701 memset(&hints, 0, sizeof(hints));
3ddb9247 702
0c9de4fc 703 hints.ai_family = AF_INET6;
704 hints.ai_flags = AI_NUMERICHOST;
3ddb9247 705
0c9de4fc 706 int error;
707 if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { // this is correct
708 return -1;
709 }
3ddb9247 710
0c9de4fc 711 memcpy(ret, res->ai_addr, res->ai_addrlen);
712 freeaddrinfo(res);
f71bc087 713 }
0c9de4fc 714
85db02c5
BH
715 if(port >= 0)
716 ret->sin6_port = htons(port);
0c9de4fc 717
f71bc087
BH
718 return 0;
719}
834942f1 720
76cb4593 721int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret)
85db02c5
BH
722{
723 if(str.empty()) {
724 return -1;
725 }
726 struct in_addr inp;
3ddb9247 727
85db02c5
BH
728 string::size_type pos = str.find(':');
729 if(pos == string::npos) { // no port specified, not touching the port
3897b9e1 730 if(inet_aton(str.c_str(), &inp)) {
85db02c5
BH
731 ret->sin_addr.s_addr=inp.s_addr;
732 return 0;
733 }
734 return -1;
735 }
736 if(!*(str.c_str() + pos + 1)) // trailing :
3ddb9247
PD
737 return -1;
738
85db02c5
BH
739 char *eptr = (char*)str.c_str() + str.size();
740 int port = strtol(str.c_str() + pos + 1, &eptr, 10);
741 if(*eptr)
742 return -1;
3ddb9247 743
85db02c5 744 ret->sin_port = htons(port);
3897b9e1 745 if(inet_aton(str.substr(0, pos).c_str(), &inp)) {
85db02c5
BH
746 ret->sin_addr.s_addr=inp.s_addr;
747 return 0;
748 }
749 return -1;
750}
751
76cb4593
CH
752int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret)
753{
754 if (path.empty())
755 return -1;
756
757 memset(ret, 0, sizeof(struct sockaddr_un));
758 ret->sun_family = AF_UNIX;
759 if (path.length() >= sizeof(ret->sun_path))
760 return -1;
761
762 path.copy(ret->sun_path, sizeof(ret->sun_path), 0);
763 return 0;
764}
85db02c5 765
834942f1
BH
766//! read a line of text from a FILE* to a std::string, returns false on 'no data'
767bool stringfgets(FILE* fp, std::string& line)
768{
769 char buffer[1024];
770 line.clear();
3ddb9247 771
834942f1
BH
772 do {
773 if(!fgets(buffer, sizeof(buffer), fp))
774 return !line.empty();
3ddb9247
PD
775
776 line.append(buffer);
834942f1
BH
777 } while(!strchr(buffer, '\n'));
778 return true;
779}
e611a06c 780
4e9a20e6 781bool readFileIfThere(const char* fname, std::string* line)
782{
783 line->clear();
784 FILE* fp = fopen(fname, "r");
785 if(!fp)
786 return false;
787 stringfgets(fp, *line);
788 fclose(fp);
789 return true;
790}
791
3ee84c3f
BH
792Regex::Regex(const string &expr)
793{
794 if(regcomp(&d_preg, expr.c_str(), REG_ICASE|REG_NOSUB|REG_EXTENDED))
3f81d239 795 throw PDNSException("Regular expression did not compile");
3ee84c3f 796}
65d8e171 797
bb86485d 798void addCMsgSrcAddr(struct msghdr* msgh, void* cmsgbuf, const ComboAddress* source)
65d8e171 799{
ecc8571f 800 struct cmsghdr *cmsg = NULL;
65d8e171
KN
801
802 if(source->sin4.sin_family == AF_INET6) {
803 struct in6_pktinfo *pkt;
804
805 msgh->msg_control = cmsgbuf;
806 msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt));
807
808 cmsg = CMSG_FIRSTHDR(msgh);
809 cmsg->cmsg_level = IPPROTO_IPV6;
810 cmsg->cmsg_type = IPV6_PKTINFO;
811 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
812
813 pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
814 memset(pkt, 0, sizeof(*pkt));
815 pkt->ipi6_addr = source->sin6.sin6_addr;
816 msgh->msg_controllen = cmsg->cmsg_len; // makes valgrind happy and is slightly better style
817 }
818 else {
819#ifdef IP_PKTINFO
820 struct in_pktinfo *pkt;
821
822 msgh->msg_control = cmsgbuf;
823 msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt));
824
825 cmsg = CMSG_FIRSTHDR(msgh);
826 cmsg->cmsg_level = IPPROTO_IP;
827 cmsg->cmsg_type = IP_PKTINFO;
828 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
829
830 pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
831 memset(pkt, 0, sizeof(*pkt));
832 pkt->ipi_spec_dst = source->sin4.sin_addr;
ecc8571f 833 msgh->msg_controllen = cmsg->cmsg_len;
65d8e171
KN
834#endif
835#ifdef IP_SENDSRCADDR
836 struct in_addr *in;
837
838 msgh->msg_control = cmsgbuf;
839 msgh->msg_controllen = CMSG_SPACE(sizeof(*in));
840
841 cmsg = CMSG_FIRSTHDR(msgh);
842 cmsg->cmsg_level = IPPROTO_IP;
843 cmsg->cmsg_type = IP_SENDSRCADDR;
844 cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
845
846 in = (struct in_addr *) CMSG_DATA(cmsg);
847 *in = source->sin4.sin_addr;
65d8e171 848 msgh->msg_controllen = cmsg->cmsg_len;
ecc8571f 849#endif
65d8e171
KN
850 }
851}
3a8a4d68 852
853unsigned int getFilenumLimit(bool hardOrSoft)
854{
855 struct rlimit rlim;
856 if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
857 unixDie("Requesting number of available file descriptors");
858 return hardOrSoft ? rlim.rlim_max : rlim.rlim_cur;
859}
860
861void setFilenumLimit(unsigned int lim)
862{
863 struct rlimit rlim;
864
865 if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
866 unixDie("Requesting number of available file descriptors");
867 rlim.rlim_cur=lim;
868 if(setrlimit(RLIMIT_NOFILE, &rlim) < 0)
869 unixDie("Setting number of available file descriptors");
870}
06ea9015 871
872#define burtlemix(a,b,c) \
873{ \
874 a -= b; a -= c; a ^= (c>>13); \
875 b -= c; b -= a; b ^= (a<<8); \
876 c -= a; c -= b; c ^= (b>>13); \
877 a -= b; a -= c; a ^= (c>>12); \
878 b -= c; b -= a; b ^= (a<<16); \
879 c -= a; c -= b; c ^= (b>>5); \
880 a -= b; a -= c; a ^= (c>>3); \
881 b -= c; b -= a; b ^= (a<<10); \
882 c -= a; c -= b; c ^= (b>>15); \
883}
884
885uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t initval)
886{
887 uint32_t a,b,c,len;
888
889 /* Set up the internal state */
890 len = length;
891 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
892 c = initval; /* the previous hash value */
893
894 /*---------------------------------------- handle most of the key */
895 while (len >= 12) {
896 a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
897 b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
898 c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
899 burtlemix(a,b,c);
900 k += 12; len -= 12;
901 }
902
903 /*------------------------------------- handle the last 11 bytes */
904 c += length;
905 switch(len) { /* all the case statements fall through */
906 case 11: c+=((uint32_t)k[10]<<24);
907 case 10: c+=((uint32_t)k[9]<<16);
908 case 9 : c+=((uint32_t)k[8]<<8);
909 /* the first byte of c is reserved for the length */
910 case 8 : b+=((uint32_t)k[7]<<24);
911 case 7 : b+=((uint32_t)k[6]<<16);
912 case 6 : b+=((uint32_t)k[5]<<8);
913 case 5 : b+=k[4];
914 case 4 : a+=((uint32_t)k[3]<<24);
915 case 3 : a+=((uint32_t)k[2]<<16);
916 case 2 : a+=((uint32_t)k[1]<<8);
917 case 1 : a+=k[0];
918 /* case 0: nothing left to add */
919 }
920 burtlemix(a,b,c);
921 /*-------------------------------------------- report the result */
922 return c;
923}
9ae194e2 924
915b0c39 925bool setSocketTimestamps(int fd)
9ae194e2 926{
eb4c1792 927#ifdef SO_TIMESTAMP
9ae194e2 928 int on=1;
915b0c39 929 return setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, (char*)&on, sizeof(on)) == 0;
eb4c1792 930#endif
915b0c39 931 return true; // we pretend this happened.
9ae194e2 932}
58044407 933
f55691d1 934uint32_t pdns_strtoui(const char *nptr, char **endptr, int base)
58044407 935{
ec4280c5 936#if ULONG_MAX == 4294967295
937 return strtoul(nptr, endptr, base);
938#else
58044407
AT
939 unsigned long val = strtoul(nptr, endptr, base);
940 if (val > UINT_MAX) {
941 errno = ERANGE;
942 return UINT_MAX;
3ddb9247 943 }
58044407
AT
944
945 return val;
ec4280c5 946#endif
58044407 947}
3897b9e1 948bool setNonBlocking(int sock)
949{
3ddb9247 950 int flags=fcntl(sock,F_GETFL,0);
3897b9e1 951 if(flags<0 || fcntl(sock, F_SETFL,flags|O_NONBLOCK) <0)
952 return false;
953 return true;
954}
955
956bool setBlocking(int sock)
957{
3ddb9247 958 int flags=fcntl(sock,F_GETFL,0);
3897b9e1 959 if(flags<0 || fcntl(sock, F_SETFL,flags&(~O_NONBLOCK)) <0)
960 return false;
961 return true;
962}
963
964// Closes a socket.
965int closesocket( int socket )
966{
967 int ret=::close(socket);
968 if(ret < 0 && errno == ECONNRESET) // see ticket 192, odd BSD behaviour
969 return 0;
3ddb9247 970 if(ret < 0)
3897b9e1 971 throw PDNSException("Error closing socket: "+stringerror());
972 return ret;
973}
974
975bool setCloseOnExec(int sock)
976{
3ddb9247 977 int flags=fcntl(sock,F_GETFD,0);
3897b9e1 978 if(flags<0 || fcntl(sock, F_SETFD,flags|FD_CLOEXEC) <0)
979 return false;
980 return true;
981}
982
8290ad9f 983uint64_t udpErrorStats(const std::string& str)
984{
985#ifdef __linux__
986 ifstream ifs("/proc/net/snmp");
987 if(!ifs)
988 return 0;
989 string line;
990 vector<string> parts;
991 while(getline(ifs,line)) {
992 if(boost::starts_with(line, "Udp: ") && isdigit(line[5])) {
993 stringtok(parts, line, " \n\t\r");
994 if(parts.size() < 7)
995 break;
996 if(str=="udp-rcvbuf-errors")
997 return boost::lexical_cast<uint64_t>(parts[5]);
998 else if(str=="udp-sndbuf-errors")
999 return boost::lexical_cast<uint64_t>(parts[6]);
1000 else if(str=="udp-noport-errors")
1001 return boost::lexical_cast<uint64_t>(parts[2]);
1002 else if(str=="udp-in-errors")
1003 return boost::lexical_cast<uint64_t>(parts[3]);
1004 else
1005 return 0;
1006 }
1007 }
1008#endif
1009 return 0;
1010}
da15912b 1011
21a3792f 1012bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum)
da15912b 1013{
68d25b43
PL
1014 string strAlgoName = algoName.toString();
1015 if (strAlgoName == "hmac-md5.sig-alg.reg.int." || strAlgoName == "hmac-md5.") // FIXME400
da15912b 1016 algoEnum = TSIG_MD5;
68d25b43 1017 else if (strAlgoName == "hmac-sha1.")
da15912b 1018 algoEnum = TSIG_SHA1;
68d25b43 1019 else if (strAlgoName == "hmac-sha224.")
da15912b 1020 algoEnum = TSIG_SHA224;
68d25b43 1021 else if (strAlgoName == "hmac-sha256.")
da15912b 1022 algoEnum = TSIG_SHA256;
68d25b43 1023 else if (strAlgoName == "hmac-sha384.")
da15912b 1024 algoEnum = TSIG_SHA384;
68d25b43 1025 else if (strAlgoName == "hmac-sha512.")
da15912b 1026 algoEnum = TSIG_SHA512;
68d25b43 1027 else if (strAlgoName == "gss-tsig.")
bcb5b94e 1028 algoEnum = TSIG_GSS;
da15912b
AT
1029 else {
1030 return false;
1031 }
1032 return true;
1033}
bfd4efae 1034
21a3792f 1035DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum)
bfd4efae
AT
1036{
1037 switch(algoEnum) {
21a3792f
KM
1038 case TSIG_MD5: return "hmac-md5.sig-alg.reg.int.";
1039 case TSIG_SHA1: return "hmac-sha1.";
1040 case TSIG_SHA224: return "hmac-sha224.";
1041 case TSIG_SHA256: return "hmac-sha256.";
1042 case TSIG_SHA384: return "hmac-sha384.";
1043 case TSIG_SHA512: return "hmac-sha512.";
1044 case TSIG_GSS: return "gss-tsig.";
bfd4efae
AT
1045 }
1046 throw PDNSException("getTSIGAlgoName does not understand given algorithm, please fix!");
1047}