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

Revision 1508, 62.5 KB (checked in by ahu, 3 years ago)

oops, set number of threads before allocating room for them..

  • 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 - 2010  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18
19#ifndef WIN32
20# include <netdb.h>
21# include <unistd.h>
22#else
23 #include "ntservice.hh"
24 #include "recursorservice.hh"
25#endif // WIN32
26
27#include <boost/foreach.hpp>
28#include <pthread.h>
29#include "recpacketcache.hh"
30#include "utility.hh"
31#include "dns_random.hh"
32#include <iostream>
33#include <errno.h>
34#include <map>
35#include <set>
36#include "recursor_cache.hh"
37#include <stdio.h>
38#include <signal.h>
39#include <stdlib.h>
40#include "misc.hh"
41#include "mtasker.hh"
42#include <utility>
43#include "arguments.hh"
44#include "syncres.hh"
45#include <fcntl.h>
46#include <fstream>
47#include "sstuff.hh"
48#include <boost/tuple/tuple.hpp>
49#include <boost/tuple/tuple_comparison.hpp>
50#include <boost/shared_array.hpp>
51#include <boost/lexical_cast.hpp>
52#include <boost/function.hpp>
53#include <boost/algorithm/string.hpp>
54#include <netinet/tcp.h>
55#include "dnsparser.hh"
56#include "dnswriter.hh"
57#include "dnsrecords.hh"
58#include "zoneparser-tng.hh"
59#include "rec_channel.hh"
60#include "logger.hh"
61#include "iputils.hh"
62#include "mplexer.hh"
63#include "config.h"
64#include "lua-pdns-recursor.hh"
65
66#ifndef RECURSOR
67#include "statbag.hh"
68StatBag S;
69#endif
70
71__thread FDMultiplexer* t_fdm;
72__thread unsigned int t_id;
73unsigned int g_maxTCPPerClient;
74unsigned int g_networkTimeoutMsec;
75bool g_logCommonErrors;
76__thread shared_ptr<PowerDNSLua>* t_pdl;
77
78RecursorControlChannel s_rcc; // only active in thread 0
79
80// for communicating with our threads
81struct ThreadPipeSet
82{
83  int writeToThread;
84  int readToThread;
85  int writeFromThread;
86  int readFromThread;
87};
88
89vector<ThreadPipeSet> g_pipes; // effectively readonly after startup
90
91SyncRes::domainmap_t* g_initialDomainMap; // new threads needs this to be setup
92
93#include "namespaces.hh"
94
95__thread MemRecursorCache* t_RC;
96__thread RecursorPacketCache* t_packetCache;
97RecursorStats g_stats;
98bool g_quiet;
99
100static __thread NetmaskGroup* t_allowFrom;
101static NetmaskGroup* g_initialAllowFrom; // new thread needs to be setup with this
102
103NetmaskGroup* g_dontQuery;
104string s_programname="pdns_recursor";
105
106typedef vector<int> tcpListenSockets_t;
107tcpListenSockets_t g_tcpListenSockets;   // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets
108int g_tcpTimeout;
109unsigned int g_maxMThreads;
110struct timeval g_now; // timestamp, updated (too) frequently
111map<int, ComboAddress> g_listenSocketsAddresses; // is shared across all threads right now
112
113__thread MT_t* MT; // the big MTasker
114
115unsigned int g_numThreads;
116
117#define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10"
118
119//! used to send information to a newborn mthread
120struct DNSComboWriter {
121  DNSComboWriter(const char* data, uint16_t len, const struct timeval& now) : d_mdp(data, len), d_now(now), 
122                                                                                                        d_tcp(false), d_socket(-1)
123  {}
124  MOADNSParser d_mdp;
125  void setRemote(ComboAddress* sa)
126  {
127    d_remote=*sa;
128  }
129
130  void setSocket(int sock)
131  {
132    d_socket=sock;
133  }
134
135  string getRemote() const
136  {
137    return d_remote.toString();
138  }
139
140  struct timeval d_now;
141  ComboAddress d_remote;
142  bool d_tcp;
143  int d_socket;
144};
145
146
147ArgvMap &arg()
148{
149  static ArgvMap theArg;
150  return theArg;
151}
152
153
154void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var);
155
156// -1 is error, 0 is timeout, 1 is success
157int asendtcp(const string& data, Socket* sock) 
158{
159  PacketID pident;
160  pident.sock=sock;
161  pident.outMSG=data;
162 
163  t_fdm->addWriteFD(sock->getHandle(), handleTCPClientWritable, pident);
164  string packet;
165
166  int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec);
167
168  if(!ret || ret==-1) { // timeout
169    t_fdm->removeWriteFD(sock->getHandle());
170  }
171  else if(packet.size() !=data.size()) { // main loop tells us what it sent out, or empty in case of an error
172    return -1;
173  }
174  return ret;
175}
176
177void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var);
178
179// -1 is error, 0 is timeout, 1 is success
180int arecvtcp(string& data, int len, Socket* sock) 
181{
182  data.clear();
183  PacketID pident;
184  pident.sock=sock;
185  pident.inNeeded=len;
186  t_fdm->addReadFD(sock->getHandle(), handleTCPClientReadable, pident);
187
188  int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec);
189  if(!ret || ret==-1) { // timeout
190    t_fdm->removeReadFD(sock->getHandle());
191  }
192  else if(data.empty()) {// error, EOF or other
193    return -1;
194  }
195
196  return ret;
197}
198
199vector<ComboAddress> g_localQueryAddresses4, g_localQueryAddresses6; 
200ComboAddress g_local4("0.0.0.0"), g_local6("::");
201
202//! pick a random query local address
203ComboAddress getQueryLocalAddress(int family, uint16_t port)
204{
205  ComboAddress ret;
206  if(family==AF_INET) {
207    if(g_localQueryAddresses4.empty()) 
208      ret = g_local4;
209    else 
210      ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())];
211    ret.sin4.sin_port = htons(port);
212  }
213  else {
214    if(g_localQueryAddresses6.empty())
215      ret = g_local6;
216    else
217      ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())];
218     
219    ret.sin6.sin6_port = htons(port);
220  }
221  return ret;
222}
223
224void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t&);
225
226void setSocketBuffer(int fd, int optname, uint32_t size)
227{
228  uint32_t psize=0;
229  socklen_t len=sizeof(psize);
230 
231  if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
232    L<<Logger::Error<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
233    return; 
234  }
235
236  if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
237    L<<Logger::Error<<"Warning: unable to raise socket buffer size to "<<size<<": "<<strerror(errno)<<endl;
238}
239
240
241static void setSocketReceiveBuffer(int fd, uint32_t size)
242{
243  setSocketBuffer(fd, SO_RCVBUF, size);
244}
245
246static void setSocketSendBuffer(int fd, uint32_t size)
247{
248  setSocketBuffer(fd, SO_SNDBUF, size);
249}
250
251
252// you can ask this class for a UDP socket to send a query from
253// this socket is not yours, don't even think about deleting it
254// but after you call 'returnSocket' on it, don't assume anything anymore
255class UDPClientSocks
256{
257  unsigned int d_numsocks;
258  unsigned int d_maxsocks;
259public:
260  UDPClientSocks() : d_numsocks(0), d_maxsocks(5000)
261  {
262  }
263
264  typedef set<int> socks_t;
265  socks_t d_socks;
266
267  // returning -1 means: temporary OS error (ie, out of files), -2 means OS error
268  int getSocket(const ComboAddress& toaddr, int* fd)
269  {
270    *fd=makeClientSocket(toaddr.sin4.sin_family);
271    if(*fd < 0) // temporary error - receive exception otherwise
272      return -1;
273
274    if(connect(*fd, (struct sockaddr*)(&toaddr), toaddr.getSocklen()) < 0) {
275      int err = errno;
276      //      returnSocket(*fd);
277      Utility::closesocket(*fd);
278      if(err==ENETUNREACH) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
279        return -2;
280      return -1;
281    }
282
283    d_socks.insert(*fd);
284    d_numsocks++;
285    return 0;
286  }
287
288  void returnSocket(int fd)
289  {
290    socks_t::iterator i=d_socks.find(fd);
291    if(i==d_socks.end()) {
292      throw AhuException("Trying to return a socket (fd="+lexical_cast<string>(fd)+") not in the pool");
293    }
294    returnSocketLocked(i);
295  }
296
297  // return a socket to the pool, or simply erase it
298  void returnSocketLocked(socks_t::iterator& i)
299  {
300    if(i==d_socks.end()) {
301      throw AhuException("Trying to return a socket not in the pool");
302    }
303    try {
304      t_fdm->removeReadFD(*i);
305    }
306    catch(FDMultiplexerException& e) {
307      // we sometimes return a socket that has not yet been assigned to t_fdm
308    }
309    Utility::closesocket(*i);
310   
311    d_socks.erase(i++);
312    --d_numsocks;
313  }
314
315  // returns -1 for errors which might go away, throws for ones that won't
316  static int makeClientSocket(int family)
317  {
318    int ret=(int)socket(family, SOCK_DGRAM, 0);
319    if(ret < 0 && errno==EMFILE) // this is not a catastrophic error
320      return ret;
321   
322    if(ret<0) 
323      throw AhuException("Making a socket for resolver: "+stringerror());
324
325   
326    int tries=10;
327    while(--tries) {
328      uint16_t port;
329     
330      if(tries==1)  // fall back to kernel 'random'
331        port = 0;
332      else
333        port = 1025 + dns_random(64510);
334     
335      ComboAddress sin=getQueryLocalAddress(family, port); // does htons for us
336
337      if (::bind(ret, (struct sockaddr *)&sin, sin.getSocklen()) >= 0) 
338        break;
339    }
340    if(!tries)
341      throw AhuException("Resolver binding to local query client socket: "+stringerror());
342   
343    Utility::setNonBlocking(ret);
344    return ret;
345  }
346};
347
348static __thread UDPClientSocks* t_udpclientsocks;
349
350/* these two functions are used by LWRes */
351// -2 is OS error, -1 is error that depends on the remote, > 0 is success
352int asendto(const char *data, int len, int flags, 
353            const ComboAddress& toaddr, uint16_t id, const string& domain, uint16_t qtype, int* fd) 
354{
355
356  PacketID pident;
357  pident.domain = domain;
358  pident.remote = toaddr;
359  pident.type = qtype;
360
361  // see if there is an existing outstanding request we can chain on to, using partial equivalence function
362  pair<MT_t::waiters_t::iterator, MT_t::waiters_t::iterator> chain=MT->d_waiters.equal_range(pident, PacketIDBirthdayCompare());
363
364  for(; chain.first != chain.second; chain.first++) {
365    if(chain.first->key.fd > -1) { // don't chain onto existing chained waiter!
366      /*
367      cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
368      cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
369          <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
370      */
371      chain.first->key.chain.insert(id); // we can chain
372      *fd=-1;                            // gets used in waitEvent / sendEvent later on
373      return 1;
374    }
375  }
376
377  int ret=t_udpclientsocks->getSocket(toaddr, fd);
378  if(ret < 0)
379    return ret;
380
381  pident.fd=*fd;
382  pident.id=id;
383 
384  t_fdm->addReadFD(*fd, handleUDPServerResponse, pident);
385  ret = send(*fd, data, len, 0);
386
387  int tmp = errno;
388
389  if(ret < 0)
390    t_udpclientsocks->returnSocket(*fd);
391
392  errno = tmp; // this is for logging purposes only
393  return ret;
394}
395
396// -1 is error, 0 is timeout, 1 is success
397int arecvfrom(char *data, int len, int flags, const ComboAddress& fromaddr, int *d_len, 
398              uint16_t id, const string& domain, uint16_t qtype, int fd, struct timeval* now)
399{
400  static optional<unsigned int> nearMissLimit;
401  if(!nearMissLimit) 
402    nearMissLimit=::arg().asNum("spoof-nearmiss-max");
403
404  PacketID pident;
405  pident.fd=fd;
406  pident.id=id;
407  pident.domain=domain;
408  pident.type = qtype;
409  pident.remote=fromaddr;
410
411  string packet;
412  int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec, now);
413
414  if(ret > 0) {
415    if(packet.empty()) // means "error"
416      return -1; 
417
418    *d_len=(int)packet.size();
419    memcpy(data,packet.c_str(),min(len,*d_len));
420    if(*nearMissLimit && pident.nearMisses > *nearMissLimit) {
421      L<<Logger::Error<<"Too many ("<<pident.nearMisses<<" > "<<*nearMissLimit<<") bogus answers for '"<<domain<<"' from "<<fromaddr.toString()<<", assuming spoof attempt."<<endl;
422      g_stats.spoofCount++;
423      return -1;
424    }
425  }
426  else {
427    if(fd >= 0)
428      t_udpclientsocks->returnSocket(fd);
429  }
430  return ret;
431}
432
433
434string s_pidfname;
435static void writePid(void)
436{
437  ofstream of(s_pidfname.c_str(), ios_base::app);
438  if(of)
439    of<< Utility::getpid() <<endl;
440  else
441    L<<Logger::Error<<"Requested to write pid for "<<Utility::getpid()<<" to "<<s_pidfname<<" failed: "<<strerror(errno)<<endl;
442}
443
444
445map<ComboAddress, uint32_t> g_tcpClientCounts;
446
447struct TCPConnection
448{
449  int fd;
450  enum stateenum {BYTE0, BYTE1, GETQUESTION, DONE} state;
451  int qlen;
452  int bytesread;
453  ComboAddress remote;
454  char data[65535];
455  time_t startTime;
456
457  static void closeAndCleanup(int fd, const ComboAddress& remote) 
458  {
459    Utility::closesocket(fd);
460    if(!g_tcpClientCounts[remote]--) 
461      g_tcpClientCounts.erase(remote);
462    s_currentConnections--;
463  }
464  void closeAndCleanup()
465  {
466    closeAndCleanup(fd, remote);
467  }
468  static unsigned int s_currentConnections; //!< total number of current TCP connections
469};
470
471unsigned int TCPConnection::s_currentConnections; 
472void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var);
473
474void updateRcodeStats(int res)
475{
476  switch(res) {
477  case RCode::ServFail:
478    g_stats.servFails++;
479    break;
480  case RCode::NXDomain:
481    g_stats.nxDomains++;
482    break;
483  case RCode::NoError:
484    g_stats.noErrors++;
485    break;
486  }
487}
488
489void startDoResolve(void *p)
490{
491  DNSComboWriter* dc=(DNSComboWriter *)p;
492
493  try {
494    uint16_t maxudpsize=512;
495    EDNSOpts edo;
496    if(getEDNSOpts(dc->d_mdp, &edo)) {
497      maxudpsize=max(edo.d_packetsize, (uint16_t)1280);
498    }
499   
500    vector<DNSResourceRecord> ret;
501    vector<uint8_t> packet;
502
503    DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass); 
504
505    pw.getHeader()->aa=0;
506    pw.getHeader()->ra=1;
507    pw.getHeader()->qr=1;
508    pw.getHeader()->tc=0;
509    pw.getHeader()->id=dc->d_mdp.d_header.id;
510    pw.getHeader()->rd=dc->d_mdp.d_header.rd;
511
512    SyncRes sr(dc->d_now);
513    if(!g_quiet)
514      L<<Logger::Error<<t_id<<" ["<<MT->getTid()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
515       <<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote()<<endl;
516
517    sr.setId(MT->getTid());
518    if(!dc->d_mdp.d_header.rd)
519      sr.setCacheOnly();
520
521    int res;
522
523    if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res)) {
524       res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
525
526      if(t_pdl->get()) {
527        if(res == RCode::NXDomain)
528          (*t_pdl)->nxdomain(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res);
529      }
530    }
531    uint32_t minTTL=numeric_limits<uint32_t>::max();
532    if(res<0) {
533      pw.getHeader()->rcode=RCode::ServFail;
534      // no commit here, because no record
535      g_stats.servFails++;
536    }
537    else {
538      pw.getHeader()->rcode=res;
539      updateRcodeStats(res);
540   
541      if(ret.size()) {
542        shuffle(ret);
543       
544        for(vector<DNSResourceRecord>::const_iterator i=ret.begin(); i!=ret.end(); ++i) {
545          pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, i->qclass, (DNSPacketWriter::Place)i->d_place); 
546          minTTL = min(minTTL, i->ttl);
547          if(i->qtype.getCode() == QType::A) { // blast out A record w/o doing whole dnswriter thing
548            uint32_t ip=0;
549            IpToU32(i->content, &ip);
550            pw.xfr32BitInt(htonl(ip));
551          } else {
552            shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(i->qtype.getCode(), i->qclass, i->content)); 
553            drc->toPacket(pw);
554          }
555          if(!dc->d_tcp && pw.size() > maxudpsize) {
556            pw.rollback();
557            if(i->d_place==DNSResourceRecord::ANSWER)  // only truncate if we actually omitted parts of the answer
558              pw.getHeader()->tc=1;
559            goto sendit; // need to jump over pw.commit
560          }
561        }
562
563      pw.commit();
564      }
565    }
566  sendit:;
567    if(!dc->d_tcp) {
568      sendto(dc->d_socket, (const char*)&*packet.begin(), packet.size(), 0, (struct sockaddr *)(&dc->d_remote), dc->d_remote.getSocklen());
569      if(!SyncRes::s_nopacketcache) {
570        t_packetCache->insertResponsePacket(string((const char*)&*packet.begin(), packet.size()), g_now.tv_sec, 
571                                           min(minTTL, 
572                                               pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl : SyncRes::s_packetcachettl
573                                               )
574                                          );
575      }
576    }
577    else {
578      char buf[2];
579      buf[0]=packet.size()/256;
580      buf[1]=packet.size()%256;
581
582      Utility::iovec iov[2];
583
584      iov[0].iov_base=(void*)buf;              iov[0].iov_len=2;
585      iov[1].iov_base=(void*)&*packet.begin(); iov[1].iov_len = packet.size();
586
587      int ret=Utility::writev(dc->d_socket, iov, 2);
588      bool hadError=true;
589
590      if(ret == 0) 
591        L<<Logger::Error<<"EOF writing TCP answer to "<<dc->getRemote()<<endl;
592      else if(ret < 0 ) 
593        L<<Logger::Error<<"Error writing TCP answer to "<<dc->getRemote()<<": "<< strerror(errno) <<endl;
594      else if((unsigned int)ret != 2 + packet.size())
595        L<<Logger::Error<<"Oops, partial answer sent to "<<dc->getRemote()<<" for "<<dc->d_mdp.d_qname<<" (size="<< (2 + packet.size()) <<", sent "<<ret<<")"<<endl;
596      else
597        hadError=false;
598     
599      // update tcp connection status, either by closing or moving to 'BYTE0'
600   
601      if(hadError) {
602        // no need to remove us from FDM, we weren't there
603        TCPConnection::closeAndCleanup(dc->d_socket, dc->d_remote);
604      }
605      else {
606        TCPConnection tc;
607        tc.fd=dc->d_socket;
608        tc.state=TCPConnection::BYTE0;
609        tc.remote=dc->d_remote;
610        Utility::gettimeofday(&g_now, 0); // needs to be updated
611        tc.startTime=g_now.tv_sec;
612        t_fdm->addReadFD(tc.fd, handleRunningTCPQuestion, tc);
613        t_fdm->setReadTTD(tc.fd, g_now, g_tcpTimeout);
614      }
615    }
616   
617    if(!g_quiet) {
618      L<<Logger::Error<<t_id<<" ["<<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);
619      L<<"': "<<ntohs(pw.getHeader()->ancount)<<" answers, "<<ntohs(pw.getHeader()->arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
620      sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<<res<<endl;
621    }
622
623    sr.d_outqueries ? t_RC->cacheMisses++ : t_RC->cacheHits++; 
624    float spent=makeFloat(sr.d_now-dc->d_now);
625    if(spent < 0.001)
626      g_stats.answers0_1++;
627    else if(spent < 0.010)
628      g_stats.answers1_10++;
629    else if(spent < 0.1)
630      g_stats.answers10_100++;
631    else if(spent < 1.0)
632      g_stats.answers100_1000++;
633    else
634      g_stats.answersSlow++;
635
636    uint64_t newLat=(uint64_t)(spent*1000000);
637    if(newLat < 1000000)  // outliers of several minutes exist..
638      g_stats.avgLatencyUsec=(uint64_t)((1-0.0001)*g_stats.avgLatencyUsec + 0.0001*newLat);
639
640    delete dc;
641  }
642  catch(AhuException &ae) {
643    L<<Logger::Error<<"startDoResolve problem: "<<ae.reason<<endl;
644  }
645  catch(MOADNSException& e) {
646    L<<Logger::Error<<"DNS parser error: "<<dc->d_mdp.d_qname<<", "<<e.what()<<endl;
647  }
648  catch(std::exception& e) {
649    L<<Logger::Error<<"STL error: "<<e.what()<<endl;
650  }
651  catch(...) {
652    L<<Logger::Error<<"Any other exception in a resolver context"<<endl;
653  }
654}
655
656void makeControlChannelSocket()
657{
658  string sockname=::arg()["socket-dir"]+"/pdns_recursor.controlsocket";
659  if(::arg().mustDo("fork")) {
660    sockname+="."+lexical_cast<string>(Utility::getpid());
661    L<<Logger::Warning<<"Forked control socket name: "<<sockname<<endl;
662  }
663  s_rcc.listen(sockname);
664}
665
666void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
667{
668  TCPConnection* conn=any_cast<TCPConnection>(&var);
669
670  if(conn->state==TCPConnection::BYTE0) {
671    int bytes=recv(conn->fd, conn->data, 2, 0);
672    if(bytes==1)
673      conn->state=TCPConnection::BYTE1;
674    if(bytes==2) { 
675      conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
676      conn->bytesread=0;
677      conn->state=TCPConnection::GETQUESTION;
678    }
679    if(!bytes || bytes < 0) {
680      TCPConnection tmp(*conn); 
681      t_fdm->removeReadFD(fd);
682      tmp.closeAndCleanup();
683      return;
684    }
685  }
686  else if(conn->state==TCPConnection::BYTE1) {
687    int bytes=recv(conn->fd, conn->data+1, 1, 0);
688    if(bytes==1) {
689      conn->state=TCPConnection::GETQUESTION;
690      conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
691      conn->bytesread=0;
692    }
693    if(!bytes || bytes < 0) {
694      if(g_logCommonErrors)
695        L<<Logger::Error<<"TCP client "<< conn->remote.toString() <<" disconnected after first byte"<<endl;
696      TCPConnection tmp(*conn); 
697      t_fdm->removeReadFD(fd);
698      tmp.closeAndCleanup();  // conn loses validity here..
699      return;
700    }
701  }
702  else if(conn->state==TCPConnection::GETQUESTION) {
703    int bytes=recv(conn->fd, conn->data + conn->bytesread, conn->qlen - conn->bytesread, 0);
704    if(!bytes || bytes < 0) {
705      L<<Logger::Error<<"TCP client "<< conn->remote.toString() <<" disconnected while reading question body"<<endl;
706      TCPConnection tmp(*conn);
707      t_fdm->removeReadFD(fd);
708      tmp.closeAndCleanup();  // conn loses validity here..
709
710      return;
711    }
712    conn->bytesread+=bytes;
713    if(conn->bytesread==conn->qlen) {
714      TCPConnection tconn(*conn); 
715      t_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read
716
717      DNSComboWriter* dc=0;
718      try {
719        dc=new DNSComboWriter(tconn.data, tconn.qlen, g_now);
720      }
721      catch(MOADNSException &mde) {
722        g_stats.clientParseError++; 
723        if(g_logCommonErrors)
724          L<<Logger::Error<<"Unable to parse packet from TCP client "<< tconn.remote.toString() <<endl;
725        tconn.closeAndCleanup();
726        return;
727      }
728     
729      dc->setSocket(tconn.fd);
730      dc->d_tcp=true;
731      dc->setRemote(&tconn.remote);
732      if(dc->d_mdp.d_header.qr) {
733        delete dc;
734        L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
735        tconn.closeAndCleanup();
736        return;
737      }
738      else {
739        ++g_stats.qcounter;
740        ++g_stats.tcpqcounter;
741        MT->makeThread(startDoResolve, dc); // deletes dc
742        return;
743      }
744    }
745  }
746}
747
748//! Handle new incoming TCP connection
749void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& )
750{
751  ComboAddress addr;
752  socklen_t addrlen=sizeof(addr);
753  int newsock=(int)accept(fd, (struct sockaddr*)&addr, &addrlen);
754  if(newsock>0) {
755    if(MT->numProcesses() > g_maxMThreads) {
756      g_stats.overCapacityDrops++;
757      Utility::closesocket(newsock);
758      return;
759    }
760
761    g_stats.addRemote(addr);
762    if(t_allowFrom && !t_allowFrom->match(&addr)) {
763      if(!g_quiet) 
764        L<<Logger::Error<<"["<<MT->getTid()<<"] dropping TCP query from "<<addr.toString()<<", address not matched by allow-from"<<endl;
765
766      g_stats.unauthorizedTCP++;
767      Utility::closesocket(newsock);
768      return;
769    }
770   
771    if(g_maxTCPPerClient && g_tcpClientCounts.count(addr) && g_tcpClientCounts[addr] >= g_maxTCPPerClient) {
772      g_stats.tcpClientOverflow++;
773      Utility::closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
774      return;
775    }
776    g_tcpClientCounts[addr]++;
777    Utility::setNonBlocking(newsock);
778    TCPConnection tc;
779    tc.fd=newsock;
780    tc.state=TCPConnection::BYTE0;
781    tc.remote=addr;
782    tc.startTime=g_now.tv_sec;
783    TCPConnection::s_currentConnections++;
784    t_fdm->addReadFD(tc.fd, handleRunningTCPQuestion, tc);
785
786    struct timeval now;
787    Utility::gettimeofday(&now, 0);
788    t_fdm->setReadTTD(tc.fd, now, g_tcpTimeout);
789  }
790}
791 
792void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
793{
794  int len;
795  char data[1500];
796  ComboAddress fromaddr;
797  socklen_t addrlen=sizeof(fromaddr);
798
799 
800  if((len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen)) >= 0) {
801
802    g_stats.addRemote(fromaddr);
803
804    if(t_allowFrom && !t_allowFrom->match(&fromaddr)) {
805      if(!g_quiet) 
806        L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl;
807
808      g_stats.unauthorizedUDP++;
809      return;
810    }
811    try {
812      dnsheader* dh=(dnsheader*)data;
813     
814      if(dh->qr) {
815        if(g_logCommonErrors)
816          L<<Logger::Error<<"Ignoring answer from "<<fromaddr.toString()<<" on server socket!"<<endl;
817      }
818      else {
819        ++g_stats.qcounter;
820
821        string response;
822        try {
823          if(!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(string(data, len), g_now.tv_sec, &response)) {
824            if(!g_quiet)
825              L<<Logger::Error<<t_id<< " question answered from packet cache from "<<fromaddr.toString()<<endl;
826 
827            g_stats.packetCacheHits++;
828            SyncRes::s_queries++;
829            sendto(fd, response.c_str(), response.length(), 0, (struct sockaddr*) &fromaddr, fromaddr.getSocklen());
830            if(response.length() >= sizeof(struct dnsheader))
831              updateRcodeStats(((struct dnsheader*)response.c_str())->rcode);
832            return;
833          }
834        } 
835        catch(std::exception& e) {
836          throw MOADNSException(e.what()); // translate
837        }
838        if(MT->numProcesses() > g_maxMThreads) {
839          g_stats.overCapacityDrops++;
840          return;
841        }
842 
843        DNSComboWriter* dc = new DNSComboWriter(data, len, g_now);
844        dc->setSocket(fd);
845        dc->setRemote(&fromaddr);
846
847        dc->d_tcp=false;
848
849        MT->makeThread(startDoResolve, (void*) dc); // deletes dc
850      }
851    }
852    catch(MOADNSException& mde) {
853      g_stats.clientParseError++; 
854      if(g_logCommonErrors)
855        L<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<mde.what()<<endl;
856    }
857  }
858}
859
860typedef vector<pair<int, function< void(int, any&) > > > deferredAdd_t;
861deferredAdd_t deferredAdd;
862
863void makeTCPServerSockets()
864{
865  int fd;
866  vector<string>locals;
867  stringtok(locals,::arg()["local-address"]," ,");
868
869  if(locals.empty())
870    throw AhuException("No local address specified");
871 
872  for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
873    ServiceTuple st;
874    st.port=::arg().asNum("local-port");
875    parseService(*i, st);
876   
877    ComboAddress sin;
878
879    memset((char *)&sin,0, sizeof(sin));
880    sin.sin4.sin_family = AF_INET;
881    if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
882      sin.sin6.sin6_family = AF_INET6;
883      if(Utility::inet_pton(AF_INET6, st.host.c_str(), &sin.sin6.sin6_addr) <= 0)
884        throw AhuException("Unable to resolve local address for TCP server on '"+ st.host +"'"); 
885    }
886
887    fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0);
888    if(fd<0) 
889      throw AhuException("Making a TCP server socket for resolver: "+stringerror());
890
891    int tmp=1;
892    if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
893      L<<Logger::Error<<"Setsockopt failed for TCP listening socket"<<endl;
894      exit(1);
895    }
896   
897#ifdef TCP_DEFER_ACCEPT
898    if(setsockopt(fd, SOL_TCP,TCP_DEFER_ACCEPT,(char*)&tmp,sizeof tmp) >= 0) {
899      if(i==locals.begin())
900        L<<Logger::Error<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl;
901    }
902#endif
903
904    sin.sin4.sin_port = htons(st.port);
905    int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
906    if (::bind(fd, (struct sockaddr *)&sin, socklen )<0) 
907      throw AhuException("Binding TCP server socket for "+ st.host +": "+stringerror());
908   
909    Utility::setNonBlocking(fd);
910    setSocketSendBuffer(fd, 65000);
911    listen(fd, 128);
912    deferredAdd.push_back(make_pair(fd, handleNewTCPQuestion));
913    g_tcpListenSockets.push_back(fd);
914
915    if(sin.sin4.sin_family == AF_INET) 
916      L<<Logger::Error<<"Listening for TCP queries on "<< sin.toString() <<":"<<st.port<<endl;
917    else
918      L<<Logger::Error<<"Listening for TCP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
919  }
920}
921
922
923
924void makeUDPServerSockets()
925{
926  vector<string>locals;
927  stringtok(locals,::arg()["local-address"]," ,");
928
929  if(locals.empty())
930    throw AhuException("No local address specified");
931 
932  if(::arg()["local-address"]=="0.0.0.0") {
933    L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
934  }
935
936  for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
937    ServiceTuple st;
938    st.port=::arg().asNum("local-port");
939    parseService(*i, st);
940
941    ComboAddress sin;
942
943    memset(&sin, 0, sizeof(sin));
944    sin.sin4.sin_family = AF_INET;
945    if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
946      sin.sin6.sin6_family = AF_INET6;
947      if(Utility::inet_pton(AF_INET6, st.host.c_str(), &sin.sin6.sin6_addr) <= 0)
948        throw AhuException("Unable to resolve local address for UDP server on '"+ st.host +"'"); 
949    }
950   
951    int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0);
952
953    if(fd < 0) {
954      throw AhuException("Making a UDP server socket for resolver: "+netstringerror());
955    }
956
957    setSocketReceiveBuffer(fd, 200000);
958    sin.sin4.sin_port = htons(st.port);
959
960    int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
961    if (::bind(fd, (struct sockaddr *)&sin, socklen)<0) 
962      throw AhuException("Resolver binding to server socket on port "+ lexical_cast<string>(st.port) +" for "+ st.host+": "+stringerror());
963   
964    Utility::setNonBlocking(fd);
965
966    deferredAdd.push_back(make_pair(fd, handleNewUDPQuestion));
967    g_listenSocketsAddresses[fd]=sin;  // this is written to only from the startup thread, not from the workers
968    if(sin.sin4.sin_family == AF_INET) 
969      L<<Logger::Error<<"Listening for UDP queries on "<< sin.toString() <<":"<<st.port<<endl;
970    else
971      L<<Logger::Error<<"Listening for UDP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
972  }
973}
974
975
976#ifndef WIN32
977void daemonize(void)
978{
979  if(fork())
980    exit(0); // bye bye
981 
982  setsid(); 
983
984  int i=open("/dev/null",O_RDWR); /* open stdin */
985  if(i < 0) 
986    L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
987  else {
988    dup2(i,0); /* stdin */
989    dup2(i,1); /* stderr */
990    dup2(i,2); /* stderr */
991    close(i);
992  }
993}
994#endif
995
996uint64_t counter;
997bool statsWanted;
998
999void usr1Handler(int)
1000{
1001  statsWanted=true;
1002}
1003
1004void usr2Handler(int)
1005{
1006  SyncRes::setLog(true);
1007  g_quiet=false;
1008  ::arg().set("quiet")="no";
1009
1010}
1011
1012void doStats(void)
1013{
1014  static time_t lastOutputTime;
1015  static uint64_t lastQueryCount;
1016 
1017  if(g_stats.qcounter && (t_RC->cacheHits + t_RC->cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {  // this only runs once thread 0 has had hits
1018    uint64_t cacheHits = broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
1019    uint64_t cacheMisses = broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
1020   
1021    L<<Logger::Warning<<"stats: "<<g_stats.qcounter<<" questions, "<<
1022      broadcastAccFunction<uint64_t>(pleaseGetCacheSize)<< " cache entries, "<<
1023      broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize)<<" negative entries, "<<
1024      (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<<endl; 
1025   
1026    L<<Logger::Warning<<"stats: throttle map: "
1027      << broadcastAccFunction<uint64_t>(pleaseGetThrottleSize) <<", ns speeds: "
1028      << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<endl; 
1029    L<<Logger::Warning<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
1030    L<<Logger::Warning<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
1031     <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
1032    L<<Logger::Warning<<"stats: "<<SyncRes::s_tcpoutqueries<<" outgoing tcp connections, "<<
1033      broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries)<<" queries running, "<<SyncRes::s_outgoingtimeouts<<" outgoing timeouts"<<endl;
1034
1035    //L<<Logger::Warning<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
1036      //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
1037   
1038    L<<Logger::Warning<<"stats: " <<  broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize) <<
1039    " packet cache entries, "<<(int)(100.0*broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"<<endl;
1040   
1041    time_t now = time(0);
1042    if(lastOutputTime && lastQueryCount && now != lastOutputTime) {
1043      L<<Logger::Warning<<"stats: "<< (SyncRes::s_queries - lastQueryCount) / (now - lastOutputTime) <<" qps (average over "<< (now - lastOutputTime) << " seconds)"<<endl;
1044    }
1045    lastOutputTime = now;
1046    lastQueryCount = SyncRes::s_queries;
1047  }
1048  else if(statsWanted) 
1049    L<<Logger::Warning<<"stats: no stats yet!"<<endl;
1050
1051  statsWanted=false;
1052}
1053
1054static void houseKeeping(void *)
1055try
1056{
1057  static __thread time_t last_stat, last_rootupdate, last_prune;
1058  struct timeval now;
1059  Utility::gettimeofday(&now, 0);
1060
1061  if(now.tv_sec - last_prune > (time_t)(5 + t_id)) { 
1062    DTime dt;
1063    dt.setTimeval(now);
1064    t_RC->doPrune(); // this function is local to a thread, so fine anyhow
1065    t_packetCache->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numThreads);
1066   
1067    typedef SyncRes::negcache_t::nth_index<1>::type negcache_by_ttd_index_t;
1068    negcache_by_ttd_index_t& ttdindex=boost::multi_index::get<1>(SyncRes::t_sstorage->negcache); 
1069
1070    negcache_by_ttd_index_t::iterator i=ttdindex.lower_bound(now.tv_sec);
1071    ttdindex.erase(ttdindex.begin(), i);
1072
1073    time_t limit=now.tv_sec-300;
1074    for(SyncRes::nsspeeds_t::iterator i = SyncRes::t_sstorage->nsSpeeds.begin() ; i!= SyncRes::t_sstorage->nsSpeeds.end(); )
1075      if(i->second.stale(limit))
1076        SyncRes::t_sstorage->nsSpeeds.erase(i++);
1077      else
1078        ++i;
1079//    L<<Logger::Warning<<"Spent "<<dt.udiff()/1000<<" msec cleaning"<<endl;
1080    last_prune=time(0);
1081  }
1082  if(!t_id) {
1083    if(now.tv_sec - last_stat>1800) { 
1084      doStats();
1085      last_stat=time(0);
1086    }
1087  }
1088  if(now.tv_sec - last_rootupdate > 7200) {
1089    SyncRes sr(now);
1090    sr.setDoEDNS0(true);
1091    vector<DNSResourceRecord> ret;
1092
1093    sr.setNoCache();
1094    int res=sr.beginResolve(".", QType(QType::NS), 1, ret);
1095    if(!res) {
1096      L<<Logger::Warning<<"Refreshed . records"<<endl;
1097      last_rootupdate=now.tv_sec;
1098    }
1099    else
1100      L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
1101  }
1102}
1103catch(AhuException& ae)
1104{
1105  L<<Logger::Error<<"Fatal error: "<<ae.reason<<endl;
1106  throw;
1107}
1108;
1109
1110void makeThreadPipes()
1111{
1112  for(unsigned int n=0; n < g_numThreads; ++n) {
1113    struct ThreadPipeSet tps;
1114    int fd[2];
1115    if(pipe(fd) < 0)
1116      unixDie("Creating pipe for inter-thread communications");
1117   
1118    tps.readToThread = fd[0];
1119    tps.writeToThread = fd[1];
1120   
1121    if(pipe(fd) < 0)
1122      unixDie("Creating pipe for inter-thread communications");
1123    tps.readFromThread = fd[0];
1124    tps.writeFromThread = fd[1];
1125   
1126    g_pipes.push_back(tps);
1127  }
1128}
1129
1130void broadcastFunction(const pipefunc_t& func, bool skipSelf)
1131{
1132  unsigned int n = 0;
1133  BOOST_FOREACH(ThreadPipeSet& tps, g_pipes) 
1134  {
1135    if(n++ == t_id) {
1136      if(!skipSelf)
1137        func(); // don't write to ourselves!
1138      continue;
1139    }
1140     
1141    pipefunc_t *funcptr = new pipefunc_t(func);
1142    if(write(tps.writeToThread, &funcptr, sizeof(funcptr)) != sizeof(funcptr))
1143      unixDie("write to thread pipe returned wrong size or error");
1144   
1145    string* resp;
1146    if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
1147      unixDie("read from thread pipe returned wrong size or error");
1148   
1149    if(resp) {
1150//      cerr <<"got response: " << *resp << endl;
1151      delete resp;
1152    }
1153  }
1154}
1155
1156
1157
1158void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var)
1159{
1160  pipefunc_t* func;
1161  if(read(fd, &func, sizeof(func)) != sizeof(func)) { // fd == readToThread
1162    unixDie("read from thread pipe returned wrong size or error");
1163  }
1164 
1165  void *resp = (*func)();
1166 
1167  if(write(g_pipes[t_id].writeFromThread, &resp, sizeof(resp)) != sizeof(resp))
1168    unixDie("write to thread pipe returned wrong size or error");
1169 
1170  delete func;
1171}
1172
1173template<class T> void *voider(const boost::function<T*()>& func)
1174{
1175  return func();
1176}
1177
1178template<class T> T broadcastAccFunction(const boost::function<T*()>& func, bool skipSelf)
1179{
1180  unsigned int n = 0;
1181  T ret=T();
1182  BOOST_FOREACH(ThreadPipeSet& tps, g_pipes) 
1183  {
1184    if(n++ == t_id) {
1185      if(!skipSelf) {
1186        T* resp = (T*)func(); // don't write to ourselves!
1187        if(resp) {
1188          //~ cerr <<"got direct: " << *resp << endl;
1189          ret += *resp;
1190          delete resp;
1191        }
1192      }
1193      continue;
1194    }
1195     
1196    pipefunc_t *funcptr = new pipefunc_t(boost::bind(voider<T>, func));
1197    if(write(tps.writeToThread, &funcptr, sizeof(funcptr)) != sizeof(funcptr))
1198      unixDie("write to thread pipe returned wrong size or error");
1199   
1200    T* resp;
1201    if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
1202      unixDie("read from thread pipe returned wrong size or error");
1203   
1204    if(resp) {
1205      //~ cerr <<"got response: " << *resp << endl;
1206      ret += *resp;
1207      delete resp;
1208    }
1209  }
1210  return ret;
1211}
1212
1213template string broadcastAccFunction(const boost::function<string*()>& fun, bool skipSelf); // explicit instantiation
1214template uint64_t broadcastAccFunction(const boost::function<uint64_t*()>& fun, bool skipSelf); // explicit instantiation
1215
1216void handleRCC(int fd, FDMultiplexer::funcparam_t& var)
1217{
1218  string remote;
1219  string msg=s_rcc.recv(&remote);
1220  RecursorControlParser rcp;
1221  RecursorControlParser::func_t* command;
1222  string answer=rcp.getAnswer(msg, &command);
1223  try {
1224    s_rcc.send(answer, &remote);
1225    command();
1226  }
1227  catch(std::exception& e) {
1228    L<<Logger::Error<<"Error dealing with control socket request: "<<e.what()<<endl;
1229  }
1230  catch(AhuException& ae) {
1231    L<<Logger::Error<<"Error dealing with control socket request: "<<ae.reason<<endl;
1232  }
1233}
1234
1235void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var)
1236{
1237  PacketID* pident=any_cast<PacketID>(&var);
1238  //  cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
1239
1240  shared_array<char> buffer(new char[pident->inNeeded]);
1241
1242  int ret=recv(fd, buffer.get(), pident->inNeeded,0);
1243  if(ret > 0) {
1244    pident->inMSG.append(&buffer[0], &buffer[ret]);
1245    pident->inNeeded-=ret;
1246    if(!pident->inNeeded) {
1247      //      cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
1248      PacketID pid=*pident;
1249      string msg=pident->inMSG;
1250     
1251      t_fdm->removeReadFD(fd);
1252      MT->sendEvent(pid, &msg); 
1253    }
1254    else {
1255      //      cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
1256    }
1257  }
1258  else {
1259    PacketID tmp=*pident;
1260    t_fdm->removeReadFD(fd); // pident might now be invalid (it isn't, but still)
1261    string empty;
1262    MT->sendEvent(tmp, &empty); // this conveys error status
1263  }
1264}
1265
1266void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var)
1267{
1268  PacketID* pid=any_cast<PacketID>(&var);
1269  int ret=send(fd, pid->outMSG.c_str() + pid->outPos, pid->outMSG.size() - pid->outPos,0);
1270  if(ret > 0) {
1271    pid->outPos+=ret;
1272    if(pid->outPos==pid->outMSG.size()) {
1273      PacketID tmp=*pid;
1274      t_fdm->removeWriteFD(fd);
1275      MT->sendEvent(tmp, &tmp.outMSG);  // send back what we sent to convey everything is ok
1276    }
1277  }
1278  else {  // error or EOF
1279    PacketID tmp(*pid);
1280    t_fdm->removeWriteFD(fd);
1281    string sent;
1282    MT->sendEvent(tmp, &sent);         // we convey error status by sending empty string
1283  }
1284}
1285
1286// resend event to everybody chained onto it
1287void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content)
1288{
1289  if(iter->key.chain.empty())
1290    return;
1291  //  cerr<<"doResends called!\n";
1292  for(PacketID::chain_t::iterator i=iter->key.chain.begin(); i != iter->key.chain.end() ; ++i) {
1293    resend.fd=-1;
1294    resend.id=*i;
1295    //    cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
1296
1297    MT->sendEvent(resend, &content);
1298    g_stats.chainResends++;
1299  }
1300}
1301
1302void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t& var)
1303{
1304  PacketID pid=any_cast<PacketID>(var);
1305  int len;
1306  char data[1500];
1307  ComboAddress fromaddr;
1308  socklen_t addrlen=sizeof(fromaddr);
1309
1310  len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);
1311
1312  if(len < (int)sizeof(dnsheader)) {
1313    if(len < 0)
1314      ; //      cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
1315    else {
1316      g_stats.serverParseError++; 
1317      if(g_logCommonErrors)
1318        L<<Logger::Error<<"Unable to parse packet from remote UDP server "<< sockAddrToString((struct sockaddr_in*) &fromaddr) <<
1319          ": packet smalller than DNS header"<<endl;
1320    }
1321
1322    t_udpclientsocks->returnSocket(fd);
1323    string empty;
1324
1325    MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid);
1326    if(iter != MT->d_waiters.end()) 
1327      doResends(iter, pid, empty);
1328   
1329    MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot)
1330    return;
1331  } 
1332
1333  dnsheader dh;
1334  memcpy(&dh, data, sizeof(dh));
1335 
1336  if(dh.qr) {
1337    PacketID pident;
1338    pident.remote=fromaddr;
1339    pident.id=dh.id;
1340    pident.fd=fd;
1341    if(!dh.qdcount) { // UPC, Nominum, very old BIND on FormErr, NSD
1342      pident.domain.clear();
1343      pident.type = 0;
1344    }
1345    else {
1346      try {
1347        pident.domain=questionExpand(data, len, pident.type); // don't copy this from above - we need to do the actual read
1348      }
1349      catch(std::exception& e) {
1350        g_stats.serverParseError++; // won't be fed to lwres.cc, so we have to increment
1351        L<<Logger::Warning<<"Error in packet from "<<sockAddrToString((struct sockaddr_in*) &fromaddr) << ": "<<e.what() << endl;
1352        return;
1353      }
1354    }
1355    string packet;
1356    packet.assign(data, len);
1357
1358    MT_t::waiters_t::iterator iter=MT->d_waiters.find(pident);
1359    if(iter != MT->d_waiters.end()) {
1360      doResends(iter, pident, packet);
1361    }
1362
1363  retryWithName:
1364
1365    if(!MT->sendEvent(pident, &packet)) {
1366     
1367      // we do a full scan for outstanding queries on unexpected answers. not too bad since we only accept them on the right port number, which is hard enough to guess
1368      for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) {
1369        if(pident.fd==mthread->key.fd && mthread->key.remote==pident.remote &&  mthread->key.type == pident.type &&
1370           pdns_iequals(pident.domain, mthread->key.domain)) {
1371          mthread->key.nearMisses++;
1372        }
1373
1374        // be a bit paranoid here since we're weakening our matching
1375        if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type && 
1376           pident.id  == mthread->key.id && mthread->key.remote == pident.remote) {
1377          //        cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
1378          pident.domain = mthread->key.domain;
1379          pident.type = mthread->key.type;
1380          goto retryWithName;
1381        }
1382      }
1383      g_stats.unexpectedCount++; // if we made it here, it really is an unexpected answer
1384      if(g_logCommonErrors)
1385        L<<Logger::Warning<<"Discarding unexpected packet from "<<fromaddr.toString()<<": "<<pident.domain<<", "<<pident.type<<endl;
1386    }
1387    else if(fd >= 0) {
1388      t_udpclientsocks->returnSocket(fd);
1389    }
1390  }
1391  else
1392    L<<Logger::Warning<<"Ignoring question on outgoing socket from "<< sockAddrToString((struct sockaddr_in*) &fromaddr)  <<endl;
1393}
1394
1395FDMultiplexer* getMultiplexer()
1396{
1397  FDMultiplexer* ret;
1398  for(FDMultiplexer::FDMultiplexermap_t::const_iterator i = FDMultiplexer::getMultiplexerMap().begin();
1399      i != FDMultiplexer::getMultiplexerMap().end(); ++i) {
1400    try {
1401      ret=i->second();
1402      return ret;
1403    }
1404    catch(FDMultiplexerException &fe) {
1405      L<<Logger::Error<<"Non-fatal error initializing possible multiplexer ("<<fe.what()<<"), falling back"<<endl;
1406    }
1407    catch(...) {
1408      L<<Logger::Error<<"Non-fatal error initializing possible multiplexer"<<endl;
1409    }
1410  }
1411  L<<Logger::Error<<"No working multiplexer found!"<<endl;
1412  exit(1);
1413}
1414
1415 
1416void* doReloadLuaScript()
1417{
1418  string fname= ::arg()["lua-dns-script"];
1419  try {
1420    if(fname.empty()) {
1421      t_pdl->reset();
1422      L<<Logger::Error<<t_id<<" Unloaded current lua script"<<endl;
1423    }
1424    else {
1425      *t_pdl = shared_ptr<PowerDNSLua>(new PowerDNSLua(fname));
1426    }
1427  }
1428  catch(std::exception& e) {
1429    L<<Logger::Error<<t_id<<" Retaining current script, error from '"<<fname<<"': "<< e.what() <<endl;
1430  }
1431   
1432  L<<Logger::Warning<<t_id<<" (Re)loaded lua script from '"<<fname<<"'"<<endl;
1433  return 0;
1434}
1435
1436string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end)
1437{
1438  if(begin != end) 
1439    ::arg().set("lua-dns-script") = *begin;
1440 
1441  broadcastFunction(doReloadLuaScript);
1442 
1443  return "ok, reload/unload queued\n";
1444} 
1445
1446void* recursorThread(void*);
1447
1448void* pleaseSupplantACLs(NetmaskGroup *ng)
1449{
1450  t_allowFrom = ng;
1451  return 0;
1452}
1453
1454void parseACLs()
1455{
1456  static bool l_initialized;
1457 
1458  if(l_initialized) { // only reload configuration file on second call
1459    string configname=::arg()["config-dir"]+"/recursor.conf";
1460    cleanSlashes(configname);
1461   
1462    if(!::arg().preParseFile(configname.c_str(), "allow-from-file")) 
1463      L<<Logger::Warning<<"Unable to re-parse configuration file '"<<configname<<"'"<<endl;
1464   
1465    ::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS);
1466  }
1467
1468  NetmaskGroup* oldAllowFrom = t_allowFrom, *allowFrom=new NetmaskGroup;
1469 
1470  if(!::arg()["allow-from-file"].empty()) {
1471    string line;
1472    ifstream ifs(::arg()["allow-from-file"].c_str());
1473    if(!ifs) {
1474      delete allowFrom; 
1475      throw AhuException("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
1476    }
1477
1478    string::size_type pos;
1479    while(getline(ifs,line)) {
1480      pos=line.find('#');
1481      if(pos!=string::npos)
1482        line.resize(pos);
1483      trim(line);
1484      if(line.empty())
1485        continue;
1486
1487      allowFrom->addMask(line);
1488    }
1489    L<<Logger::Warning<<"Done parsing " << allowFrom->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl;
1490  }
1491  else if(!::arg()["allow-from"].empty()) {
1492    vector<string> ips;
1493    stringtok(ips, ::arg()["allow-from"], ", ");
1494    L<<Logger::Warning<<"Only allowing queries from: ";
1495    for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
1496      allowFrom->addMask(*i);
1497      if(i!=ips.begin())
1498        L<<Logger::Warning<<", ";
1499      L<<Logger::Warning<<*i;
1500    }
1501    L<<Logger::Warning<<endl;
1502  }
1503  else {
1504    if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53) 
1505      L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl;
1506    delete allowFrom;
1507    allowFrom = 0;
1508  }
1509 
1510  g_initialAllowFrom = allowFrom;
1511  broadcastFunction(boost::bind(pleaseSupplantACLs, allowFrom));
1512  delete oldAllowFrom;
1513 
1514  l_initialized = true;
1515}
1516
1517int serviceMain(int argc, char*argv[])
1518{
1519  L.setName("pdns_recursor");
1520
1521  L.setLoglevel((Logger::Urgency)(6)); // info and up
1522
1523  if(!::arg()["logging-facility"].empty()) {
1524    boost::optional<int> val=logFacilityToLOG(::arg().asNum("logging-facility") );
1525    if(val)
1526      theL().setFacility(*val);
1527    else
1528      L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
1529  }
1530
1531  L<<Logger::Warning<<"PowerDNS recursor "<<VERSION<<" (C) 2001-2010 PowerDNS.COM BV ("<<__DATE__", "__TIME__;
1532#ifdef __GNUC__
1533  L<<", gcc "__VERSION__;
1534#endif // add other compilers here
1535#ifdef _MSC_VER
1536  L<<", MSVC "<<_MSC_VER;
1537#endif
1538  L<<") starting up"<<endl;
1539 
1540  L<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
1541    "This is free software, and you are welcome to redistribute it "
1542    "according to the terms of the GPL version 2."<<endl;
1543 
1544  L<<Logger::Warning<<"Operating in "<<(sizeof(unsigned long)*8) <<" bits mode"<<endl;
1545 
1546  #if 0
1547  unsigned int maxFDs, curFDs;
1548  getFDLimits(curFDs, maxFDs);
1549  if(curFDs < 2048)
1550    L<<Logger::Warning<<"Only "<<curFDs<<" file descriptors available (out of: "<<maxFDs<<"), may not be suitable for high performance"<<endl;
1551  #endif
1552 
1553  seedRandom(::arg()["entropy-source"]);
1554
1555  parseACLs();
1556 
1557  if(!::arg()["dont-query"].empty()) {
1558    g_dontQuery=new NetmaskGroup;
1559    vector<string> ips;
1560    stringtok(ips, ::arg()["dont-query"], ", ");
1561    L<<Logger::Warning<<"Will not send queries to: ";
1562    for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
1563      g_dontQuery->addMask(*i);
1564      if(i!=ips.begin())
1565        L<<Logger::Warning<<", ";
1566      L<<Logger::Warning<<*i;
1567    }
1568    L<<Logger::Warning<<endl;
1569  }
1570
1571  g_quiet=::arg().mustDo("quiet");
1572  if(::arg().mustDo("trace")) {
1573    SyncRes::setLog(true);
1574    ::arg().set("quiet")="no";
1575    g_quiet=false;
1576  }
1577 
1578  try {
1579    vector<string> addrs; 
1580    if(!::arg()["query-local-address6"].empty()) {
1581      SyncRes::s_doIPv6=true;
1582      L<<Logger::Error<<"Enabling IPv6 transport for outgoing queries"<<endl;
1583     
1584      stringtok(addrs, ::arg()["query-local-address6"], ", ;");
1585      BOOST_FOREACH(const string& addr, addrs) {
1586        g_localQueryAddresses6.push_back(ComboAddress(addr));
1587      }
1588    }
1589    addrs.clear();
1590    stringtok(addrs, ::arg()["query-local-address"], ", ;");
1591    BOOST_FOREACH(const string& addr, addrs) {
1592      g_localQueryAddresses4.push_back(ComboAddress(addr));
1593    }
1594  }
1595  catch(std::exception& e) {
1596    L<<Logger::Error<<"Assigning local query addresses: "<<e.what();
1597    exit(99);
1598  }
1599 
1600  SyncRes::s_noEDNSPing = ::arg().mustDo("disable-edns-ping");
1601  SyncRes::s_noEDNS = ::arg().mustDo("disable-edns");
1602
1603  SyncRes::s_nopacketcache = ::arg().mustDo("disable-packetcache");
1604
1605  SyncRes::s_maxnegttl=::arg().asNum("max-negative-ttl");
1606  SyncRes::s_maxcachettl=::arg().asNum("max-cache-ttl");
1607  SyncRes::s_packetcachettl=::arg().asNum("packetcache-ttl");
1608  SyncRes::s_packetcacheservfailttl=::arg().asNum("packetcache-servfail-ttl");
1609  SyncRes::s_serverID=::arg()["server-id"];
1610  if(SyncRes::s_serverID.empty()) {
1611    char tmp[128];
1612    gethostname(tmp, sizeof(tmp)-1);
1613    SyncRes::s_serverID=tmp;
1614  }
1615 
1616  g_networkTimeoutMsec = ::arg().asNum("network-timeout");
1617
1618  g_initialDomainMap = parseAuthAndForwards();
1619 
1620  //  g_stats.remotes.resize(::arg().asNum("remotes-ringbuffer-entries")); XXX FIXME NEEDS TO BE REDONE FOR "MULTITHREADING"
1621  if(!g_stats.remotes.empty())
1622    memset(&g_stats.remotes[0], 0, g_stats.remotes.size() * sizeof(RecursorStats::remotes_t::value_type));
1623  g_logCommonErrors=::arg().mustDo("log-common-errors");
1624 
1625  makeUDPServerSockets();
1626  makeTCPServerSockets();
1627
1628  s_pidfname=::arg()["socket-dir"]+"/"+s_programname+".pid";
1629  if(!s_pidfname.empty())
1630    unlink(s_pidfname.c_str()); // remove possible old pid file
1631 
1632#ifndef WIN32
1633  if(::arg().mustDo("fork")) {
1634    fork();
1635    L<<Logger::Warning<<"This is forked pid "<<getpid()<<endl;
1636  }
1637#endif
1638
1639#ifndef WIN32
1640  if(::arg().mustDo("daemon")) {
1641    L<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
1642    L.toConsole(Logger::Critical);
1643    daemonize();
1644  }
1645  signal(SIGUSR1,usr1Handler);
1646  signal(SIGUSR2,usr2Handler);
1647  signal(SIGPIPE,SIG_IGN);
1648  writePid();
1649#endif
1650  makeControlChannelSocket();       
1651  g_numThreads = ::arg().asNum("threads");
1652 
1653  makeThreadPipes();
1654 
1655  g_tcpTimeout=::arg().asNum("client-tcp-timeout");
1656  g_maxTCPPerClient=::arg().asNum("max-tcp-per-client");
1657  g_maxMThreads=::arg().asNum("max-mthreads");
1658
1659  if(g_numThreads == 1) {
1660    L<<Logger::Warning<<"Operating unthreaded"<<endl;
1661    recursorThread(0);
1662  }
1663  else {
1664    pthread_t tid;
1665    L<<Logger::Warning<<"Launching "<< g_numThreads <<" threads"<<endl;
1666    for(unsigned int n=0; n < g_numThreads; ++n) {
1667      pthread_create(&tid, 0, recursorThread, (void*)n);
1668    }
1669    void* res;
1670
1671   
1672    pthread_join(tid, &res);
1673  }
1674  return 0;
1675}
1676
1677void* recursorThread(void* ptr)
1678try
1679{
1680  t_id=(int) (long) ptr;
1681  SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so..
1682  SyncRes::t_sstorage->domainmap = g_initialDomainMap;
1683  t_allowFrom = g_initialAllowFrom;
1684  t_udpclientsocks = new UDPClientSocks();
1685  primeHints();
1686 
1687  t_packetCache = new RecursorPacketCache();
1688 
1689  L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
1690   
1691  t_RC->d_followRFC2181=::arg().mustDo("auth-can-lower-ttl");
1692  t_pdl = new shared_ptr<PowerDNSLua>();
1693 
1694  try {
1695    if(!::arg()["lua-dns-script"].empty()) {
1696      *t_pdl = shared_ptr<PowerDNSLua>(new PowerDNSLua(::arg()["lua-dns-script"]));
1697      L<<Logger::Warning<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl;
1698    }
1699   
1700  }
1701  catch(std::exception &e) {
1702    L<<Logger::Error<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e.what()<<endl;
1703    exit(99);
1704  }
1705 
1706  MT=new MTasker<PacketID,string>(::arg().asNum("stack-size"));
1707 
1708  PacketID pident;
1709
1710  t_fdm=getMultiplexer();
1711  if(!t_id) 
1712    L<<Logger::Error<<"Enabled '"<< t_fdm->getName() << "' multiplexer"<<endl;
1713
1714  t_fdm->addReadFD(g_pipes[t_id].readToThread, handlePipeRequest);
1715
1716  for(deferredAdd_t::const_iterator i=deferredAdd.begin(); i!=deferredAdd.end(); ++i) 
1717    t_fdm->addReadFD(i->first, i->second);
1718 
1719  if(!t_id) {
1720    int newgid=0;
1721    if(!::arg()["setgid"].empty())
1722      newgid=Utility::makeGidNumeric(::arg()["setgid"]);
1723    int newuid=0;
1724    if(!::arg()["setuid"].empty())
1725      newuid=Utility::makeUidNumeric(::arg()["setuid"]);
1726 
1727#ifndef WIN32
1728    if (!::arg()["chroot"].empty()) {
1729      if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
1730        L<<Logger::Error<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno)<<", exiting"<<endl;
1731        exit(1);
1732      }
1733    }
1734 
1735    Utility::dropPrivs(newuid, newgid);
1736 
1737    t_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel
1738  }
1739#endif
1740 
1741  unsigned int maxTcpClients=::arg().asNum("max-tcp-clients");
1742 
1743  bool listenOnTCP(true);
1744
1745  counter=0; // used to periodically execute certain tasks
1746  for(;;) {
1747    while(MT->schedule(&g_now)); // housekeeping, let threads do their thing
1748     
1749    if(!(counter%500)) {
1750      MT->makeThread(houseKeeping, 0);
1751    }
1752
1753    if(!(counter%55)) {
1754      typedef vector<pair<int, FDMultiplexer::funcparam_t> > expired_t;
1755      expired_t expired=t_fdm->getTimeouts(g_now);
1756       
1757      for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) {
1758        TCPConnection conn=any_cast<TCPConnection>(i->second);
1759        if(g_logCommonErrors)
1760          L<<Logger::Warning<<"Timeout from remote TCP client "<< conn.remote.toString() <<endl;
1761        t_fdm->removeReadFD(i->first);
1762        conn.closeAndCleanup();
1763      }
1764    }
1765     
1766    counter++;
1767
1768    if(!t_id && statsWanted) {
1769      doStats();
1770    }
1771
1772    Utility::gettimeofday(&g_now, 0);
1773    t_fdm->run(&g_now);
1774    // 'run' updates g_now for us
1775
1776    if(listenOnTCP) {
1777      if(TCPConnection::s_currentConnections > maxTcpClients) {  // shutdown, too many connections
1778        for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
1779          t_fdm->removeReadFD(*i);
1780        listenOnTCP=false;
1781      }
1782    }
1783    else {
1784      if(TCPConnection::s_currentConnections <= maxTcpClients) {  // reenable
1785        for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
1786          t_fdm->addReadFD(*i, handleNewTCPQuestion);
1787        listenOnTCP=true;
1788      }
1789    }
1790  }
1791}
1792catch(AhuException &ae) {
1793  L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
1794  return 0;
1795}
1796catch(std::exception &e) {
1797   L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
1798   return 0;
1799}
1800catch(...) {
1801   L<<Logger::Error<<"any other exception in main: "<<endl;
1802   return 0;
1803}
1804
1805#ifdef WIN32
1806void doWindowsServiceArguments(RecursorService& recursor)
1807{
1808  if(::arg().mustDo( "register-service" )) {
1809    if ( !recursor.registerService( "The PowerDNS Recursor.", true )) {
1810      cerr << "Could not register service." << endl;
1811      exit( 99 );
1812    }
1813   
1814    exit( 0 );
1815  }
1816
1817  if ( ::arg().mustDo( "unregister-service" )) {
1818    recursor.unregisterService();
1819    exit( 0 );
1820  }
1821}
1822#endif
1823
1824
1825int main(int argc, char **argv) 
1826{
1827  g_stats.startupTime=time(0);
1828  reportBasicTypes();
1829
1830  int ret = EXIT_SUCCESS;
1831#ifdef WIN32
1832  RecursorService service;
1833  WSADATA wsaData;
1834  if(WSAStartup( MAKEWORD( 2, 2 ), &wsaData )) {
1835    cerr<<"Unable to initialize winsock\n";
1836    exit(1);
1837  }
1838#endif // WIN32
1839
1840  try {
1841    ::arg().set("stack-size","stack size per mthread")="200000";
1842    ::arg().set("soa-minimum-ttl","Don't change")="0";
1843    ::arg().set("soa-serial-offset","Don't change")="0";
1844    ::arg().set("no-shuffle","Don't change")="off";
1845    ::arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
1846    ::arg().set("local-port","port to listen on")="53";
1847    ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
1848    ::arg().set("trace","if we should output heaps of logging")="off";
1849    ::arg().set("daemon","Operate as a daemon")="yes";
1850    ::arg().set("log-common-errors","If we should log rather common errors")="yes";
1851    ::arg().set("chroot","switch to chroot jail")="";
1852    ::arg().set("setgid","If set, change group id to this gid for more security")="";
1853    ::arg().set("setuid","If set, change user id to this uid for more security")="";
1854    ::arg().set("network-timeout", "Wait this nummer of milliseconds for network i/o")="1500";
1855    ::arg().set("threads", "Launch this number of threads")="2";
1856#ifdef WIN32
1857    ::arg().set("quiet","Suppress logging of questions and answers")="off";
1858    ::arg().setSwitch( "register-service", "Register the service" )= "no";
1859    ::arg().setSwitch( "unregister-service", "Unregister the service" )= "no";
1860    ::arg().setSwitch( "ntservice", "Run as service" )= "no";
1861    ::arg().setSwitch( "use-ntlog", "Use the NT logging facilities" )= "yes"; 
1862    ::arg().setSwitch( "use-logfile", "Use a log file" )= "no"; 
1863    ::arg().setSwitch( "logfile", "Filename of the log file" )= "recursor.log"; 
1864#else
1865    ::arg().set("quiet","Suppress logging of questions and answers")="";
1866    ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
1867#endif
1868    ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
1869#ifndef WIN32
1870    ::arg().set("socket-owner","Owner of socket")="";
1871    ::arg().set("socket-group","Group of socket")="";
1872    ::arg().set("socket-mode", "Permissions for socket")="";
1873#endif
1874   
1875    ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
1876    ::arg().set("delegation-only","Which domains we only accept delegations from")="";
1877    ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
1878    ::arg().set("query-local-address6","Source IPv6 address for sending queries")="";
1879    ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
1880    ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
1881    ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
1882    ::arg().set("hint-file", "If set, load root hints from this file")="";
1883    ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
1884    ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
1885    ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
1886    ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
1887    ::arg().set("max-packetcache-entries", "maximum number of seconds to keep a cached entry in packetcache")="500000";
1888    ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
1889    ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
1890    ::arg().set("remotes-ringbuffer-entries", "maximum number of packets to store statistics for")="0";
1891    ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Recursor "VERSION" $Id$";
1892    ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS;
1893    ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
1894    ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
1895    ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=LOCAL_NETS; 
1896    ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
1897    ::arg().set("fork", "If set, fork the daemon for possible double performance")="no";
1898    ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
1899    ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
1900    ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
1901    ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
1902    ::arg().set("forward-zones-recurse", "Zones for which we forward queries, comma separated domain=ip pairs")="";
1903    ::arg().set("forward-zones-file", "File with domain=ip pairs for forwarding")="";
1904    ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
1905    ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
1906    ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
1907    ::arg().set("auth-can-lower-ttl", "If we follow RFC 2181 to the letter, an authoritative server can lower the TTL of NS records")="off";
1908    ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
1909    ::arg().setSwitch( "ignore-rd-bit", "Assume each packet requires recursion, for compatability" )= "off"; 
1910    ::arg().setSwitch( "disable-edns-ping", "Disable EDNSPing" )= "no"; 
1911    ::arg().setSwitch( "disable-edns", "Disable EDNS" )= ""; 
1912    ::arg().setSwitch( "disable-packetcache", "Disable packetcahe" )= "no"; 
1913
1914    ::arg().setCmd("help","Provide a helpful message");
1915    ::arg().setCmd("version","Print version string ("VERSION")");
1916    ::arg().setCmd("config","Output blank configuration");
1917    L.toConsole(Logger::Info);
1918    ::arg().laxParse(argc,argv); // do a lax parse
1919
1920    string configname=::arg()["config-dir"]+"/recursor.conf";
1921    cleanSlashes(configname);
1922
1923    if(!::arg().file(configname.c_str())) 
1924      L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
1925
1926    ::arg().parse(argc,argv);
1927
1928    ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
1929
1930    if(::arg().mustDo("help")) {
1931      cerr<<"syntax:"<<endl<<endl;
1932      cerr<<::arg().helpstring(::arg()["help"])<<endl;
1933      exit(99);
1934    }
1935    if(::arg().mustDo("version")) {
1936      cerr<<"version: "VERSION<<endl;
1937      exit(99);
1938    }
1939
1940    if(::arg().mustDo("config")) {
1941      cout<<::arg().configstring()<<endl;
1942      exit(0);
1943    }
1944
1945
1946#ifndef WIN32
1947    serviceMain(argc, argv);
1948#else
1949    doWindowsServiceArguments(service);
1950        L.toNTLog();
1951    RecursorService::instance()->start( argc, argv, ::arg().mustDo( "ntservice" )); 
1952#endif
1953
1954  }
1955  catch(AhuException &ae) {
1956    L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
1957    ret=EXIT_FAILURE;
1958  }
1959  catch(std::exception &e) {
1960    L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
1961    ret=EXIT_FAILURE;
1962  }
1963  catch(...) {
1964    L<<Logger::Error<<"any other exception in main: "<<endl;
1965    ret=EXIT_FAILURE;
1966  }
1967 
1968#ifdef WIN32
1969  WSACleanup();
1970#endif // WIN32
1971
1972  return ret;
1973}
Note: See TracBrowser for help on using the browser.