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