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