]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/pdns_recursor.cc
XPF: Fix coverity "copy paste" issue
[thirdparty/pdns.git] / pdns / pdns_recursor.cc
CommitLineData
288f4aa9 1/*
6edbf68a
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
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
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
3e61e7f7 25
76473b92
KM
26#include <netdb.h>
27#include <sys/stat.h>
28#include <unistd.h>
fa8fd4d2 29
2470b36e 30#include "ws-recursor.hh"
49a699c4 31#include <pthread.h>
3ea54bf0 32#include "recpacketcache.hh"
3ddb9247 33#include "utility.hh"
51e2144e 34#include "dns_random.hh"
d1b28475
KM
35#ifdef HAVE_LIBSODIUM
36#include <sodium.h>
37#endif
3afde9b2 38#include "opensslsigners.hh"
288f4aa9
BH
39#include <iostream>
40#include <errno.h>
81859ba5 41#include <boost/static_assert.hpp>
288f4aa9
BH
42#include <map>
43#include <set>
97bb160b 44#include "recursor_cache.hh"
38c9ceaa 45#include "cachecleaner.hh"
288f4aa9 46#include <stdio.h>
c75a6a9e 47#include <signal.h>
288f4aa9 48#include <stdlib.h>
bb4bdbaf 49#include "misc.hh"
288f4aa9
BH
50#include "mtasker.hh"
51#include <utility>
288f4aa9
BH
52#include "arguments.hh"
53#include "syncres.hh"
88def049
BH
54#include <fcntl.h>
55#include <fstream>
3e61e7f7 56#include "sortlist.hh"
5c633640
BH
57#include "sstuff.hh"
58#include <boost/tuple/tuple.hpp>
59#include <boost/tuple/tuple_comparison.hpp>
72df400f 60#include <boost/shared_array.hpp>
7f1fa77d 61#include <boost/function.hpp>
5605c067 62#include <boost/algorithm/string.hpp>
8f7473d7 63#ifdef MALLOC_TRACE
64#include "malloctrace.hh"
65#endif
40a3dd64 66#include <netinet/tcp.h>
ea634573
BH
67#include "dnsparser.hh"
68#include "dnswriter.hh"
69#include "dnsrecords.hh"
f814d7c8 70#include "zoneparser-tng.hh"
1d5b3ce6 71#include "rec_channel.hh"
aaacf7f2 72#include "logger.hh"
c8ddb7c2 73#include "iputils.hh"
09e6702a 74#include "mplexer.hh"
c038218b 75#include "config.h"
808c5ef7 76#include "lua-recursor4.hh"
ba1a571d 77#include "version.hh"
79332bff 78#include "responsestats.hh"
d67620e4 79#include "secpoll-recursor.hh"
c5c066bf 80#include "dnsname.hh"
644dd1da 81#include "filterpo.hh"
82#include "rpzloader.hh"
b3f0ed10 83#include "validate-recursor.hh"
f3c18728 84#include "rec-lua-conf.hh"
5c3b5e7f 85#include "ednsoptions.hh"
85c7ca75 86#include "gettime.hh"
f3c18728 87
d9d3f9c1 88#include "rec-protobuf.hh"
d705aad9 89#include "rec-snmp.hh"
aa7929a3 90
6b6720de
PL
91#ifdef HAVE_SYSTEMD
92#include <systemd/sd-daemon.h>
93#endif
94
d187038c
RG
95#include "namespaces.hh"
96
5cc8371b
RG
97#include "xpf.hh"
98
d187038c
RG
99typedef map<ComboAddress, uint32_t, ComboAddress::addressOnlyLessThan> tcpClientCounts_t;
100
f26bf547
RG
101static thread_local std::shared_ptr<RecursorLua4> t_pdl;
102static thread_local unsigned int t_id;
103static thread_local std::shared_ptr<Regex> t_traceRegex;
104static thread_local std::unique_ptr<tcpClientCounts_t> t_tcpClientCounts;
105
106thread_local std::unique_ptr<MT_t> MT; // the big MTasker
107thread_local std::unique_ptr<MemRecursorCache> t_RC;
108thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
3337c2f7 109thread_local FDMultiplexer* t_fdm{nullptr};
f26bf547
RG
110thread_local std::unique_ptr<addrringbuf_t> t_remotes, t_servfailremotes, t_largeanswerremotes;
111thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > > t_queryring, t_servfailqueryring;
112thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
aa7929a3 113#ifdef HAVE_PROTOBUF
f26bf547 114thread_local std::unique_ptr<boost::uuids::random_generator> t_uuidGenerator;
aa7929a3 115#endif
d187038c 116__thread struct timeval g_now; // timestamp, updated (too) frequently
d7dae798
BH
117
118// for communicating with our threads
49a699c4
BH
119struct ThreadPipeSet
120{
121 int writeToThread;
122 int readToThread;
123 int writeFromThread;
124 int readFromThread;
125};
810ff705 126
d187038c
RG
127typedef vector<int> tcpListenSockets_t;
128typedef map<int, ComboAddress> listenSocketsAddresses_t; // is shared across all threads right now
129typedef vector<pair<int, function< void(int, any&) > > > deferredAdd_t;
3ea54bf0 130
d187038c
RG
131static const ComboAddress g_local4("0.0.0.0"), g_local6("::");
132static vector<ThreadPipeSet> g_pipes; // effectively readonly after startup
133static tcpListenSockets_t g_tcpListenSockets; // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets
134static listenSocketsAddresses_t g_listenSocketsAddresses; // is shared across all threads right now
810ff705 135static std::unordered_map<unsigned int, deferredAdd_t> deferredAdds;
d187038c
RG
136static set<int> g_fromtosockets; // listen sockets that use 'sendfromto()' mechanism
137static vector<ComboAddress> g_localQueryAddresses4, g_localQueryAddresses6;
138static AtomicCounter counter;
9065eb05 139static std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // new threads needs this to be setup
f26bf547 140static std::shared_ptr<NetmaskGroup> g_initialAllowFrom; // new thread needs to be setup with this
5cc8371b 141static NetmaskGroup g_XPFAcl;
d187038c
RG
142static size_t g_tcpMaxQueriesPerConn;
143static uint64_t g_latencyStatSize;
144static uint32_t g_disthashseed;
145static unsigned int g_maxTCPPerClient;
146static unsigned int g_networkTimeoutMsec;
147static unsigned int g_maxMThreads;
148static unsigned int g_numWorkerThreads;
149static int g_tcpTimeout;
150static uint16_t g_udpTruncationThreshold;
59cb4a79 151static uint16_t g_xpfRRCode{0};
d187038c
RG
152static std::atomic<bool> statsWanted;
153static std::atomic<bool> g_quiet;
154static bool g_logCommonErrors;
155static bool g_anyToTcp;
d187038c 156static bool g_weDistributeQueries; // if true, only 1 thread listens on the incoming query sockets
810ff705
RG
157static bool g_reusePort{false};
158static bool g_useOneSocketPerThread;
00b8cadc 159static bool g_gettagNeedsEDNSOptions{false};
0ec489bf 160static time_t g_statisticsInterval;
9065eb05 161static bool g_useIncomingECS;
a6f7f5fe 162std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries;
49a699c4 163
d187038c
RG
164RecursorControlChannel s_rcc; // only active in thread 0
165RecursorStats g_stats;
2d733c0f 166string s_programname="pdns_recursor";
d187038c 167string s_pidfname;
c1c29961 168bool g_lowercaseOutgoing;
d187038c
RG
169unsigned int g_numThreads;
170uint16_t g_outgoingEDNSBufsize;
98d36505 171bool g_logRPZChanges{false};
c3828c03 172
12cd44ee 173#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"
2fe3354d 174#define LOCAL_NETS_INVERSE "!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"
12cd44ee 175// Bad Nets taken from both:
3ddb9247 176// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
12cd44ee 177// and
178// http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
179// where such a network may not be considered a valid destination
180#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"
181#define DONT_QUERY LOCAL_NETS ", " BAD_NETS
49a699c4 182
d7dae798 183//! used to send information to a newborn mthread
ea634573 184struct DNSComboWriter {
27c0050c 185 DNSComboWriter(const char* data, uint16_t len, const struct timeval& now) : d_mdp(true, data, len), d_now(now),
232f0877 186 d_tcp(false), d_socket(-1)
ea634573 187 {}
5cc8371b
RG
188
189 void setRemote(const ComboAddress& sa)
190 {
191 d_remote=sa;
192 }
193
194 void setSource(const ComboAddress& sa)
ea634573 195 {
5cc8371b 196 d_source=sa;
ea634573
BH
197 }
198
b71b60ee 199 void setLocal(const ComboAddress& sa)
200 {
201 d_local=sa;
202 }
203
5cc8371b
RG
204 void setDestination(const ComboAddress& sa)
205 {
206 d_destination=sa;
207 }
b71b60ee 208
ea634573
BH
209 void setSocket(int sock)
210 {
211 d_socket=sock;
212 }
a1754c6a
BH
213
214 string getRemote() const
215 {
5cc8371b
RG
216 if (d_source == d_remote) {
217 return d_source.toStringWithPort();
218 }
219 return d_source.toStringWithPort() + " (proxied by " + d_remote.toStringWithPort() + ")";
a1754c6a
BH
220 }
221
5cc8371b 222 MOADNSParser d_mdp;
c9e9e5e0 223 struct timeval d_now;
5cc8371b
RG
224 /* Remote client, might differ from d_source
225 in case of XPF, in which case d_source holds
226 the IP of the client and d_remote of the proxy
227 */
228 ComboAddress d_remote;
229 ComboAddress d_source;
230 /* Destination address, might differ from
231 d_destination in case of XPF, in which case
232 d_destination holds the IP of the proxy and
233 d_local holds our own. */
234 ComboAddress d_local;
235 ComboAddress d_destination;
aa7929a3
RG
236#ifdef HAVE_PROTOBUF
237 boost::uuids::uuid d_uuid;
67e31ebe 238 string d_requestorId;
590388d2 239 string d_deviceId;
aa7929a3 240#endif
b40562da
RG
241 EDNSSubnetOpts d_ednssubnet;
242 bool d_ecsFound{false};
243 bool d_ecsParsed{false};
ea634573
BH
244 bool d_tcp;
245 int d_socket;
b673817a 246 unsigned int d_tag{0};
e9f63d47 247 uint32_t d_qhash{0};
49a3500d 248 string d_query;
cd989c87 249 shared_ptr<TCPConnection> d_tcpConnection;
e8340d27 250 vector<pair<uint16_t, string> > d_ednsOpts;
02b47f43 251 std::vector<std::string> d_policyTags;
5fd2577f 252 LuaContext::LuaObject d_data;
ea634573
BH
253};
254
06857845
RG
255MT_t* getMT()
256{
257 return MT ? MT.get() : nullptr;
258}
ea634573 259
288f4aa9
BH
260ArgvMap &arg()
261{
262 static ArgvMap theArg;
263 return theArg;
264}
4ef015cd 265
b4015453
RG
266unsigned int getRecursorThreadId()
267{
268 return t_id;
269}
09e6702a 270
30ee601a
RG
271int getMTaskerTID()
272{
273 return MT->getTid();
274}
275
d187038c 276static void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var);
09e6702a 277
50c81227 278// -1 is error, 0 is timeout, 1 is success
3ddb9247 279int asendtcp(const string& data, Socket* sock)
5c633640
BH
280{
281 PacketID pident;
282 pident.sock=sock;
283 pident.outMSG=data;
3ddb9247 284
bb4bdbaf 285 t_fdm->addWriteFD(sock->getHandle(), handleTCPClientWritable, pident);
50c81227 286 string packet;
5c633640 287
5b0ddd18 288 int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec);
23db0a09 289
9170fbaf 290 if(!ret || ret==-1) { // timeout
bb4bdbaf 291 t_fdm->removeWriteFD(sock->getHandle());
5c633640 292 }
50c81227
BH
293 else if(packet.size() !=data.size()) { // main loop tells us what it sent out, or empty in case of an error
294 return -1;
295 }
9170fbaf 296 return ret;
5c633640
BH
297}
298
d187038c 299static void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var);
09e6702a 300
9170fbaf 301// -1 is error, 0 is timeout, 1 is success
a683e8bd 302int arecvtcp(string& data, size_t len, Socket* sock, bool incompleteOkay)
288f4aa9 303{
50c81227 304 data.clear();
5c633640
BH
305 PacketID pident;
306 pident.sock=sock;
307 pident.inNeeded=len;
825fa717 308 pident.inIncompleteOkay=incompleteOkay;
bb4bdbaf 309 t_fdm->addReadFD(sock->getHandle(), handleTCPClientReadable, pident);
5c633640 310
bb4bdbaf 311 int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec);
9170fbaf 312 if(!ret || ret==-1) { // timeout
bb4bdbaf 313 t_fdm->removeReadFD(sock->getHandle());
288f4aa9 314 }
50c81227
BH
315 else if(data.empty()) {// error, EOF or other
316 return -1;
317 }
318
9170fbaf 319 return ret;
288f4aa9
BH
320}
321
d187038c 322static void handleGenUDPQueryResponse(int fd, FDMultiplexer::funcparam_t& var)
4465e941 323{
fba1e944 324 PacketID pident=*any_cast<PacketID>(&var);
4465e941 325 char resp[512];
7c77ce63
RG
326 ComboAddress fromaddr;
327 socklen_t addrlen=sizeof(fromaddr);
328
329 ssize_t ret=recvfrom(fd, resp, sizeof(resp), 0, (sockaddr *)&fromaddr, &addrlen);
330 if (fromaddr != pident.remote) {
331 L<<Logger::Notice<<"Response received from the wrong remote host ("<<fromaddr.toStringWithPort()<<" instead of "<<pident.remote.toStringWithPort()<<"), discarding"<<endl;
332
333 }
334
4465e941 335 t_fdm->removeReadFD(fd);
336 if(ret >= 0) {
a683e8bd 337 string data(resp, (size_t) ret);
fba1e944 338 MT->sendEvent(pident, &data);
4465e941 339 }
340 else {
fba1e944 341 string empty;
342 MT->sendEvent(pident, &empty);
343 // cerr<<"Had some kind of error: "<<ret<<", "<<strerror(errno)<<endl;
4465e941 344 }
345}
fba1e944 346string GenUDPQueryResponse(const ComboAddress& dest, const string& query)
4465e941 347{
4465e941 348 Socket s(dest.sin4.sin_family, SOCK_DGRAM);
349 s.setNonBlocking();
350 ComboAddress local = getQueryLocalAddress(dest.sin4.sin_family, 0);
351
352 s.bind(local);
353 s.connect(dest);
4465e941 354 s.send(query);
355
356 PacketID pident;
357 pident.sock=&s;
7c77ce63 358 pident.remote=dest;
4465e941 359 pident.type=0;
fba1e944 360 t_fdm->addReadFD(s.getHandle(), handleGenUDPQueryResponse, pident);
4465e941 361
362 string data;
fba1e944 363
4465e941 364 int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec);
fba1e944 365
4465e941 366 if(!ret || ret==-1) { // timeout
4465e941 367 t_fdm->removeReadFD(s.getHandle());
368 }
369 else if(data.empty()) {// error, EOF or other
fba1e944 370 // we could special case this
4465e941 371 return data;
372 }
4465e941 373 return data;
374}
375
d7dae798 376//! pick a random query local address
1652a63e 377ComboAddress getQueryLocalAddress(int family, uint16_t port)
5a38281c 378{
1652a63e 379 ComboAddress ret;
5a38281c 380 if(family==AF_INET) {
3ddb9247 381 if(g_localQueryAddresses4.empty())
1652a63e 382 ret = g_local4;
3ddb9247 383 else
1652a63e
BH
384 ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())];
385 ret.sin4.sin_port = htons(port);
5a38281c
BH
386 }
387 else {
388 if(g_localQueryAddresses6.empty())
1652a63e
BH
389 ret = g_local6;
390 else
391 ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())];
3ddb9247 392
1652a63e 393 ret.sin6.sin6_port = htons(port);
5a38281c 394 }
1652a63e 395 return ret;
5a38281c 396}
4ef015cd 397
d187038c 398static void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t&);
09e6702a 399
d187038c 400static void setSocketBuffer(int fd, int optname, uint32_t size)
d7dae798
BH
401{
402 uint32_t psize=0;
403 socklen_t len=sizeof(psize);
3ddb9247 404
d7dae798
BH
405 if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
406 L<<Logger::Error<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
3ddb9247 407 return;
d7dae798
BH
408 }
409
410 if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
c057bfaa 411 L<<Logger::Error<<"Unable to raise socket buffer size to "<<size<<": "<<strerror(errno)<<endl;
d7dae798
BH
412}
413
414
415static void setSocketReceiveBuffer(int fd, uint32_t size)
416{
417 setSocketBuffer(fd, SO_RCVBUF, size);
418}
419
420static void setSocketSendBuffer(int fd, uint32_t size)
421{
422 setSocketBuffer(fd, SO_SNDBUF, size);
423}
424
425
4ef015cd
BH
426// you can ask this class for a UDP socket to send a query from
427// this socket is not yours, don't even think about deleting it
428// but after you call 'returnSocket' on it, don't assume anything anymore
429class UDPClientSocks
430{
4ef015cd 431 unsigned int d_numsocks;
4ef015cd 432public:
e2642526 433 UDPClientSocks() : d_numsocks(0)
4ef015cd
BH
434 {
435 }
436
996c89cc 437 typedef set<int> socks_t;
4ef015cd
BH
438 socks_t d_socks;
439
2ee280cf 440 // returning -2 means: temporary OS error (ie, out of files), -1 means error related to remote
d8f6d49f 441 int getSocket(const ComboAddress& toaddr, int* fd)
4ef015cd 442 {
d8f6d49f
BH
443 *fd=makeClientSocket(toaddr.sin4.sin_family);
444 if(*fd < 0) // temporary error - receive exception otherwise
2ee280cf 445 return -2;
d8f6d49f
BH
446
447 if(connect(*fd, (struct sockaddr*)(&toaddr), toaddr.getSocklen()) < 0) {
448 int err = errno;
41ff43f8 449 // returnSocket(*fd);
a7b68ae7
RG
450 try {
451 closesocket(*fd);
452 }
453 catch(const PDNSException& e) {
454 L<<Logger::Error<<"Error closing UDP socket after connect() failed: "<<e.reason<<endl;
455 }
456
d8f6d49f 457 if(err==ENETUNREACH) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
4957a608 458 return -2;
998a4334 459 return -1;
d8f6d49f 460 }
998a4334 461
d8f6d49f 462 d_socks.insert(*fd);
998a4334 463 d_numsocks++;
d8f6d49f 464 return 0;
4ef015cd
BH
465 }
466
095c3045
BH
467 void returnSocket(int fd)
468 {
469 socks_t::iterator i=d_socks.find(fd);
34801ab1 470 if(i==d_socks.end()) {
335da0ba 471 throw PDNSException("Trying to return a socket (fd="+std::to_string(fd)+") not in the pool");
34801ab1 472 }
bb4bdbaf 473 returnSocketLocked(i);
095c3045
BH
474 }
475
4ef015cd 476 // return a socket to the pool, or simply erase it
bb4bdbaf 477 void returnSocketLocked(socks_t::iterator& i)
4ef015cd 478 {
600fc20b 479 if(i==d_socks.end()) {
3f81d239 480 throw PDNSException("Trying to return a socket not in the pool");
600fc20b 481 }
80baf329 482 try {
bb4bdbaf 483 t_fdm->removeReadFD(*i);
80baf329
BH
484 }
485 catch(FDMultiplexerException& e) {
bb4bdbaf 486 // we sometimes return a socket that has not yet been assigned to t_fdm
80baf329 487 }
a7b68ae7
RG
488 try {
489 closesocket(*i);
490 }
491 catch(const PDNSException& e) {
492 L<<Logger::Error<<"Error closing returned UDP socket: "<<e.reason<<endl;
493 }
3ddb9247 494
998a4334
BH
495 d_socks.erase(i++);
496 --d_numsocks;
4ef015cd 497 }
d8f6d49f
BH
498
499 // returns -1 for errors which might go away, throws for ones that won't
bb4bdbaf 500 static int makeClientSocket(int family)
d8f6d49f 501 {
a683e8bd 502 int ret=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 503
d8f6d49f
BH
504 if(ret < 0 && errno==EMFILE) // this is not a catastrophic error
505 return ret;
3ddb9247
PD
506
507 if(ret<0)
335da0ba 508 throw PDNSException("Making a socket for resolver (family = "+std::to_string(family)+"): "+stringerror());
36855b53 509
7eb73ffa 510 // setCloseOnExec(ret); // we're not going to exec
5a38281c 511
d8f6d49f 512 int tries=10;
3aa91c3e 513 ComboAddress sin;
d8f6d49f 514 while(--tries) {
1652a63e 515 uint16_t port;
3ddb9247 516
d8f6d49f 517 if(tries==1) // fall back to kernel 'random'
4957a608 518 port = 0;
1652a63e
BH
519 else
520 port = 1025 + dns_random(64510);
5a38281c 521
3aa91c3e 522 sin=getQueryLocalAddress(family, port); // does htons for us
5a38281c 523
3ddb9247 524 if (::bind(ret, (struct sockaddr *)&sin, sin.getSocklen()) >= 0)
4957a608 525 break;
d8f6d49f
BH
526 }
527 if(!tries)
3aa91c3e 528 throw PDNSException("Resolver binding to local query client socket on "+sin.toString()+": "+stringerror());
3ddb9247 529
3897b9e1 530 setNonBlocking(ret);
d8f6d49f
BH
531 return ret;
532 }
49a699c4
BH
533};
534
f26bf547 535static thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
4ef015cd 536
288f4aa9 537/* these two functions are used by LWRes */
34801ab1 538// -2 is OS error, -1 is error that depends on the remote, > 0 is success
a683e8bd 539int asendto(const char *data, size_t len, int flags,
3ddb9247 540 const ComboAddress& toaddr, uint16_t id, const DNSName& domain, uint16_t qtype, int* fd)
288f4aa9 541{
34801ab1
BH
542
543 PacketID pident;
787e5eab
BH
544 pident.domain = domain;
545 pident.remote = toaddr;
546 pident.type = qtype;
34801ab1
BH
547
548 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
549 pair<MT_t::waiters_t::iterator, MT_t::waiters_t::iterator> chain=MT->d_waiters.equal_range(pident, PacketIDBirthdayCompare());
550
551 for(; chain.first != chain.second; chain.first++) {
552 if(chain.first->key.fd > -1) { // don't chain onto existing chained waiter!
e27e91a8 553 /*
4665c31e
BH
554 cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
555 cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
4957a608 556 <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
e27e91a8 557 */
34801ab1
BH
558 chain.first->key.chain.insert(id); // we can chain
559 *fd=-1; // gets used in waitEvent / sendEvent later on
560 return 1;
561 }
562 }
563
49a699c4 564 int ret=t_udpclientsocks->getSocket(toaddr, fd);
d8f6d49f
BH
565 if(ret < 0)
566 return ret;
34801ab1 567
998a4334
BH
568 pident.fd=*fd;
569 pident.id=id;
3ddb9247 570
bb4bdbaf
BH
571 t_fdm->addReadFD(*fd, handleUDPServerResponse, pident);
572 ret = send(*fd, data, len, 0);
573
5b0ddd18 574 int tmp = errno;
bb4bdbaf 575
7302ed0a 576 if(ret < 0)
49a699c4 577 t_udpclientsocks->returnSocket(*fd);
bb4bdbaf 578
5b0ddd18 579 errno = tmp; // this is for logging purposes only
7302ed0a 580 return ret;
288f4aa9
BH
581}
582
9170fbaf 583// -1 is error, 0 is timeout, 1 is success
a683e8bd 584int arecvfrom(char *data, size_t len, int flags, const ComboAddress& fromaddr, size_t *d_len,
c5c066bf 585 uint16_t id, const DNSName& domain, uint16_t qtype, int fd, struct timeval* now)
288f4aa9 586{
0d5f0a9f 587 static optional<unsigned int> nearMissLimit;
3ddb9247 588 if(!nearMissLimit)
0d5f0a9f
BH
589 nearMissLimit=::arg().asNum("spoof-nearmiss-max");
590
288f4aa9 591 PacketID pident;
4ef015cd 592 pident.fd=fd;
288f4aa9 593 pident.id=id;
0d5f0a9f 594 pident.domain=domain;
787e5eab 595 pident.type = qtype;
996c89cc 596 pident.remote=fromaddr;
b636533b 597
288f4aa9 598 string packet;
5b0ddd18 599 int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec, now);
34801ab1 600
9170fbaf 601 if(ret > 0) {
996c89cc 602 if(packet.empty()) // means "error"
3ddb9247 603 return -1;
998a4334 604
a683e8bd 605 *d_len=packet.size();
9170fbaf 606 memcpy(data,packet.c_str(),min(len,*d_len));
0d5f0a9f 607 if(*nearMissLimit && pident.nearMisses > *nearMissLimit) {
996c89cc 608 L<<Logger::Error<<"Too many ("<<pident.nearMisses<<" > "<<*nearMissLimit<<") bogus answers for '"<<domain<<"' from "<<fromaddr.toString()<<", assuming spoof attempt."<<endl;
0d5f0a9f 609 g_stats.spoofCount++;
35ce8576
BH
610 return -1;
611 }
288f4aa9 612 }
09e6702a 613 else {
34801ab1 614 if(fd >= 0)
49a699c4 615 t_udpclientsocks->returnSocket(fd);
09e6702a 616 }
9170fbaf 617 return ret;
288f4aa9
BH
618}
619
88def049
BH
620static void writePid(void)
621{
191f2e47 622 if(!::arg().mustDo("write-pid"))
623 return;
18e7758c 624 ofstream of(s_pidfname.c_str(), std::ios_base::app);
88def049 625 if(of)
705f31ae 626 of<< Utility::getpid() <<endl;
88def049 627 else
c057bfaa 628 L<<Logger::Error<<"Writing pid for "<<Utility::getpid()<<" to "<<s_pidfname<<" failed: "<<strerror(errno)<<endl;
88def049
BH
629}
630
cd989c87 631TCPConnection::TCPConnection(int fd, const ComboAddress& addr) : d_remote(addr), d_fd(fd)
3ddb9247
PD
632{
633 ++s_currentConnections;
cd989c87 634 (*t_tcpClientCounts)[d_remote]++;
0e408828 635}
cd989c87
BH
636
637TCPConnection::~TCPConnection()
0e408828 638{
a7b68ae7
RG
639 try {
640 if(closesocket(d_fd) < 0)
641 L<<Logger::Error<<"Error closing socket for TCPConnection"<<endl;
642 }
643 catch(const PDNSException& e) {
644 L<<Logger::Error<<"Error closing TCPConnection socket: "<<e.reason<<endl;
645 }
646
3ddb9247 647 if(t_tcpClientCounts->count(d_remote) && !(*t_tcpClientCounts)[d_remote]--)
cd989c87 648 t_tcpClientCounts->erase(d_remote);
1bc9e6bd 649 --s_currentConnections;
0e408828 650}
0e9d9ce2 651
3ddb9247 652AtomicCounter TCPConnection::s_currentConnections;
d187038c
RG
653
654static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var);
6dcd28c3 655
92011b8f 656// the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming.
d187038c 657static void updateResponseStats(int res, const ComboAddress& remote, unsigned int packetsize, const DNSName* query, uint16_t qtype)
2cc13433 658{
92011b8f 659 if(packetsize > 1000 && t_largeanswerremotes)
660 t_largeanswerremotes->push_back(remote);
2cc13433
BH
661 switch(res) {
662 case RCode::ServFail:
92011b8f 663 if(t_servfailremotes) {
664 t_servfailremotes->push_back(remote);
5af86fdc 665 if(query && t_servfailqueryring) // packet cache
92011b8f 666 t_servfailqueryring->push_back(make_pair(*query, qtype));
667 }
2cc13433
BH
668 g_stats.servFails++;
669 break;
670 case RCode::NXDomain:
671 g_stats.nxDomains++;
672 break;
673 case RCode::NoError:
674 g_stats.noErrors++;
675 break;
676 }
677}
678
a903b39c 679static string makeLoginfo(DNSComboWriter* dc)
680try
681{
5cc8371b 682 return "("+dc->d_mdp.d_qname.toLogString()+"/"+DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)+" from "+(dc->getRemote())+")";
a903b39c 683}
684catch(...)
685{
686 return "Exception making error message for exception";
687}
688
aa7929a3 689#ifdef HAVE_PROTOBUF
590388d2 690static void protobufLogQuery(const std::shared_ptr<RemoteLogger>& logger, uint8_t maskV4, uint8_t maskV6, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const Netmask& ednssubnet, bool tcp, uint16_t id, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::vector<std::string>& policyTags, const std::string& requestorId, const std::string& deviceId)
aa7929a3 691{
e1c8a4bb
RG
692 Netmask requestorNM(remote, remote.sin4.sin_family == AF_INET ? maskV4 : maskV6);
693 const ComboAddress& requestor = requestorNM.getMaskedNetwork();
694 RecProtoBufMessage message(DNSProtoBufMessage::Query, uniqueId, &requestor, &local, qname, qtype, qclass, id, tcp, len);
a94bc5d7 695 message.setEDNSSubnet(ednssubnet, ednssubnet.isIpv4() ? maskV4 : maskV6);
67e31ebe 696 message.setRequestorId(requestorId);
590388d2 697 message.setDeviceId(deviceId);
02b47f43 698
02b47f43 699 if (!policyTags.empty()) {
d9d3f9c1 700 message.setPolicyTags(policyTags);
02b47f43 701 }
aa7929a3 702
d9d3f9c1 703// cerr <<message.toDebugString()<<endl;
aa7929a3 704 std::string str;
d9d3f9c1 705 message.serialize(str);
aa7929a3 706 logger->queueData(str);
aa7929a3
RG
707}
708
d9d3f9c1 709static void protobufLogResponse(const std::shared_ptr<RemoteLogger>& logger, const RecProtoBufMessage& message)
aa7929a3 710{
d9d3f9c1 711// cerr <<message.toDebugString()<<endl;
aa7929a3 712 std::string str;
d9d3f9c1 713 message.serialize(str);
aa7929a3 714 logger->queueData(str);
aa7929a3
RG
715}
716#endif
717
53508135
PL
718/**
719 * Chases the CNAME provided by the PolicyCustom RPZ policy.
720 *
721 * @param spoofed: The DNSRecord that was created by the policy, should already be added to ret
722 * @param qtype: The QType of the original query
723 * @param sr: A SyncRes
724 * @param res: An integer that will contain the RCODE of the lookup we do
725 * @param ret: A vector of DNSRecords where the result of the CNAME chase should be appended to
726 */
d187038c 727static void handleRPZCustom(const DNSRecord& spoofed, const QType& qtype, SyncRes& sr, int& res, vector<DNSRecord>& ret)
53508135
PL
728{
729 if (spoofed.d_type == QType::CNAME) {
30ee601a
RG
730 bool oldWantsRPZ = sr.getWantsRPZ();
731 sr.setWantsRPZ(false);
53508135
PL
732 vector<DNSRecord> ans;
733 res = sr.beginResolve(DNSName(spoofed.d_content->getZoneRepresentation()), qtype, 1, ans);
734 for (const auto& rec : ans) {
735 if(rec.d_place == DNSResourceRecord::ANSWER) {
736 ret.push_back(rec);
737 }
738 }
739 // Reset the RPZ state of the SyncRes
30ee601a 740 sr.setWantsRPZ(oldWantsRPZ);
53508135
PL
741 }
742}
743
97c6d7e5
RG
744static bool addRecordToPacket(DNSPacketWriter& pw, const DNSRecord& rec, uint32_t& minTTL, const uint16_t maxAnswerSize)
745{
746 pw.startRecord(rec.d_name, rec.d_type, rec.d_ttl, rec.d_class, rec.d_place);
747
748 if(rec.d_type != QType::OPT) // their TTL ain't real
749 minTTL = min(minTTL, rec.d_ttl);
750
751 rec.d_content->toPacket(pw);
752 if(pw.size() > static_cast<size_t>(maxAnswerSize)) {
753 pw.rollback();
754 if(rec.d_place != DNSResourceRecord::ADDITIONAL) {
755 pw.getHeader()->tc=1;
756 pw.truncate();
757 }
758 return false;
759 }
760
761 return true;
762}
763
d187038c 764static void startDoResolve(void *p)
288f4aa9 765{
7b1469bb 766 DNSComboWriter* dc=(DNSComboWriter *)p;
288f4aa9 767 try {
5af86fdc
RG
768 if (t_queryring)
769 t_queryring->push_back(make_pair(dc->d_mdp.d_qname, dc->d_mdp.d_qtype));
92011b8f 770
32015748 771 uint16_t maxanswersize = dc->d_tcp ? 65535 : min(static_cast<uint16_t>(512), g_udpTruncationThreshold);
7f7b8d55 772 EDNSOpts edo;
8e079f3a 773 bool haveEDNS=false;
774 if(getEDNSOpts(dc->d_mdp, &edo)) {
32015748
RG
775 if(!dc->d_tcp) {
776 /* rfc6891 6.2.3:
777 "Values lower than 512 MUST be treated as equal to 512."
778 */
779 maxanswersize = min(static_cast<uint16_t>(edo.d_packetsize >= 512 ? edo.d_packetsize : 512), g_udpTruncationThreshold);
780 }
e8340d27 781 dc->d_ednsOpts = edo.d_options;
8e079f3a 782 haveEDNS=true;
b40562da
RG
783
784 if (g_useIncomingECS && !dc->d_ecsParsed) {
785 for (const auto& o : edo.d_options) {
786 if (o.first == EDNSOptionCode::ECS) {
787 dc->d_ecsFound = getEDNSSubnetOptsFromString(o.second, &dc->d_ednssubnet);
788 break;
789 }
790 }
791 }
10321a98 792 }
b40562da
RG
793 /* perhaps there was no EDNS or no ECS but by now we looked */
794 dc->d_ecsParsed = true;
e325f20c 795 vector<DNSRecord> ret;
ea634573 796 vector<uint8_t> packet;
b23b8614 797
ad42489c 798 auto luaconfsLocal = g_luaconfs.getLocal();
b8470add
PL
799 // Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query
800 bool wantsRPZ(true);
d9d3f9c1 801 RecProtoBufMessage pbMessage(RecProtoBufMessage::Response);
aa7929a3 802#ifdef HAVE_PROTOBUF
d9d3f9c1 803 if (luaconfsLocal->protobufServer) {
5cc8371b 804 Netmask requestorNM(dc->d_source, dc->d_source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
e1c8a4bb 805 const ComboAddress& requestor = requestorNM.getMaskedNetwork();
5cc8371b 806 pbMessage.update(dc->d_uuid, &requestor, &dc->d_destination, dc->d_tcp, dc->d_mdp.d_header.id);
b40562da 807 pbMessage.setEDNSSubnet(dc->d_ednssubnet.source, dc->d_ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
d9d3f9c1
RG
808 pbMessage.setQuestion(dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
809 }
810#endif /* HAVE_PROTOBUF */
ad42489c 811
3ddb9247 812 DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
ea634573
BH
813
814 pw.getHeader()->aa=0;
815 pw.getHeader()->ra=1;
c154c8a4 816 pw.getHeader()->qr=1;
bb4bdbaf 817 pw.getHeader()->tc=0;
ea634573 818 pw.getHeader()->id=dc->d_mdp.d_header.id;
10321a98 819 pw.getHeader()->rd=dc->d_mdp.d_header.rd;
57769f13 820 pw.getHeader()->cd=dc->d_mdp.d_header.cd;
ea634573 821
904d3219
PD
822 uint32_t minTTL=std::numeric_limits<uint32_t>::max();
823
824 SyncRes sr(dc->d_now);
0c43f455 825
2e921ec6 826 bool DNSSECOK=false;
3457a2a0 827 if(t_pdl) {
f26bf547 828 sr.setLuaEngine(t_pdl);
3457a2a0 829 }
9eec8c98 830 if(g_dnssecmode != DNSSECMode::Off) {
30ee601a 831 sr.setDoDNSSEC(true);
9eec8c98
PL
832
833 // Does the requestor want DNSSEC records?
834 if(edo.d_Z & EDNSOpts::DNSSECOK) {
835 DNSSECOK=true;
836 g_stats.dnssecQueries++;
837 }
838 } else {
839 // Ignore the client-set CD flag
840 pw.getHeader()->cd=0;
5b9853c9 841 }
0c43f455
RG
842 sr.setDNSSECValidationRequested(g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode==DNSSECMode::ValidateForLog || ((dc->d_mdp.d_header.ad || DNSSECOK) && g_dnssecmode==DNSSECMode::Process));
843
4898a348 844#ifdef HAVE_PROTOBUF
30ee601a 845 sr.setInitialRequestId(dc->d_uuid);
4898a348 846#endif
0c43f455 847
2fe3354d 848 sr.setQuerySource(dc->d_remote, g_useIncomingECS && !dc->d_ednssubnet.source.empty() ? boost::optional<const EDNSSubnetOpts&>(dc->d_ednssubnet) : boost::none);
57769f13 849
904d3219
PD
850 bool tracedQuery=false; // we could consider letting Lua know about this too
851 bool variableAnswer = false;
9fc36e90 852 bool shouldNotValidate = false;
904d3219 853
ef3b6cd7
RG
854 /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
855 int res = RCode::NoError;
1f1ca368 856 DNSFilterEngine::Policy appliedPolicy;
39ec5d29 857 DNSRecord spoofed;
5cc8371b 858 RecursorLua4::DNSQuestion dq(dc->d_source, dc->d_destination, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_tcp, variableAnswer, wantsRPZ);
6e505c5e
RG
859 dq.ednsFlags = &edo.d_Z;
860 dq.ednsOptions = &dc->d_ednsOpts;
861 dq.tag = dc->d_tag;
862 dq.discardedPolicies = &sr.d_discardedPolicies;
863 dq.policyTags = &dc->d_policyTags;
864 dq.appliedPolicy = &appliedPolicy;
865 dq.currentRecords = &ret;
866 dq.dh = &dc->d_mdp.d_header;
05c74122 867 dq.data = dc->d_data;
67e31ebe
RG
868#ifdef HAVE_PROTOBUF
869 dq.requestorId = dc->d_requestorId;
590388d2 870 dq.deviceId = dc->d_deviceId;
67e31ebe 871#endif
ba21fcfe 872
e661a20b 873 if(dc->d_mdp.d_qtype==QType::ANY && !dc->d_tcp && g_anyToTcp) {
56b4d21b
PD
874 pw.getHeader()->tc = 1;
875 res = 0;
876 variableAnswer = true;
e661a20b
PD
877 goto sendit;
878 }
879
f26bf547 880 if(t_traceRegex && t_traceRegex->match(dc->d_mdp.d_qname.toString())) {
77499b05
BH
881 sr.setLogMode(SyncRes::Store);
882 tracedQuery=true;
883 }
3ddb9247 884
8f7473d7 885
976ec823 886 if(!g_quiet || tracedQuery) {
461df9d2 887 L<<Logger::Warning<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
976ec823 888 <<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote();
b40562da
RG
889 if(!dc->d_ednssubnet.source.empty()) {
890 L<<" (ecs "<<dc->d_ednssubnet.source.toString()<<")";
6e986f5e 891 }
976ec823 892 L<<endl;
893 }
c75a6a9e 894
fededf47 895 sr.setId(MT->getTid());
67828389 896 if(!dc->d_mdp.d_header.rd)
c836dc19
BH
897 sr.setCacheOnly();
898
f26bf547
RG
899 if (t_pdl) {
900 t_pdl->prerpz(dq, res);
0a273054
RG
901 }
902
db486de5 903 // Check if the query has a policy attached to it
0a273054 904 if (wantsRPZ) {
5cc8371b 905 appliedPolicy = luaconfsLocal->dfe.getQueryPolicy(dc->d_mdp.d_qname, dc->d_source, sr.d_discardedPolicies);
0a273054 906 }
644dd1da 907
54be222b 908 // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
f26bf547 909 if(!t_pdl || !t_pdl->preresolve(dq, res)) {
b8470add 910
30ee601a 911 sr.setWantsRPZ(wantsRPZ);
b8470add
PL
912 if(wantsRPZ) {
913 switch(appliedPolicy.d_kind) {
914 case DNSFilterEngine::PolicyKind::NoAction:
915 break;
916 case DNSFilterEngine::PolicyKind::Drop:
917 g_stats.policyDrops++;
7a25883a 918 g_stats.policyResults[appliedPolicy.d_kind]++;
b8470add
PL
919 delete dc;
920 dc=0;
921 return;
922 case DNSFilterEngine::PolicyKind::NXDOMAIN:
923 g_stats.policyResults[appliedPolicy.d_kind]++;
924 res=RCode::NXDomain;
925 goto haveAnswer;
926 case DNSFilterEngine::PolicyKind::NODATA:
927 g_stats.policyResults[appliedPolicy.d_kind]++;
928 res=RCode::NoError;
db486de5 929 goto haveAnswer;
b8470add
PL
930 case DNSFilterEngine::PolicyKind::Custom:
931 g_stats.policyResults[appliedPolicy.d_kind]++;
932 res=RCode::NoError;
a9e029ee 933 spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname);
b8470add 934 ret.push_back(spoofed);
53508135 935 handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret);
b8470add
PL
936 goto haveAnswer;
937 case DNSFilterEngine::PolicyKind::Truncate:
938 if(!dc->d_tcp) {
939 g_stats.policyResults[appliedPolicy.d_kind]++;
940 res=RCode::NoError;
941 pw.getHeader()->tc=1;
942 goto haveAnswer;
943 }
944 break;
945 }
db486de5
PL
946 }
947
b8470add 948 // Query got not handled for QNAME Policy reasons, now actually go out to find an answer
44971ca0
PD
949 try {
950 res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
9fc36e90 951 shouldNotValidate = sr.wasOutOfBand();
44971ca0
PD
952 }
953 catch(ImmediateServFailException &e) {
854d44e3 954 if(g_logCommonErrors)
955 L<<Logger::Notice<<"Sending SERVFAIL to "<<dc->getRemote()<<" during resolve of '"<<dc->d_mdp.d_qname<<"' because: "<<e.reason<<endl;
44971ca0
PD
956 res = RCode::ServFail;
957 }
4485aa35 958
1921a4c2
RG
959 dq.validationState = sr.getValidationState();
960
b8470add
PL
961 // During lookup, an NSDNAME or NSIP trigger was hit in RPZ
962 if (res == -2) { // XXX This block should be macro'd, it is repeated post-resolve.
963 appliedPolicy = sr.d_appliedPolicy;
964 g_stats.policyResults[appliedPolicy.d_kind]++;
965 switch(appliedPolicy.d_kind) {
966 case DNSFilterEngine::PolicyKind::NoAction: // This can never happen
967 throw PDNSException("NoAction policy returned while a NSDNAME or NSIP trigger was hit");
968 case DNSFilterEngine::PolicyKind::Drop:
969 g_stats.policyDrops++;
970 delete dc;
971 dc=0;
972 return;
973 case DNSFilterEngine::PolicyKind::NXDOMAIN:
974 ret.clear();
975 res=RCode::NXDomain;
976 goto haveAnswer;
977
978 case DNSFilterEngine::PolicyKind::NODATA:
979 ret.clear();
980 res=RCode::NoError;
981 goto haveAnswer;
982
983 case DNSFilterEngine::PolicyKind::Truncate:
984 if(!dc->d_tcp) {
985 ret.clear();
986 res=RCode::NoError;
987 pw.getHeader()->tc=1;
988 goto haveAnswer;
989 }
990 break;
991
992 case DNSFilterEngine::PolicyKind::Custom:
993 ret.clear();
994 res=RCode::NoError;
a9e029ee 995 spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname);
b8470add 996 ret.push_back(spoofed);
53508135 997 handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret);
b8470add
PL
998 goto haveAnswer;
999 }
1000 }
1001
1002 if (wantsRPZ) {
1f1ca368 1003 appliedPolicy = luaconfsLocal->dfe.getPostPolicy(ret, sr.d_discardedPolicies);
b8470add 1004 }
db486de5 1005
f26bf547 1006 if(t_pdl) {
db486de5
PL
1007 if(res == RCode::NoError) {
1008 auto i=ret.cbegin();
1009 for(; i!= ret.cend(); ++i)
1010 if(i->d_type == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER)
1011 break;
f26bf547 1012 if(i == ret.cend() && t_pdl->nodata(dq, res))
3ca4e735
PL
1013 shouldNotValidate = true;
1014
db486de5 1015 }
f26bf547 1016 else if(res == RCode::NXDomain && t_pdl->nxdomain(dq, res))
3ca4e735 1017 shouldNotValidate = true;
db486de5 1018
f26bf547 1019 if(t_pdl->postresolve(dq, res))
3ca4e735 1020 shouldNotValidate = true;
db486de5
PL
1021 }
1022
b8470add
PL
1023 if (wantsRPZ) { //XXX This block is repeated, see above
1024 g_stats.policyResults[appliedPolicy.d_kind]++;
1025 switch(appliedPolicy.d_kind) {
1026 case DNSFilterEngine::PolicyKind::NoAction:
1027 break;
1028 case DNSFilterEngine::PolicyKind::Drop:
1029 g_stats.policyDrops++;
1030 delete dc;
1031 dc=0;
1032 return;
1033 case DNSFilterEngine::PolicyKind::NXDOMAIN:
1034 ret.clear();
1035 res=RCode::NXDomain;
1036 goto haveAnswer;
1037
1038 case DNSFilterEngine::PolicyKind::NODATA:
1039 ret.clear();
1040 res=RCode::NoError;
1041 goto haveAnswer;
1042
1043 case DNSFilterEngine::PolicyKind::Truncate:
1044 if(!dc->d_tcp) {
1045 ret.clear();
1046 res=RCode::NoError;
1047 pw.getHeader()->tc=1;
1048 goto haveAnswer;
1049 }
1050 break;
1051
1052 case DNSFilterEngine::PolicyKind::Custom:
1053 ret.clear();
1054 res=RCode::NoError;
a9e029ee 1055 spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname);
b8470add 1056 ret.push_back(spoofed);
53508135 1057 handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret);
b8470add
PL
1058 goto haveAnswer;
1059 }
644dd1da 1060 }
4485aa35 1061 }
644dd1da 1062 haveAnswer:;
3e8216c8 1063 if(res == PolicyDecision::DROP) {
e9c2ad3a 1064 g_stats.policyDrops++;
ae7e77ad 1065 delete dc;
1066 dc=0;
1067 return;
3ddb9247 1068 }
9cdfab64 1069 if(tracedQuery || res == -1 || res == RCode::ServFail || pw.getHeader()->rcode == RCode::ServFail)
1dc8f4d0 1070 {
85ffbc53
PD
1071 string trace(sr.getTrace());
1072 if(!trace.empty()) {
1073 vector<string> lines;
1074 boost::split(lines, trace, boost::is_any_of("\n"));
1dc8f4d0 1075 for(const string& line : lines) {
85ffbc53
PD
1076 if(!line.empty())
1077 L<<Logger::Warning<< line << endl;
1078 }
1079 }
1080 }
3ddb9247 1081
9cdfab64 1082 if(res == -1) {
0fe1d080
PD
1083 pw.getHeader()->rcode=RCode::ServFail;
1084 // no commit here, because no record
1085 g_stats.servFails++;
1086 }
288f4aa9 1087 else {
ea634573 1088 pw.getHeader()->rcode=res;
92011b8f 1089
f3fe4ae6 1090 // Does the validation mode or query demand validation?
0c43f455 1091 if(!shouldNotValidate && sr.isDNSSECValidationRequested()) {
b25cae9a 1092 try {
f3fe4ae6 1093 if(sr.doLog()) {
5cc8371b 1094 L<<Logger::Warning<<"Starting validation of answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<endl;
2e921ec6 1095 }
4d2be65d
RG
1096
1097 auto state = sr.getValidationState();
1098
b25cae9a 1099 if(state == Secure) {
2e921ec6 1100 if(sr.doLog()) {
5cc8371b 1101 L<<Logger::Warning<<"Answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<" validates correctly"<<endl;
2e921ec6 1102 }
b25cae9a 1103
1104 // Is the query source interested in the value of the ad-bit?
885c8881 1105 if (dc->d_mdp.d_header.ad || DNSSECOK)
b25cae9a 1106 pw.getHeader()->ad=1;
1107 }
1108 else if(state == Insecure) {
f3fe4ae6 1109 if(sr.doLog()) {
5cc8371b 1110 L<<Logger::Warning<<"Answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<" validates as Insecure"<<endl;
12ce523e 1111 }
b25cae9a 1112
1113 pw.getHeader()->ad=0;
f3fe4ae6 1114 }
b25cae9a 1115 else if(state == Bogus) {
c87e1876 1116 if(g_dnssecLogBogus || sr.doLog() || g_dnssecmode == DNSSECMode::ValidateForLog) {
5cc8371b 1117 L<<Logger::Warning<<"Answer to "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" for "<<dc->getRemote()<<" validates as Bogus"<<endl;
b25cae9a 1118 }
1119
1120 // Does the query or validation mode sending out a SERVFAIL on validation errors?
885c8881 1121 if(!pw.getHeader()->cd && (g_dnssecmode == DNSSECMode::ValidateAll || dc->d_mdp.d_header.ad || DNSSECOK)) {
b25cae9a 1122 if(sr.doLog()) {
5fc44cd2 1123 L<<Logger::Warning<<"Sending out SERVFAIL for "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" because recursor or query demands it for Bogus results"<<endl;
b25cae9a 1124 }
1125
1126 pw.getHeader()->rcode=RCode::ServFail;
1127 goto sendit;
1128 } else {
1129 if(sr.doLog()) {
5fc44cd2 1130 L<<Logger::Warning<<"Not sending out SERVFAIL for "<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<" Bogus validation since neither config nor query demands this"<<endl;
b25cae9a 1131 }
1132 }
1133 }
1134 }
1135 catch(ImmediateServFailException &e) {
1136 if(g_logCommonErrors)
5fc44cd2 1137 L<<Logger::Notice<<"Sending SERVFAIL to "<<dc->getRemote()<<" during validation of '"<<dc->d_mdp.d_qname<<"|"<<QType(dc->d_mdp.d_qtype).getName()<<"' because: "<<e.reason<<endl;
b25cae9a 1138 pw.getHeader()->rcode=RCode::ServFail;
1139 goto sendit;
f3fe4ae6 1140 }
b3f0ed10 1141 }
1142
c154c8a4 1143 if(ret.size()) {
92476c8b 1144 orderAndShuffle(ret);
5cc8371b 1145 if(auto sl = luaconfsLocal->sortlist.getOrderCmp(dc->d_source)) {
20d84f77 1146 stable_sort(ret.begin(), ret.end(), *sl);
3e61e7f7 1147 variableAnswer=true;
1148 }
8e079f3a 1149 }
0afa32d4
RG
1150
1151 bool needCommit = false;
8e079f3a 1152 for(auto i=ret.cbegin(); i!=ret.cend(); ++i) {
3e80ebce
KM
1153 if( ! DNSSECOK &&
1154 ( i->d_type == QType::NSEC3 ||
1155 (
1156 ( i->d_type == QType::RRSIG || i->d_type==QType::NSEC ) &&
1157 (
1158 ( dc->d_mdp.d_qtype != i->d_type && dc->d_mdp.d_qtype != QType::ANY ) ||
1159 i->d_place != DNSResourceRecord::ANSWER
1160 )
1161 )
1162 )
1163 ) {
2e921ec6 1164 continue;
3e80ebce
KM
1165 }
1166
97c6d7e5
RG
1167 if (!addRecordToPacket(pw, *i, minTTL, maxanswersize)) {
1168 needCommit = false;
1169 break;
1170 }
1171 needCommit = true;
1172
aa7929a3 1173#ifdef HAVE_PROTOBUF
d9d3f9c1
RG
1174 if(luaconfsLocal->protobufServer && (i->d_type == QType::A || i->d_type == QType::AAAA || i->d_type == QType::CNAME)) {
1175 pbMessage.addRR(*i);
aa7929a3
RG
1176 }
1177#endif
ea634573 1178 }
0afa32d4 1179 if(needCommit)
8e079f3a 1180 pw.commit();
288f4aa9 1181 }
10321a98 1182 sendit:;
b3f0ed10 1183
97c6d7e5
RG
1184 if (haveEDNS) {
1185 /* we try to add the EDNS OPT RR even for truncated answers,
1186 as rfc6891 states:
1187 "The minimal response MUST be the DNS header, question section, and an
1188 OPT record. This MUST also occur when a truncated response (using
1189 the DNS header's TC bit) is returned."
1190 */
1191 if (addRecordToPacket(pw, makeOpt(edo.d_packetsize, 0, edo.d_Z), minTTL, maxanswersize)) {
1192 pw.commit();
1193 }
1194 }
1195
79332bff 1196 g_rs.submitResponse(dc->d_mdp.d_qtype, packet.size(), !dc->d_tcp);
5cc8371b 1197 updateResponseStats(res, dc->d_source, packet.size(), &dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
aa7929a3 1198#ifdef HAVE_PROTOBUF
b790ef3d 1199 if (luaconfsLocal->protobufServer && (!luaconfsLocal->protobufTaggedOnly || (appliedPolicy.d_name && !appliedPolicy.d_name->empty()) || !dc->d_policyTags.empty())) {
d9d3f9c1
RG
1200 pbMessage.setBytes(packet.size());
1201 pbMessage.setResponseCode(pw.getHeader()->rcode);
0a273054
RG
1202 if (appliedPolicy.d_name) {
1203 pbMessage.setAppliedPolicy(*appliedPolicy.d_name);
f3da83fe 1204 pbMessage.setAppliedPolicyType(appliedPolicy.d_type);
0a273054 1205 }
d9d3f9c1 1206 pbMessage.setPolicyTags(dc->d_policyTags);
58307a85 1207 pbMessage.setQueryTime(dc->d_now.tv_sec, dc->d_now.tv_usec);
67e31ebe 1208 pbMessage.setRequestorId(dq.requestorId);
590388d2 1209 pbMessage.setDeviceId(dq.deviceId);
02b47f43 1210 protobufLogResponse(luaconfsLocal->protobufServer, pbMessage);
aa7929a3
RG
1211 }
1212#endif
ea634573 1213 if(!dc->d_tcp) {
b71b60ee 1214 struct msghdr msgh;
1215 struct iovec iov;
1216 char cbuf[256];
1217 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)&*packet.begin(), packet.size(), &dc->d_remote);
2c0af54f
PD
1218 msgh.msg_control=NULL;
1219
cbc03320 1220 if(g_fromtosockets.count(dc->d_socket)) {
fbe2a2e0 1221 addCMsgSrcAddr(&msgh, cbuf, &dc->d_local, 0);
2c0af54f 1222 }
cbc03320 1223 if(sendmsg(dc->d_socket, &msgh, 0) < 0 && g_logCommonErrors)
5cc8371b 1224 L<<Logger::Warning<<"Sending UDP reply to client "<<dc->getRemote()<<" failed with: "<<strerror(errno)<<endl;
3762e821 1225 if(!SyncRes::s_nopacketcache && !variableAnswer && !sr.wasVariable() ) {
e9f63d47 1226 t_packetCache->insertResponsePacket(dc->d_tag, dc->d_qhash, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass,
76e2b9e3 1227 string((const char*)&*packet.begin(), packet.size()),
3ddb9247 1228 g_now.tv_sec,
76e2b9e3 1229 pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl :
d9d3f9c1
RG
1230 min(minTTL,SyncRes::s_packetcachettl),
1231 &pbMessage);
1051f8a9 1232 }
3762e821 1233 // else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
feccc9fc 1234 }
9c495589
BH
1235 else {
1236 char buf[2];
ea634573
BH
1237 buf[0]=packet.size()/256;
1238 buf[1]=packet.size()%256;
feccc9fc 1239
c038218b 1240 Utility::iovec iov[2];
feccc9fc 1241
ea634573
BH
1242 iov[0].iov_base=(void*)buf; iov[0].iov_len=2;
1243 iov[1].iov_base=(void*)&*packet.begin(); iov[1].iov_len = packet.size();
feccc9fc 1244
dd079764 1245 int wret=Utility::writev(dc->d_socket, iov, 2);
0e9d9ce2 1246 bool hadError=true;
feccc9fc 1247
dd079764 1248 if(wret == 0)
18af64a8 1249 L<<Logger::Error<<"EOF writing TCP answer to "<<dc->getRemote()<<endl;
dd079764 1250 else if(wret < 0 )
18af64a8 1251 L<<Logger::Error<<"Error writing TCP answer to "<<dc->getRemote()<<": "<< strerror(errno) <<endl;
dd079764
RG
1252 else if((unsigned int)wret != 2 + packet.size())
1253 L<<Logger::Error<<"Oops, partial answer sent to "<<dc->getRemote()<<" for "<<dc->d_mdp.d_qname<<" (size="<< (2 + packet.size()) <<", sent "<<wret<<")"<<endl;
0e9d9ce2 1254 else
18af64a8 1255 hadError=false;
3ddb9247 1256
09e6702a 1257 // update tcp connection status, either by closing or moving to 'BYTE0'
3ddb9247 1258
09e6702a 1259 if(hadError) {
18af64a8 1260 // no need to remove us from FDM, we weren't there
c36bc97a 1261 dc->d_socket = -1;
09e6702a 1262 }
a6ae6414 1263 else {
fde296a3
RG
1264 dc->d_tcpConnection->queriesCount++;
1265 if (g_tcpMaxQueriesPerConn && dc->d_tcpConnection->queriesCount >= g_tcpMaxQueriesPerConn) {
1266 dc->d_socket = -1;
1267 }
1268 else {
1269 dc->d_tcpConnection->state=TCPConnection::BYTE0;
1270 Utility::gettimeofday(&g_now, 0); // needs to be updated
1271 t_fdm->addReadFD(dc->d_socket, handleRunningTCPQuestion, dc->d_tcpConnection);
1272 t_fdm->setReadTTD(dc->d_socket, g_now, g_tcpTimeout);
1273 }
0e9d9ce2 1274 }
9c495589 1275 }
2c9119cd 1276 float spent=makeFloat(sr.getNow()-dc->d_now);
1d5b3ce6 1277 if(!g_quiet) {
461df9d2 1278 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 1279 L<<"': "<<ntohs(pw.getHeader()->ancount)<<" answers, "<<ntohs(pw.getHeader()->arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
2c9119cd 1280 sr.d_totUsec/1000.0<<" netw ms, "<< spent*1000.0<<" tot ms, "<<
1281 sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<< res;
1282
1283 if(!shouldNotValidate && sr.isDNSSECValidationRequested()) {
1284 L<< ", dnssec="<<vStates[sr.getValidationState()];
1285 }
1286
1287 L<<endl;
1288
c75a6a9e 1289 }
b23b8614 1290
3ddb9247 1291 sr.d_outqueries ? t_RC->cacheMisses++ : t_RC->cacheHits++;
2c9119cd 1292
fe213470
BH
1293 if(spent < 0.001)
1294 g_stats.answers0_1++;
1295 else if(spent < 0.010)
1296 g_stats.answers1_10++;
1297 else if(spent < 0.1)
1298 g_stats.answers10_100++;
1299 else if(spent < 1.0)
1300 g_stats.answers100_1000++;
1301 else
1302 g_stats.answersSlow++;
1303
574af7ea 1304 uint64_t newLat=(uint64_t)(spent*1000000);
b841314c 1305 newLat = min(newLat,(uint64_t)(((uint64_t) g_networkTimeoutMsec)*1000)); // outliers of several minutes exist..
08f3f638 1306 g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + (float)newLat/g_latencyStatSize;
0a6b1027 1307 // no worries, we do this for packet cache hits elsewhere
19178da9 1308
1309 auto ourtime = 1000.0*spent-sr.d_totUsec/1000.0; // in msec
1310 if(ourtime < 1)
1311 g_stats.ourtime0_1++;
1312 else if(ourtime < 2)
1313 g_stats.ourtime1_2++;
1314 else if(ourtime < 4)
1315 g_stats.ourtime2_4++;
1316 else if(ourtime < 8)
1317 g_stats.ourtime4_8++;
1318 else if(ourtime < 16)
1319 g_stats.ourtime8_16++;
1320 else if(ourtime < 32)
1321 g_stats.ourtime16_32++;
1322 else {
1323 // cerr<<"SLOW: "<<ourtime<<"ms -> "<<dc->d_mdp.d_qname<<"|"<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<endl;
1324 g_stats.ourtimeSlow++;
1325 }
042da1a1 1326 if(ourtime >= 0.0) {
1327 newLat=ourtime*1000; // usec
1328 g_stats.avgLatencyOursUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyOursUsec + (float)newLat/g_latencyStatSize;
1329 }
c6d04bdc 1330 // cout<<dc->d_mdp.d_qname<<"\t"<<MT->getUsec()<<"\t"<<sr.d_outqueries<<endl;
ea634573 1331 delete dc;
c36bc97a 1332 dc=0;
288f4aa9 1333 }
3f81d239 1334 catch(PDNSException &ae) {
a903b39c 1335 L<<Logger::Error<<"startDoResolve problem "<<makeLoginfo(dc)<<": "<<ae.reason<<endl;
c36bc97a 1336 delete dc;
288f4aa9 1337 }
7b1469bb 1338 catch(MOADNSException& e) {
a903b39c 1339 L<<Logger::Error<<"DNS parser error "<<makeLoginfo(dc) <<": "<<dc->d_mdp.d_qname<<", "<<e.what()<<endl;
c36bc97a 1340 delete dc;
7b1469bb 1341 }
fdbf35ac 1342 catch(std::exception& e) {
068c7634
PD
1343 L<<Logger::Error<<"STL error "<< makeLoginfo(dc)<<": "<<e.what();
1344
1345 // Luawrapper nests the exception from Lua, so we unnest it here
1346 try {
1347 std::rethrow_if_nested(e);
2010ac95
RG
1348 } catch(const std::exception& ne) {
1349 L<<". Extra info: "<<ne.what();
068c7634
PD
1350 } catch(...) {}
1351
1352 L<<endl;
c36bc97a 1353 delete dc;
c154c8a4 1354 }
288f4aa9 1355 catch(...) {
a903b39c 1356 L<<Logger::Error<<"Any other exception in a resolver context "<< makeLoginfo(dc) <<endl;
288f4aa9 1357 }
3ddb9247 1358
ec6eacbc 1359 g_stats.maxMThreadStackUsage = max(MT->getMaxStackUsage(), g_stats.maxMThreadStackUsage);
288f4aa9
BH
1360}
1361
d187038c 1362static void makeControlChannelSocket(int processNum=-1)
1d5b3ce6 1363{
2d733c0f 1364 string sockname=::arg()["socket-dir"]+"/"+s_programname;
677e2a46 1365 if(processNum >= 0)
335da0ba 1366 sockname += "."+std::to_string(processNum);
677e2a46 1367 sockname+=".controlsocket";
41f7a068 1368 s_rcc.listen(sockname);
3ddb9247 1369
387de317
BH
1370 int sockowner = -1;
1371 int sockgroup = -1;
1372
1373 if (!::arg().isEmpty("socket-group"))
1374 sockgroup=::arg().asGid("socket-group");
1375 if (!::arg().isEmpty("socket-owner"))
1376 sockowner=::arg().asUid("socket-owner");
3ddb9247 1377
f838ad8d
BH
1378 if (sockgroup > -1 || sockowner > -1) {
1379 if(chown(sockname.c_str(), sockowner, sockgroup) < 0) {
1380 unixDie("Failed to chown control socket");
1381 }
1382 }
387de317
BH
1383
1384 // do mode change if socket-mode is given
1385 if(!::arg().isEmpty("socket-mode")) {
1386 mode_t sockmode=::arg().asMode("socket-mode");
34c513f9
RG
1387 if(chmod(sockname.c_str(), sockmode) < 0) {
1388 unixDie("Failed to chmod control socket");
1389 }
387de317 1390 }
1d5b3ce6
BH
1391}
1392
5cc8371b
RG
1393static void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass,
1394 bool& foundECS, EDNSSubnetOpts* ednssubnet, std::map<uint16_t, EDNSOptionView>* options,
1395 bool& foundXPF, ComboAddress* xpfSource, ComboAddress* xpfDest)
02b47f43 1396{
59cb4a79 1397 const bool lookForXPF = xpfSource != nullptr && g_xpfRRCode != 0;
5cc8371b
RG
1398 const bool lookForECS = ednssubnet != nullptr;
1399 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(question.c_str());
02b47f43
RG
1400 size_t questionLen = question.length();
1401 unsigned int consumed=0;
1402 *dnsname=DNSName(question.c_str(), questionLen, sizeof(dnsheader), false, qtype, qclass, &consumed);
1403
1404 size_t pos= sizeof(dnsheader)+consumed+4;
5cc8371b
RG
1405 const size_t headerSize = /* root */ 1 + sizeof(dnsrecordheader);
1406 const uint16_t arcount = ntohs(dh->arcount);
1407
1408 for (uint16_t arpos = 0; arpos < arcount && questionLen > (pos + headerSize) && ((lookForECS && !foundECS) || (lookForXPF && !foundXPF)); arpos++) {
1409 if (question.at(pos) != 0) {
1410 /* not an OPT or a XPF, bye. */
1411 return;
1412 }
1413
1414 pos += 1;
1415 const dnsrecordheader* drh = reinterpret_cast<const dnsrecordheader*>(&question.at(pos));
1416 pos += sizeof(dnsrecordheader);
1417
1418 if (pos >= questionLen) {
1419 return;
1420 }
1421
02b47f43 1422 /* OPT root label (1) followed by type (2) */
5cc8371b 1423 if(lookForECS && ntohs(drh->d_type) == QType::OPT) {
00b8cadc
RG
1424 if (!options) {
1425 char* ecsStart = nullptr;
1426 size_t ecsLen = 0;
5cc8371b
RG
1427 /* we need to pass the record len */
1428 int res = getEDNSOption(const_cast<char*>(reinterpret_cast<const char*>(&question.at(pos - sizeof(drh->d_clen)))), questionLen - pos + sizeof(drh->d_clen), EDNSOptionCode::ECS, &ecsStart, &ecsLen);
00b8cadc
RG
1429 if (res == 0 && ecsLen > 4) {
1430 EDNSSubnetOpts eso;
1431 if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) {
1432 *ednssubnet=eso;
5cc8371b 1433 foundECS = true;
00b8cadc
RG
1434 }
1435 }
1436 }
1437 else {
5cc8371b
RG
1438 /* we need to pass the record len */
1439 int res = getEDNSOptions(reinterpret_cast<const char*>(&question.at(pos -sizeof(drh->d_clen))), questionLen - pos + (sizeof(drh->d_clen)), *options);
00b8cadc
RG
1440 if (res == 0) {
1441 const auto& it = options->find(EDNSOptionCode::ECS);
1442 if (it != options->end() && it->second.content != nullptr && it->second.size > 0) {
1443 EDNSSubnetOpts eso;
1444 if(getEDNSSubnetOptsFromString(it->second.content, it->second.size, &eso)) {
1445 *ednssubnet=eso;
5cc8371b 1446 foundECS = true;
00b8cadc
RG
1447 }
1448 }
02b47f43
RG
1449 }
1450 }
1451 }
59cb4a79 1452 else if (lookForXPF && ntohs(drh->d_type) == g_xpfRRCode && ntohs(drh->d_class) == QClass::IN && drh->d_ttl == 0) {
5cc8371b
RG
1453 if ((questionLen - pos) < ntohs(drh->d_clen)) {
1454 return;
1455 }
1456
1457 foundXPF = parseXPFPayload(reinterpret_cast<const char*>(&question.at(pos)), ntohs(drh->d_clen), *xpfSource, xpfDest);
1458 }
1459
1460 pos += ntohs(drh->d_clen);
02b47f43
RG
1461 }
1462}
1463
d187038c 1464static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 1465{
cd989c87 1466 shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(var);
c038218b 1467
879b3f70 1468 if(conn->state==TCPConnection::BYTE0) {
b841314c 1469 ssize_t bytes=recv(conn->getFD(), conn->data, 2, 0);
09e6702a 1470 if(bytes==1)
667f7e60 1471 conn->state=TCPConnection::BYTE1;
3ddb9247 1472 if(bytes==2) {
a0aa4f64 1473 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
667f7e60
BH
1474 conn->bytesread=0;
1475 conn->state=TCPConnection::GETQUESTION;
09e6702a
BH
1476 }
1477 if(!bytes || bytes < 0) {
bb4bdbaf 1478 t_fdm->removeReadFD(fd);
09e6702a
BH
1479 return;
1480 }
1481 }
667f7e60 1482 else if(conn->state==TCPConnection::BYTE1) {
b841314c 1483 ssize_t bytes=recv(conn->getFD(), conn->data+1, 1, 0);
09e6702a 1484 if(bytes==1) {
667f7e60 1485 conn->state=TCPConnection::GETQUESTION;
a0aa4f64 1486 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
667f7e60 1487 conn->bytesread=0;
09e6702a
BH
1488 }
1489 if(!bytes || bytes < 0) {
1490 if(g_logCommonErrors)
5cc8371b 1491 L<<Logger::Error<<"TCP client "<< conn->d_remote.toStringWithPort() <<" disconnected after first byte"<<endl;
bb4bdbaf 1492 t_fdm->removeReadFD(fd);
09e6702a
BH
1493 return;
1494 }
1495 }
667f7e60 1496 else if(conn->state==TCPConnection::GETQUESTION) {
b841314c 1497 ssize_t bytes=recv(conn->getFD(), conn->data + conn->bytesread, conn->qlen - conn->bytesread, 0);
f9d67b41 1498 if(!bytes || bytes < 0 || bytes > std::numeric_limits<std::uint16_t>::max()) {
5cc8371b 1499 L<<Logger::Error<<"TCP client "<< conn->d_remote.toStringWithPort() <<" disconnected while reading question body"<<endl;
bb4bdbaf 1500 t_fdm->removeReadFD(fd);
09e6702a
BH
1501 return;
1502 }
b841314c 1503 conn->bytesread+=(uint16_t)bytes;
667f7e60 1504 if(conn->bytesread==conn->qlen) {
bb4bdbaf 1505 t_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read
879b3f70 1506
f26bf547 1507 DNSComboWriter* dc=nullptr;
09e6702a 1508 try {
cd989c87 1509 dc=new DNSComboWriter(conn->data, conn->qlen, g_now);
09e6702a
BH
1510 }
1511 catch(MOADNSException &mde) {
3ddb9247 1512 g_stats.clientParseError++;
4957a608 1513 if(g_logCommonErrors)
5cc8371b 1514 L<<Logger::Error<<"Unable to parse packet from TCP client "<< conn->d_remote.toStringWithPort() <<endl;
4957a608 1515 return;
09e6702a 1516 }
cd989c87
BH
1517 dc->d_tcpConnection = conn; // carry the torch
1518 dc->setSocket(conn->getFD()); // this is the only time a copy is made of the actual fd
09e6702a 1519 dc->d_tcp=true;
5cc8371b
RG
1520 dc->setRemote(conn->d_remote);
1521 dc->setSource(conn->d_remote);
a6147cd2 1522 ComboAddress dest;
1523 memset(&dest, 0, sizeof(dest));
1524 dest.sin4.sin_family = conn->d_remote.sin4.sin_family;
1525 socklen_t len = dest.getSocklen();
1526 getsockname(conn->getFD(), (sockaddr*)&dest, &len); // if this fails, we're ok with it
1527 dc->setLocal(dest);
5cc8371b 1528 dc->setDestination(dest);
33dcceba
RG
1529 DNSName qname;
1530 uint16_t qtype=0;
1531 uint16_t qclass=0;
1532 bool needECS = false;
5cc8371b 1533 bool needXPF = g_XPFAcl.match(conn->d_remote);
67e31ebe 1534 string requestorId;
590388d2 1535 string deviceId;
aa7929a3 1536#ifdef HAVE_PROTOBUF
02b47f43 1537 auto luaconfsLocal = g_luaconfs.getLocal();
33dcceba
RG
1538 if (luaconfsLocal->protobufServer) {
1539 needECS = true;
1540 }
1541#endif
1542
5cc8371b 1543 if(needECS || needXPF || (t_pdl && t_pdl->d_gettag)) {
33dcceba
RG
1544
1545 try {
00b8cadc 1546 std::map<uint16_t, EDNSOptionView> ednsOptions;
5cc8371b 1547 bool xpfFound = false;
b40562da 1548 dc->d_ecsParsed = true;
5cc8371b
RG
1549 dc->d_ecsFound = false;
1550 getQNameAndSubnet(std::string(conn->data, conn->qlen), &qname, &qtype, &qclass,
1551 dc->d_ecsFound, &dc->d_ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr,
1552 xpfFound, needXPF ? &dc->d_source : nullptr, needXPF ? &dc->d_destination : nullptr);
02b47f43 1553
f26bf547 1554 if(t_pdl && t_pdl->d_gettag) {
33dcceba 1555 try {
5cc8371b 1556 dc->d_tag = t_pdl->gettag(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId);
33dcceba
RG
1557 }
1558 catch(std::exception& e) {
1559 if(g_logCommonErrors)
1560 L<<Logger::Warning<<"Error parsing a query packet qname='"<<qname<<"' for tag determination, setting tag=0: "<<e.what()<<endl;
1561 }
1562 }
1563 }
1564 catch(std::exception& e)
1565 {
1566 if(g_logCommonErrors)
1567 L<<Logger::Warning<<"Error parsing a query packet for tag determination, setting tag=0: "<<e.what()<<endl;
1568 }
1569 }
1570#ifdef HAVE_PROTOBUF
4898a348 1571 if(luaconfsLocal->protobufServer || luaconfsLocal->outgoingProtobufServer) {
67e31ebe 1572 dc->d_requestorId = requestorId;
590388d2 1573 dc->d_deviceId = deviceId;
02b47f43 1574 dc->d_uuid = (*t_uuidGenerator)();
4898a348 1575 }
02b47f43 1576
4898a348 1577 if(luaconfsLocal->protobufServer) {
02b47f43 1578 try {
02b47f43 1579 const struct dnsheader* dh = (const struct dnsheader*) conn->data;
02b47f43 1580
b790ef3d 1581 if (!luaconfsLocal->protobufTaggedOnly) {
5cc8371b 1582 protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, dc->d_uuid, dc->d_source, dc->d_destination, dc->d_ednssubnet.source, true, dh->id, conn->qlen, qname, qtype, qclass, dc->d_policyTags, dc->d_requestorId, dc->d_deviceId);
b790ef3d 1583 }
02b47f43
RG
1584 }
1585 catch(std::exception& e) {
1586 if(g_logCommonErrors)
1587 L<<Logger::Warning<<"Error parsing a TCP query packet for edns subnet: "<<e.what()<<endl;
1588 }
1589 }
aa7929a3 1590#endif
879b3f70 1591 if(dc->d_mdp.d_header.qr) {
4957a608 1592 delete dc;
048f5db6 1593 g_stats.ignoredCount++;
5cc8371b 1594 L<<Logger::Error<<"Ignoring answer from TCP client "<< dc->getRemote() <<" on server socket!"<<endl;
4957a608 1595 return;
879b3f70 1596 }
3abcdab2
PD
1597 if(dc->d_mdp.d_header.opcode) {
1598 delete dc;
048f5db6 1599 g_stats.ignoredCount++;
5cc8371b 1600 L<<Logger::Error<<"Ignoring non-query opcode from TCP client "<< dc->getRemote() <<" on server socket!"<<endl;
3abcdab2
PD
1601 return;
1602 }
09e6702a 1603 else {
4957a608
BH
1604 ++g_stats.qcounter;
1605 ++g_stats.tcpqcounter;
50a5ef72 1606 MT->makeThread(startDoResolve, dc); // deletes dc, will set state to BYTE0 again
4957a608 1607 return;
09e6702a
BH
1608 }
1609 }
1610 }
1611}
1612
6dcd28c3 1613//! Handle new incoming TCP connection
d187038c 1614static void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& )
09e6702a 1615{
37d3f960 1616 ComboAddress addr;
09e6702a 1617 socklen_t addrlen=sizeof(addr);
a683e8bd 1618 int newsock=accept(fd, (struct sockaddr*)&addr, &addrlen);
b841314c 1619 if(newsock>=0) {
85c32340
BH
1620 if(MT->numProcesses() > g_maxMThreads) {
1621 g_stats.overCapacityDrops++;
a7b68ae7
RG
1622 try {
1623 closesocket(newsock);
1624 }
1625 catch(const PDNSException& e) {
1626 L<<Logger::Error<<"Error closing TCP socket after an over capacity drop: "<<e.reason<<endl;
1627 }
85c32340
BH
1628 return;
1629 }
1630
92011b8f 1631 if(t_remotes)
1632 t_remotes->push_back(addr);
49a699c4 1633 if(t_allowFrom && !t_allowFrom->match(&addr)) {
3ddb9247 1634 if(!g_quiet)
4957a608 1635 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping TCP query from "<<addr.toString()<<", address not matched by allow-from"<<endl;
2914b022 1636
09e6702a 1637 g_stats.unauthorizedTCP++;
a7b68ae7
RG
1638 try {
1639 closesocket(newsock);
1640 }
1641 catch(const PDNSException& e) {
1642 L<<Logger::Error<<"Error closing TCP socket after an ACL drop: "<<e.reason<<endl;
1643 }
09e6702a
BH
1644 return;
1645 }
bd0289fc 1646 if(g_maxTCPPerClient && t_tcpClientCounts->count(addr) && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) {
09e6702a 1647 g_stats.tcpClientOverflow++;
a7b68ae7
RG
1648 try {
1649 closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
1650 }
1651 catch(const PDNSException& e) {
1652 L<<Logger::Error<<"Error closing TCP socket after an overflow drop: "<<e.reason<<endl;
1653 }
09e6702a
BH
1654 return;
1655 }
3ddb9247 1656
3897b9e1 1657 setNonBlocking(newsock);
f26bf547 1658 std::shared_ptr<TCPConnection> tc = std::make_shared<TCPConnection>(newsock, addr);
cd989c87 1659 tc->state=TCPConnection::BYTE0;
3ddb9247 1660
cd989c87 1661 t_fdm->addReadFD(tc->getFD(), handleRunningTCPQuestion, tc);
c038218b 1662
0bff046b 1663 struct timeval now;
c038218b 1664 Utility::gettimeofday(&now, 0);
cd989c87 1665 t_fdm->setReadTTD(tc->getFD(), now, g_tcpTimeout);
09e6702a
BH
1666 }
1667}
3ddb9247 1668
d187038c 1669static string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd)
1bc3c142 1670{
183eb877 1671 gettimeofday(&g_now, 0);
b71b60ee 1672 struct timeval diff = g_now - tv;
1673 double delta=(diff.tv_sec*1000 + diff.tv_usec/1000.0);
183eb877 1674
22cf1fda 1675 if(tv.tv_sec && delta > 1000.0) {
b71b60ee 1676 g_stats.tooOldDrops++;
1677 return 0;
1678 }
1679
1bc3c142 1680 ++g_stats.qcounter;
d7f10541
BH
1681 if(fromaddr.sin4.sin_family==AF_INET6)
1682 g_stats.ipv6qcounter++;
1bc3c142
BH
1683
1684 string response;
93f0da94 1685 const struct dnsheader* dh = (struct dnsheader*)question.c_str();
49a3500d 1686 unsigned int ctag=0;
f57486f1 1687 uint32_t qhash = 0;
12aff2e5 1688 bool needECS = false;
5cc8371b 1689 bool needXPF = g_XPFAcl.match(fromaddr);
02b47f43 1690 std::vector<std::string> policyTags;
5fd2577f 1691 LuaContext::LuaObject data;
5cc8371b
RG
1692 ComboAddress source = fromaddr;
1693 ComboAddress destination = destaddr;
67e31ebe 1694 string requestorId;
590388d2 1695 string deviceId;
12aff2e5 1696#ifdef HAVE_PROTOBUF
02b47f43 1697 boost::uuids::uuid uniqueId;
02b47f43
RG
1698 auto luaconfsLocal = g_luaconfs.getLocal();
1699 if (luaconfsLocal->protobufServer) {
4898a348 1700 uniqueId = (*t_uuidGenerator)();
02b47f43 1701 needECS = true;
4898a348 1702 } else if (luaconfsLocal->outgoingProtobufServer) {
02b47f43
RG
1703 uniqueId = (*t_uuidGenerator)();
1704 }
12aff2e5 1705#endif
b40562da
RG
1706 EDNSSubnetOpts ednssubnet;
1707 bool ecsFound = false;
1708 bool ecsParsed = false;
1bc3c142 1709 try {
02b47f43
RG
1710 DNSName qname;
1711 uint16_t qtype=0;
1712 uint16_t qclass=0;
1bc3c142 1713 uint32_t age;
c15ff3df 1714 bool qnameParsed=false;
8f7473d7 1715#ifdef MALLOC_TRACE
1716 /*
1717 static uint64_t last=0;
1718 if(!last)
1719 g_mtracer->clearAllocators();
1720 cout<<g_mtracer->getAllocs()-last<<" "<<g_mtracer->getNumOut()<<" -- BEGIN TRACE"<<endl;
1721 last=g_mtracer->getAllocs();
1722 cout<<g_mtracer->topAllocatorsString()<<endl;
1723 g_mtracer->clearAllocators();
1724 */
1725#endif
55a1378f 1726
5cc8371b 1727 if(needECS || needXPF || (t_pdl && t_pdl->d_gettag)) {
b2eacd67 1728 try {
00b8cadc 1729 std::map<uint16_t, EDNSOptionView> ednsOptions;
5cc8371b
RG
1730 bool xpfFound = false;
1731
1732 ecsFound = false;
1733
1734 getQNameAndSubnet(question, &qname, &qtype, &qclass,
1735 ecsFound, &ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr,
1736 xpfFound, needXPF ? &source : nullptr, needXPF ? &destination : nullptr);
1737
c15ff3df
RG
1738 qnameParsed = true;
1739 ecsParsed = true;
12aff2e5 1740
f26bf547 1741 if(t_pdl && t_pdl->d_gettag) {
12aff2e5 1742 try {
5cc8371b 1743 ctag=t_pdl->gettag(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId);
12aff2e5
RG
1744 }
1745 catch(std::exception& e) {
1746 if(g_logCommonErrors)
1747 L<<Logger::Warning<<"Error parsing a query packet qname='"<<qname<<"' for tag determination, setting tag=0: "<<e.what()<<endl;
1748 }
8ea8c302 1749 }
b2eacd67 1750 }
1751 catch(std::exception& e)
1752 {
1753 if(g_logCommonErrors)
1754 L<<Logger::Warning<<"Error parsing a query packet for tag determination, setting tag=0: "<<e.what()<<endl;
12aff2e5 1755 }
12ce523e 1756 }
3ddb9247 1757
02b47f43 1758 bool cacheHit = false;
d9d3f9c1 1759 RecProtoBufMessage pbMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response);
02b47f43
RG
1760#ifdef HAVE_PROTOBUF
1761 if(luaconfsLocal->protobufServer) {
b790ef3d 1762 if (!luaconfsLocal->protobufTaggedOnly || !policyTags.empty()) {
5cc8371b 1763 protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, source, destination, ednssubnet.source, false, dh->id, question.size(), qname, qtype, qclass, policyTags, requestorId, deviceId);
b790ef3d 1764 }
d9d3f9c1
RG
1765 }
1766#endif /* HAVE_PROTOBUF */
02b47f43 1767
c15ff3df
RG
1768 if (qnameParsed) {
1769 cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, qname, qtype, qclass, g_now.tv_sec, &response, &age, &qhash, &pbMessage));
1770 }
1771 else {
1772 cacheHit = (!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(ctag, question, g_now.tv_sec, &response, &age, &qhash, &pbMessage));
1773 }
1774
d9d3f9c1
RG
1775 if (cacheHit) {
1776#ifdef HAVE_PROTOBUF
b790ef3d 1777 if(luaconfsLocal->protobufServer && (!luaconfsLocal->protobufTaggedOnly || !pbMessage.getAppliedPolicy().empty() || !pbMessage.getPolicyTags().empty())) {
5cc8371b 1778 Netmask requestorNM(source, source.sin4.sin_family == AF_INET ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
e1c8a4bb 1779 const ComboAddress& requestor = requestorNM.getMaskedNetwork();
5cc8371b 1780 pbMessage.update(uniqueId, &requestor, &destination, false, dh->id);
b40562da 1781 pbMessage.setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIpv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6);
58307a85 1782 pbMessage.setQueryTime(g_now.tv_sec, g_now.tv_usec);
67e31ebe 1783 pbMessage.setRequestorId(requestorId);
590388d2 1784 pbMessage.setDeviceId(deviceId);
02b47f43
RG
1785 protobufLogResponse(luaconfsLocal->protobufServer, pbMessage);
1786 }
d9d3f9c1 1787#endif /* HAVE_PROTOBUF */
49a3500d 1788 if(!g_quiet)
5cc8371b 1789 L<<Logger::Notice<<t_id<< " question answered from packet cache tag="<<ctag<<" from "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<endl;
8f7473d7 1790
1bc3c142
BH
1791 g_stats.packetCacheHits++;
1792 SyncRes::s_queries++;
1793 ageDNSPacket(response, age);
b71b60ee 1794 struct msghdr msgh;
1795 struct iovec iov;
1796 char cbuf[256];
1797 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)response.c_str(), response.length(), const_cast<ComboAddress*>(&fromaddr));
2c0af54f
PD
1798 msgh.msg_control=NULL;
1799
cbc03320 1800 if(g_fromtosockets.count(fd)) {
fbe2a2e0 1801 addCMsgSrcAddr(&msgh, cbuf, &destaddr, 0);
b71b60ee 1802 }
cbc03320 1803 if(sendmsg(fd, &msgh, 0) < 0 && g_logCommonErrors)
5cc8371b 1804 L<<Logger::Warning<<"Sending UDP reply to client "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<" failed with: "<<strerror(errno)<<endl;
b71b60ee 1805
97bee66d 1806 if(response.length() >= sizeof(struct dnsheader)) {
dd079764
RG
1807 struct dnsheader tmpdh;
1808 memcpy(&tmpdh, response.c_str(), sizeof(tmpdh));
5cc8371b 1809 updateResponseStats(tmpdh.rcode, source, response.length(), 0, 0);
97bee66d 1810 }
08f3f638 1811 g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + 0.0; // we assume 0 usec
19178da9 1812 g_stats.avgLatencyOursUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyOursUsec + 0.0; // we assume 0 usec
1bc3c142
BH
1813 return 0;
1814 }
3ddb9247 1815 }
1bc3c142
BH
1816 catch(std::exception& e) {
1817 L<<Logger::Error<<"Error processing or aging answer packet: "<<e.what()<<endl;
1818 return 0;
1819 }
3ddb9247 1820
f26bf547 1821 if(t_pdl) {
5cc8371b 1822 if(t_pdl->ipfilter(source, destination, *dh)) {
4ea94941 1823 if(!g_quiet)
5cc8371b 1824 L<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED question from "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<" based on policy"<<endl;
4ea94941 1825 g_stats.policyDrops++;
1826 return 0;
1827 }
1828 }
1829
1bc3c142 1830 if(MT->numProcesses() > g_maxMThreads) {
461df9d2 1831 if(!g_quiet)
5cc8371b 1832 L<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED question from "<<source.toStringWithPort()<<(source != fromaddr ? " (via "+fromaddr.toStringWithPort()+")" : "")<<", over capacity"<<endl;
461df9d2 1833
1bc3c142
BH
1834 g_stats.overCapacityDrops++;
1835 return 0;
1836 }
3ddb9247 1837
1bc3c142
BH
1838 DNSComboWriter* dc = new DNSComboWriter(question.c_str(), question.size(), g_now);
1839 dc->setSocket(fd);
49a3500d 1840 dc->d_tag=ctag;
e9f63d47 1841 dc->d_qhash=qhash;
49a3500d 1842 dc->d_query = question;
5cc8371b
RG
1843 dc->setRemote(fromaddr);
1844 dc->setSource(source);
b71b60ee 1845 dc->setLocal(destaddr);
5cc8371b 1846 dc->setDestination(destination);
1bc3c142 1847 dc->d_tcp=false;
02b47f43 1848 dc->d_policyTags = policyTags;
05c74122 1849 dc->d_data = data;
b40562da
RG
1850 dc->d_ecsFound = ecsFound;
1851 dc->d_ecsParsed = ecsParsed;
1852 dc->d_ednssubnet = ednssubnet;
aa7929a3 1853#ifdef HAVE_PROTOBUF
4898a348 1854 if (luaconfsLocal->protobufServer || luaconfsLocal->outgoingProtobufServer) {
d9d3f9c1
RG
1855 dc->d_uuid = uniqueId;
1856 }
67e31ebe 1857 dc->d_requestorId = requestorId;
590388d2 1858 dc->d_deviceId = deviceId;
aa7929a3
RG
1859#endif
1860
1bc3c142
BH
1861 MT->makeThread(startDoResolve, (void*) dc); // deletes dc
1862 return 0;
3ddb9247
PD
1863}
1864
b71b60ee 1865
d187038c 1866static void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
5db529f8 1867{
a683e8bd 1868 ssize_t len;
5db529f8
BH
1869 char data[1500];
1870 ComboAddress fromaddr;
b71b60ee 1871 struct msghdr msgh;
1872 struct iovec iov;
1873 char cbuf[256];
390f1dab 1874 bool firstQuery = true;
b71b60ee 1875
1876 fromaddr.sin6.sin6_family=AF_INET6; // this makes sure fromaddr is big enough
1877 fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), data, sizeof(data), &fromaddr);
1878
3ddb9247 1879 for(;;)
b71b60ee 1880 if((len=recvmsg(fd, &msgh, 0)) >= 0) {
390f1dab
RG
1881
1882 firstQuery = false;
1883
92011b8f 1884 if(t_remotes)
1885 t_remotes->push_back(fromaddr);
b23b8614 1886
49a699c4 1887 if(t_allowFrom && !t_allowFrom->match(&fromaddr)) {
3ddb9247 1888 if(!g_quiet)
4957a608 1889 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl;
2914b022 1890
5db529f8 1891 g_stats.unauthorizedUDP++;
a9af3782 1892 return;
5db529f8 1893 }
15c01deb 1894 BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
81859ba5 1895 if(!fromaddr.sin4.sin_port) { // also works for IPv6
3ddb9247 1896 if(!g_quiet)
81859ba5 1897 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toStringWithPort()<<", can't deal with port 0"<<endl;
1898
1899 g_stats.clientParseError++; // not quite the best place to put it, but needs to go somewhere
1900 return;
1901 }
5db529f8 1902 try {
b23b8614 1903 dnsheader* dh=(dnsheader*)data;
3ddb9247 1904
b23b8614 1905 if(dh->qr) {
048f5db6 1906 g_stats.ignoredCount++;
4957a608
BH
1907 if(g_logCommonErrors)
1908 L<<Logger::Error<<"Ignoring answer from "<<fromaddr.toString()<<" on server socket!"<<endl;
5db529f8 1909 }
3abcdab2 1910 else if(dh->opcode) {
048f5db6 1911 g_stats.ignoredCount++;
3abcdab2
PD
1912 if(g_logCommonErrors)
1913 L<<Logger::Error<<"Ignoring non-query opcode "<<dh->opcode<<" from "<<fromaddr.toString()<<" on server socket!"<<endl;
1914 }
5db529f8 1915 else {
a683e8bd 1916 string question(data, (size_t)len);
b71b60ee 1917 struct timeval tv={0,0};
1918 HarvestTimestamp(&msgh, &tv);
1919 ComboAddress dest;
c3cecd36 1920 memset(&dest, 0, sizeof(dest)); // this makes sure we ignore this address if not returned by recvmsg above
a6147cd2 1921 auto loc = rplookup(g_listenSocketsAddresses, fd);
1922 if(HarvestDestinationAddress(&msgh, &dest)) {
1923 // but.. need to get port too
1924 if(loc)
1925 dest.sin4.sin_port = loc->sin4.sin_port;
1926 }
1927 else {
1928 if(loc) {
1929 dest = *loc;
1930 }
1931 else {
1932 dest.sin4.sin_family = fromaddr.sin4.sin_family;
a683e8bd
RG
1933 socklen_t slen = dest.getSocklen();
1934 getsockname(fd, (sockaddr*)&dest, &slen); // if this fails, we're ok with it
a6147cd2 1935 }
1936 }
232f0877 1937 if(g_weDistributeQueries)
b71b60ee 1938 distributeAsyncFunction(question, boost::bind(doProcessUDPQuestion, question, fromaddr, dest, tv, fd));
232f0877 1939 else
b71b60ee 1940 doProcessUDPQuestion(question, fromaddr, dest, tv, fd);
5db529f8
BH
1941 }
1942 }
1943 catch(MOADNSException& mde) {
3ddb9247 1944 g_stats.clientParseError++;
84e66a59 1945 if(g_logCommonErrors)
4957a608 1946 L<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<mde.what()<<endl;
5db529f8 1947 }
0b602819
KM
1948 catch(std::runtime_error& e) {
1949 g_stats.clientParseError++;
1950 if(g_logCommonErrors)
1951 L<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<e.what()<<endl;
5db529f8
BH
1952 }
1953 }
ac0e821b
BH
1954 else {
1955 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
390f1dab 1956 if(firstQuery && errno == EAGAIN)
9326cae1 1957 g_stats.noPacketError++;
390f1dab 1958
bf3b0cec 1959 break;
ac0e821b 1960 }
5db529f8
BH
1961}
1962
810ff705 1963static void makeTCPServerSockets(unsigned int threadId)
9c495589 1964{
37d3f960 1965 int fd;
f28307ad 1966 vector<string>locals;
2e3d8a19 1967 stringtok(locals,::arg()["local-address"]," ,");
9c495589 1968
f28307ad 1969 if(locals.empty())
3f81d239 1970 throw PDNSException("No local address specified");
3ddb9247 1971
f28307ad 1972 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
1973 ServiceTuple st;
1974 st.port=::arg().asNum("local-port");
1975 parseService(*i, st);
3ddb9247 1976
32252594
BH
1977 ComboAddress sin;
1978
f28307ad 1979 memset((char *)&sin,0, sizeof(sin));
37d3f960 1980 sin.sin4.sin_family = AF_INET;
32252594 1981 if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 1982 sin.sin6.sin6_family = AF_INET6;
f71bc087 1983 if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
3ddb9247 1984 throw PDNSException("Unable to resolve local address for TCP server on '"+ st.host +"'");
37d3f960
BH
1985 }
1986
1987 fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0);
3ddb9247 1988 if(fd<0)
3f81d239 1989 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
f28307ad 1990
3897b9e1 1991 setCloseOnExec(fd);
a903b39c 1992
f28307ad 1993 int tmp=1;
810ff705 1994 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp)<0) {
f28307ad 1995 L<<Logger::Error<<"Setsockopt failed for TCP listening socket"<<endl;
c8ddb7c2 1996 exit(1);
f28307ad 1997 }
0dfa94ab 1998 if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
1999 L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
2000 }
2001
c8ddb7c2 2002#ifdef TCP_DEFER_ACCEPT
38ac0821 2003 if(setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &tmp, sizeof tmp) >= 0) {
37d3f960 2004 if(i==locals.begin())
4957a608 2005 L<<Logger::Error<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl;
c8ddb7c2
BH
2006 }
2007#endif
2008
fec7dd5a
SS
2009 if( ::arg().mustDo("non-local-bind") )
2010 Utility::setBindAny(AF_INET, fd);
2011
2332f42d 2012#ifdef SO_REUSEPORT
810ff705
RG
2013 if(g_reusePort) {
2014 if(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &tmp, sizeof(tmp)) < 0)
2332f42d 2015 throw PDNSException("SO_REUSEPORT: "+stringerror());
2016 }
2017#endif
2018
0735b17e
RG
2019 if (::arg().asNum("tcp-fast-open") > 0) {
2020#ifdef TCP_FASTOPEN
2021 int fastOpenQueueSize = ::arg().asNum("tcp-fast-open");
2022 if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &fastOpenQueueSize, sizeof fastOpenQueueSize) < 0) {
2023 L<<Logger::Error<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno)<<endl;
2024 }
2025#else
2026 L<<Logger::Warning<<"TCP Fast Open configured but not supported for listening socket"<<endl;
2027#endif
2028 }
2029
32252594 2030 sin.sin4.sin_port = htons(st.port);
a683e8bd 2031 socklen_t socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
3ddb9247 2032 if (::bind(fd, (struct sockaddr *)&sin, socklen )<0)
3f81d239 2033 throw PDNSException("Binding TCP server socket for "+ st.host +": "+stringerror());
3ddb9247 2034
3897b9e1 2035 setNonBlocking(fd);
49a699c4 2036 setSocketSendBuffer(fd, 65000);
37d3f960 2037 listen(fd, 128);
810ff705 2038 deferredAdds[threadId].push_back(make_pair(fd, handleNewTCPQuestion));
c2136bf0 2039 g_tcpListenSockets.push_back(fd);
84433b79 2040 // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
2041 // - fd is not that which we know here, but returned from accept()
3ddb9247 2042 if(sin.sin4.sin_family == AF_INET)
32252594 2043 L<<Logger::Error<<"Listening for TCP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 2044 else
32252594 2045 L<<Logger::Error<<"Listening for TCP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 2046 }
9c495589
BH
2047}
2048
810ff705 2049static void makeUDPServerSockets(unsigned int threadId)
288f4aa9 2050{
fec7dd5a 2051 int one=1;
f28307ad 2052 vector<string>locals;
2e3d8a19 2053 stringtok(locals,::arg()["local-address"]," ,");
288f4aa9 2054
f28307ad 2055 if(locals.empty())
3f81d239 2056 throw PDNSException("No local address specified");
3ddb9247 2057
f28307ad 2058 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
2059 ServiceTuple st;
2060 st.port=::arg().asNum("local-port");
2061 parseService(*i, st);
2062
37d3f960 2063 ComboAddress sin;
996c89cc 2064
37d3f960
BH
2065 memset(&sin, 0, sizeof(sin));
2066 sin.sin4.sin_family = AF_INET;
32252594 2067 if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 2068 sin.sin6.sin6_family = AF_INET6;
f71bc087 2069 if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
3ddb9247 2070 throw PDNSException("Unable to resolve local address for UDP server on '"+ st.host +"'");
37d3f960 2071 }
3ddb9247 2072
bb4bdbaf 2073 int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0);
d3b4137e 2074 if(fd < 0) {
3f81d239 2075 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
d3b4137e 2076 }
915b0c39
AT
2077 if (!setSocketTimestamps(fd))
2078 L<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
0dfa94ab 2079
b71b60ee 2080 if(IsAnyAddress(sin)) {
cbc03320 2081 if(sin.sin4.sin_family == AF_INET)
2082 if(!setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one))) // linux supports this, so why not - might fail on other systems
2083 g_fromtosockets.insert(fd);
757d3179 2084#ifdef IPV6_RECVPKTINFO
cbc03320 2085 if(sin.sin4.sin_family == AF_INET6)
2086 if(!setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)))
2087 g_fromtosockets.insert(fd);
757d3179 2088#endif
0dfa94ab 2089 if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) {
2090 L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
2091 }
b71b60ee 2092 }
fec7dd5a
SS
2093 if( ::arg().mustDo("non-local-bind") )
2094 Utility::setBindAny(AF_INET6, fd);
2095
3897b9e1 2096 setCloseOnExec(fd);
a903b39c 2097
4e9a20e6 2098 setSocketReceiveBuffer(fd, 250000);
32252594 2099 sin.sin4.sin_port = htons(st.port);
37d3f960 2100
2332f42d 2101
2573d4a6 2102#ifdef SO_REUSEPORT
810ff705 2103 if(g_reusePort) {
2332f42d 2104 if(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
2105 throw PDNSException("SO_REUSEPORT: "+stringerror());
2106 }
2107#endif
a683e8bd 2108 socklen_t socklen=sin.getSocklen();
3ddb9247 2109 if (::bind(fd, (struct sockaddr *)&sin, socklen)<0)
335da0ba 2110 throw PDNSException("Resolver binding to server socket on port "+ std::to_string(st.port) +" for "+ st.host+": "+stringerror());
3ddb9247 2111
3897b9e1 2112 setNonBlocking(fd);
c2136bf0 2113
810ff705 2114 deferredAdds[threadId].push_back(make_pair(fd, handleNewUDPQuestion));
40a3dd64 2115 g_listenSocketsAddresses[fd]=sin; // this is written to only from the startup thread, not from the workers
3ddb9247 2116 if(sin.sin4.sin_family == AF_INET)
32252594 2117 L<<Logger::Error<<"Listening for UDP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 2118 else
32252594 2119 L<<Logger::Error<<"Listening for UDP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 2120 }
c836dc19 2121}
caa6eefa 2122
d187038c 2123static void daemonize(void)
c836dc19
BH
2124{
2125 if(fork())
2126 exit(0); // bye bye
3ddb9247
PD
2127
2128 setsid();
c836dc19 2129
27a5ead5 2130 int i=open("/dev/null",O_RDWR); /* open stdin */
3ddb9247 2131 if(i < 0)
27a5ead5
BH
2132 L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
2133 else {
2134 dup2(i,0); /* stdin */
2135 dup2(i,1); /* stderr */
2136 dup2(i,2); /* stderr */
2137 close(i);
2138 }
288f4aa9 2139}
caa6eefa 2140
d187038c 2141static void usr1Handler(int)
c75a6a9e
BH
2142{
2143 statsWanted=true;
2144}
ae1b2e98 2145
d187038c 2146static void usr2Handler(int)
9170fbaf 2147{
f1f34cc2 2148 g_quiet= !g_quiet;
2149 SyncRes::setDefaultLogMode(g_quiet ? SyncRes::LogNone : SyncRes::Log);
2150 ::arg().set("quiet")=g_quiet ? "" : "no";
9170fbaf
BH
2151}
2152
d187038c 2153static void doStats(void)
c75a6a9e 2154{
16beeaa4
BH
2155 static time_t lastOutputTime;
2156 static uint64_t lastQueryCount;
d299d4f5 2157
2158 uint64_t cacheHits = broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
2159 uint64_t cacheMisses = broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
3ddb9247 2160
d299d4f5 2161 if(g_stats.qcounter && (cacheHits + cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {
bd301954 2162 L<<Logger::Notice<<"stats: "<<g_stats.qcounter<<" questions, "<<
3427fa8a
BH
2163 broadcastAccFunction<uint64_t>(pleaseGetCacheSize)<< " cache entries, "<<
2164 broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize)<<" negative entries, "<<
3ddb9247
PD
2165 (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<<endl;
2166
bd301954 2167 L<<Logger::Notice<<"stats: throttle map: "
3427fa8a 2168 << broadcastAccFunction<uint64_t>(pleaseGetThrottleSize) <<", ns speeds: "
3ddb9247 2169 << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<endl;
bd301954
JB
2170 L<<Logger::Notice<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
2171 L<<Logger::Notice<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
525b8a7c 2172 <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
bd301954 2173 L<<Logger::Notice<<"stats: "<<SyncRes::s_tcpoutqueries<<" outgoing tcp connections, "<<
3427fa8a 2174 broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries)<<" queries running, "<<SyncRes::s_outgoingtimeouts<<" outgoing timeouts"<<endl;
81883dcc 2175
bd301954 2176 //L<<Logger::Notice<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
16beeaa4 2177 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
3ddb9247 2178
bd301954 2179 L<<Logger::Notice<<"stats: " << broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize) <<
16beeaa4 2180 " packet cache entries, "<<(int)(100.0*broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"<<endl;
3ddb9247 2181
16beeaa4
BH
2182 time_t now = time(0);
2183 if(lastOutputTime && lastQueryCount && now != lastOutputTime) {
bd301954 2184 L<<Logger::Notice<<"stats: "<< (SyncRes::s_queries - lastQueryCount) / (now - lastOutputTime) <<" qps (average over "<< (now - lastOutputTime) << " seconds)"<<endl;
16beeaa4
BH
2185 }
2186 lastOutputTime = now;
2187 lastQueryCount = SyncRes::s_queries;
c75a6a9e 2188 }
3ddb9247 2189 else if(statsWanted)
bd301954 2190 L<<Logger::Notice<<"stats: no stats yet!"<<endl;
7becf07f 2191
c75a6a9e
BH
2192 statsWanted=false;
2193}
c836dc19 2194
29f0b1ce 2195static void houseKeeping(void *)
c836dc19 2196{
3337c2f7
RG
2197 static thread_local time_t last_stat, last_rootupdate, last_prune, last_secpoll;
2198 static thread_local int cleanCounter=0;
2199 static thread_local bool s_running; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
cc59bce6 2200 try {
2201 if(s_running)
2202 return;
2203 s_running=true;
3ddb9247 2204
cc59bce6 2205 struct timeval now;
2206 Utility::gettimeofday(&now, 0);
3ddb9247
PD
2207
2208 if(now.tv_sec - last_prune > (time_t)(5 + t_id)) {
cc59bce6 2209 DTime dt;
2210 dt.setTimeval(now);
a6f7f5fe 2211 t_RC->doPrune(g_maxCacheEntries / g_numThreads); // this function is local to a thread, so fine anyhow
2212 t_packetCache->doPruneTo(g_maxPacketCacheEntries / g_numWorkerThreads);
3ddb9247 2213
a6f7f5fe 2214 SyncRes::pruneNegCache(g_maxCacheEntries / (g_numWorkerThreads * 10));
3ddb9247 2215
cc59bce6 2216 if(!((cleanCounter++)%40)) { // this is a full scan!
2217 time_t limit=now.tv_sec-300;
a712cb56 2218 SyncRes::pruneNSSpeeds(limit);
cc59bce6 2219 }
2220 last_prune=time(0);
d67620e4 2221 }
3ddb9247 2222
cc59bce6 2223 if(now.tv_sec - last_rootupdate > 7200) {
30ee601a 2224 int res = SyncRes::getRootNS(g_now, nullptr);
7836f7b4
PL
2225 if (!res)
2226 last_rootupdate=now.tv_sec;
cc59bce6 2227 }
3ddb9247 2228
cc59bce6 2229 if(!t_id) {
0ec489bf 2230 if(g_statisticsInterval > 0 && now.tv_sec - last_stat >= g_statisticsInterval) {
cc59bce6 2231 doStats();
2232 last_stat=time(0);
2233 }
3ddb9247 2234
cc59bce6 2235 if(now.tv_sec - last_secpoll >= 3600) {
2236 try {
2237 doSecPoll(&last_secpoll);
2238 }
581d4ea3 2239 catch(std::exception& e)
2240 {
2241 L<<Logger::Error<<"Exception while performing security poll: "<<e.what()<<endl;
2242 }
47e9b74f 2243 catch(PDNSException& e)
2244 {
2245 L<<Logger::Error<<"Exception while performing security poll: "<<e.reason<<endl;
2246 }
d0992a65
CH
2247 catch(ImmediateServFailException &e)
2248 {
2249 L<<Logger::Error<<"Exception while performing security poll: "<<e.reason<<endl;
2250 }
47e9b74f 2251 catch(...)
2252 {
2253 L<<Logger::Error<<"Exception while performing security poll"<<endl;
2254 }
2255
18b73338 2256 }
d67620e4 2257 }
cc59bce6 2258 s_running=false;
d67620e4 2259 }
cc59bce6 2260 catch(PDNSException& ae)
2261 {
2262 s_running=false;
2263 L<<Logger::Error<<"Fatal error in housekeeping thread: "<<ae.reason<<endl;
2264 throw;
2265 }
779828c4 2266}
d6d5dea7 2267
d187038c 2268static void makeThreadPipes()
49a699c4 2269{
c3828c03 2270 for(unsigned int n=0; n < g_numThreads; ++n) {
49a699c4
BH
2271 struct ThreadPipeSet tps;
2272 int fd[2];
2273 if(pipe(fd) < 0)
2274 unixDie("Creating pipe for inter-thread communications");
3ddb9247 2275
49a699c4
BH
2276 tps.readToThread = fd[0];
2277 tps.writeToThread = fd[1];
3ddb9247 2278
49a699c4
BH
2279 if(pipe(fd) < 0)
2280 unixDie("Creating pipe for inter-thread communications");
2281 tps.readFromThread = fd[0];
2282 tps.writeFromThread = fd[1];
3ddb9247 2283
49a699c4
BH
2284 g_pipes.push_back(tps);
2285 }
2286}
2287
00c9b8c1
BH
2288struct ThreadMSG
2289{
2290 pipefunc_t func;
2291 bool wantAnswer;
2292};
2293
49a699c4
BH
2294void broadcastFunction(const pipefunc_t& func, bool skipSelf)
2295{
49a699c4 2296 unsigned int n = 0;
1dc8f4d0 2297 for(ThreadPipeSet& tps : g_pipes)
49a699c4
BH
2298 {
2299 if(n++ == t_id) {
2300 if(!skipSelf)
2301 func(); // don't write to ourselves!
2302 continue;
2303 }
3ddb9247 2304
00c9b8c1
BH
2305 ThreadMSG* tmsg = new ThreadMSG();
2306 tmsg->func = func;
2307 tmsg->wantAnswer = true;
b841314c
RG
2308 if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) {
2309 delete tmsg;
49a699c4 2310 unixDie("write to thread pipe returned wrong size or error");
b841314c 2311 }
3ddb9247 2312
49a699c4
BH
2313 string* resp;
2314 if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
2315 unixDie("read from thread pipe returned wrong size or error");
3ddb9247 2316
49a699c4
BH
2317 if(resp) {
2318// cerr <<"got response: " << *resp << endl;
2319 delete resp;
2320 }
2321 }
2322}
06ea9015 2323
8171ab83 2324void distributeAsyncFunction(const string& packet, const pipefunc_t& func)
00c9b8c1 2325{
8171ab83 2326 unsigned int hash = hashQuestion(packet.c_str(), packet.length(), g_disthashseed);
06ea9015 2327 unsigned int target = 1 + (hash % (g_pipes.size()-1));
2328
00c9b8c1
BH
2329 if(target == t_id) {
2330 func();
2331 return;
2332 }
3ddb9247 2333 ThreadPipeSet& tps = g_pipes[target];
00c9b8c1
BH
2334 ThreadMSG* tmsg = new ThreadMSG();
2335 tmsg->func = func;
2336 tmsg->wantAnswer = false;
3ddb9247 2337
b841314c
RG
2338 if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) {
2339 delete tmsg;
3ddb9247 2340 unixDie("write to thread pipe returned wrong size or error");
b841314c 2341 }
00c9b8c1 2342}
3427fa8a 2343
d187038c 2344static void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var)
49a699c4 2345{
f26bf547 2346 ThreadMSG* tmsg = nullptr;
3ddb9247
PD
2347
2348 if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread
49a699c4
BH
2349 unixDie("read from thread pipe returned wrong size or error");
2350 }
3ddb9247 2351
2f22827a 2352 void *resp=0;
2353 try {
2354 resp = tmsg->func();
2355 }
2356 catch(std::exception& e) {
6d2010a8 2357 if(g_logCommonErrors)
2358 L<<Logger::Error<<"PIPE function we executed created exception: "<<e.what()<<endl; // but what if they wanted an answer.. we send 0
2f22827a 2359 }
2360 catch(PDNSException& e) {
6d2010a8 2361 if(g_logCommonErrors)
2362 L<<Logger::Error<<"PIPE function we executed created PDNS exception: "<<e.reason<<endl; // but what if they wanted an answer.. we send 0
2f22827a 2363 }
d7c676a5
RG
2364 if(tmsg->wantAnswer) {
2365 if(write(g_pipes[t_id].writeFromThread, &resp, sizeof(resp)) != sizeof(resp)) {
2366 delete tmsg;
00c9b8c1 2367 unixDie("write to thread pipe returned wrong size or error");
d7c676a5
RG
2368 }
2369 }
3ddb9247 2370
00c9b8c1 2371 delete tmsg;
49a699c4 2372}
09e6702a 2373
13034931
BH
2374template<class T> void *voider(const boost::function<T*()>& func)
2375{
2376 return func();
2377}
2378
b3b5459d
BH
2379vector<ComboAddress>& operator+=(vector<ComboAddress>&a, const vector<ComboAddress>& b)
2380{
2381 a.insert(a.end(), b.begin(), b.end());
2382 return a;
2383}
2384
92011b8f 2385vector<pair<string, uint16_t> >& operator+=(vector<pair<string, uint16_t> >&a, const vector<pair<string, uint16_t> >& b)
2386{
2387 a.insert(a.end(), b.begin(), b.end());
2388 return a;
2389}
2390
3ddb9247
PD
2391vector<pair<DNSName, uint16_t> >& operator+=(vector<pair<DNSName, uint16_t> >&a, const vector<pair<DNSName, uint16_t> >& b)
2392{
2393 a.insert(a.end(), b.begin(), b.end());
2394 return a;
2395}
2396
92011b8f 2397
13034931 2398template<class T> T broadcastAccFunction(const boost::function<T*()>& func, bool skipSelf)
3427fa8a
BH
2399{
2400 unsigned int n = 0;
2401 T ret=T();
1dc8f4d0 2402 for(ThreadPipeSet& tps : g_pipes)
3427fa8a
BH
2403 {
2404 if(n++ == t_id) {
2405 if(!skipSelf) {
2406 T* resp = (T*)func(); // don't write to ourselves!
2407 if(resp) {
2408 //~ cerr <<"got direct: " << *resp << endl;
2409 ret += *resp;
2410 delete resp;
2411 }
2412 }
2413 continue;
2414 }
3ddb9247 2415
00c9b8c1
BH
2416 ThreadMSG* tmsg = new ThreadMSG();
2417 tmsg->func = boost::bind(voider<T>, func);
2418 tmsg->wantAnswer = true;
3ddb9247 2419
b841314c
RG
2420 if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) {
2421 delete tmsg;
3427fa8a 2422 unixDie("write to thread pipe returned wrong size or error");
b841314c 2423 }
3ddb9247 2424
3427fa8a
BH
2425 T* resp;
2426 if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
2427 unixDie("read from thread pipe returned wrong size or error");
3ddb9247 2428
3427fa8a
BH
2429 if(resp) {
2430 //~ cerr <<"got response: " << *resp << endl;
2431 ret += *resp;
2432 delete resp;
2433 }
2434 }
2435 return ret;
2436}
2437
13034931
BH
2438template string broadcastAccFunction(const boost::function<string*()>& fun, bool skipSelf); // explicit instantiation
2439template uint64_t broadcastAccFunction(const boost::function<uint64_t*()>& fun, bool skipSelf); // explicit instantiation
b3b5459d 2440template vector<ComboAddress> broadcastAccFunction(const boost::function<vector<ComboAddress> *()>& fun, bool skipSelf); // explicit instantiation
3ddb9247 2441template vector<pair<DNSName,uint16_t> > broadcastAccFunction(const boost::function<vector<pair<DNSName, uint16_t> > *()>& fun, bool skipSelf); // explicit instantiation
3427fa8a 2442
d187038c 2443static void handleRCC(int fd, FDMultiplexer::funcparam_t& var)
09e6702a
BH
2444{
2445 string remote;
2446 string msg=s_rcc.recv(&remote);
2447 RecursorControlParser rcp;
2448 RecursorControlParser::func_t* command;
3ddb9247 2449
09e6702a 2450 string answer=rcp.getAnswer(msg, &command);
f0f3f0b0
PL
2451
2452 // If we are inside a chroot, we need to strip
2453 if (!arg()["chroot"].empty()) {
a683e8bd 2454 size_t len = arg()["chroot"].length();
f0f3f0b0
PL
2455 remote = remote.substr(len);
2456 }
2457
ab5c053d
BH
2458 try {
2459 s_rcc.send(answer, &remote);
2460 command();
2461 }
fdbf35ac 2462 catch(std::exception& e) {
ab5c053d
BH
2463 L<<Logger::Error<<"Error dealing with control socket request: "<<e.what()<<endl;
2464 }
3f81d239 2465 catch(PDNSException& ae) {
ab5c053d
BH
2466 L<<Logger::Error<<"Error dealing with control socket request: "<<ae.reason<<endl;
2467 }
09e6702a
BH
2468}
2469
d187038c 2470static void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 2471{
0b18b22e 2472 PacketID* pident=any_cast<PacketID>(&var);
667f7e60 2473 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
09e6702a 2474
667f7e60 2475 shared_array<char> buffer(new char[pident->inNeeded]);
09e6702a 2476
a683e8bd 2477 ssize_t ret=recv(fd, buffer.get(), pident->inNeeded,0);
09e6702a 2478 if(ret > 0) {
667f7e60 2479 pident->inMSG.append(&buffer[0], &buffer[ret]);
a683e8bd 2480 pident->inNeeded-=(size_t)ret;
825fa717 2481 if(!pident->inNeeded || pident->inIncompleteOkay) {
667f7e60
BH
2482 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
2483 PacketID pid=*pident;
2484 string msg=pident->inMSG;
3ddb9247 2485
bb4bdbaf 2486 t_fdm->removeReadFD(fd);
3ddb9247 2487 MT->sendEvent(pid, &msg);
09e6702a
BH
2488 }
2489 else {
667f7e60 2490 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
09e6702a
BH
2491 }
2492 }
2493 else {
667f7e60 2494 PacketID tmp=*pident;
bb4bdbaf 2495 t_fdm->removeReadFD(fd); // pident might now be invalid (it isn't, but still)
09e6702a
BH
2496 string empty;
2497 MT->sendEvent(tmp, &empty); // this conveys error status
2498 }
2499}
2500
d187038c 2501static void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 2502{
0b18b22e 2503 PacketID* pid=any_cast<PacketID>(&var);
a683e8bd 2504 ssize_t ret=send(fd, pid->outMSG.c_str() + pid->outPos, pid->outMSG.size() - pid->outPos,0);
09e6702a 2505 if(ret > 0) {
a683e8bd 2506 pid->outPos+=(ssize_t)ret;
667f7e60
BH
2507 if(pid->outPos==pid->outMSG.size()) {
2508 PacketID tmp=*pid;
bb4bdbaf 2509 t_fdm->removeWriteFD(fd);
09e6702a
BH
2510 MT->sendEvent(tmp, &tmp.outMSG); // send back what we sent to convey everything is ok
2511 }
2512 }
2513 else { // error or EOF
667f7e60 2514 PacketID tmp(*pid);
bb4bdbaf 2515 t_fdm->removeWriteFD(fd);
09e6702a 2516 string sent;
998a4334 2517 MT->sendEvent(tmp, &sent); // we convey error status by sending empty string
09e6702a
BH
2518 }
2519}
2520
34801ab1 2521// resend event to everybody chained onto it
d187038c 2522static void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content)
34801ab1
BH
2523{
2524 if(iter->key.chain.empty())
2525 return;
e27e91a8 2526 // cerr<<"doResends called!\n";
34801ab1
BH
2527 for(PacketID::chain_t::iterator i=iter->key.chain.begin(); i != iter->key.chain.end() ; ++i) {
2528 resend.fd=-1;
2529 resend.id=*i;
e27e91a8 2530 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
4665c31e 2531
34801ab1
BH
2532 MT->sendEvent(resend, &content);
2533 g_stats.chainResends++;
34801ab1
BH
2534 }
2535}
2536
d187038c 2537static void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t& var)
09e6702a 2538{
600fc20b 2539 PacketID pid=any_cast<PacketID>(var);
a683e8bd 2540 ssize_t len;
e45beeda 2541 char data[g_outgoingEDNSBufsize];
996c89cc 2542 ComboAddress fromaddr;
09e6702a
BH
2543 socklen_t addrlen=sizeof(fromaddr);
2544
998a4334 2545 len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);
c1da7976 2546
a683e8bd 2547 if(len < (ssize_t) sizeof(dnsheader)) {
998a4334 2548 if(len < 0)
996c89cc 2549 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
09e6702a 2550 else {
3ddb9247 2551 g_stats.serverParseError++;
09e6702a 2552 if(g_logCommonErrors)
85db02c5 2553 L<<Logger::Error<<"Unable to parse packet from remote UDP server "<< fromaddr.toString() <<
e44d9fa7 2554 ": packet smaller than DNS header"<<endl;
998a4334 2555 }
34801ab1 2556
49a699c4 2557 t_udpclientsocks->returnSocket(fd);
34801ab1
BH
2558 string empty;
2559
2560 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid);
3ddb9247 2561 if(iter != MT->d_waiters.end())
34801ab1 2562 doResends(iter, pid, empty);
3ddb9247 2563
34801ab1 2564 MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot)
998a4334 2565 return;
3ddb9247 2566 }
998a4334
BH
2567
2568 dnsheader dh;
2569 memcpy(&dh, data, sizeof(dh));
3ddb9247 2570
6da3b3ad
PD
2571 PacketID pident;
2572 pident.remote=fromaddr;
2573 pident.id=dh.id;
2574 pident.fd=fd;
34801ab1 2575
33a928af 2576 if(!dh.qr && g_logCommonErrors) {
854d44e3 2577 L<<Logger::Notice<<"Not taking data from question on outgoing socket from "<< fromaddr.toStringWithPort() <<endl;
6da3b3ad
PD
2578 }
2579
2580 if(!dh.qdcount || // UPC, Nominum, very old BIND on FormErr, NSD
2581 !dh.qr) { // one weird server
2582 pident.domain.clear();
2583 pident.type = 0;
2584 }
2585 else {
2586 try {
0b31e67e 2587 if(len > 12)
2588 pident.domain=DNSName(data, len, 12, false, &pident.type); // don't copy this from above - we need to do the actual read
6da3b3ad
PD
2589 }
2590 catch(std::exception& e) {
2591 g_stats.serverParseError++; // won't be fed to lwres.cc, so we have to increment
0b31e67e 2592 L<<Logger::Warning<<"Error in packet from remote nameserver "<< fromaddr.toStringWithPort() << ": "<<e.what() << endl;
6da3b3ad 2593 return;
34801ab1 2594 }
6da3b3ad
PD
2595 }
2596 string packet;
2597 packet.assign(data, len);
34801ab1 2598
6da3b3ad
PD
2599 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pident);
2600 if(iter != MT->d_waiters.end()) {
2601 doResends(iter, pident, packet);
2602 }
c1da7976 2603
6da3b3ad 2604retryWithName:
4957a608 2605
6da3b3ad
PD
2606 if(!MT->sendEvent(pident, &packet)) {
2607 // 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
2608 for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) {
2609 if(pident.fd==mthread->key.fd && mthread->key.remote==pident.remote && mthread->key.type == pident.type &&
e325f20c 2610 pident.domain == mthread->key.domain) {
6da3b3ad 2611 mthread->key.nearMisses++;
998a4334 2612 }
6da3b3ad
PD
2613
2614 // be a bit paranoid here since we're weakening our matching
3ddb9247 2615 if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type &&
6da3b3ad
PD
2616 pident.id == mthread->key.id && mthread->key.remote == pident.remote) {
2617 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
2618 pident.domain = mthread->key.domain;
2619 pident.type = mthread->key.type;
2620 goto retryWithName; // note that this only passes on an error, lwres will still reject the packet
d4fb76e9 2621 }
09e6702a 2622 }
6da3b3ad
PD
2623 g_stats.unexpectedCount++; // if we made it here, it really is an unexpected answer
2624 if(g_logCommonErrors) {
8a464ee3 2625 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 2626 }
09e6702a 2627 }
6da3b3ad
PD
2628 else if(fd >= 0) {
2629 t_udpclientsocks->returnSocket(fd);
2630 }
09e6702a
BH
2631}
2632
1f4abb20
BH
2633FDMultiplexer* getMultiplexer()
2634{
2635 FDMultiplexer* ret;
f26bf547 2636 for(const auto& i : FDMultiplexer::getMultiplexerMap()) {
1f4abb20 2637 try {
f26bf547 2638 ret=i.second();
1f4abb20
BH
2639 return ret;
2640 }
98d0ee4a 2641 catch(FDMultiplexerException &fe) {
0a7f24cb 2642 L<<Logger::Error<<"Non-fatal error initializing possible multiplexer ("<<fe.what()<<"), falling back"<<endl;
98d0ee4a
BH
2643 }
2644 catch(...) {
2645 L<<Logger::Error<<"Non-fatal error initializing possible multiplexer"<<endl;
2646 }
1f4abb20
BH
2647 }
2648 L<<Logger::Error<<"No working multiplexer found!"<<endl;
2649 exit(1);
2650}
2651
3ddb9247 2652
d187038c 2653static string* doReloadLuaScript()
4485aa35 2654{
674cf0f6 2655 string fname= ::arg()["lua-dns-script"];
4485aa35 2656 try {
674cf0f6 2657 if(fname.empty()) {
f26bf547 2658 t_pdl.reset();
674cf0f6 2659 L<<Logger::Error<<t_id<<" Unloaded current lua script"<<endl;
0f39c1a3 2660 return new string("unloaded\n");
4485aa35
BH
2661 }
2662 else {
9694e14f
AT
2663 t_pdl = std::make_shared<RecursorLua4>();
2664 t_pdl->loadFile(fname);
4485aa35
BH
2665 }
2666 }
fdbf35ac 2667 catch(std::exception& e) {
674cf0f6 2668 L<<Logger::Error<<t_id<<" Retaining current script, error from '"<<fname<<"': "<< e.what() <<endl;
0f39c1a3 2669 return new string("retaining current script, error from '"+fname+"': "+e.what()+"\n");
4485aa35 2670 }
3ddb9247 2671
674cf0f6 2672 L<<Logger::Warning<<t_id<<" (Re)loaded lua script from '"<<fname<<"'"<<endl;
0f39c1a3 2673 return new string("(re)loaded '"+fname+"'\n");
4485aa35
BH
2674}
2675
49a699c4
BH
2676string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end)
2677{
3ddb9247 2678 if(begin != end)
49a699c4 2679 ::arg().set("lua-dns-script") = *begin;
3ddb9247 2680
0f39c1a3 2681 return broadcastAccFunction<string>(doReloadLuaScript);
3ddb9247 2682}
49a699c4 2683
d187038c 2684static string* pleaseUseNewTraceRegex(const std::string& newRegex)
77499b05
BH
2685try
2686{
2687 if(newRegex.empty()) {
f26bf547 2688 t_traceRegex.reset();
77499b05
BH
2689 return new string("unset\n");
2690 }
2691 else {
f26bf547 2692 t_traceRegex = std::make_shared<Regex>(newRegex);
77499b05
BH
2693 return new string("ok\n");
2694 }
2695}
3f81d239 2696catch(PDNSException& ae)
77499b05
BH
2697{
2698 return new string(ae.reason+"\n");
2699}
2700
2701string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end)
2702{
2703 return broadcastAccFunction<string>(boost::bind(pleaseUseNewTraceRegex, begin!=end ? *begin : ""));
2704}
2705
4e9a20e6 2706static void checkLinuxIPv6Limits()
2707{
2708#ifdef __linux__
2709 string line;
2710 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line)) {
335da0ba 2711 int lim=std::stoi(line);
4e9a20e6 2712 if(lim < 16384) {
36849ff2 2713 L<<Logger::Error<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim<<" which is < 16384"<<endl;
4e9a20e6 2714 }
2715 }
2716#endif
2717}
36849ff2 2718static void checkOrFixFDS()
4e9a20e6 2719{
c0063e60 2720 unsigned int availFDs=getFilenumLimit();
2721 unsigned int wantFDs = g_maxMThreads * g_numWorkerThreads +25; // even healthier margin then before
2722
2723 if(wantFDs > availFDs) {
067ad20e 2724 unsigned int hardlimit= getFilenumLimit(true);
2725 if(hardlimit >= wantFDs) {
c0063e60 2726 setFilenumLimit(wantFDs);
2727 L<<Logger::Warning<<"Raised soft limit on number of filedescriptors to "<<wantFDs<<" to match max-mthreads and threads settings"<<endl;
36849ff2 2728 }
2729 else {
067ad20e 2730 int newval = (hardlimit - 25) / g_numWorkerThreads;
2731 L<<Logger::Warning<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<hardlimit<<" < "<<wantFDs<<"), reducing max-mthreads to "<<newval<<endl;
36849ff2 2732 g_maxMThreads = newval;
067ad20e 2733 setFilenumLimit(hardlimit);
36849ff2 2734 }
2735 }
4e9a20e6 2736}
77499b05 2737
d187038c 2738static void* recursorThread(void*);
51e2144e 2739
f26bf547 2740static void* pleaseSupplantACLs(std::shared_ptr<NetmaskGroup> ng)
49a699c4
BH
2741{
2742 t_allowFrom = ng;
f26bf547 2743 return nullptr;
49a699c4
BH
2744}
2745
dbd23fc2
BH
2746int g_argc;
2747char** g_argv;
2748
18af64a8 2749void parseACLs()
f7c1d4e3 2750{
18af64a8 2751 static bool l_initialized;
3ddb9247 2752
49a699c4 2753 if(l_initialized) { // only reload configuration file on second call
18af64a8 2754 string configname=::arg()["config-dir"]+"/recursor.conf";
3e63da83
JR
2755 if(::arg()["config-name"]!="") {
2756 configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
2757 }
18af64a8 2758 cleanSlashes(configname);
3ddb9247
PD
2759
2760 if(!::arg().preParseFile(configname.c_str(), "allow-from-file"))
7e818521 2761 throw runtime_error("Unable to re-parse configuration file '"+configname+"'");
49a699c4 2762 ::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS);
242b90e1 2763 ::arg().preParseFile(configname.c_str(), "include-dir");
829849d6
AT
2764 ::arg().preParse(g_argc, g_argv, "include-dir");
2765
2766 // then process includes
2767 std::vector<std::string> extraConfigs;
242b90e1
AT
2768 ::arg().gatherIncludes(extraConfigs);
2769
1dc8f4d0 2770 for(const std::string& fn : extraConfigs) {
7e818521 2771 if(!::arg().preParseFile(fn.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
2772 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
2773 if(!::arg().preParseFile(fn.c_str(), "allow-from", ::arg()["allow-from"]))
2774 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
829849d6 2775 }
ca2c884c
AT
2776
2777 ::arg().preParse(g_argc, g_argv, "allow-from-file");
2778 ::arg().preParse(g_argc, g_argv, "allow-from");
f27e6356 2779 }
49a699c4 2780
f26bf547
RG
2781 std::shared_ptr<NetmaskGroup> oldAllowFrom = t_allowFrom;
2782 std::shared_ptr<NetmaskGroup> allowFrom = std::make_shared<NetmaskGroup>();
3ddb9247 2783
2c95fc65
BH
2784 if(!::arg()["allow-from-file"].empty()) {
2785 string line;
2c95fc65
BH
2786 ifstream ifs(::arg()["allow-from-file"].c_str());
2787 if(!ifs) {
9c61b9d0 2788 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
2c95fc65
BH
2789 }
2790
2791 string::size_type pos;
2792 while(getline(ifs,line)) {
2793 pos=line.find('#');
2794 if(pos!=string::npos)
2795 line.resize(pos);
2796 trim(line);
2797 if(line.empty())
2798 continue;
2799
18af64a8 2800 allowFrom->addMask(line);
2c95fc65 2801 }
49a699c4 2802 L<<Logger::Warning<<"Done parsing " << allowFrom->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl;
2c95fc65
BH
2803 }
2804 else if(!::arg()["allow-from"].empty()) {
f7c1d4e3
BH
2805 vector<string> ips;
2806 stringtok(ips, ::arg()["allow-from"], ", ");
3ddb9247 2807
f7c1d4e3
BH
2808 L<<Logger::Warning<<"Only allowing queries from: ";
2809 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
18af64a8 2810 allowFrom->addMask(*i);
f7c1d4e3 2811 if(i!=ips.begin())
674cf0f6 2812 L<<Logger::Warning<<", ";
f7c1d4e3
BH
2813 L<<Logger::Warning<<*i;
2814 }
2815 L<<Logger::Warning<<endl;
2816 }
49a699c4 2817 else {
3ddb9247 2818 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
49a699c4 2819 L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl;
f26bf547 2820 allowFrom = nullptr;
49a699c4 2821 }
3ddb9247 2822
49a699c4 2823 g_initialAllowFrom = allowFrom;
d7dae798 2824 broadcastFunction(boost::bind(pleaseSupplantACLs, allowFrom));
f26bf547 2825 oldAllowFrom = nullptr;
3ddb9247 2826
49a699c4 2827 l_initialized = true;
18af64a8
BH
2828}
2829
795215f2 2830
756e82cf 2831static void setupDelegationOnly()
2832{
2833 vector<string> parts;
2834 stringtok(parts, ::arg()["delegation-only"], ", \t");
2835 for(const auto& p : parts) {
9065eb05 2836 SyncRes::addDelegationOnly(DNSName(p));
756e82cf 2837 }
2838}
795215f2 2839
8fd25133
RG
2840static std::map<unsigned int, std::set<int> > parseCPUMap()
2841{
2842 std::map<unsigned int, std::set<int> > result;
2843
2844 const std::string value = ::arg()["cpu-map"];
2845
2846 if (!value.empty() && !isSettingThreadCPUAffinitySupported()) {
2847 L<<Logger::Warning<<"CPU mapping requested but not supported, skipping"<<endl;
2848 return result;
2849 }
2850
2851 std::vector<std::string> parts;
2852
2853 stringtok(parts, value, " \t");
2854
2855 for(const auto& part : parts) {
2856 if (part.find('=') == string::npos)
2857 continue;
2858
2859 try {
2860 auto headers = splitField(part, '=');
2861 trim(headers.first);
2862 trim(headers.second);
2863
2864 unsigned int threadId = pdns_stou(headers.first);
2865 std::vector<std::string> cpus;
2866
2867 stringtok(cpus, headers.second, ",");
2868
2869 for(const auto& cpu : cpus) {
2870 int cpuId = std::stoi(cpu);
2871
2872 result[threadId].insert(cpuId);
2873 }
2874 }
2875 catch(const std::exception& e) {
2876 L<<Logger::Error<<"Error parsing cpu-map entry '"<<part<<"': "<<e.what()<<endl;
2877 }
2878 }
2879
2880 return result;
2881}
2882
2883static void setCPUMap(const std::map<unsigned int, std::set<int> >& cpusMap, unsigned int n, pthread_t tid)
2884{
2885 const auto& cpuMapping = cpusMap.find(n);
2886 if (cpuMapping != cpusMap.cend()) {
2887 int rc = mapThreadToCPUList(tid, cpuMapping->second);
2888 if (rc == 0) {
2889 L<<Logger::Info<<"CPU affinity for worker "<<n<<" has been set to CPU map:";
2890 for (const auto cpu : cpuMapping->second) {
2891 L<<Logger::Info<<" "<<cpu;
2892 }
2893 L<<Logger::Info<<endl;
2894 }
2895 else {
2896 L<<Logger::Warning<<"Error setting CPU affinity for worker "<<n<<" to CPU map:";
2897 for (const auto cpu : cpuMapping->second) {
2898 L<<Logger::Info<<" "<<cpu;
2899 }
2900 L<<Logger::Info<<strerror(rc)<<endl;
2901 }
2902 }
2903}
2904
d187038c 2905static int serviceMain(int argc, char*argv[])
18af64a8 2906{
5124de27 2907 L.setName(s_programname);
b6cfa948 2908 L.disableSyslog(::arg().mustDo("disable-syslog"));
b18fa400 2909 L.setTimestamps(::arg().mustDo("log-timestamp"));
18af64a8
BH
2910
2911 if(!::arg()["logging-facility"].empty()) {
f8499e52
BH
2912 int val=logFacilityToLOG(::arg().asNum("logging-facility") );
2913 if(val >= 0)
2914 theL().setFacility(val);
18af64a8
BH
2915 else
2916 L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
2917 }
2918
ba1a571d 2919 showProductVersion();
18af64a8 2920 seedRandom(::arg()["entropy-source"]);
3afde9b2 2921
06ea9015 2922 g_disthashseed=dns_random(0xffffffff);
2923
b7ef5828
PL
2924 checkLinuxIPv6Limits();
2925 try {
2926 vector<string> addrs;
2927 if(!::arg()["query-local-address6"].empty()) {
2928 SyncRes::s_doIPv6=true;
2929 L<<Logger::Warning<<"Enabling IPv6 transport for outgoing queries"<<endl;
2930
2931 stringtok(addrs, ::arg()["query-local-address6"], ", ;");
2932 for(const string& addr : addrs) {
2933 g_localQueryAddresses6.push_back(ComboAddress(addr));
2934 }
2935 }
2936 else {
2937 L<<Logger::Warning<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl;
2938 }
2939 addrs.clear();
2940 stringtok(addrs, ::arg()["query-local-address"], ", ;");
2941 for(const string& addr : addrs) {
2942 g_localQueryAddresses4.push_back(ComboAddress(addr));
2943 }
2944 }
2945 catch(std::exception& e) {
2946 L<<Logger::Error<<"Assigning local query addresses: "<<e.what();
2947 exit(99);
2948 }
2949
e48c6b8a
PL
2950 // keep this ABOVE loadRecursorLuaConfig!
2951 if(::arg()["dnssec"]=="off")
2952 g_dnssecmode=DNSSECMode::Off;
2953 else if(::arg()["dnssec"]=="process-no-validate")
2954 g_dnssecmode=DNSSECMode::ProcessNoValidate;
2955 else if(::arg()["dnssec"]=="process")
2956 g_dnssecmode=DNSSECMode::Process;
2957 else if(::arg()["dnssec"]=="validate")
2958 g_dnssecmode=DNSSECMode::ValidateAll;
2959 else if(::arg()["dnssec"]=="log-fail")
2960 g_dnssecmode=DNSSECMode::ValidateForLog;
2961 else {
2962 L<<Logger::Error<<"Unknown DNSSEC mode "<<::arg()["dnssec"]<<endl;
2963 exit(1);
2964 }
2965
2966 g_dnssecLogBogus = ::arg().mustDo("dnssec-log-bogus");
d377bb54 2967 g_maxNSEC3Iterations = ::arg().asNum("nsec3-max-iterations");
e48c6b8a 2968
a6f7f5fe 2969 g_maxCacheEntries = ::arg().asNum("max-cache-entries");
2970 g_maxPacketCacheEntries = ::arg().asNum("max-packetcache-entries");
2971
0f5785a6
PL
2972 try {
2973 loadRecursorLuaConfig(::arg()["lua-config-file"], ::arg().mustDo("daemon"));
2974 }
2975 catch (PDNSException &e) {
2976 L<<Logger::Error<<"Cannot load Lua configuration: "<<e.reason<<endl;
2977 exit(1);
2978 }
ad42489c 2979
18af64a8 2980 parseACLs();
92011b8f 2981 sortPublicSuffixList();
2982
eb5bae86 2983 if(!::arg()["dont-query"].empty()) {
eb5bae86
BH
2984 vector<string> ips;
2985 stringtok(ips, ::arg()["dont-query"], ", ");
66e0b6ea
BH
2986 ips.push_back("0.0.0.0");
2987 ips.push_back("::");
c36bc97a 2988
eb5bae86
BH
2989 L<<Logger::Warning<<"Will not send queries to: ";
2990 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
9065eb05 2991 SyncRes::addDontQuery(*i);
eb5bae86 2992 if(i!=ips.begin())
4957a608 2993 L<<Logger::Warning<<", ";
eb5bae86
BH
2994 L<<Logger::Warning<<*i;
2995 }
2996 L<<Logger::Warning<<endl;
2997 }
2998
f7c1d4e3 2999 g_quiet=::arg().mustDo("quiet");
3ddb9247 3000
1bc3c142
BH
3001 g_weDistributeQueries = ::arg().mustDo("pdns-distributes-queries");
3002 if(g_weDistributeQueries) {
3003 L<<Logger::Warning<<"PowerDNS Recursor itself will distribute queries over threads"<<endl;
3004 }
3ddb9247 3005
756e82cf 3006 setupDelegationOnly();
b33c2462 3007 g_outgoingEDNSBufsize=::arg().asNum("edns-outgoing-bufsize");
756e82cf 3008
77499b05
BH
3009 if(::arg()["trace"]=="fail") {
3010 SyncRes::setDefaultLogMode(SyncRes::Store);
3011 }
3012 else if(::arg().mustDo("trace")) {
3013 SyncRes::setDefaultLogMode(SyncRes::Log);
f7c1d4e3
BH
3014 ::arg().set("quiet")="no";
3015 g_quiet=false;
3e9c6c0a 3016 g_dnssecLOG=true;
f7c1d4e3 3017 }
3ddb9247 3018
aadceba8 3019 SyncRes::s_minimumTTL = ::arg().asNum("minimum-ttl-override");
3020
1051f8a9
BH
3021 SyncRes::s_nopacketcache = ::arg().mustDo("disable-packetcache");
3022
f7c1d4e3 3023 SyncRes::s_maxnegttl=::arg().asNum("max-negative-ttl");
63637fd8 3024 SyncRes::s_maxcachettl=max(::arg().asNum("max-cache-ttl"), 15);
1051f8a9 3025 SyncRes::s_packetcachettl=::arg().asNum("packetcache-ttl");
79ec0627
PL
3026 // Cap the packetcache-servfail-ttl to the packetcache-ttl
3027 uint32_t packetCacheServFailTTL = ::arg().asNum("packetcache-servfail-ttl");
3028 SyncRes::s_packetcacheservfailttl=(packetCacheServFailTTL > SyncRes::s_packetcachettl) ? SyncRes::s_packetcachettl : packetCacheServFailTTL;
628e2c7b
PA
3029 SyncRes::s_serverdownmaxfails=::arg().asNum("server-down-max-fails");
3030 SyncRes::s_serverdownthrottletime=::arg().asNum("server-down-throttle-time");
f7c1d4e3 3031 SyncRes::s_serverID=::arg()["server-id"];
173d790e 3032 SyncRes::s_maxqperq=::arg().asNum("max-qperq");
9de3e034 3033 SyncRes::s_maxtotusec=1000*::arg().asNum("max-total-msec");
7c3398aa 3034 SyncRes::s_maxdepth=::arg().asNum("max-recursion-depth");
01402d56 3035 SyncRes::s_rootNXTrust = ::arg().mustDo( "root-nx-trust");
f7c1d4e3
BH
3036 if(SyncRes::s_serverID.empty()) {
3037 char tmp[128];
3038 gethostname(tmp, sizeof(tmp)-1);
3039 SyncRes::s_serverID=tmp;
3040 }
3ddb9247 3041
e9f9b8ec
RG
3042 SyncRes::s_ecsipv4limit = ::arg().asNum("ecs-ipv4-bits");
3043 SyncRes::s_ecsipv6limit = ::arg().asNum("ecs-ipv6-bits");
3044
8a3a3822
RG
3045 if (!::arg().isEmpty("ecs-scope-zero-address")) {
3046 ComboAddress scopeZero(::arg()["ecs-scope-zero-address"]);
3047 SyncRes::setECSScopeZeroAddress(Netmask(scopeZero, scopeZero.isIPv4() ? 32 : 128));
3048 }
3049 else {
3050 bool found = false;
3051 for (const auto& addr : g_localQueryAddresses4) {
3052 if (!IsAnyAddress(addr)) {
3053 SyncRes::setECSScopeZeroAddress(Netmask(addr, 32));
3054 found = true;
3055 break;
3056 }
3057 }
3058 if (!found) {
3059 for (const auto& addr : g_localQueryAddresses6) {
3060 if (!IsAnyAddress(addr)) {
3061 SyncRes::setECSScopeZeroAddress(Netmask(addr, 128));
3062 found = true;
3063 break;
3064 }
3065 }
3066 if (!found) {
3067 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
3068 }
3069 }
3070 }
3071
2fe3354d
CH
3072 SyncRes::parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
3073 SyncRes::parseEDNSSubnetAddFor(::arg()["ecs-add-for"]);
3074 g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet");
3075
5cc8371b 3076 g_XPFAcl.toMasks(::arg()["xpf-allow-from"]);
59cb4a79 3077 g_xpfRRCode = ::arg().asNum("xpf-rr-code");
5cc8371b 3078
5b0ddd18 3079 g_networkTimeoutMsec = ::arg().asNum("network-timeout");
bb4bdbaf 3080
49a699c4 3081 g_initialDomainMap = parseAuthAndForwards();
3ddb9247 3082
08f3f638 3083 g_latencyStatSize=::arg().asNum("latency-statistic-size");
3ddb9247 3084
f7c1d4e3 3085 g_logCommonErrors=::arg().mustDo("log-common-errors");
98d36505 3086 g_logRPZChanges = ::arg().mustDo("log-rpz-changes");
e661a20b
PD
3087
3088 g_anyToTcp = ::arg().mustDo("any-to-tcp");
a09a8ce0
PD
3089 g_udpTruncationThreshold = ::arg().asNum("udp-truncation-threshold");
3090
b3adda56
PD
3091 g_lowercaseOutgoing = ::arg().mustDo("lowercase-outgoing");
3092
810ff705 3093 g_numWorkerThreads = ::arg().asNum("threads");
1c4f2e1b
RG
3094 if (g_numWorkerThreads < 1) {
3095 L<<Logger::Warning<<"Asked to run with 0 threads, raising to 1 instead"<<endl;
3096 g_numWorkerThreads = 1;
3097 }
3098
810ff705
RG
3099 g_numThreads = g_numWorkerThreads + g_weDistributeQueries;
3100 g_maxMThreads = ::arg().asNum("max-mthreads");
3101
00b8cadc
RG
3102 g_gettagNeedsEDNSOptions = ::arg().mustDo("gettag-needs-edns-options");
3103
0ec489bf 3104 g_statisticsInterval = ::arg().asNum("statistics-interval");
3105
810ff705
RG
3106#ifdef SO_REUSEPORT
3107 g_reusePort = ::arg().mustDo("reuseport");
3108#endif
3109
3110 g_useOneSocketPerThread = (!g_weDistributeQueries && g_reusePort);
3111
3112 if (g_useOneSocketPerThread) {
3113 for (unsigned int threadId = 0; threadId < g_numWorkerThreads; threadId++) {
3114 makeUDPServerSockets(threadId);
3115 makeTCPServerSockets(threadId);
3116 }
3117 }
3118 else {
3119 makeUDPServerSockets(0);
3120 makeTCPServerSockets(0);
3121 }
815099b2 3122
677e2a46
BH
3123 int forks;
3124 for(forks = 0; forks < ::arg().asNum("processes") - 1; ++forks) {
1bc3c142
BH
3125 if(!fork()) // we are child
3126 break;
3127 }
3ddb9247 3128
f7c1d4e3
BH
3129 if(::arg().mustDo("daemon")) {
3130 L<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
3131 L.toConsole(Logger::Critical);
f7c1d4e3 3132 daemonize();
a4241908 3133 loadRecursorLuaConfig(::arg()["lua-config-file"], false);
f7c1d4e3
BH
3134 }
3135 signal(SIGUSR1,usr1Handler);
3136 signal(SIGUSR2,usr2Handler);
3137 signal(SIGPIPE,SIG_IGN);
810ff705 3138
a6414fdc 3139 checkOrFixFDS();
3ddb9247 3140
d1b28475
KM
3141#ifdef HAVE_LIBSODIUM
3142 if (sodium_init() == -1) {
3143 L<<Logger::Error<<"Unable to initialize sodium crypto library"<<endl;
3144 exit(99);
3145 }
3146#endif
3147
3afde9b2
PL
3148 openssl_thread_setup();
3149 openssl_seed();
3150
138435cb
BH
3151 int newgid=0;
3152 if(!::arg()["setgid"].empty())
3153 newgid=Utility::makeGidNumeric(::arg()["setgid"]);
3154 int newuid=0;
3155 if(!::arg()["setuid"].empty())
3156 newuid=Utility::makeUidNumeric(::arg()["setuid"]);
3157
f1d6a7ce
KM
3158 Utility::dropGroupPrivs(newuid, newgid);
3159
138435cb 3160 if (!::arg()["chroot"].empty()) {
75336810
PL
3161#ifdef HAVE_SYSTEMD
3162 char *ns;
3163 ns = getenv("NOTIFY_SOCKET");
3164 if (ns != nullptr) {
3165 L<<Logger::Error<<"Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'"<<endl;
3166 exit(1);
3167 }
3168#endif
138435cb
BH
3169 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
3170 L<<Logger::Error<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno)<<", exiting"<<endl;
3171 exit(1);
3172 }
f0f3f0b0
PL
3173 else
3174 L<<Logger::Error<<"Chrooted to '"<<::arg()["chroot"]<<"'"<<endl;
138435cb
BH
3175 }
3176
f0f3f0b0
PL
3177 s_pidfname=::arg()["socket-dir"]+"/"+s_programname+".pid";
3178 if(!s_pidfname.empty())
3179 unlink(s_pidfname.c_str()); // remove possible old pid file
3180 writePid();
3181
3182 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks : -1);
3183
f1d6a7ce 3184 Utility::dropUserPrivs(newuid);
c0063e60 3185
49a699c4 3186 makeThreadPipes();
3ddb9247 3187
5d4dd7fe
BH
3188 g_tcpTimeout=::arg().asNum("client-tcp-timeout");
3189 g_maxTCPPerClient=::arg().asNum("max-tcp-per-client");
fde296a3 3190 g_tcpMaxQueriesPerConn=::arg().asNum("max-tcp-queries-per-connection");
343257a4 3191
d705aad9
RG
3192 if (::arg().mustDo("snmp-agent")) {
3193 g_snmpAgent = std::make_shared<RecursorSNMPAgent>("recursor", ::arg()["snmp-master-socket"]);
3194 g_snmpAgent->run();
3195 }
3196
8fd25133 3197 const auto cpusMap = parseCPUMap();
c3828c03 3198 if(g_numThreads == 1) {
76698c6e 3199 L<<Logger::Warning<<"Operating unthreaded"<<endl;
6b6720de
PL
3200#ifdef HAVE_SYSTEMD
3201 sd_notify(0, "READY=1");
3202#endif
8fd25133 3203 setCPUMap(cpusMap, 0, pthread_self());
76698c6e
BH
3204 recursorThread(0);
3205 }
3206 else {
3207 pthread_t tid;
c3828c03
BH
3208 L<<Logger::Warning<<"Launching "<< g_numThreads <<" threads"<<endl;
3209 for(unsigned int n=0; n < g_numThreads; ++n) {
77499b05 3210 pthread_create(&tid, 0, recursorThread, (void*)(long)n);
8fd25133
RG
3211
3212 setCPUMap(cpusMap, n, tid);
76698c6e
BH
3213 }
3214 void* res;
6b6720de
PL
3215#ifdef HAVE_SYSTEMD
3216 sd_notify(0, "READY=1");
3217#endif
76698c6e 3218 pthread_join(tid, &res);
bb4bdbaf 3219 }
bb4bdbaf
BH
3220 return 0;
3221}
3222
d187038c 3223static void* recursorThread(void* ptr)
bb4bdbaf
BH
3224try
3225{
2e2cd8ec 3226 t_id=(int) (long) ptr;
49a699c4 3227 SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so..
a712cb56 3228 SyncRes::setDomainMap(g_initialDomainMap);
49a699c4 3229 t_allowFrom = g_initialAllowFrom;
f26bf547
RG
3230 t_udpclientsocks = std::unique_ptr<UDPClientSocks>(new UDPClientSocks());
3231 t_tcpClientCounts = std::unique_ptr<tcpClientCounts_t>(new tcpClientCounts_t());
49a699c4 3232 primeHints();
3ddb9247 3233
f26bf547 3234 t_packetCache = std::unique_ptr<RecursorPacketCache>(new RecursorPacketCache());
3ddb9247 3235
aa7929a3 3236#ifdef HAVE_PROTOBUF
f26bf547 3237 t_uuidGenerator = std::unique_ptr<boost::uuids::random_generator>(new boost::uuids::random_generator());
aa7929a3 3238#endif
49a699c4 3239 L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
3ddb9247 3240
674cf0f6
BH
3241 try {
3242 if(!::arg()["lua-dns-script"].empty()) {
9694e14f
AT
3243 t_pdl = std::make_shared<RecursorLua4>();
3244 t_pdl->loadFile(::arg()["lua-dns-script"]);
674cf0f6
BH
3245 L<<Logger::Warning<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl;
3246 }
674cf0f6
BH
3247 }
3248 catch(std::exception &e) {
3249 L<<Logger::Error<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e.what()<<endl;
62f0ae62 3250 _exit(99);
674cf0f6 3251 }
3ddb9247 3252
f8f243b0 3253 unsigned int ringsize=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads;
92011b8f 3254 if(ringsize) {
f26bf547 3255 t_remotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
f8f243b0 3256 if(g_weDistributeQueries) // if so, only 1 thread does recvfrom
3ddb9247 3257 t_remotes->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
f8f243b0 3258 else
3ddb9247 3259 t_remotes->set_capacity(ringsize);
f26bf547 3260 t_servfailremotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
3ddb9247 3261 t_servfailremotes->set_capacity(ringsize);
f26bf547 3262 t_largeanswerremotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
3ddb9247 3263 t_largeanswerremotes->set_capacity(ringsize);
92011b8f 3264
f26bf547 3265 t_queryring = std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > >(new boost::circular_buffer<pair<DNSName, uint16_t> >());
3ddb9247 3266 t_queryring->set_capacity(ringsize);
f26bf547 3267 t_servfailqueryring = std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > >(new boost::circular_buffer<pair<DNSName, uint16_t> >());
3ddb9247 3268 t_servfailqueryring->set_capacity(ringsize);
92011b8f 3269 }
3ddb9247 3270
f26bf547 3271 MT=std::unique_ptr<MTasker<PacketID,string> >(new MTasker<PacketID,string>(::arg().asNum("stack-size")));
3ddb9247 3272
bb4bdbaf
BH
3273 PacketID pident;
3274
3275 t_fdm=getMultiplexer();
f3d1d67b 3276 if(!t_id) {
d07bf7ff 3277 if(::arg().mustDo("webserver")) {
30a1aa92 3278 L<<Logger::Warning << "Enabling web server" << endl;
8989097d 3279 try {
1ce57618 3280 new RecursorWebServer(t_fdm);
8989097d
CH
3281 }
3282 catch(PDNSException &e) {
3283 L<<Logger::Error<<"Exception: "<<e.reason<<endl;
3284 exit(99);
3285 }
f3d1d67b 3286 }
83252304 3287 L<<Logger::Error<<"Enabled '"<< t_fdm->getName() << "' multiplexer"<<endl;
f3d1d67b 3288 }
83252304 3289
49a699c4 3290 t_fdm->addReadFD(g_pipes[t_id].readToThread, handlePipeRequest);
83252304 3291
810ff705 3292 if(g_useOneSocketPerThread) {
2573d4a6
RG
3293 for(deferredAdd_t::const_iterator i = deferredAdds[t_id].cbegin(); i != deferredAdds[t_id].cend(); ++i) {
3294 t_fdm->addReadFD(i->first, i->second);
810ff705
RG
3295 }
3296 }
3297 else {
3298 if(!g_weDistributeQueries || !t_id) { // if we distribute queries, only t_id = 0 listens
0670917b 3299 for(deferredAdd_t::const_iterator i = deferredAdds[0].cbegin(); i != deferredAdds[0].cend(); ++i) {
810ff705
RG
3300 t_fdm->addReadFD(i->first, i->second);
3301 }
3302 }
3303 }
3ddb9247 3304
b0b37121 3305 registerAllStats();
674cf0f6 3306 if(!t_id) {
674cf0f6
BH
3307 t_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel
3308 }
1bc3c142 3309
f7c1d4e3 3310 unsigned int maxTcpClients=::arg().asNum("max-tcp-clients");
3ddb9247 3311
f7c1d4e3 3312 bool listenOnTCP(true);
49a699c4 3313
2c78bd57 3314 time_t last_carbon=0;
3315 time_t carbonInterval=::arg().asNum("carbon-interval");
ac0995bb 3316 counter.store(0); // used to periodically execute certain tasks
f7c1d4e3 3317 for(;;) {
ac0e821b 3318 while(MT->schedule(&g_now)); // MTasker letting the mthreads do their thing
3ddb9247 3319
3427fa8a
BH
3320 if(!(counter%500)) {
3321 MT->makeThread(houseKeeping, 0);
f7c1d4e3
BH
3322 }
3323
d2392145 3324 if(!(counter%55)) {
d8f6d49f 3325 typedef vector<pair<int, FDMultiplexer::funcparam_t> > expired_t;
bb4bdbaf 3326 expired_t expired=t_fdm->getTimeouts(g_now);
3ddb9247 3327
f7c1d4e3 3328 for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) {
cd989c87 3329 shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(i->second);
4957a608 3330 if(g_logCommonErrors)
5cc8371b 3331 L<<Logger::Warning<<"Timeout from remote TCP client "<< conn->d_remote.toStringWithPort() <<endl;
4957a608 3332 t_fdm->removeReadFD(i->first);
f7c1d4e3
BH
3333 }
3334 }
3ddb9247 3335
f7c1d4e3
BH
3336 counter++;
3337
3427fa8a 3338 if(!t_id && statsWanted) {
f7c1d4e3
BH
3339 doStats();
3340 }
3341
3342 Utility::gettimeofday(&g_now, 0);
2c78bd57 3343
3344 if(!t_id && (g_now.tv_sec - last_carbon >= carbonInterval)) {
3345 MT->makeThread(doCarbonDump, 0);
3346 last_carbon = g_now.tv_sec;
3347 }
3348
bb4bdbaf 3349 t_fdm->run(&g_now);
3ea54bf0 3350 // 'run' updates g_now for us
f7c1d4e3 3351
b8ef5c5c 3352 if(!g_weDistributeQueries || !t_id) { // if pdns distributes queries, only tid 0 should do this
5c889cf5 3353 if(listenOnTCP) {
3354 if(TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections
3355 for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
3356 t_fdm->removeReadFD(*i);
3357 listenOnTCP=false;
3358 }
f7c1d4e3 3359 }
5c889cf5 3360 else {
3361 if(TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable
3362 for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
3363 t_fdm->addReadFD(*i, handleNewTCPQuestion);
3364 listenOnTCP=true;
3365 }
f7c1d4e3
BH
3366 }
3367 }
3368 }
3369}
3f81d239 3370catch(PDNSException &ae) {
bb4bdbaf
BH
3371 L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
3372 return 0;
3373}
3374catch(std::exception &e) {
3375 L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
3376 return 0;
3377}
3378catch(...) {
3379 L<<Logger::Error<<"any other exception in main: "<<endl;
3380 return 0;
3381}
3382
51e2144e 3383
3ddb9247 3384int main(int argc, char **argv)
288f4aa9 3385{
dbd23fc2
BH
3386 g_argc = argc;
3387 g_argv = argv;
5e3de507 3388 g_stats.startupTime=time(0);
3e135495 3389 versionSetProduct(ProductRecursor);
8a63d3ce 3390 reportBasicTypes();
0007c2e5 3391 reportOtherTypes();
ea634573 3392
22030c37 3393 int ret = EXIT_SUCCESS;
caa6eefa 3394
288f4aa9 3395 try {
f888311c 3396 ::arg().set("stack-size","stack size per mthread")="200000";
2e3d8a19 3397 ::arg().set("soa-minimum-ttl","Don't change")="0";
2e3d8a19 3398 ::arg().set("no-shuffle","Don't change")="off";
2e3d8a19 3399 ::arg().set("local-port","port to listen on")="53";
32252594 3400 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
fec7dd5a 3401 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
77499b05 3402 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
a6415142 3403 ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate (default)/process/log-fail/validate")="process-no-validate";
c87e1876 3404 ::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations")="no";
d3f809bf 3405 ::arg().set("daemon","Operate as a daemon")="no";
191f2e47 3406 ::arg().setSwitch("write-pid","Write a PID file")="yes";
9afa8662 3407 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="6";
b6cfa948 3408 ::arg().set("disable-syslog","Disable logging to syslog, useful when running inside a supervisor that logs stdout")="no";
b18fa400 3409 ::arg().set("log-timestamp","Print timestamps in log lines, useful to disable when running with a tool that timestamps stdout already")="yes";
22e0810c 3410 ::arg().set("log-common-errors","If we should log rather common errors")="no";
2e3d8a19
BH
3411 ::arg().set("chroot","switch to chroot jail")="";
3412 ::arg().set("setgid","If set, change group id to this gid for more security")="";
3413 ::arg().set("setuid","If set, change user id to this uid for more security")="";
c83ee49d 3414 ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o")="1500";
bb4bdbaf 3415 ::arg().set("threads", "Launch this number of threads")="2";
adabfcb9 3416 ::arg().set("processes", "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)")="1"; // if we un-experimental this, need to fix openssl rand seeding for multiple PIDs!
5124de27 3417 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
d07bf7ff 3418 ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = "";
479e0976
CH
3419 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
3420 ::arg().set("api-logfile", "Location of the server logfile (used by the REST API)") = "/var/log/pdns.log";
3421 ::arg().set("api-readonly", "Disallow data modification through the REST API when set") = "no";
3422 ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no";
d07bf7ff
PL
3423 ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
3424 ::arg().set("webserver-port", "Port of webserver to listen on") = "8082";
3425 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
be3e1477 3426 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="127.0.0.1,::1";
cc08b5a9 3427 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
e12f8407 3428 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address")="";
2c78bd57 3429 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
0ec489bf 3430 ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable")="1800";
c038218b 3431 ::arg().set("quiet","Suppress logging of questions and answers")="";
f27e6356 3432 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
2e3d8a19 3433 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
fdbf35ac
BH
3434 ::arg().set("socket-owner","Owner of socket")="";
3435 ::arg().set("socket-group","Group of socket")="";
3436 ::arg().set("socket-mode", "Permissions for socket")="";
3ddb9247 3437
f0f3f0b0 3438 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR+" when unset and not chrooted" )="";
2e3d8a19
BH
3439 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
3440 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
d4fb76e9 3441 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
2e3d8a19 3442 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
85c32340 3443 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
2e3d8a19 3444 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
324dc148 3445 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
979edd70 3446 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
2e3d8a19 3447 ::arg().set("hint-file", "If set, load root hints from this file")="";
b45eb27c 3448 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
a9af3782 3449 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
c3e753c7 3450 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
1051f8a9 3451 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
927c12b0 3452 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
1051f8a9 3453 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
54c4c0d8 3454 ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname")="";
92011b8f 3455 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
ba1a571d 3456 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
49a699c4 3457 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS;
2c95fc65 3458 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
51e2144e 3459 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
3ddb9247 3460 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY;
4e120339 3461 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
fde296a3 3462 ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection")="0";
0d5f0a9f 3463 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
4ef015cd 3464 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
5605c067 3465 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
3e61e7f7 3466 ::arg().set("lua-config-file", "More powerful configuration options")="";
644dd1da 3467
5605c067 3468 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
927c12b0
BH
3469 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
3470 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
5605c067 3471 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
ac0b4eb3 3472 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
3ea54bf0 3473 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
e498dac1 3474 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="yes";
4485aa35 3475 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
08f3f638 3476 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
3ddb9247 3477 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
35695d18 3478 ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24";
3479 ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
3f975863 3480 ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
2fe3354d 3481 ::arg().set("ecs-add-for", "List of client netmasks for which EDNS Client Subnet will be added")="0.0.0.0/0, ::/0, " LOCAL_NETS_INVERSE;
8a3a3822 3482 ::arg().set("ecs-scope-zero-address", "Address to send to whitelisted authoritative servers for incoming queries with ECS prefix-length source of 0")="";
a16c4536 3483 ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="no";
e498dac1 3484 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes";
4ca2d205 3485 ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes";
e661a20b 3486 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
b3adda56 3487 ::arg().setSwitch( "lowercase-outgoing","Force outgoing questions to lowercase")="no";
00b8cadc 3488 ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook")="no";
a09a8ce0 3489 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680";
b33c2462 3490 ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size")="1680";
aadceba8 3491 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
173d790e 3492 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
c5950146 3493 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000";
7c3398aa 3494 ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40";
a09a8ce0 3495
68e6df3c 3496 ::arg().set("include-dir","Include *.conf files from this directory")="";
d67620e4 3497 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
2332f42d 3498
3499 ::arg().setSwitch("reuseport","Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address")="no";
2e3d8a19 3500
d705aad9 3501 ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent")="no";
396f126e 3502 ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP master")="";
d705aad9 3503
0735b17e 3504 ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
d377bb54 3505 ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record")="2500";
0735b17e 3506
8fd25133
RG
3507 ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs")="";
3508
98d36505
RG
3509 ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level")="no";
3510
5cc8371b 3511 ::arg().set("xpf-allow-from","XPF information is only processed from these subnets")="";
59cb4a79 3512 ::arg().set("xpf-rr-code","XPF option code to use")="0";
5cc8371b 3513
2e3d8a19 3514 ::arg().setCmd("help","Provide a helpful message");
ba1a571d 3515 ::arg().setCmd("version","Print version string");
d5141417 3516 ::arg().setCmd("config","Output blank configuration");
f27e6356 3517 L.toConsole(Logger::Info);
2e3d8a19 3518 ::arg().laxParse(argc,argv); // do a lax parse
c75a6a9e 3519
2d733c0f
CH
3520 string configname=::arg()["config-dir"]+"/recursor.conf";
3521 if(::arg()["config-name"]!="") {
3522 configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
5124de27 3523 s_programname+="-"+::arg()["config-name"];
2d733c0f
CH
3524 }
3525 cleanSlashes(configname);
5124de27 3526
5cc1ea1d
CH
3527 if(!::arg().getCommands().empty()) {
3528 cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
3529 exit(99);
3530 }
3531
577cf284
BH
3532 if(::arg().mustDo("config")) {
3533 cout<<::arg().configstring()<<endl;
3534 exit(0);
3535 }
3536
3ddb9247 3537 if(!::arg().file(configname.c_str()))
c75a6a9e
BH
3538 L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
3539
2e3d8a19 3540 ::arg().parse(argc,argv);
c836dc19 3541
f0f3f0b0
PL
3542 if( !::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty() && !::arg().mustDo("api-readonly") ) {
3543 L<<Logger::Error<<"Using chroot and a writable API is not possible"<<endl;
3544 exit(EXIT_FAILURE);
3545 }
3546
3547 if (::arg()["socket-dir"].empty()) {
3548 if (::arg()["chroot"].empty())
3549 ::arg().set("socket-dir") = LOCALSTATEDIR;
3550 else
3551 ::arg().set("socket-dir") = "/";
3552 }
3553
2e3d8a19 3554 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
562588a3 3555
61d74169 3556 if(::arg().asNum("threads")==1)
3557 ::arg().set("pdns-distributes-queries")="no";
3558
2e3d8a19 3559 if(::arg().mustDo("help")) {
ff5ba4f9
WA
3560 cout<<"syntax:"<<endl<<endl;
3561 cout<<::arg().helpstring(::arg()["help"])<<endl;
3562 exit(0);
b636533b 3563 }
5e3de507 3564 if(::arg().mustDo("version")) {
ba1a571d 3565 showProductVersion();
3613a51c 3566 showBuildConfiguration();
67076869 3567 exit(0);
5e3de507 3568 }
b636533b 3569
34162f8f 3570 Logger::Urgency logUrgency = (Logger::Urgency)::arg().asNum("loglevel");
f48d7b65 3571
34162f8f
CH
3572 if (logUrgency < Logger::Error)
3573 logUrgency = Logger::Error;
f48d7b65 3574 if(!g_quiet && logUrgency < Logger::Info) { // Logger::Info=6, Logger::Debug=7
3575 logUrgency = Logger::Info; // if you do --quiet=no, you need Info to also see the query log
3576 }
34162f8f
CH
3577 L.setLoglevel(logUrgency);
3578 L.toConsole(logUrgency);
3579
f7c1d4e3 3580 serviceMain(argc, argv);
288f4aa9 3581 }
3f81d239 3582 catch(PDNSException &ae) {
c836dc19 3583 L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
22030c37 3584 ret=EXIT_FAILURE;
288f4aa9 3585 }
fdbf35ac 3586 catch(std::exception &e) {
c836dc19 3587 L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
22030c37 3588 ret=EXIT_FAILURE;
288f4aa9
BH
3589 }
3590 catch(...) {
c836dc19 3591 L<<Logger::Error<<"any other exception in main: "<<endl;
22030c37 3592 ret=EXIT_FAILURE;
288f4aa9 3593 }
3ddb9247 3594
22030c37 3595 return ret;
288f4aa9 3596}