root/trunk/pdns/pdns/pdns_recursor.cc @ 330

Revision 330, 18.8 KB (checked in by ahu, 8 years ago)

ancient patch by Bram Vandoren implementing setuid, setgid and chroot in pdns_recursor

  • 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) 2005  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    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17*/
18
19#include "utility.hh"
20#include <iostream>
21#include <errno.h>
22#include <map>
23#include <set>
24#ifndef WIN32
25#include <netdb.h>
26#endif // WIN32
27#include <stdio.h>
28#include <signal.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include "mtasker.hh"
32#include <utility>
33#include "dnspacket.hh"
34#include "statbag.hh"
35#include "arguments.hh"
36#include "syncres.hh"
37#include <fcntl.h>
38#include <fstream>
39#include "recursor_cache.hh"
40
41#ifdef __FreeBSD__           // see cvstrac ticket #26
42#include <pthread.h>
43#include <semaphore.h>
44#endif
45
46MemRecursorCache RC;
47
48string s_programname="pdns_recursor";
49
50#ifndef WIN32
51#ifndef __FreeBSD__
52extern "C" {
53  int sem_init(sem_t*, int, unsigned int){return 0;}
54  int sem_wait(sem_t*){return 0;}
55  int sem_trywait(sem_t*){return 0;}
56  int sem_post(sem_t*){return 0;}
57  int sem_getvalue(sem_t*, int*){return 0;}
58  pthread_t pthread_self(void){return (pthread_t) 0;}
59  int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr){ return 0; }
60  int pthread_mutex_lock(pthread_mutex_t *mutex){ return 0; }
61  int pthread_mutex_unlock(pthread_mutex_t *mutex) { return 0; }
62
63}
64#endif // __FreeBSD__
65#endif // WIN32
66
67StatBag S;
68ArgvMap &arg()
69{
70  static ArgvMap theArg;
71  return theArg;
72}
73static int d_clientsock;
74static vector<int> d_udpserversocks;
75static vector<int> d_tcpserversocks;
76
77struct PacketID
78{
79  u_int16_t id;
80  struct sockaddr_in remote;
81};
82
83bool operator<(const PacketID& a, const PacketID& b)
84{
85  if(a.id<b.id)
86    return true;
87
88  if(a.id==b.id) {
89    if(a.remote.sin_addr.s_addr < b.remote.sin_addr.s_addr)
90      return true;
91    if(a.remote.sin_addr.s_addr == b.remote.sin_addr.s_addr)
92      if(a.remote.sin_port < b.remote.sin_port)
93        return true;
94  }
95
96  return false;
97}
98
99MTasker<PacketID,string>* MT;
100
101/* these two functions are used by LWRes */
102int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id) 
103{
104  return sendto(d_clientsock, data, len, flags, toaddr, addrlen);
105}
106
107int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id)
108{
109  PacketID pident;
110  pident.id=id;
111  memcpy(&pident.remote,toaddr,sizeof(pident.remote));
112
113  string packet;
114  if(!MT->waitEvent(pident,&packet,1)) { // timeout
115    return 0; 
116  }
117
118  *d_len=packet.size();
119  memcpy(data,packet.c_str(),min(len,*d_len));
120
121  return 1;
122}
123
124
125static void writePid(void)
126{
127  string fname=arg()["socket-dir"]+"/"+s_programname+".pid";
128  ofstream of(fname.c_str());
129  if(of)
130    of<<getpid()<<endl;
131  else
132    L<<Logger::Error<<"Requested to write pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
133}
134
135void primeHints(void)
136{
137  // prime root cache
138
139  static char*ips[]={"198.41.0.4", "192.228.79.201", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53", 
140                     "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
141  DNSResourceRecord arr, nsrr;
142  arr.qtype=QType::A;
143  arr.ttl=time(0)+3600000;
144  nsrr.qtype=QType::NS;
145  nsrr.ttl=time(0)+3600000;
146 
147  set<DNSResourceRecord>nsset;
148  for(char c='a';c<='m';++c) {
149    static char templ[40];
150    strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
151    *templ=c;
152    arr.qname=nsrr.content=templ;
153    arr.content=ips[c-'a'];
154    set<DNSResourceRecord>aset;
155    aset.insert(arr);
156    RC.replace(string(templ),QType(QType::A),aset);
157
158    nsset.insert(nsrr);
159  }
160  RC.replace("",QType(QType::NS),nsset);
161}
162
163void startDoResolve(void *p)
164{
165  try {
166    bool quiet=arg().mustDo("quiet");
167    DNSPacket P=*(DNSPacket *)p;
168
169    delete (DNSPacket *)p;
170
171    vector<DNSResourceRecord>ret;
172    DNSPacket *R=P.replyPacket();
173    R->setA(false);
174    R->setRA(true);
175
176    SyncRes sr;
177    if(!quiet)
178      L<<Logger::Error<<"["<<MT->getTid()<<"] question for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl;
179
180    sr.setId(MT->getTid());
181    if(!P.d.rd)
182      sr.setCacheOnly();
183
184    int res=sr.beginResolve(P.qdomain, P.qtype, ret);
185    if(res<0)
186      R->setRcode(RCode::ServFail);
187    else {
188      R->setRcode(res);
189      for(vector<DNSResourceRecord>::const_iterator i=ret.begin();i!=ret.end();++i)
190        R->addRecord(*i);
191    }
192
193    const char *buffer=R->getData();
194
195    if(!R->d_tcp)
196      sendto(R->getSocket(),buffer,R->len,0,(struct sockaddr *)(R->remote),R->d_socklen);
197    else {
198      char buf[2];
199      buf[0]=R->len/256;
200      buf[1]=R->len%256;
201      if(write(R->getSocket(),buf,2)!=2 || write(R->getSocket(),buffer,R->len)!=R->len)
202        L<<Logger::Error<<"Oops, partial answer sent to "<<P.getRemote()<<" - probably would have trouble receiving our answer anyhow (size="<<R->len<<")"<<endl;
203    }
204
205    if(!quiet) {
206      L<<Logger::Error<<"["<<MT->getTid()<<"] answer to "<<(P.d.rd?"":"non-rd ")<<"question '"<<P.qdomain<<"|"<<P.qtype.getName();
207      L<<"': "<<ntohs(R->d.ancount)<<" answers, "<<ntohs(R->d.arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
208        sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, rcode="<<res<<endl;
209    }
210   
211    sr.d_outqueries ? RC.cacheMisses++ : RC.cacheHits++; 
212
213    delete R;
214  }
215  catch(AhuException &ae) {
216    L<<Logger::Error<<"startDoResolve problem: "<<ae.reason<<endl;
217  }
218  catch(...) {
219    L<<Logger::Error<<"Any other exception in a resolver context"<<endl;
220  }
221}
222
223void makeClientSocket()
224{
225  d_clientsock=socket(AF_INET, SOCK_DGRAM,0);
226  if(d_clientsock<0) 
227    throw AhuException("Making a socket for resolver: "+stringerror());
228 
229  struct sockaddr_in sin;
230  memset((char *)&sin,0, sizeof(sin));
231 
232  sin.sin_family = AF_INET;
233  sin.sin_addr.s_addr = INADDR_ANY;
234 
235  int tries=10;
236  while(--tries) {
237    u_int16_t port=10000+Utility::random()%10000;
238    sin.sin_port = htons(port); 
239   
240    if (bind(d_clientsock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 
241      break;
242   
243  }
244  if(!tries)
245    throw AhuException("Resolver binding to local socket: "+stringerror());
246
247  Utility::setNonBlocking(d_clientsock);
248}
249
250void makeTCPServerSockets()
251{
252  vector<string>locals;
253  stringtok(locals,arg()["local-address"]," ,");
254
255  if(locals.empty())
256    throw AhuException("No local address specified");
257 
258  if(arg()["local-address"]=="0.0.0.0") {
259    L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
260  }
261
262  for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
263    int fd=socket(AF_INET, SOCK_STREAM,0);
264    if(fd<0) 
265      throw AhuException("Making a server socket for resolver: "+stringerror());
266 
267    struct sockaddr_in sin;
268    memset((char *)&sin,0, sizeof(sin));
269   
270    sin.sin_family = AF_INET;
271    if(!IpToU32(*i, &sin.sin_addr.s_addr))
272      throw AhuException("Unable to resolve local address '"+ *i +"'"); 
273
274    int tmp=1;
275    if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
276      L<<Logger::Error<<"Setsockopt failed for TCP listening socket"<<endl;
277      exit(1); 
278    }
279   
280    sin.sin_port = htons(arg().asNum("local-port")); 
281   
282    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))<0) 
283      throw AhuException("Binding TCP server socket for "+*i+": "+stringerror());
284   
285    Utility::setNonBlocking(fd);
286    listen(fd, 128);
287    d_tcpserversocks.push_back(fd);
288    L<<Logger::Error<<"Listening for TCP queries on "<<inet_ntoa(sin.sin_addr)<<":"<<arg().asNum("local-port")<<endl;
289  }
290}
291
292
293void makeUDPServerSockets()
294{
295  vector<string>locals;
296  stringtok(locals,arg()["local-address"]," ,");
297
298  if(locals.empty())
299    throw AhuException("No local address specified");
300 
301  if(arg()["local-address"]=="0.0.0.0") {
302    L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
303  }
304
305  for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
306    int fd=socket(AF_INET, SOCK_DGRAM,0);
307    if(fd<0) 
308      throw AhuException("Making a server socket for resolver: "+stringerror());
309 
310    struct sockaddr_in sin;
311    memset((char *)&sin,0, sizeof(sin));
312   
313    sin.sin_family = AF_INET;
314    if(!IpToU32(*i, &sin.sin_addr.s_addr))
315      throw AhuException("Unable to resolve local address '"+ *i +"'"); 
316   
317    sin.sin_port = htons(arg().asNum("local-port")); 
318   
319    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))<0) 
320      throw AhuException("Resolver binding to server socket for "+*i+": "+stringerror());
321   
322    Utility::setNonBlocking(fd);
323    d_udpserversocks.push_back(fd);
324    L<<Logger::Error<<"Listening for UDP queries on "<<inet_ntoa(sin.sin_addr)<<":"<<arg().asNum("local-port")<<endl;
325  }
326}
327
328
329#ifndef WIN32
330void daemonize(void)
331{
332  if(fork())
333    exit(0); // bye bye
334 
335  setsid(); 
336
337  // cleanup open fds, but skip sockets
338  close(0);
339  close(1);
340  close(2);
341
342}
343#endif
344
345int counter, qcounter;
346bool statsWanted;
347
348void usr1Handler(int)
349{
350  statsWanted=true;
351}
352
353
354void doStats(void)
355{
356  if(qcounter) {
357    L<<Logger::Error<<"stats: "<<qcounter<<" questions, "<<RC.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, "
358     <<(int)((RC.cacheHits*100.0)/(RC.cacheHits+RC.cacheMisses))<<"% cache hits";
359    L<<Logger::Error<<", outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
360    L<<Logger::Error<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
361     <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
362    L<<Logger::Error<<"queries running: "<<MT->numProcesses()<<endl;
363  }
364  statsWanted=false;
365}
366
367void houseKeeping(void *)
368{
369  static time_t last_stat, last_rootupdate, last_prune;
370  time_t now=time(0);
371  if(now - last_stat>60) { 
372    RC.doPrune();
373    last_prune=time(0);
374  }
375  if(now - last_stat>1800) { 
376    doStats();
377    last_stat=time(0);
378  }
379  if(now -last_rootupdate>7200) {
380    SyncRes sr;
381    vector<DNSResourceRecord>ret;
382
383    sr.setNoCache();
384    int res=sr.beginResolve("", QType(QType::NS), ret);
385    if(!res) {
386      L<<Logger::Error<<"Refreshed . records"<<endl;
387      last_rootupdate=now;
388    }
389    else
390      L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
391  }
392}
393
394struct TCPConnection
395{
396  int fd;
397  enum {BYTE0, BYTE1, GETQUESTION} state;
398  int qlen;
399  int bytesread;
400  struct sockaddr_in remote;
401  char data[65535];
402};
403
404int main(int argc, char **argv) 
405{
406#ifdef WIN32
407    WSADATA wsaData;
408    WSAStartup( MAKEWORD( 2, 0 ), &wsaData );
409#endif // WIN32
410
411  try {
412    Utility::srandom(time(0));
413    arg().set("soa-minimum-ttl","Don't change")="0";
414    arg().set("soa-serial-offset","Don't change")="0";
415    arg().set("no-shuffle","Don't change")="off";
416    arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
417    arg().set("local-port","port to listen on")="53";
418    arg().set("local-address","single address to listen on")="0.0.0.0";
419    arg().set("trace","if we should output heaps of logging")="off";
420    arg().set("daemon","Operate as a daemon")="yes";
421    arg().set("chroot","switch to chroot jail")="";
422    arg().set("setgid","If set, change group id to this gid for more security")="";
423    arg().set("setuid","If set, change user id to this uid for more security")="";
424    arg().set("quiet","Suppress logging of questions and answers")="off";
425    arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
426    arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
427    arg().set("delegation-only","Which domains we only accept delegations from")="";
428    arg().setCmd("help","Provide a helpful message");
429    L.toConsole(Logger::Warning);
430    arg().laxParse(argc,argv); // do a lax parse
431
432    string configname=arg()["config-dir"]+"/recursor.conf";
433    cleanSlashes(configname);
434
435    if(!arg().file(configname.c_str())) 
436      L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
437
438    arg().parse(argc,argv);
439
440    arg().set("delegation-only")=toLower(arg()["delegation-only"]);
441
442    if(arg().mustDo("help")) {
443      cerr<<"syntax:"<<endl<<endl;
444      cerr<<arg().helpstring(arg()["help"])<<endl;
445      exit(99);
446    }
447
448    L.setName("pdns_recursor");
449
450    if(arg().mustDo("trace"))
451      SyncRes::setLog(true);
452   
453    makeClientSocket();
454    makeUDPServerSockets();
455    makeTCPServerSockets();
456       
457    MT=new MTasker<PacketID,string>(100000);
458
459    char data[1500];
460    struct sockaddr_in fromaddr;
461   
462    PacketID pident;
463    primeHints();   
464    L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
465#ifndef WIN32
466    if(arg().mustDo("daemon")) {
467      L.toConsole(Logger::Critical);
468      daemonize();
469    }
470    signal(SIGUSR1,usr1Handler);
471
472    writePid();
473#endif
474
475    int newgid=0;
476    if(!arg()["setgid"].empty())
477      newgid=Utility::makeGidNumeric(arg()["setgid"]);
478    int newuid=0;
479    if(!arg()["setuid"].empty())
480      newuid=Utility::makeUidNumeric(arg()["setuid"]);
481
482
483    if (!arg()["chroot"].empty()) {
484        if (chroot(arg()["chroot"].c_str())<0) {
485            L<<Logger::Error<<"Unable to chroot to '"+arg()["chroot"]+"': "<<strerror (errno)<<", exiting"<<endl;
486            exit(1);
487        }
488    }
489
490    Utility::dropPrivs(newuid, newgid);
491
492    vector<TCPConnection> tcpconnections;
493    counter=0;
494    for(;;) {
495      while(MT->schedule()); // housekeeping, let threads do their thing
496     
497      if(!((counter++)%100)) 
498        MT->makeThread(houseKeeping,0);
499      if(statsWanted)
500        doStats();
501
502      Utility::socklen_t addrlen=sizeof(fromaddr);
503      int d_len;
504      DNSPacket P;
505     
506      struct timeval tv;
507      tv.tv_sec=0;
508      tv.tv_usec=500000;
509     
510      fd_set readfds;
511      FD_ZERO( &readfds );
512      FD_SET( d_clientsock, &readfds );
513      int fdmax=d_clientsock;
514
515      for(vector<TCPConnection>::const_iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) {
516        FD_SET(i->fd, &readfds);
517        fdmax=max(fdmax,i->fd);
518      }
519      for(vector<int>::const_iterator i=d_udpserversocks.begin(); i!=d_udpserversocks.end(); ++i) {
520        FD_SET( *i, &readfds );
521        fdmax=max(fdmax,*i);
522      }
523      for(vector<int>::const_iterator i=d_tcpserversocks.begin(); i!=d_tcpserversocks.end(); ++i) {
524        FD_SET( *i, &readfds );
525        fdmax=max(fdmax,*i);
526      }
527
528      int selret = select(  fdmax + 1, &readfds, NULL, NULL, &tv );
529      if(selret<=0) 
530        if (selret == -1 && errno!=EINTR) 
531          throw AhuException("Select returned: "+stringerror());
532        else
533          continue;
534
535      if(FD_ISSET(d_clientsock,&readfds)) { // do we have a question response?
536        d_len=recvfrom(d_clientsock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);   
537        if(d_len<0) 
538          continue;
539       
540        P.setRemote((struct sockaddr *)&fromaddr, addrlen);
541        if(P.parse(data,d_len)<0) {
542          L<<Logger::Error<<"Unparseable packet from remote server "<<P.getRemote()<<endl;
543        }
544        else { 
545          if(P.d.qr) {
546
547            pident.remote=fromaddr;
548            pident.id=P.d.id;
549            string packet;
550            packet.assign(data,d_len);
551            MT->sendEvent(pident,&packet);
552          }
553          else 
554            L<<Logger::Warning<<"Ignoring question on outgoing socket from "<<P.getRemote()<<endl;
555        }
556      }
557     
558
559      for(vector<int>::const_iterator i=d_udpserversocks.begin(); i!=d_udpserversocks.end(); ++i) {
560        if(FD_ISSET(*i,&readfds)) { // do we have a new question on udp?
561          d_len=recvfrom(*i, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);   
562          if(d_len<0) 
563            continue;
564          P.setRemote((struct sockaddr *)&fromaddr, addrlen);
565          if(P.parse(data,d_len)<0) {
566            L<<Logger::Error<<"Unparseable packet from remote client "<<P.getRemote()<<endl;
567          }
568          else { 
569            if(P.d.qr)
570              L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
571            else {
572              ++qcounter;
573              P.setSocket(*i);
574              P.d_tcp=false;
575              MT->makeThread(startDoResolve,(void*)new DNSPacket(P));
576            }
577          }
578        }
579      }
580
581      for(vector<int>::const_iterator i=d_tcpserversocks.begin(); i!=d_tcpserversocks.end(); ++i) { 
582        if(FD_ISSET(*i ,&readfds)) { // do we have a new TCP connection
583          struct sockaddr_in addr;
584          socklen_t addrlen=sizeof(addr);
585          int newsock=accept(*i, (struct sockaddr*)&addr, &addrlen);
586         
587          if(newsock>0) {
588            Utility::setNonBlocking(newsock);
589            TCPConnection tc;
590            tc.fd=newsock;
591            tc.state=TCPConnection::BYTE0;
592            tc.remote=addr;
593            tcpconnections.push_back(tc);
594          }
595        }
596      }
597
598      for(vector<TCPConnection>::iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) {
599        if(FD_ISSET(i->fd, &readfds)) {
600          if(i->state==TCPConnection::BYTE0) {
601            int bytes=read(i->fd,i->data,2);
602            if(bytes==1)
603              i->state=TCPConnection::BYTE1;
604            if(bytes==2) { 
605              i->qlen=(i->data[0]<<8)+i->data[1];
606              i->bytesread=0;
607              i->state=TCPConnection::GETQUESTION;
608            }
609            if(!bytes || bytes < 0) {
610              close(i->fd);
611              tcpconnections.erase(i);
612              break;
613            }
614          }
615          else if(i->state==TCPConnection::BYTE1) {
616            int bytes=read(i->fd,i->data+1,1);
617            if(bytes==1) {
618              i->state=TCPConnection::GETQUESTION;
619              i->qlen=(i->data[0]<<8)+i->data[1];
620              i->bytesread=0;
621            }
622            if(!bytes || bytes < 0) {
623              L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected after first byte"<<endl;
624              close(i->fd);
625              tcpconnections.erase(i);
626              break;
627            }
628           
629          }
630          else if(i->state==TCPConnection::GETQUESTION) {
631            int bytes=read(i->fd,i->data + i->bytesread,i->qlen - i->bytesread);
632            if(!bytes || bytes < 0) {
633              L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected while reading question body"<<endl;
634              close(i->fd);
635              tcpconnections.erase(i);
636              break;
637            }
638            i->bytesread+=bytes;
639            if(i->bytesread==i->qlen) {
640              i->state=TCPConnection::BYTE0;
641
642              if(P.parse(i->data,i->qlen)<0) {
643                L<<Logger::Error<<"Unparseable packet from remote client "<<P.getRemote()<<endl;
644                close(i->fd);
645                tcpconnections.erase(i);
646                break;
647              }
648              else { 
649                P.setSocket(i->fd);
650                P.d_tcp=true;
651                P.setRemote((struct sockaddr *)&i->remote,sizeof(i->remote));
652                if(P.d.qr)
653                  L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
654                else {
655                  ++qcounter;
656                  MT->makeThread(startDoResolve,(void*)new DNSPacket(P));
657                }
658              }
659            }
660          }
661        }
662      }
663    }
664  }
665  catch(AhuException &ae) {
666    L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
667  }
668  catch(exception &e) {
669    L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
670  }
671  catch(...) {
672    L<<Logger::Error<<"any other exception in main: "<<endl;
673  }
674 
675#ifdef WIN32
676  WSACleanup();
677#endif // WIN32
678
679  return 0;
680}
Note: See TracBrowser for help on using the browser.