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