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