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

Revision 664, 31.6 KB (checked in by ahu, 7 years ago)

lower case diff for hints-zone

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