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