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

Revision 521, 28.3 KB (checked in by ahu, 8 years ago)

add beginning of next generation zoneparser
add error checking to socket close - there are probably some duplicate closes around, causing havoc
add PTR to records that are propely parsed by the pdns_recursor
teach pdns_recursor to read hints from a zone file, "official" root is still in source
fix some --trace output that would look for .-terminated qnames
document hints-file

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