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

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

implement explicit (configurable) limit to number of mthreads - we are usually implicitly limited, this is no change of behaviour for almost all setups

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