]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/pdns_recursor.cc
add ipfilter() lua hook, document it and also preoutquery. Cache which lua functions...
[thirdparty/pdns.git] / pdns / pdns_recursor.cc
CommitLineData
288f4aa9
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
4e9a20e6 3 Copyright (C) 2003 - 2014 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;
d7dae798 124struct 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
c3828c03
BH
130unsigned int g_numThreads;
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, "<<
18af64a8 740 sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<<res<<endl;
c75a6a9e 741 }
b23b8614 742
49a699c4 743 sr.d_outqueries ? t_RC->cacheMisses++ : t_RC->cacheHits++;
fe213470
BH
744 float spent=makeFloat(sr.d_now-dc->d_now);
745 if(spent < 0.001)
746 g_stats.answers0_1++;
747 else if(spent < 0.010)
748 g_stats.answers1_10++;
749 else if(spent < 0.1)
750 g_stats.answers10_100++;
751 else if(spent < 1.0)
752 g_stats.answers100_1000++;
753 else
754 g_stats.answersSlow++;
755
574af7ea 756 uint64_t newLat=(uint64_t)(spent*1000000);
08f3f638 757 newLat = min(newLat,(uint64_t)(g_networkTimeoutMsec*1000)); // outliers of several minutes exist..
758 g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + (float)newLat/g_latencyStatSize;
0a6b1027 759 // no worries, we do this for packet cache hits elsewhere
c6d04bdc 760 // cout<<dc->d_mdp.d_qname<<"\t"<<MT->getUsec()<<"\t"<<sr.d_outqueries<<endl;
ea634573 761 delete dc;
c36bc97a 762 dc=0;
288f4aa9 763 }
3f81d239 764 catch(PDNSException &ae) {
a903b39c 765 L<<Logger::Error<<"startDoResolve problem "<<makeLoginfo(dc)<<": "<<ae.reason<<endl;
c36bc97a 766 delete dc;
288f4aa9 767 }
7b1469bb 768 catch(MOADNSException& e) {
a903b39c 769 L<<Logger::Error<<"DNS parser error "<<makeLoginfo(dc) <<": "<<dc->d_mdp.d_qname<<", "<<e.what()<<endl;
c36bc97a 770 delete dc;
7b1469bb 771 }
fdbf35ac 772 catch(std::exception& e) {
a903b39c 773 L<<Logger::Error<<"STL error "<< makeLoginfo(dc)<<": "<<e.what()<<endl;
c36bc97a 774 delete dc;
c154c8a4 775 }
288f4aa9 776 catch(...) {
a903b39c 777 L<<Logger::Error<<"Any other exception in a resolver context "<< makeLoginfo(dc) <<endl;
288f4aa9 778 }
ec6eacbc
BH
779
780 g_stats.maxMThreadStackUsage = max(MT->getMaxStackUsage(), g_stats.maxMThreadStackUsage);
288f4aa9
BH
781}
782
677e2a46 783void makeControlChannelSocket(int processNum=-1)
1d5b3ce6 784{
2d733c0f 785 string sockname=::arg()["socket-dir"]+"/"+s_programname;
677e2a46
BH
786 if(processNum >= 0)
787 sockname += "."+lexical_cast<string>(processNum);
788 sockname+=".controlsocket";
41f7a068 789 s_rcc.listen(sockname);
387de317 790
387de317
BH
791 int sockowner = -1;
792 int sockgroup = -1;
793
794 if (!::arg().isEmpty("socket-group"))
795 sockgroup=::arg().asGid("socket-group");
796 if (!::arg().isEmpty("socket-owner"))
797 sockowner=::arg().asUid("socket-owner");
798
f838ad8d
BH
799 if (sockgroup > -1 || sockowner > -1) {
800 if(chown(sockname.c_str(), sockowner, sockgroup) < 0) {
801 unixDie("Failed to chown control socket");
802 }
803 }
387de317
BH
804
805 // do mode change if socket-mode is given
806 if(!::arg().isEmpty("socket-mode")) {
807 mode_t sockmode=::arg().asMode("socket-mode");
808 chmod(sockname.c_str(), sockmode);
809 }
1d5b3ce6
BH
810}
811
d8f6d49f 812void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 813{
cd989c87 814 shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(var);
c038218b 815
879b3f70 816 if(conn->state==TCPConnection::BYTE0) {
cd989c87 817 int bytes=recv(conn->getFD(), conn->data, 2, 0);
09e6702a 818 if(bytes==1)
667f7e60 819 conn->state=TCPConnection::BYTE1;
09e6702a 820 if(bytes==2) {
a0aa4f64 821 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
667f7e60
BH
822 conn->bytesread=0;
823 conn->state=TCPConnection::GETQUESTION;
09e6702a
BH
824 }
825 if(!bytes || bytes < 0) {
bb4bdbaf 826 t_fdm->removeReadFD(fd);
09e6702a
BH
827 return;
828 }
829 }
667f7e60 830 else if(conn->state==TCPConnection::BYTE1) {
cd989c87 831 int bytes=recv(conn->getFD(), conn->data+1, 1, 0);
09e6702a 832 if(bytes==1) {
667f7e60 833 conn->state=TCPConnection::GETQUESTION;
a0aa4f64 834 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
667f7e60 835 conn->bytesread=0;
09e6702a
BH
836 }
837 if(!bytes || bytes < 0) {
838 if(g_logCommonErrors)
cd989c87 839 L<<Logger::Error<<"TCP client "<< conn->d_remote.toString() <<" disconnected after first byte"<<endl;
bb4bdbaf 840 t_fdm->removeReadFD(fd);
09e6702a
BH
841 return;
842 }
843 }
667f7e60 844 else if(conn->state==TCPConnection::GETQUESTION) {
cd989c87 845 int bytes=recv(conn->getFD(), conn->data + conn->bytesread, conn->qlen - conn->bytesread, 0);
09e6702a 846 if(!bytes || bytes < 0) {
cd989c87 847 L<<Logger::Error<<"TCP client "<< conn->d_remote.toString() <<" disconnected while reading question body"<<endl;
bb4bdbaf 848 t_fdm->removeReadFD(fd);
09e6702a
BH
849 return;
850 }
667f7e60
BH
851 conn->bytesread+=bytes;
852 if(conn->bytesread==conn->qlen) {
bb4bdbaf 853 t_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read
879b3f70 854
09e6702a
BH
855 DNSComboWriter* dc=0;
856 try {
cd989c87 857 dc=new DNSComboWriter(conn->data, conn->qlen, g_now);
09e6702a
BH
858 }
859 catch(MOADNSException &mde) {
4957a608
BH
860 g_stats.clientParseError++;
861 if(g_logCommonErrors)
cd989c87 862 L<<Logger::Error<<"Unable to parse packet from TCP client "<< conn->d_remote.toString() <<endl;
4957a608 863 return;
09e6702a 864 }
cd989c87
BH
865 dc->d_tcpConnection = conn; // carry the torch
866 dc->setSocket(conn->getFD()); // this is the only time a copy is made of the actual fd
09e6702a 867 dc->d_tcp=true;
cd989c87 868 dc->setRemote(&conn->d_remote);
879b3f70 869 if(dc->d_mdp.d_header.qr) {
4957a608
BH
870 delete dc;
871 L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
4957a608 872 return;
879b3f70 873 }
3abcdab2
PD
874 if(dc->d_mdp.d_header.opcode) {
875 delete dc;
876 L<<Logger::Error<<"Ignoring non-query opcode on server socket!"<<endl;
877 return;
878 }
09e6702a 879 else {
4957a608
BH
880 ++g_stats.qcounter;
881 ++g_stats.tcpqcounter;
50a5ef72 882 MT->makeThread(startDoResolve, dc); // deletes dc, will set state to BYTE0 again
4957a608 883 return;
09e6702a
BH
884 }
885 }
886 }
887}
888
6dcd28c3 889//! Handle new incoming TCP connection
d8f6d49f 890void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& )
09e6702a 891{
37d3f960 892 ComboAddress addr;
09e6702a 893 socklen_t addrlen=sizeof(addr);
705f31ae 894 int newsock=(int)accept(fd, (struct sockaddr*)&addr, &addrlen);
09e6702a 895 if(newsock>0) {
85c32340
BH
896 if(MT->numProcesses() > g_maxMThreads) {
897 g_stats.overCapacityDrops++;
898 Utility::closesocket(newsock);
899 return;
900 }
901
92011b8f 902 if(t_remotes)
903 t_remotes->push_back(addr);
49a699c4 904 if(t_allowFrom && !t_allowFrom->match(&addr)) {
2914b022 905 if(!g_quiet)
4957a608 906 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping TCP query from "<<addr.toString()<<", address not matched by allow-from"<<endl;
2914b022 907
09e6702a 908 g_stats.unauthorizedTCP++;
705f31ae 909 Utility::closesocket(newsock);
09e6702a
BH
910 return;
911 }
bd0289fc 912 if(g_maxTCPPerClient && t_tcpClientCounts->count(addr) && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) {
09e6702a 913 g_stats.tcpClientOverflow++;
705f31ae 914 Utility::closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
09e6702a
BH
915 return;
916 }
cd989c87 917
09e6702a 918 Utility::setNonBlocking(newsock);
cd989c87
BH
919 shared_ptr<TCPConnection> tc(new TCPConnection(newsock, addr));
920 tc->state=TCPConnection::BYTE0;
921
922 t_fdm->addReadFD(tc->getFD(), handleRunningTCPQuestion, tc);
c038218b 923
0bff046b 924 struct timeval now;
c038218b 925 Utility::gettimeofday(&now, 0);
cd989c87 926 t_fdm->setReadTTD(tc->getFD(), now, g_tcpTimeout);
09e6702a
BH
927 }
928}
2914b022 929
b71b60ee 930string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd)
1bc3c142 931{
b71b60ee 932 struct timeval diff = g_now - tv;
933 double delta=(diff.tv_sec*1000 + diff.tv_usec/1000.0);
934
935 if(delta > 1000.0) {
936 g_stats.tooOldDrops++;
937 return 0;
938 }
939
1bc3c142 940 ++g_stats.qcounter;
d7f10541
BH
941 if(fromaddr.sin4.sin_family==AF_INET6)
942 g_stats.ipv6qcounter++;
1bc3c142
BH
943
944 string response;
945 try {
946 uint32_t age;
947 if(!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(question, g_now.tv_sec, &response, &age)) {
948 if(!g_quiet)
d738f00f 949 L<<Logger::Notice<<t_id<< " question answered from packet cache from "<<fromaddr.toString()<<endl;
92011b8f 950 // t_queryring->push_back("packetcached");
0a6b1027 951
1bc3c142
BH
952 g_stats.packetCacheHits++;
953 SyncRes::s_queries++;
954 ageDNSPacket(response, age);
b71b60ee 955 struct msghdr msgh;
956 struct iovec iov;
957 char cbuf[256];
958 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)response.c_str(), response.length(), const_cast<ComboAddress*>(&fromaddr));
959 if(destaddr.sin4.sin_family) {
b71b60ee 960 addCMsgSrcAddr(&msgh, cbuf, &destaddr);
961 }
962 sendmsg(fd, &msgh, 0);
963
97bee66d
BH
964 if(response.length() >= sizeof(struct dnsheader)) {
965 struct dnsheader dh;
966 memcpy(&dh, response.c_str(), sizeof(dh));
92011b8f 967 updateResponseStats(dh.rcode, fromaddr, response.length(), 0, 0);
97bee66d 968 }
08f3f638 969 g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + 0.0; // we assume 0 usec
1bc3c142
BH
970 return 0;
971 }
972 }
973 catch(std::exception& e) {
974 L<<Logger::Error<<"Error processing or aging answer packet: "<<e.what()<<endl;
975 return 0;
976 }
977
4ea94941 978 if(t_pdl->get()) {
979 if((*t_pdl)->ipfilter(fromaddr, destaddr)) {
980 if(!g_quiet)
981 L<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED question from "<<fromaddr.toStringWithPort()<<" based on policy"<<endl;
982 g_stats.policyDrops++;
983 return 0;
984 }
985 }
986
1bc3c142 987 if(MT->numProcesses() > g_maxMThreads) {
461df9d2 988 if(!g_quiet)
854d44e3 989 L<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED question from "<<fromaddr.toStringWithPort()<<", over capacity"<<endl;
461df9d2 990
1bc3c142
BH
991 g_stats.overCapacityDrops++;
992 return 0;
993 }
994
995 DNSComboWriter* dc = new DNSComboWriter(question.c_str(), question.size(), g_now);
996 dc->setSocket(fd);
997 dc->setRemote(&fromaddr);
b71b60ee 998 dc->setLocal(destaddr);
1bc3c142
BH
999
1000 dc->d_tcp=false;
1001 MT->makeThread(startDoResolve, (void*) dc); // deletes dc
1002 return 0;
1003}
1004
b71b60ee 1005
d8f6d49f 1006void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
5db529f8 1007{
a9af3782 1008 int len;
5db529f8
BH
1009 char data[1500];
1010 ComboAddress fromaddr;
b71b60ee 1011 struct msghdr msgh;
1012 struct iovec iov;
1013 char cbuf[256];
1014
1015 fromaddr.sin6.sin6_family=AF_INET6; // this makes sure fromaddr is big enough
1016 fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), data, sizeof(data), &fromaddr);
1017
bf3b0cec 1018 for(;;)
b71b60ee 1019 if((len=recvmsg(fd, &msgh, 0)) >= 0) {
92011b8f 1020 if(t_remotes)
1021 t_remotes->push_back(fromaddr);
b23b8614 1022
49a699c4 1023 if(t_allowFrom && !t_allowFrom->match(&fromaddr)) {
2914b022 1024 if(!g_quiet)
4957a608 1025 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl;
2914b022 1026
5db529f8 1027 g_stats.unauthorizedUDP++;
a9af3782 1028 return;
5db529f8 1029 }
15c01deb 1030 BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
81859ba5 1031 if(!fromaddr.sin4.sin_port) { // also works for IPv6
1032 if(!g_quiet)
1033 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toStringWithPort()<<", can't deal with port 0"<<endl;
1034
1035 g_stats.clientParseError++; // not quite the best place to put it, but needs to go somewhere
1036 return;
1037 }
5db529f8 1038 try {
b23b8614 1039 dnsheader* dh=(dnsheader*)data;
5db529f8 1040
b23b8614 1041 if(dh->qr) {
4957a608
BH
1042 if(g_logCommonErrors)
1043 L<<Logger::Error<<"Ignoring answer from "<<fromaddr.toString()<<" on server socket!"<<endl;
5db529f8 1044 }
3abcdab2
PD
1045 else if(dh->opcode) {
1046 if(g_logCommonErrors)
1047 L<<Logger::Error<<"Ignoring non-query opcode "<<dh->opcode<<" from "<<fromaddr.toString()<<" on server socket!"<<endl;
1048 }
5db529f8 1049 else {
232f0877 1050 string question(data, len);
b71b60ee 1051 struct timeval tv={0,0};
1052 HarvestTimestamp(&msgh, &tv);
1053 ComboAddress dest;
1054 memset(&dest, 0, sizeof(dest)); // this makes sure we igore this address if not returned by recvmsg above
1055 HarvestDestinationAddress(&msgh, &dest);
232f0877 1056 if(g_weDistributeQueries)
b71b60ee 1057 distributeAsyncFunction(question, boost::bind(doProcessUDPQuestion, question, fromaddr, dest, tv, fd));
232f0877 1058 else
b71b60ee 1059 doProcessUDPQuestion(question, fromaddr, dest, tv, fd);
5db529f8
BH
1060 }
1061 }
1062 catch(MOADNSException& mde) {
1063 g_stats.clientParseError++;
84e66a59 1064 if(g_logCommonErrors)
4957a608 1065 L<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<mde.what()<<endl;
5db529f8
BH
1066 }
1067 }
ac0e821b
BH
1068 else {
1069 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
bf3b0cec 1070 if(errno == EAGAIN)
9326cae1 1071 g_stats.noPacketError++;
bf3b0cec 1072 break;
ac0e821b 1073 }
5db529f8
BH
1074}
1075
1bc3c142 1076
5db529f8
BH
1077typedef vector<pair<int, function< void(int, any&) > > > deferredAdd_t;
1078deferredAdd_t deferredAdd;
1079
f28307ad 1080void makeTCPServerSockets()
9c495589 1081{
37d3f960 1082 int fd;
f28307ad 1083 vector<string>locals;
2e3d8a19 1084 stringtok(locals,::arg()["local-address"]," ,");
9c495589 1085
f28307ad 1086 if(locals.empty())
3f81d239 1087 throw PDNSException("No local address specified");
f28307ad 1088
f28307ad 1089 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
1090 ServiceTuple st;
1091 st.port=::arg().asNum("local-port");
1092 parseService(*i, st);
1093
1094 ComboAddress sin;
1095
f28307ad 1096 memset((char *)&sin,0, sizeof(sin));
37d3f960 1097 sin.sin4.sin_family = AF_INET;
32252594 1098 if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 1099 sin.sin6.sin6_family = AF_INET6;
f71bc087 1100 if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
3f81d239 1101 throw PDNSException("Unable to resolve local address for TCP server on '"+ st.host +"'");
37d3f960
BH
1102 }
1103
1104 fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0);
1105 if(fd<0)
3f81d239 1106 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
f28307ad 1107
a903b39c 1108 Utility::setCloseOnExec(fd);
1109
f28307ad 1110 int tmp=1;
37d3f960 1111 if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
f28307ad 1112 L<<Logger::Error<<"Setsockopt failed for TCP listening socket"<<endl;
c8ddb7c2 1113 exit(1);
f28307ad 1114 }
0dfa94ab 1115 if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
1116 L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
1117 }
1118
c8ddb7c2 1119#ifdef TCP_DEFER_ACCEPT
37d3f960
BH
1120 if(setsockopt(fd, SOL_TCP,TCP_DEFER_ACCEPT,(char*)&tmp,sizeof tmp) >= 0) {
1121 if(i==locals.begin())
4957a608 1122 L<<Logger::Error<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl;
c8ddb7c2
BH
1123 }
1124#endif
1125
32252594 1126 sin.sin4.sin_port = htons(st.port);
37d3f960
BH
1127 int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
1128 if (::bind(fd, (struct sockaddr *)&sin, socklen )<0)
3f81d239 1129 throw PDNSException("Binding TCP server socket for "+ st.host +": "+stringerror());
f28307ad 1130
37d3f960 1131 Utility::setNonBlocking(fd);
49a699c4 1132 setSocketSendBuffer(fd, 65000);
37d3f960 1133 listen(fd, 128);
5db529f8 1134 deferredAdd.push_back(make_pair(fd, handleNewTCPQuestion));
c2136bf0 1135 g_tcpListenSockets.push_back(fd);
84433b79 1136 // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
1137 // - fd is not that which we know here, but returned from accept()
aa136564 1138 if(sin.sin4.sin_family == AF_INET)
32252594 1139 L<<Logger::Error<<"Listening for TCP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 1140 else
32252594 1141 L<<Logger::Error<<"Listening for TCP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 1142 }
9c495589
BH
1143}
1144
f28307ad 1145void makeUDPServerSockets()
288f4aa9 1146{
f28307ad 1147 vector<string>locals;
2e3d8a19 1148 stringtok(locals,::arg()["local-address"]," ,");
288f4aa9 1149
f28307ad 1150 if(locals.empty())
3f81d239 1151 throw PDNSException("No local address specified");
f28307ad 1152
f28307ad 1153 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
1154 ServiceTuple st;
1155 st.port=::arg().asNum("local-port");
1156 parseService(*i, st);
1157
37d3f960 1158 ComboAddress sin;
996c89cc 1159
37d3f960
BH
1160 memset(&sin, 0, sizeof(sin));
1161 sin.sin4.sin_family = AF_INET;
32252594 1162 if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 1163 sin.sin6.sin6_family = AF_INET6;
f71bc087 1164 if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
3f81d239 1165 throw PDNSException("Unable to resolve local address for UDP server on '"+ st.host +"'");
37d3f960
BH
1166 }
1167
bb4bdbaf 1168 int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0);
d3b4137e 1169 if(fd < 0) {
3f81d239 1170 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
d3b4137e 1171 }
b71b60ee 1172 setSocketTimestamps(fd);
0dfa94ab 1173
b71b60ee 1174 if(IsAnyAddress(sin)) {
0dfa94ab 1175 int one=1;
b71b60ee 1176 setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
1177 setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
0dfa94ab 1178 if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) {
1179 L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
1180 }
1181
b71b60ee 1182 }
37d3f960 1183
a903b39c 1184 Utility::setCloseOnExec(fd);
1185
4e9a20e6 1186 setSocketReceiveBuffer(fd, 250000);
32252594 1187 sin.sin4.sin_port = htons(st.port);
37d3f960
BH
1188
1189 int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
1190 if (::bind(fd, (struct sockaddr *)&sin, socklen)<0)
3f81d239 1191 throw PDNSException("Resolver binding to server socket on port "+ lexical_cast<string>(st.port) +" for "+ st.host+": "+stringerror());
f28307ad
BH
1192
1193 Utility::setNonBlocking(fd);
c2136bf0 1194
0aaecd50 1195 deferredAdd.push_back(make_pair(fd, handleNewUDPQuestion));
40a3dd64 1196 g_listenSocketsAddresses[fd]=sin; // this is written to only from the startup thread, not from the workers
aa136564 1197 if(sin.sin4.sin_family == AF_INET)
32252594 1198 L<<Logger::Error<<"Listening for UDP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 1199 else
32252594 1200 L<<Logger::Error<<"Listening for UDP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 1201 }
c836dc19 1202}
caa6eefa 1203
9c495589 1204
c836dc19
BH
1205void daemonize(void)
1206{
1207 if(fork())
1208 exit(0); // bye bye
1209
1210 setsid();
1211
27a5ead5
BH
1212 int i=open("/dev/null",O_RDWR); /* open stdin */
1213 if(i < 0)
1214 L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
1215 else {
1216 dup2(i,0); /* stdin */
1217 dup2(i,1); /* stderr */
1218 dup2(i,2); /* stderr */
1219 close(i);
1220 }
288f4aa9 1221}
caa6eefa 1222
aaacf7f2 1223uint64_t counter;
c75a6a9e
BH
1224bool statsWanted;
1225
1226void usr1Handler(int)
1227{
1228 statsWanted=true;
1229}
ae1b2e98 1230
9170fbaf
BH
1231void usr2Handler(int)
1232{
f1f34cc2 1233 g_quiet= !g_quiet;
1234 SyncRes::setDefaultLogMode(g_quiet ? SyncRes::LogNone : SyncRes::Log);
1235 ::arg().set("quiet")=g_quiet ? "" : "no";
9170fbaf
BH
1236}
1237
c75a6a9e
BH
1238void doStats(void)
1239{
16beeaa4
BH
1240 static time_t lastOutputTime;
1241 static uint64_t lastQueryCount;
d299d4f5 1242
1243 uint64_t cacheHits = broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
1244 uint64_t cacheMisses = broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
16beeaa4 1245
d299d4f5 1246 if(g_stats.qcounter && (cacheHits + cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {
3427fa8a
BH
1247 L<<Logger::Warning<<"stats: "<<g_stats.qcounter<<" questions, "<<
1248 broadcastAccFunction<uint64_t>(pleaseGetCacheSize)<< " cache entries, "<<
1249 broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize)<<" negative entries, "<<
1250 (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<<endl;
1251
1252 L<<Logger::Warning<<"stats: throttle map: "
1253 << broadcastAccFunction<uint64_t>(pleaseGetThrottleSize) <<", ns speeds: "
1254 << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<endl;
70c2c8b1
BH
1255 L<<Logger::Warning<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
1256 L<<Logger::Warning<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
525b8a7c 1257 <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
3427fa8a
BH
1258 L<<Logger::Warning<<"stats: "<<SyncRes::s_tcpoutqueries<<" outgoing tcp connections, "<<
1259 broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries)<<" queries running, "<<SyncRes::s_outgoingtimeouts<<" outgoing timeouts"<<endl;
81883dcc 1260
16beeaa4
BH
1261 //L<<Logger::Warning<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
1262 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
1263
1264 L<<Logger::Warning<<"stats: " << broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize) <<
1265 " packet cache entries, "<<(int)(100.0*broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"<<endl;
1266
1267 time_t now = time(0);
1268 if(lastOutputTime && lastQueryCount && now != lastOutputTime) {
1269 L<<Logger::Warning<<"stats: "<< (SyncRes::s_queries - lastQueryCount) / (now - lastOutputTime) <<" qps (average over "<< (now - lastOutputTime) << " seconds)"<<endl;
1270 }
1271 lastOutputTime = now;
1272 lastQueryCount = SyncRes::s_queries;
c75a6a9e 1273 }
7becf07f 1274 else if(statsWanted)
70c2c8b1 1275 L<<Logger::Warning<<"stats: no stats yet!"<<endl;
7becf07f 1276
c75a6a9e
BH
1277 statsWanted=false;
1278}
c836dc19 1279
29f0b1ce 1280static void houseKeeping(void *)
779828c4 1281try
c836dc19 1282{
d67620e4 1283 static __thread time_t last_stat, last_rootupdate, last_prune, last_secpoll;
8baca3fa 1284 static __thread int cleanCounter=0;
c9e9e5e0 1285 struct timeval now;
c038218b 1286 Utility::gettimeofday(&now, 0);
c9e9e5e0 1287
1a16adf0 1288 // clog<<"* "<<t_id<<" "<<(void*)&last_stat<<"\t"<<(unsigned int)last_stat<<endl;
ac0e821b 1289
c3828c03 1290 if(now.tv_sec - last_prune > (time_t)(5 + t_id)) {
5e4a2466
BH
1291 DTime dt;
1292 dt.setTimeval(now);
49a699c4 1293 t_RC->doPrune(); // this function is local to a thread, so fine anyhow
c3828c03 1294 t_packetCache->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numThreads);
33988bfb 1295
1a16adf0 1296 pruneCollection(t_sstorage->negcache, ::arg().asNum("max-cache-entries") / (g_numThreads * 10), 200);
8baca3fa
BH
1297
1298 if(!((cleanCounter++)%40)) { // this is a full scan!
1299 time_t limit=now.tv_sec-300;
ac0e821b 1300 for(SyncRes::nsspeeds_t::iterator i = t_sstorage->nsSpeeds.begin() ; i!= t_sstorage->nsSpeeds.end(); )
8baca3fa 1301 if(i->second.stale(limit))
ac0e821b 1302 t_sstorage->nsSpeeds.erase(i++);
8baca3fa
BH
1303 else
1304 ++i;
1305 }
7393d6c0 1306// L<<Logger::Warning<<"Spent "<<dt.udiff()/1000<<" msec cleaning"<<endl;
ae1b2e98
BH
1307 last_prune=time(0);
1308 }
ac0e821b 1309
c038218b 1310 if(now.tv_sec - last_rootupdate > 7200) {
c9e9e5e0 1311 SyncRes sr(now);
2188dcc3 1312 sr.setDoEDNS0(true);
ea634573 1313 vector<DNSResourceRecord> ret;
c836dc19
BH
1314
1315 sr.setNoCache();
a9af3782 1316 int res=sr.beginResolve(".", QType(QType::NS), 1, ret);
c836dc19 1317 if(!res) {
854d44e3 1318 L<<Logger::Notice<<"Refreshed . records"<<endl;
c9e9e5e0 1319 last_rootupdate=now.tv_sec;
c836dc19
BH
1320 }
1321 else
1322 L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
1323 }
d67620e4 1324
1325 if(!t_id) {
1326 if(now.tv_sec - last_stat >= 1800) {
1327 doStats();
1328 last_stat=time(0);
1329 }
1330
c0a074d7 1331 if(now.tv_sec - last_secpoll >= 3600) {
18b73338
KM
1332 try {
1333 doSecPoll(&last_secpoll);
1334 }
1335 catch(...) {}
d67620e4 1336 }
1337 }
c836dc19 1338}
3f81d239 1339catch(PDNSException& ae)
779828c4 1340{
c0a074d7 1341 L<<Logger::Error<<"Fatal error in housekeeping thread: "<<ae.reason<<endl;
779828c4
BH
1342 throw;
1343}
d6d5dea7 1344
49a699c4
BH
1345void makeThreadPipes()
1346{
c3828c03 1347 for(unsigned int n=0; n < g_numThreads; ++n) {
49a699c4
BH
1348 struct ThreadPipeSet tps;
1349 int fd[2];
1350 if(pipe(fd) < 0)
1351 unixDie("Creating pipe for inter-thread communications");
1352
1353 tps.readToThread = fd[0];
1354 tps.writeToThread = fd[1];
1355
1356 if(pipe(fd) < 0)
1357 unixDie("Creating pipe for inter-thread communications");
1358 tps.readFromThread = fd[0];
1359 tps.writeFromThread = fd[1];
1360
1361 g_pipes.push_back(tps);
1362 }
1363}
1364
00c9b8c1
BH
1365struct ThreadMSG
1366{
1367 pipefunc_t func;
1368 bool wantAnswer;
1369};
1370
49a699c4
BH
1371void broadcastFunction(const pipefunc_t& func, bool skipSelf)
1372{
49a699c4
BH
1373 unsigned int n = 0;
1374 BOOST_FOREACH(ThreadPipeSet& tps, g_pipes)
1375 {
1376 if(n++ == t_id) {
1377 if(!skipSelf)
1378 func(); // don't write to ourselves!
1379 continue;
1380 }
00c9b8c1
BH
1381
1382 ThreadMSG* tmsg = new ThreadMSG();
1383 tmsg->func = func;
1384 tmsg->wantAnswer = true;
1385 if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg))
49a699c4
BH
1386 unixDie("write to thread pipe returned wrong size or error");
1387
1388 string* resp;
1389 if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
1390 unixDie("read from thread pipe returned wrong size or error");
1391
1392 if(resp) {
1393// cerr <<"got response: " << *resp << endl;
1394 delete resp;
1395 }
1396 }
1397}
06ea9015 1398
1399uint32_t g_disthashseed;
1400void distributeAsyncFunction(const std::string& question, const pipefunc_t& func)
00c9b8c1 1401{
06ea9015 1402 unsigned int hash = hashQuestion(question.c_str(), question.length(), g_disthashseed);
1403 unsigned int target = 1 + (hash % (g_pipes.size()-1));
1404
00c9b8c1
BH
1405 if(target == t_id) {
1406 func();
1407 return;
1408 }
1409 ThreadPipeSet& tps = g_pipes[target];
1410 ThreadMSG* tmsg = new ThreadMSG();
1411 tmsg->func = func;
1412 tmsg->wantAnswer = false;
1413
1414 if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg))
06ea9015 1415 unixDie("write to thread pipe returned wrong size or error");
00c9b8c1 1416}
3427fa8a 1417
49a699c4
BH
1418void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var)
1419{
00c9b8c1
BH
1420 ThreadMSG* tmsg;
1421
1422 if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread
49a699c4
BH
1423 unixDie("read from thread pipe returned wrong size or error");
1424 }
3427fa8a 1425
2f22827a 1426 void *resp=0;
1427 try {
1428 resp = tmsg->func();
1429 }
1430 catch(std::exception& e) {
1431 L<<Logger::Error<<"PIPE function we executed created exception: "<<e.what()<<endl; // but what if they wanted an answer.. we send 0
1432 }
1433 catch(PDNSException& e) {
1434 L<<Logger::Error<<"PIPE function we executed created PDNS exception: "<<e.reason<<endl; // but what if they wanted an answer.. we send 0
1435 }
00c9b8c1
BH
1436 if(tmsg->wantAnswer)
1437 if(write(g_pipes[t_id].writeFromThread, &resp, sizeof(resp)) != sizeof(resp))
1438 unixDie("write to thread pipe returned wrong size or error");
3427fa8a 1439
00c9b8c1 1440 delete tmsg;
49a699c4 1441}
09e6702a 1442
13034931
BH
1443template<class T> void *voider(const boost::function<T*()>& func)
1444{
1445 return func();
1446}
1447
b3b5459d
BH
1448vector<ComboAddress>& operator+=(vector<ComboAddress>&a, const vector<ComboAddress>& b)
1449{
1450 a.insert(a.end(), b.begin(), b.end());
1451 return a;
1452}
1453
92011b8f 1454vector<pair<string, uint16_t> >& operator+=(vector<pair<string, uint16_t> >&a, const vector<pair<string, uint16_t> >& b)
1455{
1456 a.insert(a.end(), b.begin(), b.end());
1457 return a;
1458}
1459
1460
13034931 1461template<class T> T broadcastAccFunction(const boost::function<T*()>& func, bool skipSelf)
3427fa8a
BH
1462{
1463 unsigned int n = 0;
1464 T ret=T();
1465 BOOST_FOREACH(ThreadPipeSet& tps, g_pipes)
1466 {
1467 if(n++ == t_id) {
1468 if(!skipSelf) {
1469 T* resp = (T*)func(); // don't write to ourselves!
1470 if(resp) {
1471 //~ cerr <<"got direct: " << *resp << endl;
1472 ret += *resp;
1473 delete resp;
1474 }
1475 }
1476 continue;
1477 }
1478
00c9b8c1
BH
1479 ThreadMSG* tmsg = new ThreadMSG();
1480 tmsg->func = boost::bind(voider<T>, func);
1481 tmsg->wantAnswer = true;
1482
1483 if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg))
3427fa8a 1484 unixDie("write to thread pipe returned wrong size or error");
00c9b8c1 1485
3427fa8a
BH
1486
1487 T* resp;
1488 if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
1489 unixDie("read from thread pipe returned wrong size or error");
1490
1491 if(resp) {
1492 //~ cerr <<"got response: " << *resp << endl;
1493 ret += *resp;
1494 delete resp;
1495 }
1496 }
1497 return ret;
1498}
1499
13034931
BH
1500template string broadcastAccFunction(const boost::function<string*()>& fun, bool skipSelf); // explicit instantiation
1501template uint64_t broadcastAccFunction(const boost::function<uint64_t*()>& fun, bool skipSelf); // explicit instantiation
b3b5459d 1502template vector<ComboAddress> broadcastAccFunction(const boost::function<vector<ComboAddress> *()>& fun, bool skipSelf); // explicit instantiation
92011b8f 1503template vector<pair<string,uint16_t> > broadcastAccFunction(const boost::function<vector<pair<string, uint16_t> > *()>& fun, bool skipSelf); // explicit instantiation
3427fa8a 1504
d8f6d49f 1505void handleRCC(int fd, FDMultiplexer::funcparam_t& var)
09e6702a
BH
1506{
1507 string remote;
1508 string msg=s_rcc.recv(&remote);
1509 RecursorControlParser rcp;
1510 RecursorControlParser::func_t* command;
77499b05 1511
09e6702a 1512 string answer=rcp.getAnswer(msg, &command);
ab5c053d
BH
1513 try {
1514 s_rcc.send(answer, &remote);
1515 command();
1516 }
fdbf35ac 1517 catch(std::exception& e) {
ab5c053d
BH
1518 L<<Logger::Error<<"Error dealing with control socket request: "<<e.what()<<endl;
1519 }
3f81d239 1520 catch(PDNSException& ae) {
ab5c053d
BH
1521 L<<Logger::Error<<"Error dealing with control socket request: "<<ae.reason<<endl;
1522 }
09e6702a
BH
1523}
1524
d8f6d49f 1525void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 1526{
0b18b22e 1527 PacketID* pident=any_cast<PacketID>(&var);
667f7e60 1528 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
09e6702a 1529
667f7e60 1530 shared_array<char> buffer(new char[pident->inNeeded]);
09e6702a 1531
705f31ae 1532 int ret=recv(fd, buffer.get(), pident->inNeeded,0);
09e6702a 1533 if(ret > 0) {
667f7e60
BH
1534 pident->inMSG.append(&buffer[0], &buffer[ret]);
1535 pident->inNeeded-=ret;
825fa717 1536 if(!pident->inNeeded || pident->inIncompleteOkay) {
667f7e60
BH
1537 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
1538 PacketID pid=*pident;
1539 string msg=pident->inMSG;
09e6702a 1540
bb4bdbaf 1541 t_fdm->removeReadFD(fd);
09e6702a
BH
1542 MT->sendEvent(pid, &msg);
1543 }
1544 else {
667f7e60 1545 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
09e6702a
BH
1546 }
1547 }
1548 else {
667f7e60 1549 PacketID tmp=*pident;
bb4bdbaf 1550 t_fdm->removeReadFD(fd); // pident might now be invalid (it isn't, but still)
09e6702a
BH
1551 string empty;
1552 MT->sendEvent(tmp, &empty); // this conveys error status
1553 }
1554}
1555
d8f6d49f 1556void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 1557{
0b18b22e 1558 PacketID* pid=any_cast<PacketID>(&var);
4ca15bca 1559 int ret=send(fd, pid->outMSG.c_str() + pid->outPos, pid->outMSG.size() - pid->outPos,0);
09e6702a 1560 if(ret > 0) {
667f7e60
BH
1561 pid->outPos+=ret;
1562 if(pid->outPos==pid->outMSG.size()) {
1563 PacketID tmp=*pid;
bb4bdbaf 1564 t_fdm->removeWriteFD(fd);
09e6702a
BH
1565 MT->sendEvent(tmp, &tmp.outMSG); // send back what we sent to convey everything is ok
1566 }
1567 }
1568 else { // error or EOF
667f7e60 1569 PacketID tmp(*pid);
bb4bdbaf 1570 t_fdm->removeWriteFD(fd);
09e6702a 1571 string sent;
998a4334 1572 MT->sendEvent(tmp, &sent); // we convey error status by sending empty string
09e6702a
BH
1573 }
1574}
1575
34801ab1
BH
1576// resend event to everybody chained onto it
1577void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content)
1578{
1579 if(iter->key.chain.empty())
1580 return;
e27e91a8 1581 // cerr<<"doResends called!\n";
34801ab1
BH
1582 for(PacketID::chain_t::iterator i=iter->key.chain.begin(); i != iter->key.chain.end() ; ++i) {
1583 resend.fd=-1;
1584 resend.id=*i;
e27e91a8 1585 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
4665c31e 1586
34801ab1
BH
1587 MT->sendEvent(resend, &content);
1588 g_stats.chainResends++;
34801ab1
BH
1589 }
1590}
1591
d8f6d49f 1592void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 1593{
600fc20b 1594 PacketID pid=any_cast<PacketID>(var);
998a4334 1595 int len;
09e6702a 1596 char data[1500];
996c89cc 1597 ComboAddress fromaddr;
09e6702a
BH
1598 socklen_t addrlen=sizeof(fromaddr);
1599
998a4334 1600 len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);
c1da7976 1601
998a4334
BH
1602 if(len < (int)sizeof(dnsheader)) {
1603 if(len < 0)
996c89cc 1604 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
09e6702a
BH
1605 else {
1606 g_stats.serverParseError++;
1607 if(g_logCommonErrors)
85db02c5 1608 L<<Logger::Error<<"Unable to parse packet from remote UDP server "<< fromaddr.toString() <<
e44d9fa7 1609 ": packet smaller than DNS header"<<endl;
998a4334 1610 }
34801ab1 1611
49a699c4 1612 t_udpclientsocks->returnSocket(fd);
34801ab1
BH
1613 string empty;
1614
1615 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid);
1616 if(iter != MT->d_waiters.end())
1617 doResends(iter, pid, empty);
1618
1619 MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot)
998a4334
BH
1620 return;
1621 }
1622
1623 dnsheader dh;
1624 memcpy(&dh, data, sizeof(dh));
1625
6da3b3ad
PD
1626 PacketID pident;
1627 pident.remote=fromaddr;
1628 pident.id=dh.id;
1629 pident.fd=fd;
34801ab1 1630
33a928af 1631 if(!dh.qr && g_logCommonErrors) {
854d44e3 1632 L<<Logger::Notice<<"Not taking data from question on outgoing socket from "<< fromaddr.toStringWithPort() <<endl;
6da3b3ad
PD
1633 }
1634
1635 if(!dh.qdcount || // UPC, Nominum, very old BIND on FormErr, NSD
1636 !dh.qr) { // one weird server
1637 pident.domain.clear();
1638 pident.type = 0;
1639 }
1640 else {
1641 try {
1642 pident.domain=questionExpand(data, len, pident.type); // don't copy this from above - we need to do the actual read
1643 }
1644 catch(std::exception& e) {
1645 g_stats.serverParseError++; // won't be fed to lwres.cc, so we have to increment
1646 L<<Logger::Warning<<"Error in packet from "<< fromaddr.toStringWithPort() << ": "<<e.what() << endl;
1647 return;
34801ab1 1648 }
6da3b3ad
PD
1649 }
1650 string packet;
1651 packet.assign(data, len);
34801ab1 1652
6da3b3ad
PD
1653 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pident);
1654 if(iter != MT->d_waiters.end()) {
1655 doResends(iter, pident, packet);
1656 }
c1da7976 1657
6da3b3ad 1658retryWithName:
4957a608 1659
6da3b3ad
PD
1660 if(!MT->sendEvent(pident, &packet)) {
1661 // 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
1662 for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) {
1663 if(pident.fd==mthread->key.fd && mthread->key.remote==pident.remote && mthread->key.type == pident.type &&
1664 pdns_iequals(pident.domain, mthread->key.domain)) {
1665 mthread->key.nearMisses++;
998a4334 1666 }
6da3b3ad
PD
1667
1668 // be a bit paranoid here since we're weakening our matching
1669 if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type &&
1670 pident.id == mthread->key.id && mthread->key.remote == pident.remote) {
1671 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
1672 pident.domain = mthread->key.domain;
1673 pident.type = mthread->key.type;
1674 goto retryWithName; // note that this only passes on an error, lwres will still reject the packet
d4fb76e9 1675 }
09e6702a 1676 }
6da3b3ad
PD
1677 g_stats.unexpectedCount++; // if we made it here, it really is an unexpected answer
1678 if(g_logCommonErrors) {
1679 L<<Logger::Warning<<"Discarding unexpected packet from "<<fromaddr.toStringWithPort()<<": "<<pident.domain<<", "<<pident.type<<", "<<MT->d_waiters.size()<<" waiters"<<endl;
d8f6d49f 1680 }
09e6702a 1681 }
6da3b3ad
PD
1682 else if(fd >= 0) {
1683 t_udpclientsocks->returnSocket(fd);
1684 }
09e6702a
BH
1685}
1686
1f4abb20
BH
1687FDMultiplexer* getMultiplexer()
1688{
1689 FDMultiplexer* ret;
1690 for(FDMultiplexer::FDMultiplexermap_t::const_iterator i = FDMultiplexer::getMultiplexerMap().begin();
1691 i != FDMultiplexer::getMultiplexerMap().end(); ++i) {
1692 try {
1693 ret=i->second();
1f4abb20
BH
1694 return ret;
1695 }
98d0ee4a 1696 catch(FDMultiplexerException &fe) {
0a7f24cb 1697 L<<Logger::Error<<"Non-fatal error initializing possible multiplexer ("<<fe.what()<<"), falling back"<<endl;
98d0ee4a
BH
1698 }
1699 catch(...) {
1700 L<<Logger::Error<<"Non-fatal error initializing possible multiplexer"<<endl;
1701 }
1f4abb20
BH
1702 }
1703 L<<Logger::Error<<"No working multiplexer found!"<<endl;
1704 exit(1);
1705}
1706
5605c067 1707
0f39c1a3 1708string* doReloadLuaScript()
4485aa35 1709{
674cf0f6 1710 string fname= ::arg()["lua-dns-script"];
4485aa35 1711 try {
674cf0f6
BH
1712 if(fname.empty()) {
1713 t_pdl->reset();
1714 L<<Logger::Error<<t_id<<" Unloaded current lua script"<<endl;
0f39c1a3 1715 return new string("unloaded\n");
4485aa35
BH
1716 }
1717 else {
5704e107 1718 *t_pdl = shared_ptr<RecursorLua>(new RecursorLua(fname));
4485aa35
BH
1719 }
1720 }
fdbf35ac 1721 catch(std::exception& e) {
674cf0f6 1722 L<<Logger::Error<<t_id<<" Retaining current script, error from '"<<fname<<"': "<< e.what() <<endl;
0f39c1a3 1723 return new string("retaining current script, error from '"+fname+"': "+e.what()+"\n");
4485aa35 1724 }
674cf0f6
BH
1725
1726 L<<Logger::Warning<<t_id<<" (Re)loaded lua script from '"<<fname<<"'"<<endl;
0f39c1a3 1727 return new string("(re)loaded '"+fname+"'\n");
4485aa35
BH
1728}
1729
49a699c4
BH
1730string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end)
1731{
1732 if(begin != end)
1733 ::arg().set("lua-dns-script") = *begin;
1734
0f39c1a3 1735 return broadcastAccFunction<string>(doReloadLuaScript);
49a699c4
BH
1736}
1737
77499b05
BH
1738string* pleaseUseNewTraceRegex(const std::string& newRegex)
1739try
1740{
1741 if(newRegex.empty()) {
1742 t_traceRegex->reset();
1743 return new string("unset\n");
1744 }
1745 else {
1746 (*t_traceRegex) = shared_ptr<Regex>(new Regex(newRegex));
1747 return new string("ok\n");
1748 }
1749}
3f81d239 1750catch(PDNSException& ae)
77499b05
BH
1751{
1752 return new string(ae.reason+"\n");
1753}
1754
1755string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end)
1756{
1757 return broadcastAccFunction<string>(boost::bind(pleaseUseNewTraceRegex, begin!=end ? *begin : ""));
1758}
1759
4e9a20e6 1760static void checkLinuxIPv6Limits()
1761{
1762#ifdef __linux__
1763 string line;
1764 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line)) {
1765 int lim=atoi(line.c_str());
1766 if(lim < 16384) {
36849ff2 1767 L<<Logger::Error<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim<<" which is < 16384"<<endl;
4e9a20e6 1768 }
1769 }
1770#endif
1771}
36849ff2 1772static void checkOrFixFDS()
4e9a20e6 1773{
36849ff2 1774 unsigned int availFDs=getFilenumLimit();
1775 if(g_maxMThreads * g_numThreads > availFDs) {
1776 if(getFilenumLimit(true) >= g_maxMThreads * g_numThreads) {
1777 setFilenumLimit(g_maxMThreads * g_numThreads);
1778 L<<Logger::Warning<<"Raised soft limit on number of filedescriptors to "<<g_maxMThreads * g_numThreads<<" to match max-mthreads and threads settings"<<endl;
1779 }
1780 else {
1781 int newval = getFilenumLimit(true) / g_numThreads;
1782 L<<Logger::Warning<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<availFDs<<" < "<<g_maxMThreads*g_numThreads<<"), reducing max-mthreads to "<<newval<<endl;
1783 g_maxMThreads = newval;
1784 setFilenumLimit(g_maxMThreads * g_numThreads);
1785 }
1786 }
1787
4e9a20e6 1788}
77499b05 1789
bb4bdbaf 1790void* recursorThread(void*);
51e2144e 1791
3427fa8a 1792void* pleaseSupplantACLs(NetmaskGroup *ng)
49a699c4
BH
1793{
1794 t_allowFrom = ng;
3427fa8a 1795 return 0;
49a699c4
BH
1796}
1797
dbd23fc2
BH
1798int g_argc;
1799char** g_argv;
1800
18af64a8 1801void parseACLs()
f7c1d4e3 1802{
18af64a8 1803 static bool l_initialized;
49a699c4
BH
1804
1805 if(l_initialized) { // only reload configuration file on second call
18af64a8
BH
1806 string configname=::arg()["config-dir"]+"/recursor.conf";
1807 cleanSlashes(configname);
1808
1809 if(!::arg().preParseFile(configname.c_str(), "allow-from-file"))
7e818521 1810 throw runtime_error("Unable to re-parse configuration file '"+configname+"'");
49a699c4 1811 ::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS);
242b90e1 1812 ::arg().preParseFile(configname.c_str(), "include-dir");
829849d6
AT
1813 ::arg().preParse(g_argc, g_argv, "include-dir");
1814
1815 // then process includes
1816 std::vector<std::string> extraConfigs;
242b90e1
AT
1817 ::arg().gatherIncludes(extraConfigs);
1818
829849d6 1819 BOOST_FOREACH(const std::string& fn, extraConfigs) {
7e818521 1820 if(!::arg().preParseFile(fn.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
1821 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
1822 if(!::arg().preParseFile(fn.c_str(), "allow-from", ::arg()["allow-from"]))
1823 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
829849d6 1824 }
ca2c884c
AT
1825
1826 ::arg().preParse(g_argc, g_argv, "allow-from-file");
1827 ::arg().preParse(g_argc, g_argv, "allow-from");
f27e6356 1828 }
49a699c4
BH
1829
1830 NetmaskGroup* oldAllowFrom = t_allowFrom, *allowFrom=new NetmaskGroup;
1831
2c95fc65
BH
1832 if(!::arg()["allow-from-file"].empty()) {
1833 string line;
2c95fc65
BH
1834 ifstream ifs(::arg()["allow-from-file"].c_str());
1835 if(!ifs) {
49a699c4 1836 delete allowFrom;
9c61b9d0 1837 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
2c95fc65
BH
1838 }
1839
1840 string::size_type pos;
1841 while(getline(ifs,line)) {
1842 pos=line.find('#');
1843 if(pos!=string::npos)
1844 line.resize(pos);
1845 trim(line);
1846 if(line.empty())
1847 continue;
1848
18af64a8 1849 allowFrom->addMask(line);
2c95fc65 1850 }
49a699c4 1851 L<<Logger::Warning<<"Done parsing " << allowFrom->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl;
2c95fc65
BH
1852 }
1853 else if(!::arg()["allow-from"].empty()) {
f7c1d4e3
BH
1854 vector<string> ips;
1855 stringtok(ips, ::arg()["allow-from"], ", ");
c36bc97a 1856
f7c1d4e3
BH
1857 L<<Logger::Warning<<"Only allowing queries from: ";
1858 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
18af64a8 1859 allowFrom->addMask(*i);
f7c1d4e3 1860 if(i!=ips.begin())
674cf0f6 1861 L<<Logger::Warning<<", ";
f7c1d4e3
BH
1862 L<<Logger::Warning<<*i;
1863 }
1864 L<<Logger::Warning<<endl;
1865 }
49a699c4
BH
1866 else {
1867 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
1868 L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl;
1869 delete allowFrom;
1870 allowFrom = 0;
1871 }
1872
1873 g_initialAllowFrom = allowFrom;
d7dae798 1874 broadcastFunction(boost::bind(pleaseSupplantACLs, allowFrom));
49a699c4
BH
1875 delete oldAllowFrom;
1876
1877 l_initialized = true;
18af64a8
BH
1878}
1879
1880int serviceMain(int argc, char*argv[])
1881{
5124de27 1882 L.setName(s_programname);
18af64a8
BH
1883
1884 L.setLoglevel((Logger::Urgency)(6)); // info and up
1885
1886 if(!::arg()["logging-facility"].empty()) {
f8499e52
BH
1887 int val=logFacilityToLOG(::arg().asNum("logging-facility") );
1888 if(val >= 0)
1889 theL().setFacility(val);
18af64a8
BH
1890 else
1891 L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
1892 }
1893
ba1a571d 1894 showProductVersion();
18af64a8 1895 seedRandom(::arg()["entropy-source"]);
06ea9015 1896 g_disthashseed=dns_random(0xffffffff);
1897
18af64a8 1898 parseACLs();
92011b8f 1899 sortPublicSuffixList();
1900
eb5bae86
BH
1901 if(!::arg()["dont-query"].empty()) {
1902 g_dontQuery=new NetmaskGroup;
1903 vector<string> ips;
1904 stringtok(ips, ::arg()["dont-query"], ", ");
66e0b6ea
BH
1905 ips.push_back("0.0.0.0");
1906 ips.push_back("::");
c36bc97a 1907
eb5bae86
BH
1908 L<<Logger::Warning<<"Will not send queries to: ";
1909 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
1910 g_dontQuery->addMask(*i);
1911 if(i!=ips.begin())
4957a608 1912 L<<Logger::Warning<<", ";
eb5bae86
BH
1913 L<<Logger::Warning<<*i;
1914 }
1915 L<<Logger::Warning<<endl;
1916 }
1917
f7c1d4e3 1918 g_quiet=::arg().mustDo("quiet");
4ea94941 1919
1bc3c142
BH
1920 g_weDistributeQueries = ::arg().mustDo("pdns-distributes-queries");
1921 if(g_weDistributeQueries) {
1922 L<<Logger::Warning<<"PowerDNS Recursor itself will distribute queries over threads"<<endl;
1923 }
1924
77499b05
BH
1925 if(::arg()["trace"]=="fail") {
1926 SyncRes::setDefaultLogMode(SyncRes::Store);
1927 }
1928 else if(::arg().mustDo("trace")) {
1929 SyncRes::setDefaultLogMode(SyncRes::Log);
f7c1d4e3
BH
1930 ::arg().set("quiet")="no";
1931 g_quiet=false;
1932 }
f7c1d4e3 1933
aadceba8 1934 SyncRes::s_minimumTTL = ::arg().asNum("minimum-ttl-override");
1935
4e9a20e6 1936 checkLinuxIPv6Limits();
5a38281c
BH
1937 try {
1938 vector<string> addrs;
1939 if(!::arg()["query-local-address6"].empty()) {
1940 SyncRes::s_doIPv6=true;
d4fb76e9 1941 L<<Logger::Warning<<"Enabling IPv6 transport for outgoing queries"<<endl;
5a38281c
BH
1942
1943 stringtok(addrs, ::arg()["query-local-address6"], ", ;");
1944 BOOST_FOREACH(const string& addr, addrs) {
4957a608 1945 g_localQueryAddresses6.push_back(ComboAddress(addr));
5a38281c
BH
1946 }
1947 }
d4fb76e9
BH
1948 else {
1949 L<<Logger::Warning<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl;
1950 }
5a38281c
BH
1951 addrs.clear();
1952 stringtok(addrs, ::arg()["query-local-address"], ", ;");
1953 BOOST_FOREACH(const string& addr, addrs) {
1954 g_localQueryAddresses4.push_back(ComboAddress(addr));
1955 }
1956 }
1957 catch(std::exception& e) {
1958 L<<Logger::Error<<"Assigning local query addresses: "<<e.what();
1959 exit(99);
f7c1d4e3 1960 }
f555e92e 1961
578361b3 1962 SyncRes::s_noEDNSPing = true; // ::arg().mustDo("disable-edns-ping");
4bfae16d 1963 SyncRes::s_noEDNS = ::arg().mustDo("disable-edns");
578361b3 1964 if(!SyncRes::s_noEDNS) {
1965 L<<Logger::Warning<<"Running in experimental EDNS mode - may cause problems"<<endl;
1966 }
bb4bdbaf 1967
1051f8a9
BH
1968 SyncRes::s_nopacketcache = ::arg().mustDo("disable-packetcache");
1969
f7c1d4e3 1970 SyncRes::s_maxnegttl=::arg().asNum("max-negative-ttl");
c3e753c7 1971 SyncRes::s_maxcachettl=::arg().asNum("max-cache-ttl");
1051f8a9
BH
1972 SyncRes::s_packetcachettl=::arg().asNum("packetcache-ttl");
1973 SyncRes::s_packetcacheservfailttl=::arg().asNum("packetcache-servfail-ttl");
628e2c7b
PA
1974 SyncRes::s_serverdownmaxfails=::arg().asNum("server-down-max-fails");
1975 SyncRes::s_serverdownthrottletime=::arg().asNum("server-down-throttle-time");
f7c1d4e3 1976 SyncRes::s_serverID=::arg()["server-id"];
173d790e 1977 SyncRes::s_maxqperq=::arg().asNum("max-qperq");
f7c1d4e3
BH
1978 if(SyncRes::s_serverID.empty()) {
1979 char tmp[128];
1980 gethostname(tmp, sizeof(tmp)-1);
1981 SyncRes::s_serverID=tmp;
1982 }
1983
5b0ddd18 1984 g_networkTimeoutMsec = ::arg().asNum("network-timeout");
bb4bdbaf 1985
49a699c4 1986 g_initialDomainMap = parseAuthAndForwards();
674cf0f6 1987
08f3f638 1988 g_latencyStatSize=::arg().asNum("latency-statistic-size");
b3b5459d 1989
f7c1d4e3 1990 g_logCommonErrors=::arg().mustDo("log-common-errors");
e661a20b
PD
1991
1992 g_anyToTcp = ::arg().mustDo("any-to-tcp");
a09a8ce0
PD
1993 g_udpTruncationThreshold = ::arg().asNum("udp-truncation-threshold");
1994
f7c1d4e3
BH
1995 makeUDPServerSockets();
1996 makeTCPServerSockets();
815099b2 1997
677e2a46
BH
1998 int forks;
1999 for(forks = 0; forks < ::arg().asNum("processes") - 1; ++forks) {
1bc3c142
BH
2000 if(!fork()) // we are child
2001 break;
2002 }
2003
2d733c0f 2004 s_pidfname=::arg()["socket-dir"]+"/"+s_programname+".pid";
815099b2
BH
2005 if(!s_pidfname.empty())
2006 unlink(s_pidfname.c_str()); // remove possible old pid file
f7c1d4e3 2007
f7c1d4e3
BH
2008 if(::arg().mustDo("daemon")) {
2009 L<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
2010 L.toConsole(Logger::Critical);
f7c1d4e3
BH
2011 daemonize();
2012 }
2013 signal(SIGUSR1,usr1Handler);
2014 signal(SIGUSR2,usr2Handler);
2015 signal(SIGPIPE,SIG_IGN);
2016 writePid();
677e2a46 2017 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks : -1);
138435cb
BH
2018
2019 int newgid=0;
2020 if(!::arg()["setgid"].empty())
2021 newgid=Utility::makeGidNumeric(::arg()["setgid"]);
2022 int newuid=0;
2023 if(!::arg()["setuid"].empty())
2024 newuid=Utility::makeUidNumeric(::arg()["setuid"]);
2025
f1d6a7ce
KM
2026 Utility::dropGroupPrivs(newuid, newgid);
2027
138435cb
BH
2028 if (!::arg()["chroot"].empty()) {
2029 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
2030 L<<Logger::Error<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno)<<", exiting"<<endl;
2031 exit(1);
2032 }
2033 }
2034
f1d6a7ce 2035 Utility::dropUserPrivs(newuid);
77c535ae 2036 g_numThreads = ::arg().asNum("threads") + ::arg().mustDo("pdns-distributes-queries");
343257a4 2037
49a699c4 2038 makeThreadPipes();
5d4dd7fe
BH
2039
2040 g_tcpTimeout=::arg().asNum("client-tcp-timeout");
2041 g_maxTCPPerClient=::arg().asNum("max-tcp-per-client");
3a8a4d68 2042 g_maxMThreads=::arg().asNum("max-mthreads");
36849ff2 2043 checkOrFixFDS();
343257a4 2044
c3828c03 2045 if(g_numThreads == 1) {
76698c6e 2046 L<<Logger::Warning<<"Operating unthreaded"<<endl;
76698c6e
BH
2047 recursorThread(0);
2048 }
2049 else {
2050 pthread_t tid;
c3828c03
BH
2051 L<<Logger::Warning<<"Launching "<< g_numThreads <<" threads"<<endl;
2052 for(unsigned int n=0; n < g_numThreads; ++n) {
77499b05 2053 pthread_create(&tid, 0, recursorThread, (void*)(long)n);
76698c6e
BH
2054 }
2055 void* res;
49a699c4
BH
2056
2057
76698c6e 2058 pthread_join(tid, &res);
bb4bdbaf 2059 }
bb4bdbaf
BH
2060 return 0;
2061}
2062
2063void* recursorThread(void* ptr)
2064try
2065{
2e2cd8ec 2066 t_id=(int) (long) ptr;
49a699c4 2067 SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so..
ac0e821b 2068 t_sstorage->domainmap = g_initialDomainMap;
49a699c4
BH
2069 t_allowFrom = g_initialAllowFrom;
2070 t_udpclientsocks = new UDPClientSocks();
bd0289fc 2071 t_tcpClientCounts = new tcpClientCounts_t();
49a699c4 2072 primeHints();
674cf0f6 2073
49a699c4
BH
2074 t_packetCache = new RecursorPacketCache();
2075
2076 L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
2077
5704e107 2078 t_pdl = new shared_ptr<RecursorLua>();
49a699c4 2079
674cf0f6
BH
2080 try {
2081 if(!::arg()["lua-dns-script"].empty()) {
5704e107 2082 *t_pdl = shared_ptr<RecursorLua>(new RecursorLua(::arg()["lua-dns-script"]));
674cf0f6
BH
2083 L<<Logger::Warning<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl;
2084 }
674cf0f6
BH
2085 }
2086 catch(std::exception &e) {
2087 L<<Logger::Error<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e.what()<<endl;
62f0ae62 2088 _exit(99);
674cf0f6
BH
2089 }
2090
77499b05 2091 t_traceRegex = new shared_ptr<Regex>();
92011b8f 2092 unsigned int ringsize=::arg().asNum("stats-ringbuffer-entries") / g_numThreads;
2093 if(ringsize) {
60c8afa8 2094 t_remotes = new addrringbuf_t();
92011b8f 2095 t_remotes->set_capacity(ringsize);
60c8afa8 2096 t_servfailremotes = new addrringbuf_t();
92011b8f 2097 t_servfailremotes->set_capacity(ringsize);
60c8afa8 2098 t_largeanswerremotes = new addrringbuf_t();
92011b8f 2099 t_largeanswerremotes->set_capacity(ringsize);
2100
2101
2102 t_queryring = new boost::circular_buffer<pair<string, uint16_t> >();
2103 t_queryring->set_capacity(ringsize);
2104 t_servfailqueryring = new boost::circular_buffer<pair<string, uint16_t> >();
2105 t_servfailqueryring->set_capacity(ringsize);
2106 }
b3b5459d 2107
bb4bdbaf
BH
2108 MT=new MTasker<PacketID,string>(::arg().asNum("stack-size"));
2109
bb4bdbaf
BH
2110 PacketID pident;
2111
2112 t_fdm=getMultiplexer();
f3d1d67b 2113 if(!t_id) {
30a1aa92 2114 if(::arg().mustDo("experimental-webserver")) {
2115 L<<Logger::Warning << "Enabling web server" << endl;
8989097d 2116 try {
1ce57618 2117 new RecursorWebServer(t_fdm);
8989097d
CH
2118 }
2119 catch(PDNSException &e) {
2120 L<<Logger::Error<<"Exception: "<<e.reason<<endl;
2121 exit(99);
2122 }
f3d1d67b 2123 }
83252304 2124 L<<Logger::Error<<"Enabled '"<< t_fdm->getName() << "' multiplexer"<<endl;
f3d1d67b 2125 }
83252304 2126
49a699c4 2127 t_fdm->addReadFD(g_pipes[t_id].readToThread, handlePipeRequest);
83252304 2128
1bc3c142
BH
2129 if(!g_weDistributeQueries || !t_id) // if we distribute queries, only t_id = 0 listens
2130 for(deferredAdd_t::const_iterator i=deferredAdd.begin(); i!=deferredAdd.end(); ++i)
2131 t_fdm->addReadFD(i->first, i->second);
f7c1d4e3 2132
674cf0f6 2133 if(!t_id) {
674cf0f6
BH
2134 t_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel
2135 }
1bc3c142 2136
f7c1d4e3 2137 unsigned int maxTcpClients=::arg().asNum("max-tcp-clients");
f7c1d4e3 2138
f7c1d4e3 2139 bool listenOnTCP(true);
49a699c4 2140
2c78bd57 2141 time_t last_carbon=0;
2142 time_t carbonInterval=::arg().asNum("carbon-interval");
3427fa8a 2143 counter=0; // used to periodically execute certain tasks
f7c1d4e3 2144 for(;;) {
ac0e821b 2145 while(MT->schedule(&g_now)); // MTasker letting the mthreads do their thing
f7c1d4e3 2146
3427fa8a
BH
2147 if(!(counter%500)) {
2148 MT->makeThread(houseKeeping, 0);
f7c1d4e3
BH
2149 }
2150
d2392145 2151 if(!(counter%55)) {
d8f6d49f 2152 typedef vector<pair<int, FDMultiplexer::funcparam_t> > expired_t;
bb4bdbaf 2153 expired_t expired=t_fdm->getTimeouts(g_now);
4957a608 2154
f7c1d4e3 2155 for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) {
cd989c87 2156 shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(i->second);
4957a608 2157 if(g_logCommonErrors)
cd989c87 2158 L<<Logger::Warning<<"Timeout from remote TCP client "<< conn->d_remote.toString() <<endl;
4957a608 2159 t_fdm->removeReadFD(i->first);
f7c1d4e3
BH
2160 }
2161 }
2162
2163 counter++;
2164
3427fa8a 2165 if(!t_id && statsWanted) {
f7c1d4e3
BH
2166 doStats();
2167 }
2168
2169 Utility::gettimeofday(&g_now, 0);
2c78bd57 2170
2171 if(!t_id && (g_now.tv_sec - last_carbon >= carbonInterval)) {
2172 MT->makeThread(doCarbonDump, 0);
2173 last_carbon = g_now.tv_sec;
2174 }
2175
bb4bdbaf 2176 t_fdm->run(&g_now);
3ea54bf0 2177 // 'run' updates g_now for us
f7c1d4e3 2178
b8ef5c5c 2179 if(!g_weDistributeQueries || !t_id) { // if pdns distributes queries, only tid 0 should do this
5c889cf5 2180 if(listenOnTCP) {
2181 if(TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections
2182 for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
2183 t_fdm->removeReadFD(*i);
2184 listenOnTCP=false;
2185 }
f7c1d4e3 2186 }
5c889cf5 2187 else {
2188 if(TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable
2189 for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
2190 t_fdm->addReadFD(*i, handleNewTCPQuestion);
2191 listenOnTCP=true;
2192 }
f7c1d4e3
BH
2193 }
2194 }
2195 }
2196}
3f81d239 2197catch(PDNSException &ae) {
bb4bdbaf
BH
2198 L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
2199 return 0;
2200}
2201catch(std::exception &e) {
2202 L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
2203 return 0;
2204}
2205catch(...) {
2206 L<<Logger::Error<<"any other exception in main: "<<endl;
2207 return 0;
2208}
2209
51e2144e 2210
288f4aa9
BH
2211int main(int argc, char **argv)
2212{
dbd23fc2
BH
2213 g_argc = argc;
2214 g_argv = argv;
5e3de507 2215 g_stats.startupTime=time(0);
3e135495 2216 versionSetProduct(ProductRecursor);
8a63d3ce 2217 reportBasicTypes();
0007c2e5 2218 reportOtherTypes();
ea634573 2219
22030c37 2220 int ret = EXIT_SUCCESS;
caa6eefa 2221
288f4aa9 2222 try {
f888311c 2223 ::arg().set("stack-size","stack size per mthread")="200000";
2e3d8a19 2224 ::arg().set("soa-minimum-ttl","Don't change")="0";
2e3d8a19 2225 ::arg().set("no-shuffle","Don't change")="off";
2e3d8a19 2226 ::arg().set("local-port","port to listen on")="53";
32252594 2227 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
77499b05 2228 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
2e3d8a19 2229 ::arg().set("daemon","Operate as a daemon")="yes";
34162f8f 2230 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="4";
0e9d9ce2 2231 ::arg().set("log-common-errors","If we should log rather common errors")="yes";
2e3d8a19
BH
2232 ::arg().set("chroot","switch to chroot jail")="";
2233 ::arg().set("setgid","If set, change group id to this gid for more security")="";
2234 ::arg().set("setuid","If set, change user id to this uid for more security")="";
5b0ddd18 2235 ::arg().set("network-timeout", "Wait this nummer of milliseconds for network i/o")="1500";
bb4bdbaf 2236 ::arg().set("threads", "Launch this number of threads")="2";
1bc3c142 2237 ::arg().set("processes", "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)")="1";
5124de27 2238 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
9097239c 2239 ::arg().set( "experimental-logfile", "Filename of the log file for JSON parser" )= "/var/log/pdns.log";
88d77d73
CH
2240 ::arg().setSwitch("experimental-webserver", "Start a webserver for monitoring") = "no";
2241 ::arg().set("experimental-webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
2242 ::arg().set("experimental-webserver-port", "Port of webserver to listen on") = "8082";
2243 ::arg().set("experimental-webserver-password", "Password required for accessing the webserver") = "";
69e7f117 2244 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="0.0.0.0/0,::/0";
c348c0c8 2245 ::arg().set("experimental-api-config-dir", "Directory where REST API stores config and zones") = "";
bbef8f04 2246 ::arg().set("experimental-api-key", "REST API Static authentication key (required for API use)") = "";
cc08b5a9 2247 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
2c78bd57 2248 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server")="";
2249 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
b4ae7322 2250 ::arg().set("experimental-api-readonly", "If the JSON API should disallow data modification") = "no";
c038218b 2251 ::arg().set("quiet","Suppress logging of questions and answers")="";
f27e6356 2252 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
2e3d8a19 2253 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
fdbf35ac
BH
2254 ::arg().set("socket-owner","Owner of socket")="";
2255 ::arg().set("socket-group","Group of socket")="";
2256 ::arg().set("socket-mode", "Permissions for socket")="";
fdbf35ac 2257
2e3d8a19
BH
2258 ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
2259 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
2260 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
d4fb76e9 2261 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
2e3d8a19 2262 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
85c32340 2263 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
2e3d8a19 2264 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
324dc148 2265 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
979edd70 2266 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
2e3d8a19 2267 ::arg().set("hint-file", "If set, load root hints from this file")="";
b45eb27c 2268 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
a9af3782 2269 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
c3e753c7 2270 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
1051f8a9 2271 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
927c12b0 2272 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
1051f8a9 2273 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
7f7b8d55 2274 ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
92011b8f 2275 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
ba1a571d 2276 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
49a699c4 2277 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS;
2c95fc65 2278 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
51e2144e 2279 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
12cd44ee 2280 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY;
4e120339 2281 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
0d5f0a9f 2282 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
4ef015cd 2283 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
5605c067
BH
2284 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
2285 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
927c12b0
BH
2286 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
2287 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
5605c067 2288 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
ac0b4eb3 2289 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
3ea54bf0 2290 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
9bc8c14c 2291 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
4485aa35 2292 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
08f3f638 2293 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
578361b3 2294// ::arg().setSwitch( "disable-edns-ping", "Disable EDNSPing - EXPERIMENTAL, LEAVE DISABLED" )= "no";
2295 ::arg().setSwitch( "disable-edns", "Disable EDNS - EXPERIMENTAL, LEAVE DISABLED" )= "";
1bc3c142 2296 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
966d3ba8 2297 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="";
e661a20b 2298 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
a09a8ce0 2299 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680";
aadceba8 2300 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
173d790e 2301 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
a09a8ce0 2302
68e6df3c 2303 ::arg().set("include-dir","Include *.conf files from this directory")="";
d67620e4 2304 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
2e3d8a19
BH
2305
2306 ::arg().setCmd("help","Provide a helpful message");
ba1a571d 2307 ::arg().setCmd("version","Print version string");
d5141417 2308 ::arg().setCmd("config","Output blank configuration");
f27e6356 2309 L.toConsole(Logger::Info);
2e3d8a19 2310 ::arg().laxParse(argc,argv); // do a lax parse
c75a6a9e 2311
2d733c0f
CH
2312 string configname=::arg()["config-dir"]+"/recursor.conf";
2313 if(::arg()["config-name"]!="") {
2314 configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
5124de27 2315 s_programname+="-"+::arg()["config-name"];
2d733c0f
CH
2316 }
2317 cleanSlashes(configname);
5124de27 2318
577cf284
BH
2319 if(::arg().mustDo("config")) {
2320 cout<<::arg().configstring()<<endl;
2321 exit(0);
2322 }
2323
2e3d8a19 2324 if(!::arg().file(configname.c_str()))
c75a6a9e
BH
2325 L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
2326
2e3d8a19 2327 ::arg().parse(argc,argv);
c836dc19 2328
2e3d8a19 2329 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
562588a3 2330
61d74169 2331 if(::arg().asNum("threads")==1)
2332 ::arg().set("pdns-distributes-queries")="no";
2333
2e3d8a19 2334 if(::arg().mustDo("help")) {
ff5ba4f9
WA
2335 cout<<"syntax:"<<endl<<endl;
2336 cout<<::arg().helpstring(::arg()["help"])<<endl;
2337 exit(0);
b636533b 2338 }
5e3de507 2339 if(::arg().mustDo("version")) {
ba1a571d 2340 showProductVersion();
3613a51c 2341 showBuildConfiguration();
5e3de507
BH
2342 exit(99);
2343 }
b636533b 2344
34162f8f
CH
2345 Logger::Urgency logUrgency = (Logger::Urgency)::arg().asNum("loglevel");
2346 if (logUrgency < Logger::Error)
2347 logUrgency = Logger::Error;
d738f00f 2348 if(!g_quiet)
2349 logUrgency = Logger::Info;
34162f8f
CH
2350 L.setLoglevel(logUrgency);
2351 L.toConsole(logUrgency);
2352
f7c1d4e3 2353 serviceMain(argc, argv);
288f4aa9 2354 }
3f81d239 2355 catch(PDNSException &ae) {
c836dc19 2356 L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
22030c37 2357 ret=EXIT_FAILURE;
288f4aa9 2358 }
fdbf35ac 2359 catch(std::exception &e) {
c836dc19 2360 L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
22030c37 2361 ret=EXIT_FAILURE;
288f4aa9
BH
2362 }
2363 catch(...) {
c836dc19 2364 L<<Logger::Error<<"any other exception in main: "<<endl;
22030c37 2365 ret=EXIT_FAILURE;
288f4aa9 2366 }
caa6eefa 2367
22030c37 2368 return ret;
288f4aa9 2369}