]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/misc.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2014 PowerDNS.COM BV
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
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.
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.
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
26 #include <sys/param.h>
27 #include <sys/socket.h>
31 #include <sys/resource.h>
32 #include <netinet/in.h>
42 #include <boost/optional.hpp>
48 #include "pdnsexception.hh"
49 #include <sys/types.h>
51 #include <boost/algorithm/string.hpp>
55 bool g_singleThreaded
;
57 int writen2(int fd
, const void *buf
, size_t count
)
59 const char *ptr
= (char*)buf
;
60 const char *eptr
= ptr
+ count
;
64 res
= ::write(fd
, ptr
, eptr
- ptr
);
67 throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN");
69 unixDie("failed in writen2");
72 throw std::runtime_error("could not write all bytes, got eof in writen2");
80 int readn2(int fd
, void* buffer
, unsigned int len
)
85 res
= read(fd
, (char*)buffer
+ pos
, len
- pos
);
87 throw runtime_error("EOF while writing message");
90 throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN");
92 unixDie("failed in writen2");
106 string t
=ctime(&now
);
107 boost::trim_right(t
);
111 uint16_t getShort(const unsigned char *p
)
113 return p
[0] * 256 + p
[1];
117 uint16_t getShort(const char *p
)
119 return getShort((const unsigned char *)p
);
122 uint32_t getLong(const unsigned char* p
)
124 return (p
[0]<<24) + (p
[1]<<16) + (p
[2]<<8) + p
[3];
127 uint32_t getLong(const char* p
)
129 return getLong((unsigned char *)p
);
134 /** strips a domain suffix from a domain, returns true if it stripped */
135 bool stripDomainSuffix(string
*qname
, const string
&domain
)
137 if(!endsOn(*qname
, domain
))
140 if(toLower(*qname
)==toLower(domain
))
143 if((*qname
)[qname
->size()-domain
.size()-1]!='.')
146 qname
->resize(qname
->size()-domain
.size()-1);
151 /** 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 */
152 bool chopOff(string
&domain
)
157 string::size_type fdot
=domain
.find('.');
159 if(fdot
==string::npos
)
162 string::size_type remain
= domain
.length() - (fdot
+ 1);
164 memcpy(tmp
, domain
.c_str()+fdot
+1, remain
);
165 domain
.assign(tmp
, remain
); // don't dare to do this w/o tmp holder :-)
170 /** 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 */
171 bool chopOffDotted(string
&domain
)
173 if(domain
.empty() || (domain
.size()==1 && domain
[0]=='.'))
176 string::size_type fdot
=domain
.find('.');
177 if(fdot
== string::npos
)
180 if(fdot
==domain
.size()-1)
183 string::size_type remain
= domain
.length() - (fdot
+ 1);
185 memcpy(tmp
, domain
.c_str()+fdot
+1, remain
);
186 domain
.assign(tmp
, remain
);
192 bool ciEqual(const string
& a
, const string
& b
)
194 if(a
.size()!=b
.size())
197 string::size_type pos
=0, epos
=a
.size();
198 for(;pos
< epos
; ++pos
)
199 if(dns_tolower(a
[pos
])!=dns_tolower(b
[pos
]))
204 /** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
205 bool endsOn(const string
&domain
, const string
&suffix
)
207 if( suffix
.empty() || ciEqual(domain
, suffix
) )
210 if(domain
.size()<=suffix
.size())
213 string::size_type dpos
=domain
.size()-suffix
.size()-1, spos
=0;
215 if(domain
[dpos
++]!='.')
218 for(; dpos
< domain
.size(); ++dpos
, ++spos
)
219 if(dns_tolower(domain
[dpos
]) != dns_tolower(suffix
[spos
]))
225 /** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
226 bool dottedEndsOn(const string
&domain
, const string
&suffix
)
228 if( suffix
=="." || ciEqual(domain
, suffix
) )
231 if(domain
.size()<=suffix
.size())
234 string::size_type dpos
=domain
.size()-suffix
.size()-1, spos
=0;
236 if(domain
[dpos
++]!='.')
239 for(; dpos
< domain
.size(); ++dpos
, ++spos
)
240 if(dns_tolower(domain
[dpos
]) != dns_tolower(suffix
[spos
]))
246 static void parseService4(const string
&descr
, ServiceTuple
&st
)
249 stringtok(parts
,descr
,":");
251 throw PDNSException("Unable to parse '"+descr
+"' as a service");
254 st
.port
=atoi(parts
[1].c_str());
257 static void parseService6(const string
&descr
, ServiceTuple
&st
)
259 string::size_type pos
=descr
.find(']');
260 if(pos
== string::npos
)
261 throw PDNSException("Unable to parse '"+descr
+"' as an IPv6 service");
263 st
.host
=descr
.substr(1, pos
-1);
264 if(pos
+ 2 < descr
.length())
265 st
.port
=atoi(descr
.c_str() + pos
+2);
269 void parseService(const string
&descr
, ServiceTuple
&st
)
272 throw PDNSException("Unable to parse '"+descr
+"' as a service");
274 vector
<string
> parts
;
275 stringtok(parts
, descr
, ":");
278 parseService6(descr
, st
);
280 else if(descr
[0]==':' || parts
.size() > 2 || descr
.find("::") != string::npos
) {
284 parseService4(descr
, st
);
288 // returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
289 int waitForData(int fd
, int seconds
, int useconds
)
291 return waitForRWData(fd
, true, seconds
, useconds
);
294 int waitForRWData(int fd
, bool waitForRead
, int seconds
, int useconds
)
299 memset(&pfd
, 0, sizeof(pfd
));
307 ret
= poll(&pfd
, 1, seconds
* 1000 + useconds
/1000);
309 errno
= ETIMEDOUT
; // ???
314 // returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
315 int waitFor2Data(int fd1
, int fd2
, int seconds
, int useconds
, int*fd
)
319 struct pollfd pfds
[2];
320 memset(&pfds
[0], 0, 2*sizeof(struct pollfd
));
324 pfds
[0].events
= pfds
[1].events
= POLLIN
;
326 int nsocks
= 1 + (fd2
>= 0); // fd2 can optionally be -1
329 ret
= poll(pfds
, nsocks
, seconds
* 1000 + useconds
/1000);
331 ret
= poll(pfds
, nsocks
, -1);
335 if((pfds
[0].revents
& POLLIN
) && !(pfds
[1].revents
& POLLIN
))
337 else if((pfds
[1].revents
& POLLIN
) && !(pfds
[0].revents
& POLLIN
))
340 *fd
= pfds
[random()%2].fd
;
343 *fd
= -1; // should never happen
349 string
humanDuration(time_t passed
)
353 ret
<<passed
<<" seconds";
355 ret
<<std::setprecision(2)<<passed
/60.0<<" minutes";
356 else if(passed
<86400)
357 ret
<<std::setprecision(3)<<passed
/3600.0<<" hours";
358 else if(passed
<(86400*30.41))
359 ret
<<std::setprecision(3)<<passed
/86400.0<<" days";
361 ret
<<std::setprecision(3)<<passed
/(86400*30.41)<<" months";
368 // set(); // saves lots of gettimeofday calls
371 DTime::DTime(const DTime
&dt
)
381 const string
unquotify(const string
&item
)
386 string::size_type bpos
=0, epos
=item
.size();
391 if(item
[epos
-1]=='"')
394 return item
.substr(bpos
,epos
-bpos
);
397 void stripLine(string
&line
)
399 string::size_type pos
=line
.find_first_of("\r\n");
400 if(pos
!=string::npos
) {
405 string
urlEncode(const string
&text
)
408 for(string::const_iterator i
=text
.begin();i
!=text
.end();++i
)
409 if(*i
==' ')ret
.append("%20");
410 else ret
.append(1,*i
);
416 #ifndef MAXHOSTNAMELEN
417 #define MAXHOSTNAMELEN 255
420 char tmp
[MAXHOSTNAMELEN
];
421 if(gethostname(tmp
, MAXHOSTNAMELEN
))
434 string
uitoa(unsigned int i
) // MSVC 6 doesn't grok overloading (un)signed
441 string
bitFlip(const string
&str
)
443 string::size_type pos
=0, epos
=str
.size();
446 for(;pos
< epos
; ++pos
)
447 ret
.append(1, ~str
[pos
]);
453 return strerror(errno
);
456 string
netstringerror()
458 return stringerror();
461 void cleanSlashes(string
&str
)
463 string::const_iterator i
;
465 for(i
=str
.begin();i
!=str
.end();++i
) {
466 if(*i
=='/' && i
!=str
.begin() && *(i
-1)=='/')
474 bool IpToU32(const string
&str
, uint32_t *ip
)
482 if(Utility::inet_aton(str
.c_str(), &inp
)) {
489 string
U32ToIP(uint32_t val
)
492 snprintf(tmp
, sizeof(tmp
)-1, "%u.%u.%u.%u",
501 string
makeHexDump(const string
& str
)
505 ret
.reserve((int)(str
.size()*2.2));
507 for(string::size_type n
=0;n
<str
.size();++n
) {
508 sprintf(tmp
,"%02x ", (unsigned char)str
[n
]);
514 // shuffle, maintaining some semblance of order
515 void shuffle(vector
<DNSResourceRecord
>& rrs
)
517 vector
<DNSResourceRecord
>::iterator first
, second
;
518 for(first
=rrs
.begin();first
!=rrs
.end();++first
)
519 if(first
->d_place
==DNSResourceRecord::ANSWER
&& first
->qtype
.getCode() != QType::CNAME
) // CNAME must come first
521 for(second
=first
;second
!=rrs
.end();++second
)
522 if(second
->d_place
!=DNSResourceRecord::ANSWER
)
526 random_shuffle(first
,second
);
528 // now shuffle the additional records
529 for(first
=second
;first
!=rrs
.end();++first
)
530 if(first
->d_place
==DNSResourceRecord::ADDITIONAL
&& first
->qtype
.getCode() != QType::CNAME
) // CNAME must come first
532 for(second
=first
;second
!=rrs
.end();++second
)
533 if(second
->d_place
!=DNSResourceRecord::ADDITIONAL
)
537 random_shuffle(first
,second
);
539 // we don't shuffle the rest
542 static bool comparePlace(DNSResourceRecord a
, DNSResourceRecord b
)
544 return (a
.d_place
< b
.d_place
);
547 // make sure rrs is sorted in d_place order to avoid surprises later
548 // then shuffle the parts that desire shuffling
549 void orderAndShuffle(vector
<DNSResourceRecord
>& rrs
)
551 std::stable_sort(rrs
.begin(), rrs
.end(), comparePlace
);
555 void normalizeTV(struct timeval
& tv
)
557 if(tv
.tv_usec
> 1000000) {
561 else if(tv
.tv_usec
< 0) {
567 const struct timeval
operator+(const struct timeval
& lhs
, const struct timeval
& rhs
)
570 ret
.tv_sec
=lhs
.tv_sec
+ rhs
.tv_sec
;
571 ret
.tv_usec
=lhs
.tv_usec
+ rhs
.tv_usec
;
576 const struct timeval
operator-(const struct timeval
& lhs
, const struct timeval
& rhs
)
579 ret
.tv_sec
=lhs
.tv_sec
- rhs
.tv_sec
;
580 ret
.tv_usec
=lhs
.tv_usec
- rhs
.tv_usec
;
585 pair
<string
, string
> splitField(const string
& inp
, char sepa
)
587 pair
<string
, string
> ret
;
588 string::size_type cpos
=inp
.find(sepa
);
589 if(cpos
==string::npos
)
592 ret
.first
=inp
.substr(0, cpos
);
593 ret
.second
=inp
.substr(cpos
+1);
598 int logFacilityToLOG(unsigned int facility
)
622 string
stripDot(const string
& dom
)
627 if(dom
[dom
.size()-1]!='.')
630 return dom
.substr(0,dom
.size()-1);
634 string
labelReverse(const std::string
& qname
)
639 bool dotName
= qname
.find('.') != string::npos
;
641 vector
<string
> labels
;
642 stringtok(labels
, qname
, ". ");
646 string ret
; // vv const_reverse_iter http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
647 for(vector
<string
>::reverse_iterator iter
= labels
.rbegin(); iter
!= labels
.rend(); ++iter
) {
648 if(iter
!= labels
.rbegin())
649 ret
.append(1, dotName
? ' ' : '.');
655 // do NOT feed trailing dots!
656 // www.powerdns.com, powerdns.com -> www
657 string
makeRelative(const std::string
& fqdn
, const std::string
& zone
)
662 return fqdn
.substr(0, fqdn
.size() - zone
.length() - 1); // strip domain name
666 string
dotConcat(const std::string
& a
, const std::string
&b
)
668 if(a
.empty() || b
.empty())
674 int makeIPv6sockaddr(const std::string
& addr
, struct sockaddr_in6
* ret
)
678 string
ourAddr(addr
);
680 if(addr
[0]=='[') { // [::]:53 style address
681 string::size_type pos
= addr
.find(']');
682 if(pos
== string::npos
|| pos
+ 2 > addr
.size() || addr
[pos
+1]!=':')
684 ourAddr
.assign(addr
.c_str() + 1, pos
-1);
685 port
= atoi(addr
.c_str()+pos
+2);
687 ret
->sin6_scope_id
=0;
688 ret
->sin6_family
=AF_INET6
;
690 if(inet_pton(AF_INET6
, ourAddr
.c_str(), (void*)&ret
->sin6_addr
) != 1) {
691 struct addrinfo
* res
;
692 struct addrinfo hints
;
693 memset(&hints
, 0, sizeof(hints
));
695 hints
.ai_family
= AF_INET6
;
696 hints
.ai_flags
= AI_NUMERICHOST
;
699 if((error
=getaddrinfo(ourAddr
.c_str(), 0, &hints
, &res
))) { // this is correct
703 memcpy(ret
, res
->ai_addr
, res
->ai_addrlen
);
708 ret
->sin6_port
= htons(port
);
713 int makeIPv4sockaddr(const std::string
& str
, struct sockaddr_in
* ret
)
720 string::size_type pos
= str
.find(':');
721 if(pos
== string::npos
) { // no port specified, not touching the port
722 if(Utility::inet_aton(str
.c_str(), &inp
)) {
723 ret
->sin_addr
.s_addr
=inp
.s_addr
;
728 if(!*(str
.c_str() + pos
+ 1)) // trailing :
731 char *eptr
= (char*)str
.c_str() + str
.size();
732 int port
= strtol(str
.c_str() + pos
+ 1, &eptr
, 10);
736 ret
->sin_port
= htons(port
);
737 if(Utility::inet_aton(str
.substr(0, pos
).c_str(), &inp
)) {
738 ret
->sin_addr
.s_addr
=inp
.s_addr
;
744 int makeUNsockaddr(const std::string
& path
, struct sockaddr_un
* ret
)
749 memset(ret
, 0, sizeof(struct sockaddr_un
));
750 ret
->sun_family
= AF_UNIX
;
751 if (path
.length() >= sizeof(ret
->sun_path
))
754 path
.copy(ret
->sun_path
, sizeof(ret
->sun_path
), 0);
758 //! read a line of text from a FILE* to a std::string, returns false on 'no data'
759 bool stringfgets(FILE* fp
, std::string
& line
)
765 if(!fgets(buffer
, sizeof(buffer
), fp
))
766 return !line
.empty();
769 } while(!strchr(buffer
, '\n'));
773 bool readFileIfThere(const char* fname
, std::string
* line
)
776 FILE* fp
= fopen(fname
, "r");
779 stringfgets(fp
, *line
);
784 Regex::Regex(const string
&expr
)
786 if(regcomp(&d_preg
, expr
.c_str(), REG_ICASE
|REG_NOSUB
|REG_EXTENDED
))
787 throw PDNSException("Regular expression did not compile");
790 void addCMsgSrcAddr(struct msghdr
* msgh
, void* cmsgbuf
, const ComboAddress
* source
)
792 struct cmsghdr
*cmsg
= NULL
;
794 if(source
->sin4
.sin_family
== AF_INET6
) {
795 struct in6_pktinfo
*pkt
;
797 msgh
->msg_control
= cmsgbuf
;
798 msgh
->msg_controllen
= CMSG_SPACE(sizeof(*pkt
));
800 cmsg
= CMSG_FIRSTHDR(msgh
);
801 cmsg
->cmsg_level
= IPPROTO_IPV6
;
802 cmsg
->cmsg_type
= IPV6_PKTINFO
;
803 cmsg
->cmsg_len
= CMSG_LEN(sizeof(*pkt
));
805 pkt
= (struct in6_pktinfo
*) CMSG_DATA(cmsg
);
806 memset(pkt
, 0, sizeof(*pkt
));
807 pkt
->ipi6_addr
= source
->sin6
.sin6_addr
;
808 msgh
->msg_controllen
= cmsg
->cmsg_len
; // makes valgrind happy and is slightly better style
812 struct in_pktinfo
*pkt
;
814 msgh
->msg_control
= cmsgbuf
;
815 msgh
->msg_controllen
= CMSG_SPACE(sizeof(*pkt
));
817 cmsg
= CMSG_FIRSTHDR(msgh
);
818 cmsg
->cmsg_level
= IPPROTO_IP
;
819 cmsg
->cmsg_type
= IP_PKTINFO
;
820 cmsg
->cmsg_len
= CMSG_LEN(sizeof(*pkt
));
822 pkt
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
823 memset(pkt
, 0, sizeof(*pkt
));
824 pkt
->ipi_spec_dst
= source
->sin4
.sin_addr
;
825 msgh
->msg_controllen
= cmsg
->cmsg_len
;
827 #ifdef IP_SENDSRCADDR
830 msgh
->msg_control
= cmsgbuf
;
831 msgh
->msg_controllen
= CMSG_SPACE(sizeof(*in
));
833 cmsg
= CMSG_FIRSTHDR(msgh
);
834 cmsg
->cmsg_level
= IPPROTO_IP
;
835 cmsg
->cmsg_type
= IP_SENDSRCADDR
;
836 cmsg
->cmsg_len
= CMSG_LEN(sizeof(*in
));
838 in
= (struct in_addr
*) CMSG_DATA(cmsg
);
839 *in
= source
->sin4
.sin_addr
;
840 msgh
->msg_controllen
= cmsg
->cmsg_len
;
845 unsigned int getFilenumLimit(bool hardOrSoft
)
848 if(getrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
849 unixDie("Requesting number of available file descriptors");
850 return hardOrSoft
? rlim
.rlim_max
: rlim
.rlim_cur
;
853 void setFilenumLimit(unsigned int lim
)
857 if(getrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
858 unixDie("Requesting number of available file descriptors");
860 if(setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
861 unixDie("Setting number of available file descriptors");
864 #define burtlemix(a,b,c) \
866 a -= b; a -= c; a ^= (c>>13); \
867 b -= c; b -= a; b ^= (a<<8); \
868 c -= a; c -= b; c ^= (b>>13); \
869 a -= b; a -= c; a ^= (c>>12); \
870 b -= c; b -= a; b ^= (a<<16); \
871 c -= a; c -= b; c ^= (b>>5); \
872 a -= b; a -= c; a ^= (c>>3); \
873 b -= c; b -= a; b ^= (a<<10); \
874 c -= a; c -= b; c ^= (b>>15); \
877 uint32_t burtle(const unsigned char* k
, uint32_t length
, uint32_t initval
)
881 /* Set up the internal state */
883 a
= b
= 0x9e3779b9; /* the golden ratio; an arbitrary value */
884 c
= initval
; /* the previous hash value */
886 /*---------------------------------------- handle most of the key */
888 a
+= (k
[0] +((uint32_t)k
[1]<<8) +((uint32_t)k
[2]<<16) +((uint32_t)k
[3]<<24));
889 b
+= (k
[4] +((uint32_t)k
[5]<<8) +((uint32_t)k
[6]<<16) +((uint32_t)k
[7]<<24));
890 c
+= (k
[8] +((uint32_t)k
[9]<<8) +((uint32_t)k
[10]<<16)+((uint32_t)k
[11]<<24));
895 /*------------------------------------- handle the last 11 bytes */
897 switch(len
) { /* all the case statements fall through */
898 case 11: c
+=((uint32_t)k
[10]<<24);
899 case 10: c
+=((uint32_t)k
[9]<<16);
900 case 9 : c
+=((uint32_t)k
[8]<<8);
901 /* the first byte of c is reserved for the length */
902 case 8 : b
+=((uint32_t)k
[7]<<24);
903 case 7 : b
+=((uint32_t)k
[6]<<16);
904 case 6 : b
+=((uint32_t)k
[5]<<8);
906 case 4 : a
+=((uint32_t)k
[3]<<24);
907 case 3 : a
+=((uint32_t)k
[2]<<16);
908 case 2 : a
+=((uint32_t)k
[1]<<8);
910 /* case 0: nothing left to add */
913 /*-------------------------------------------- report the result */
917 void setSocketTimestamps(int fd
)
921 if (setsockopt(fd
, SOL_SOCKET
, SO_TIMESTAMP
, (char*)&on
, sizeof(on
)) < 0 )
922 L
<<Logger::Error
<<"Unable to enable timestamp reporting for socket"<<endl
;
926 uint32_t pdns_strtoui(const char *nptr
, char **endptr
, int base
)
928 #if ULONG_MAX == 4294967295
929 return strtoul(nptr
, endptr
, base
);
931 unsigned long val
= strtoul(nptr
, endptr
, base
);
932 if (val
> UINT_MAX
) {