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