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

Revision 518, 27.7 KB (checked in by ahu, 8 years ago)

make ./configure fail if Boost is not installed, and give out helpful tip
add code to send out root referrals for unauth domains

and documentation --send-root-referral

remove some bogus errors on EINTR (there is a remaining bug out there)
prepare MOADNSParser for record types for which only the name is known, and no maker functions
expand and improve EDNS0 parsing code
templatize optString
fix qtype name reporting in pdns_recorsor (regressed during move to MOADNSParser)
make sure outgoing queries are randomised again (regressed etc)
complete AAAA support in MOADNSParser/generator stuff

  • 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) 2003 - 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 "sstuff.hh"
40#include <boost/tuple/tuple.hpp>
41#include <boost/tuple/tuple_comparison.hpp>
42#include <boost/shared_array.hpp>
43#include <boost/lexical_cast.hpp>
44#include "dnsparser.hh"
45#include "dnswriter.hh"
46#include "dnsrecords.hh"
47using namespace boost;
48
49#include "recursor_cache.hh"
50
51#ifdef __FreeBSD__           // see cvstrac ticket #26
52#include <pthread.h>
53#include <semaphore.h>
54#endif
55
56MemRecursorCache RC;
57
58string s_programname="pdns_recursor";
59
60struct DNSComboWriter {
61  DNSComboWriter(const char* data, uint16_t len) : d_mdp(data, len), d_tcp(false), d_socket(-1)
62  {}
63  MOADNSParser d_mdp;
64  void setRemote(struct sockaddr* sa, socklen_t len)
65  {
66    memcpy((void *)d_remote, (void *)sa, len);
67    d_socklen=len;
68  }
69
70  void setSocket(int sock)
71  {
72    d_socket=sock;
73  }
74
75  string getRemote() const
76  {
77    return sockAddrToString((struct sockaddr_in *)d_remote, d_socklen);
78  }
79
80
81  char d_remote[sizeof(sockaddr_in6)];
82  socklen_t d_socklen;
83  bool d_tcp;
84  int d_socket;
85};
86
87
88#if 0
89#ifndef WIN32
90#ifndef __FreeBSD__
91extern "C" {
92  int sem_init(sem_t*, int, unsigned int){return 0;}
93  int sem_wait(sem_t*){return 0;}
94  int sem_trywait(sem_t*){return 0;}
95  int sem_post(sem_t*){return 0;}
96  int sem_getvalue(sem_t*, int*){return 0;}
97  pthread_t pthread_self(void){return (pthread_t) 0;}
98  int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr){ return 0; }
99  int pthread_mutex_lock(pthread_mutex_t *mutex){ return 0; }
100  int pthread_mutex_unlock(pthread_mutex_t *mutex) { return 0; }
101  int pthread_mutex_destroy(pthread_mutex_t *mutex) { return 0; }
102}
103#endif // __FreeBSD__
104#endif // WIN32
105#endif
106
107StatBag S;
108ArgvMap &arg()
109{
110  static ArgvMap theArg;
111  return theArg;
112}
113static int d_clientsock;
114static vector<int> d_udpserversocks;
115
116typedef vector<int> tcpserversocks_t;
117static tcpserversocks_t s_tcpserversocks;
118
119struct PacketID
120{
121  PacketID() : sock(0), inNeeded(0), outPos(0)
122  {}
123
124  uint16_t id;  // wait for a specific id/remote paie
125  struct sockaddr_in remote;  // this is the remote
126
127  Socket* sock;  // or wait for an event on a TCP fd
128  int inNeeded; // if this is set, we'll read until inNeeded bytes are read
129  string inMSG; // they'll go here
130
131  string outMSG; // the outgoing message that needs to be sent
132  int outPos;    // how far we are along in the outMSG
133
134  bool operator<(const PacketID& b) const
135  {
136    int ourSock= sock ? sock->getHandle() : 0;
137    int bSock = b.sock ? b.sock->getHandle() : 0;
138    return 
139      tie(id, remote.sin_addr.s_addr, remote.sin_port, ourSock) <
140      tie(b.id, b.remote.sin_addr.s_addr, b.remote.sin_port, bSock);
141  }
142};
143
144static map<int,PacketID> d_tcpclientreadsocks, d_tcpclientwritesocks;
145
146MTasker<PacketID,string>* MT;
147
148int asendtcp(const string& data, Socket* sock) 
149{
150  PacketID pident;
151  pident.sock=sock;
152  pident.outMSG=data;
153  string packet;
154
155  //  cerr<<"asendtcp called for "<<data.size()<<" bytes"<<endl;
156  d_tcpclientwritesocks[sock->getHandle()]=pident;
157
158  int ret=MT->waitEvent(pident,&packet,1);
159  if(!ret || ret==-1) { // timeout
160    d_tcpclientwritesocks.erase(sock->getHandle());
161  }
162  return ret;
163}
164
165// -1 is error, 0 is timeout, 1 is success
166int arecvtcp(string& data, int len, Socket* sock) 
167{
168  data="";
169  PacketID pident;
170  pident.sock=sock;
171  pident.inNeeded=len;
172
173  // cerr<<"arecvtcp called for "<<len<<" bytes"<<endl;
174  // cerr<<d_tcpclientwritesocks.size()<<" write sockets"<<endl;
175  d_tcpclientreadsocks[sock->getHandle()]=pident;
176
177  int ret=MT->waitEvent(pident,&data,1);
178  if(!ret || ret==-1) { // timeout
179    d_tcpclientreadsocks.erase(sock->getHandle());
180  }
181  return ret;
182}
183
184
185/* these two functions are used by LWRes */
186// -1 is error, > 1 is success
187int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id) 
188{
189  return sendto(d_clientsock, data, len, flags, toaddr, addrlen);
190}
191
192// -1 is error, 0 is timeout, 1 is success
193int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id)
194{
195  PacketID pident;
196  pident.id=id;
197  memcpy(&pident.remote,toaddr,sizeof(pident.remote));
198
199  string packet;
200  int ret=MT->waitEvent(pident,&packet,1);
201  if(ret > 0) {
202    *d_len=packet.size();
203    memcpy(data,packet.c_str(),min(len,*d_len));
204  }
205
206  return ret;
207}
208
209
210static void writePid(void)
211{
212  string fname=arg()["socket-dir"]+"/"+s_programname+".pid";
213  ofstream of(fname.c_str());
214  if(of)
215    of<<getpid()<<endl;
216  else
217    L<<Logger::Error<<"Requested to write pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
218}
219
220void primeHints(void)
221{
222  // prime root cache
223
224  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", 
225                     "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
226  DNSResourceRecord arr, nsrr;
227  arr.qtype=QType::A;
228  arr.ttl=time(0)+3600000;
229  nsrr.qtype=QType::NS;
230  nsrr.ttl=time(0)+3600000;
231 
232  set<DNSResourceRecord>nsset;
233  for(char c='a';c<='m';++c) {
234    static char templ[40];
235    strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
236    *templ=c;
237    arr.qname=nsrr.content=templ;
238    arr.content=ips[c-'a'];
239    set<DNSResourceRecord> aset;
240    aset.insert(arr);
241    RC.replace(string(templ), QType(QType::A), aset);
242
243    nsset.insert(nsrr);
244  }
245  RC.replace("",QType(QType::NS),nsset); // and stuff in the cache
246}
247
248void startDoResolve(void *p)
249{
250  try {
251    bool quiet=arg().mustDo("quiet");
252    DNSComboWriter* dc=(DNSComboWriter *)p;
253
254    uint16_t maxudpsize=512;
255    MOADNSParser::EDNSOpts edo;
256    if(dc->d_mdp.getEDNSOpts(&edo)) {
257      maxudpsize=edo.d_packetsize;
258    }
259
260    vector<DNSResourceRecord> ret;
261   
262    vector<uint8_t> packet;
263    DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
264
265    pw.getHeader()->aa=0;
266    pw.getHeader()->ra=1;
267    pw.getHeader()->qr=1;
268    pw.getHeader()->id=dc->d_mdp.d_header.id;
269    pw.getHeader()->rd=dc->d_mdp.d_header.rd;
270
271    //    MT->setTitle("udp question for "+P.qdomain+"|"+P.qtype.getName());
272    SyncRes sr;
273    if(!quiet)
274      L<<Logger::Error<<"["<<MT->getTid()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
275       <<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote()<<endl;
276
277    sr.setId(MT->getTid());
278    if(!dc->d_mdp.d_header.rd)
279      sr.setCacheOnly();
280
281    int res=sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret);
282    if(res<0)
283      pw.getHeader()->rcode=RCode::ServFail;
284    else {
285      pw.getHeader()->rcode=res;
286      if(ret.size()) {
287        for(vector<DNSResourceRecord>::const_iterator i=ret.begin();i!=ret.end();++i) {
288          pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, 1, (DNSPacketWriter::Place)i->d_place);
289          shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(i->qtype.getCode(), 1, i->content)); 
290          drc->toPacket(pw);
291          if(!dc->d_tcp && pw.size() > maxudpsize) {
292            pw.rollback();
293            pw.getHeader()->tc=1;
294            goto sendit; // need to jump over pw.commit
295          }
296        }
297        pw.commit();
298      }
299    }
300  sendit:;
301    if(!dc->d_tcp) {
302      sendto(dc->d_socket, &*packet.begin(), packet.size(), 0, (struct sockaddr *)(dc->d_remote), dc->d_socklen);
303    }
304    else {
305      char buf[2];
306      buf[0]=packet.size()/256;
307      buf[1]=packet.size()%256;
308
309      struct iovec iov[2];
310
311      iov[0].iov_base=(void*)buf;              iov[0].iov_len=2;
312      iov[1].iov_base=(void*)&*packet.begin(); iov[1].iov_len = packet.size();
313
314      int ret=writev(dc->d_socket, iov, 2);
315
316      if(ret <= 0 ) 
317        L<<Logger::Error<<"Error writing TCP answer to "<<dc->getRemote()<<": "<< (ret ? strerror(errno) : "EOF") <<endl;
318      else if((unsigned int)ret != 2 + packet.size())
319        L<<Logger::Error<<"Oops, partial answer sent to "<<dc->getRemote()<<" - probably would have trouble receiving our answer anyhow (size="<<packet.size()<<")"<<endl;
320
321      //      if(write(R->getSocket(),buf,2)!=2 || write(R->getSocket(),buffer,R->len)!=R->len)
322      //  XXX FIXME write this writev fallback otherwise
323    }
324
325    //    MT->setTitle("DONE! udp question for "+P.qdomain+"|"+P.qtype.getName());
326    if(!quiet) {
327      L<<Logger::Error<<"["<<MT->getTid()<<"] answer to "<<(dc->d_mdp.d_header.rd?"":"non-rd ")<<"question '"<<dc->d_mdp.d_qname<<"|"<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype);
328      L<<"': "<<ntohs(pw.getHeader()->ancount)<<" answers, "<<ntohs(pw.getHeader()->arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
329        sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<<res<<endl;
330    }
331   
332    sr.d_outqueries ? RC.cacheMisses++ : RC.cacheHits++; 
333    delete dc;
334  }
335  catch(AhuException &ae) {
336    L<<Logger::Error<<"startDoResolve problem: "<<ae.reason<<endl;
337  }
338  catch(exception& e) {
339    L<<Logger::Error<<"STL error: "<<e.what()<<endl;
340  }
341  catch(...) {
342    L<<Logger::Error<<"Any other exception in a resolver context"<<endl;
343  }
344}
345
346void makeClientSocket()
347{
348  d_clientsock=socket(AF_INET, SOCK_DGRAM,0);
349  if(d_clientsock<0) 
350    throw AhuException("Making a socket for resolver: "+stringerror());
351 
352  struct sockaddr_in sin;
353  memset((char *)&sin,0, sizeof(sin));
354 
355  sin.sin_family = AF_INET;
356
357  if(!IpToU32(arg()["query-local-address"], &sin.sin_addr.s_addr))
358    throw AhuException("Unable to resolve local address '"+ arg()["query-local-address"] +"'"); 
359
360  int tries=10;
361  while(--tries) {
362    uint16_t port=10000+Utility::random()%10000;
363    sin.sin_port = htons(port); 
364   
365    if (bind(d_clientsock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 
366      break;
367   
368  }
369  if(!tries)
370    throw AhuException("Resolver binding to local socket: "+stringerror());
371
372  Utility::setNonBlocking(d_clientsock);
373  L<<Logger::Error<<"Sending UDP queries from "<<inet_ntoa(sin.sin_addr)<<":"<< ntohs(sin.sin_port)  <<endl;
374}
375
376void makeTCPServerSockets()
377{
378  vector<string>locals;
379  stringtok(locals,arg()["local-address"]," ,");
380
381  if(locals.empty())
382    throw AhuException("No local address specified");
383 
384  for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
385    int fd=socket(AF_INET, SOCK_STREAM,0);
386    if(fd<0) 
387      throw AhuException("Making a server socket for resolver: "+stringerror());
388 
389    struct sockaddr_in sin;
390    memset((char *)&sin,0, sizeof(sin));
391   
392    sin.sin_family = AF_INET;
393    if(!IpToU32(*i, &sin.sin_addr.s_addr))
394      throw AhuException("Unable to resolve local address '"+ *i +"'"); 
395
396    int tmp=1;
397    if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
398      L<<Logger::Error<<"Setsockopt failed for TCP listening socket"<<endl;
399      exit(1); 
400    }
401   
402    sin.sin_port = htons(arg().asNum("local-port")); 
403   
404    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))<0) 
405      throw AhuException("Binding TCP server socket for "+*i+": "+stringerror());
406   
407    Utility::setNonBlocking(fd);
408    listen(fd, 128);
409    s_tcpserversocks.push_back(fd);
410    L<<Logger::Error<<"Listening for TCP queries on "<<inet_ntoa(sin.sin_addr)<<":"<<arg().asNum("local-port")<<endl;
411  }
412}
413
414void makeUDPServerSockets()
415{
416  vector<string>locals;
417  stringtok(locals,arg()["local-address"]," ,");
418
419  if(locals.empty())
420    throw AhuException("No local address specified");
421 
422  if(arg()["local-address"]=="0.0.0.0") {
423    L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
424  }
425
426  for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
427    int fd=socket(AF_INET, SOCK_DGRAM,0);
428    if(fd<0) 
429      throw AhuException("Making a server socket for resolver: "+stringerror());
430 
431    struct sockaddr_in sin;
432    memset((char *)&sin,0, sizeof(sin));
433   
434    sin.sin_family = AF_INET;
435    if(!IpToU32(*i, &sin.sin_addr.s_addr))
436      throw AhuException("Unable to resolve local address '"+ *i +"'"); 
437   
438    sin.sin_port = htons(arg().asNum("local-port")); 
439   
440    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))<0) 
441      throw AhuException("Resolver binding to server socket for "+*i+": "+stringerror());
442   
443    Utility::setNonBlocking(fd);
444    d_udpserversocks.push_back(fd);
445    L<<Logger::Error<<"Listening for UDP queries on "<<inet_ntoa(sin.sin_addr)<<":"<<arg().asNum("local-port")<<endl;
446  }
447}
448
449
450#ifndef WIN32
451void daemonize(void)
452{
453  if(fork())
454    exit(0); // bye bye
455 
456  setsid(); 
457
458  // cleanup open fds, but skip sockets
459  close(0);
460  close(1);
461  close(2);
462}
463#endif
464
465int counter, qcounter;
466bool statsWanted;
467
468void usr1Handler(int)
469{
470  statsWanted=true;
471}
472
473void usr2Handler(int)
474{
475  SyncRes::setLog(true);
476}
477
478void doStats(void)
479{
480  if(qcounter) {
481    L<<Logger::Error<<"stats: "<<qcounter<<" questions, "<<RC.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, "
482     <<(int)((RC.cacheHits*100.0)/(RC.cacheHits+RC.cacheMisses))<<"% cache hits";
483    L<<Logger::Error<<", outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
484    L<<Logger::Error<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
485     <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
486    L<<Logger::Error<<"stats: "<<SyncRes::s_tcpoutqueries<<" outgoing tcp connections, "<<MT->numProcesses()<<" queries running, "<<SyncRes::s_outgoingtimeouts<<" outgoing timeouts"<<endl;
487  }
488  else if(statsWanted) 
489    L<<Logger::Error<<"stats: no stats yet!"<<endl;
490
491  statsWanted=false;
492}
493
494void houseKeeping(void *)
495{
496  static time_t last_stat, last_rootupdate, last_prune;
497  time_t now=time(0);
498  if(now - last_prune > 60) { 
499    RC.doPrune();
500    last_prune=time(0);
501  }
502  if(now - last_stat>1800) { 
503    doStats();
504    last_stat=time(0);
505  }
506  if(now -last_rootupdate>7200) {
507    SyncRes sr;
508    vector<DNSResourceRecord> ret;
509
510    sr.setNoCache();
511    int res=sr.beginResolve("", QType(QType::NS), ret);
512    if(!res) {
513      L<<Logger::Error<<"Refreshed . records"<<endl;
514      last_rootupdate=now;
515    }
516    else
517      L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
518  }
519}
520
521struct TCPConnection
522{
523  int fd;
524  enum {BYTE0, BYTE1, GETQUESTION} state;
525  int qlen;
526  int bytesread;
527  struct sockaddr_in remote;
528  char data[65535];
529  time_t startTime;
530};
531
532#if 0
533
534#include <execinfo.h>
535
536static void maketrace()
537{
538  void *array[20]; //only care about last 17 functions (3 taken with tracing support)
539  size_t size;
540  char **strings;
541  size_t i;
542
543  size = backtrace (array, 20);
544  strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
545
546  for (i = 0; i < size; i++) //skip useless functions
547    cout<<strings[i]<<"\n";
548  cout<<"--"<<endl;
549}
550
551extern "C" {
552int gettimeofday (struct timeval *__restrict __tv,
553                  __timezone_ptr_t __tz)
554{
555  maketrace();
556  return 0;
557}
558
559}
560#endif
561
562int main(int argc, char **argv) 
563{
564  reportBasicTypes();
565
566  int ret = EXIT_SUCCESS;
567#ifdef WIN32
568    WSADATA wsaData;
569    WSAStartup( MAKEWORD( 2, 0 ), &wsaData );
570#endif // WIN32
571
572  try {
573    Utility::srandom(time(0));
574    arg().set("soa-minimum-ttl","Don't change")="0";
575    arg().set("soa-serial-offset","Don't change")="0";
576    arg().set("no-shuffle","Don't change")="off";
577    arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
578    arg().set("local-port","port to listen on")="53";
579    arg().set("local-address","IP addresses to listen on, separated by spaces or commas")="0.0.0.0";
580    arg().set("trace","if we should output heaps of logging")="off";
581    arg().set("daemon","Operate as a daemon")="yes";
582    arg().set("chroot","switch to chroot jail")="";
583    arg().set("setgid","If set, change group id to this gid for more security")="";
584    arg().set("setuid","If set, change user id to this uid for more security")="";
585    arg().set("quiet","Suppress logging of questions and answers")="true";
586    arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
587    arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
588    arg().set("delegation-only","Which domains we only accept delegations from")="";
589    arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
590    arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
591    arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
592
593    arg().setCmd("help","Provide a helpful message");
594    L.toConsole(Logger::Warning);
595    arg().laxParse(argc,argv); // do a lax parse
596
597    string configname=arg()["config-dir"]+"/recursor.conf";
598    cleanSlashes(configname);
599
600    if(!arg().file(configname.c_str())) 
601      L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
602
603    arg().parse(argc,argv);
604
605    arg().set("delegation-only")=toLower(arg()["delegation-only"]);
606
607    if(arg().mustDo("help")) {
608      cerr<<"syntax:"<<endl<<endl;
609      cerr<<arg().helpstring(arg()["help"])<<endl;
610      exit(99);
611    }
612
613    L.setName("pdns_recursor");
614
615    L<<Logger::Warning<<"PowerDNS recursor "<<VERSION<<" (C) 2001-2005 PowerDNS.COM BV ("<<__DATE__", "__TIME__;
616#ifdef __GNUC__
617    L<<", gcc "__VERSION__;
618#endif // add other compilers here
619    L<<") starting up"<<endl;
620
621  L<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
622    "This is free software, and you are welcome to redistribute it "
623    "according to the terms of the GPL version 2."<<endl;
624
625
626  if(arg().mustDo("trace")) {
627      SyncRes::setLog(true);
628      arg().set("quiet")="no";
629     
630  }
631   
632    makeClientSocket();
633    makeUDPServerSockets();
634    makeTCPServerSockets();
635       
636    MT=new MTasker<PacketID,string>(100000);
637
638    char data[1500];
639    struct sockaddr_in fromaddr;
640   
641    PacketID pident;
642    primeHints();   
643    L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
644#ifndef WIN32
645    if(arg().mustDo("daemon")) {
646      L.toConsole(Logger::Critical);
647      daemonize();
648    }
649    signal(SIGUSR1,usr1Handler);
650    signal(SIGUSR2,usr2Handler);
651    signal(SIGPIPE,SIG_IGN);
652
653    writePid();
654#endif
655
656    int newgid=0;
657    if(!arg()["setgid"].empty())
658      newgid=Utility::makeGidNumeric(arg()["setgid"]);
659    int newuid=0;
660    if(!arg()["setuid"].empty())
661      newuid=Utility::makeUidNumeric(arg()["setuid"]);
662
663
664    if (!arg()["chroot"].empty()) {
665        if (chroot(arg()["chroot"].c_str())<0) {
666            L<<Logger::Error<<"Unable to chroot to '"+arg()["chroot"]+"': "<<strerror (errno)<<", exiting"<<endl;
667            exit(1);
668        }
669    }
670
671    Utility::dropPrivs(newuid, newgid);
672
673    vector<TCPConnection> tcpconnections;
674    counter=0;
675    time_t now=0;
676    unsigned int maxTcpClients=arg().asNum("max-tcp-clients");
677    for(;;) {
678      while(MT->schedule()); // housekeeping, let threads do their thing
679     
680      if(!((counter++)%100)) 
681        MT->makeThread(houseKeeping,0,"housekeeping");
682      if(statsWanted)
683        doStats();
684
685      Utility::socklen_t addrlen=sizeof(fromaddr);
686      int d_len;
687     
688      struct timeval tv;
689      tv.tv_sec=0;
690      tv.tv_usec=500000;
691     
692      fd_set readfds, writefds;
693      FD_ZERO( &readfds );
694      FD_ZERO( &writefds );
695      FD_SET( d_clientsock, &readfds );
696      int fdmax=d_clientsock;
697
698      if(!tcpconnections.empty())
699        now=time(0);
700
701      vector<TCPConnection> sweeped;
702      int tcpLimit=arg().asNum("client-tcp-timeout");
703      for(vector<TCPConnection>::iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) {
704        if(now < i->startTime + tcpLimit) {
705          FD_SET(i->fd, &readfds);
706          fdmax=max(fdmax,i->fd);
707          sweeped.push_back(*i);
708        }
709        else {
710          L<<Logger::Error<<"TCP timeout from client "<<inet_ntoa(i->remote.sin_addr)<<endl;
711          close(i->fd);
712        }
713      }
714      sweeped.swap(tcpconnections);
715
716      for(vector<int>::const_iterator i=d_udpserversocks.begin(); i!=d_udpserversocks.end(); ++i) {
717        FD_SET( *i, &readfds );
718        fdmax=max(fdmax,*i);
719      }
720      if(tcpconnections.size() < maxTcpClients) 
721        for(tcpserversocks_t::const_iterator i=s_tcpserversocks.begin(); i!=s_tcpserversocks.end(); ++i) {
722          FD_SET(*i, &readfds );
723          fdmax=max(fdmax,*i);
724        }
725
726      for(map<int,PacketID>::const_iterator i=d_tcpclientreadsocks.begin(); i!=d_tcpclientreadsocks.end(); ++i) {
727        // cerr<<"Adding TCP socket "<<i->first<<" to read select set"<<endl;
728        FD_SET( i->first, &readfds );
729        fdmax=max(fdmax,i->first);
730      }
731
732      for(map<int,PacketID>::const_iterator i=d_tcpclientwritesocks.begin(); i!=d_tcpclientwritesocks.end(); ++i) {
733        // cerr<<"Adding TCP socket "<<i->first<<" to write select set"<<endl;
734        FD_SET( i->first, &writefds );
735        fdmax=max(fdmax,i->first);
736      }
737
738      int selret = select(  fdmax + 1, &readfds, &writefds, NULL, &tv );
739      if(selret<=0) 
740        if (selret == -1 && errno!=EINTR) 
741          throw AhuException("Select returned: "+stringerror());
742        else
743          continue;
744
745      if(FD_ISSET(d_clientsock,&readfds)) { // do we have a question response?
746        d_len=recvfrom(d_clientsock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);   
747        if(d_len<0) 
748          continue;
749
750        try {
751          DNSComboWriter dc(data, d_len);
752          dc.setRemote((struct sockaddr *)&fromaddr, addrlen);
753
754          if(dc.d_mdp.d_header.qr) {
755            pident.remote=fromaddr;
756            pident.id=dc.d_mdp.d_header.id;
757            string packet;
758            packet.assign(data, d_len);
759            MT->sendEvent(pident, &packet);
760          }
761          else 
762            L<<Logger::Warning<<"Ignoring question on outgoing socket from "<<dc.getRemote()<<endl;
763        }
764        catch(MOADNSException& mde) {
765          L<<Logger::Error<<"Unparseable packet from remote server "<< sockAddrToString((struct sockaddr_in*) &fromaddr, addrlen) <<": "<<mde.what()<<endl;
766        }
767
768      }
769     
770      for(vector<int>::const_iterator i=d_udpserversocks.begin(); i!=d_udpserversocks.end(); ++i) {
771        if(FD_ISSET(*i,&readfds)) { // do we have a new question on udp?
772          d_len=recvfrom(*i, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);   
773          if(d_len<0) 
774            continue;
775
776          DNSComboWriter* dc = new DNSComboWriter(data, d_len);
777
778          dc->setRemote((struct sockaddr *)&fromaddr, addrlen);
779
780          if(dc->d_mdp.d_header.qr)
781            L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
782          else {
783            ++qcounter;
784            dc->setSocket(*i);
785            dc->d_tcp=false;
786            MT->makeThread(startDoResolve, (void*) dc, "udp");
787          }
788        }
789      }
790
791      for(tcpserversocks_t::const_iterator i=s_tcpserversocks.begin(); i!=s_tcpserversocks.end(); ++i) { 
792        if(FD_ISSET(*i ,&readfds)) { // do we have a new TCP connection
793          struct sockaddr_in addr;
794          socklen_t addrlen=sizeof(addr);
795          int newsock=accept(*i, (struct sockaddr*)&addr, &addrlen);
796         
797          if(newsock>0) {
798            Utility::setNonBlocking(newsock);
799            TCPConnection tc;
800            tc.fd=newsock;
801            tc.state=TCPConnection::BYTE0;
802            tc.remote=addr;
803            tc.startTime=time(0);
804            tcpconnections.push_back(tc);
805          }
806        }
807      }
808
809      for(map<int,PacketID>::iterator i=d_tcpclientreadsocks.begin(); i!=d_tcpclientreadsocks.end();) { 
810        bool haveErased=false;
811        if(FD_ISSET(i->first, &readfds)) { // can we receive
812          shared_array<char> buffer(new char[i->second.inNeeded]);
813
814          int ret=read(i->first, buffer.get(), min(i->second.inNeeded,200));
815          // cerr<<"Read returned "<<ret<<endl;
816          if(ret > 0) {
817            i->second.inMSG.append(&buffer[0], &buffer[ret]);
818            i->second.inNeeded-=ret;
819            if(!i->second.inNeeded) {
820              // cerr<<"Got entire load of "<<i->second.inMSG.size()<<" bytes"<<endl;
821              PacketID pid=i->second;
822              string msg=i->second.inMSG;
823             
824              d_tcpclientreadsocks.erase((i++));
825              haveErased=true;
826              MT->sendEvent(pid, &msg);   // XXX DODGY
827            }
828            else {
829              // cerr<<"Still have "<<i->second.inNeeded<<" left to go"<<endl;
830            }
831          }
832          else {
833            //      cerr<<"when reading ret="<<ret<<endl;
834            // XXX FIXME I think some stuff needs to happen here - like send an EOF event
835          }
836        }
837        if(!haveErased)
838          ++i;
839      }
840
841      for(map<int,PacketID>::iterator i=d_tcpclientwritesocks.begin(); i!=d_tcpclientwritesocks.end(); ) { 
842        bool haveErased=false;
843        if(FD_ISSET(i->first, &writefds)) { // can we send over TCP
844          // cerr<<"Socket "<<i->first<<" available for writing"<<endl;
845          int ret=write(i->first, i->second.outMSG.c_str(), i->second.outMSG.size() - i->second.outPos);
846          if(ret > 0) {
847            i->second.outPos+=ret;
848            if(i->second.outPos==i->second.outMSG.size()) {
849              // cerr<<"Sent out entire load of "<<i->second.outMSG.size()<<" bytes"<<endl;
850              PacketID pid=i->second;
851              d_tcpclientwritesocks.erase((i++));
852              MT->sendEvent(pid, 0);
853              haveErased=true;
854              // cerr<<"Sent event too"<<endl;
855            }
856
857          }
858          else { 
859            //      cerr<<"ret="<<ret<<" when writing"<<endl;
860            // XXX FIXME I think some stuff needs to happen here - like send an EOF event
861          }
862        }
863        if(!haveErased)
864          ++i;
865      }
866
867
868      for(vector<TCPConnection>::iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) {
869        if(FD_ISSET(i->fd, &readfds)) {
870          if(i->state==TCPConnection::BYTE0) {
871            int bytes=read(i->fd,i->data,2);
872            if(bytes==1)
873              i->state=TCPConnection::BYTE1;
874            if(bytes==2) { 
875              i->qlen=(i->data[0]<<8)+i->data[1];
876              i->bytesread=0;
877              i->state=TCPConnection::GETQUESTION;
878            }
879            if(!bytes || bytes < 0) {
880              close(i->fd);
881              tcpconnections.erase(i);
882              break;
883            }
884          }
885          else if(i->state==TCPConnection::BYTE1) {
886            int bytes=read(i->fd,i->data+1,1);
887            if(bytes==1) {
888              i->state=TCPConnection::GETQUESTION;
889              i->qlen=(i->data[0]<<8)+i->data[1];
890              i->bytesread=0;
891            }
892            if(!bytes || bytes < 0) {
893              L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected after first byte"<<endl;
894              close(i->fd);
895              tcpconnections.erase(i);
896              break;
897            }
898           
899          }
900          else if(i->state==TCPConnection::GETQUESTION) {
901            int bytes=read(i->fd,i->data + i->bytesread,i->qlen - i->bytesread);
902            if(!bytes || bytes < 0) {
903              L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected while reading question body"<<endl;
904              close(i->fd);
905              tcpconnections.erase(i);
906              break;
907            }
908            i->bytesread+=bytes;
909            if(i->bytesread==i->qlen) {
910              i->state=TCPConnection::BYTE0;
911              DNSComboWriter* dc=0;
912              try {
913                dc=new DNSComboWriter(i->data, i->qlen);
914              }
915              catch(MOADNSException &mde) {
916                L<<Logger::Error<<"Unparseable packet from remote client "<<sockAddrToString(&i->remote,sizeof(i->remote))<<endl;
917                close(i->fd);
918                tcpconnections.erase(i);
919                break;
920              }
921
922              dc->setSocket(i->fd);
923              dc->d_tcp=true;
924              dc->setRemote((struct sockaddr *)&i->remote,sizeof(i->remote));
925              if(dc->d_mdp.d_header.qr)
926                L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
927              else {
928                ++qcounter;
929                MT->makeThread(startDoResolve, dc, "tcp");
930              }
931            }
932          }
933        }
934      }
935    }
936  }
937  catch(AhuException &ae) {
938    L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
939    ret=EXIT_FAILURE;
940  }
941  catch(exception &e) {
942    L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
943    ret=EXIT_FAILURE;
944  }
945  catch(...) {
946    L<<Logger::Error<<"any other exception in main: "<<endl;
947    ret=EXIT_FAILURE;
948  }
949 
950#ifdef WIN32
951  WSACleanup();
952#endif // WIN32
953
954  return ret;
955}
Note: See TracBrowser for help on using the browser.