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