root/trunk/pdns/pdns/misc.cc @ 845

Revision 845, 10.6 KB (checked in by ahu, 7 years ago)

add support to make powerdns able to listen on multiple different ports, per local-address.
Accepts [::1]:5300 syntax and 127.0.0.1:5300

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2002  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
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18*/
19
20#ifndef WIN32
21#include <sys/param.h>
22#include <netdb.h>
23#include <sys/time.h>
24#include <time.h>
25#include <netinet/in.h>
26#include <unistd.h>
27#endif // WIN32
28
29#include "misc.hh"
30#include <vector>
31#include <sstream>
32#include <errno.h>
33#include <cstring>
34#include <iostream>
35#include <algorithm>
36
37#include <iomanip>
38#include <string.h>
39#include <stdlib.h>
40#include <stdio.h>
41#include "ahuexception.hh"
42#include <sys/types.h>
43
44
45#include "utility.hh"
46
47string nowTime()
48{
49  time_t now=time(0);
50  string t=ctime(&now);
51  chomp(t,"\n");
52  return t;
53}
54
55uint16_t getShort(const unsigned char *p)
56{
57  return p[0] * 256 + p[1];
58}
59
60
61uint16_t getShort(const char *p)
62{
63  return getShort((const unsigned char *)p);
64}
65
66uint32_t getLong(const unsigned char* p)
67{
68  return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
69}
70
71uint32_t getLong(const char* p)
72{
73  return getLong((unsigned char *)p);
74}
75
76
77
78/** strips a domain suffix from a domain, returns true if it stripped */
79bool stripDomainSuffix(string *qname, const string &domain)
80{
81  if(!endsOn(*qname, domain))
82    return false;
83
84  if(toLower(*qname)==toLower(domain))
85    *qname="@";
86  else {
87    if((*qname)[qname->size()-domain.size()-1]!='.')
88      return false;
89
90    qname->resize(qname->size()-domain.size()-1);
91  }
92  return true;
93}
94
95/** 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 */
96bool chopOff(string &domain)
97{
98  if(domain.empty())
99    return false;
100
101  string::size_type fdot=domain.find('.');
102
103  if(fdot==string::npos) 
104    domain="";
105  else 
106    domain=domain.substr(fdot+1);
107  return true;
108}
109
110/** 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 */
111bool chopOffDotted(string &domain)
112{
113  if(domain.empty() || (domain.size()==1 && domain[0]=='.'))
114    return false;
115
116  string::size_type fdot=domain.find('.');
117
118  if(fdot==domain.size()-1) 
119    domain=".";
120  else 
121    domain=domain.substr(fdot+1);
122  return true;
123}
124
125
126bool ciEqual(const string& a, const string& b)
127{
128  if(a.size()!=b.size())
129    return false;
130
131  string::size_type pos=0, epos=a.size();
132  for(;pos < epos; ++pos)
133    if(dns_tolower(a[pos])!=dns_tolower(b[pos]))
134      return false;
135  return true;
136}
137
138/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
139bool endsOn(const string &domain, const string &suffix) 
140{
141  if( suffix.empty() || ciEqual(domain, suffix) )
142    return true;
143
144  if(domain.size()<=suffix.size())
145    return false;
146 
147  string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
148
149  if(domain[dpos++]!='.')
150    return false;
151
152  for(; dpos < domain.size(); ++dpos, ++spos)
153    if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
154      return false;
155
156  return true;
157}
158
159/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
160bool dottedEndsOn(const string &domain, const string &suffix) 
161{
162  if( suffix=="." || ciEqual(domain, suffix) )
163    return true;
164
165  if(domain.size()<=suffix.size())
166    return false;
167 
168  string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
169
170  if(domain[dpos++]!='.')
171    return false;
172
173  for(; dpos < domain.size(); ++dpos, ++spos)
174    if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
175      return false;
176
177  return true;
178}
179
180
181int sendData(const char *buffer, int replen, int outsock)
182{
183  uint16_t nlen=htons(replen);
184  Utility::iovec iov[2];
185  iov[0].iov_base=(char*)&nlen;
186  iov[0].iov_len=2;
187  iov[1].iov_base=(char*)buffer;
188  iov[1].iov_len=replen;
189  int ret=Utility::writev(outsock,iov,2);
190
191  if(ret<0) {
192    return -1;
193  }
194  if(ret!=replen+2) {
195    return -1;
196  }
197  return 0;
198}
199
200static void parseService4(const string &descr, ServiceTuple &st)
201{
202  vector<string>parts;
203  stringtok(parts,descr,":");
204  if(parts.empty())
205    throw AhuException("Unable to parse '"+descr+"' as a service");
206  st.host=parts[0];
207  if(parts.size()>1)
208    st.port=atoi(parts[1].c_str());
209}
210
211static void parseService6(const string &descr, ServiceTuple &st)
212{
213  string::size_type pos=descr.find(']');
214  if(pos == string::npos)
215    throw AhuException("Unable to parse '"+descr+"' as an IPv6 service");
216
217  st.host=descr.substr(1, pos-1);
218  if(pos + 2 < descr.length())
219    st.port=atoi(descr.c_str() + pos +2);
220}
221
222
223void parseService(const string &descr, ServiceTuple &st)
224{
225  if(descr.empty())
226    throw AhuException("Unable to parse '"+descr+"' as a service");
227
228  vector<string> parts;
229  stringtok(parts, descr, ":");
230
231  if(descr[0]=='[') {
232    parseService6(descr, st);
233  }
234  else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) {
235    st.host=descr;
236  }
237  else {
238    parseService4(descr, st);
239  }
240}
241
242int waitForData(int fd, int seconds, int useconds)
243{
244  struct timeval tv;
245  int ret;
246
247  tv.tv_sec   = seconds;
248  tv.tv_usec  = useconds;
249
250  fd_set readfds;
251  FD_ZERO( &readfds );
252  FD_SET( fd, &readfds );
253
254  ret = select( fd + 1, &readfds, NULL, NULL, &tv );
255  if ( ret == -1 )
256    errno = ETIMEDOUT;
257
258  return ret;
259}
260
261
262string humanDuration(time_t passed)
263{
264  ostringstream ret;
265  if(passed<60)
266    ret<<passed<<" seconds";
267  else if(passed<3600)
268    ret<<setprecision(2)<<passed/60.0<<" minutes";
269  else if(passed<86400)
270    ret<<setprecision(3)<<passed/3600.0<<" hours";
271  else if(passed<(86400*30.41))
272    ret<<setprecision(3)<<passed/86400.0<<" days";
273  else
274    ret<<setprecision(3)<<passed/(86400*30.41)<<" months";
275
276  return ret.str();
277}
278
279DTime::DTime()
280{
281//  set(); // saves lots of gettimeofday calls
282}
283
284DTime::DTime(const DTime &dt)
285{
286  d_set=dt.d_set;
287}
288
289time_t DTime::time()
290{
291  return d_set.tv_sec;
292}
293
294const string unquotify(const string &item)
295{
296  if(item.size()<2)
297    return item;
298
299  string::size_type bpos=0, epos=item.size();
300
301  if(item[0]=='"') 
302    bpos=1;
303
304  if(item[epos-1]=='"')
305    epos-=1;
306
307  return item.substr(bpos,epos-bpos);
308}
309
310void stripLine(string &line)
311{
312  string::size_type pos=line.find_first_of("\r\n");
313  if(pos!=string::npos) {
314    line.resize(pos);
315  }
316}
317
318string urlEncode(const string &text)
319{
320  string ret;
321  for(string::const_iterator i=text.begin();i!=text.end();++i)
322    if(*i==' ')ret.append("%20");
323    else ret.append(1,*i);
324  return ret;
325}
326
327string getHostname()
328{
329#ifdef WIN32
330# define MAXHOSTNAMELEN 1025
331#endif // WIN32
332
333  char tmp[MAXHOSTNAMELEN];
334  if(gethostname(tmp, MAXHOSTNAMELEN))
335    return "UNKNOWN";
336
337  return tmp;
338}
339
340string itoa(int i)
341{
342  ostringstream o;
343  o<<i;
344  return o.str();
345}
346
347string uitoa(unsigned int i) // MSVC 6 doesn't grok overloading (un)signed
348{
349  ostringstream o;
350  o<<i;
351  return o.str();
352}
353
354
355string stringerror()
356{
357  return strerror(errno);
358}
359
360#ifdef WIN32
361string netstringerror()
362{
363  char buf[512];
364  int err=WSAGetLastError();
365  if(FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
366                     0, buf, sizeof(buf)-1, NULL)) {
367    return string(buf);
368  }
369  else {
370    return strerror(err);
371  }
372}
373#else
374string netstringerror()
375{
376  return stringerror();
377}
378#endif
379
380void cleanSlashes(string &str)
381{
382  string::const_iterator i;
383  string out;
384  for(i=str.begin();i!=str.end();++i) {
385    if(*i=='/' && i!=str.begin() && *(i-1)=='/')
386      continue;
387    out.append(1,*i);
388  }
389  str=out;
390}
391
392
393bool IpToU32(const string &str, uint32_t *ip)
394{
395  if(str.empty()) {
396    *ip=0;
397    return true;
398  }
399 
400  struct in_addr inp;
401  if(Utility::inet_aton(str.c_str(), &inp)) {
402    *ip=inp.s_addr;
403    return true;
404  }
405  return false;
406}
407
408string U32ToIP(uint32_t val)
409{
410  char tmp[17];
411  snprintf(tmp, sizeof(tmp)-1, "%u.%u.%u.%u", 
412           (val >> 24)&0xff,
413           (val >> 16)&0xff,
414           (val >>  8)&0xff,
415           (val      )&0xff);
416  return tmp;
417}
418
419
420const string sockAddrToString(struct sockaddr_in *remote) 
421{   
422  if(remote->sin_family == AF_INET) {
423    struct sockaddr_in sip;
424    memcpy(&sip,(struct sockaddr_in*)remote,sizeof(sip));
425    return inet_ntoa(sip.sin_addr);
426  }
427  else {
428    char tmp[128];
429   
430    if(!Utility::inet_ntop(AF_INET6, ( const char * ) &((struct sockaddr_in6 *)remote)->sin6_addr, tmp, sizeof(tmp)))
431      return "IPv6 untranslateable";
432
433    return tmp;
434  }
435}
436
437string makeHexDump(const string& str)
438{
439  char tmp[5];
440  string ret;
441  ret.reserve((int)(str.size()*2.2));
442
443  for(string::size_type n=0;n<str.size();++n) {
444    sprintf(tmp,"%02x ", (unsigned char)str[n]);
445    ret+=tmp;
446  }
447  return ret;
448}
449
450
451
452// shuffle, maintaining some semblance of order
453void shuffle(vector<DNSResourceRecord>& rrs)
454{
455  vector<DNSResourceRecord>::iterator first, second;
456  for(first=rrs.begin();first!=rrs.end();++first) 
457    if(first->d_place==DNSResourceRecord::ANSWER && first->qtype.getCode() != QType::CNAME) // CNAME must come first
458      break;
459  for(second=first;second!=rrs.end();++second)
460    if(second->d_place!=DNSResourceRecord::ANSWER)
461      break;
462 
463  if(second-first>1)
464    random_shuffle(first,second);
465 
466  // now shuffle the additional records
467  for(first=second;first!=rrs.end();++first) 
468    if(first->d_place==DNSResourceRecord::ADDITIONAL && first->qtype.getCode() != QType::CNAME) // CNAME must come first
469      break;
470  for(second=first;second!=rrs.end();++second)
471    if(second->d_place!=DNSResourceRecord::ADDITIONAL)
472      break;
473 
474  if(second-first>1)
475    random_shuffle(first,second);
476
477  // we don't shuffle the rest
478}
479
480
481void normalizeTV(struct timeval& tv)
482{
483  if(tv.tv_usec > 1000000) {
484    ++tv.tv_sec;
485    tv.tv_usec-=1000000;
486  }
487  else if(tv.tv_usec < 0) {
488    --tv.tv_sec;
489    tv.tv_usec+=1000000;
490  }
491}
492
493const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs)
494{
495  struct timeval ret;
496  ret.tv_sec=lhs.tv_sec + rhs.tv_sec;
497  ret.tv_usec=lhs.tv_usec + rhs.tv_usec;
498  normalizeTV(ret);
499  return ret;
500}
501
502const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
503{
504  struct timeval ret;
505  ret.tv_sec=lhs.tv_sec - rhs.tv_sec;
506  ret.tv_usec=lhs.tv_usec - rhs.tv_usec;
507  normalizeTV(ret);
508  return ret;
509}
510
511pair<string, string> splitField(const string& inp, char sepa)
512{
513  pair<string, string> ret;
514  string::size_type cpos=inp.find(sepa);
515  if(cpos==string::npos)
516    ret.first=inp;
517  else {
518    ret.first=inp.substr(0, cpos);
519    ret.second=inp.substr(cpos+1);
520  }
521  return ret;
522}
Note: See TracBrowser for help on using the browser.