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

Revision 934, 56.2 KB (checked in by ahu, 6 years ago)

some more stats

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